diff --git a/.circleci/config.yml b/.circleci/config.yml index 3879be904..2e98f0726 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1 +1,836 @@ version: 2.1 +orbs: + slack: circleci/slack@4.12.5 + helm: circleci/helm@2.0.1 + aws-eks: circleci/aws-eks@2.2.0 + kubernetes: circleci/kubernetes@1.3 + fynarfin-orb: fynarfin/docker-image-availability-check-and-upgrade@1.0.2 + +executors: + docker-executor: + docker: + - image: circleci/openjdk:17-buster-node-browsers-legacy + auth: + username: $DOCKERHUB_USERNAME + password: $DOCKERHUB_PASSWORD + +jobs: + build-g2p-sandbox-ci-chart: + docker: + - image: cimg/python:3.10 + working_directory: ~/repo + environment: + TERM: dumb + steps: + - checkout + - run: rm -f ph-ee-env-labs/helm/ph-ee-g2p-sandbox-ci/Chart.lock ph-ee-env-labs/helm/ph-ee-g2p-sandbox-ci/requirements.lock ph-ee-env-labs/helm/ph-ee-g2p-sandbox-ci/charts/* + - helm/install-helm-client: + version: "v3.8.2" + # - run: "sed -i '12s/.*/version: 0.0.0/' helm/ph-ee-g2p-sandbox-ci/Chart.yaml" + - run: + name: build-and-host-ph-ee-g2p-sandbox-ci + environment: + JIRA_STORY: '' + JIRA_STORY_DIR: '' + command: | + if [ "$CIRCLE_BRANCH" != "develop" ]; then + PR_NUMBER=$(basename $CIRCLE_PULL_REQUEST) + PR_TITLE=$(curl -sSL "https://api.github.com/repos/fynarfin/$CIRCLE_PROJECT_REPONAME/pulls/$PR_NUMBER" | jq -r '.title') + JIRA_STORY=-$(echo $PR_TITLE | cut -d "[" -f2 | cut -d "]" -f1 | tr '[A-Z]' '[a-z]') + if [ -z "$JIRA_STORY" ]; then echo "Invalid PR title" && exit 1; else echo "Ticket NO: $JIRA_STORY" && JIRA_STORY_DIR=$(echo /jira-story-version); fi + echo Charts will save in https://fynarfin.io/images/fynarfin$JIRA_STORY_DIR + fi + CHART_URL="https://fynarfin.io/images/fynarfin$JIRA_STORY_DIR/ph-ee-g2p-sandbox-ci-0.0.0$JIRA_STORY" + if curl --output /dev/null --silent --head --fail "$CHART_URL"; then + sed -i "11s@^ *repository:.*\$@ repository: $CHART_URL@" ph-ee-env-labs/helm/ph-ee-g2p-sandbox-ci/Chart.yaml + sed -i "12s@^ *version:.*\$@ version: 0.0.0$JIRA_STORY@" ph-ee-env-labs/helm/ph-ee-g2p-sandbox-ci/Chart.yaml + echo "chart used: < $CHART_URL >" + else + CHART_URL="https://fynarfin.io/images/fynarfin/ph-ee-g2p-sandbox-ci-0.0.0" + echo "chart used: < $CHART_URL >" + fi + sed -i "6s/.*/version: 0.0.0$JIRA_STORY/" ph-ee-env-labs/helm/ph-ee-g2p-sandbox-ci/Chart.yaml + cat ph-ee-env-labs/helm/ph-ee-g2p-sandbox-ci/Chart.yaml + helm dep up ph-ee-env-labs/helm/ph-ee-g2p-sandbox-ci + helm package ph-ee-env-labs/helm/ph-ee-g2p-sandbox-ci + helm repo index . + echo "$CERT_FILE" | base64 --decode > b64encoded.pem + chmod 400 b64encoded.pem + ssh -i b64encoded.pem -o StrictHostKeyChecking=No ec2-user@13.233.68.128 sudo mkdir -p /apps/apache-tomcat-7.0.82/webapps/ROOT/images/fynarfin$JIRA_STORY_DIR/ph-ee-g2p-sandbox-ci$JIRA_STORY + scp -o StrictHostKeyChecking=No -i b64encoded.pem index.yaml ph-ee-g2p-sandbox-ci-0.0.0$JIRA_STORY.tgz ec2-user@13.233.68.128:~/ + ssh -i b64encoded.pem -o StrictHostKeyChecking=No ec2-user@13.233.68.128 sudo mv -t /apps/apache-tomcat-7.0.82/webapps/ROOT/images/fynarfin$JIRA_STORY_DIR/ph-ee-g2p-sandbox-ci$JIRA_STORY index.yaml ph-ee-g2p-sandbox-ci-0.0.0$JIRA_STORY.tgz + build-and-host-engine: + docker: + - image: cimg/python:3.10 + working_directory: ~/repo + environment: + TERM: dumb + steps: + - checkout + - run: rm -f ph-ee-env-template/helm/ph-ee-engine/Chart.lock ph-ee-env-template/helm/ph-ee-engine/requirements.lock helm/ph-ee-engine/charts/* + - helm/install-helm-client: + version: "v3.8.2" + - run: + name: build-and-host-engine + environment: + JIRA_STORY: '' + JIRA_STORY_DIR: '' + command: | + if [ "$CIRCLE_BRANCH" != "develop" ]; then + PR_NUMBER=$(basename $CIRCLE_PULL_REQUEST) + PR_TITLE=$(curl -sSL "https://api.github.com/repos/fynarfin/$CIRCLE_PROJECT_REPONAME/pulls/$PR_NUMBER" | jq -r '.title') + JIRA_STORY=-$(echo $PR_TITLE | cut -d "[" -f2 | cut -d "]" -f1 | tr '[A-Z]' '[a-z]') + if [ -z "$JIRA_STORY" ]; then echo "Invalid PR title" && exit 1; else echo "Ticket NO: $JIRA_STORY" && JIRA_STORY_DIR=$(echo /jira-story-version); fi + echo Charts will save in https://fynarfin.io/images/fynarfin$JIRA_STORY_DIR + fi + sed -i "5s/.*/version: 0.0.0-SNAPSHOT$JIRA_STORY/" ph-ee-env-template/helm/ph-ee-engine/Chart.yaml + helm dep up ph-ee-env-template/helm/ph-ee-engine + helm package ph-ee-env-template/helm/ph-ee-engine + helm repo index . + echo "$CERT_FILE" | base64 --decode > b64encoded.pem + chmod 400 b64encoded.pem + ssh -i b64encoded.pem -o StrictHostKeyChecking=No ec2-user@13.233.68.128 sudo mkdir -p /apps/apache-tomcat-7.0.82/webapps/ROOT/images/fynarfin$JIRA_STORY_DIR/ph-ee-engine-0.0.0-SNAPSHOT$JIRA_STORY + scp -o StrictHostKeyChecking=No -i b64encoded.pem index.yaml ph-ee-engine-0.0.0-SNAPSHOT$JIRA_STORY.tgz ec2-user@13.233.68.128:~/ + ssh -i b64encoded.pem -o StrictHostKeyChecking=No ec2-user@13.233.68.128 sudo cp -t /apps/apache-tomcat-7.0.82/webapps/ROOT/images/fynarfin$JIRA_STORY_DIR/ph-ee-engine-0.0.0-SNAPSHOT$JIRA_STORY index.yaml ph-ee-engine-0.0.0-SNAPSHOT$JIRA_STORY.tgz + build-and-host-g2p-sandbox: + docker: + - image: cimg/python:3.10 + working_directory: ~/repo + environment: + TERM: dumb + steps: + - checkout + - run: rm -f ph-ee-env-template/helm/g2p-sandbox/Chart.lock ph-ee-env-template/helm/g2p-sandbox/requirements.lock ph-ee-env-template/helm/g2p-sandbox/charts/* + - helm/install-helm-client: + version: "v3.8.2" + - run: + name: build-and-host-g2p-sandbox + environment: + JIRA_STORY: '' + JIRA_STORY_DIR: '' + command: | + if [ "$CIRCLE_BRANCH" != "develop" ]; then + PR_NUMBER=$(basename $CIRCLE_PULL_REQUEST) + PR_TITLE=$(curl -sSL "https://api.github.com/repos/fynarfin/$CIRCLE_PROJECT_REPONAME/pulls/$PR_NUMBER" | jq -r '.title') + JIRA_STORY=-$(echo $PR_TITLE | cut -d "[" -f2 | cut -d "]" -f1 | tr '[A-Z]' '[a-z]') + if [ -z "$JIRA_STORY" ]; then echo "Invalid PR title" && exit 1; else echo "Ticket NO: $JIRA_STORY" && JIRA_STORY_DIR=$(echo /jira-story-version); fi + fi + CHART_URL="https://fynarfin.io/images/fynarfin$JIRA_STORY_DIR/ph-ee-engine-0.0.0-SNAPSHOT$JIRA_STORY" + if curl --output /dev/null --silent --head --fail "$CHART_URL"; then + sed -i "10s@^ *repository:.*\$@ repository: $CHART_URL@" ph-ee-env-template/helm/g2p-sandbox/Chart.yaml + sed -i "11s@^ *version:.*\$@ version: 0.0.0-SNAPSHOT$JIRA_STORY@" ph-ee-env-template/helm/g2p-sandbox/Chart.yaml + echo "chart used: < $CHART_URL >" + else + CHART_URL="https://fynarfin.io/images/fynarfin/ph-ee-engine-0.0.0-SNAPSHOT" + echo "chart used: < $CHART_URL >" + fi + sed -i "5s/.*/version: 0.0.0$JIRA_STORY/" ph-ee-env-template/helm/g2p-sandbox/Chart.yaml + # rm -rf ph-ee-env-template/helm/g2p-sandbox/templates/config.yml + cat ph-ee-env-template/helm/g2p-sandbox/Chart.yaml + helm dep up ph-ee-env-template/helm/g2p-sandbox + helm package ph-ee-env-template/helm/g2p-sandbox + helm repo index . + echo "$CERT_FILE" | base64 --decode > b64encoded.pem + chmod 400 b64encoded.pem + ssh -i b64encoded.pem -o StrictHostKeyChecking=No ec2-user@13.233.68.128 sudo mkdir -p /apps/apache-tomcat-7.0.82/webapps/ROOT/images/fynarfin$JIRA_STORY_DIR/ph-ee-g2psandbox-0.0.0$JIRA_STORY + scp -o StrictHostKeyChecking=No -i b64encoded.pem index.yaml ph-ee-g2psandbox-0.0.0$JIRA_STORY.tgz ec2-user@13.233.68.128:~/ + ssh -i b64encoded.pem -o StrictHostKeyChecking=No ec2-user@13.233.68.128 sudo mv -t /apps/apache-tomcat-7.0.82/webapps/ROOT/images/fynarfin$JIRA_STORY_DIR/ph-ee-g2psandbox-0.0.0$JIRA_STORY index.yaml ph-ee-g2psandbox-0.0.0$JIRA_STORY.tgz + build-host-g2p-fyn-chart: + docker: + - image: cimg/python:3.10 + working_directory: ~/repo + environment: + TERM: dumb + steps: + - checkout + - run: rm -f ph-ee-env-labs/helm/g2p-sandbox-fynarfin-SIT/Chart.lock ph-ee-env-labs/helm/g2p-sandbox-fynarfin-SIT/requirements.lock ph-ee-env-labs/helm/g2p-sandbox-fynarfin-SIT/charts/* + - helm/install-helm-client: + version: "v3.8.2" + # - run: "sed -i '12s/.*/version: 0.0.0/' helm/g2p-sandbox-fynarfin-SIT/Chart.yaml" + - run: + name: build-host-g2p-fyn-chart + environment: + JIRA_STORY: '' + JIRA_STORY_DIR: '' + command: | + if [ "$CIRCLE_BRANCH" != "develop" ]; then + PR_NUMBER=$(basename $CIRCLE_PULL_REQUEST) + PR_TITLE=$(curl -sSL "https://api.github.com/repos/fynarfin/$CIRCLE_PROJECT_REPONAME/pulls/$PR_NUMBER" | jq -r '.title') + JIRA_STORY=-$(echo $PR_TITLE | cut -d "[" -f2 | cut -d "]" -f1 | tr '[A-Z]' '[a-z]') + if [ -z "$JIRA_STORY" ]; then echo "Invalid PR title" && exit 1; else echo "Ticket NO: $JIRA_STORY" && JIRA_STORY_DIR=$(echo /jira-story-version); fi + fi + CHART_URL="https://fynarfin.io/images/fynarfin$JIRA_STORY_DIR/ph-ee-g2psandbox-0.0.0$JIRA_STORY" + if curl --output /dev/null --silent --head --fail "$CHART_URL"; then + sed -i "11s@^ *repository:.*\$@ repository: $CHART_URL@" ph-ee-env-labs/helm/g2p-sandbox-fynarfin-SIT/Chart.yaml + sed -i "12s@^ *version:.*\$@ version: 0.0.0$JIRA_STORY@" ph-ee-env-labs/helm/g2p-sandbox-fynarfin-SIT/Chart.yaml + echo "chart used: < $CHART_URL >" + else + CHART_URL="https://fynarfin.io/images/fynarfin/ph-ee-g2psandbox-0.0.0" + echo "chart used: < $CHART_URL >" + fi + sed -i "6s/.*/version: 0.2.0$JIRA_STORY/" ph-ee-env-labs/helm/g2p-sandbox-fynarfin-SIT/Chart.yaml + cat ph-ee-env-labs/helm/g2p-sandbox-fynarfin-SIT/Chart.yaml + helm dep up ph-ee-env-labs/helm/g2p-sandbox-fynarfin-SIT + helm package ph-ee-env-labs/helm/g2p-sandbox-fynarfin-SIT + helm repo index . + echo "$CERT_FILE" | base64 --decode > b64encoded.pem + chmod 400 b64encoded.pem + ssh -i b64encoded.pem -o StrictHostKeyChecking=No ec2-user@13.233.68.128 sudo mkdir -p /apps/apache-tomcat-7.0.82/webapps/ROOT/images/fynarfin$JIRA_STORY_DIR/ph-ee-g2psandbox-fynarfin$JIRA_STORY + scp -o StrictHostKeyChecking=No -i b64encoded.pem index.yaml ph-ee-g2psandbox-fynarfin-0.2.0$JIRA_STORY.tgz ec2-user@13.233.68.128:~/ + ssh -i b64encoded.pem -o StrictHostKeyChecking=No ec2-user@13.233.68.128 sudo mv -t /apps/apache-tomcat-7.0.82/webapps/ROOT/images/fynarfin$JIRA_STORY_DIR/ph-ee-g2psandbox-fynarfin$JIRA_STORY index.yaml ph-ee-g2psandbox-fynarfin-0.2.0$JIRA_STORY.tgz + build-and-host-g2p-sandbox-security: + docker: + - image: cimg/python:3.10 + working_directory: ~/repo + environment: + TERM: dumb + steps: + - checkout + - run: rm -f ph-ee-env-template/helm/g2p-sandbox-security/Chart.lock ph-ee-env-template/helm/g2p-sandbox-security/requirements.lock ph-ee-env-template/helm/g2p-sandbox-security/charts/* + - helm/install-helm-client: + version: "v3.8.2" + - run: + name: build-and-host-g2p-sandbox-security + environment: + JIRA_STORY: '' + JIRA_STORY_DIR: '' + command: | + if [ "$CIRCLE_BRANCH" != "develop" ]; then + PR_NUMBER=$(basename $CIRCLE_PULL_REQUEST) + PR_TITLE=$(curl -sSL "https://api.github.com/repos/fynarfin/$CIRCLE_PROJECT_REPONAME/pulls/$PR_NUMBER" | jq -r '.title') + JIRA_STORY=-$(echo $PR_TITLE | cut -d "[" -f2 | cut -d "]" -f1 | tr '[A-Z]' '[a-z]') + if [ -z "$JIRA_STORY" ]; then echo "Invalid PR title" && exit 1; else echo "Ticket NO: $JIRA_STORY" && JIRA_STORY_DIR=$(echo /jira-story-version); fi + fi + CHART_URL="https://fynarfin.io/images/fynarfin$JIRA_STORY_DIR/ph-ee-engine-0.0.0-SNAPSHOT$JIRA_STORY" + if curl --output /dev/null --silent --head --fail "$CHART_URL"; then + sed -i "10s@^ *repository:.*\$@ repository: $CHART_URL@" ph-ee-env-template/helm/g2p-sandbox-security/Chart.yaml + sed -i "11s@^ *version:.*\$@ version: 0.0.0-SNAPSHOT$JIRA_STORY@" ph-ee-env-template/helm/g2p-sandbox-security/Chart.yaml + echo "chart used: < $CHART_URL >" + else + CHART_URL="https://fynarfin.io/images/fynarfin/ph-ee-engine-0.0.0-SNAPSHOT" + echo "chart used: < $CHART_URL >" + fi + sed -i "5s/.*/version: 0.0.0$JIRA_STORY/" ph-ee-env-template/helm/g2p-sandbox-security/Chart.yaml + cat ph-ee-env-template/helm/g2p-sandbox-security/Chart.yaml + # - run: "sed -i '4s/.*/version: 0.0.0-SNAPSHOT/' ph-ee-env-template/helm/g2p-sandbox-security/requirements.yaml" + # SED & replace dependency with 0.0.0 + helm dep up ph-ee-env-template/helm/g2p-sandbox-security + helm package ph-ee-env-template/helm/g2p-sandbox-security + helm repo index . + echo "$CERT_FILE" | base64 --decode > b64encoded.pem + chmod 400 b64encoded.pem + ssh -i b64encoded.pem -o StrictHostKeyChecking=No ec2-user@13.233.68.128 sudo mkdir -p /apps/apache-tomcat-7.0.82/webapps/ROOT/images/fynarfin$JIRA_STORY_DIR/ph-ee-g2psandbox-security$JIRA_STORY + scp -o StrictHostKeyChecking=No -i b64encoded.pem index.yaml ph-ee-g2psandbox-security-0.0.0$JIRA_STORY.tgz ec2-user@13.233.68.128:~/ + ssh -i b64encoded.pem -o StrictHostKeyChecking=No ec2-user@13.233.68.128 sudo mv -t /apps/apache-tomcat-7.0.82/webapps/ROOT/images/fynarfin$JIRA_STORY_DIR/ph-ee-g2psandbox-security$JIRA_STORY index.yaml ph-ee-g2psandbox-security-0.0.0$JIRA_STORY.tgz + minikube-run-helm-upgrade-and-helm-test: + machine: + image: ubuntu-2004:current + docker_layer_caching: true + resource_class: large + environment: + TERM: dumb + parameters: + namespace: + default: "paymenthub" + description: | + The kubernetes namespace that should be used. + type: string + release-name: + default: "g2p-sandbox" + description: | + Specify a name for the release. + type: string + cluster-name: + default: "minikube" + type: string + service-file-path: + default: https://raw.githubusercontent.com/fynarfin/ph-ee-core/ph-ee-env-labs/develop/.circleci/services.txt + type: string + chart-base-url: + default: https://fynarfin.io/images/fynarfin + type: string + chart-name: + default: ph-ee-g2p-sandbox-ci + type: string + chart-version: + default: 0.0.0 + type: string + steps: + - helm/install-helm-client: + version: "v3.8.2" + - run: + name: run minikube + no_output_timeout: 40m + command: | + free -m + #!/bin/bash + #insatll kubectl-------- + echo hello + sudo apt-get update + sudo apt-get install -y apt-transport-https ca-certificates curl gpg + sudo mkdir -p /etc/apt/keyrings + sudo touch -y /etc/apt/keyrings/kubernetes-apt-keyring.gpg || echo done + curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.28/deb/Release.key | sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg + echo 'deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.28/deb/ /' | sudo tee /etc/apt/sources.list.d/kubernetes.list + sudo apt-get update + sudo apt-get install -y kubelet kubeadm kubectl + sudo apt-mark hold kubelet kubeadm kubectl + + #Setup Minikube + curl -LO https://storage.googleapis.com/minikube/releases/latest/minikube_latest_amd64.deb + sudo dpkg -i minikube_latest_amd64.deb + echo minikube waiting + minikube config set cpus 4 + minikube config set memory 15721 + minikube start #--extra-config=kubelet.max-pods=60 --cpus max --memory max --disk-size 50g + echo "Minikube started-----------------------------------------------------" + minikube addons enable metrics-server + # To check the allocated values + #minikube config get cpus + #minikube config get memory + + MINIKUBE_IP=`minikube ip` + echo $MINIKUBE_IP + # cat ~/.kube/config + + minikube kubectl -- get po -A #Interact with Minikube cluster + kubectl create namespace paymenthub + kubectl get -A namespace + + # # For remote access to minikube uncomment the following lines. + # #---------------------minikube remote aceess start--------------------- + # sudo apt install nginx + # sudo touch /etc/nginx/conf.d/minikube.conf + # echo "create nginx conf" + # sudo chmod 777 -R /etc/nginx/conf.d/ + # echo "changed access" + + # sudo apt-get install apache2-utils -y + # echo "apache2-utils installed" + # htpasswd -bc /home/circleci/project/.htpasswd minikube minikube + + # sudo cat \< /etc/nginx/conf.d/minikube.conf + # server { + # listen 8080; + # listen [::]:8080; + # server_name localhost; + # access_log /home/circleci/project/nginx_access.log; + # auth_basic "Administrators Area"; + # auth_basic_user_file /home/circleci/project/.htpasswd; + + # location / { + # proxy_pass https://$MINIKUBE_IP:8443; + # proxy_ssl_certificate /home/circleci/.minikube/profiles/minikube/client.crt; + # proxy_ssl_certificate_key /home/circleci/.minikube/profiles/minikube/client.key; + # } + # } + # EOF + # sudo service nginx restart || echo 'start nginx' + # SYSTEMD_LESS=FRXMK systemctl status nginx.service + + # sleep 10 + + # echo "test-nginx-proxy" + # curl -u minikube:minikube http://localhost:8080 + + # curl -s https://ngrok-agent.s3.amazonaws.com/ngrok.asc | sudo tee /etc/apt/trusted.gpg.d/ngrok.asc >/dev/null && echo "deb https://ngrok-agent.s3.amazonaws.com buster main" | sudo tee /etc/apt/sources.list.d/ngrok.list && sudo apt update && sudo apt install ngrok + # ngrok config add-authtoken $AUTH_TOKEN + # echo "web_addr: $LOCAL_PORT" >> /home/circleci/.config/ngrok/ngrok.yml + # ngrok http 8080 > /dev/null & + + # echo -n "Extracting ngrok public url ." + # NGROK_PUBLIC_URL="" + # while [ -z "$NGROK_PUBLIC_URL" ]; do + # # Run 'curl' against ngrok API and extract public (using 'sed' command) + # export NGROK_PUBLIC_URL=$(curl --silent --max-time 10 --connect-timeout 5 \ + # --show-error http://127.0.0.1:$LOCAL_PORT/api/tunnels | \ + # sed -nE 's/.*public_url":"https:..([^"]*).*/\1/p') + # sleep 1 + # echo -n "." + # done + # echo ---------copy the below public_URL for NGrok---------- + # echo "https://$NGROK_PUBLIC_URL" + # echo "https://$NGROK_PUBLIC_URL" + + # echo "test ngrok " + # curl -u minikube:minikube https://$NGROK_PUBLIC_URL + # echo "https://$NGROK_PUBLIC_URL" + # # ---------------------minikube remote access end--------------------- + + curl https://baltocdn.com/helm/signing.asc | gpg --dearmor | sudo tee /usr/share/keyrings/helm.gpg > /dev/null + sudo apt-get install apt-transport-https --yes + echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/helm.gpg] https://baltocdn.com/helm/stable/debian/ all main" | sudo tee /etc/apt/sources.list.d/helm-stable-debian.list + #helm install + sudo apt-get update + sudo apt-get install helm + kubectl create namespace paymenthub || echo namespace already exists + minikube ssh -- free -m + echo ------------MEMORY CHECK ----------- + + - run: + no_output_timeout: 20m + name: fetch docker images and helm upgrade + environment: + ORB_CHART_BASE_URL: << parameters.chart-base-url >> + ORB_CHART_NAME: << parameters.chart-name >> + ORB_CHART_VERSION: << parameters.chart-version >> + ORB_PARAM_NAMESPACE: << parameters.namespace >> + ORB_PARAM_RELEASE_NAME: << parameters.release-name >> + JIRA_STORY: '' + JIRA_STORY_DIR: '' + VALUES_TO_OVERRIDE: '' + SERVICE_FILE_PATH: << parameters.service-file-path>> + command: | + function get_services_from_file() { + file=$1 + while IFS= read -r line || [ -n "$line" ]; do + generate_values_to_override $line + done < "$file" + } + + function generate_values_to_override() { + PREFIX="docker.io/" + if [ "$CIRCLE_BRANCH" != "develop" ] && check_for_image_tag ${2#"$PREFIX"} ${JIRA_STORY}; then + echo "image: < $1=$2:$JIRA_STORY >" + VALUES_TO_OVERRIDE+=$(echo "$1=$2:$JIRA_STORY"), + else + echo "image: < $1=$2:latest >" + VALUES_TO_OVERRIDE+=$(echo "$1=$2:latest"), + fi + } + function check_for_image_tag(){ + curl --silent -f --head -lL https://hub.docker.com/v2/repositories/$1/tags/$2/ > /dev/null + } + if [ "$CIRCLE_BRANCH" != "develop" ]; then + + PR_NUMBER=$(basename $CIRCLE_PULL_REQUEST) + PR_TITLE=$(curl -sSL "https://api.github.com/repos/fynarfin/$CIRCLE_PROJECT_REPONAME/pulls/$PR_NUMBER" | jq -r '.title') + JIRA_STORY=$(echo $PR_TITLE | cut -d "[" -f2 | cut -d "]" -f1 | tr '[A-Z]' '[a-z]') + if [ -z "$JIRA_STORY" ]; then echo "Invalid PR title" && exit 1; else echo "Ticket NO: $JIRA_STORY" && JIRA_STORY_DIR=$(echo /jira-story-version); fi + fi + + echo $SERVICE_FILE_PATH + wget $SERVICE_FILE_PATH + filename=$(basename "$SERVICE_FILE_PATH") + #Using sed replace ph-ee-g2psandbox. with empty string + sed -i 's/ph-ee-g2p-sandbox-ci\.p/p/g' $filename + echo $filename + get_services_from_file $filename + + if [ -n "${VALUES_TO_OVERRIDE}" ]; then + VALUES_TO_OVERRIDE=$(echo --set ${VALUES_TO_OVERRIDE::-1}) + echo "VALUES_TO_OVERRIDE: $VALUES_TO_OVERRIDE" + fi + + if [ -n "${ORB_PARAM_NAMESPACE}" ]; then + ORB_PARAM_NAMESPACE=$(echo --namespace ${ORB_PARAM_NAMESPACE}) + fi + if [ -n "${JIRA_STORY}" ]; then + JIRA_STORY=-$(echo $JIRA_STORY) + fi + + # Generating the chart url for deployment + # chart: "https://fynarfin.io/images/ph-ee-g2p-sandbox-ci/ph-ee-g2p-sandbox-ci-0.0.0.tgz" + ORB_PARAM_CHART=$(echo "$ORB_CHART_BASE_URL$JIRA_STORY_DIR/$ORB_CHART_NAME$JIRA_STORY/$ORB_CHART_NAME-$ORB_CHART_VERSION$JIRA_STORY.tgz") + + CHART_URL="$ORB_PARAM_CHART" + if curl --output /dev/null --silent --head --fail "$CHART_URL"; then + echo "chart used: < $CHART_URL >" + # add-repo: "https://fynarfin.io/images/ph-ee-g2p-sandbox-ci" + ORB_PARAM_REPO=$(echo "$ORB_CHART_BASE_URL$JIRA_STORY_DIR/$ORB_CHART_NAME$JIRA_STORY") + else + CHART_URL="https://fynarfin.io/images/ph-ee-g2p-sandbox-ci/ph-ee-g2p-sandbox-ci-0.0.0.tgz" + ORB_PARAM_REPO=$(echo "$ORB_CHART_BASE_URL/$ORB_CHART_NAME") + echo "chart used: < $CHART_URL >" + fi + + echo helm repo add "${ORB_PARAM_RELEASE_NAME}" "${ORB_PARAM_REPO}" + helm repo add "${ORB_PARAM_RELEASE_NAME}" "${ORB_PARAM_REPO}" + + kubectl apply -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/main/example/prometheus-operator-crd/monitoring.coreos.com_servicemonitors.yaml #Install ServiceMonitor + helm repo update + echo "helm upgrade --install ${VALUES_TO_OVERRIDE} ${ORB_PARAM_RELEASE_NAME} ${ORB_PARAM_CHART} ${ORB_PARAM_NAMESPACE}" + echo helm chart install starts + + # Download ph-ee-g2p-sandbox-ci-chart and extract + curl -O $ORB_CHART_BASE_URL$JIRA_STORY_DIR/$ORB_CHART_NAME$JIRA_STORY/$ORB_CHART_NAME-$ORB_CHART_VERSION$JIRA_STORY.tgz && tar xvf $ORB_CHART_NAME-$ORB_CHART_VERSION$JIRA_STORY.tgz + rm -rf $ORB_CHART_NAME-$ORB_CHART_VERSION$JIRA_STORY.tgz + + ORB_PARAM_REPO=$(echo "$ORB_CHART_BASE_URL/$ORB_CHART_NAME") + + EXTRA_VALUES=$(echo "-f ph-ee-g2p-sandbox-ci/values_p1.yaml") + helm upgrade ${EXTRA_VALUES} --install --timeout=1h ${VALUES_TO_OVERRIDE} ${ORB_PARAM_RELEASE_NAME} ${ORB_PARAM_CHART} ${ORB_PARAM_NAMESPACE} + echo --------------------helm upgrade in Phase 1 done--------------------- + EXTRA_VALUES=$(echo "-f ph-ee-g2p-sandbox-ci/values_p2.yaml") + helm upgrade ${EXTRA_VALUES} --install --timeout=1h ${VALUES_TO_OVERRIDE} ${ORB_PARAM_RELEASE_NAME} ${ORB_PARAM_CHART} ${ORB_PARAM_NAMESPACE} + echo --------------------helm upgrade in Phase 2 done--------------------- + echo --------------------helm upgrade is done--------------------- + sleep 1m; + + # ----------------------Post-Installation-Steps-starts--------------------------- + # #ES and Kibana secret creation + # git clone -b 7.17 https://github.com/elastic/helm-charts.git elastic/helm-charts + # cd elastic/helm-charts/elasticsearch/examples/security/ + # make secrets || echo "elastic-secrets" already exists + # git clone -b 7.17 https://github.com/elastic/helm-charts.git elastic/helm-charts + # cd elastic/helm-charts/kibana/examples/security/ + # make secrets || echo "kibana-secrets" already exists + # kubectl get secret elastic-certificate-crt -n default -o yaml | sed 's/namespace: default/namespace: paymenthub/' | kubectl create -f - + # kubectl get secret elastic-certificate-pem -n default -o yaml | sed 's/namespace: default/namespace: paymenthub/' | kubectl create -f - + # kubectl get secret elastic-certificates -n default -o yaml | sed 's/namespace: default/namespace: paymenthub/' | kubectl create -f - + # kubectl get secret elastic-credentials -n default -o yaml | sed 's/namespace: default/namespace: paymenthub/' | kubectl create -f - + # kubectl get secret kibana -n default -o yaml | sed 's/namespace: default/namespace: paymenthub/' | kubectl create -f - + # kubectl get secrets -n paymenthub + # echo ---------secrets created-------- + + # #insatll netcat + # sudo apt install -y netcat + # check_count=0 + # until ((check_count==20)) || nc -vz ph-ee-zeebe-ops 80; do + # echo "Waiting for zeebe-ops service"; + # sleep 5; + # check_count=$(($check_count + 1)); + # done; + # echo ------zeebe-ops service available----------- + # # until nc -vz ph-ee-zeebe-ops 80; do echo "Waiting for zeebe-ops service"; sleep 2; done; + + # #Deploy BPMN + # kubectl port-forward service/ph-ee-zeebe-ops 5000:80 -n paymenthub & #portforward zeebe-ops &' + # git clone https://github.com/fynarfin/ph-ee-env-labs.git fynarfin/ph-ee-env-labs + # cd fynarfin/ph-ee-env-labs/orchestration + # ls + # sed -i "/HOST=/c\HOST=http://localhost:5000/zeebe/upload" deployBpmn.sh + # cat deployBpmn.sh + # cd .. + # sh orchestration/deployBpmn.sh || echo 'deploy Bpmn done' + #------------------Post-Installation-Steps-ends------------------------------- + + - run: + name: Run Helm Tests + command: | + helm test g2p-sandbox --filter name=g2p-sandbox-test-gov --namespace paymenthub || echo test + helm test g2p-sandbox --filter name=g2p-sandbox-test-ams --namespace paymenthub || echo test + + - run: + name: Fetch Integration Test Report + command: | + #!/bin/bash + mkdir -p integration_report/test-report + + echo "Fetch Integration Test Report for ams" + kubectl cp paymenthub/`kubectl get pods -n paymenthub | grep g2p-sandbox-test-ams |cut -d " " -f1`:/ph-ee-connector-integration-test/build integration_report/test-report + # Specify the path to the downloaded file + downloaded_file="integration_report/test-report/cucumber.xml" + # Loop until the file is not empty + while [ ! -s $downloaded_file ]; do + echo "File is empty, waiting..." + sleep 60 # You can adjust the sleep interval as needed + kubectl cp paymenthub/`kubectl get pods -n paymenthub | grep g2p-sandbox-test-ams |cut -d " " -f1`:/ph-ee-connector-integration-test/build/ integration_report/test-report + downloaded_file="integration_report/test-report/cucumber.xml" + done + echo "File is no longer empty, processing..." + mv integration_report/test-report/cucumber.xml integration_report/test-report/cucumber_ams.xml + mv integration_report/test-report/reports/tests/test integration_report/test-report/reports/tests/test_ams + # kubectl cp paymenthubb/`kubectl get pods -n paymenthub | grep g2p-sandbox-test-ams |cut -d " " -f1`:/ph-ee-connector-integration-test/build integration_report/test-report + + for i in $(kubectl get pods -n paymenthub | grep g2p-sandbox-test-ams |cut -d " " -f1); do + echo "--------------------------------------------------------------------Logs of $i Start---------------------------------------------------------------------------" >> all_pod_logs.log + kubectl logs -n paymenthub $i --all-containers=true >> all_pod_logs.log + echo "---------------------------------------------------------------------Logs of $i End----------------------------------------------------------------------------" >> all_pod_logs.log + echo " " >> all_pod_logs.log + echo " " >> all_pod_logs.log + done + + echo "Fetch Integration Test Report for GOV" + kubectl cp paymenthub/`kubectl get pods -n paymenthub | grep g2p-sandbox-test-gov |cut -d " " -f1`:/ph-ee-connector-integration-test/build integration_report/test-report + # Specify the path to the downloaded file + downloaded_file="integration_report/test-report/cucumber.xml" + # Loop until the file is not empty + while [ ! -s $downloaded_file ]; do + echo "File is empty, waiting..." + sleep 60 # You can adjust the sleep interval as needed + kubectl cp paymenthub/`kubectl get pods -n paymenthub | grep g2p-sandbox-test-gov |cut -d " " -f1`:/ph-ee-connector-integration-test/build/ integration_report/test-report + downloaded_file="integration_report/test-report/cucumber.xml" + done + echo "File is no longer empty, processing..." + mv integration_report/test-report/cucumber.xml integration_report/test-report/cucumber_gov.xml + mv integration_report/test-report/reports/tests/test integration_report/test-report/reports/tests/test_gov + + mkdir -p integration_report_final + cp integration_report/test-report/cucumber_gov.xml integration_report_final/ || echo "" + cp integration_report/test-report/cucumber_ams.xml integration_report_final/ || echo "" + + ls integration_report/test-report/ + # kubectl cp paymenthub/`kubectl get pods -n paymenthub | grep g2p-sandbox-test-gov |cut -d " " -f1`:/ph-ee-connector-integration-test/build integration_report/test-report + for i in $(kubectl get pods -n paymenthub |cut -d " " -f1|tail -n +2); do + echo "--------------------------------------------------------------------Logs of $i Start---------------------------------------------------------------------------" >> all_pod_logs.log + kubectl logs -n paymenthub $i --all-containers=true >> all_pod_logs.log + echo "---------------------------------------------------------------------Logs of $i End----------------------------------------------------------------------------" >> all_pod_logs.log + echo " " >> all_pod_logs.log + echo " " >> all_pod_logs.log + done + mv all_pod_logs.log integration_report/test-report/reports/tests/ + + - store_test_results: + path: integration_report_final/ + - store_artifacts: + path: integration_report/test-report/reports/tests + check_for_changes: + executor: docker-executor + steps: + - checkout + - run: + name: Check for changes in billPay + command: | + # Fetch the latest changes + git fetch origin + + # Determine the commit range + if [ -z "$CIRCLE_PULL_REQUEST" ]; then + echo "Not a pull request, skipping check." + echo "export BUILD_BILLPAY=false" >> $BASH_ENV + else + PR_BASE_BRANCH=$(jq -r .base.ref < "$CIRCLE_PULL_REQUEST") + PR_HEAD_BRANCH=$(jq -r .head.ref < "$CIRCLE_PULL_REQUEST") + + # Check for changes in the ph-ee-bill-pay directory + if git diff --quiet origin/$PR_BASE_BRANCH...$PR_HEAD_BRANCH ph-ee-bill-pay; then + echo "No changes in ph-ee-bill-pay, skipping build." + echo "export BUILD_BILLPAY=false" >> $BASH_ENV + else + echo "Changes detected in ph-ee-bill-pay, proceeding with build." + echo "export BUILD_BILLPAY=true" >> $BASH_ENV + fi + fi + - persist_to_workspace: + root: . + paths: + - . + build_and_push_billPay_tag_image: + executor: docker-executor + environment: + JVM_OPTS: -Xmx512m + TERM: dumb + GITHUB_TOKEN: ${GITHUB_TOKEN} + + steps: + - checkout + - setup_remote_docker: + version: 20.10.14 + - run: + name: Build and Push Docker tag Image + command: | + if [ "$BUILD_BILLPAY" == "true" ]; then + IMAGE_TAG=$CIRCLE_TAG + if curl -s -f -u "$DOCKERHUB_USERNAME":"$DOCKERHUB_PASSWORD" "https://hub.docker.com/v2/repositories/fynarfin/ph-ee-bill-pay/tags/$IMAGE_TAG" > /dev/null; then + echo "Skipping the build and push as the tag $IMAGE_TAG already exists in Docker Hub." + exit 0 + fi + cd ph-ee-bill-pay + ./gradlew bootJar + docker build -t "fynarfin/ph-ee-bill-pay:$IMAGE_TAG" . + docker login -u "$DOCKERHUB_USERNAME" -p "$DOCKERHUB_PASSWORD" + docker push "fynarfin/ph-ee-bill-pay:$IMAGE_TAG" + else + echo "Skipping build and push as there are no changes in ph-ee-bill-pay." + fi + + build_and_push_billPay_latest_image: + executor: docker-executor + environment: + JVM_OPTS: -Xmx512m + TERM: dumb + + steps: + - checkout + - setup_remote_docker: + version: 20.10.14 + - run: + name: Build Docker image + command: | + if [ "$BUILD_BILLPAY" == "true" ]; then + cd ph-ee-bill-pay + ./gradlew checkstyleMain + ./gradlew bootJar + docker build -t fynarfin/ph-ee-bill-pay:latest . + if [ "$CIRCLE_BRANCH" != "develop" ]; then + PR_NUMBER=$(basename $CIRCLE_PULL_REQUEST) + PR_TITLE=$(curl -sSL "https://api.github.com/repos/fynarfin/$CIRCLE_PR_REPONAME/pulls/$PR_NUMBER" | jq -r '.title') + JIRA_STORY=$(echo $PR_TITLE | cut -d "[" -f2 | cut -d "]" -f1 | tr '[A-Z]' '[a-z]') + if [ -z "$JIRA_STORY" ]; then echo "Invalid PR title" && exit 1; else echo "Ticket NO: $JIRA_STORY"; fi + docker image tag fynarfin/ph-ee-bill-pay:latest fynarfin/ph-ee-bill-pay:$JIRA_STORY + fi + else + echo "Skipping build as there are no changes in ph-ee-bill-pay." + fi + - run: + name: Login to DockerHub + command: | + if [ "$BUILD_BILLPAY" == "true" ]; then + echo "${DOCKERHUB_PASSWORD}" | docker login -u "${DOCKERHUB_USERNAME}" --password-stdin + else + echo "Skipping DockerHub login as there are no changes in ph-ee-bill-pay." + fi + - run: + name: Push Docker image to DockerHub + command: | + if [ "$BUILD_BILLPAY" == "true" ]; then + if [ "$CIRCLE_BRANCH" = "develop" ]; then + docker push fynarfin/ph-ee-bill-pay:latest + fi + if [ "$CIRCLE_BRANCH" != "develop" ]; then + PR_NUMBER=$(basename $CIRCLE_PULL_REQUEST) + PR_TITLE=$(curl -sSL "https://api.github.com/repos/fynarfin/$CIRCLE_PR_REPONAME/pulls/$PR_NUMBER" | jq -r '.title') + JIRA_STORY=$(echo $PR_TITLE | cut -d "[" -f2 | cut -d "]" -f1 | tr '[A-Z]' '[a-z]') + docker push fynarfin/ph-ee-bill-pay:${JIRA_STORY} + fi + else + echo "Skipping push as there are no changes in ph-ee-bill-pay." + fi + + build_and_push_vouchers_tag_image: + executor: docker-executor + environment: + JVM_OPTS: -Xmx512m + TERM: dumb + GITHUB_TOKEN: ${GITHUB_TOKEN} + + steps: + - checkout + - setup_remote_docker: + version: 20.10.14 + - run: + name: Build and Push Docker tag Image for ph-ee-vouchers + command: | + IMAGE_TAG=$CIRCLE_TAG + if curl -s -f -u "$DOCKERHUB_USERNAME":"$DOCKERHUB_PASSWORD" "https://hub.docker.com/v2/repositories/fynarfin/ph-ee-vouchers/tags/$IMAGE_TAG" > /dev/null; then + echo "Skipping the build and push as the tag $IMAGE_TAG already exists in Docker Hub." + exit 0 + fi + cd ph-ee-vouchers + ./gradlew bootJar + docker build -t "fynarfin/ph-ee-vouchers:$IMAGE_TAG" . + docker login -u "$DOCKERHUB_USERNAME" -p "$DOCKERHUB_PASSWORD" + docker push "fynarfin/ph-ee-vouchers:$IMAGE_TAG" + + build_and_push_vouchers_latest_image: + executor: docker-executor + environment: + JVM_OPTS: -Xmx512m + TERM: dumb + + steps: + - checkout + - setup_remote_docker: + version: 20.10.14 + - run: + name: Build Docker image for ph-ee-vouchers + command: | + cd ph-ee-vouchers + ./gradlew checkstyleMain + ./gradlew bootJar + docker build -t fynarfin/ph-ee-vouchers:latest . + if [ "$CIRCLE_BRANCH" != "develop" ]; then + PR_NUMBER=$(basename $CIRCLE_PULL_REQUEST) + PR_TITLE=$(curl -sSL "https://api.github.com/repos/fynarfin/$CIRCLE_PR_REPONAME/pulls/$PR_NUMBER" | jq -r '.title') + JIRA_STORY=$(echo $PR_TITLE | cut -d "[" -f2 | cut -d "]" -f1 | tr '[A-Z]' '[a-z]') + if [ -z "$JIRA_STORY" ]; then echo "Invalid PR title" && exit 1; else echo "Ticket NO: $JIRA_STORY"; fi + docker image tag fynarfin/ph-ee-vouchers:latest fynarfin/ph-ee-vouchers:$JIRA_STORY + fi + - run: + name: Login to DockerHub + command: echo "${DOCKERHUB_PASSWORD}" | docker login -u "${DOCKERHUB_USERNAME}" --password-stdin + - run: + name: Push Docker image to DockerHub + command: | + if [ "$CIRCLE_BRANCH" = "develop" ]; then + docker push fynarfin/ph-ee-vouchers:latest + fi + if [ "$CIRCLE_BRANCH" != "develop" ]; then + PR_NUMBER=$(basename $CIRCLE_PULL_REQUEST) + PR_TITLE=$(curl -sSL "https://api.github.com/repos/fynarfin/$CIRCLE_PR_REPONAME/pulls/$PR_NUMBER" | jq -r '.title') + JIRA_STORY=$(echo $PR_TITLE | cut -d "[" -f2 | cut -d "]" -f1 | tr '[A-Z]' '[a-z]') + docker push fynarfin/ph-ee-vouchers:${JIRA_STORY} + fi + + deploy: + executor: docker-executor + steps: + - run: + name: Deploy to environment + command: | + echo "Deploying to environment..." + # Add your deployment scripts/commands here + echo "Deployment completed." + +workflows: + version: 2 + build-and-deploy: + jobs: + - check_for_changes + - build_and_push_billPay_tag_image: + filters: + tags: + only: /^v\d+\.\d+\.\d+$/ # Match tags in the format v1.2.3 + context: + - DOCKER + - build_and_push_billPay_latest_image: + requires: + - check_for_changes + context: + - DOCKER + - build_and_push_vouchers_tag_image: + filters: + tags: + only: /^v\d+\.\d+\.\d+$/ # Match tags in the format v1.2.3 + context: + - DOCKER + - build_and_push_vouchers_latest_image: + context: + - DOCKER + - build-and-host-engine: + requires: + - build_and_push_billPay_tag_image + - build_and_push_billPay_latest_image + - build_and_push_vouchers_tag_image + - build_and_push_vouchers_latest_image + context: + - AWS + - Helm + - slack + - build-and-host-g2p-sandbox: + requires: + - build-and-host-engine + context: + - AWS + - Helm + - slack + - build-host-g2p-fyn-chart: + requires: + - build-and-host-g2p-sandbox + context: + - AWS + - Helm + - build-g2p-sandbox-ci-chart: + requires: + - build-host-g2p-fyn-chart + context: + - AWS + - Helm + - slack + - build-and-host-g2p-sandbox-security: + requires: + - build-g2p-sandbox-ci-chart + context: + - AWS + - Helm + - slack + - minikube-run-helm-upgrade-and-helm-test: + context: + - AWS + - Helm + - slack + - Ngrok + requires: + - build-g2p-sandbox-ci-chart + diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..80cab67c6 --- /dev/null +++ b/.gitignore @@ -0,0 +1,33 @@ +target/ +.gradle +build/ +!gradle/wrapper/gradle-wrapper.jar + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ + +### VS Code ### +.vscode/ + +### MAC +.DS_Store diff --git a/README.md b/README.md index 91e9aa6b6..41e36c4e9 100644 --- a/README.md +++ b/README.md @@ -1 +1 @@ -# ph-ee-core \ No newline at end of file +# ph-ee-core diff --git a/build.gradle b/build.gradle new file mode 100644 index 000000000..3c4978e0e --- /dev/null +++ b/build.gradle @@ -0,0 +1,32 @@ +allprojects { + repositories { + mavenLocal() + maven { + url = uri('https://repo.maven.apache.org/maven2') + } + + maven { + url = uri('https://jfrog.sandbox.fynarfin.io/artifactory/fyn-libs-snapshot') + } + } +} + +subprojects { + apply plugin: 'java' + + version = '0.0.1-SNAPSHOT' + + sourceCompatibility = '17' + + repositories { + mavenCentral() + } + + dependencies { + } + + test { + useJUnitPlatform() + } +} + diff --git a/config/checkstyle/checkstyle.xml b/config/checkstyle/checkstyle.xml new file mode 100644 index 000000000..5183efef5 --- /dev/null +++ b/config/checkstyle/checkstyle.xml @@ -0,0 +1,266 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/config/checkstyle/suppressions.xml b/config/checkstyle/suppressions.xml new file mode 100644 index 000000000..f4e5b54c3 --- /dev/null +++ b/config/checkstyle/suppressions.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + diff --git a/config/cleanup.xml b/config/cleanup.xml new file mode 100644 index 000000000..8eb4eaa5f --- /dev/null +++ b/config/cleanup.xml @@ -0,0 +1,71 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/config/formatter.xml b/config/formatter.xml new file mode 100644 index 000000000..b8adbd7f5 --- /dev/null +++ b/config/formatter.xml @@ -0,0 +1,366 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 000000000..033e24c4c Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 000000000..62f495dfe --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,7 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.2-bin.zip +networkTimeout=10000 +validateDistributionUrl=true +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew new file mode 100755 index 000000000..fcb6fca14 --- /dev/null +++ b/gradlew @@ -0,0 +1,248 @@ +#!/bin/sh + +# +# Copyright © 2015-2021 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat new file mode 100644 index 000000000..6689b85be --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,92 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 0 goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/ph-ee-bill-pay/.circleci/config.yml b/ph-ee-bill-pay/.circleci/config.yml new file mode 100644 index 000000000..6b751f1bb --- /dev/null +++ b/ph-ee-bill-pay/.circleci/config.yml @@ -0,0 +1,102 @@ +version: 2.1 +executors: + docker-executor: + docker: + - image: circleci/openjdk:17-buster-node-browsers-legacy + auth: + username: $DOCKERHUB_USERNAME + password: $DOCKERHUB_PASSWORD + +jobs: + build_and_push_tag_image: + executor: docker-executor + environment: + JVM_OPTS: -Xmx512m + TERM: dumb + GITHUB_TOKEN: ${GITHUB_TOKEN} # Add the GitHub token as an environment variable + + steps: + - checkout + - setup_remote_docker: + version: 20.10.14 + - run: + name: Build and Push Docker tag Image + command: | + # Set environment variables + IMAGE_TAG=$CIRCLE_TAG + + # Check if the Docker image with the same tag already exists in Docker Hub + if curl -s -f -u "$DOCKERHUB_USERNAME":"$DOCKERHUB_PASSWORD" "https://hub.docker.com/v2/repositories/fynarfin/ph-ee-bill-pay/tags/$IMAGE_TAG" > /dev/null; then + echo "Skipping the build and push as the tag $IMAGE_TAG already exists in Docker Hub." + exit 0 + fi + + # Build and tag the Docker image + ./gradlew bootJar + docker build -t "fynarfin/ph-ee-bill-pay:$IMAGE_TAG" . + + # Push the Docker image to Docker Hub + docker login -u "$DOCKERHUB_USERNAME" -p "$DOCKERHUB_PASSWORD" + docker push "fynarfin/ph-ee-bill-pay:$IMAGE_TAG" + + # when: always # The job will be executed even if there's no match for the tag filter + + build_and_push_latest_image: + executor: docker-executor + environment: + JVM_OPTS: -Xmx512m + TERM: dumb + + steps: + - checkout + # Install Docker to build and push the image + - setup_remote_docker: + version: 20.10.14 + + # Build the Docker image + - run: + name: Build Docker image + command: | + ./gradlew checkstyleMain + ./gradlew bootJar + docker build -t fynarfin/ph-ee-bill-pay:latest . + if [ "$CIRCLE_BRANCH" != "develop" ]; then + PR_NUMBER=$(basename $CIRCLE_PULL_REQUEST) + PR_TITLE=$(curl -sSL "https://api.github.com/repos/fynarfin/$CIRCLE_PR_REPONAME/pulls/$PR_NUMBER" | jq -r '.title') + JIRA_STORY=$(echo $PR_TITLE | cut -d "[" -f2 | cut -d "]" -f1 | tr '[A-Z]' '[a-z]') + if [ -z "$JIRA_STORY" ]; then echo "Invalid PR title" && exit 1; else echo "Ticket NO: $JIRA_STORY"; fi + docker image tag fynarfin/$CIRCLE_PR_REPONAME:latest fynarfin/$CIRCLE_PR_REPONAME:$JIRA_STORY + fi + + # Log in to DockerHub using environment variables + - run: + name: Login to DockerHub + command: echo "${DOCKERHUB_PASSWORD}" | docker login -u "${DOCKERHUB_USERNAME}" --password-stdin + + # Push the Docker image to DockerHub + - run: + name: Push Docker image to DockerHub + command: | + if [ "$CIRCLE_BRANCH" = "develop" ]; then + docker push fynarfin/ph-ee-bill-pay:latest + fi + if [ "$CIRCLE_BRANCH" != "develop" ]; then + PR_NUMBER=$(basename $CIRCLE_PULL_REQUEST) + PR_TITLE=$(curl -sSL "https://api.github.com/repos/fynarfin/$CIRCLE_PR_REPONAME/pulls/$PR_NUMBER" | jq -r '.title') + JIRA_STORY=$(echo $PR_TITLE | cut -d "[" -f2 | cut -d "]" -f1 | tr '[A-Z]' '[a-z]') + docker push fynarfin/$CIRCLE_PR_REPONAME:${JIRA_STORY} + fi + +workflows: + version: 2 + build-and-push: + jobs: + - build_and_push_tag_image: + filters: + tags: + only: /^v\d+\.\d+\.\d+$/ # Match tags in the format v1.2.3 + context: + - DOCKER + - build_and_push_latest_image: + context: + - DOCKER diff --git a/ph-ee-bill-pay/.gitignore b/ph-ee-bill-pay/.gitignore new file mode 100644 index 000000000..c2065bc26 --- /dev/null +++ b/ph-ee-bill-pay/.gitignore @@ -0,0 +1,37 @@ +HELP.md +.gradle +build/ +!gradle/wrapper/gradle-wrapper.jar +!**/src/main/**/build/ +!**/src/test/**/build/ + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache +bin/ +!**/src/main/**/bin/ +!**/src/test/**/bin/ + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr +out/ +!**/src/main/**/out/ +!**/src/test/**/out/ + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ + +### VS Code ### +.vscode/ diff --git a/ph-ee-bill-pay/.jpb/persistence-units.xml b/ph-ee-bill-pay/.jpb/persistence-units.xml new file mode 100644 index 000000000..292da4eeb --- /dev/null +++ b/ph-ee-bill-pay/.jpb/persistence-units.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/ph-ee-bill-pay/Dockerfile b/ph-ee-bill-pay/Dockerfile new file mode 100644 index 000000000..7477fba78 --- /dev/null +++ b/ph-ee-bill-pay/Dockerfile @@ -0,0 +1,5 @@ +FROM openjdk:17 +EXPOSE 8080 + +COPY build/libs/*.jar ./ +CMD java -jar *.jar diff --git a/ph-ee-bill-pay/LICENSE b/ph-ee-bill-pay/LICENSE new file mode 100644 index 000000000..a612ad981 --- /dev/null +++ b/ph-ee-bill-pay/LICENSE @@ -0,0 +1,373 @@ +Mozilla Public License Version 2.0 +================================== + +1. Definitions +-------------- + +1.1. "Contributor" + means each individual or legal entity that creates, contributes to + the creation of, or owns Covered Software. + +1.2. "Contributor Version" + means the combination of the Contributions of others (if any) used + by a Contributor and that particular Contributor's Contribution. + +1.3. "Contribution" + means Covered Software of a particular Contributor. + +1.4. "Covered Software" + means Source Code Form to which the initial Contributor has attached + the notice in Exhibit A, the Executable Form of such Source Code + Form, and Modifications of such Source Code Form, in each case + including portions thereof. + +1.5. "Incompatible With Secondary Licenses" + means + + (a) that the initial Contributor has attached the notice described + in Exhibit B to the Covered Software; or + + (b) that the Covered Software was made available under the terms of + version 1.1 or earlier of the License, but not also under the + terms of a Secondary License. + +1.6. "Executable Form" + means any form of the work other than Source Code Form. + +1.7. "Larger Work" + means a work that combines Covered Software with other material, in + a separate file or files, that is not Covered Software. + +1.8. "License" + means this document. + +1.9. "Licensable" + means having the right to grant, to the maximum extent possible, + whether at the time of the initial grant or subsequently, any and + all of the rights conveyed by this License. + +1.10. "Modifications" + means any of the following: + + (a) any file in Source Code Form that results from an addition to, + deletion from, or modification of the contents of Covered + Software; or + + (b) any new file in Source Code Form that contains any Covered + Software. + +1.11. "Patent Claims" of a Contributor + means any patent claim(s), including without limitation, method, + process, and apparatus claims, in any patent Licensable by such + Contributor that would be infringed, but for the grant of the + License, by the making, using, selling, offering for sale, having + made, import, or transfer of either its Contributions or its + Contributor Version. + +1.12. "Secondary License" + means either the GNU General Public License, Version 2.0, the GNU + Lesser General Public License, Version 2.1, the GNU Affero General + Public License, Version 3.0, or any later versions of those + licenses. + +1.13. "Source Code Form" + means the form of the work preferred for making modifications. + +1.14. "You" (or "Your") + means an individual or a legal entity exercising rights under this + License. For legal entities, "You" includes any entity that + controls, is controlled by, or is under common control with You. For + purposes of this definition, "control" means (a) the power, direct + or indirect, to cause the direction or management of such entity, + whether by contract or otherwise, or (b) ownership of more than + fifty percent (50%) of the outstanding shares or beneficial + ownership of such entity. + +2. License Grants and Conditions +-------------------------------- + +2.1. Grants + +Each Contributor hereby grants You a world-wide, royalty-free, +non-exclusive license: + +(a) under intellectual property rights (other than patent or trademark) + Licensable by such Contributor to use, reproduce, make available, + modify, display, perform, distribute, and otherwise exploit its + Contributions, either on an unmodified basis, with Modifications, or + as part of a Larger Work; and + +(b) under Patent Claims of such Contributor to make, use, sell, offer + for sale, have made, import, and otherwise transfer either its + Contributions or its Contributor Version. + +2.2. Effective Date + +The licenses granted in Section 2.1 with respect to any Contribution +become effective for each Contribution on the date the Contributor first +distributes such Contribution. + +2.3. Limitations on Grant Scope + +The licenses granted in this Section 2 are the only rights granted under +this License. No additional rights or licenses will be implied from the +distribution or licensing of Covered Software under this License. +Notwithstanding Section 2.1(b) above, no patent license is granted by a +Contributor: + +(a) for any code that a Contributor has removed from Covered Software; + or + +(b) for infringements caused by: (i) Your and any other third party's + modifications of Covered Software, or (ii) the combination of its + Contributions with other software (except as part of its Contributor + Version); or + +(c) under Patent Claims infringed by Covered Software in the absence of + its Contributions. + +This License does not grant any rights in the trademarks, service marks, +or logos of any Contributor (except as may be necessary to comply with +the notice requirements in Section 3.4). + +2.4. Subsequent Licenses + +No Contributor makes additional grants as a result of Your choice to +distribute the Covered Software under a subsequent version of this +License (see Section 10.2) or under the terms of a Secondary License (if +permitted under the terms of Section 3.3). + +2.5. Representation + +Each Contributor represents that the Contributor believes its +Contributions are its original creation(s) or it has sufficient rights +to grant the rights to its Contributions conveyed by this License. + +2.6. Fair Use + +This License is not intended to limit any rights You have under +applicable copyright doctrines of fair use, fair dealing, or other +equivalents. + +2.7. Conditions + +Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted +in Section 2.1. + +3. Responsibilities +------------------- + +3.1. Distribution of Source Form + +All distribution of Covered Software in Source Code Form, including any +Modifications that You create or to which You contribute, must be under +the terms of this License. You must inform recipients that the Source +Code Form of the Covered Software is governed by the terms of this +License, and how they can obtain a copy of this License. You may not +attempt to alter or restrict the recipients' rights in the Source Code +Form. + +3.2. Distribution of Executable Form + +If You distribute Covered Software in Executable Form then: + +(a) such Covered Software must also be made available in Source Code + Form, as described in Section 3.1, and You must inform recipients of + the Executable Form how they can obtain a copy of such Source Code + Form by reasonable means in a timely manner, at a charge no more + than the cost of distribution to the recipient; and + +(b) You may distribute such Executable Form under the terms of this + License, or sublicense it under different terms, provided that the + license for the Executable Form does not attempt to limit or alter + the recipients' rights in the Source Code Form under this License. + +3.3. Distribution of a Larger Work + +You may create and distribute a Larger Work under terms of Your choice, +provided that You also comply with the requirements of this License for +the Covered Software. If the Larger Work is a combination of Covered +Software with a work governed by one or more Secondary Licenses, and the +Covered Software is not Incompatible With Secondary Licenses, this +License permits You to additionally distribute such Covered Software +under the terms of such Secondary License(s), so that the recipient of +the Larger Work may, at their option, further distribute the Covered +Software under the terms of either this License or such Secondary +License(s). + +3.4. Notices + +You may not remove or alter the substance of any license notices +(including copyright notices, patent notices, disclaimers of warranty, +or limitations of liability) contained within the Source Code Form of +the Covered Software, except that You may alter any license notices to +the extent required to remedy known factual inaccuracies. + +3.5. Application of Additional Terms + +You may choose to offer, and to charge a fee for, warranty, support, +indemnity or liability obligations to one or more recipients of Covered +Software. However, You may do so only on Your own behalf, and not on +behalf of any Contributor. You must make it absolutely clear that any +such warranty, support, indemnity, or liability obligation is offered by +You alone, and You hereby agree to indemnify every Contributor for any +liability incurred by such Contributor as a result of warranty, support, +indemnity or liability terms You offer. You may include additional +disclaimers of warranty and limitations of liability specific to any +jurisdiction. + +4. Inability to Comply Due to Statute or Regulation +--------------------------------------------------- + +If it is impossible for You to comply with any of the terms of this +License with respect to some or all of the Covered Software due to +statute, judicial order, or regulation then You must: (a) comply with +the terms of this License to the maximum extent possible; and (b) +describe the limitations and the code they affect. Such description must +be placed in a text file included with all distributions of the Covered +Software under this License. Except to the extent prohibited by statute +or regulation, such description must be sufficiently detailed for a +recipient of ordinary skill to be able to understand it. + +5. Termination +-------------- + +5.1. The rights granted under this License will terminate automatically +if You fail to comply with any of its terms. However, if You become +compliant, then the rights granted under this License from a particular +Contributor are reinstated (a) provisionally, unless and until such +Contributor explicitly and finally terminates Your grants, and (b) on an +ongoing basis, if such Contributor fails to notify You of the +non-compliance by some reasonable means prior to 60 days after You have +come back into compliance. Moreover, Your grants from a particular +Contributor are reinstated on an ongoing basis if such Contributor +notifies You of the non-compliance by some reasonable means, this is the +first time You have received notice of non-compliance with this License +from such Contributor, and You become compliant prior to 30 days after +Your receipt of the notice. + +5.2. If You initiate litigation against any entity by asserting a patent +infringement claim (excluding declaratory judgment actions, +counter-claims, and cross-claims) alleging that a Contributor Version +directly or indirectly infringes any patent, then the rights granted to +You by any and all Contributors for the Covered Software under Section +2.1 of this License shall terminate. + +5.3. In the event of termination under Sections 5.1 or 5.2 above, all +end user license agreements (excluding distributors and resellers) which +have been validly granted by You or Your distributors under this License +prior to termination shall survive termination. + +************************************************************************ +* * +* 6. Disclaimer of Warranty * +* ------------------------- * +* * +* Covered Software is provided under this License on an "as is" * +* basis, without warranty of any kind, either expressed, implied, or * +* statutory, including, without limitation, warranties that the * +* Covered Software is free of defects, merchantable, fit for a * +* particular purpose or non-infringing. The entire risk as to the * +* quality and performance of the Covered Software is with You. * +* Should any Covered Software prove defective in any respect, You * +* (not any Contributor) assume the cost of any necessary servicing, * +* repair, or correction. This disclaimer of warranty constitutes an * +* essential part of this License. No use of any Covered Software is * +* authorized under this License except under this disclaimer. * +* * +************************************************************************ + +************************************************************************ +* * +* 7. Limitation of Liability * +* -------------------------- * +* * +* Under no circumstances and under no legal theory, whether tort * +* (including negligence), contract, or otherwise, shall any * +* Contributor, or anyone who distributes Covered Software as * +* permitted above, be liable to You for any direct, indirect, * +* special, incidental, or consequential damages of any character * +* including, without limitation, damages for lost profits, loss of * +* goodwill, work stoppage, computer failure or malfunction, or any * +* and all other commercial damages or losses, even if such party * +* shall have been informed of the possibility of such damages. This * +* limitation of liability shall not apply to liability for death or * +* personal injury resulting from such party's negligence to the * +* extent applicable law prohibits such limitation. Some * +* jurisdictions do not allow the exclusion or limitation of * +* incidental or consequential damages, so this exclusion and * +* limitation may not apply to You. * +* * +************************************************************************ + +8. Litigation +------------- + +Any litigation relating to this License may be brought only in the +courts of a jurisdiction where the defendant maintains its principal +place of business and such litigation shall be governed by laws of that +jurisdiction, without reference to its conflict-of-law provisions. +Nothing in this Section shall prevent a party's ability to bring +cross-claims or counter-claims. + +9. Miscellaneous +---------------- + +This License represents the complete agreement concerning the subject +matter hereof. If any provision of this License is held to be +unenforceable, such provision shall be reformed only to the extent +necessary to make it enforceable. Any law or regulation which provides +that the language of a contract shall be construed against the drafter +shall not be used to construe this License against a Contributor. + +10. Versions of the License +--------------------------- + +10.1. New Versions + +Mozilla Foundation is the license steward. Except as provided in Section +10.3, no one other than the license steward has the right to modify or +publish new versions of this License. Each version will be given a +distinguishing version number. + +10.2. Effect of New Versions + +You may distribute the Covered Software under the terms of the version +of the License under which You originally received the Covered Software, +or under the terms of any subsequent version published by the license +steward. + +10.3. Modified Versions + +If you create software not governed by this License, and you want to +create a new license for such software, you may create and use a +modified version of this License if you rename the license and remove +any references to the name of the license steward (except to note that +such modified license differs from this License). + +10.4. Distributing Source Code Form that is Incompatible With Secondary +Licenses + +If You choose to distribute Source Code Form that is Incompatible With +Secondary Licenses under the terms of this version of the License, the +notice described in Exhibit B of this License must be attached. + +Exhibit A - Source Code Form License Notice +------------------------------------------- + + This Source Code Form is subject to the terms of the Mozilla Public + License, v. 2.0. If a copy of the MPL was not distributed with this + file, You can obtain one at http://mozilla.org/MPL/2.0/. + +If it is not possible or desirable to put the notice in a particular +file, then You may include the notice in a location (such as a LICENSE +file in a relevant directory) where a recipient would be likely to look +for such a notice. + +You may add additional accurate notices of copyright ownership. + +Exhibit B - "Incompatible With Secondary Licenses" Notice +--------------------------------------------------------- + + This Source Code Form is "Incompatible With Secondary Licenses", as + defined by the Mozilla Public License, v. 2.0. diff --git a/ph-ee-bill-pay/README.md b/ph-ee-bill-pay/README.md new file mode 100644 index 000000000..20d185223 --- /dev/null +++ b/ph-ee-bill-pay/README.md @@ -0,0 +1,13 @@ +# ph-ee-bill-pay + +## Spotless +Use below command to execute the spotless apply. +```shell +./gradlew spotlessApply +``` + +## Checkstyle +Use below command to execute the checkstyle test. +```shell +./gradlew checkstyleMain +``` diff --git a/ph-ee-bill-pay/build.gradle b/ph-ee-bill-pay/build.gradle new file mode 100644 index 000000000..75ee3f168 --- /dev/null +++ b/ph-ee-bill-pay/build.gradle @@ -0,0 +1,305 @@ +/* + * This file was generated by the Gradle 'init' task. + */ + +plugins { + id 'java' + id 'maven-publish' + id 'eclipse' + id 'checkstyle' + id 'org.springframework.boot' version '2.6.2' + id 'com.diffplug.spotless' version '6.19.0' + id 'net.ltgt.errorprone' version '3.1.0' +} + +repositories { + mavenLocal() + maven { + url = uri('https://repo.maven.apache.org/maven2') + } + + maven { + url = uri('https://jfrog.sandbox.fynarfin.io/artifactory/fyn-libs-snapshot') + } +} + +apply plugin:'com.diffplug.spotless' +spotless { + format 'misc', { + target '**/*.md', '**/*.properties', '**/.gitignore', '**/.openapi-generator-ignore', '**/*.yml', '**/*.xml', '**/**.json', '**/*.sql' + targetExclude '**/build/**','**/gsmastub/**', '**/bin/**', '**/.settings/**', '**/.idea/**', '**/.gradle/**', '**/gradlew.bat', '**/licenses/**', '**/banner.txt', '.vscode/**' + indentWithSpaces(4) + endWithNewline() + trimTrailingWhitespace() + } + + groovyGradle { + target '*.gradle', '**/*.gradle' + targetExclude '**/build/**', '**/gsmastub/**' + greclipse() + indentWithSpaces(4) + endWithNewline() + trimTrailingWhitespace() + } + + lineEndings 'UNIX' +} + +ext { + springBootVersion = '2.6.2' +} + +dependencies { + implementation 'com.google.code.gson:gson:2.8.9' + implementation 'org.mifos:ph-ee-connector-common:1.9.1-SNAPSHOT' + implementation 'org.apache.camel.springboot:camel-spring-boot-starter:3.12.0' + implementation('org.springframework.boot:spring-boot-starter-web:2.6.2') + implementation "org.springframework.boot:spring-boot-starter-actuator:$springBootVersion" + implementation 'org.apache.camel:camel-endpointdsl:3.12.0' + implementation 'org.apache.camel:camel-jetty:3.12.0' + implementation 'org.apache.camel:camel-http:3.12.0' + implementation 'org.springframework:spring-web:5.3.15' + implementation 'org.apache.camel:camel-bean-validator:3.12.0' + implementation 'org.apache.camel:camel-undertow:3.12.0' + implementation 'org.apache.camel.springboot:camel-jackson-starter:3.12.0' + implementation 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.13.1' + implementation 'org.json:json:20211205' + implementation 'io.camunda:zeebe-client-java:8.1.1' + testImplementation 'org.springframework.boot:spring-boot-starter-test:2.6.2' + testImplementation 'org.springframework.boot:spring-boot-starter-test:2.6.2' + implementation 'javax.servlet:javax.servlet-api:3.1.0' + implementation 'commons-codec:commons-codec:1.15' + implementation 'commons-io:commons-io:2.11.0' + implementation 'io.springfox:springfox-swagger-ui:3.0.0' + implementation 'io.springfox:springfox-oas:3.0.0' + implementation 'com.github.joschi.jackson:jackson-datatype-threetenbp:2.6.4' + implementation "org.springdoc:springdoc-openapi-ui:1.6.11" + implementation 'org.projectlombok:lombok:1.18.22' + annotationProcessor 'org.projectlombok:lombok:1.18.24' + checkstyle 'com.puppycrawl.tools:checkstyle:10.9.3' + checkstyle 'com.github.sevntu-checkstyle:sevntu-checks:1.44.1' + implementation 'com.diffplug.gradle.spotless:spotless:2.4.1' + implementation 'com.diffplug.spotless:spotless-plugin-gradle:6.17.0' +} + +configure(this) { + // NOTE: order matters! + apply plugin: 'java' + apply plugin: 'idea' + apply plugin: 'eclipse' + apply plugin: 'checkstyle' + apply plugin: 'net.ltgt.errorprone' + configurations { + implementation.setCanBeResolved(true) + api.setCanBeResolved(true) + } + tasks.withType(JavaCompile) { + options.compilerArgs += [ + "-Xlint:unchecked", + "-Xlint:cast", + "-Xlint:auxiliaryclass", + "-Xlint:deprecation", + "-Xlint:dep-ann", + "-Xlint:divzero", + "-Xlint:empty", + "-Xlint:exports", + "-Xlint:fallthrough", + "-Xlint:finally", + "-Xlint:module", + "-Xlint:opens", + "-Xlint:options", + "-Xlint:overloads", + "-Xlint:overrides", + "-Xlint:path", + "-Xlint:processing", + "-Xlint:removal", + "-Xlint:requires-automatic", + "-Xlint:requires-transitive-automatic", + "-Xlint:try", + "-Xlint:varargs", + "-Xlint:preview", + "-Xlint:static", + // -Werror needs to be disabled because EclipseLink's static weaving doesn't generate warning-free code + // and during an IntelliJ recompilation, it fails + //"-Werror", + "-Xmaxwarns", + 1500, + "-Xmaxerrs", + 1500 + ] + options.deprecation = true + } + // Configuration for the spotless plugin + // https://github.com/diffplug/spotless/tree/main/plugin-gradle + spotless { + java { + targetExclude '**/build/**', '**/bin/**', '**/out/**', '**/gsmastub/**' + importOrder() //sort imports alphabetically + removeUnusedImports() + eclipse().configFile "$rootDir/config/formatter.xml" + endWithNewline() + trimTrailingWhitespace() + // Enforce style modifier order + custom 'Modifier ordering', { + def modifierRanking = [ + public : 1, + protected : 2, + private : 3, + abstract : 4, + default : 5, + static : 6, + final : 7, + transient : 8, + volatile : 9, + synchronized: 10, + native : 11, + strictfp : 12] + // Find any instance of multiple modifiers. Lead with a non-word character to avoid + // accidental matching against for instance, "an alternative default value" + it.replaceAll(/\W(?:public |protected |private |abstract |default |static |final |transient |volatile |synchronized |native |strictfp ){2,}/, { + // Do not replace the leading non-word character. Identify the modifiers + it.replaceAll(/(?:public |protected |private |abstract |default |static |final |transient |volatile |synchronized |native |strictfp ){2,}/, { + // Sort the modifiers according to the ranking above + it.split().sort({ modifierRanking[it] }).join(' ') + ' ' + } + ) + } + ) + } + } + lineEndings 'UNIX' + } + // If we are running Gradle within Eclipse to enhance classes, + // set the classes directory to point to Eclipse's default build directory + if (project.hasProperty('env') && project.getProperty('env') == 'eclipse') { + sourceSets.main.java.outputDir = file("$projectDir/bin/main") + } + // Configuration for the Checkstyle plugin + // https://docs.gradle.org/current/userguide/checkstyle_plugin.html + dependencies { + checkstyle 'com.puppycrawl.tools:checkstyle:10.3.1' + checkstyle 'com.github.sevntu-checkstyle:sevntu-checks:1.42.0' + } + // Configuration for the errorprone plugin + // https://github.com/tbroyer/gradle-errorprone-plugin + dependencies { + errorprone "com.google.errorprone:error_prone_core:2.20.0" + } + + tasks.withType(JavaCompile) { + options.errorprone { + enabled = project.gradle.startParameter.taskNames.contains('build') || project.gradle.startParameter.taskNames.contains('check') + disableWarningsInGeneratedCode = true + excludedPaths = ".*/build/.*" + disable( + // TODO Remove disabled checks from this list, by fixing remaining usages + "UnusedVariable", + "TypeParameterUnusedInFormals", + "EmptyBlockTag", + "MissingSummary", + "InvalidParam", + "ReturnFromVoid", + "AlmostJavadoc", + "InvalidBlockTag", + "JavaUtilDate", // TODO FINERACT-1298 + "ReturnValueIgnored", + "DirectInvocationOnMock", + "CanIgnoreReturnValueSuggester", + "SameNameButDifferent", // Until errorprone recognizes Lombok + "MultiVariableDeclaration", // Until errorprone recognizes Lombok + "UnnecessaryDefaultInEnumSwitch" // FINERACT-1911 + ) + error( + "DefaultCharset", + "RemoveUnusedImports", + "WaitNotInLoop", + "ThreeLetterTimeZoneID", + "VariableNameSameAsType", + "UnnecessaryParentheses", + "MultipleTopLevelClasses", + "MixedMutabilityReturnType", + "AssertEqualsArgumentOrderChecker", + "EmptySetMultibindingContributions", + "BigDecimalEquals", + "MixedArrayDimensions", + "PackageLocation", + "UseBinds", + "BadImport", + "IntLongMath", + "FloatCast", + "ReachabilityFenceUsage", + "StreamResourceLeak", + "TruthIncompatibleType", + "ByteBufferBackingArray", + "OrphanedFormatString", + "CatchAndPrintStackTrace", + "ObjectToString", + "StringSplitter", + "AssertThrowsMultipleStatements", + "BoxedPrimitiveConstructor", + "EmptyCatch", + "BoxedPrimitiveEquality", + "SynchronizeOnNonFinalField", + "WildcardImport", + "PrivateConstructorForNoninstantiableModule", + "ClassCanBeStatic", + "ClassNewInstance", + "UnnecessaryStaticImport", + "UnsafeFinalization", + "JavaTimeDefaultTimeZone", + "JodaPlusMinusLong", + "SwitchDefault", + "VarTypeName", + "ArgumentSelectionDefectChecker", + "CompareToZero", + "InjectOnConstructorOfAbstractClass", + "ImmutableEnumChecker", + "NarrowingCompoundAssignment", + "MissingCasesInEnumSwitch", + "ReferenceEquality", + "UndefinedEquals", + "UnescapedEntity", + "ModifyCollectionInEnhancedForLoop", + "NonCanonicalType", + "InvalidInlineTag", + "MutablePublicArray", + "StaticAssignmentInConstructor", + "ProtectedMembersInFinalClass", + "OperatorPrecedence", + "EqualsGetClass", + "EqualsUnsafeCast", + "DoubleBraceInitialization", + "UnusedNestedClass", + "UnusedMethod", + "ModifiedButNotUsed", + "InconsistentCapitalization", + "MissingOverride", + ) + } + } +} + + + + +group = 'org.mifos' +version = '1.0.0-SNAPSHOT' +sourceCompatibility = JavaVersion.VERSION_17 +targetCompatibility = JavaVersion.VERSION_17 + +test { + useJUnitPlatform() +} + +publishing { + publications { + maven(MavenPublication) { + from(components.java) + } + } +} + + +tasks.withType(JavaCompile) { + options.encoding = 'UTF-8' +} diff --git a/ph-ee-bill-pay/config/billPay-cleanup.xml b/ph-ee-bill-pay/config/billPay-cleanup.xml new file mode 100644 index 000000000..8eb4eaa5f --- /dev/null +++ b/ph-ee-bill-pay/config/billPay-cleanup.xml @@ -0,0 +1,71 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ph-ee-bill-pay/config/billPay-formatter.xml b/ph-ee-bill-pay/config/billPay-formatter.xml new file mode 100644 index 000000000..b8adbd7f5 --- /dev/null +++ b/ph-ee-bill-pay/config/billPay-formatter.xml @@ -0,0 +1,366 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ph-ee-bill-pay/config/checkstyle/checkstyle.xml b/ph-ee-bill-pay/config/checkstyle/checkstyle.xml new file mode 100644 index 000000000..5183efef5 --- /dev/null +++ b/ph-ee-bill-pay/config/checkstyle/checkstyle.xml @@ -0,0 +1,266 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ph-ee-bill-pay/config/checkstyle/suppressions.xml b/ph-ee-bill-pay/config/checkstyle/suppressions.xml new file mode 100644 index 000000000..f4e5b54c3 --- /dev/null +++ b/ph-ee-bill-pay/config/checkstyle/suppressions.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + diff --git a/ph-ee-bill-pay/gradle/wrapper/gradle-wrapper.jar b/ph-ee-bill-pay/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 000000000..033e24c4c Binary files /dev/null and b/ph-ee-bill-pay/gradle/wrapper/gradle-wrapper.jar differ diff --git a/ph-ee-bill-pay/gradle/wrapper/gradle-wrapper.properties b/ph-ee-bill-pay/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 000000000..774fae876 --- /dev/null +++ b/ph-ee-bill-pay/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.1-bin.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/ph-ee-bill-pay/gradlew b/ph-ee-bill-pay/gradlew new file mode 100755 index 000000000..fcb6fca14 --- /dev/null +++ b/ph-ee-bill-pay/gradlew @@ -0,0 +1,248 @@ +#!/bin/sh + +# +# Copyright © 2015-2021 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/ph-ee-bill-pay/gradlew.bat b/ph-ee-bill-pay/gradlew.bat new file mode 100644 index 000000000..6689b85be --- /dev/null +++ b/ph-ee-bill-pay/gradlew.bat @@ -0,0 +1,92 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 0 goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/ph-ee-bill-pay/settings.gradle b/ph-ee-bill-pay/settings.gradle new file mode 100644 index 000000000..0d8f26a67 --- /dev/null +++ b/ph-ee-bill-pay/settings.gradle @@ -0,0 +1 @@ +rootProject.name = 'ph-ee-bill-pay' diff --git a/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/PheeBillPayApplication.java b/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/PheeBillPayApplication.java new file mode 100644 index 000000000..022dd564d --- /dev/null +++ b/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/PheeBillPayApplication.java @@ -0,0 +1,18 @@ +package org.mifos.pheebillpay; + +import org.mifos.pheebillpay.utils.AbstractApplicationConfiguration; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cache.annotation.EnableCaching; +import org.springframework.context.annotation.ComponentScan; + +@EnableCaching +@SpringBootApplication +@ComponentScan("org.mifos.pheebillpay") +public class PheeBillPayApplication extends AbstractApplicationConfiguration { + + public static void main(String[] args) { + SpringApplication.run(PheeBillPayApplication.class, args); + } + +} diff --git a/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/api/definition/BillInquiryApi.java b/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/api/definition/BillInquiryApi.java new file mode 100644 index 000000000..051af8a6e --- /dev/null +++ b/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/api/definition/BillInquiryApi.java @@ -0,0 +1,23 @@ +package org.mifos.pheebillpay.api.definition; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import java.util.concurrent.ExecutionException; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestHeader; +import org.springframework.web.bind.annotation.RequestParam; + +@Tag(name = "GOV") +public interface BillInquiryApi { + + @Operation(summary = "Bill Inquiry API from Payer FSP to PBB") + @GetMapping("/bills/{billId}") + ResponseEntity billInquiry(@RequestHeader(value = "Platform-TenantId") String tenantId, + @RequestHeader(value = "X-CorrelationID") String correlationId, @RequestHeader(value = "X-CallbackURL") String callbackURL, + @RequestHeader(value = "Payer-FSP-Id") String payerFspId, @PathVariable(value = "billId") String billId, + @RequestParam(value = "fields", defaultValue = "inquiry") String field) throws ExecutionException, InterruptedException; +} + + diff --git a/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/api/definition/BillPaymentsApi.java b/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/api/definition/BillPaymentsApi.java new file mode 100644 index 000000000..73635de76 --- /dev/null +++ b/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/api/definition/BillPaymentsApi.java @@ -0,0 +1,21 @@ +package org.mifos.pheebillpay.api.definition; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import java.util.concurrent.ExecutionException; +import org.mifos.pheebillpay.data.BillPaymentsReqDTO; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestHeader; + +@Tag(name = "GOV") +public interface BillPaymentsApi { + + @Operation(summary = "Bill Payments API from Payer FSP to PBB") + @PostMapping("/paymentNotifications") + ResponseEntity billPayments(@RequestHeader(value = "X-Platform-TenantId") String tenantId, + @RequestHeader(value = "X-CorrelationID") String correlationId, @RequestHeader(value = "X-CallbackURL") String callbackURL, + @RequestHeader(value = "X-PayerFSP-Id") String payerFspId, @RequestBody BillPaymentsReqDTO body) + throws ExecutionException, InterruptedException; +} diff --git a/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/api/definition/BillRtpReqApi.java b/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/api/definition/BillRtpReqApi.java new file mode 100644 index 000000000..c75d83867 --- /dev/null +++ b/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/api/definition/BillRtpReqApi.java @@ -0,0 +1,21 @@ +package org.mifos.pheebillpay.api.definition; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import java.util.concurrent.ExecutionException; +import org.mifos.pheebillpay.data.BillRTPReqDTO; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestHeader; + +@Tag(name = "GOV") +public interface BillRtpReqApi { + + @Operation(summary = "Bill RTP Req API from Bill Agg to PBB") + @PostMapping("/billTransferRequests") + ResponseEntity billRTPReq(@RequestHeader(value = "X-Platform-TenantId") String tenantId, + @RequestHeader(value = "X-Client-Correlation-ID") String correlationId, + @RequestHeader(value = "X-Callback-URL") String callbackUrl, @RequestHeader(value = "X-Biller-Id") String billerId, + @RequestBody BillRTPReqDTO billRTPReqDTO) throws ExecutionException, InterruptedException; +} diff --git a/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/api/definition/BillStatusApi.java b/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/api/definition/BillStatusApi.java new file mode 100644 index 000000000..b1125e783 --- /dev/null +++ b/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/api/definition/BillStatusApi.java @@ -0,0 +1,23 @@ +package org.mifos.pheebillpay.api.definition; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import java.util.concurrent.ExecutionException; +import org.mifos.pheebillpay.data.BillStatusReqDTO; +import org.mifos.pheebillpay.data.BillStatusResponseDTO; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestHeader; + +@Tag(name = "GOV") +public interface BillStatusApi { + + @Operation(summary = "Bill Status API ") + @GetMapping("/transferRequests/{correlationId}") + ResponseEntity billStatus(@RequestHeader(value = "Platform-TenantId") String tenantId, + @RequestHeader(value = "X-CorrelationID") String correlationId, @RequestHeader(value = "X-Biller-Id") String billerId, + @RequestHeader(value = "billId") String billId, @PathVariable(value = "correlationId") String transferRequestId, + @RequestBody BillStatusReqDTO billStatusReqDTO) throws ExecutionException, InterruptedException; +} diff --git a/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/api/definition/PayerRtpRespApi.java b/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/api/definition/PayerRtpRespApi.java new file mode 100644 index 000000000..4ac86f1fa --- /dev/null +++ b/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/api/definition/PayerRtpRespApi.java @@ -0,0 +1,21 @@ +package org.mifos.pheebillpay.api.definition; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import java.util.concurrent.ExecutionException; +import org.mifos.pheebillpay.data.PayerRTPResponse; +import org.mifos.pheebillpay.data.ResponseDTO; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestHeader; + +@Tag(name = "GOV") +public interface PayerRtpRespApi { + + @Operation(summary = "Bill RTP Resp API from PFI to PBB") + @PutMapping("/billTransferRequests") + ResponseEntity billRTPResp(@RequestHeader(value = "X-Platform-TenantId") String tenantId, + @RequestHeader(value = "X-Client-Correlation-ID") String correlationId, @RequestHeader(value = "X-Biller-Id") String billerId, + @RequestBody PayerRTPResponse payerRTPResponse) throws ExecutionException, InterruptedException; +} diff --git a/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/api/implementation/BillInquiryController.java b/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/api/implementation/BillInquiryController.java new file mode 100644 index 000000000..0f0f465b4 --- /dev/null +++ b/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/api/implementation/BillInquiryController.java @@ -0,0 +1,42 @@ +package org.mifos.pheebillpay.api.implementation; + +import java.util.concurrent.ExecutionException; +import org.mifos.pheebillpay.api.definition.BillInquiryApi; +import org.mifos.pheebillpay.data.BillInquiryResponseDTO; +import org.mifos.pheebillpay.service.BillInquiryService; +import org.mifos.pheebillpay.service.ValidateHeaders; +import org.mifos.pheebillpay.utils.HeaderConstants; +import org.mifos.pheebillpay.validators.HeaderValidator; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.RestController; + +@RestController() +public class BillInquiryController implements BillInquiryApi { + + @Autowired + private BillInquiryService billInquiryService; + + @Override + @ValidateHeaders(requiredHeaders = { HeaderConstants.PLATFORM_TENANT_ID, HeaderConstants.X_CORRELATION_ID, + HeaderConstants.X_CALLBACKURL, + HeaderConstants.PAYER_FSP_ID }, validatorClass = HeaderValidator.class, validationFunction = "validateBillInquiryRequest") + public ResponseEntity billInquiry(String tenantId, String correlationId, String callbackURL, String payerFspId, String billId, + String field) throws ExecutionException, InterruptedException { + BillInquiryResponseDTO billInquiryResponseDTO = new BillInquiryResponseDTO(); + try { + billInquiryResponseDTO + .setTransactionId(billInquiryService.billInquiry(tenantId, correlationId, callbackURL, payerFspId, billId, field)); + + } catch (Exception e) { + return ResponseEntity.badRequest().build(); + } + if (billInquiryResponseDTO.getTransactionId().equals("Exception in starting workflow") + || billInquiryResponseDTO.getTransactionId().equals("Participant Not Onboarded")) { + return (ResponseEntity) ResponseEntity.status(HttpStatus.NOT_FOUND).body(billInquiryResponseDTO); + } else { + return (ResponseEntity) ResponseEntity.status(HttpStatus.ACCEPTED).body(billInquiryResponseDTO); + } + } +} diff --git a/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/api/implementation/BillPaymentsController.java b/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/api/implementation/BillPaymentsController.java new file mode 100644 index 000000000..53a4a5281 --- /dev/null +++ b/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/api/implementation/BillPaymentsController.java @@ -0,0 +1,51 @@ +package org.mifos.pheebillpay.api.implementation; + +import java.util.concurrent.ExecutionException; +import org.mifos.connector.common.channel.dto.PhErrorDTO; +import org.mifos.pheebillpay.api.definition.BillPaymentsApi; +import org.mifos.pheebillpay.data.BillInquiryResponseDTO; +import org.mifos.pheebillpay.data.BillPaymentsReqDTO; +import org.mifos.pheebillpay.service.BillPaymentsService; +import org.mifos.pheebillpay.service.ValidateHeaders; +import org.mifos.pheebillpay.utils.HeaderConstants; +import org.mifos.pheebillpay.validators.BillPayValidator; +import org.mifos.pheebillpay.validators.HeaderValidator; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.RestController; + +@RestController +public class BillPaymentsController implements BillPaymentsApi { + + @Autowired + private BillPaymentsService billPaymentsService; + + @Autowired + private BillPayValidator billPayValidator; + + @Override + @ValidateHeaders(requiredHeaders = { HeaderConstants.X_PLATFORM_TENANT_ID, HeaderConstants.X_CORRELATION_ID, + HeaderConstants.X_CALLBACKURL, + HeaderConstants.X_PAYER_FSP_ID }, validatorClass = HeaderValidator.class, validationFunction = "validateBillPaymentRequest") + public ResponseEntity billPayments(String tenantId, String correlationId, String callbackURL, String payerFspId, + BillPaymentsReqDTO body) throws ExecutionException { + BillInquiryResponseDTO billInquiryResponseDTO = new BillInquiryResponseDTO(); + + // validate for request body + PhErrorDTO phErrorDTO = billPayValidator.validateBillPayments(body); + if (phErrorDTO != null) { + return ResponseEntity.status(HttpStatus.BAD_REQUEST).body((T) phErrorDTO); + } + + try { + billInquiryResponseDTO + .setTransactionId(billPaymentsService.billPayments(tenantId, correlationId, callbackURL, payerFspId, body)); + + } catch (Exception e) { + return ResponseEntity.badRequest().build(); + } + return ResponseEntity.status(HttpStatus.ACCEPTED).body((T) billInquiryResponseDTO); + } + +} diff --git a/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/api/implementation/BillRTPReqController.java b/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/api/implementation/BillRTPReqController.java new file mode 100644 index 000000000..6cb21adc0 --- /dev/null +++ b/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/api/implementation/BillRTPReqController.java @@ -0,0 +1,52 @@ +package org.mifos.pheebillpay.api.implementation; + +import java.util.concurrent.ExecutionException; +import org.mifos.connector.common.channel.dto.PhErrorDTO; +import org.mifos.pheebillpay.api.definition.BillRtpReqApi; +import org.mifos.pheebillpay.data.BillRTPReqDTO; +import org.mifos.pheebillpay.data.ResponseDTO; +import org.mifos.pheebillpay.service.BillRTPReqService; +import org.mifos.pheebillpay.service.ValidateHeaders; +import org.mifos.pheebillpay.utils.BillPayEnum; +import org.mifos.pheebillpay.utils.HeaderConstants; +import org.mifos.pheebillpay.validators.HeaderValidator; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.RestController; + +@RestController +public class BillRTPReqController implements BillRtpReqApi { + + private Logger logger = LoggerFactory.getLogger(BillRTPReqController.class); + + @Autowired + private BillRTPReqService billRTPReqService; + + @Override + @ValidateHeaders(requiredHeaders = { HeaderConstants.X_PLATFORM_TENANT_ID, HeaderConstants.X_CLIENT_CORRELATION_ID, + HeaderConstants.X_CALLBACK_URL, HeaderConstants.X_REGISTERING_INSTITUTION_ID, + HeaderConstants.X_BILLER_ID }, validatorClass = HeaderValidator.class, validationFunction = "validateBillRTPRequest") + public ResponseEntity billRTPReq(String tenantId, String correlationId, String callbackUrl, String billerId, + BillRTPReqDTO billRTPReqDTO) throws ExecutionException, InterruptedException { + + try { + PhErrorDTO phErrorDTO = billRTPReqService.billRtpReq(tenantId, correlationId, callbackUrl, billerId, billRTPReqDTO); + + if (phErrorDTO != null) { + return ResponseEntity.status(HttpStatus.BAD_REQUEST).body((T) phErrorDTO); + } + + } catch (Exception e) { + logger.info(e.getMessage()); + ResponseDTO responseDTO = new ResponseDTO(BillPayEnum.FAILED_RESPONSE_CODE.getValue(), + BillPayEnum.FAILED_RESPONSE_MESSAGE.getValue(), correlationId); + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body((T) responseDTO); + } + ResponseDTO responseDTO = new ResponseDTO(BillPayEnum.SUCCESS_RESPONSE_CODE.getValue(), + BillPayEnum.SUCCESS_RESPONSE_MESSAGE.getValue(), correlationId); + return ResponseEntity.status(HttpStatus.ACCEPTED).body((T) responseDTO); + } +} diff --git a/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/api/implementation/BillStatusController.java b/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/api/implementation/BillStatusController.java new file mode 100644 index 000000000..3a30ecb32 --- /dev/null +++ b/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/api/implementation/BillStatusController.java @@ -0,0 +1,73 @@ +package org.mifos.pheebillpay.api.implementation; + +import java.util.concurrent.ExecutionException; +import org.mifos.pheebillpay.api.definition.BillStatusApi; +import org.mifos.pheebillpay.data.BillStatusReqDTO; +import org.mifos.pheebillpay.data.BillStatusResponseDTO; +import org.mifos.pheebillpay.data.TrasactionDTO; +import org.mifos.pheebillpay.service.BillStatusService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.RestController; + +@RestController +public class BillStatusController implements BillStatusApi { + + @Autowired + private BillStatusService billStatusService; + + private Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Override + public ResponseEntity billStatus(String tenantId, String correlationId, String billerId, String billId, + String transferRequestId, BillStatusReqDTO body) throws ExecutionException, InterruptedException { + logger.info("Bill Status API called"); + BillStatusResponseDTO bill = new BillStatusResponseDTO(); + TrasactionDTO trasactionDTO = new TrasactionDTO(); + try { + logger.info("Bill Status API called"); + trasactionDTO = billStatusService.billStatus(tenantId, correlationId, billerId, billId, transferRequestId, body); + bill = convertToBillStatusResponseDTO(trasactionDTO, body); + if (trasactionDTO.getId() == 0) { + logger.info("Transaction not found"); + return ResponseEntity.status(HttpStatus.NOT_FOUND).body(bill); + } + } catch (Exception e) { + return ResponseEntity.badRequest().build(); + } + logger.info("Txn found response sent"); + return ResponseEntity.status(HttpStatus.OK).body(bill); + } + + private BillStatusResponseDTO convertToBillStatusResponseDTO(TrasactionDTO trasactionDTO, BillStatusReqDTO body) { + BillStatusResponseDTO bill = new BillStatusResponseDTO(); + if (trasactionDTO.getId() == 0) { + bill.setResponseCode("01"); + bill.setResponseDescription("Transaction not found"); + bill.setRtpId(body.getRtpId()); + bill.setRequestStatus("Failed"); + } else { + bill.setResponseCode("00"); + bill.setResponseDescription("Request Successfully received by Payments BB"); + bill.setRtpId(body.getRtpId()); + if (trasactionDTO.getState().equals("SUCCESS")) { + bill.setRequestStatus("COM"); + } else if (trasactionDTO.getState().equals("IN_PROGRESS")) { + bill.setRequestStatus("PND"); + } else if (trasactionDTO.getState().equals("INITIATED")) { + bill.setRequestStatus("PND"); + } else if (trasactionDTO.getState().equals("ACCEPTED")) { + bill.setRequestStatus("ACCEPTED"); + } else if (trasactionDTO.getState().equals("REQUEST_ACCEPTED")) { + bill.setRequestStatus("REQUEST_ACCEPTED"); + } else if (trasactionDTO.getState().equals("FAILED")) { + bill.setRequestStatus("FAILED"); + } + bill.setLastUpdateDate(trasactionDTO.getCompletedAt()); + } + return bill; + } +} diff --git a/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/api/implementation/PayerRtpRespController.java b/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/api/implementation/PayerRtpRespController.java new file mode 100644 index 000000000..d4a29757b --- /dev/null +++ b/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/api/implementation/PayerRtpRespController.java @@ -0,0 +1,30 @@ +package org.mifos.pheebillpay.api.implementation; + +import com.fasterxml.jackson.databind.ObjectMapper; +import io.camunda.zeebe.client.ZeebeClient; +import java.util.concurrent.ExecutionException; +import org.mifos.pheebillpay.api.definition.PayerRtpRespApi; +import org.mifos.pheebillpay.data.PayerRTPResponse; +import org.mifos.pheebillpay.data.ResponseDTO; +import org.mifos.pheebillpay.utils.BillPayEnum; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Controller; + +@Controller +public class PayerRtpRespController implements PayerRtpRespApi { + + @Autowired(required = false) + private ZeebeClient zeebeClient; + @Autowired + private ObjectMapper objectMapper; + + @Override + public ResponseEntity billRTPResp(String tenantId, String correlationId, String billerId, + PayerRTPResponse payerRTPResponse) throws ExecutionException, InterruptedException { + ResponseDTO responseDTO = new ResponseDTO(BillPayEnum.SUCCESS_RESPONSE_CODE.getValue(), + BillPayEnum.SUCCESS_RESPONSE_MESSAGE.getValue(), correlationId); + return ResponseEntity.status(HttpStatus.ACCEPTED).body(responseDTO); + } +} diff --git a/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/camel/routes/BillInquiryRouteBuilder.java b/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/camel/routes/BillInquiryRouteBuilder.java new file mode 100644 index 000000000..eff454a8d --- /dev/null +++ b/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/camel/routes/BillInquiryRouteBuilder.java @@ -0,0 +1,66 @@ +package org.mifos.pheebillpay.camel.routes; + +import static org.mifos.pheebillpay.utils.BillPayEnum.FAILED_RESPONSE_CODE; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.apache.camel.Exchange; +import org.apache.camel.LoggingLevel; +import org.mifos.connector.common.camel.ErrorHandlerRouteBuilder; +import org.mifos.pheebillpay.data.Bill; +import org.mifos.pheebillpay.data.ResponseDTO; +import org.mifos.pheebillpay.zeebe.ZeebeVariables; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component +public class BillInquiryRouteBuilder extends ErrorHandlerRouteBuilder { + + private Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Autowired + private Bill billDetails; + + @Autowired + ResponseDTO responseDTO; + + @Override + public void configure() { + + from("direct:bill-inquiry-response").routeId("bill-inquiry-response").log("Triggering callback for bill inquiry response") + .setHeader(Exchange.HTTP_RESPONSE_CODE, constant(200)).process(exchange -> { + if (exchange.getProperty(ZeebeVariables.BILL_INQUIRY_RESPONSE) != null) { + Object obj = exchange.getProperty(ZeebeVariables.BILL_INQUIRY_RESPONSE); + ObjectMapper objectMapper = new ObjectMapper(); + String jsonString = objectMapper.writeValueAsString(obj); + exchange.getIn().setBody(jsonString); + logger.debug("Bill Inquiry Response: {} ", jsonString); + } else { + exchange.getIn().setHeader(Exchange.HTTP_RESPONSE_CODE, constant(400)); + responseDTO = setFailureMessage(exchange); + ObjectMapper objectMapper = new ObjectMapper(); + String jsonString = objectMapper.writeValueAsString(responseDTO); + exchange.getIn().setBody(jsonString); + logger.debug("Bill Inquiry Failure Response: {}", jsonString); + } + }).log(LoggingLevel.DEBUG, "Sending bill inquiry response to callback URL: ${exchangeProperty.X-CallbackURL}") + .toD("${exchangeProperty.X-CallbackURL}" + "?bridgeEndpoint=true&throwExceptionOnFailure=false").process(exchange -> { + // Access the HTTP response code + int responseCode = exchange.getMessage().getHeader(Exchange.HTTP_RESPONSE_CODE, Integer.class); + logger.info(String.valueOf(responseCode)); + String responseBody = exchange.getIn().getBody(String.class); + logger.info(responseBody); + + }); + } + + private ResponseDTO setFailureMessage(Exchange exchange) { + ResponseDTO responseDTO1 = new ResponseDTO(); + responseDTO1.setResponseCode(FAILED_RESPONSE_CODE.getValue()); + responseDTO1.setResponseDescription(exchange.getProperty(ZeebeVariables.ERROR_INFORMATION).toString()); + responseDTO1.setRequestID(exchange.getProperty(ZeebeVariables.CLIENTCORRELATIONID).toString()); + return responseDTO1; + } + +} diff --git a/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/camel/routes/BillPaymentNotificationRouteBuilder.java b/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/camel/routes/BillPaymentNotificationRouteBuilder.java new file mode 100644 index 000000000..0301f4b74 --- /dev/null +++ b/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/camel/routes/BillPaymentNotificationRouteBuilder.java @@ -0,0 +1,51 @@ +package org.mifos.pheebillpay.camel.routes; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.apache.camel.Exchange; +import org.mifos.connector.common.camel.ErrorHandlerRouteBuilder; +import org.mifos.pheebillpay.data.BillPaymentsResponseDTO; +import org.mifos.pheebillpay.zeebe.ZeebeVariables; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component +public class BillPaymentNotificationRouteBuilder extends ErrorHandlerRouteBuilder { + + private Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Autowired + BillPaymentsResponseDTO billPaymentsResponseDTO; + + @Override + public void configure() { + + from("direct:paymentNotification-response").routeId("paymentNotification-response").log("Bill Inquiry over, moving to bill payment") + .setHeader("Content-Type", constant("application/json")).process(exchange -> { + BillPaymentsResponseDTO responseDTO = setResponseBody(exchange); + exchange.getIn().setHeader(ZeebeVariables.PLATFORM_TENANT, exchange.getIn().getHeader(ZeebeVariables.PLATFORM_TENANT)); + exchange.getIn().setHeader(ZeebeVariables.CLIENTCORRELATIONID, + exchange.getIn().getHeader(ZeebeVariables.CLIENTCORRELATIONID)); + exchange.getIn().setHeader(ZeebeVariables.PAYER_FSP, exchange.getIn().getHeader(ZeebeVariables.PAYER_FSP)); + exchange.getIn().setHeader(ZeebeVariables.CALLBACK_URL, exchange.getProperty(ZeebeVariables.CALLBACK_URL)); + ObjectMapper objectMapper = new ObjectMapper(); + String jsonString = objectMapper.writeValueAsString(responseDTO); + exchange.getIn().setBody(jsonString); + }).log("Payment Notification Body: ${body}").log("Payment Notification Headers: ${headers}") + .toD("${exchangeProperty.X-CallbackURL}" + "?bridgeEndpoint=true&throwExceptionOnFailure=false"); + + } + + private BillPaymentsResponseDTO setResponseBody(Exchange exchange) { + + billPaymentsResponseDTO.setCode(exchange.getProperty("code").toString()); + billPaymentsResponseDTO.setStatus(exchange.getProperty("status").toString()); + billPaymentsResponseDTO.setReason(exchange.getProperty("reason").toString()); + billPaymentsResponseDTO.setBillId(exchange.getIn().getHeader(ZeebeVariables.BILL_ID).toString()); + billPaymentsResponseDTO.setRequestID(exchange.getIn().getHeader(ZeebeVariables.CLIENTCORRELATIONID).toString()); + return billPaymentsResponseDTO; + + } + +} diff --git a/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/camel/routes/BillRTPRespRouteBuilder.java b/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/camel/routes/BillRTPRespRouteBuilder.java new file mode 100644 index 000000000..775180763 --- /dev/null +++ b/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/camel/routes/BillRTPRespRouteBuilder.java @@ -0,0 +1,48 @@ +package org.mifos.pheebillpay.camel.routes; + +import static org.mifos.pheebillpay.utils.BillPayEnum.SUCCESS_RESPONSE_CODE; +import static org.mifos.pheebillpay.utils.BillPayEnum.SUCCESS_RESPONSE_MESSAGE; + +import org.apache.camel.Exchange; +import org.json.JSONObject; +import org.mifos.connector.common.camel.ErrorHandlerRouteBuilder; +import org.mifos.pheebillpay.data.ResponseDTO; +import org.mifos.pheebillpay.zeebe.ZeebeVariables; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component +public class BillRTPRespRouteBuilder extends ErrorHandlerRouteBuilder { + + private Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Autowired + ResponseDTO responseDTO; + + @Override + public void configure() { + + from("direct:bill-rtp-resp").routeId("bill-rtp-resp").log("Sending response for bill rtp request") + .setHeader(Exchange.HTTP_RESPONSE_CODE, constant(200)).setBody(exchange -> { + JSONObject response = setResponseBody(exchange.getProperty(ZeebeVariables.CLIENTCORRELATIONID).toString()); + exchange.setProperty("response", response); + return response; + }); + + from("direct:aync-response").routeId("aync-response").log("Setting response for request for bill inquiry") + .setHeader(Exchange.HTTP_RESPONSE_CODE, constant(202)).setBody(constant("Request Processing")); + } + + private JSONObject setResponseBody(String clientCorrelationId) { + + JSONObject response = new JSONObject(); + responseDTO.setResponseCode(SUCCESS_RESPONSE_CODE.toString()); + responseDTO.setResponseDescription(SUCCESS_RESPONSE_MESSAGE.toString()); + responseDTO.setRequestID(clientCorrelationId); + response.put("BillPaymentsResponse", responseDTO); + return response; + } + +} diff --git a/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/camel/routes/BillerFetchRouteBuilder.java b/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/camel/routes/BillerFetchRouteBuilder.java new file mode 100644 index 000000000..fc56f14d1 --- /dev/null +++ b/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/camel/routes/BillerFetchRouteBuilder.java @@ -0,0 +1,90 @@ +package org.mifos.pheebillpay.camel.routes; + +import org.mifos.connector.common.camel.ErrorHandlerRouteBuilder; +import org.mifos.pheebillpay.data.Bill; +import org.mifos.pheebillpay.data.BillInquiryResponseDTO; +import org.mifos.pheebillpay.properties.BillerDetails; +import org.mifos.pheebillpay.properties.BillerDetailsProperties; +import org.mifos.pheebillpay.zeebe.ZeebeVariables; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +@Component +public class BillerFetchRouteBuilder extends ErrorHandlerRouteBuilder { + + private Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Autowired + BillInquiryResponseDTO billInquiryResponseDTO; + + @Autowired + private Bill billDetails; + + @Value("${billPay.billIdEmpty}") + private String billIdEmpty; + @Value("${billPay.billIdEmptyOriginal}") + private String billIdEmptyOriginal; + + @Autowired + private BillerDetailsProperties billerDetailsProperties; + + @Override + public void configure() { + + from("direct:biller-fetch").routeId("biller-fetch").log("Received request for biller fetch").process(exchange -> { + String billId = exchange.getIn().getHeader("billId").toString(); + logger.debug("Bill Id: {}", billId); + BillerDetails billerDetails = getBillDetails(billId); + if (billerDetails != null) { + if (billerDetails.getId().equals(billId)) { + if (billId.equals(billIdEmptyOriginal)) { + exchange.setProperty(ZeebeVariables.BILL_ID, billIdEmpty); + } else { + exchange.setProperty(ZeebeVariables.BILL_ID, billId); + } + exchange.setProperty("billerDetails", billerDetails); + exchange.setProperty("billerId", billerDetails.getId()); + exchange.setProperty("billerName", billerDetails.getBiller()); + exchange.setProperty("billerType", billerDetails.getBillerCategory()); + exchange.setProperty("billerAccount", billerDetails.getBillerAccount()); + exchange.setProperty("billerFetchFailed", false); + } else { + logger.debug("Biller details not found for bill id: {}", billId); + exchange.setProperty(ZeebeVariables.ERROR_INFORMATION, "Unindentified Biller: Bill Id does not exist in biller table"); + exchange.setProperty("billerFetchFailed", true); + } + } else { + logger.debug("Biller details not found for bill id: {}", billId); + exchange.setProperty(ZeebeVariables.ERROR_INFORMATION, "Unindentified Biller: Payer FI prefix does not match"); + exchange.setProperty("billerDetails", null); + exchange.setProperty("billerFetchFailed", true); + + } + + }); + + } + + private BillerDetails getBillDetails(String billId) { + boolean flag = false; + BillerDetails billerDetails1 = new BillerDetails(); + for (BillerDetails billerDetails : billerDetailsProperties.getDetails()) { + logger.info("Biller Details: {}", billerDetails.toString()); + String prefix = billId.substring(0, 2); + if (billerDetails.getId().equals(billId)) { + return billerDetails; + } else if (billerDetails.getId().contains(prefix)) { + flag = true; + billerDetails1 = billerDetails; + + } + } + if (flag) { + return billerDetails1; + } + return null; + } +} diff --git a/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/data/Alias.java b/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/data/Alias.java new file mode 100644 index 000000000..0856df6e8 --- /dev/null +++ b/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/data/Alias.java @@ -0,0 +1,26 @@ +package org.mifos.pheebillpay.data; + +import com.fasterxml.jackson.annotation.JsonAnySetter; +import java.util.HashMap; +import java.util.Map; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +public class Alias { + + private String aliasType; + private String aliasId; + + private Map additionalProperties = new HashMap<>(); + + @JsonAnySetter + public void setAdditionalProperty(String name, Object value) { + additionalProperties.put(name, value); + } +} diff --git a/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/data/Bill.java b/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/data/Bill.java new file mode 100644 index 000000000..ee87d2674 --- /dev/null +++ b/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/data/Bill.java @@ -0,0 +1,28 @@ +package org.mifos.pheebillpay.data; + +import com.fasterxml.jackson.annotation.JsonAnySetter; +import java.util.HashMap; +import java.util.Map; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import org.springframework.stereotype.Component; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +@Component +public class Bill { + + private String billerName; + private double amount; + + private Map additionalProperties = new HashMap<>(); + + @JsonAnySetter + public void setAdditionalProperty(String name, Object value) { + additionalProperties.put(name, value); + } +} diff --git a/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/data/BillDetails.java b/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/data/BillDetails.java new file mode 100644 index 000000000..6633689cd --- /dev/null +++ b/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/data/BillDetails.java @@ -0,0 +1,17 @@ +package org.mifos.pheebillpay.data; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +public class BillDetails { + + private String billId; + private String billerName; + private Double amount; +} diff --git a/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/data/BillInquiryResponseDTO.java b/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/data/BillInquiryResponseDTO.java new file mode 100644 index 000000000..5ca9d6497 --- /dev/null +++ b/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/data/BillInquiryResponseDTO.java @@ -0,0 +1,19 @@ +package org.mifos.pheebillpay.data; + +import java.io.Serializable; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import org.springframework.stereotype.Component; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +@Component +public class BillInquiryResponseDTO implements Serializable { + + private String transactionId; + private String error; +} diff --git a/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/data/BillPaymentsReqDTO.java b/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/data/BillPaymentsReqDTO.java new file mode 100644 index 000000000..796afe7be --- /dev/null +++ b/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/data/BillPaymentsReqDTO.java @@ -0,0 +1,77 @@ +package org.mifos.pheebillpay.data; + +import com.fasterxml.jackson.annotation.JsonAnySetter; +import java.io.Serializable; +import java.util.HashMap; +import java.util.Map; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import org.springframework.stereotype.Component; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +@Component +public class BillPaymentsReqDTO implements Serializable { + + private String clientCorrelationId; + private String billInquiryRequestId; + private String billId; + private String paymentReferenceID; + + private Map additionalProperties = new HashMap<>(); + + @JsonAnySetter + public void setAdditionalProperty(String name, Object value) { + additionalProperties.put(name, value); + } + + @Override + public String toString() { + return "BillPaymentsReqDTO{" + "clientCorrelationId='" + clientCorrelationId + '\'' + ", billInquiryRequestId='" + + billInquiryRequestId + '\'' + ", billId='" + billId + '\'' + ", paymentReferenceID='" + paymentReferenceID + '\'' + '}'; + } + + public String getClientCorrelationId() { + return clientCorrelationId; + } + + public void setClientCorrelationId(String clientCorrelationId) { + this.clientCorrelationId = clientCorrelationId; + } + + public String getBillInquiryRequestId() { + return billInquiryRequestId; + } + + public void setBillInquiryRequestId(String billInquiryRequestId) { + this.billInquiryRequestId = billInquiryRequestId; + } + + public String getBillId() { + return billId; + } + + public void setBillId(String billId) { + this.billId = billId; + } + + public String getPaymentReferenceID() { + return paymentReferenceID; + } + + public void setPaymentReferenceID(String paymentReferenceID) { + this.paymentReferenceID = paymentReferenceID; + } + + public BillPaymentsReqDTO(String clientCorrelationId, String billInquiryRequestId, String billId, String paymentReferenceID) { + this.clientCorrelationId = clientCorrelationId; + this.billInquiryRequestId = billInquiryRequestId; + this.billId = billId; + this.paymentReferenceID = paymentReferenceID; + } + +} diff --git a/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/data/BillPaymentsResponseDTO.java b/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/data/BillPaymentsResponseDTO.java new file mode 100644 index 000000000..2627fc4b8 --- /dev/null +++ b/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/data/BillPaymentsResponseDTO.java @@ -0,0 +1,75 @@ +package org.mifos.pheebillpay.data; + +import java.io.Serializable; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import org.springframework.stereotype.Component; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor + +/* + * Sample response { "RequestID": "915251236706", “code”: “00” “reason”: “Transaction Successful” "billId”: + * “123456789101112”, “status”: “ACK” } + * + */ +@Component +public class BillPaymentsResponseDTO implements Serializable { + + private String code; + private String reason; + private String requestID; + private String billId; + private String status; + + public String getRequestID() { + return requestID; + } + + public void setRequestID(String requestID) { + this.requestID = requestID; + } + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } + + public String getCode() { + return code; + } + + public void setCode(String code) { + this.code = code; + } + + public String getReason() { + return reason; + } + + public void setReason(String reason) { + this.reason = reason; + } + + public String getBillId() { + return billId; + } + + public void setBillId(String billId) { + this.billId = billId; + } + + @Override + public String toString() { + return "BillPaymentsResponseDTO{" + "code='" + code + '\'' + ", reason='" + reason + '\'' + ", requestID='" + requestID + '\'' + + ", billId='" + billId + '\'' + ", status='" + status + '\'' + '}'; + } + +} diff --git a/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/data/BillRTPReqDTO.java b/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/data/BillRTPReqDTO.java new file mode 100644 index 000000000..4b636bfd0 --- /dev/null +++ b/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/data/BillRTPReqDTO.java @@ -0,0 +1,31 @@ +package org.mifos.pheebillpay.data; + +import com.fasterxml.jackson.annotation.JsonAnySetter; +import java.io.Serializable; +import java.util.HashMap; +import java.util.Map; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +public class BillRTPReqDTO implements Serializable { + + private String clientCorrelationId; + private String billID; + private String requestType; + private PayerFSPDetail payerFspDetails; + private Alias alias; + private Bill billDetails; + private Map additionalProperties = new HashMap<>(); + + @JsonAnySetter + public void setAdditionalProperty(String name, Object value) { + additionalProperties.put(name, value); + } + +} diff --git a/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/data/BillRTPResponseDTO.java b/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/data/BillRTPResponseDTO.java new file mode 100644 index 000000000..b29853a64 --- /dev/null +++ b/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/data/BillRTPResponseDTO.java @@ -0,0 +1,19 @@ +package org.mifos.pheebillpay.data; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +public class BillRTPResponseDTO { + + private String requestId; + private String rtpId; + private String billId; + private String rtpStatus; + private String rejectReason; +} diff --git a/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/data/BillStatusReqDTO.java b/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/data/BillStatusReqDTO.java new file mode 100644 index 000000000..5f868b4dd --- /dev/null +++ b/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/data/BillStatusReqDTO.java @@ -0,0 +1,17 @@ +package org.mifos.pheebillpay.data; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +public class BillStatusReqDTO { + + private String rtpId; + private String requestId; + +} diff --git a/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/data/BillStatusResponseDTO.java b/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/data/BillStatusResponseDTO.java new file mode 100644 index 000000000..3dae04a24 --- /dev/null +++ b/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/data/BillStatusResponseDTO.java @@ -0,0 +1,22 @@ +package org.mifos.pheebillpay.data; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +public class BillStatusResponseDTO { + + private String responseCode; + private String responseDescription; + private String rtpId; + private String requestStatus; + private String paymentReferenceID; + private String voucherNumber; + private long lastUpdateDate; + +} diff --git a/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/data/PayerFSPDetail.java b/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/data/PayerFSPDetail.java new file mode 100644 index 000000000..da3111254 --- /dev/null +++ b/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/data/PayerFSPDetail.java @@ -0,0 +1,25 @@ +package org.mifos.pheebillpay.data; + +import com.fasterxml.jackson.annotation.JsonAnySetter; +import java.util.HashMap; +import java.util.Map; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +public class PayerFSPDetail { + + private String payerFSPID; + private String financialAddress; + private Map additionalProperties = new HashMap<>(); + + @JsonAnySetter + public void setAdditionalProperty(String name, Object value) { + additionalProperties.put(name, value); + } +} diff --git a/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/data/PayerRTPResponse.java b/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/data/PayerRTPResponse.java new file mode 100644 index 000000000..4192615c0 --- /dev/null +++ b/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/data/PayerRTPResponse.java @@ -0,0 +1,18 @@ +package org.mifos.pheebillpay.data; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +public class PayerRTPResponse { + + private String txnId; + private String billId; + private String rtpStatus; + private String rejectReason; +} diff --git a/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/data/PayerRequestDTO.java b/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/data/PayerRequestDTO.java new file mode 100644 index 000000000..3143da0ad --- /dev/null +++ b/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/data/PayerRequestDTO.java @@ -0,0 +1,19 @@ +package org.mifos.pheebillpay.data; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +public class PayerRequestDTO { + + private String requestId; + private String transactionId; + private Integer rtpId; + private BillDetails billDetails; + +} diff --git a/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/data/ResponseDTO.java b/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/data/ResponseDTO.java new file mode 100644 index 000000000..46b478835 --- /dev/null +++ b/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/data/ResponseDTO.java @@ -0,0 +1,19 @@ +package org.mifos.pheebillpay.data; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import org.springframework.stereotype.Component; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +@Component +public class ResponseDTO { + + private String responseCode; + private String responseDescription; + private String requestID; +} diff --git a/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/data/TrasactionDTO.java b/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/data/TrasactionDTO.java new file mode 100644 index 000000000..5437f7836 --- /dev/null +++ b/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/data/TrasactionDTO.java @@ -0,0 +1,40 @@ +package org.mifos.pheebillpay.data; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +public class TrasactionDTO { + + private int id; + private String workflowInstanceKey; + private String transactionId; + private long startedAt; + private long completedAt; + private String state; + private String payeeDfspId; + private String payeePartyId; + private String payeePartyIdType; + private Double payeeFee; + private String payeeQuoteCode; + private String payerDfspId; + private String payerPartyId; + private String payerPartyIdType; + private Double payerFee; + private String payerQuoteCode; + private Double amount; + private String currency; + private String direction; + private String authType; + private String initiatorType; + private String scenario; + private String externalId; + private String clientCorrelationId; + private String errorInformation; + +} diff --git a/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/interceptor/HeaderValidationInterceptor.java b/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/interceptor/HeaderValidationInterceptor.java new file mode 100644 index 000000000..759096c46 --- /dev/null +++ b/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/interceptor/HeaderValidationInterceptor.java @@ -0,0 +1,73 @@ +package org.mifos.pheebillpay.interceptor; + +import com.fasterxml.jackson.databind.ObjectMapper; +import java.lang.reflect.Method; +import java.util.Arrays; +import java.util.Set; +import java.util.stream.Collectors; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import lombok.extern.slf4j.Slf4j; +import org.mifos.pheebillpay.service.ValidateHeaders; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.http.HttpStatus; +import org.springframework.stereotype.Component; +import org.springframework.web.method.HandlerMethod; +import org.springframework.web.servlet.HandlerInterceptor; + +@Slf4j +@Component +public class HeaderValidationInterceptor implements HandlerInterceptor { + + @Autowired + private ApplicationContext applicationContext; + + @Override + public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { + log.debug("At interceptor"); + if (handler instanceof HandlerMethod) { + HandlerMethod handlerMethod = (HandlerMethod) handler; + Method method = handlerMethod.getMethod(); + if (method.isAnnotationPresent(ValidateHeaders.class)) { + ValidateHeaders validateHeaders = method.getAnnotation(ValidateHeaders.class); + Set headersSet = extractRequiredHeaders(validateHeaders); + + Object validatorInstance = getValidatorInstance(validateHeaders); + + Object methodResponse = invokeValidationMethod(validateHeaders, validatorInstance, headersSet, request); + + if (methodResponse != null) { + handleValidationFailure(response, methodResponse); + return false; + } + } + } + return true; + } + + private Set extractRequiredHeaders(ValidateHeaders validateHeaders) { + return Arrays.stream(validateHeaders.requiredHeaders()).map(String::toLowerCase).collect(Collectors.toSet()); + } + + private Object getValidatorInstance(ValidateHeaders validateHeaders) { + return applicationContext.getBean(validateHeaders.validatorClass()); + } + + private Object invokeValidationMethod(ValidateHeaders validateHeaders, Object validatorInstance, Set headersSet, + HttpServletRequest request) throws Exception { + Method validationMethod = validatorInstance.getClass().getDeclaredMethod(validateHeaders.validationFunction(), Set.class, + HttpServletRequest.class); + Object[] parameters = { headersSet, request }; + return validationMethod.invoke(validatorInstance, parameters); + } + + private void handleValidationFailure(HttpServletResponse response, Object methodResponse) throws Exception { + ObjectMapper objectMapper = new ObjectMapper(); + String jsonResponse = objectMapper.writeValueAsString(methodResponse); + response.setHeader("Content-Type", "application/json"); + response.setStatus(HttpStatus.BAD_REQUEST.value()); + response.getWriter().write(jsonResponse); + } + +} diff --git a/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/interceptor/config/WebMvcConfig.java b/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/interceptor/config/WebMvcConfig.java new file mode 100644 index 000000000..810ca0796 --- /dev/null +++ b/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/interceptor/config/WebMvcConfig.java @@ -0,0 +1,23 @@ +package org.mifos.pheebillpay.interceptor.config; + +import org.mifos.pheebillpay.interceptor.HeaderValidationInterceptor; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.config.annotation.InterceptorRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +@Configuration +public class WebMvcConfig implements WebMvcConfigurer { + + private final HeaderValidationInterceptor headerValidationInterceptor; + + @Autowired + public WebMvcConfig(HeaderValidationInterceptor headerValidationInterceptor) { + this.headerValidationInterceptor = headerValidationInterceptor; + } + + @Override + public void addInterceptors(InterceptorRegistry registry) { + registry.addInterceptor(headerValidationInterceptor); + } +} diff --git a/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/properties/BillerDetails.java b/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/properties/BillerDetails.java new file mode 100644 index 000000000..464575e5e --- /dev/null +++ b/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/properties/BillerDetails.java @@ -0,0 +1,48 @@ +package org.mifos.pheebillpay.properties; + +public class BillerDetails { + + String id; + String biller; + String billerAccount; + String billerCategory; + + @Override + public String toString() { + return "BillerDetails{" + "id='" + id + '\'' + ", biller='" + biller + '\'' + ", billerAccount='" + billerAccount + '\'' + + ", billerCategory='" + billerCategory + '\'' + '}'; + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getBiller() { + return biller; + } + + public void setBiller(String biller) { + this.biller = biller; + } + + public String getBillerAccount() { + return billerAccount; + } + + public void setBillerAccount(String billerAccount) { + this.billerAccount = billerAccount; + } + + public String getBillerCategory() { + return billerCategory; + } + + public void setBillerCategory(String billerCategory) { + this.billerCategory = billerCategory; + } + +} diff --git a/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/properties/BillerDetailsProperties.java b/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/properties/BillerDetailsProperties.java new file mode 100644 index 000000000..f4c3d2635 --- /dev/null +++ b/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/properties/BillerDetailsProperties.java @@ -0,0 +1,21 @@ +package org.mifos.pheebillpay.properties; + +import java.util.List; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +@Component +@ConfigurationProperties(prefix = "billers") +public class BillerDetailsProperties { + + public List getDetails() { + return details; + } + + public void setDetails(List details) { + this.details = details; + } + + List details; + +} diff --git a/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/service/BillInquiryService.java b/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/service/BillInquiryService.java new file mode 100644 index 000000000..fb8d0d643 --- /dev/null +++ b/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/service/BillInquiryService.java @@ -0,0 +1,57 @@ +package org.mifos.pheebillpay.service; + +import static org.mifos.pheebillpay.zeebe.ZeebeVariables.BILL_ID; +import static org.mifos.pheebillpay.zeebe.ZeebeVariables.CALLBACK_URL; +import static org.mifos.pheebillpay.zeebe.ZeebeVariables.CLIENTCORRELATIONID; +import static org.mifos.pheebillpay.zeebe.ZeebeVariables.FIELD; +import static org.mifos.pheebillpay.zeebe.ZeebeVariables.PAYER_FSP_ID; +import static org.mifos.pheebillpay.zeebe.ZeebeVariables.TENANT_ID; + +import java.util.HashMap; +import java.util.Map; +import org.mifos.pheebillpay.zeebe.ZeebeProcessStarter; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; + +@Service +public class BillInquiryService { + + private Logger logger = LoggerFactory.getLogger(BillInquiryService.class); + + @Autowired + private ZeebeProcessStarter zeebeProcessStarter; + + @Value("${bpmn.flows.bill-pay}") + String billPayFlow; + + @Value("${billPay.FspNotOnboarded}") + private String fspNotOnboarded; + + String transactionId; + + public String billInquiry(String tenantId, String correlationId, String callbackUrl, String payerFspId, String billId, String field) { + Map extraVariables = new HashMap<>(); + if (billId.equals(fspNotOnboarded)) { + transactionId = "Participant Not Onboarded"; + } else { + extraVariables.put(TENANT_ID, tenantId); + extraVariables.put(CLIENTCORRELATIONID, correlationId); + extraVariables.put(CALLBACK_URL, callbackUrl); + extraVariables.put(PAYER_FSP_ID, payerFspId); + extraVariables.put(BILL_ID, billId); + extraVariables.put(FIELD, field); + String tenantSpecificBpmn = billPayFlow.replace("{dfspid}", tenantId); + try { + transactionId = zeebeProcessStarter.startZeebeWorkflow(tenantSpecificBpmn, null, extraVariables); + } catch (Exception e) { + logger.info("Exception in starting workflow: {}", e.getMessage()); + transactionId = "Exception in starting workflow"; + } + } + return transactionId; + } + +} diff --git a/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/service/BillPaymentsService.java b/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/service/BillPaymentsService.java new file mode 100644 index 000000000..74e82fcb2 --- /dev/null +++ b/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/service/BillPaymentsService.java @@ -0,0 +1,50 @@ +package org.mifos.pheebillpay.service; + +import static org.mifos.pheebillpay.zeebe.ZeebeVariables.BILL_ID; +import static org.mifos.pheebillpay.zeebe.ZeebeVariables.BILL_PAYMENTS_REQ; +import static org.mifos.pheebillpay.zeebe.ZeebeVariables.BILL_REQ_ID; +import static org.mifos.pheebillpay.zeebe.ZeebeVariables.CALLBACK_URL; +import static org.mifos.pheebillpay.zeebe.ZeebeVariables.CLIENTCORRELATIONID; +import static org.mifos.pheebillpay.zeebe.ZeebeVariables.PAYER_FSP_ID; +import static org.mifos.pheebillpay.zeebe.ZeebeVariables.PAYMENTS_REF_ID; +import static org.mifos.pheebillpay.zeebe.ZeebeVariables.TENANT_ID; + +import java.util.HashMap; +import java.util.Map; +import org.mifos.pheebillpay.data.BillPaymentsReqDTO; +import org.mifos.pheebillpay.zeebe.ZeebeProcessStarter; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; + +@Service +public class BillPaymentsService { + + @Autowired + private ZeebeProcessStarter zeebeProcessStarter; + + @Value("${bpmn.flows.payment-notification}") + String paymentNotificationFlow; + + String transactionId; + + public String billPayments(String tenantId, String correlationId, String callbackUrl, String payerFspId, BillPaymentsReqDTO body) { + Map extraVariables = new HashMap<>(); + extraVariables.put(TENANT_ID, tenantId); + extraVariables.put(CLIENTCORRELATIONID, correlationId); + extraVariables.put(PAYER_FSP_ID, payerFspId); + extraVariables.put(BILL_ID, body.getBillId()); + extraVariables.put(PAYMENTS_REF_ID, body.getPaymentReferenceID()); + extraVariables.put(BILL_REQ_ID, body.getBillInquiryRequestId()); + extraVariables.put(CALLBACK_URL, callbackUrl); + extraVariables.put(BILL_PAYMENTS_REQ, body); + extraVariables.put("payeePartyIdType", "Bill"); + extraVariables.put("payeePartyId", body.getBillId()); + extraVariables.put("payerPartyIdType", "Bill"); + extraVariables.put("payerPartyId", payerFspId); + String tenantSpecificBpmn = paymentNotificationFlow.replace("{dfspid}", tenantId); + transactionId = zeebeProcessStarter.startZeebeWorkflow(tenantSpecificBpmn, body.toString(), extraVariables); + return transactionId; + } + +} diff --git a/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/service/BillRTPReqService.java b/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/service/BillRTPReqService.java new file mode 100644 index 000000000..351dbd1e0 --- /dev/null +++ b/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/service/BillRTPReqService.java @@ -0,0 +1,67 @@ +package org.mifos.pheebillpay.service; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import java.util.HashMap; +import java.util.Map; +import org.mifos.connector.common.channel.dto.PhErrorDTO; +import org.mifos.pheebillpay.data.BillRTPReqDTO; +import org.mifos.pheebillpay.validators.BillPayValidator; +import org.mifos.pheebillpay.zeebe.ZeebeProcessStarter; +import org.mifos.pheebillpay.zeebe.ZeebeVariables; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; + +@Service +public class BillRTPReqService { + + @Autowired + private ZeebeProcessStarter zeebeProcessStarter; + @Autowired + private BillPayValidator billPayValidator; + + @Autowired + private ObjectMapper objectMapper; + + @Value("${bpmn.flows.bill-request}") + String billPayFlow; + + String transactionId; + private static final Logger logger = LoggerFactory.getLogger(BillRTPReqService.class); + + public PhErrorDTO billRtpReq(String tenantId, String correlationId, String callBackUrl, String billerId, BillRTPReqDTO body) { + PhErrorDTO phErrorDTO = billPayValidator.validateBillRTPRequest(body); + if (phErrorDTO == null) { + Map extraVariables = new HashMap<>(); + extraVariables.put(ZeebeVariables.TENANT_ID, tenantId); + extraVariables.put(ZeebeVariables.CLIENTCORRELATIONID, correlationId); + extraVariables.put(ZeebeVariables.BILL_ID, body.getBillID()); + extraVariables.put(ZeebeVariables.BILLER_ID, billerId); + extraVariables.put(ZeebeVariables.CALLBACK_URL, callBackUrl); + extraVariables.put("payerFspId", body.getPayerFspDetails().getPayerFSPID()); + extraVariables.put("payeePartyIdType", "Bill"); + extraVariables.put("payeePartyId", body.getBillID()); + extraVariables.put("payerPartyIdType", "Bill"); + extraVariables.put("payerPartyId", billerId); + extraVariables.put("state", "INITIATED"); + String jsonString = null; + + try { + jsonString = objectMapper.writeValueAsString(body); + } catch (JsonProcessingException e) { + logger.error(e.getMessage()); + } + + extraVariables.put(ZeebeVariables.BILL_RTP_REQ, jsonString); + // adding a method to be implemented that checks the rrequest and perofrms als if needed + // checkRequest(body); + String tenantSpecificBpmn = billPayFlow.replace("{dfspid}", tenantId); + transactionId = zeebeProcessStarter.startZeebeWorkflow(tenantSpecificBpmn, body.toString(), extraVariables); + } + + return phErrorDTO; + } +} diff --git a/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/service/BillStatusService.java b/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/service/BillStatusService.java new file mode 100644 index 000000000..9a0122a74 --- /dev/null +++ b/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/service/BillStatusService.java @@ -0,0 +1,76 @@ +package org.mifos.pheebillpay.service; + +import static org.mifos.pheebillpay.zeebe.ZeebeVariables.PLATFORM_TENANT; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import java.security.KeyManagementException; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import org.apache.http.conn.ssl.NoopHostnameVerifier; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClients; +import org.apache.http.ssl.SSLContextBuilder; +import org.mifos.pheebillpay.data.BillStatusReqDTO; +import org.mifos.pheebillpay.data.TrasactionDTO; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; +import org.springframework.stereotype.Service; +import org.springframework.web.client.RestTemplate; +import org.springframework.web.util.UriComponentsBuilder; + +@Service +public class BillStatusService { + + private Logger logger = LoggerFactory.getLogger(BillStatusService.class); + + @Value("${operations.url}") + private String baseUrl; + + @Value("${operations.endpoint.transactionReq}") + private String transactionReqEndpoint; + + private ObjectMapper objectMapper = new ObjectMapper(); + + String transactionId; + + public TrasactionDTO billStatus(String tenantId, String correlationId, String billerId, String billId, String transferRequestId, + BillStatusReqDTO body) throws NoSuchAlgorithmException, KeyStoreException, KeyManagementException, JsonProcessingException { + TrasactionDTO trasactionDTO = new TrasactionDTO(); + logger.info("Bill Status Implementation"); + String url = baseUrl + transactionReqEndpoint + "&clientCorrelationId={clientid}"; + logger.info("Url {}", url); + RestTemplate restTemplate = new RestTemplate(); + HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory(); + CloseableHttpClient httpClient = HttpClients.custom() + .setSSLContext(new SSLContextBuilder().loadTrustMaterial(null, (certificate, authType) -> true).build()) + .setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE).build(); + restTemplate.setRequestFactory(new HttpComponentsClientHttpRequestFactory(httpClient)); + + HttpHeaders headers = new HttpHeaders(); + headers.set(PLATFORM_TENANT, tenantId); + headers.setContentType(MediaType.APPLICATION_JSON); + url = UriComponentsBuilder.fromUriString(url).buildAndExpand(transferRequestId).toUriString(); + + HttpEntity entity = new HttpEntity<>(headers); + TrasactionDTO txnResponseDTO = new TrasactionDTO(); + ResponseEntity response = restTemplate.exchange(url, HttpMethod.GET, entity, String.class); + logger.info("Response from operations: " + response.getBody()); + JsonNode contentNode = objectMapper.readTree(response.getBody()).get("content"); + if (contentNode.isEmpty()) { + return txnResponseDTO; + } else { + txnResponseDTO = objectMapper.treeToValue(contentNode.get(0), TrasactionDTO.class); + } + return txnResponseDTO; + } + +} diff --git a/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/service/ValidateHeaders.java b/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/service/ValidateHeaders.java new file mode 100644 index 000000000..696ff5efb --- /dev/null +++ b/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/service/ValidateHeaders.java @@ -0,0 +1,17 @@ +package org.mifos.pheebillpay.service; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +public @interface ValidateHeaders { + + String[] requiredHeaders(); + + Class validatorClass(); + + String validationFunction(); +} diff --git a/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/utils/AbstractApplicationConfiguration.java b/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/utils/AbstractApplicationConfiguration.java new file mode 100644 index 000000000..70b69ae47 --- /dev/null +++ b/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/utils/AbstractApplicationConfiguration.java @@ -0,0 +1,33 @@ +package org.mifos.pheebillpay.utils; + +import java.util.concurrent.Executor; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.scheduling.annotation.EnableAsync; +import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; + +@Configuration +@EnableAsync +@ComponentScan(basePackages = "org.mifos.pheebillpay") +public abstract class AbstractApplicationConfiguration { + + @Value("${async.core-pool-size}") + public Integer corePoolSize; + @Value("${async.max-pool-size}") + public Integer maxPoolSize; + @Value("${async.queue-capacity}") + public Integer queueCapacity; + + @Bean(name = "asyncExecutor") + public Executor asyncExecutor() { + ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); + executor.setCorePoolSize(corePoolSize); + executor.setMaxPoolSize(maxPoolSize); + executor.setQueueCapacity(queueCapacity); + executor.setThreadNamePrefix("AsyncThread-"); + executor.initialize(); + return executor; + } +} diff --git a/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/utils/BillPayDTOConstant.java b/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/utils/BillPayDTOConstant.java new file mode 100644 index 000000000..2f8195573 --- /dev/null +++ b/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/utils/BillPayDTOConstant.java @@ -0,0 +1,23 @@ +package org.mifos.pheebillpay.utils; + +@SuppressWarnings("HideUtilityClassConstructor") +public class BillPayDTOConstant { + + public static final String requestId = "requestId"; + public static final String billInquiryRequestId = "billInquiryRequestId"; + public static final String billId = "billId"; + public static final String paymentRefereneID = "paymentRefereneID"; + public static final String clientCorrelationId = "clientCorrelationId"; + public static final String billID = "billID"; + public static final String requestType = "requestType"; + public static final String payerFSPDetails = "payerFSPDetails"; + public static final String payerFSPID = "payerFSPID"; + public static final String financialAddress = "financialAddress"; + public static final String alias = "alias"; + public static final String aliasType = "aliasType"; + public static final String aliasId = "aliasId"; + public static final String billerName = "billerName"; + public static final String amount = "amount"; + public static final String billDetails = "billDetails"; + +} diff --git a/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/utils/BillPayEnum.java b/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/utils/BillPayEnum.java new file mode 100644 index 000000000..fa6d5ff4a --- /dev/null +++ b/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/utils/BillPayEnum.java @@ -0,0 +1,17 @@ +package org.mifos.pheebillpay.utils; + +public enum BillPayEnum { + + SUCCESS_RESPONSE_CODE("00"), FAILED_RESPONSE_CODE("01"), SUCCESS_RESPONSE_MESSAGE( + "Request successfully received by Pay-BB"), FAILED_RESPONSE_MESSAGE("Request not acknowledged by Pay-BB"); + + private final String value; + + BillPayEnum(String value) { + this.value = value; + } + + public String getValue() { + return this.value; + } +} diff --git a/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/utils/BillValidatorEnum.java b/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/utils/BillValidatorEnum.java new file mode 100644 index 000000000..f4a55a349 --- /dev/null +++ b/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/utils/BillValidatorEnum.java @@ -0,0 +1,110 @@ +package org.mifos.pheebillpay.utils; + +import org.mifos.connector.common.exception.PaymentHubErrorCategory; +import org.mifos.connector.common.validation.ValidationCodeType; + +public enum BillValidatorEnum implements ValidationCodeType { + + HEADER_VALIDATION_ERROR("error.msg.header.validation.errors", "The headers are invalid"), BILL_SCHEMA_VALIDATION_ERROR( + "error.msg.schema.validation.errors", + "The request is invalid"), INVALID_CORRELATION_ID("error.msg.schema.correlation.id.cannot.be.null.or.empty", + "Correlation ID cannot be null or empty"), INVALID_CORRELATION_ID_LENGTH( + "error.msg.schema.correlation.id.length.is.invalid", + "Correlation ID length is invalid"), INVALID_TENANT_ID("error.msg.schema.tenant.id.cannot.be.null.or.empty", + "Tenant ID cannot be null or empty"), INVALID_TENANT_ID_LENGTH( + "error.msg.schema.tenant.id.length.is.invalid", + "Tenant ID length is invalid"), INVALID_PAYER_FSP_ID( + "error.msg.schema.payer.fsp.id.cannot.be.null.or.empty", + "Payer FSP ID cannot be null or empty"), INVALID_PAYER_FSP_ID_LENGTH( + "error.msg.schema.payer.fsp.id.length.is.invalid", + "Payer FSP ID length is invalid"), INVALID_CLIENT_CORRELATION_ID( + "error.msg.schema.client.correlation.id.cannot.be.null.or.empty", + "Client Correlation ID cannot be null or empty"), INVALID_CLIENT_CORRELATION_ID_LENGTH( + "error.msg.schema.client.correlation.id.length.is.invalid", + "Client Correlation ID length is invalid"), INVALID_PLATFORM_TENANT_ID( + "error.msg.schema.platform.tenant.id.cannot.be.null.or.empty", + "Platform Tenant ID cannot be null or empty"), INVALID_PLATFORM_TENANT_ID_LENGTH( + "error.msg.schema.platform.tenant.id.length.is.invalid", + "Platform Tenant ID length is invalid"), INVALID_BILLER_ID( + "error.msg.schema.biller.id.cannot.be.null.or.empty", + "Biller ID cannot be null or empty"), INVALID_BILLER_ID_LENGTH( + "error.msg.schema.biller.id.length.is.invalid", + "Biller ID length is invalid"), INVALID_CALLBACK_URL( + "error.msg.schema.callback.url.cannot.be.null.or.empty", + "Callback URL cannot be null or empty"), INVALID_CALLBACK_URL_LENGTH( + "error.msg.schema.callback.url.length.is.invalid", + "Callback URL length is invalid"), INVALID_REGISTERING_INSTITUTION_ID( + "error.msg.schema.registering.institution.id.cannot.be.null.or.empty", + "Registering Institution ID cannot be null or empty"), INVALID_REGISTERING_INSTITUTION_ID_LENGTH( + "error.msg.schema.registering.institution.id.length.is.invalid", + "Registering Institution ID length is invalid"), INVALID_BILL_ID( + "error.msg.schema.bill.id.cannot.be.null.or.empty", + "Bill ID cannot be null or empty"), INVALID_BILL_ID_LENGTH( + "error.msg.schema.bill.id.length.is.invalid", + "Bill ID length is invalid"), INVALID_REQUEST_TYPE( + "error.msg.schema.request.type.cannot.be.null.or.empty", + "Request Type cannot be null or empty"), INVALID_REQUEST_TYPE_VALUE( + "error.msg.schema.request.type.is.invalid", + "Request Type is Invalid"), INVALID_FINANCIAL_ADDRESS( + "error.msg.schema.financial.address.cannot.be.null.or.empty", + "Financial Address cannot be null or empty"), INVALID_FINANCIAL_ADDRESS_LENGTH( + "error.msg.schema.financial.address.length.is.invalid", + "Financial Address length is invalid"), INVALID_PAYER_FSP_DETAILS( + "error.msg.schema.payer.fsp.details.cannot.be.null.or.empty", + "Payer Fsp details cannot be null or empty"), INVALID_ALIAS( + "error.msg.schema.alias.cannot.be.null.or.empty", + "alias cannot be null or empty"), INVALID_ALIAS_ID( + "error.msg.schema.alias.id.cannot.be.null.or.empty", + "Alias Id cannot be null or empty"), INVALID_ALIAS_ID_LENGTH( + "error.msg.schema.alias.id.length.is.invalid", + "Alias Id length is invalid"), INVALID_ALIAS_TYPE( + "error.msg.schema.alias.type.cannot.be.null.or.empty", + "Alias Type cannot be null or empty"), INVALID_ALIAS_TYPE_VALUE( + "error.msg.schema.alias.type.is.invalid", + "Alias Type is Invalid"), INVALID_ALIAS_DETAILS( + "error.msg.schema.alias.cannot.be.null.or.empty", + "Alias cannot be null or empty"), INVALID_BILL_DETAILS( + "error.msg.schema.bill.details.cannot.be.null.or.empty", + "bill details cannot be null or empty"), INVALID_BILLER_NAME( + "error.msg.schema.biller.name.cannot.be.null.or.empty", + "Biller Name cannot be null or empty"), INVALID_BILLER_NAME_LENGTH( + "error.msg.schema.biller.name.length.is.invalid", + "Biller Name length is invalid"), INVALID_AMOUNT( + "error.msg.schema.amount.cannot.be.null.or.empty", + "Amount cannot be null or empty"), INVALID_NEGATIVE_AMOUNT( + "error.msg.schema.amount.cannot.be.negative", + "Amount cannot be negative"), + + INVALID_BILL_INQUIRY_REQUEST_ID("error.msg.schema.bill.inquiry.request.id.cannot.be.null.or.empty", + "Bill Inquiry Request ID cannot be null or empty"), INVALID_BILL_INQUIRY_REQUEST_ID_LENGTH( + "error.msg.schema.bill.inquiry.request.id.length.is.invalid", + "Bill Inquiry Request ID length is invalid"), INVALID_PAYMENT_REFERENCE_ID( + "error.msg.schema.payment.reference.id.cannot.be.null.or.empty", + "Payment Reference ID cannot be null or empty"), INVALID_PAYMENT_REFERENCE_ID_LENGTH( + "error.msg.schema.payment.reference.id.length.is.invalid", "Payment Reference ID length is invalid"); + + private final String code; + private final String category; + private final String message; + + BillValidatorEnum(String code, String message) { + this.code = code; + this.category = PaymentHubErrorCategory.Validation.toString(); + this.message = message; + } + + @Override + public String getCode() { + return this.code; + } + + @Override + public String getCategory() { + return this.category; + } + + @Override + public String getMessage() { + return message; + } +} diff --git a/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/utils/HeaderConstants.java b/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/utils/HeaderConstants.java new file mode 100644 index 000000000..27f86c1a2 --- /dev/null +++ b/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/utils/HeaderConstants.java @@ -0,0 +1,16 @@ +package org.mifos.pheebillpay.utils; + +@SuppressWarnings("HideUtilityClassConstructor") +public class HeaderConstants { + + public static final String PLATFORM_TENANT_ID = "Platform-TenantId"; + public static final String X_CORRELATION_ID = "X-CorrelationID"; + public static final String X_CALLBACKURL = "X-CallbackURL"; + public static final String X_CALLBACK_URL = "X-Callback-URL"; + public static final String PAYER_FSP_ID = "Payer-FSP-Id"; + public static final String X_PLATFORM_TENANT_ID = "X-Platform-TenantId"; + public static final String X_PAYER_FSP_ID = "X-PayerFSP-Id"; + public static final String X_CLIENT_CORRELATION_ID = "X-Client-Correlation-ID"; + public static final String X_REGISTERING_INSTITUTION_ID = "X-Registering-Institution-ID"; + public static final String X_BILLER_ID = "X-Biller-Id"; +} diff --git a/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/utils/Headers.java b/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/utils/Headers.java new file mode 100644 index 000000000..66a2d1e3c --- /dev/null +++ b/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/utils/Headers.java @@ -0,0 +1,45 @@ +package org.mifos.pheebillpay.utils; + +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +public final class Headers { + + private Map headers; + + private Headers() {} + + private void setHeaders(Map headers) { + this.headers = headers; + } + + public Map getHeaders() { + return headers; + } + + public Set getHeadersKey() { + return this.headers.keySet(); + } + + public Object get(String key) { + return this.headers.get(key); + } + + public static class HeaderBuilder { + + private Map headers = new HashMap<>(); + + public HeaderBuilder addHeader(String key, Object value) { + headers.put(key, value); + return this; + } + + public Headers build() { + Headers headersClassInstance = new Headers(); + headersClassInstance.setHeaders(this.headers); + + return headersClassInstance; + } + } +} diff --git a/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/utils/SpringWrapperUtil.java b/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/utils/SpringWrapperUtil.java new file mode 100644 index 000000000..d08e3e78a --- /dev/null +++ b/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/utils/SpringWrapperUtil.java @@ -0,0 +1,30 @@ +package org.mifos.pheebillpay.utils; + +import org.apache.camel.CamelContext; +import org.apache.camel.Exchange; +import org.apache.camel.support.DefaultExchange; + +public final class SpringWrapperUtil { + + private SpringWrapperUtil() {} + + public static Exchange getDefaultWrappedExchange(CamelContext camelContext, Headers headers, String body) { + Exchange exchange = new DefaultExchange(camelContext); + + // Setting headers + for (String headerKey : headers.getHeadersKey()) { + exchange.getIn().setHeader(headerKey, headers.get(headerKey)); + } + + // Setting body if available + if (body != null) { + try { + exchange.getIn().setBody((String) body); + } catch (Exception e) { + exchange.getIn().setBody(body); + + } + } + return exchange; + } +} diff --git a/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/validators/BillPayValidator.java b/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/validators/BillPayValidator.java new file mode 100644 index 000000000..321aa6d14 --- /dev/null +++ b/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/validators/BillPayValidator.java @@ -0,0 +1,179 @@ +package org.mifos.pheebillpay.validators; + +import static org.mifos.connector.common.exception.PaymentHubError.ExtValidationError; + +import java.util.Objects; +import org.mifos.connector.common.channel.dto.PhErrorDTO; +import org.mifos.connector.common.exception.PaymentHubErrorCategory; +import org.mifos.connector.common.validation.ValidatorBuilder; +import org.mifos.pheebillpay.data.Alias; +import org.mifos.pheebillpay.data.Bill; +import org.mifos.pheebillpay.data.BillPaymentsReqDTO; +import org.mifos.pheebillpay.data.BillRTPReqDTO; +import org.mifos.pheebillpay.data.PayerFSPDetail; +import org.mifos.pheebillpay.utils.BillPayDTOConstant; +import org.mifos.pheebillpay.utils.BillValidatorEnum; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component +public class BillPayValidator { + + @Autowired + UnsupportedParameterValidator unsupportedParameterValidator; + + private static final String resource = "billPayValidator"; + + public static final int expectedRequestIdLength = 12; + public static final int expectedBillInquiryRequestIdLength = 12; + public static final int expectedBillIdLength = 20; + public static final int expectedPaymentRefereneIDLength = 16; + public static final int expectedClientCorrelationIdLength = 12; + public static final int expectedBillerIdLength = 10; + public static final int expectedRequestTypeLength = 2; + public static final int expectedPayerFSPIDLength = 10; + public static final int expectedFinancialAddressLength = 30; + public static final int expectedAliasTypeLength = 2; + public static final int expectedAliasIdLength = 30; + public static final int expectedBillerNameLength = 10; + + public PhErrorDTO validateBillPayments(BillPaymentsReqDTO request) { + final ValidatorBuilder validatorBuilder = new ValidatorBuilder(); + + // Checks for unsupportedParameter + unsupportedParameterValidator.handleUnsupportedParameterValidation(request.getAdditionalProperties(), validatorBuilder); + + // Checks for billInquiryRequestId + validatorBuilder.validateFieldIgnoreNullAndMaxLengthWithFailureCode(resource, BillPayDTOConstant.billInquiryRequestId, + request.getBillInquiryRequestId(), expectedBillInquiryRequestIdLength, + BillValidatorEnum.INVALID_BILL_INQUIRY_REQUEST_ID_LENGTH); + + // Checks for billId + validatorBuilder.validateFieldIsNullAndMaxLengthWithFailureCode(resource, BillPayDTOConstant.billId, request.getBillId(), + BillValidatorEnum.INVALID_BILL_ID, expectedBillIdLength, BillValidatorEnum.INVALID_BILL_ID_LENGTH); + + // Checks for paymentReferenceID + validatorBuilder.validateFieldIsNullAndMaxLengthWithFailureCode(resource, BillPayDTOConstant.paymentRefereneID, + request.getPaymentReferenceID(), BillValidatorEnum.INVALID_PAYMENT_REFERENCE_ID, expectedPaymentRefereneIDLength, + BillValidatorEnum.INVALID_PAYMENT_REFERENCE_ID_LENGTH); + + return handleValidationErrors(validatorBuilder); + } + + public PhErrorDTO validateBillRTPRequest(BillRTPReqDTO request) { + final ValidatorBuilder validatorBuilder = new ValidatorBuilder(); + + // Checks for unsupportedParameter + unsupportedParameterValidator.handleUnsupportedParameterValidation(request.getAdditionalProperties(), validatorBuilder); + + // Checks for clientCorrelationId + validatorBuilder.validateFieldIgnoreNullAndMaxLengthWithFailureCode(resource, BillPayDTOConstant.clientCorrelationId, + request.getClientCorrelationId(), expectedClientCorrelationIdLength, + BillValidatorEnum.INVALID_CLIENT_CORRELATION_ID_LENGTH); + + // Checks for billID/billerID + validatorBuilder.validateFieldIsNullAndMaxLengthWithFailureCode(resource, BillPayDTOConstant.billID, request.getBillID(), + BillValidatorEnum.INVALID_BILL_ID, expectedBillerIdLength, BillValidatorEnum.INVALID_BILL_ID_LENGTH); + + // Checks for requestType + validatorBuilder.validateFieldIsNullAndExactLengthWithFailureCode(resource, BillPayDTOConstant.requestType, + request.getRequestType(), BillValidatorEnum.INVALID_REQUEST_TYPE, expectedRequestTypeLength, + BillValidatorEnum.INVALID_REQUEST_TYPE_VALUE); + + if (request.getRequestType() != null + && !(Objects.equals(request.getRequestType(), "00") || Objects.equals(request.getRequestType(), "01"))) { + validatorBuilder.reset().resource(resource).parameter(BillPayDTOConstant.requestType).value(request.getRequestType()) + .failWithCode(BillValidatorEnum.INVALID_REQUEST_TYPE_VALUE); + } + + // Checks for payerFSPDetails + if (request.getRequestType() != null && Objects.equals(request.getRequestType(), "00")) { + validatorBuilder.reset().resource(resource).parameter(BillPayDTOConstant.payerFSPDetails).value(request.getPayerFspDetails()) + .isNullWithFailureCode(BillValidatorEnum.INVALID_PAYER_FSP_DETAILS); + + if (request.getPayerFspDetails() == null) { + request.setPayerFspDetails(new PayerFSPDetail()); + } + validatePayerFSPDetails(request.getPayerFspDetails(), validatorBuilder); + } + + // Checks for alias + if (request.getRequestType() != null && Objects.equals(request.getRequestType(), "01")) { + validatorBuilder.reset().resource(resource).parameter(BillPayDTOConstant.alias).value(request.getAlias()) + .isNullWithFailureCode(BillValidatorEnum.INVALID_ALIAS); + + if (request.getAlias() == null) { + request.setAlias(new Alias()); + } + validateAlias(request.getAlias(), validatorBuilder); + } + + // Checks for billDetails + validatorBuilder.reset().resource(resource).parameter(BillPayDTOConstant.billDetails).value(request.getBillDetails()) + .isNullWithFailureCode(BillValidatorEnum.INVALID_BILL_DETAILS); + if (request.getBillDetails() == null) { + request.setBillDetails(new Bill()); + } + validateBillDetails(request.getBillDetails(), validatorBuilder); + + return handleValidationErrors(validatorBuilder); + } + + private void validatePayerFSPDetails(PayerFSPDetail payerFSPDetail, ValidatorBuilder validatorBuilder) { + // Checks for unsupportedParameter + unsupportedParameterValidator.handleUnsupportedParameterValidation(payerFSPDetail.getAdditionalProperties(), validatorBuilder); + + // Checks for payerFSPID + validatorBuilder.validateFieldIsNullAndMaxLengthWithFailureCode(resource, BillPayDTOConstant.payerFSPID, + payerFSPDetail.getPayerFSPID(), BillValidatorEnum.INVALID_PAYER_FSP_ID, expectedPayerFSPIDLength, + BillValidatorEnum.INVALID_PAYER_FSP_ID_LENGTH); + + // Checks for financialAddress + validatorBuilder.validateFieldIsNullAndMaxLengthWithFailureCode(resource, BillPayDTOConstant.financialAddress, + payerFSPDetail.getFinancialAddress(), BillValidatorEnum.INVALID_FINANCIAL_ADDRESS, expectedFinancialAddressLength, + BillValidatorEnum.INVALID_FINANCIAL_ADDRESS_LENGTH); + } + + private void validateAlias(Alias alias, ValidatorBuilder validatorBuilder) { + // Checks for unsupportedParameter + unsupportedParameterValidator.handleUnsupportedParameterValidation(alias.getAdditionalProperties(), validatorBuilder); + + // Checks for aliasType + validatorBuilder.validateFieldIsNullAndMaxLengthWithFailureCode(resource, BillPayDTOConstant.aliasType, alias.getAliasType(), + BillValidatorEnum.INVALID_ALIAS_TYPE, expectedAliasTypeLength, BillValidatorEnum.INVALID_ALIAS_TYPE_VALUE); + + // Checks for aliasId + validatorBuilder.validateFieldIgnoreNullAndMaxLengthWithFailureCode(resource, BillPayDTOConstant.aliasId, alias.getAliasId(), + expectedAliasIdLength, BillValidatorEnum.INVALID_ALIAS_ID_LENGTH); + + } + + private void validateBillDetails(Bill bill, ValidatorBuilder validatorBuilder) { + // Checks for unsupportedParameter + unsupportedParameterValidator.handleUnsupportedParameterValidation(bill.getAdditionalProperties(), validatorBuilder); + + // Checks for billerName + validatorBuilder.validateFieldIsNullAndMaxLengthWithFailureCode(resource, BillPayDTOConstant.billerName, bill.getBillerName(), + BillValidatorEnum.INVALID_BILLER_NAME, expectedBillerNameLength, BillValidatorEnum.INVALID_BILLER_NAME_LENGTH); + + // Checks for amount + validatorBuilder.reset().resource(resource).parameter(BillPayDTOConstant.amount).value(bill.getAmount()) + .isNullWithFailureCode(BillValidatorEnum.INVALID_AMOUNT) + .validateBigDecimalFieldNotNegativeWithFailureCode(BillValidatorEnum.INVALID_NEGATIVE_AMOUNT); + } + + private PhErrorDTO handleValidationErrors(ValidatorBuilder validatorBuilder) { + if (validatorBuilder.hasError()) { + validatorBuilder.errorCategory(PaymentHubErrorCategory.Validation.toString()) + .errorCode(BillValidatorEnum.BILL_SCHEMA_VALIDATION_ERROR.getCode()) + .errorDescription(BillValidatorEnum.BILL_SCHEMA_VALIDATION_ERROR.getMessage()) + .developerMessage(BillValidatorEnum.BILL_SCHEMA_VALIDATION_ERROR.getMessage()) + .defaultUserMessage(BillValidatorEnum.BILL_SCHEMA_VALIDATION_ERROR.getMessage()); + + PhErrorDTO.PhErrorDTOBuilder phErrorDTOBuilder = new PhErrorDTO.PhErrorDTOBuilder(ExtValidationError.getErrorCode()); + phErrorDTOBuilder.fromValidatorBuilder(validatorBuilder); + return phErrorDTOBuilder.build(); + } + return null; + } +} diff --git a/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/validators/HeaderValidator.java b/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/validators/HeaderValidator.java new file mode 100644 index 000000000..cdf754928 --- /dev/null +++ b/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/validators/HeaderValidator.java @@ -0,0 +1,143 @@ +package org.mifos.pheebillpay.validators; + +import static org.mifos.connector.common.exception.PaymentHubError.ExtValidationError; + +import java.util.Collections; +import java.util.Enumeration; +import java.util.List; +import java.util.Set; +import javax.servlet.http.HttpServletRequest; +import org.mifos.connector.common.channel.dto.PhErrorDTO; +import org.mifos.connector.common.exception.PaymentHubErrorCategory; +import org.mifos.connector.common.validation.ValidatorBuilder; +import org.mifos.pheebillpay.utils.BillValidatorEnum; +import org.mifos.pheebillpay.utils.HeaderConstants; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +@Component +public class HeaderValidator { + + @Autowired + UnsupportedParameterValidator unsupportedParameterValidator; + + @Value("#{'${default_api_headers}'.split(',')}") + private List defaultHeader; + + private static final String resource = "billPayValidator"; + + public PhErrorDTO validateBillInquiryRequest(Set requiredHeaders, HttpServletRequest request) { + final ValidatorBuilder validatorBuilder = new ValidatorBuilder(); + + List headers = getHeaderList(request); + // Checks for unsupported parameters + unsupportedParameterValidator.handleRequiredParameterValidation(headers, requiredHeaders, validatorBuilder); + + // Checks for X-CorrelationID + validatorBuilder.validateFieldIgnoreNullAndMaxLengthWithFailureCode(resource, HeaderConstants.X_CORRELATION_ID, + request.getHeader(HeaderConstants.X_CORRELATION_ID), 20, BillValidatorEnum.INVALID_CORRELATION_ID_LENGTH); + + // Checks for Platform-TenantId + validatorBuilder.validateFieldIgnoreNullAndMaxLengthWithFailureCode(resource, HeaderConstants.PLATFORM_TENANT_ID, + request.getHeader(HeaderConstants.PLATFORM_TENANT_ID), 20, BillValidatorEnum.INVALID_PLATFORM_TENANT_ID_LENGTH); + + // Checks for X-Callback-URL + validatorBuilder.validateFieldIgnoreNullAndMaxLengthWithFailureCode(resource, HeaderConstants.X_CALLBACKURL, + request.getHeader(HeaderConstants.X_CALLBACKURL), 100, BillValidatorEnum.INVALID_CALLBACK_URL_LENGTH); + + // Checks for Payer-FSP-Id + validatorBuilder.validateFieldIgnoreNullAndMaxLengthWithFailureCode(resource, HeaderConstants.PAYER_FSP_ID, + request.getHeader(HeaderConstants.PAYER_FSP_ID), 20, BillValidatorEnum.INVALID_PAYER_FSP_ID_LENGTH); + + return handleValidationErrors(validatorBuilder); + + } + + public PhErrorDTO validateBillPaymentRequest(Set requiredHeaders, HttpServletRequest request) { + final ValidatorBuilder validatorBuilder = new ValidatorBuilder(); + + List headers = getHeaderList(request); + // Set requiredHeaders = headerBuilderService.buildHeadersForBillPaymentsAPI(); + + // Checks for unsupported parameters + unsupportedParameterValidator.handleRequiredParameterValidation(headers, requiredHeaders, validatorBuilder); + + // Checks for X-CorrelationID + validatorBuilder.validateFieldIsNullAndMaxLengthWithFailureCode(resource, HeaderConstants.X_CORRELATION_ID, + request.getHeader(HeaderConstants.X_CORRELATION_ID), BillValidatorEnum.INVALID_CORRELATION_ID, 20, + BillValidatorEnum.INVALID_CORRELATION_ID_LENGTH); + + // Checks for X-Platform-TenantId + validatorBuilder.validateFieldIsNullAndMaxLengthWithFailureCode(resource, HeaderConstants.X_PLATFORM_TENANT_ID, + request.getHeader(HeaderConstants.X_PLATFORM_TENANT_ID), BillValidatorEnum.INVALID_PLATFORM_TENANT_ID, 20, + BillValidatorEnum.INVALID_PLATFORM_TENANT_ID_LENGTH); + + // Checks for X-Callback-URL + validatorBuilder.validateFieldIsNullAndMaxLengthWithFailureCode(resource, HeaderConstants.X_CALLBACKURL, + request.getHeader(HeaderConstants.X_CALLBACKURL), BillValidatorEnum.INVALID_CALLBACK_URL, 100, + BillValidatorEnum.INVALID_CALLBACK_URL_LENGTH); + + // Checks for X-PayerFSP-Id + validatorBuilder.validateFieldIsNullAndMaxLengthWithFailureCode(resource, HeaderConstants.X_PAYER_FSP_ID, + request.getHeader(HeaderConstants.X_PAYER_FSP_ID), BillValidatorEnum.INVALID_PAYER_FSP_ID, 20, + BillValidatorEnum.INVALID_PAYER_FSP_ID_LENGTH); + return handleValidationErrors(validatorBuilder); + + } + + public PhErrorDTO validateBillRTPRequest(Set requiredHeaders, HttpServletRequest request) { + final ValidatorBuilder validatorBuilder = new ValidatorBuilder(); + + List headers = getHeaderList(request); + + // Checks for unsupported parameters + unsupportedParameterValidator.handleRequiredParameterValidation(headers, requiredHeaders, validatorBuilder); + + // Checks for X-Client-Correlation-ID + validatorBuilder.validateFieldIsNullAndMaxLengthWithFailureCode(resource, HeaderConstants.X_CLIENT_CORRELATION_ID, + request.getHeader(HeaderConstants.X_CLIENT_CORRELATION_ID), BillValidatorEnum.INVALID_CORRELATION_ID, 20, + BillValidatorEnum.INVALID_CORRELATION_ID_LENGTH); + + // Checks for X-Platform-TenantId + validatorBuilder.validateFieldIsNullAndMaxLengthWithFailureCode(resource, HeaderConstants.X_PLATFORM_TENANT_ID, + request.getHeader(HeaderConstants.X_PLATFORM_TENANT_ID), BillValidatorEnum.INVALID_TENANT_ID, 20, + BillValidatorEnum.INVALID_TENANT_ID_LENGTH); + + // Checks for X-Biller-Id + validatorBuilder.validateFieldIsNullAndMaxLengthWithFailureCode(resource, HeaderConstants.X_BILLER_ID, + request.getHeader(HeaderConstants.X_BILLER_ID), BillValidatorEnum.INVALID_BILLER_ID, 20, + BillValidatorEnum.INVALID_BILLER_ID_LENGTH); + + // Checks for X-Callback-URL + validatorBuilder.validateFieldIsNullAndMaxLengthWithFailureCode(resource, HeaderConstants.X_CALLBACK_URL, + request.getHeader(HeaderConstants.X_CALLBACK_URL), BillValidatorEnum.INVALID_CALLBACK_URL, 100, + BillValidatorEnum.INVALID_CALLBACK_URL_LENGTH); + + // Checks for X-Registering-Institution-ID + validatorBuilder.validateFieldIgnoreNullAndMaxLengthWithFailureCode(resource, HeaderConstants.X_REGISTERING_INSTITUTION_ID, + request.getHeader(HeaderConstants.X_REGISTERING_INSTITUTION_ID), 100, + BillValidatorEnum.INVALID_REGISTERING_INSTITUTION_ID_LENGTH); + return handleValidationErrors(validatorBuilder); + } + + private PhErrorDTO handleValidationErrors(ValidatorBuilder validatorBuilder) { + if (validatorBuilder.hasError()) { + validatorBuilder.errorCategory(PaymentHubErrorCategory.Validation.toString()) + .errorCode(BillValidatorEnum.HEADER_VALIDATION_ERROR.getCode()) + .errorDescription(BillValidatorEnum.HEADER_VALIDATION_ERROR.getMessage()) + .developerMessage(BillValidatorEnum.HEADER_VALIDATION_ERROR.getMessage()) + .defaultUserMessage(BillValidatorEnum.HEADER_VALIDATION_ERROR.getMessage()); + + PhErrorDTO.PhErrorDTOBuilder phErrorDTOBuilder = new PhErrorDTO.PhErrorDTOBuilder(ExtValidationError.getErrorCode()); + phErrorDTOBuilder.fromValidatorBuilder(validatorBuilder); + return phErrorDTOBuilder.build(); + } + return null; + } + + public List getHeaderList(HttpServletRequest request) { + Enumeration headers = request.getHeaderNames(); + return Collections.list(request.getHeaderNames()); + } +} diff --git a/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/validators/UnsupportedParameterValidator.java b/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/validators/UnsupportedParameterValidator.java new file mode 100644 index 000000000..97b55bc64 --- /dev/null +++ b/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/validators/UnsupportedParameterValidator.java @@ -0,0 +1,70 @@ +package org.mifos.pheebillpay.validators; + +import java.util.List; +import java.util.Map; +import java.util.Set; +import lombok.extern.slf4j.Slf4j; +import org.mifos.connector.common.validation.ValidationCodeType; +import org.mifos.connector.common.validation.ValidatorBuilder; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +@Component +@Slf4j +public class UnsupportedParameterValidator { + + @Value("#{'${default_api_headers}'.split(',')}") + private Set defaultHeader; + + final StringBuilder validationErrorCode = new StringBuilder("error.msg.parameter.unsupported"); + + public void handleUnsupportedParameterValidation(Map additionalProperties, ValidatorBuilder validatorBuilder) { + + for (final String parameterName : additionalProperties.keySet()) { + final StringBuilder defaultEnglishMessage = new StringBuilder("The parameter ").append(parameterName) + .append(" is not supported."); + + ValidationCodeType validationCode = convertToStructuredErrorMessage(validationErrorCode.toString(), + defaultEnglishMessage.toString()); + validatorBuilder.failWithCode(validationCode); + } + + } + + public void handleRequiredParameterValidation(List fields, Set requiredFields, ValidatorBuilder validatorBuilder) { + + for (final String fieldName : fields) { + if (!fieldName.equals("additionalProperties") && !requiredFields.contains(fieldName) && !defaultHeader.contains(fieldName)) { + + final StringBuilder defaultEnglishMessage = new StringBuilder("The parameter ").append(fieldName) + .append(" is not supported."); + + ValidationCodeType validationCode = convertToStructuredErrorMessage(validationErrorCode.toString(), + defaultEnglishMessage.toString()); + validatorBuilder.failWithCode(validationCode); + } + } + + } + + private ValidationCodeType convertToStructuredErrorMessage(String errorCode, String errorMessage) { + return new ValidationCodeType() { + + @Override + public String getCode() { + return errorCode; + } + + @Override + public String getCategory() { + return "Validation"; + } + + @Override + public String getMessage() { + return errorMessage; + } + }; + } + +} diff --git a/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/zeebe/ZeebeClientConfiguration.java b/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/zeebe/ZeebeClientConfiguration.java new file mode 100644 index 000000000..7142bab51 --- /dev/null +++ b/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/zeebe/ZeebeClientConfiguration.java @@ -0,0 +1,26 @@ +package org.mifos.pheebillpay.zeebe; + +import io.camunda.zeebe.client.ZeebeClient; +import java.time.Duration; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +@ConditionalOnExpression("${zeebe.enabled:true}") +public class ZeebeClientConfiguration { + + @Value("${zeebe.broker.contactpoint}") + private String zeebeBrokerContactpoint; + + @Value("${zeebe.client.max-execution-threads}") + private int zeebeClientMaxThreads; + + @Bean + public ZeebeClient setup() { + return ZeebeClient.newClientBuilder().gatewayAddress(zeebeBrokerContactpoint).usePlaintext() + .defaultJobPollInterval(Duration.ofMillis(1)).defaultJobWorkerMaxJobsActive(2000) + .numJobWorkerExecutionThreads(zeebeClientMaxThreads).build(); + } +} diff --git a/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/zeebe/ZeebeProcessStarter.java b/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/zeebe/ZeebeProcessStarter.java new file mode 100644 index 000000000..38aaeb647 --- /dev/null +++ b/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/zeebe/ZeebeProcessStarter.java @@ -0,0 +1,62 @@ +package org.mifos.pheebillpay.zeebe; + +import io.camunda.zeebe.client.ZeebeClient; +import io.camunda.zeebe.client.api.response.ProcessInstanceEvent; +import java.time.Instant; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +/** + * Start a Zeebe workflow + */ +@Component +public class ZeebeProcessStarter { + + private static Logger logger = LoggerFactory.getLogger(ZeebeProcessStarter.class); + + @Autowired + private ZeebeClient zeebeClient; + + @Value("${transaction-id-length}") + private int transactionIdLength; + + public String startZeebeWorkflow(String workflowId, String request, Map extraVariables) { + String transactionId = generateTransactionId(); + + Map variables = new HashMap<>(); + variables.put(ZeebeVariables.TRANSACTION_ID, transactionId); + variables.put(ZeebeVariables.CHANNEL_REQUEST, request); + variables.put(ZeebeVariables.ORIGIN_DATE, Instant.now().toEpochMilli()); + if (extraVariables != null) { + variables.putAll(extraVariables); + } + + logger.info("starting workflow HERE:"); + // TODO if successful transfer response arrives in X timeout return it otherwise do callback + ProcessInstanceEvent instance = zeebeClient.newCreateInstanceCommand().bpmnProcessId(workflowId).latestVersion() + .variables(variables).send().join(); + + logger.info("zeebee workflow instance from process {} started with transactionId {}, instance key: {}", workflowId, transactionId, + instance.getProcessInstanceKey()); + return transactionId; + } + + // TODO generate proper cluster-safe transaction id + private String generateTransactionId() { + return UUID.randomUUID().toString(); + } + + /* + * private String randomCharOfSize(int size) { String data = + * "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; char[] arr = data.toCharArray(); StringBuilder + * s = new StringBuilder(); for (int i = 0; i < size; i++) { int index = (int) (Math.random() * data.length()); + * s.append(arr[index]); } return s.toString(); } + */ + +} diff --git a/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/zeebe/ZeebeVariables.java b/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/zeebe/ZeebeVariables.java new file mode 100644 index 000000000..bf7c55d0d --- /dev/null +++ b/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/zeebe/ZeebeVariables.java @@ -0,0 +1,47 @@ +package org.mifos.pheebillpay.zeebe; + +public final class ZeebeVariables { + + private ZeebeVariables() {} + + public static final String ACCOUNT = "account"; + public static final String CHANNEL_REQUEST = "channelRequest"; + public static final String ERROR_INFORMATION = "errorInformation"; + public static final String ERROR_DESCRIPTION = "errorDescription"; + public static final String IS_AUTHORISATION_REQUIRED = "isAuthorisationRequired"; + public static final String IS_RTP_REQUEST = "isRtpRequest"; + public static final String ORIGIN_DATE = "originDate"; + public static final String PARTY_ID = "partyId"; + public static final String PARTY_ID_TYPE = "partyIdType"; + public static final String TENANT_ID = "tenantId"; + public static final String TRANSACTION_ID = "transactionId"; + public static final String TRANSACTION_TYPE = "transactionType"; + public static final String CLIENTCORRELATIONID = "X-CorrelationID"; + public static final String PAYER_FSP_ID = "payerFspId"; + public static final String BILL_ID = "billId"; + public static final String FIELD = "field"; + public static final String CALLBACK_URL = "X-CallbackURL"; + public static final String BILLER_ID = "billerId"; + public static final String BILLER_NAME = "billerName"; + public static final String BILL_AMOUNT = "billAmount"; + public static final String BILLER_CATEGORY = "billerCategory"; + public static final String BILL_RTP_REQ = "billRTPReqBody"; + public static final String BILL_REQ_ID = "billRequestId"; + public static final String BILL_PAYMENTS_REQ = "billPaymentsReq"; + public static final String PAYMENTS_REF_ID = "paymentReferenceId"; + public static final String FIELDS = "fields"; + public static final String BILLER_TYPE = "billerType"; + public static final String BILLER_ACCOUNT = "billerAccount"; + public static final String BILLER_FETCH_FAILED = "billerFetchFailed"; + public static final String BILLER_DETAILS = "billerDetails"; + public static final String BILL_INQUIRY_RESPONSE = "billInquiryResponse"; + + public static final String BILL_FETCH_FAILED = "billFetchFailed"; + public static final String BILL_PAY_RESPONSE = "billPayResponse"; + public static final String BILL_PAY_FAILED = "billPayFailed"; + public static final String PAYER_FSP = "X-PayerFSP-Id"; + public static final String PLATFORM_TENANT = "Platform-TenantId"; + public static final String PAYER_RTP_REQ = "payerRtpRequest"; + public static final String RTP_STATUS = "rtpStatus"; + public static final String RTP_ID = "rtpId"; +} diff --git a/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/zeebe/ZeebeWorkers.java b/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/zeebe/ZeebeWorkers.java new file mode 100644 index 000000000..0315cedf1 --- /dev/null +++ b/ph-ee-bill-pay/src/main/java/org/mifos/pheebillpay/zeebe/ZeebeWorkers.java @@ -0,0 +1,383 @@ +package org.mifos.pheebillpay.zeebe; + +import static org.mifos.pheebillpay.zeebe.ZeebeVariables.BILLER_ACCOUNT; +import static org.mifos.pheebillpay.zeebe.ZeebeVariables.BILLER_DETAILS; +import static org.mifos.pheebillpay.zeebe.ZeebeVariables.BILLER_FETCH_FAILED; +import static org.mifos.pheebillpay.zeebe.ZeebeVariables.BILLER_ID; +import static org.mifos.pheebillpay.zeebe.ZeebeVariables.BILLER_NAME; +import static org.mifos.pheebillpay.zeebe.ZeebeVariables.BILLER_TYPE; +import static org.mifos.pheebillpay.zeebe.ZeebeVariables.BILL_AMOUNT; +import static org.mifos.pheebillpay.zeebe.ZeebeVariables.BILL_ID; +import static org.mifos.pheebillpay.zeebe.ZeebeVariables.BILL_INQUIRY_RESPONSE; +import static org.mifos.pheebillpay.zeebe.ZeebeVariables.BILL_PAYMENTS_REQ; +import static org.mifos.pheebillpay.zeebe.ZeebeVariables.BILL_PAY_FAILED; +import static org.mifos.pheebillpay.zeebe.ZeebeVariables.BILL_PAY_RESPONSE; +import static org.mifos.pheebillpay.zeebe.ZeebeVariables.BILL_RTP_REQ; +import static org.mifos.pheebillpay.zeebe.ZeebeVariables.CALLBACK_URL; +import static org.mifos.pheebillpay.zeebe.ZeebeVariables.CLIENTCORRELATIONID; +import static org.mifos.pheebillpay.zeebe.ZeebeVariables.ERROR_INFORMATION; +import static org.mifos.pheebillpay.zeebe.ZeebeVariables.PAYER_FSP; +import static org.mifos.pheebillpay.zeebe.ZeebeVariables.PAYER_RTP_REQ; +import static org.mifos.pheebillpay.zeebe.ZeebeVariables.PLATFORM_TENANT; +import static org.mifos.pheebillpay.zeebe.ZeebeVariables.RTP_ID; +import static org.mifos.pheebillpay.zeebe.ZeebeVariables.RTP_STATUS; +import static org.mifos.pheebillpay.zeebe.ZeebeVariables.TENANT_ID; +import static org.mifos.pheebillpay.zeebe.ZeebeVariables.TRANSACTION_ID; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import io.camunda.zeebe.client.ZeebeClient; +import io.camunda.zeebe.client.api.response.ActivatedJob; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; +import javax.annotation.PostConstruct; +import org.apache.camel.CamelContext; +import org.apache.camel.Exchange; +import org.apache.camel.ProducerTemplate; +import org.apache.http.conn.ssl.NoopHostnameVerifier; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClients; +import org.apache.http.ssl.SSLContextBuilder; +import org.json.JSONObject; +import org.mifos.pheebillpay.data.BillDetails; +import org.mifos.pheebillpay.data.BillPaymentsReqDTO; +import org.mifos.pheebillpay.data.BillRTPReqDTO; +import org.mifos.pheebillpay.data.BillRTPResponseDTO; +import org.mifos.pheebillpay.data.PayerRequestDTO; +import org.mifos.pheebillpay.data.ResponseDTO; +import org.mifos.pheebillpay.utils.Headers; +import org.mifos.pheebillpay.utils.SpringWrapperUtil; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; +import org.springframework.stereotype.Component; +import org.springframework.web.client.HttpClientErrorException; +import org.springframework.web.client.HttpServerErrorException; +import org.springframework.web.client.RestTemplate; + +@Component +public class ZeebeWorkers { + + private Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Autowired + private ZeebeClient zeebeClient; + + @Autowired + private ProducerTemplate producerTemplate; + + @Autowired + private CamelContext camelContext; + + @Autowired + private ObjectMapper objectMapper; + + @Value("${zeebe.client.evenly-allocated-max-jobs}") + private int workerMaxJobs; + @Value("${connector.contactpoint}") + private String connectorContactPoint; + @Value("${billpay.contactpoint}") + private String billPayContactPoint; + @Value("${billpay.endpoint.payerRtpResponse}") + private String payerRtpResponseEndpoint; + @Value("${payer_fsp.tenant}") + private String payerFspTenant; + @Value("${payer_fsp.mockPayerUnreachable.fspId}") + private String mockPayerUnreachableFspId; + @Value("${payer_fsp.mockPayerUnreachable.financialAddress}") + private String mockPayerUnreachableFinancialAddress; + @Value("${payer_fsp.mockDebitFailed.fspId}") + private String mockDebitFailedFspId; + @Value("${payer_fsp.mockDebitFailed.financialAddress}") + private String mockDebitFailedFinancialAddress; + + @Value("${status.billAcceptedId}") + private String billAcceptedId; + + @Value("${status.billTimeout}") + private int billTimeout; + + private static final ScheduledExecutorService scheduledThreadPoolExecutor = Executors.newScheduledThreadPool(10); + + @PostConstruct + public void setupWorkers() { + // billerdetails + zeebeClient.newWorker().jobType("discover-biller").handler((client, job) -> { + logger.info("Job '{}' started from process '{}' with key {}", job.getType(), job.getBpmnProcessId(), job.getKey()); + logWorkerDetails(job); + Map variables = job.getVariablesAsMap(); + Headers headers = new Headers.HeaderBuilder().addHeader(PLATFORM_TENANT, variables.get(TENANT_ID).toString()) + .addHeader(CLIENTCORRELATIONID, variables.get(CLIENTCORRELATIONID).toString()) + .addHeader(PAYER_FSP, variables.get("payerFspId").toString()).addHeader(BILL_ID, variables.get("billId").toString()) + .build(); + Exchange exchange = SpringWrapperUtil.getDefaultWrappedExchange(producerTemplate.getCamelContext(), headers, null); + producerTemplate.send("direct:biller-fetch", exchange); + Boolean response = exchange.getProperty(BILLER_FETCH_FAILED, Boolean.class); + variables.put(BILLER_FETCH_FAILED, response); + if (variables.get(BILLER_FETCH_FAILED).equals(false)) { + variables.put(BILLER_DETAILS, exchange.getProperty(BILLER_DETAILS, String.class)); + variables.put(BILLER_ID, exchange.getProperty(BILLER_ID, String.class)); + variables.put(BILLER_NAME, exchange.getProperty(BILLER_NAME, String.class)); + variables.put(BILLER_TYPE, exchange.getProperty(BILLER_TYPE, String.class)); + variables.put(BILLER_ACCOUNT, exchange.getProperty(BILLER_ACCOUNT, String.class)); + variables.put(BILL_ID, exchange.getProperty(BILL_ID, String.class)); + } else { + variables.put(ERROR_INFORMATION, exchange.getProperty(ERROR_INFORMATION)); + } + logger.info("Zeebe variable {}", job.getVariablesAsMap()); + + zeebeClient.newCompleteCommand(job.getKey()).variables(variables).send().join(); + + }).name("discover-biller").maxJobsActive(workerMaxJobs).open(); + + // setting callback for inquiry api + zeebeClient.newWorker().jobType("billFetchResponse").handler((client, job) -> { + logger.info("Job '{}' started from process '{}' with key {}", job.getType(), job.getBpmnProcessId(), job.getKey()); + logWorkerDetails(job); + Map variables = job.getVariablesAsMap(); + Headers headers = new Headers.HeaderBuilder().addHeader("Platform-TenantId", variables.get(TENANT_ID).toString()) + .addHeader(CLIENTCORRELATIONID, variables.get(CLIENTCORRELATIONID).toString()) + .addHeader(PAYER_FSP, variables.get("payerFspId").toString()).addHeader(BILL_ID, variables.get(BILL_ID).toString()) + .build(); + Exchange exchange = SpringWrapperUtil.getDefaultWrappedExchange(producerTemplate.getCamelContext(), headers, null); + if (variables.get(BILLER_DETAILS) != null) { + exchange.setProperty(BILLER_DETAILS, variables.get(BILLER_DETAILS).toString()); + } + exchange.setProperty(CALLBACK_URL, variables.get(CALLBACK_URL).toString()); + exchange.setProperty(BILL_INQUIRY_RESPONSE, variables.get(BILL_INQUIRY_RESPONSE)); + exchange.setProperty(ERROR_INFORMATION, variables.get(ERROR_INFORMATION)); + exchange.setProperty(CLIENTCORRELATIONID, variables.get(CLIENTCORRELATIONID)); + producerTemplate.send("direct:bill-inquiry-response", exchange); + variables.put(BILL_PAY_RESPONSE, exchange.getIn().getBody(String.class)); + variables.put(BILL_PAY_FAILED, exchange.getProperty(BILL_PAY_FAILED)); + logger.info("Zeebe variable {}", job.getVariablesAsMap()); + client.newCompleteCommand(job.getKey()).variables(variables).send(); + }).name("billFetchResponse").maxJobsActive(workerMaxJobs).open(); + + // setting response to callback url for payment status + zeebeClient.newWorker().jobType("billPayResponse").handler((client, job) -> { + logger.info("Job '{}' started from process '{}' with key {}", job.getType(), job.getBpmnProcessId(), job.getKey()); + logWorkerDetails(job); + Map variables = job.getVariablesAsMap(); + String currentBillId = variables.get(BILL_ID).toString(); + if (currentBillId.equals(billAcceptedId)) { + logger.debug("Bill Id matches, moving to execution pause"); + pauseExec(); + } + Headers headers = new Headers.HeaderBuilder().addHeader("Platform-TenantId", variables.get(TENANT_ID).toString()) + .addHeader(CLIENTCORRELATIONID, variables.get(CLIENTCORRELATIONID).toString()) + .addHeader(PAYER_FSP, variables.get("payerFspId").toString()).addHeader(BILL_ID, variables.get(BILL_ID).toString()) + .build(); + Exchange exchange = SpringWrapperUtil.getDefaultWrappedExchange(producerTemplate.getCamelContext(), headers, null); + exchange.setProperty(CALLBACK_URL, variables.get(CALLBACK_URL).toString()); + exchange.setProperty(BILL_PAY_RESPONSE, variables.get(BILL_PAY_RESPONSE).toString()); + exchange.setProperty("code", variables.get("code")); + exchange.setProperty("reason", variables.get("reason")); + exchange.setProperty("status", variables.get("status")); + producerTemplate.send("direct:paymentNotification-response", exchange); + variables.put(BILL_PAY_RESPONSE, exchange.getProperty(BILL_PAY_RESPONSE)); + variables.put("state", "SUCCESS"); + zeebeClient.newCompleteCommand(job.getKey()).variables(variables).send(); + logger.info("Zeebe variable {}", job.getVariablesAsMap()); + }).name("billPayResponse").maxJobsActive(workerMaxJobs).open(); + + zeebeClient.newWorker().jobType("payerRtpRequest").handler((client, job) -> { + logger.info("Job '{}' started from process '{}' with key {}", job.getType(), job.getBpmnProcessId(), job.getKey()); + Map variables = job.getVariablesAsMap(); + String url = connectorContactPoint + "/billTransferRequests"; + String tenantId = variables.get("tenantId").toString(); + String clientCorrelation = (String) variables.get("X-CorrelationID"); + + variables.put("payerTenantId", payerFspTenant); + variables.put("payerCallbackUrl", billPayContactPoint + payerRtpResponseEndpoint); + String body = variables.get(BILL_RTP_REQ).toString(); + String billerId = variables.get("billerId").toString(); + BillRTPReqDTO billRTPReqDTO = objectMapper.readValue(body, BillRTPReqDTO.class); + if (billRTPReqDTO.getPayerFspDetails() != null) { + if (billRTPReqDTO.getPayerFspDetails().getPayerFSPID().equals(mockPayerUnreachableFspId) + && billRTPReqDTO.getPayerFspDetails().getFinancialAddress().equals(mockPayerUnreachableFinancialAddress)) { + variables.put("payerRtpRequestSuccess", false); + variables.put("errorInformation", "Payer FI was unreachable"); + } else if (billRTPReqDTO.getPayerFspDetails().getPayerFSPID().equals(mockDebitFailedFspId) + && billRTPReqDTO.getPayerFspDetails().getFinancialAddress().equals(mockDebitFailedFinancialAddress)) { + variables.put("payerRtpRequestSuccess", false); + variables.put("errorInformation", "Payer FSP is unable to debit amount"); + } else { + variables.put("payerRtpRequestSuccess", true); + } + } + + variables.put(BILLER_NAME, billRTPReqDTO.getBillDetails().getBillerName()); + variables.put(BILL_AMOUNT, billRTPReqDTO.getBillDetails().getAmount()); + variables.put(RTP_ID, 123456); + PayerRequestDTO payerRequestDTO = new PayerRequestDTO(); + payerRequestDTO.setRequestId(String.valueOf(job.getElementInstanceKey())); + payerRequestDTO.setRtpId(123456); + payerRequestDTO.setTransactionId(variables.get(TRANSACTION_ID).toString()); + payerRequestDTO.setBillDetails(new BillDetails(billRTPReqDTO.getBillID(), billRTPReqDTO.getBillDetails().getBillerName(), + billRTPReqDTO.getBillDetails().getAmount())); + ObjectMapper objectMapper = new ObjectMapper(); + String jsonPayload = objectMapper.writeValueAsString(payerRequestDTO); + + HttpHeaders headers = new HttpHeaders(); + headers.set("X-Platform-TenantId", payerFspTenant); + headers.set("X-Client-Correlation-ID", clientCorrelation); + headers.set("X-Biller-Id", billerId); + headers.set("X-Callback-URL", billPayContactPoint + payerRtpResponseEndpoint); + + headers.setContentType(MediaType.APPLICATION_JSON); + + HttpEntity requestEntity = new HttpEntity<>(jsonPayload, headers); + + RestTemplate restTemplate = new RestTemplate(); + + CloseableHttpClient httpClient = HttpClients.custom() + .setSSLContext(new SSLContextBuilder().loadTrustMaterial(null, (certificate, authType) -> true).build()) + .setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE).build(); + restTemplate.setRequestFactory(new HttpComponentsClientHttpRequestFactory(httpClient)); + + ResponseEntity responseEntity = null; + + try { + responseEntity = restTemplate.exchange(url, HttpMethod.POST, requestEntity, ResponseDTO.class); + } catch (HttpClientErrorException | HttpServerErrorException e) { + logger.error(e.getMessage()); + variables.put(PAYER_RTP_REQ, false); + } + if (responseEntity != null && responseEntity.getBody().getResponseCode().equals("00")) { + variables.put(PAYER_RTP_REQ, true); + } else { + variables.put(PAYER_RTP_REQ, false); + } + client.newCompleteCommand(job.getKey()).variables(variables).send(); + }).name("payerRtpRequest").maxJobsActive(workerMaxJobs).open(); + + zeebeClient.newWorker().jobType("billerRtpResponse").handler((client, job) -> { + logger.info("Job '{}' started from process '{}' with key {}", job.getType(), job.getBpmnProcessId(), job.getKey()); + Map variables = job.getVariablesAsMap(); + String tenantId = variables.get(TENANT_ID).toString(); + String correlationId = variables.get(CLIENTCORRELATIONID).toString(); + String callbackUrl = variables.get(CALLBACK_URL).toString(); + HttpHeaders headers = new HttpHeaders(); + + String billId = variables.get(BILL_ID).toString(); + String billerName = variables.get(BILLER_NAME).toString(); + String amount = variables.get(BILL_AMOUNT).toString(); + String rtpStatus = variables.get(RTP_STATUS).toString(); + String rtpId = variables.get(RTP_ID).toString(); + BillPaymentsReqDTO billPaymentsReqDTO = new BillPaymentsReqDTO(correlationId, generateUniqueNumber(12), billId, + generateUniqueNumber(12)); + variables.put(BILL_PAYMENTS_REQ, billPaymentsReqDTO); + + headers.set("X-Platform-TenantId", tenantId); + headers.set("X-Client-Correlation-ID", correlationId); + + headers.setContentType(MediaType.APPLICATION_JSON); + BillRTPResponseDTO billRTPResponseDTO = new BillRTPResponseDTO(); + billRTPResponseDTO.setRequestId(correlationId); + billRTPResponseDTO.setBillId(billId); + billRTPResponseDTO.setRtpStatus(rtpStatus); + billRTPResponseDTO.setRtpId(rtpId); + variables.put("state", "REQUEST_ACCEPTED"); + // billRTPResponseDTO.setRejectReason(rejectReason); + + HttpEntity requestEntity = new HttpEntity<>(billRTPResponseDTO, headers); + + RestTemplate restTemplate = new RestTemplate(); + + CloseableHttpClient httpClient = HttpClients.custom() + .setSSLContext(new SSLContextBuilder().loadTrustMaterial(null, (certificate, authType) -> true).build()) + .setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE).build(); + restTemplate.setRequestFactory(new HttpComponentsClientHttpRequestFactory(httpClient)); + + ResponseEntity responseEntity = null; + + try { + restTemplate.exchange(callbackUrl, HttpMethod.POST, requestEntity, ResponseDTO.class); + } catch (HttpClientErrorException | HttpServerErrorException e) { + logger.error(e.getMessage()); + } + client.newCompleteCommand(job.getKey()).variables(variables).send(); + }).name("billerRtpResponse").maxJobsActive(workerMaxJobs).open(); + + zeebeClient.newWorker().jobType("sendError").handler((client, job) -> { + logger.info("Job '{}' started from process '{}' with key {}", job.getType(), job.getBpmnProcessId(), job.getKey()); + Map variables = job.getVariablesAsMap(); + String correlationId = variables.get(CLIENTCORRELATIONID).toString(); + + RestTemplate restTemplate = new RestTemplate(); + CloseableHttpClient httpClient = HttpClients.custom() + .setSSLContext(new SSLContextBuilder().loadTrustMaterial(null, (certificate, authType) -> true).build()) + .setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE).build(); + restTemplate.setRequestFactory(new HttpComponentsClientHttpRequestFactory(httpClient)); + String callbackUrl = variables.get(CALLBACK_URL).toString(); + HttpHeaders headers = new HttpHeaders(); + headers.add("X-Client-Correlation-ID", correlationId); + ResponseEntity responseEntity = null; + + headers.setContentType(MediaType.APPLICATION_JSON); + Map errorInfo = new HashMap<>(); + errorInfo.put("errorMessage", variables.get("errorInformation").toString()); + ObjectMapper objectMapper = new ObjectMapper(); + String jsonBody = null; + try { + jsonBody = objectMapper.writeValueAsString(errorInfo); + } catch (JsonProcessingException e) { + // Handle the exception appropriately + logger.error(e.getMessage()); + } + HttpEntity requestEntity = new HttpEntity<>(jsonBody, headers); + + try { + restTemplate.exchange(callbackUrl, HttpMethod.POST, requestEntity, String.class); + } catch (HttpClientErrorException | HttpServerErrorException e) { + logger.error(e.getMessage()); + } + + client.newCompleteCommand(job.getKey()).variables(variables).send(); + }).name("sendError").maxJobsActive(workerMaxJobs).open(); + + } + + private void logWorkerDetails(ActivatedJob job) { + JSONObject jsonJob = new JSONObject(); + jsonJob.put("bpmnProcessId", job.getBpmnProcessId()); + jsonJob.put("elementInstanceKey", job.getElementInstanceKey()); + jsonJob.put("jobKey", job.getKey()); + jsonJob.put("jobType", job.getType()); + jsonJob.put("workflowElementId", job.getElementId()); + jsonJob.put("workflowDefinitionVersion", job.getProcessDefinitionVersion()); + jsonJob.put("workflowKey", job.getProcessDefinitionKey()); + jsonJob.put("workflowInstanceKey", job.getProcessInstanceKey()); + logger.info("Job started: {}", jsonJob.toString(4)); + } + + public String generateUniqueNumber(int length) { + StringBuilder sb = new StringBuilder(); + while (sb.length() < length) { + sb.append(UUID.randomUUID().toString().replaceAll("-", "")); + } + return sb.substring(0, length); + } + + private void pauseExec() { + try { + logger.debug("Pausing execution for capturing intermediary status "); + scheduledThreadPoolExecutor.schedule(() -> { }, billTimeout, TimeUnit.SECONDS).get(); + } catch (Exception exception) { + throw new RuntimeException(exception); + } + logger.debug("Resuming execution post pause"); + } +} diff --git a/ph-ee-bill-pay/src/main/resources/application.yml b/ph-ee-bill-pay/src/main/resources/application.yml new file mode 100644 index 000000000..826183ee3 --- /dev/null +++ b/ph-ee-bill-pay/src/main/resources/application.yml @@ -0,0 +1,125 @@ +camel: + server-port: 5000 + springboot: + main-run-controller: true + dataformat: + json-jackson: + auto-discover-object-mapper: true + +dfspids: "DFSPIDS" + +server: + port: 8080 + +zeebe: + client: + max-execution-threads: 100 + evenly-allocated-max-jobs: 100 + # max-execution-threads: 100 + # number-of-workers: 8 + # evenly-allocated-max-jobs: "#{${zeebe.client.max-execution-threads} / ${zeebe.client.number-of-workers}}" + broker: + contactpoint: "127.0.0.1:26500" + +bpmn: + flows: + bill-pay: "bill_inquiry-{dfspid}" + payment-notification: "payment_notification-{dfspid}" + bill-request: "bill_request-{dfspid}" + +ams: + local: + server-cert-check: false + enabled: true + + +logging: + level: + root: INFO + +async: + core_pool_size: 10 + max_pool_size: 10 + queue_capacity: 100 + +threshold: + amount: 20000 + + +billers: + details: + - id: "001" + biller: "Biller1" + billerAccount: "BillerAccount1" + billerCategory: "BillerCategory1" + - id: "002" + biller: "Biller2" + billerAccount: "BillerAccount2" + billerCategory: "BillerCategory2" + - id: "003" + biller: "Biller3" + billerAccount: "BillerAccount3" + billerCategory: "BillerCategory3" + - id: "004" + biller: "Biller4" + billerAccount: "BillerAccount4" + billerCategory: "BillerCategory4" + - id: "007" + biller: "Biller7" + billerAccount: "BillerAccount7" + billerCategory: "BillerCategory7" + - id: "008" + biller: "Biller8" + billerAccount: "BillerAccount8" + billerCategory: "BillerCategory8" + +connector: + contactpoint: "http://ph-ee-connector:8080" + endpoint: + payerRtp: "/billTransferRequests" + +billpay: + contactpoint: "http://ph-ee-bill-pay:8080" + endpoint: + payerRtpResponse: "/billTransferRequests" + +payer_fsp: + tenant: "lion" + mockPayerUnreachable: + fspId: "rhino" + financialAddress: "122333" + mockDebitFailed: + fspId: "rhino" + financialAddress: "1223334444" + +billPay: + FspNotOnboarded : "003" + billIdEmptyOriginal : "004" + billIdEmpty : "00" + billPayTimeoutId : "005" + + +management: + endpoint: + health: + enabled: true + probes: + enabled: true + liveness: + enabled: true + readiness: + enabled: true + +operations: + url: "http://ph-ee-operations-app/api/v1" + auth-enabled: false + endpoint: + transfers: "/transfers?page=0&size=1&" + transactionReq: "/transactionRequests/?page=0&size=1" + +status: + billAcceptedId: "1234" + billTimeout: 6 + + +default_api_headers: "user-agent,accept,postman-token,host,accept-encoding,connection,content-type,content-length,x-request-id,x-real-ip,x-forwarded-host,x-forwarded-port,x-forwarded-proto,x-forwarded-scheme,x-scheme" diff --git a/ph-ee-bill-pay/src/main/resources/billerAggregator.yml b/ph-ee-bill-pay/src/main/resources/billerAggregator.yml new file mode 100644 index 000000000..e07509c6e --- /dev/null +++ b/ph-ee-bill-pay/src/main/resources/billerAggregator.yml @@ -0,0 +1,14 @@ +billers: + details: + - id: "001" + biller: "Biller1" + billerAccount: "BillerAccount1" + billerCategory: "BillerCategory1" + - id: "002" + biller: "Biller2" + billerAccount: "BillerAccount2" + billerCategory: "BillerCategory2" + - id: "004" + biller: "Biller4" + billerAccount: "BillerAccount4" + billerCategory: "BillerCategory4" diff --git a/ph-ee-bulk-processor/.circleci/config.yml b/ph-ee-bulk-processor/.circleci/config.yml new file mode 100644 index 000000000..d7ead11a0 --- /dev/null +++ b/ph-ee-bulk-processor/.circleci/config.yml @@ -0,0 +1,102 @@ +version: 2.1 +executors: + docker-executor: + docker: + - image: circleci/openjdk:17-buster-node-browsers-legacy + auth: + username: $DOCKERHUB_USERNAME + password: $DOCKERHUB_PASSWORD + +jobs: + build_and_push_tag_image: + executor: docker-executor + environment: + JVM_OPTS: -Xmx512m + TERM: dumb + GITHUB_TOKEN: ${GITHUB_TOKEN} # Add the GitHub token as an environment variable + + steps: + - checkout + - setup_remote_docker: + version: 20.10.14 + - run: + name: Build and Push Docker tag Image + command: | + # Set environment variables + IMAGE_TAG=$CIRCLE_TAG + + # Check if the Docker image with the same tag already exists in Docker Hub + if curl -s -f -u "$DOCKERHUB_USERNAME":"$DOCKERHUB_PASSWORD" "https://hub.docker.com/v2/repositories/fynarfin/ph-ee-bulk-processor/tags/$IMAGE_TAG" > /dev/null; then + echo "Skipping the build and push as the tag $IMAGE_TAG already exists in Docker Hub." + exit 0 + fi + + # Build and tag the Docker image + ./gradlew bootJar + docker build -t "fynarfin/ph-ee-bulk-processor:$IMAGE_TAG" . + + # Push the Docker image to Docker Hub + docker login -u "$DOCKERHUB_USERNAME" -p "$DOCKERHUB_PASSWORD" + docker push "fynarfin/ph-ee-bulk-processor:$IMAGE_TAG" + + # when: always # The job will be executed even if there's no match for the tag filter + + build_and_push_latest_image: + executor: docker-executor + environment: + JVM_OPTS: -Xmx512m + TERM: dumb + + steps: + - checkout + # Install Docker to build and push the image + - setup_remote_docker: + version: 20.10.14 + + # Build the Docker image + - run: + name: Build Docker image + command: | + ./gradlew checkstyleMain + ./gradlew bootJar + docker build -t fynarfin/ph-ee-bulk-processor:latest . + if [ "$CIRCLE_BRANCH" != "develop" ]; then + PR_NUMBER=$(basename $CIRCLE_PULL_REQUEST) + PR_TITLE=$(curl -sSL "https://api.github.com/repos/fynarfin/$CIRCLE_PR_REPONAME/pulls/$PR_NUMBER" | jq -r '.title') + JIRA_STORY=$(echo $PR_TITLE | cut -d "[" -f2 | cut -d "]" -f1 | tr '[A-Z]' '[a-z]') + if [ -z "$JIRA_STORY" ]; then echo "Invalid PR title" && exit 1; else echo "Ticket NO: $JIRA_STORY"; fi + docker image tag fynarfin/$CIRCLE_PR_REPONAME:latest fynarfin/$CIRCLE_PR_REPONAME:$JIRA_STORY + fi + + # Log in to DockerHub using environment variables + - run: + name: Login to DockerHub + command: echo "${DOCKERHUB_PASSWORD}" | docker login -u "${DOCKERHUB_USERNAME}" --password-stdin + + # Push the Docker image to DockerHub + - run: + name: Push Docker image to DockerHub + command: | + if [ "$CIRCLE_BRANCH" = "develop" ]; then + docker push fynarfin/ph-ee-bulk-processor:latest + fi + if [ "$CIRCLE_BRANCH" != "develop" ]; then + PR_NUMBER=$(basename $CIRCLE_PULL_REQUEST) + PR_TITLE=$(curl -sSL "https://api.github.com/repos/fynarfin/$CIRCLE_PR_REPONAME/pulls/$PR_NUMBER" | jq -r '.title') + JIRA_STORY=$(echo $PR_TITLE | cut -d "[" -f2 | cut -d "]" -f1 | tr '[A-Z]' '[a-z]') + docker push fynarfin/$CIRCLE_PR_REPONAME:${JIRA_STORY} + fi + +workflows: + version: 2 + build-and-push: + jobs: + - build_and_push_tag_image: + filters: + tags: + only: /^v\d+\.\d+\.\d+$/ # Match tags in the format v1.2.3 + context: + - DOCKER + - build_and_push_latest_image: + context: + - DOCKER diff --git a/ph-ee-bulk-processor/.github/pull_request_template.md b/ph-ee-bulk-processor/.github/pull_request_template.md new file mode 100644 index 000000000..bcf84d8d0 --- /dev/null +++ b/ph-ee-bulk-processor/.github/pull_request_template.md @@ -0,0 +1,22 @@ +## Description + +* PR title should have jira ticket enclosed in `[]`.
+Format: ``` [jira_ticket] description```
+ex: [phee-123] PR title. +* Add a link to the Jira ticket. +* Describe the changes made and why they were made. + +## Checklist + +Please make sure these boxes are checked before submitting your pull request - thanks! +- [ ] Followed the PR title naming convention mentioned above. + +- [ ] Design related bullet points or design document link related to this PR added in the description above. + +- [ ] Updated corresponding Postman Collection or Api documentation for the changes in this PR. + +- [ ] Created/updated unit or integration tests for verifying the changes made. + +- [ ] Added required Swagger annotation and update API documentation with details of any API changes if applicable + +- [ ] Followed the naming conventions as given in https://docs.google.com/document/d/1Q4vaMSzrTxxh9TS0RILuNkSkYCxotuYk1Xe0CMIkkCU/edit?usp=sharing diff --git a/ph-ee-bulk-processor/.gitignore b/ph-ee-bulk-processor/.gitignore new file mode 100644 index 000000000..14cce966c --- /dev/null +++ b/ph-ee-bulk-processor/.gitignore @@ -0,0 +1,39 @@ +HELP.md +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/**/target/ +!**/src/test/**/target/ +.gradle +build/ +!gradle/wrapper/gradle-wrapper.jar + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ +!**/src/main/**/build/ +!**/src/test/**/build/ + +### VS Code ### +.vscode/ + +.DS_Store +/.mvn \ No newline at end of file diff --git a/ph-ee-bulk-processor/Dockerfile b/ph-ee-bulk-processor/Dockerfile new file mode 100644 index 000000000..ac38c28a2 --- /dev/null +++ b/ph-ee-bulk-processor/Dockerfile @@ -0,0 +1,5 @@ +FROM openjdk:17 +EXPOSE 5000 + +COPY build/libs/*.jar . +CMD java -jar *.jar \ No newline at end of file diff --git a/ph-ee-bulk-processor/LICENSE.md b/ph-ee-bulk-processor/LICENSE.md new file mode 100644 index 000000000..a612ad981 --- /dev/null +++ b/ph-ee-bulk-processor/LICENSE.md @@ -0,0 +1,373 @@ +Mozilla Public License Version 2.0 +================================== + +1. Definitions +-------------- + +1.1. "Contributor" + means each individual or legal entity that creates, contributes to + the creation of, or owns Covered Software. + +1.2. "Contributor Version" + means the combination of the Contributions of others (if any) used + by a Contributor and that particular Contributor's Contribution. + +1.3. "Contribution" + means Covered Software of a particular Contributor. + +1.4. "Covered Software" + means Source Code Form to which the initial Contributor has attached + the notice in Exhibit A, the Executable Form of such Source Code + Form, and Modifications of such Source Code Form, in each case + including portions thereof. + +1.5. "Incompatible With Secondary Licenses" + means + + (a) that the initial Contributor has attached the notice described + in Exhibit B to the Covered Software; or + + (b) that the Covered Software was made available under the terms of + version 1.1 or earlier of the License, but not also under the + terms of a Secondary License. + +1.6. "Executable Form" + means any form of the work other than Source Code Form. + +1.7. "Larger Work" + means a work that combines Covered Software with other material, in + a separate file or files, that is not Covered Software. + +1.8. "License" + means this document. + +1.9. "Licensable" + means having the right to grant, to the maximum extent possible, + whether at the time of the initial grant or subsequently, any and + all of the rights conveyed by this License. + +1.10. "Modifications" + means any of the following: + + (a) any file in Source Code Form that results from an addition to, + deletion from, or modification of the contents of Covered + Software; or + + (b) any new file in Source Code Form that contains any Covered + Software. + +1.11. "Patent Claims" of a Contributor + means any patent claim(s), including without limitation, method, + process, and apparatus claims, in any patent Licensable by such + Contributor that would be infringed, but for the grant of the + License, by the making, using, selling, offering for sale, having + made, import, or transfer of either its Contributions or its + Contributor Version. + +1.12. "Secondary License" + means either the GNU General Public License, Version 2.0, the GNU + Lesser General Public License, Version 2.1, the GNU Affero General + Public License, Version 3.0, or any later versions of those + licenses. + +1.13. "Source Code Form" + means the form of the work preferred for making modifications. + +1.14. "You" (or "Your") + means an individual or a legal entity exercising rights under this + License. For legal entities, "You" includes any entity that + controls, is controlled by, or is under common control with You. For + purposes of this definition, "control" means (a) the power, direct + or indirect, to cause the direction or management of such entity, + whether by contract or otherwise, or (b) ownership of more than + fifty percent (50%) of the outstanding shares or beneficial + ownership of such entity. + +2. License Grants and Conditions +-------------------------------- + +2.1. Grants + +Each Contributor hereby grants You a world-wide, royalty-free, +non-exclusive license: + +(a) under intellectual property rights (other than patent or trademark) + Licensable by such Contributor to use, reproduce, make available, + modify, display, perform, distribute, and otherwise exploit its + Contributions, either on an unmodified basis, with Modifications, or + as part of a Larger Work; and + +(b) under Patent Claims of such Contributor to make, use, sell, offer + for sale, have made, import, and otherwise transfer either its + Contributions or its Contributor Version. + +2.2. Effective Date + +The licenses granted in Section 2.1 with respect to any Contribution +become effective for each Contribution on the date the Contributor first +distributes such Contribution. + +2.3. Limitations on Grant Scope + +The licenses granted in this Section 2 are the only rights granted under +this License. No additional rights or licenses will be implied from the +distribution or licensing of Covered Software under this License. +Notwithstanding Section 2.1(b) above, no patent license is granted by a +Contributor: + +(a) for any code that a Contributor has removed from Covered Software; + or + +(b) for infringements caused by: (i) Your and any other third party's + modifications of Covered Software, or (ii) the combination of its + Contributions with other software (except as part of its Contributor + Version); or + +(c) under Patent Claims infringed by Covered Software in the absence of + its Contributions. + +This License does not grant any rights in the trademarks, service marks, +or logos of any Contributor (except as may be necessary to comply with +the notice requirements in Section 3.4). + +2.4. Subsequent Licenses + +No Contributor makes additional grants as a result of Your choice to +distribute the Covered Software under a subsequent version of this +License (see Section 10.2) or under the terms of a Secondary License (if +permitted under the terms of Section 3.3). + +2.5. Representation + +Each Contributor represents that the Contributor believes its +Contributions are its original creation(s) or it has sufficient rights +to grant the rights to its Contributions conveyed by this License. + +2.6. Fair Use + +This License is not intended to limit any rights You have under +applicable copyright doctrines of fair use, fair dealing, or other +equivalents. + +2.7. Conditions + +Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted +in Section 2.1. + +3. Responsibilities +------------------- + +3.1. Distribution of Source Form + +All distribution of Covered Software in Source Code Form, including any +Modifications that You create or to which You contribute, must be under +the terms of this License. You must inform recipients that the Source +Code Form of the Covered Software is governed by the terms of this +License, and how they can obtain a copy of this License. You may not +attempt to alter or restrict the recipients' rights in the Source Code +Form. + +3.2. Distribution of Executable Form + +If You distribute Covered Software in Executable Form then: + +(a) such Covered Software must also be made available in Source Code + Form, as described in Section 3.1, and You must inform recipients of + the Executable Form how they can obtain a copy of such Source Code + Form by reasonable means in a timely manner, at a charge no more + than the cost of distribution to the recipient; and + +(b) You may distribute such Executable Form under the terms of this + License, or sublicense it under different terms, provided that the + license for the Executable Form does not attempt to limit or alter + the recipients' rights in the Source Code Form under this License. + +3.3. Distribution of a Larger Work + +You may create and distribute a Larger Work under terms of Your choice, +provided that You also comply with the requirements of this License for +the Covered Software. If the Larger Work is a combination of Covered +Software with a work governed by one or more Secondary Licenses, and the +Covered Software is not Incompatible With Secondary Licenses, this +License permits You to additionally distribute such Covered Software +under the terms of such Secondary License(s), so that the recipient of +the Larger Work may, at their option, further distribute the Covered +Software under the terms of either this License or such Secondary +License(s). + +3.4. Notices + +You may not remove or alter the substance of any license notices +(including copyright notices, patent notices, disclaimers of warranty, +or limitations of liability) contained within the Source Code Form of +the Covered Software, except that You may alter any license notices to +the extent required to remedy known factual inaccuracies. + +3.5. Application of Additional Terms + +You may choose to offer, and to charge a fee for, warranty, support, +indemnity or liability obligations to one or more recipients of Covered +Software. However, You may do so only on Your own behalf, and not on +behalf of any Contributor. You must make it absolutely clear that any +such warranty, support, indemnity, or liability obligation is offered by +You alone, and You hereby agree to indemnify every Contributor for any +liability incurred by such Contributor as a result of warranty, support, +indemnity or liability terms You offer. You may include additional +disclaimers of warranty and limitations of liability specific to any +jurisdiction. + +4. Inability to Comply Due to Statute or Regulation +--------------------------------------------------- + +If it is impossible for You to comply with any of the terms of this +License with respect to some or all of the Covered Software due to +statute, judicial order, or regulation then You must: (a) comply with +the terms of this License to the maximum extent possible; and (b) +describe the limitations and the code they affect. Such description must +be placed in a text file included with all distributions of the Covered +Software under this License. Except to the extent prohibited by statute +or regulation, such description must be sufficiently detailed for a +recipient of ordinary skill to be able to understand it. + +5. Termination +-------------- + +5.1. The rights granted under this License will terminate automatically +if You fail to comply with any of its terms. However, if You become +compliant, then the rights granted under this License from a particular +Contributor are reinstated (a) provisionally, unless and until such +Contributor explicitly and finally terminates Your grants, and (b) on an +ongoing basis, if such Contributor fails to notify You of the +non-compliance by some reasonable means prior to 60 days after You have +come back into compliance. Moreover, Your grants from a particular +Contributor are reinstated on an ongoing basis if such Contributor +notifies You of the non-compliance by some reasonable means, this is the +first time You have received notice of non-compliance with this License +from such Contributor, and You become compliant prior to 30 days after +Your receipt of the notice. + +5.2. If You initiate litigation against any entity by asserting a patent +infringement claim (excluding declaratory judgment actions, +counter-claims, and cross-claims) alleging that a Contributor Version +directly or indirectly infringes any patent, then the rights granted to +You by any and all Contributors for the Covered Software under Section +2.1 of this License shall terminate. + +5.3. In the event of termination under Sections 5.1 or 5.2 above, all +end user license agreements (excluding distributors and resellers) which +have been validly granted by You or Your distributors under this License +prior to termination shall survive termination. + +************************************************************************ +* * +* 6. Disclaimer of Warranty * +* ------------------------- * +* * +* Covered Software is provided under this License on an "as is" * +* basis, without warranty of any kind, either expressed, implied, or * +* statutory, including, without limitation, warranties that the * +* Covered Software is free of defects, merchantable, fit for a * +* particular purpose or non-infringing. The entire risk as to the * +* quality and performance of the Covered Software is with You. * +* Should any Covered Software prove defective in any respect, You * +* (not any Contributor) assume the cost of any necessary servicing, * +* repair, or correction. This disclaimer of warranty constitutes an * +* essential part of this License. No use of any Covered Software is * +* authorized under this License except under this disclaimer. * +* * +************************************************************************ + +************************************************************************ +* * +* 7. Limitation of Liability * +* -------------------------- * +* * +* Under no circumstances and under no legal theory, whether tort * +* (including negligence), contract, or otherwise, shall any * +* Contributor, or anyone who distributes Covered Software as * +* permitted above, be liable to You for any direct, indirect, * +* special, incidental, or consequential damages of any character * +* including, without limitation, damages for lost profits, loss of * +* goodwill, work stoppage, computer failure or malfunction, or any * +* and all other commercial damages or losses, even if such party * +* shall have been informed of the possibility of such damages. This * +* limitation of liability shall not apply to liability for death or * +* personal injury resulting from such party's negligence to the * +* extent applicable law prohibits such limitation. Some * +* jurisdictions do not allow the exclusion or limitation of * +* incidental or consequential damages, so this exclusion and * +* limitation may not apply to You. * +* * +************************************************************************ + +8. Litigation +------------- + +Any litigation relating to this License may be brought only in the +courts of a jurisdiction where the defendant maintains its principal +place of business and such litigation shall be governed by laws of that +jurisdiction, without reference to its conflict-of-law provisions. +Nothing in this Section shall prevent a party's ability to bring +cross-claims or counter-claims. + +9. Miscellaneous +---------------- + +This License represents the complete agreement concerning the subject +matter hereof. If any provision of this License is held to be +unenforceable, such provision shall be reformed only to the extent +necessary to make it enforceable. Any law or regulation which provides +that the language of a contract shall be construed against the drafter +shall not be used to construe this License against a Contributor. + +10. Versions of the License +--------------------------- + +10.1. New Versions + +Mozilla Foundation is the license steward. Except as provided in Section +10.3, no one other than the license steward has the right to modify or +publish new versions of this License. Each version will be given a +distinguishing version number. + +10.2. Effect of New Versions + +You may distribute the Covered Software under the terms of the version +of the License under which You originally received the Covered Software, +or under the terms of any subsequent version published by the license +steward. + +10.3. Modified Versions + +If you create software not governed by this License, and you want to +create a new license for such software, you may create and use a +modified version of this License if you rename the license and remove +any references to the name of the license steward (except to note that +such modified license differs from this License). + +10.4. Distributing Source Code Form that is Incompatible With Secondary +Licenses + +If You choose to distribute Source Code Form that is Incompatible With +Secondary Licenses under the terms of this version of the License, the +notice described in Exhibit B of this License must be attached. + +Exhibit A - Source Code Form License Notice +------------------------------------------- + + This Source Code Form is subject to the terms of the Mozilla Public + License, v. 2.0. If a copy of the MPL was not distributed with this + file, You can obtain one at http://mozilla.org/MPL/2.0/. + +If it is not possible or desirable to put the notice in a particular +file, then You may include the notice in a location (such as a LICENSE +file in a relevant directory) where a recipient would be likely to look +for such a notice. + +You may add additional accurate notices of copyright ownership. + +Exhibit B - "Incompatible With Secondary Licenses" Notice +--------------------------------------------------------- + + This Source Code Form is "Incompatible With Secondary Licenses", as + defined by the Mozilla Public License, v. 2.0. diff --git a/ph-ee-bulk-processor/README.md b/ph-ee-bulk-processor/README.md new file mode 100644 index 000000000..3840e736a --- /dev/null +++ b/ph-ee-bulk-processor/README.md @@ -0,0 +1,26 @@ +#Auto-Trigger + +## SSL Configuration +```yaml +server: + ssl: + key-alias: "tomcat-https" + key-store: "classpath:keystore.jks" + key-store-type: JKS + key-password: "" + key-store-password: "" + port: 8443 +``` +#### NOTE: For disabling TLS, change the port to "8080" and add null values for all the "ssl" related fields. + +## Checkstyle +Use below command to execute the checkstyle test. +```shell +./gradlew checkstyleMain +``` + +## Spotless +Use below command to execute the spotless apply. +```shell +./gradlew spotlessApply +``` diff --git a/ph-ee-bulk-processor/build.gradle b/ph-ee-bulk-processor/build.gradle new file mode 100644 index 000000000..8a867c16a --- /dev/null +++ b/ph-ee-bulk-processor/build.gradle @@ -0,0 +1,264 @@ +/* + * This file was generated by the Gradle 'init' task. + */ + +plugins { + id 'java' + id 'maven-publish' + id 'eclipse' + id 'checkstyle' + id 'org.springframework.boot' version '2.6.2' + id 'com.diffplug.spotless' version '6.19.0' +} + +repositories { + // mavenLocal() + maven { + url = uri('https://repo.maven.apache.org/maven2') + } + + maven { + url = uri('https://jfrog.sandbox.fynarfin.io/artifactory/fyn-libs-snapshot') + } +} + +apply plugin:'com.diffplug.spotless' +spotless { + format 'misc', { + target '**/*.md', '**/*.properties', '**/.gitignore', '**/.openapi-generator-ignore', '**/*.yml', '**/*.xml', '**/**.json', '**/*.sql' + targetExclude '**/build/**', '**/bin/**', '**/.settings/**', '**/.idea/**', '**/.gradle/**', '**/gradlew.bat', '**/licenses/**', '**/banner.txt', '.vscode/**' + indentWithSpaces(4) + endWithNewline() + trimTrailingWhitespace() + } + + groovyGradle { + target '*.gradle', '**/*.gradle' + targetExclude '**/build/**' + greclipse() + indentWithSpaces(4) + endWithNewline() + trimTrailingWhitespace() + } + lineEndings 'UNIX' +} + +ext { + camelVersion = '3.4.0' + springBootVersion = '2.6.2' + cucumberVersion = '7.8.1' + lambokVersion = '1.18.24' +} + +dependencies { + // spring dependency + implementation "org.springframework.boot:spring-boot-starter:$springBootVersion" + implementation "org.springframework.boot:spring-boot-starter-web:$springBootVersion" + implementation "org.springframework:spring-web:5.3.14" + implementation 'org.springframework.kafka:spring-kafka:2.8.1' + implementation "org.springframework.boot:spring-boot-starter-actuator:$springBootVersion" + + // spring test dependency + testImplementation "org.springframework.boot:spring-boot-starter-test:$springBootVersion" + + // camel dependency + implementation "org.apache.camel.springboot:camel-spring-boot-starter:$camelVersion" + implementation "org.apache.camel:camel-undertow:$camelVersion" + implementation "org.apache.camel:camel-http:$camelVersion" + implementation "org.apache.camel.springboot:camel-mail-starter:$camelVersion" + implementation "org.apache.camel:camel-jackson:$camelVersion" + + // camel test dependency + testImplementation "org.apache.camel:camel-test:$camelVersion" + testImplementation "org.apache.camel:camel-test-spring-junit5:$camelVersion" + + // cucumber test dependency + testImplementation "io.cucumber:cucumber-junit:$cucumberVersion" + testImplementation "io.cucumber:cucumber-spring:$cucumberVersion" + testImplementation "io.cucumber:cucumber-java:$cucumberVersion" + + // miscellaneous dependency + implementation 'com.google.code.gson:gson:2.8.9' + implementation 'org.json:json:20210307' + implementation 'org.mifos:ph-ee-connector-common:1.8.1-SNAPSHOT' + implementation 'org.apache.camel.springboot:camel-spring-boot-starter:3.4.0' + implementation 'org.apache.camel:camel-undertow:3.4.0' + implementation 'org.springframework.boot:spring-boot-starter:2.5.2' + implementation 'org.springframework.boot:spring-boot-starter-web:2.5.2' + implementation 'org.apache.camel:camel-http:3.4.0' + implementation 'org.springframework:spring-web:5.3.19' + implementation 'com.amazonaws:aws-java-sdk:1.11.486' + implementation 'commons-io:commons-io:2.11.0' + + implementation 'com.amazonaws:aws-java-sdk-s3:1.11.486' + //To be removed + implementation 'com.amazonaws:aws-java-sdk-dynamodb:1.11.486' + implementation 'com.azure:azure-storage-blob:12.12.0' + + implementation 'io.camunda:zeebe-client-java:8.1.23' + implementation 'com.fasterxml.jackson.dataformat:jackson-dataformat-csv:2.12.3' + implementation 'org.apache.tika:tika-core:1.4' + implementation 'org.apache.commons:commons-io:1.3.2' + implementation "org.projectlombok:lombok:$lambokVersion" + annotationProcessor "org.projectlombok:lombok:$lambokVersion" + checkstyle 'com.puppycrawl.tools:checkstyle:10.9.3' + checkstyle 'com.github.sevntu-checkstyle:sevntu-checks:1.44.1' + implementation 'com.diffplug.gradle.spotless:spotless:2.4.1' + + // miscellaneous test dependency + testImplementation "com.google.truth:truth:1.1.3" + testImplementation 'com.google.code.gson:gson:2.9.0' + implementation 'io.rest-assured:rest-assured:4.4.0' + + //retrofit + implementation 'com.squareup.retrofit2:retrofit:2.9.0' + implementation 'com.squareup.retrofit2:converter-jackson:2.9.0' + implementation('com.squareup.retrofit2:converter-gson:2.4.0') +} + +configure(this) { + // NOTE: order matters! + apply plugin: 'java' + apply plugin: 'idea' + apply plugin: 'eclipse' + apply plugin: 'checkstyle' + apply plugin: 'com.diffplug.spotless' + + configurations { + implementation.setCanBeResolved(true) + api.setCanBeResolved(true) + } + tasks.withType(JavaCompile) { + options.compilerArgs += [ + "-Xlint:unchecked", + "-Xlint:cast", + "-Xlint:auxiliaryclass", + "-Xlint:deprecation", + "-Xlint:dep-ann", + "-Xlint:divzero", + "-Xlint:empty", + "-Xlint:exports", + "-Xlint:fallthrough", + "-Xlint:finally", + "-Xlint:module", + "-Xlint:opens", + "-Xlint:options", + "-Xlint:overloads", + "-Xlint:overrides", + "-Xlint:path", + "-Xlint:processing", + "-Xlint:removal", + "-Xlint:requires-automatic", + "-Xlint:requires-transitive-automatic", + "-Xlint:try", + "-Xlint:varargs", + "-Xlint:preview", + "-Xlint:static", + // -Werror needs to be disabled because EclipseLink's static weaving doesn't generate warning-free code + // and during an IntelliJ recompilation, it fails + //"-Werror", + "-Xmaxwarns", + 1500, + "-Xmaxerrs", + 1500 + ] + options.deprecation = true + } + // Configuration for the spotless plugin + // https://github.com/diffplug/spotless/tree/main/plugin-gradle + spotless { + java { + targetExclude '**/build/**', '**/bin/**', '**/out/**' + importOrder() //sort imports alphabetically + removeUnusedImports() + eclipse().configFile "$rootDir/ph-ee-bulk-processor/config/bulk-formatter.xml" + endWithNewline() + trimTrailingWhitespace() + // Enforce style modifier order + custom 'Modifier ordering', { + def modifierRanking = [ + public : 1, + protected : 2, + private : 3, + abstract : 4, + default : 5, + static : 6, + final : 7, + transient : 8, + volatile : 9, + synchronized: 10, + native : 11, + strictfp : 12] + // Find any instance of multiple modifiers. Lead with a non-word character to avoid + // accidental matching against for instance, "an alternative default value" + it.replaceAll(/\W(?:public |protected |private |abstract |default |static |final |transient |volatile |synchronized |native |strictfp ){2,}/, { + // Do not replace the leading non-word character. Identify the modifiers + it.replaceAll(/(?:public |protected |private |abstract |default |static |final |transient |volatile |synchronized |native |strictfp ){2,}/, { + // Sort the modifiers according to the ranking above + it.split().sort({ modifierRanking[it] }).join(' ') + ' ' + } + ) + } + ) + } + } + lineEndings 'UNIX' + } + // If we are running Gradle within Eclipse to enhance classes, + // set the classes directory to point to Eclipse's default build directory + if (project.hasProperty('env') && project.getProperty('env') == 'eclipse') { + sourceSets.main.java.outputDir = file("$projectDir/bin/main") + } + // Configuration for the Checkstyle plugin + // https://docs.gradle.org/current/userguide/checkstyle_plugin.html + dependencies { + checkstyle 'com.puppycrawl.tools:checkstyle:10.3.1' + checkstyle 'com.github.sevntu-checkstyle:sevntu-checks:1.42.0' + } +} + + +group = 'org.mifos' +version = '0.0.1-SNAPSHOT' +description = 'ph-ee-processor-bulk' +sourceCompatibility = '17' + +publishing { + publications { + maven(MavenPublication) { + from(components.java) + } + } +} + +tasks.withType(JavaCompile) { + options.encoding = 'UTF-8' +} + + + +// tasks.named('test') { +// useJUnitPlatform() +// } + + +// configurations { +// cucumberRuntime { +// extendsFrom testImplementation +// } +// } + +// task cucumberCli() { +// dependsOn assemble, testClasses +// doLast { +// javaexec { +// main = "io.cucumber.core.cli.Main" +// classpath = configurations.cucumberRuntime + sourceSets.main.output + sourceSets.test.output +// args = [ +// '--plugin', 'pretty', +// '--plugin', 'html:target/cucumber-report.html', +// '--glue', 'org.mifos.processor.cucumber', +// 'src/test/java/resources'] +// } +// } +// } diff --git a/ph-ee-bulk-processor/config/bulk-cleanup.xml b/ph-ee-bulk-processor/config/bulk-cleanup.xml new file mode 100644 index 000000000..67cb2b700 --- /dev/null +++ b/ph-ee-bulk-processor/config/bulk-cleanup.xml @@ -0,0 +1,71 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ph-ee-bulk-processor/config/bulk-formatter.xml b/ph-ee-bulk-processor/config/bulk-formatter.xml new file mode 100644 index 000000000..21a66024d --- /dev/null +++ b/ph-ee-bulk-processor/config/bulk-formatter.xml @@ -0,0 +1,366 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ph-ee-bulk-processor/config/checkstyle/checkstyle.xml b/ph-ee-bulk-processor/config/checkstyle/checkstyle.xml new file mode 100644 index 000000000..5183efef5 --- /dev/null +++ b/ph-ee-bulk-processor/config/checkstyle/checkstyle.xml @@ -0,0 +1,266 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ph-ee-bulk-processor/config/checkstyle/suppressions.xml b/ph-ee-bulk-processor/config/checkstyle/suppressions.xml new file mode 100644 index 000000000..f4e5b54c3 --- /dev/null +++ b/ph-ee-bulk-processor/config/checkstyle/suppressions.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + diff --git a/ph-ee-bulk-processor/gradle/wrapper/gradle-wrapper.jar b/ph-ee-bulk-processor/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 000000000..41d9927a4 Binary files /dev/null and b/ph-ee-bulk-processor/gradle/wrapper/gradle-wrapper.jar differ diff --git a/ph-ee-bulk-processor/gradle/wrapper/gradle-wrapper.properties b/ph-ee-bulk-processor/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 000000000..e750102e0 --- /dev/null +++ b/ph-ee-bulk-processor/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-7.3-bin.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/ph-ee-bulk-processor/gradlew b/ph-ee-bulk-processor/gradlew new file mode 100755 index 000000000..1b6c78733 --- /dev/null +++ b/ph-ee-bulk-processor/gradlew @@ -0,0 +1,234 @@ +#!/bin/sh + +# +# Copyright © 2015-2021 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit + +APP_NAME="Gradle" +APP_BASE_NAME=${0##*/} + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/ph-ee-bulk-processor/gradlew.bat b/ph-ee-bulk-processor/gradlew.bat new file mode 100644 index 000000000..ac1b06f93 --- /dev/null +++ b/ph-ee-bulk-processor/gradlew.bat @@ -0,0 +1,89 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/ph-ee-bulk-processor/kubernetes/phee-bulk-processor.yml b/ph-ee-bulk-processor/kubernetes/phee-bulk-processor.yml new file mode 100644 index 000000000..d9f4683ae --- /dev/null +++ b/ph-ee-bulk-processor/kubernetes/phee-bulk-processor.yml @@ -0,0 +1,47 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: "ph-ee-bulk-processor" + labels: + app: ph-ee-bulk-processor +spec: + replicas: 1 + selector: + matchLabels: + app: ph-ee-bulk-processor + template: + metadata: + labels: + app: ph-ee-bulk-processor + spec: + containers: + - name: ph-ee-bulk-processor + image: us.icr.io/phee-ns/phee-bulk-processor + ports: + - containerPort: 5000 + volumeMounts: + - name: ph-ee-config + mountPath: "/config" + volumes: + - name: ph-ee-config + configMap: + name: ph-ee-config + +--- +apiVersion: v1 +kind: Service +metadata: + labels: + app: ph-ee-bulk-processor + name: ph-ee-bulk-processor + namespace: default +spec: + ports: + - name: port + port: 80 + protocol: TCP + targetPort: 5000 + selector: + app: ph-ee-bulk-processor + sessionAffinity: None + type: LoadBalancer diff --git a/ph-ee-bulk-processor/mvnw b/ph-ee-bulk-processor/mvnw new file mode 100755 index 000000000..a16b5431b --- /dev/null +++ b/ph-ee-bulk-processor/mvnw @@ -0,0 +1,310 @@ +#!/bin/sh +# ---------------------------------------------------------------------------- +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# ---------------------------------------------------------------------------- + +# ---------------------------------------------------------------------------- +# Maven Start Up Batch script +# +# Required ENV vars: +# ------------------ +# JAVA_HOME - location of a JDK home dir +# +# Optional ENV vars +# ----------------- +# M2_HOME - location of maven2's installed home dir +# MAVEN_OPTS - parameters passed to the Java VM when running Maven +# e.g. to debug Maven itself, use +# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +# MAVEN_SKIP_RC - flag to disable loading of mavenrc files +# ---------------------------------------------------------------------------- + +if [ -z "$MAVEN_SKIP_RC" ] ; then + + if [ -f /etc/mavenrc ] ; then + . /etc/mavenrc + fi + + if [ -f "$HOME/.mavenrc" ] ; then + . "$HOME/.mavenrc" + fi + +fi + +# OS specific support. $var _must_ be set to either true or false. +cygwin=false; +darwin=false; +mingw=false +case "`uname`" in + CYGWIN*) cygwin=true ;; + MINGW*) mingw=true;; + Darwin*) darwin=true + # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home + # See https://developer.apple.com/library/mac/qa/qa1170/_index.html + if [ -z "$JAVA_HOME" ]; then + if [ -x "/usr/libexec/java_home" ]; then + export JAVA_HOME="`/usr/libexec/java_home`" + else + export JAVA_HOME="/Library/Java/Home" + fi + fi + ;; +esac + +if [ -z "$JAVA_HOME" ] ; then + if [ -r /etc/gentoo-release ] ; then + JAVA_HOME=`java-config --jre-home` + fi +fi + +if [ -z "$M2_HOME" ] ; then + ## resolve links - $0 may be a link to maven's home + PRG="$0" + + # need this for relative symlinks + while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG="`dirname "$PRG"`/$link" + fi + done + + saveddir=`pwd` + + M2_HOME=`dirname "$PRG"`/.. + + # make it fully qualified + M2_HOME=`cd "$M2_HOME" && pwd` + + cd "$saveddir" + # echo Using m2 at $M2_HOME +fi + +# For Cygwin, ensure paths are in UNIX format before anything is touched +if $cygwin ; then + [ -n "$M2_HOME" ] && + M2_HOME=`cygpath --unix "$M2_HOME"` + [ -n "$JAVA_HOME" ] && + JAVA_HOME=`cygpath --unix "$JAVA_HOME"` + [ -n "$CLASSPATH" ] && + CLASSPATH=`cygpath --path --unix "$CLASSPATH"` +fi + +# For Mingw, ensure paths are in UNIX format before anything is touched +if $mingw ; then + [ -n "$M2_HOME" ] && + M2_HOME="`(cd "$M2_HOME"; pwd)`" + [ -n "$JAVA_HOME" ] && + JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" +fi + +if [ -z "$JAVA_HOME" ]; then + javaExecutable="`which javac`" + if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then + # readlink(1) is not available as standard on Solaris 10. + readLink=`which readlink` + if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then + if $darwin ; then + javaHome="`dirname \"$javaExecutable\"`" + javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" + else + javaExecutable="`readlink -f \"$javaExecutable\"`" + fi + javaHome="`dirname \"$javaExecutable\"`" + javaHome=`expr "$javaHome" : '\(.*\)/bin'` + JAVA_HOME="$javaHome" + export JAVA_HOME + fi + fi +fi + +if [ -z "$JAVACMD" ] ; then + if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + else + JAVACMD="`which java`" + fi +fi + +if [ ! -x "$JAVACMD" ] ; then + echo "Error: JAVA_HOME is not defined correctly." >&2 + echo " We cannot execute $JAVACMD" >&2 + exit 1 +fi + +if [ -z "$JAVA_HOME" ] ; then + echo "Warning: JAVA_HOME environment variable is not set." +fi + +CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher + +# traverses directory structure from process work directory to filesystem root +# first directory with .mvn subdirectory is considered project base directory +find_maven_basedir() { + + if [ -z "$1" ] + then + echo "Path not specified to find_maven_basedir" + return 1 + fi + + basedir="$1" + wdir="$1" + while [ "$wdir" != '/' ] ; do + if [ -d "$wdir"/.mvn ] ; then + basedir=$wdir + break + fi + # workaround for JBEAP-8937 (on Solaris 10/Sparc) + if [ -d "${wdir}" ]; then + wdir=`cd "$wdir/.."; pwd` + fi + # end of workaround + done + echo "${basedir}" +} + +# concatenates all lines of a file +concat_lines() { + if [ -f "$1" ]; then + echo "$(tr -s '\n' ' ' < "$1")" + fi +} + +BASE_DIR=`find_maven_basedir "$(pwd)"` +if [ -z "$BASE_DIR" ]; then + exit 1; +fi + +########################################################################################## +# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +# This allows using the maven wrapper in projects that prohibit checking in binary data. +########################################################################################## +if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found .mvn/wrapper/maven-wrapper.jar" + fi +else + if [ "$MVNW_VERBOSE" = true ]; then + echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..." + fi + if [ -n "$MVNW_REPOURL" ]; then + jarUrl="$MVNW_REPOURL/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" + else + jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" + fi + while IFS="=" read key value; do + case "$key" in (wrapperUrl) jarUrl="$value"; break ;; + esac + done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties" + if [ "$MVNW_VERBOSE" = true ]; then + echo "Downloading from: $jarUrl" + fi + wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" + if $cygwin; then + wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"` + fi + + if command -v wget > /dev/null; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found wget ... using wget" + fi + if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then + wget "$jarUrl" -O "$wrapperJarPath" + else + wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath" + fi + elif command -v curl > /dev/null; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found curl ... using curl" + fi + if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then + curl -o "$wrapperJarPath" "$jarUrl" -f + else + curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f + fi + + else + if [ "$MVNW_VERBOSE" = true ]; then + echo "Falling back to using Java to download" + fi + javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java" + # For Cygwin, switch paths to Windows format before running javac + if $cygwin; then + javaClass=`cygpath --path --windows "$javaClass"` + fi + if [ -e "$javaClass" ]; then + if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then + if [ "$MVNW_VERBOSE" = true ]; then + echo " - Compiling MavenWrapperDownloader.java ..." + fi + # Compiling the Java class + ("$JAVA_HOME/bin/javac" "$javaClass") + fi + if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then + # Running the downloader + if [ "$MVNW_VERBOSE" = true ]; then + echo " - Running MavenWrapperDownloader.java ..." + fi + ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR") + fi + fi + fi +fi +########################################################################################## +# End of extension +########################################################################################## + +export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"} +if [ "$MVNW_VERBOSE" = true ]; then + echo $MAVEN_PROJECTBASEDIR +fi +MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" + +# For Cygwin, switch paths to Windows format before running java +if $cygwin; then + [ -n "$M2_HOME" ] && + M2_HOME=`cygpath --path --windows "$M2_HOME"` + [ -n "$JAVA_HOME" ] && + JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` + [ -n "$CLASSPATH" ] && + CLASSPATH=`cygpath --path --windows "$CLASSPATH"` + [ -n "$MAVEN_PROJECTBASEDIR" ] && + MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"` +fi + +# Provide a "standardized" way to retrieve the CLI args that will +# work with both Windows and non-Windows executions. +MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@" +export MAVEN_CMD_LINE_ARGS + +WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +exec "$JAVACMD" \ + $MAVEN_OPTS \ + -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ + "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ + ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" diff --git a/ph-ee-bulk-processor/mvnw.cmd b/ph-ee-bulk-processor/mvnw.cmd new file mode 100644 index 000000000..c8d43372c --- /dev/null +++ b/ph-ee-bulk-processor/mvnw.cmd @@ -0,0 +1,182 @@ +@REM ---------------------------------------------------------------------------- +@REM Licensed to the Apache Software Foundation (ASF) under one +@REM or more contributor license agreements. See the NOTICE file +@REM distributed with this work for additional information +@REM regarding copyright ownership. The ASF licenses this file +@REM to you under the Apache License, Version 2.0 (the +@REM "License"); you may not use this file except in compliance +@REM with the License. You may obtain a copy of the License at +@REM +@REM https://www.apache.org/licenses/LICENSE-2.0 +@REM +@REM Unless required by applicable law or agreed to in writing, +@REM software distributed under the License is distributed on an +@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +@REM KIND, either express or implied. See the License for the +@REM specific language governing permissions and limitations +@REM under the License. +@REM ---------------------------------------------------------------------------- + +@REM ---------------------------------------------------------------------------- +@REM Maven Start Up Batch script +@REM +@REM Required ENV vars: +@REM JAVA_HOME - location of a JDK home dir +@REM +@REM Optional ENV vars +@REM M2_HOME - location of maven2's installed home dir +@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands +@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending +@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven +@REM e.g. to debug Maven itself, use +@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files +@REM ---------------------------------------------------------------------------- + +@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' +@echo off +@REM set title of command window +title %0 +@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on' +@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% + +@REM set %HOME% to equivalent of $HOME +if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") + +@REM Execute a user defined script before this one +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre +@REM check for pre script, once with legacy .bat ending and once with .cmd ending +if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" +if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd" +:skipRcPre + +@setlocal + +set ERROR_CODE=0 + +@REM To isolate internal variables from possible post scripts, we use another setlocal +@setlocal + +@REM ==== START VALIDATION ==== +if not "%JAVA_HOME%" == "" goto OkJHome + +echo. +echo Error: JAVA_HOME not found in your environment. >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +:OkJHome +if exist "%JAVA_HOME%\bin\java.exe" goto init + +echo. +echo Error: JAVA_HOME is set to an invalid directory. >&2 +echo JAVA_HOME = "%JAVA_HOME%" >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +@REM ==== END VALIDATION ==== + +:init + +@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". +@REM Fallback to current working directory if not found. + +set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% +IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir + +set EXEC_DIR=%CD% +set WDIR=%EXEC_DIR% +:findBaseDir +IF EXIST "%WDIR%"\.mvn goto baseDirFound +cd .. +IF "%WDIR%"=="%CD%" goto baseDirNotFound +set WDIR=%CD% +goto findBaseDir + +:baseDirFound +set MAVEN_PROJECTBASEDIR=%WDIR% +cd "%EXEC_DIR%" +goto endDetectBaseDir + +:baseDirNotFound +set MAVEN_PROJECTBASEDIR=%EXEC_DIR% +cd "%EXEC_DIR%" + +:endDetectBaseDir + +IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig + +@setlocal EnableExtensions EnableDelayedExpansion +for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a +@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% + +:endReadAdditionalConfig + +SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" +set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" +set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" + +FOR /F "tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( + IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B +) + +@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +@REM This allows using the maven wrapper in projects that prohibit checking in binary data. +if exist %WRAPPER_JAR% ( + if "%MVNW_VERBOSE%" == "true" ( + echo Found %WRAPPER_JAR% + ) +) else ( + if not "%MVNW_REPOURL%" == "" ( + SET DOWNLOAD_URL="%MVNW_REPOURL%/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" + ) + if "%MVNW_VERBOSE%" == "true" ( + echo Couldn't find %WRAPPER_JAR%, downloading it ... + echo Downloading from: %DOWNLOAD_URL% + ) + + powershell -Command "&{"^ + "$webclient = new-object System.Net.WebClient;"^ + "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^ + "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^ + "}"^ + "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^ + "}" + if "%MVNW_VERBOSE%" == "true" ( + echo Finished downloading %WRAPPER_JAR% + ) +) +@REM End of extension + +@REM Provide a "standardized" way to retrieve the CLI args that will +@REM work with both Windows and non-Windows executions. +set MAVEN_CMD_LINE_ARGS=%* + +%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* +if ERRORLEVEL 1 goto error +goto end + +:error +set ERROR_CODE=1 + +:end +@endlocal & set ERROR_CODE=%ERROR_CODE% + +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost +@REM check for post script, once with legacy .bat ending and once with .cmd ending +if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" +if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" +:skipRcPost + +@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' +if "%MAVEN_BATCH_PAUSE%" == "on" pause + +if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% + +exit /B %ERROR_CODE% diff --git a/ph-ee-bulk-processor/settings.gradle b/ph-ee-bulk-processor/settings.gradle new file mode 100644 index 000000000..04dd61673 --- /dev/null +++ b/ph-ee-bulk-processor/settings.gradle @@ -0,0 +1,5 @@ +/* + * This file was generated by the Gradle 'init' task. + */ + +rootProject.name = 'ph-ee-processor-bulk' diff --git a/ph-ee-bulk-processor/src/main/java/org/mifos/processor/BulkProcessorApplication.java b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/BulkProcessorApplication.java new file mode 100644 index 000000000..79f1e958f --- /dev/null +++ b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/BulkProcessorApplication.java @@ -0,0 +1,61 @@ +package org.mifos.processor; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; +import com.fasterxml.jackson.dataformat.csv.CsvMapper; +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; +import org.apache.camel.Processor; +import org.mifos.connector.common.interceptor.annotation.EnableJsonWebSignature; +import org.mifos.processor.bulk.api.ApiOriginFilter; +import org.mifos.processor.bulk.camel.config.HttpClientConfigurerTrustAllCACerts; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.web.servlet.FilterRegistrationBean; +import org.springframework.context.annotation.Bean; + +@SpringBootApplication +@EnableJsonWebSignature +public class BulkProcessorApplication { + + public static void main(String[] args) { + SpringApplication.run(BulkProcessorApplication.class, args); + } + + @Bean + public ObjectMapper objectMapper() { + ObjectMapper objectMapper = new ObjectMapper(); + objectMapper.registerModule(new JavaTimeModule()); + objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false); + return objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL) + .configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true) + .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + } + + @Bean + public Processor pojoToString(ObjectMapper objectMapper) { + return exchange -> exchange.getIn().setBody(objectMapper.writeValueAsString(exchange.getIn().getBody())); + } + + @Bean + public CsvMapper csvMapper() { + return new CsvMapper(); + } + + @Bean + public HttpClientConfigurerTrustAllCACerts httpClientConfigurer() { + return new HttpClientConfigurerTrustAllCACerts(); + } + + @Bean + public FilterRegistrationBean apiOriginFilter() { + FilterRegistrationBean registration = new FilterRegistrationBean<>(); + registration.setFilter(new ApiOriginFilter()); + registration.addUrlPatterns("/**"); + registration.setName("apiOriginFilter"); + registration.setOrder(Integer.MIN_VALUE + 1); + return registration; + } + +} diff --git a/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/ConfigurationValidator.java b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/ConfigurationValidator.java new file mode 100644 index 000000000..516d32276 --- /dev/null +++ b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/ConfigurationValidator.java @@ -0,0 +1,107 @@ +package org.mifos.processor.bulk; + +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.List; +import javax.annotation.PostConstruct; +import org.mifos.processor.bulk.format.Standard; +import org.mifos.processor.bulk.schema.Transaction; +import org.mifos.processor.bulk.zeebe.worker.WorkerConfig; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +@Component +public class ConfigurationValidator { + + public Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Value("${config.ordering.field}") + private String orderingField; + + @Value("${config.completion-threshold-check.completion-threshold}") + private int completionRate; + + @Value("${config.completion-threshold-check.max-retry}") + private int maxThresholdCheckRetry; + + @Value("${config.formatting.standard}") + private String standard; + + @Autowired + private WorkerConfig workerConfig; + + @PostConstruct + private void validate() { + if (workerConfig.isOrderingWorkerEnabled) { + validateOrderingConfig(); + } + if (workerConfig.isCompletionThresholdCheckEnabled) { + validateCompletionThresholdConfig(); + validateMaxRetryFromThresholdCheck(); + } + if (workerConfig.isFormattingWorkerEnabled) { + validateFormattingStandard(); + } + } + + private void validateMaxRetryFromThresholdCheck() { + if (maxThresholdCheckRetry <= 0) { + logger.error("Invalid maxThresholdCheckRetry count set. Needs to be +ve integer"); + throw new ConfigurationValidationException("Invalid maxThresholdCheckRetry count set. Needs to be +ve integer"); + } + } + + // validates the standard to be used for formatting + private void validateFormattingStandard() { + String std = this.standard.toUpperCase(); + try { + Standard standardEnum = Standard.valueOf(std); + logger.info("Configured formatting standard as >> {}", standardEnum.name()); + return; + } catch (Exception e) { + logger.debug(e.getMessage()); + } + List possibleStandards = new ArrayList<>(); + for (Field f : Standard.class.getFields()) { + possibleStandards.add(f.getName()); + } + throw new ConfigurationValidationException( + "Invalid standard configured for formatting data. Possible values are [" + String.join(",", possibleStandards) + "]"); + } + + // validates the ordering configuration + private void validateOrderingConfig() { + List possibleOrderingFields = new ArrayList<>(); + + for (Field field : Transaction.class.getDeclaredFields()) { + possibleOrderingFields.add(field.getName()); + } + + if (!possibleOrderingFields.contains(orderingField)) { + throw new ConfigurationValidationException( + "Invalid ordering field, possible values are [" + String.join(",", possibleOrderingFields) + "]"); + } + } + + // validates the success threshold related configuration + private void validateCompletionThresholdConfig() { + if (completionRate <= 0 || completionRate > 100) { + throw new ConfigurationValidationException("Invalid completion threshold value configured (value=" + completionRate + ")."); + } + + if (completionRate < 50) { + logger.warn("It is advised to set the completion threshold greater than 50. Currently configured as {}", completionRate); + } + } + + // this exception is thrown when unexpected application config is set, and can't pass the ConfigurationValidator + public static class ConfigurationValidationException extends RuntimeException { + + ConfigurationValidationException(String message) { + super(message); + } + } +} diff --git a/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/HealthCheck.java b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/HealthCheck.java new file mode 100644 index 000000000..36285d188 --- /dev/null +++ b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/HealthCheck.java @@ -0,0 +1,83 @@ +package org.mifos.processor.bulk; + +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.BATCH_ID; + +import com.fasterxml.jackson.databind.MappingIterator; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.dataformat.csv.CsvMapper; +import com.fasterxml.jackson.dataformat.csv.CsvSchema; +import java.io.InputStream; +import java.util.UUID; +import org.apache.camel.Exchange; +import org.apache.camel.LoggingLevel; +import org.apache.camel.builder.RouteBuilder; +import org.mifos.processor.bulk.file.FileTransferService; +import org.mifos.processor.bulk.schema.TransactionOlder; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.kafka.core.KafkaTemplate; +import org.springframework.stereotype.Component; + +@Component +public class HealthCheck extends RouteBuilder { + + private Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Autowired + private CsvMapper csvMapper; + + @Autowired + private ObjectMapper objectMapper; + + @Autowired + @Qualifier("awsStorage") + private FileTransferService fileTransferService; + + @Autowired + private KafkaTemplate kafkaTemplate; + + @Value("${application.bucket-name}") + private String bucketName; + + @Value("${zeebe.client.evenly-allocated-max-jobs}") + private int workerMaxJobs; + + @Value(value = "${kafka.topic.gsma.name}") + private String gsmaTopicName; + + @Value(value = "${kafka.topic.slcb.name}") + private String slcbTopicName; + + @Override + public void configure() { + from("rest:GET:/").setHeader(Exchange.HTTP_RESPONSE_CODE, constant(200)).setBody(constant("")); + + from("rest:GET:/channel/bulk/transfer/{fileName}").id("transfer-details") + .log(LoggingLevel.INFO, "## CHANNEL -> inbound bulk transfer request with ${header.fileName}").process(exchange -> { + String fileName = exchange.getIn().getHeader("fileName", String.class); + String batchId = UUID.randomUUID().toString(); + exchange.setProperty(BATCH_ID, batchId); + + // TODO: How to get sender information? Hard coded in Channel connector? + InputStream csvFileInputStream = fileTransferService.streamFile(fileName, bucketName); + + CsvSchema schema = CsvSchema.emptySchema().withHeader(); + MappingIterator readValues = csvMapper.readerWithSchemaFor(TransactionOlder.class).with(schema) + .readValues(csvFileInputStream); + + while (readValues.hasNext()) { + TransactionOlder current = readValues.next(); + current.setBatchId(batchId); + logger.info("Writing string in kafka {}", objectMapper.writeValueAsString(current)); + if (current.getPaymentMode().equals("gsma") || current.getPaymentMode().equals("afrimoney")) { + kafkaTemplate.send(gsmaTopicName, objectMapper.writeValueAsString(current)); + } else if (current.getPaymentMode().equals("sclb")) { + kafkaTemplate.send(slcbTopicName, objectMapper.writeValueAsString(current)); + } + } + }).setHeader(Exchange.HTTP_RESPONSE_CODE, constant(200)).setBody(exchange -> exchange.getProperty(BATCH_ID)); + } +} diff --git a/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/OperationsAppConfig.java b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/OperationsAppConfig.java new file mode 100644 index 000000000..4c7548023 --- /dev/null +++ b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/OperationsAppConfig.java @@ -0,0 +1,46 @@ +package org.mifos.processor.bulk; + +import javax.annotation.PostConstruct; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +@Component +public class OperationsAppConfig { + + @Value("${operations-app.contactpoint}") + public String operationAppContactPoint; + + @Value("${operations-app.endpoints.batch-transaction}") + public String batchTransactionEndpoint; + + @Value("${operations-app.endpoints.batch-summary}") + public String batchSummaryEndpoint; + + @Value("${operations-app.endpoints.batch-aggregate}") + public String batchAggregateEndpoint; + + @Value("${operations-app.endpoints.auth}") + public String authEndpoint; + + @Value("${operations-app.username}") + public String username; + + @Value("${operations-app.password}") + public String password; + + public String batchTransactionUrl; + + public String batchSummaryUrl; + + public String batchAggregateUrl; + + public String authUrl; + + @PostConstruct + private void setup() { + batchTransactionUrl = operationAppContactPoint + batchTransactionEndpoint; + batchSummaryUrl = operationAppContactPoint + batchSummaryEndpoint; + authUrl = operationAppContactPoint + authEndpoint; + batchAggregateUrl = operationAppContactPoint + batchAggregateEndpoint; + } +} diff --git a/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/api/ApiOriginFilter.java b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/api/ApiOriginFilter.java new file mode 100644 index 000000000..4137a6cf7 --- /dev/null +++ b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/api/ApiOriginFilter.java @@ -0,0 +1,27 @@ +package org.mifos.processor.bulk.api; + +import static org.mifos.processor.bulk.camel.config.CamelProperties.HEADER_PLATFORM_TENANT_ID; + +import java.io.IOException; +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.web.filter.GenericFilterBean; + +public class ApiOriginFilter extends GenericFilterBean { + + private Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Override + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { + HttpServletRequest req = (HttpServletRequest) request; + String tenant = req.getHeader("" + HEADER_PLATFORM_TENANT_ID); + logger.debug("Tenant Name is : {}", tenant); + logger.info("Client IP Address: {}", req.getRemoteHost()); + } + +} diff --git a/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/api/CallbackController.java b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/api/CallbackController.java new file mode 100644 index 000000000..8dab4d5bc --- /dev/null +++ b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/api/CallbackController.java @@ -0,0 +1,67 @@ +package org.mifos.processor.bulk.api; + +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.APPROVED_AMOUNT; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.AUTHORIZATION_FAIL_REASON; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.AUTHORIZATION_RESPONSE; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.AUTHORIZATION_STATUS; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.AUTHORIZATION_SUCCESSFUL; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.CLIENT_CORRELATION_ID; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import io.camunda.zeebe.client.ZeebeClient; +import java.time.Duration; +import java.util.HashMap; +import java.util.Map; +import org.mifos.processor.bulk.schema.AuthorizationResponse; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; + +@RestController +public class CallbackController { + + @Autowired + private ZeebeClient zeebeClient; + + @Autowired + ObjectMapper objectMapper; + + protected Logger logger = LoggerFactory.getLogger(this.getClass()); + + private static final String EXPECTED_AUTH_STATUS = "Y"; + + @PostMapping("/authorization/callback") + public ResponseEntity handleAuthorizationCallback(@RequestBody AuthorizationResponse authResponse) + throws JsonProcessingException { + logger.info("Callback received"); + logger.debug("Auth response: {}", objectMapper.writeValueAsString(authResponse)); + Map variables = new HashMap<>(); + + boolean isAuthorizationSuccessful = EXPECTED_AUTH_STATUS.equals(authResponse.getStatus()); + variables.put(AUTHORIZATION_SUCCESSFUL, isAuthorizationSuccessful); + variables.put(CLIENT_CORRELATION_ID, authResponse.getClientCorrelationId()); + variables.put(AUTHORIZATION_STATUS, authResponse.getStatus()); + variables.put(AUTHORIZATION_FAIL_REASON, authResponse.getReason()); + + if (!isAuthorizationSuccessful) { + variables.put(APPROVED_AMOUNT, 0); + } + + logger.info("Is auth successful: {}", isAuthorizationSuccessful); + + if (zeebeClient != null) { + zeebeClient.newPublishMessageCommand().messageName(AUTHORIZATION_RESPONSE).correlationKey(authResponse.getClientCorrelationId()) + .timeToLive(Duration.ofMillis(500000)).variables(variables).send(); + logger.debug("Published zeebe message event {}", AUTHORIZATION_RESPONSE); + zeebeClient.newPublishMessageCommand().messageName(AUTHORIZATION_RESPONSE).correlationKey(authResponse.getClientCorrelationId()) + .timeToLive(Duration.ofMillis(500000)).variables(variables).send(); + } + return ResponseEntity.ok().build(); + } + +} diff --git a/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/api/definition/BatchTransactions.java b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/api/definition/BatchTransactions.java new file mode 100644 index 000000000..720bced00 --- /dev/null +++ b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/api/definition/BatchTransactions.java @@ -0,0 +1,29 @@ +package org.mifos.processor.bulk.api.definition; + +import static org.mifos.processor.bulk.camel.config.CamelProperties.CALLBACK; +import static org.mifos.processor.bulk.camel.config.CamelProperties.HEADER_CLIENT_CORRELATION_ID; +import static org.mifos.processor.bulk.camel.config.CamelProperties.HEADER_PLATFORM_TENANT_ID; +import static org.mifos.processor.bulk.camel.config.CamelProperties.HEADER_PROGRAM_ID; +import static org.mifos.processor.bulk.camel.config.CamelProperties.HEADER_REGISTERING_INSTITUTE_ID; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.FILE_NAME; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.HEADER_TYPE; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.PURPOSE; + +import java.io.IOException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestHeader; + +public interface BatchTransactions { + + @PostMapping(value = "/batchtransactions", produces = "application/json") + String batchTransactions(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, + @RequestHeader(value = HEADER_CLIENT_CORRELATION_ID) String requestId, + @RequestHeader(value = FILE_NAME, required = false) String fileName, @RequestHeader(value = PURPOSE) String purpose, + @RequestHeader(value = HEADER_TYPE) String type, @RequestHeader(value = HEADER_PLATFORM_TENANT_ID) String tenant, + @RequestHeader(value = HEADER_REGISTERING_INSTITUTE_ID, required = false) String registeringInstitutionId, + @RequestHeader(value = HEADER_PROGRAM_ID, required = false) String programId, + @RequestHeader(value = CALLBACK, required = false) String callbackUrl) throws IOException; + +} diff --git a/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/api/definition/BulkTransfer.java b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/api/definition/BulkTransfer.java new file mode 100644 index 000000000..d081c28d9 --- /dev/null +++ b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/api/definition/BulkTransfer.java @@ -0,0 +1,21 @@ +package org.mifos.processor.bulk.api.definition; + +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.FILE_NAME; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.PURPOSE; + +import java.io.IOException; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestHeader; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.multipart.MultipartFile; + +public interface BulkTransfer { + + @Deprecated + + @PostMapping(value = "/bulk/transfer/{requestId}/{fileName}", produces = "application/json") + String bulkTransfer(@RequestHeader(value = "X-CorrelationID", required = false) String requestId, + @RequestParam("data") MultipartFile file, @RequestHeader(value = FILE_NAME, required = false) String fileName, + @RequestHeader(value = PURPOSE, required = false) String purpose, @RequestHeader(value = "Type", required = false) String type, + @RequestHeader(value = "Platform-TenantId") String tenant) throws IOException; +} diff --git a/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/api/definition/Simulate.java b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/api/definition/Simulate.java new file mode 100644 index 000000000..91406d60c --- /dev/null +++ b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/api/definition/Simulate.java @@ -0,0 +1,13 @@ +package org.mifos.processor.bulk.api.definition; + +import java.io.IOException; +import javax.servlet.http.HttpServletResponse; +import org.springframework.web.bind.annotation.PostMapping; + +// from("rest:post:/simulate").log("Reached Simulation"); +public interface Simulate { + + @PostMapping(value = "/simulate", produces = "application/json") + void simulate(HttpServletResponse httpServletResponse) throws IOException; + +} diff --git a/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/api/implementation/BatchTransactionsController.java b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/api/implementation/BatchTransactionsController.java new file mode 100644 index 000000000..90df1c726 --- /dev/null +++ b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/api/implementation/BatchTransactionsController.java @@ -0,0 +1,164 @@ +package org.mifos.processor.bulk.api.implementation; + +import static org.mifos.processor.bulk.camel.config.CamelProperties.CALLBACK; +import static org.mifos.processor.bulk.camel.config.CamelProperties.HEADER_PROGRAM_ID; +import static org.mifos.processor.bulk.camel.config.CamelProperties.HEADER_REGISTERING_INSTITUTE_ID; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.FILE_NAME; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.HEADER_CLIENT_CORRELATION_ID; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.HEADER_PLATFORM_TENANT_ID; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.HEADER_TYPE; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.PURPOSE; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.dataformat.csv.CsvMapper; +import io.camunda.zeebe.client.api.command.ClientStatusException; +import io.grpc.Status; +import java.nio.charset.Charset; +import java.util.List; +import java.util.Optional; +import java.util.UUID; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; +import org.apache.camel.Exchange; +import org.apache.camel.ProducerTemplate; +import org.apache.commons.io.IOUtils; +import org.json.JSONObject; +import org.mifos.connector.common.interceptor.JWSUtil; +import org.mifos.processor.bulk.api.definition.BatchTransactions; +import org.mifos.processor.bulk.file.FileStorageService; +import org.mifos.processor.bulk.format.RestRequestConvertor; +import org.mifos.processor.bulk.schema.BatchRequestDTO; +import org.mifos.processor.bulk.schema.CamelApiResponse; +import org.mifos.processor.bulk.schema.Transaction; +import org.mifos.processor.bulk.utility.CsvWriter; +import org.mifos.processor.bulk.utility.Headers; +import org.mifos.processor.bulk.utility.SpringWrapperUtil; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.multipart.MultipartException; + +@Slf4j +@RestController +public class BatchTransactionsController implements BatchTransactions { + + @Autowired + private ProducerTemplate producerTemplate; + + @Autowired + ObjectMapper objectMapper; + + @Autowired + FileStorageService fileStorageService; + + @Autowired + RestRequestConvertor restRequestConvertor; + + @Value("#{'${tenants}'.split(',')}") + protected List tenants; + @Autowired + private CsvMapper csvMapper; + + @SneakyThrows + @Override + public String batchTransactions(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, String requestId, + String fileName, String purpose, String type, String tenant, String registeringInstitutionId, String programId, + String callbackUrl) { + + log.info("Inside api logic"); + Headers.HeaderBuilder headerBuilder = new Headers.HeaderBuilder().addHeader(HEADER_CLIENT_CORRELATION_ID, requestId) + .addHeader(PURPOSE, purpose).addHeader(HEADER_TYPE, type).addHeader(HEADER_PLATFORM_TENANT_ID, tenant) + .addHeader(HEADER_REGISTERING_INSTITUTE_ID, registeringInstitutionId).addHeader(HEADER_PROGRAM_ID, programId) + .addHeader(CALLBACK, callbackUrl); + + Optional validationResponse = isValidRequest(httpServletRequest, fileName, type); + if (validationResponse.isPresent()) { + httpServletResponse.setStatus(httpServletResponse.SC_BAD_REQUEST); + return validationResponse.get(); + } + + if (JWSUtil.isMultipartRequest(httpServletRequest)) { + log.info("This is file based request"); + String localFileName = fileStorageService.save(JWSUtil.parseFormData(httpServletRequest), fileName); + Headers headers = headerBuilder.addHeader(FILE_NAME, localFileName).build(); + log.info("Headers passed: {}", headers.getHeaders()); + + CamelApiResponse response = sendRequestToCamel(headers); + httpServletResponse.setStatus(response.getStatus()); + return response.getBody(); + } else { + log.info("This is json based request"); + String jsonString = IOUtils.toString(httpServletRequest.getInputStream(), Charset.defaultCharset()); + List batchRequestDTOList = objectMapper.readValue(jsonString, new TypeReference<>() {}); + List transactionList = restRequestConvertor.convertListFrom(batchRequestDTOList); + + String localFileName = UUID.randomUUID() + ".csv"; + CsvWriter.writeToCsv(transactionList, Transaction.class, csvMapper, true, localFileName); + Headers headers = headerBuilder.addHeader(HEADER_TYPE, "csv").addHeader(FILE_NAME, localFileName).build(); + + CamelApiResponse response = sendRequestToCamel(headers); + httpServletResponse.setStatus(response.getStatus()); + return response.getBody(); + } + + } + + @ExceptionHandler({ MultipartException.class }) + public String handleMultipartException(HttpServletResponse httpServletResponse) { + httpServletResponse.setStatus(httpServletResponse.SC_BAD_REQUEST); + return getErrorResponse("File not uploaded", "There was no fie uploaded with the request. " + "Please upload a file and try again.", + 400); + } + + private CamelApiResponse sendRequestToCamel(Headers headers) { + Exchange exchange = SpringWrapperUtil.getDefaultWrappedExchange(producerTemplate.getCamelContext(), headers); + exchange = producerTemplate.send("direct:post-batch-transactions", exchange); + checkAndThrowClientStatusException(exchange); + int statusCode = exchange.getIn().getHeader(Exchange.HTTP_RESPONSE_CODE, Integer.class); + String body = exchange.getIn().getBody(String.class); + return new CamelApiResponse(body, statusCode); + } + + private String getErrorResponse(String information, String description, int code) { + JSONObject json = new JSONObject(); + json.put("errorInformation", "File not uploaded"); + json.put("errorDescription", "There was no fie uploaded with the request. " + "Please upload a file and try again."); + json.put("errorCode", code); + return json.toString(); + } + + // validates the request header, and return errorJson string if the request is invalid else an empty optional + private Optional isValidRequest(HttpServletRequest httpServletRequest, String fileName, String type) { + + Optional response = Optional.empty(); + if ((JWSUtil.isMultipartRequest(httpServletRequest) && !type.equalsIgnoreCase("csv")) + || (!JWSUtil.isMultipartRequest(httpServletRequest) && !type.equalsIgnoreCase("raw"))) { + String errorJson = getErrorResponse("Type mismatch", + "The value of the header \"" + HEADER_TYPE + "\" doesn't match with the request content-type", 400); + response = Optional.of(errorJson); + + } + if (JWSUtil.isMultipartRequest(httpServletRequest) && fileName.isEmpty()) { + String errorJson = getErrorResponse("Header can't be empty", + "If the request is of type csv, the header \"" + FILE_NAME + "\"can't be empty", 400); + response = Optional.of(errorJson); + } + if (!type.equalsIgnoreCase("raw") && !type.equalsIgnoreCase("csv")) { + String errorJson = getErrorResponse("Invalid TYPE header value passed", + "The value of the header \"" + HEADER_TYPE + "\" can be \"[raw,csv]\" but is " + type, 400); + response = Optional.of(errorJson); + } + return response; + } + + private void checkAndThrowClientStatusException(Exchange exchange) { + Exception cause = exchange.getProperty(Exchange.EXCEPTION_CAUGHT, Exception.class); + if (cause instanceof ClientStatusException) { + throw new ClientStatusException(Status.FAILED_PRECONDITION, cause); + } + } +} diff --git a/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/api/implementation/BulkTransferController.java b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/api/implementation/BulkTransferController.java new file mode 100644 index 000000000..f0ef69fe4 --- /dev/null +++ b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/api/implementation/BulkTransferController.java @@ -0,0 +1,43 @@ +package org.mifos.processor.bulk.api.implementation; + +import static org.mifos.processor.bulk.camel.config.CamelProperties.HEADER_PLATFORM_TENANT_ID; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.FILE_NAME; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.HEADER_CLIENT_CORRELATION_ID; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.HEADER_TYPE; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.PURPOSE; + +import com.fasterxml.jackson.databind.ObjectMapper; +import java.io.IOException; +import org.apache.camel.Exchange; +import org.apache.camel.ProducerTemplate; +import org.mifos.processor.bulk.api.definition.BulkTransfer; +import org.mifos.processor.bulk.file.FileStorageService; +import org.mifos.processor.bulk.utility.Headers; +import org.mifos.processor.bulk.utility.SpringWrapperUtil; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.multipart.MultipartFile; + +@RestController +public class BulkTransferController implements BulkTransfer { + + @Autowired + private ProducerTemplate producerTemplate; + + @Autowired + ObjectMapper objectMapper; + + @Autowired + FileStorageService fileStorageService; + + @Override + public String bulkTransfer(String requestId, MultipartFile file, String fileName, String purpose, String type, String tenant) + throws IOException { + Headers headers = new Headers.HeaderBuilder().addHeader(HEADER_CLIENT_CORRELATION_ID, requestId).addHeader(PURPOSE, purpose) + .addHeader(FILE_NAME, fileName).addHeader(HEADER_TYPE, type).addHeader(HEADER_PLATFORM_TENANT_ID, tenant).build(); + Exchange exchange = SpringWrapperUtil.getDefaultWrappedExchange(producerTemplate.getCamelContext(), headers); + fileStorageService.save(file); + producerTemplate.send("direct:post-bulk-transfer", exchange); + return exchange.getIn().getBody(String.class); + } +} diff --git a/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/api/implementation/SimulateApiController.java b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/api/implementation/SimulateApiController.java new file mode 100644 index 000000000..e535c914a --- /dev/null +++ b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/api/implementation/SimulateApiController.java @@ -0,0 +1,14 @@ +package org.mifos.processor.bulk.api.implementation; + +import javax.servlet.http.HttpServletResponse; +import org.mifos.processor.bulk.api.definition.Simulate; +import org.springframework.web.bind.annotation.RestController; + +@RestController +public class SimulateApiController implements Simulate { + + @Override + public void simulate(HttpServletResponse httpServletResponse) { + httpServletResponse.setStatus(HttpServletResponse.SC_OK); + } +} diff --git a/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/camel/config/CamelContextConfig.java b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/camel/config/CamelContextConfig.java new file mode 100644 index 000000000..6366dd11e --- /dev/null +++ b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/camel/config/CamelContextConfig.java @@ -0,0 +1,58 @@ +package org.mifos.processor.bulk.camel.config; + +import java.util.HashMap; +import org.apache.camel.CamelContext; +import org.apache.camel.component.http.HttpComponent; +import org.apache.camel.spi.RestConfiguration; +import org.apache.camel.spring.boot.CamelContextConfiguration; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class CamelContextConfig { + + @Value("${camel.server-port}") + private int serverPort; + + @Value("${camel.disable-ssl}") + private boolean disableSSL; + + @Autowired + private HttpClientConfigurerTrustAllCACerts httpClientConfigurerTrustAllCACerts; + + @Bean + CamelContextConfiguration contextConfiguration() { + return new CamelContextConfiguration() { + + @Override + public void beforeApplicationStart(CamelContext camelContext) { + camelContext.setTracing(false); + camelContext.setMessageHistory(false); + camelContext.setStreamCaching(true); + camelContext.disableJMX(); + + if (disableSSL) { + HttpComponent httpComponent = camelContext.getComponent("https", HttpComponent.class); + httpComponent.setHttpClientConfigurer(httpClientConfigurerTrustAllCACerts); + } + + RestConfiguration rest = new RestConfiguration(); + camelContext.setRestConfiguration(rest); + rest.setComponent("undertow"); + rest.setProducerComponent("undertow"); + rest.setPort(serverPort); + rest.setBindingMode(RestConfiguration.RestBindingMode.json); + rest.setDataFormatProperties(new HashMap<>()); + rest.getDataFormatProperties().put("prettyPrint", "true"); + rest.setScheme("http"); + } + + @Override + public void afterApplicationStart(CamelContext camelContext) { + // empty + } + }; + } +} diff --git a/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/camel/config/CamelProperties.java b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/camel/config/CamelProperties.java new file mode 100644 index 000000000..4881559d7 --- /dev/null +++ b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/camel/config/CamelProperties.java @@ -0,0 +1,88 @@ +package org.mifos.processor.bulk.camel.config; + +public final class CamelProperties { + + private CamelProperties() {} + + public static final String AUTH_TYPE = "authType"; + public static final String IS_BATCH_READY = "isBatchReady"; // camel property to check if batch is ready for + // sampling + + public static final String SERVER_FILE_NAME = "serverFileName"; + + public static final String LOCAL_FILE_PATH = "localFilePath"; + + public static final String LOCAL_FILE_PATH_LIST = "localFilePaths"; + + public static final String SUB_BATCH_FILE_ARRAY = "subBatchFileArray"; + + public static final String SUB_BATCH_COUNT = "subBatchCount"; + + public static final String SUB_BATCH_CREATED = "subBatchCreated"; + public static final String SUB_BATCH_DETAILS = "subBatchDetails"; + + public static final String SERVER_SUB_BATCH_FILE_NAME_ARRAY = "serverSubBatchFileName"; + + public static final String TRANSACTION_LIST = "transactionList"; + + public static final String TRANSACTION_LIST_LENGTH = "transactionListLength"; + + public static final String TRANSACTION_LIST_ELEMENT = "transactionListElement"; + + public static final String GSMA_CHANNEL_REQUEST = "gsmaChannelRequest"; + + public static final String OVERRIDE_HEADER = "overrideHeader"; + + public static final String TENANT_NAME = "tenantName"; + + public static final String FILE_1 = "file1"; + + public static final String FILE_2 = "file2"; + + public static final String OPS_APP_ACCESS_TOKEN = "opsAppAccessToken"; + + public static final String BATCH_STATUS_FAILED = "batchStatusFailed"; + + public static final String CALLBACK_RESPONSE_CODE = "responseCode"; + + public static final String BATCH_REQUEST_TYPE = "batchRequestType"; + + public static final String RESULT_TRANSACTION_LIST = "resultTransactionList"; + + public static final String ZEEBE_VARIABLE = "zeebeVariable"; + + public static final String EXTERNAL_ENDPOINT_FAILED = "extEndpointFailed"; + + public static final String EXTERNAL_ENDPOINT = "extEndpoint"; + + public static final String PAYLOAD_LIST = "payloadList"; + + public static final String IS_PAYMENT_MODE_VALID = "isPaymentModeValid"; + + public static final String PAYMENT_MODE_TYPE = "paymentModeType"; + + public static final String PAYLOAD = "payload"; + + public static final String BATCH_ID_HEADER = "X-BatchID"; + public static final String HOST = "externalApiCallHost"; + public static final String ENDPOINT = "externalApiCallEndpoint"; + public static final String CACHED_TRANSACTION_ID = "cachedTransactionId"; + public static final String PAYEE_IDENTITY = "payeeIdentity"; + public static final String PAYMENT_MODALITY = "paymentModality"; + public static final String PAYEE_PARTY_ID = "payeePartyId"; + public static final String PAYEE_PARTY_ID_TYPE = "payeePartyIdType"; + public static final String HEADER_REGISTERING_INSTITUTE_ID = "X-Registering-Institution-ID"; + public static final String HEADER_PROGRAM_ID = "X-Program-ID"; + public static final String REGISTERING_INSTITUTE_ID = "registeringInstituteId"; + public static final String PROGRAM_ID = "programId"; + public static final String IS_UPDATED = "isUpdated"; + public static final String HEADER_PLATFORM_TENANT_ID = "Platform-TenantId"; + public static final String HEADER_CLIENT_CORRELATION_ID = "X-CorrelationID"; + public static final String CLIENT_CORRELATION_ID = "clientCorrelationId"; + public static final String SUB_BATCH_ENTITY = "subBatchEntity"; + public static final String EVENT_TYPE = "eventType"; + public static final String DUPLICATE_TRANSACTION_LIST = "duplicateTransactionList"; + public static final String ORIGINAL_TRANSACTION_LIST = "originalTransactionList"; + public static final String CALLBACK = "X-CallbackURL"; + public static final String CONTENT_TYPE = "Content-Type"; +} diff --git a/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/camel/config/HttpClientConfigurerTrustAllCACerts.java b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/camel/config/HttpClientConfigurerTrustAllCACerts.java new file mode 100644 index 000000000..7a0a6b895 --- /dev/null +++ b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/camel/config/HttpClientConfigurerTrustAllCACerts.java @@ -0,0 +1,64 @@ +package org.mifos.processor.bulk.camel.config; + +import java.security.KeyManagementException; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; +import javax.net.ssl.HostnameVerifier; +import javax.net.ssl.SSLContext; +import org.apache.camel.component.http.HttpClientConfigurer; +import org.apache.http.config.Registry; +import org.apache.http.config.RegistryBuilder; +import org.apache.http.conn.socket.ConnectionSocketFactory; +import org.apache.http.conn.socket.PlainConnectionSocketFactory; +import org.apache.http.conn.ssl.SSLConnectionSocketFactory; +import org.apache.http.conn.ssl.TrustStrategy; +import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; +import org.apache.http.ssl.SSLContextBuilder; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class HttpClientConfigurerTrustAllCACerts implements HttpClientConfigurer { + + public Logger logger = LoggerFactory.getLogger(this.getClass()); + + public HttpClientConfigurerTrustAllCACerts() {} + + @Override + public void configureHttpClient(HttpClientBuilder clientBuilder) { + // setup a Trust Strategy that allows all certificates. + // + SSLContext sslContext = null; + try { + sslContext = new SSLContextBuilder().loadTrustMaterial(null, new TrustStrategy() { + + public boolean isTrusted(X509Certificate[] arg0, String arg1) throws CertificateException { + return true; + } + }).build(); + } catch (KeyManagementException | NoSuchAlgorithmException | KeyStoreException e) { + logger.debug(e.getMessage()); + } + clientBuilder.setSslcontext(sslContext); + + // don't check Hostnames, either. + // -- use SSLConnectionSocketFactory.getDefaultHostnameVerifier(), if you don't want to weaken + HostnameVerifier hostnameVerifier = SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER; + + // here's the special part: + // -- need to create an SSL Socket Factory, to use our weakened "trust strategy"; + // -- and create a Registry, to register it. + // + SSLConnectionSocketFactory sslSocketFactory = new SSLConnectionSocketFactory(sslContext, hostnameVerifier); + Registry socketFactoryRegistry = RegistryBuilder.create() + .register("http", PlainConnectionSocketFactory.getSocketFactory()).register("https", sslSocketFactory).build(); + + // now, we create connection-manager using our Registry. + // -- allows multi-threaded use + PoolingHttpClientConnectionManager connMgr = new PoolingHttpClientConnectionManager(socketFactoryRegistry); + clientBuilder.setConnectionManager(connMgr); + } + +} diff --git a/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/camel/processor/DTOJsonConversionException.java b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/camel/processor/DTOJsonConversionException.java new file mode 100644 index 000000000..d07f4aa12 --- /dev/null +++ b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/camel/processor/DTOJsonConversionException.java @@ -0,0 +1,8 @@ +package org.mifos.processor.bulk.camel.processor; + +public class DTOJsonConversionException extends RuntimeException { + + public DTOJsonConversionException(Class dtoClass, String message, Throwable cause) { + super(message, cause); + } +} diff --git a/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/camel/processor/GsmaApiPayload.java b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/camel/processor/GsmaApiPayload.java new file mode 100644 index 000000000..b35cfa8ba --- /dev/null +++ b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/camel/processor/GsmaApiPayload.java @@ -0,0 +1,34 @@ +package org.mifos.processor.bulk.camel.processor; + +import static org.mifos.processor.bulk.camel.config.CamelProperties.TRANSACTION_LIST_ELEMENT; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import java.util.function.Function; +import lombok.extern.slf4j.Slf4j; +import org.apache.camel.Exchange; +import org.mifos.connector.common.gsma.dto.GSMATransaction; +import org.mifos.processor.bulk.schema.Transaction; +import org.mifos.processor.bulk.utility.Utils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component +@Slf4j +public class GsmaApiPayload implements Function { + + @Autowired + ObjectMapper objectMapper; + + @Override + public String apply(Exchange exchange) { + + Transaction transaction = exchange.getProperty(TRANSACTION_LIST_ELEMENT, Transaction.class); + GSMATransaction gsmaTransaction = Utils.convertTxnToGSMA(transaction); + try { + return objectMapper.writeValueAsString(gsmaTransaction); + } catch (JsonProcessingException e) { + throw new DTOJsonConversionException(GSMATransaction.class, "Unable to convert GSMATransaction to Json", e); + } + } +} diff --git a/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/camel/processor/MojaloopApiPayload.java b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/camel/processor/MojaloopApiPayload.java new file mode 100644 index 000000000..c3802c831 --- /dev/null +++ b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/camel/processor/MojaloopApiPayload.java @@ -0,0 +1,31 @@ +package org.mifos.processor.bulk.camel.processor; + +import static org.mifos.processor.bulk.camel.config.CamelProperties.TRANSACTION_LIST_ELEMENT; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import java.util.function.Function; +import org.apache.camel.Exchange; +import org.mifos.connector.common.channel.dto.TransactionChannelRequestDTO; +import org.mifos.processor.bulk.schema.Transaction; +import org.mifos.processor.bulk.utility.Utils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component +public class MojaloopApiPayload implements Function { + + @Autowired + ObjectMapper objectMapper; + + @Override + public String apply(Exchange exchange) { + Transaction transaction = exchange.getProperty(TRANSACTION_LIST_ELEMENT, Transaction.class); + TransactionChannelRequestDTO inboundTransferPayload = Utils.convertTxnToInboundTransferPayload(transaction); + try { + return objectMapper.writeValueAsString(inboundTransferPayload); + } catch (JsonProcessingException e) { + throw new DTOJsonConversionException(MojaloopApiPayload.class, "Unable to convert MojaloopPayload to JSON", e); + } + } +} diff --git a/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/camel/routes/AccountLookupCallbackRoute.java b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/camel/routes/AccountLookupCallbackRoute.java new file mode 100644 index 000000000..216d051c8 --- /dev/null +++ b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/camel/routes/AccountLookupCallbackRoute.java @@ -0,0 +1,111 @@ +package org.mifos.processor.bulk.camel.routes; + +import static org.mifos.processor.bulk.camel.config.CamelProperties.LOCAL_FILE_PATH; +import static org.mifos.processor.bulk.camel.config.CamelProperties.OVERRIDE_HEADER; +import static org.mifos.processor.bulk.camel.config.CamelProperties.RESULT_TRANSACTION_LIST; +import static org.mifos.processor.bulk.camel.config.CamelProperties.SERVER_FILE_NAME; +import static org.mifos.processor.bulk.camel.config.CamelProperties.TRANSACTION_LIST; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.PARTY_LOOKUP_SUCCESSFUL_TRANSACTION_AMOUNT; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.PARTY_LOOKUP_SUCCESSFUL_TRANSACTION_COUNT; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.RESULT_FILE; + +import io.camunda.zeebe.client.ZeebeClient; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.concurrent.atomic.AtomicInteger; +import org.mifos.processor.bulk.schema.BatchAccountLookupResponseDTO; +import org.mifos.processor.bulk.schema.BeneficiaryDTO; +import org.mifos.processor.bulk.schema.Transaction; +import org.mifos.processor.bulk.schema.TransactionResult; +import org.mifos.processor.bulk.utility.Utils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component +public class AccountLookupCallbackRoute extends BaseRouteBuilder { + + @Autowired + private ZeebeClient zeebeClient; + private Integer totalApprovedAmount; + private Integer totalApprovedCount; + + @Override + public void configure() throws Exception { + from("direct:accountLookupCallback").id("direct:accountLookupCallback") + .log("Starting route " + RouteId.ACCOUNT_LOOKUP_CALLBACK.name()).to("direct:download-file") + .to("direct:get-transaction-array").to("direct:batch-account-lookup-callback") + .process(exchange -> exchange.setProperty(OVERRIDE_HEADER, true)); + from("direct:batch-account-lookup-callback").id("direct:batch-account-lookup-callback").process(exchange -> { + String serverFileName = exchange.getProperty(SERVER_FILE_NAME, String.class); + String resultFile = String.format("Result_%s", serverFileName); + BatchAccountLookupResponseDTO batchAccountLookupCallback = objectMapper + .readValue(exchange.getProperty("batchAccountLookupCallback", String.class), BatchAccountLookupResponseDTO.class); + List transactionList = exchange.getProperty(TRANSACTION_LIST, List.class); + List transactionResultList = new ArrayList<>(); + List updatedTransactionList = new ArrayList<>(); + Map variables = new HashMap<>(); + + updateTransactionStatus(transactionList, batchAccountLookupCallback.getBeneficiaryDTOList(), transactionResultList, + updatedTransactionList); + exchange.setProperty(PARTY_LOOKUP_SUCCESSFUL_TRANSACTION_AMOUNT, totalApprovedAmount); + exchange.setProperty(PARTY_LOOKUP_SUCCESSFUL_TRANSACTION_COUNT, totalApprovedCount); + exchange.setProperty(RESULT_TRANSACTION_LIST, transactionResultList); + exchange.setProperty(RESULT_FILE, resultFile); + exchange.setProperty(TRANSACTION_LIST, updatedTransactionList); + Long workflowInstanceKey = Long.valueOf(exchange.getProperty("workflowInstanceKey").toString()); + variables.put(PARTY_LOOKUP_SUCCESSFUL_TRANSACTION_AMOUNT, totalApprovedAmount); + variables.put(PARTY_LOOKUP_SUCCESSFUL_TRANSACTION_COUNT, totalApprovedCount); + if (zeebeClient != null) { + + zeebeClient.newSetVariablesCommand(workflowInstanceKey).variables(variables).send().join(); + } + }) + // setting localfilepath as result file to make sure result file is uploaded + .log("updating orignal").setProperty(LOCAL_FILE_PATH, exchangeProperty(SERVER_FILE_NAME)) + .setProperty(OVERRIDE_HEADER, constant(true)).to("direct:update-file").to("direct:upload-file") + .log("updating failed transaction").setProperty(TRANSACTION_LIST, exchangeProperty(RESULT_TRANSACTION_LIST)) + .setProperty(LOCAL_FILE_PATH, exchangeProperty(RESULT_FILE)).setProperty(OVERRIDE_HEADER, constant(true)) + .to("direct:update-result-file").to("direct:upload-file"); + } + + public List updateTransactionStatus(List transactionList, + List batchAccountLookupResponseDTO, List transactionResultList, + List updatedTransactionList) { + totalApprovedCount = 0; + totalApprovedAmount = 0; + AtomicInteger count = new AtomicInteger(totalApprovedCount); + AtomicInteger amount = new AtomicInteger(totalApprovedAmount); + + transactionList.forEach(transaction -> { + Optional matchingBeneficiary = batchAccountLookupResponseDTO.stream() + .filter(beneficiary -> transaction.getPayeeIdentifier().equals(beneficiary.getPayeeIdentity())).findFirst(); + + if (matchingBeneficiary.isPresent()) { + count.incrementAndGet(); // Increment the count atomically + try { + amount.addAndGet(Integer.parseInt(transaction.getAmount())); + } catch (NumberFormatException e) { + logger.error(e.getMessage()); + } + String identifier = matchingBeneficiary.get().getFinancialAddress(); + transaction.setPayeeIdentifier(identifier); + transaction.setPayeeDfspId(matchingBeneficiary.get().getBankingInstitutionCode()); + updatedTransactionList.add(transaction); + } else { + TransactionResult transactionResult = Utils.mapToResultDTO(transaction); + transactionResult.setErrorCode("404"); + transactionResult.setErrorDescription("Payee Identifier not found"); + transactionResult.setStatus("Failed"); + transactionResultList.add(transactionResult); + } + }); + totalApprovedCount = count.get(); + totalApprovedAmount = amount.get(); + + return transactionResultList; + } + +} diff --git a/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/camel/routes/AccountLookupRoute.java b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/camel/routes/AccountLookupRoute.java new file mode 100644 index 000000000..e40a0c486 --- /dev/null +++ b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/camel/routes/AccountLookupRoute.java @@ -0,0 +1,91 @@ +package org.mifos.processor.bulk.camel.routes; + +import static org.mifos.processor.bulk.camel.config.CamelProperties.HEADER_REGISTERING_INSTITUTE_ID; +import static org.mifos.processor.bulk.camel.config.CamelProperties.OVERRIDE_HEADER; +import static org.mifos.processor.bulk.camel.config.CamelProperties.PAYEE_IDENTITY; +import static org.mifos.processor.bulk.camel.config.CamelProperties.PAYMENT_MODALITY; +import static org.mifos.processor.bulk.camel.config.CamelProperties.TRANSACTION_LIST; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.CALLBACK; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.PARTY_LOOKUP_FAILED; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.REGISTERING_INSTITUTION_ID; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.REQUEST_ID; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import javax.net.ssl.HttpsURLConnection; +import org.apache.camel.Exchange; +import org.apache.camel.Processor; +import org.mifos.connector.common.identityaccountmapper.dto.AccountMapperRequestDTO; +import org.mifos.connector.common.identityaccountmapper.dto.BeneficiaryDTO; +import org.mifos.processor.bulk.schema.Transaction; +import org.mifos.processor.bulk.service.BatchAccountLookup; +import org.mifos.processor.bulk.service.FileProcessingRouteService; +import org.mifos.processor.bulk.service.FileRouteService; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +@Component +public class AccountLookupRoute extends BaseRouteBuilder { + + @Value("${identity_account_mapper.account_lookup}") + private String accountLookupEndpoint; + @Value("${identity_account_mapper.hostname}") + private String identityURL; + @Value("${identity_account_mapper.hostname}") + private String identityMapperURL; + @Value("${identity_account_mapper.batch_account_lookup_callback}") + private String batchAccountLookupCallback; + @Value("${identity_account_mapper.batch_account_lookup}") + private String batchAccountLookup; + + @Override + public void configure() throws Exception { + Processor disableSslProcessor = new Processor() { + + @Override + public void process(Exchange exchange) throws Exception { + // Disable SSL certificate validation + HttpsURLConnection.setDefaultHostnameVerifier((hostname, sslSession) -> true); + } + }; + from("direct:send-account-lookup").id("account-lookup").process(exchange -> { + String callbackUrl = exchange.getProperty(CALLBACK, String.class); + String registeringInstitutionId = exchange.getProperty(HEADER_REGISTERING_INSTITUTE_ID, String.class); + exchange.getIn().setHeader(CALLBACK, callbackUrl); + exchange.getIn().setHeader(HEADER_REGISTERING_INSTITUTE_ID, registeringInstitutionId); + }).setHeader(Exchange.HTTP_METHOD, constant("GET")) + .toD(identityURL + accountLookupEndpoint + "?" + PAYEE_IDENTITY + "=${exchangeProperty.payeeIdentity}&" + PAYMENT_MODALITY + + "=${exchangeProperty.paymentModality}&" + "requestId=${exchangeProperty.requestId}") + .log("API Response: ${body}").process(disableSslProcessor); + + from(RouteId.ACCOUNT_LOOKUP.getValue()).id(RouteId.ACCOUNT_LOOKUP.getValue()).log("Starting route " + RouteId.ACCOUNT_LOOKUP.name()) + .process(exchange -> exchange.setProperty(OVERRIDE_HEADER, true)).bean(FileRouteService.class, "downloadFile") + .bean(FileProcessingRouteService.class, "getTxnArray").bean(BatchAccountLookup.class, "doBatchAccountLookup") + .bean(FileProcessingRouteService.class, "updateFile").bean(FileRouteService.class, "uploadFile").process(exchange -> { + exchange.setProperty(PARTY_LOOKUP_FAILED, false); + }); + + from("direct:batch-account-lookup").id("direct:batch-account-lookup").process(exchange -> { + List transactionList = exchange.getProperty(TRANSACTION_LIST, List.class); + HashMap> stringListHashMap = new HashMap<>(); + List beneficiaryDTOList = new ArrayList<>(); + transactionList.forEach(transaction -> { + beneficiaryDTOList.add(new BeneficiaryDTO(transaction.getPayeeIdentifier(), "", "", "")); + }); + String requestId = exchange.getProperty(REQUEST_ID, String.class); + String callbackUrl = exchange.getProperty(CALLBACK, String.class); + String registeringInstitutionId = exchange.getProperty(HEADER_REGISTERING_INSTITUTE_ID, String.class); + AccountMapperRequestDTO accountMapperRequestDTO = new AccountMapperRequestDTO(requestId, registeringInstitutionId, + beneficiaryDTOList); + String requestBody = objectMapper.writeValueAsString(accountMapperRequestDTO); + + exchange.getIn().setHeader(CALLBACK, callbackUrl); + exchange.getIn().setHeader(REGISTERING_INSTITUTION_ID, registeringInstitutionId); + exchange.getIn().setHeader("Content-type", "application/json"); + exchange.getIn().setBody(requestBody); + }).setHeader(Exchange.HTTP_METHOD, constant("POST")).toD(identityURL + batchAccountLookup).log("API Response: ${body}") + .process(disableSslProcessor); + + } +} diff --git a/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/camel/routes/BaseRouteBuilder.java b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/camel/routes/BaseRouteBuilder.java new file mode 100644 index 000000000..770f97dd2 --- /dev/null +++ b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/camel/routes/BaseRouteBuilder.java @@ -0,0 +1,60 @@ +package org.mifos.processor.bulk.camel.routes; + +import com.fasterxml.jackson.databind.ObjectMapper; +import io.camunda.zeebe.client.ZeebeClient; +import java.time.ZoneOffset; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; +import java.util.List; +import org.apache.camel.Exchange; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.model.RouteDefinition; +import org.mifos.processor.bulk.OperationsAppConfig; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; + +public abstract class BaseRouteBuilder extends RouteBuilder { + + @Autowired + public ObjectMapper objectMapper; + + @Autowired + public OperationsAppConfig operationsAppConfig; + + @Autowired + ZeebeClient zeebeClient; + + @Value("#{'${tenants}'.split(',')}") + protected List tenants; + + @Value("${cloud.aws.s3BaseUrl}") + protected String awsS3BaseUrl; + + public Logger logger = LoggerFactory.getLogger(this.getClass()); + + public RouteDefinition getBaseExternalApiRequestRouteDefinition(String routeId, HttpRequestMethod httpMethod) { + return from(String.format("direct:%s", routeId)).id(routeId).log("Starting external API request route: " + routeId) + .removeHeader("*").setHeader(Exchange.HTTP_METHOD, constant(httpMethod.text)) + .setHeader("X-Date", simple(ZonedDateTime.now(ZoneOffset.UTC).format(DateTimeFormatter.ISO_INSTANT))) + .setHeader("Content-Type", constant("application/json;charset=UTF-8")) + .setHeader("Accept", constant("application/json, text/plain, */*")); + } + + protected enum HttpRequestMethod { + + GET("GET"), POST("POST"), PUT("PUT"), DELETE("DELETE"); + + private final String text; + + HttpRequestMethod(String text) { + this.text = text; + } + + @Override + public String toString() { + return text; + } + } +} diff --git a/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/camel/routes/BatchAggregateRoute.java b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/camel/routes/BatchAggregateRoute.java new file mode 100644 index 000000000..403913d2c --- /dev/null +++ b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/camel/routes/BatchAggregateRoute.java @@ -0,0 +1,75 @@ +package org.mifos.processor.bulk.camel.routes; + +import static org.mifos.processor.bulk.camel.config.CamelProperties.BATCH_STATUS_FAILED; +import static org.mifos.processor.bulk.camel.config.CamelProperties.HEADER_PLATFORM_TENANT_ID; +import static org.mifos.processor.bulk.camel.config.CamelProperties.OPS_APP_ACCESS_TOKEN; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.BATCH_ID; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.COMPLETION_RATE; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.ERROR_CODE; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.ERROR_DESCRIPTION; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.TENANT_ID; + +import org.apache.camel.Exchange; +import org.apache.camel.LoggingLevel; +import org.apache.camel.ProducerTemplate; +import org.apache.camel.model.dataformat.JsonLibrary; +import org.mifos.processor.bulk.schema.BatchDTO; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +@Component +public class BatchAggregateRoute extends BaseRouteBuilder { + + @Value("${config.completion-threshold-check.completion-threshold}") + private int completionThreshold; + @Autowired + private ProducerTemplate producerTemplate; + + @Override + public void configure() throws Exception { + + from("rest:get:test/batch/summary").to(RouteId.BATCH_AGGREGATE.getValue()); + + /** + * Base route for kicking off ordering logic. Performs below tasks. 1. Downloads the csv form cloud. 2. Builds + * the [Transaction] array using [direct:get-transaction-array] route. 3. Format the data based on the + * configuration provided in application.yaml. @see [Standard.java] 4. Update file with the updated data. 5. + * Uploads the updated file in cloud. + */ + from(RouteId.BATCH_AGGREGATE.getValue()).id(RouteId.BATCH_AGGREGATE.getValue()) + .log("Starting route " + RouteId.BATCH_AGGREGATE.name()).to("direct:get-access-token").choice() + .when(exchange -> exchange.getProperty(OPS_APP_ACCESS_TOKEN, String.class) != null) + .log(LoggingLevel.INFO, "Got access token, moving on to API call").to("direct:batch-aggregate-api-call") + .to("direct:batch-aggregate-response-handler").otherwise().log(LoggingLevel.INFO, "Authentication failed.").endChoice(); + + getBaseExternalApiRequestRouteDefinition("batch-aggregate-api-call", HttpRequestMethod.GET) + // .setHeader(Exchange.REST_HTTP_QUERY, simple("batchId=${exchangeProperty." + BATCH_ID + "}")) + .setHeader("Authorization", simple("Bearer ${exchangeProperty." + OPS_APP_ACCESS_TOKEN + "}")) + .setHeader(HEADER_PLATFORM_TENANT_ID, simple("${exchangeProperty." + TENANT_ID + "}")).process(exchange -> { + logger.info(exchange.getIn().getHeaders().toString()); + }).toD(operationsAppConfig.batchAggregateUrl + "${exchangeProperty." + BATCH_ID + "}?bridgeEndpoint=true") + .log(LoggingLevel.DEBUG, "Batch aggregate API response: \n\n ${body}") + .log(LoggingLevel.INFO, "Aggregate Response body: ${body}"); + + from("direct:batch-aggregate-response-handler").id("direct:batch-aggregate-response-handler") + .log("Starting route direct:batch-aggregate-response-handler") + // .setBody(exchange -> exchange.getIn().getBody(String.class)) + .choice().when(header("CamelHttpResponseCode").isEqualTo("200")).log(LoggingLevel.INFO, "Batch summary request successful") + .log("Response body: ${body}").unmarshal().json(JsonLibrary.Jackson, BatchDTO.class).process(exchange -> { + BatchDTO batchAggregateResponse = exchange.getIn().getBody(BatchDTO.class); + int percentage = (int) (((double) batchAggregateResponse.getSuccessful() / batchAggregateResponse.getTotal()) * 100); + + if (percentage >= completionThreshold) { + logger.info("Batch success threshold reached. Expected rate: {}, Actual Rate: {}", completionThreshold, percentage); + } + + exchange.setProperty(COMPLETION_RATE, percentage); + }).otherwise().log(LoggingLevel.ERROR, "Batch aggregate request unsuccessful").process(exchange -> { + exchange.setProperty(BATCH_STATUS_FAILED, true); + exchange.setProperty(ERROR_DESCRIPTION, exchange.getIn().getBody(String.class)); + exchange.setProperty(ERROR_CODE, exchange.getIn().getHeader(Exchange.HTTP_RESPONSE_CODE)); + }); + } + +} diff --git a/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/camel/routes/DeDuplicationRoute.java b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/camel/routes/DeDuplicationRoute.java new file mode 100644 index 000000000..032fe09d0 --- /dev/null +++ b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/camel/routes/DeDuplicationRoute.java @@ -0,0 +1,119 @@ +package org.mifos.processor.bulk.camel.routes; + +import static org.mifos.processor.bulk.camel.config.CamelProperties.DUPLICATE_TRANSACTION_LIST; +import static org.mifos.processor.bulk.camel.config.CamelProperties.LOCAL_FILE_PATH; +import static org.mifos.processor.bulk.camel.config.CamelProperties.ORIGINAL_TRANSACTION_LIST; +import static org.mifos.processor.bulk.camel.config.CamelProperties.OVERRIDE_HEADER; +import static org.mifos.processor.bulk.camel.config.CamelProperties.SERVER_FILE_NAME; +import static org.mifos.processor.bulk.camel.config.CamelProperties.TRANSACTION_LIST; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.DE_DUPLICATION_FAILED; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.DUPLICATE_TRANSACTION_COUNT; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.FAILED_TRANSACTION_FILE; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import org.mifos.processor.bulk.schema.Transaction; +import org.springframework.stereotype.Component; + +@Component +public class DeDuplicationRoute extends BaseRouteBuilder { + + @Override + public void configure() throws Exception { + from(RouteId.DE_DUPLICATION.getValue()).id(RouteId.DE_DUPLICATION.getValue()) + .log("Started route " + RouteId.DE_DUPLICATION.getValue()).to("direct:download-file").to("direct:get-transaction-array") + .process(exchange -> { + List transactionList = exchange.getProperty(TRANSACTION_LIST, List.class); + + if (Objects.isNull(transactionList) || transactionList.isEmpty()) { + exchange.setProperty(DE_DUPLICATION_FAILED, false); + exchange.setProperty(DUPLICATE_TRANSACTION_COUNT, 0); + } + + int duplicateTxnCount = 0; + List duplicateTransactionList = new ArrayList<>(); // contains the duplicate + // transaction + List originalTransactionList = new ArrayList<>(); // contains the original txn after + // removing duplicate + Set set = new HashSet<>(); + + for (Transaction transaction : transactionList) { + String payeeDetail = fetchPayeeDetail(transaction); + if (set.contains(payeeDetail)) { + transaction.setNote("Duplicate transaction."); + duplicateTransactionList.add(transaction); + duplicateTxnCount++; + } else { + set.add(payeeDetail); + originalTransactionList.add(transaction); + } + } + + log.info("Duplicate txn: {} and count: {}", duplicateTransactionList, duplicateTxnCount); + + exchange.setProperty(DUPLICATE_TRANSACTION_COUNT, duplicateTxnCount); + exchange.setProperty(DUPLICATE_TRANSACTION_LIST, duplicateTransactionList); + exchange.setProperty(ORIGINAL_TRANSACTION_LIST, originalTransactionList); + }).choice().when(exchange -> exchange.getProperty(DUPLICATE_TRANSACTION_COUNT, Integer.class) > 0) + .log("Updating original transaction list") + .setProperty(TRANSACTION_LIST, simple("${exchangeProperty." + ORIGINAL_TRANSACTION_LIST + "}")) + .setProperty(LOCAL_FILE_PATH, simple("${exchangeProperty." + SERVER_FILE_NAME + "}")) + .setProperty(OVERRIDE_HEADER, constant(true)).to("direct:update-file").to("direct:upload-file").process(exchange -> { + String originalFileServerName = exchange.getProperty(SERVER_FILE_NAME, String.class); + String duplicateFileName = "duplicate_transaction_" + originalFileServerName; + + exchange.setProperty(FAILED_TRANSACTION_FILE, duplicateFileName); + }).log("Updating duplicate transaction list") + .setProperty(TRANSACTION_LIST, simple("${exchangeProperty." + DUPLICATE_TRANSACTION_LIST + "}")) + .setProperty(LOCAL_FILE_PATH, simple("${exchangeProperty." + FAILED_TRANSACTION_FILE + "}")) + .setProperty(OVERRIDE_HEADER, constant(true)).to("direct:update-file").to("direct:upload-file").process(exchange -> { + // checking if file upload was success or + String serverFileName = exchange.getProperty(SERVER_FILE_NAME, String.class); + if (serverFileName == null) { + exchange.setProperty(DE_DUPLICATION_FAILED, true); + } else { + exchange.setProperty(DE_DUPLICATION_FAILED, false); + } + }).otherwise().log("No duplicate transaction found").setProperty(DE_DUPLICATION_FAILED, constant(false)).endChoice(); + } + + private void removeDuplicatesIfOrderingDisabled(List transactionList) { + Set set = new HashSet<>(); + + if (Objects.isNull(transactionList)) { + return; + } + + for (Transaction transaction : transactionList) { + String payeeDetail = fetchPayeeDetail(transaction); + if (set.contains(payeeDetail)) { + transaction.setNote("Duplicate transaction."); + } else { + set.add(payeeDetail); + } + } + } + + private Map getTransactionPayeeDetailHashMap(List transactionList) { + Map payeeDetailTransactionMap = new HashMap<>(); + for (Transaction transaction : transactionList) { + payeeDetailTransactionMap.put(fetchPayeeDetail(transaction), transaction); + } + return payeeDetailTransactionMap; + } + + private String fetchPayeeDetail(Transaction transaction) { + String payeeIdentifier = transaction.getPayeeIdentifier(); + String payeeIdentifierType = transaction.getPayeeIdentifierType(); + String amount = transaction.getAmount(); + String currency = transaction.getCurrency(); + + return String.format("%s%s%s%s", payeeIdentifier, payeeIdentifierType, amount, currency); + } + +} diff --git a/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/camel/routes/ExternalApiCallRoute.java b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/camel/routes/ExternalApiCallRoute.java new file mode 100644 index 000000000..b2d645d76 --- /dev/null +++ b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/camel/routes/ExternalApiCallRoute.java @@ -0,0 +1,27 @@ +package org.mifos.processor.bulk.camel.routes; + +import static org.mifos.processor.bulk.camel.config.CamelProperties.ENDPOINT; +import static org.mifos.processor.bulk.camel.config.CamelProperties.HOST; + +import org.apache.camel.LoggingLevel; +import org.apache.camel.builder.RouteBuilder; + +//@Component +public class ExternalApiCallRoute extends RouteBuilder { + + @Override + public void configure() { + from("direct:external-api-calling").id("external-api-call").log(LoggingLevel.DEBUG, "######## API CALL -> Calling an external api") + .process(exchange -> { + // remove the trailing "/" from endpoint + String endpoint = exchange.getProperty(ENDPOINT, String.class); + if (endpoint.startsWith("/")) { + exchange.setProperty(ENDPOINT, endpoint.substring(1)); + } + }).log(LoggingLevel.DEBUG, "Host: ${exchangeProperty." + HOST + "}") + .log(LoggingLevel.DEBUG, "Endpoint: ${exchangeProperty." + ENDPOINT + "}").log(LoggingLevel.DEBUG, "Headers: ${headers}") + .log(LoggingLevel.DEBUG, "Request Body: ${body}").toD("${exchangeProperty." + HOST + "}/${exchangeProperty." + ENDPOINT + + "}" + "?bridgeEndpoint=true" + "&throwExceptionOnFailure=false") + .log(LoggingLevel.DEBUG, "Response body: ${body}"); + } +} diff --git a/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/camel/routes/FileProcessingRoute.java b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/camel/routes/FileProcessingRoute.java new file mode 100644 index 000000000..74cbb943f --- /dev/null +++ b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/camel/routes/FileProcessingRoute.java @@ -0,0 +1,117 @@ +package org.mifos.processor.bulk.camel.routes; + +import static org.mifos.processor.bulk.camel.config.CamelProperties.LOCAL_FILE_PATH; +import static org.mifos.processor.bulk.camel.config.CamelProperties.OVERRIDE_HEADER; +import static org.mifos.processor.bulk.camel.config.CamelProperties.RESULT_TRANSACTION_LIST; +import static org.mifos.processor.bulk.camel.config.CamelProperties.TRANSACTION_LIST; +import static org.mifos.processor.bulk.camel.config.CamelProperties.TRANSACTION_LIST_LENGTH; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.COMPLETED_AMOUNT; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.FAILED_AMOUNT; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.ONGOING_AMOUNT; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.TOTAL_AMOUNT; + +import com.fasterxml.jackson.databind.MappingIterator; +import com.fasterxml.jackson.databind.SequenceWriter; +import com.fasterxml.jackson.dataformat.csv.CsvMapper; +import com.fasterxml.jackson.dataformat.csv.CsvSchema; +import java.io.File; +import java.io.FileReader; +import java.util.ArrayList; +import java.util.List; +import org.mifos.processor.bulk.schema.Transaction; +import org.mifos.processor.bulk.schema.TransactionResult; +import org.mifos.processor.bulk.utility.CsvWriter; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component +public class FileProcessingRoute extends BaseRouteBuilder { + + @Autowired + private CsvMapper csvMapper; + + @Override + public void configure() { + + /** + * Parse the [Transaction] array from the csv file exchangeInput: [LOCAL_FILE_PATH] the absolute path to the csv + * file exchangeOutput: [TRANSACTION_LIST] containing the list of [Transaction] + */ + from("direct:get-transaction-array").id("direct:get-transaction-array").log("Starting route direct:get-transaction-array") + .process(exchange -> { + Double totalAmount = 0.0; + Long failedAmount = 0L; + Long completedAmount = 0L; + String filename = exchange.getProperty(LOCAL_FILE_PATH, String.class); + log.debug("Local file path: {}", filename); + CsvSchema schema = CsvSchema.emptySchema().withHeader(); + log.info("Filename: {}", filename); + FileReader reader = new FileReader(filename); + MappingIterator readValues = csvMapper.readerWithSchemaFor(Transaction.class).with(schema) + .readValues(reader); + List transactionList = new ArrayList<>(); + while (readValues.hasNext()) { + Transaction current = readValues.next(); + transactionList.add(current); + totalAmount += Double.parseDouble(current.getAmount()); + } + reader.close(); + exchange.setProperty(TRANSACTION_LIST, transactionList); + exchange.setProperty(TRANSACTION_LIST_LENGTH, transactionList.size()); + exchange.setProperty(TOTAL_AMOUNT, totalAmount); + exchange.setProperty(ONGOING_AMOUNT, totalAmount); // initially ongoing amount is same as total + // amount + exchange.setProperty(FAILED_AMOUNT, failedAmount); + exchange.setProperty(COMPLETED_AMOUNT, completedAmount); + }); + + /** + * updates the data in local file exchangeInput: [LOCAL_FILE_PATH] the absolute path to the csv file + * [RESULT_TRANSACTION_LIST] containing the list of [Transaction] [OVERRIDE_HEADER] if set to true will override + * the header or else use the existing once in csv file + */ + from("direct:update-result-file").id("direct:update-result-file").log("Starting route direct:update-result-file") + .process(exchange -> { + String filepath = exchange.getProperty(LOCAL_FILE_PATH, String.class); + List transactionList = exchange.getProperty(RESULT_TRANSACTION_LIST, List.class); + + // getting header + Boolean overrideHeader = exchange.getProperty(OVERRIDE_HEADER, Boolean.class); + + CsvWriter.writeToCsv(transactionList, TransactionResult.class, csvMapper, overrideHeader, filepath); + }).log("Update complete"); + + /** + * updates the data in local file exchangeInput: [LOCAL_FILE_PATH] the absolute path to the csv file + * [TRANSACTION_LIST] containing the list of [Transaction] [OVERRIDE_HEADER] if set to true will override the + * header or else use the existing once in csv file + */ + from("direct:update-file").id("direct:update-file").log("Starting route direct:update-file").to("direct:update-file-v2") + .log("Update complete"); + + /** + * this is backward compatible version of update-file route for new CSV schema exchangeInput: [LOCAL_FILE_PATH] + * the absolute path to the csv file [TRANSACTION_LIST] containing the list of [Transaction] [OVERRIDE_HEADER] + * if set to true will override the header or else use the existing once in csv file + */ + from("direct:update-file-v2").id("direct:update-file-v2").log("Starting route direct:update-file-v2").process(exchange -> { + String filepath = exchange.getProperty(LOCAL_FILE_PATH, String.class); + List transactionList = exchange.getProperty(TRANSACTION_LIST, List.class); + + // getting header + Boolean overrideHeader = exchange.getProperty(OVERRIDE_HEADER, Boolean.class); + CsvSchema csvSchema = csvMapper.schemaFor(Transaction.class); + if (overrideHeader) { + csvSchema = csvSchema.withHeader(); + } else { + csvSchema = csvSchema.withoutHeader(); + } + + File file = new File(filepath); + SequenceWriter writer = csvMapper.writerWithSchemaFor(Transaction.class).with(csvSchema).writeValues(file); + for (Transaction transaction : transactionList) { + writer.write(transaction); + } + }); + } +} diff --git a/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/camel/routes/FileRoute.java b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/camel/routes/FileRoute.java new file mode 100644 index 000000000..c4d48b786 --- /dev/null +++ b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/camel/routes/FileRoute.java @@ -0,0 +1,54 @@ +package org.mifos.processor.bulk.camel.routes; + +import static org.mifos.processor.bulk.camel.config.CamelProperties.LOCAL_FILE_PATH; +import static org.mifos.processor.bulk.camel.config.CamelProperties.SERVER_FILE_NAME; + +import java.io.File; +import java.io.FileOutputStream; +import org.mifos.processor.bulk.file.FileTransferService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +@Component +public class FileRoute extends BaseRouteBuilder { + + @Autowired + @Qualifier("awsStorage") + private FileTransferService fileTransferService; + + @Value("${application.bucket-name}") + private String bucketName; + + @Override + public void configure() throws Exception { + + /** + * Downloads the file from cloud, stores in local and returns the file path Input the file name through exchange + * variable: [SERVER_FILE_NAME] Output the local file path through exchange variable: [LOCAL_FILE_PATH] + */ + from("direct:download-file").id("direct:download-file").log("Started download-file route").process(exchange -> { + String filename = exchange.getProperty(SERVER_FILE_NAME, String.class); + + byte[] csvFile = fileTransferService.downloadFile(filename, bucketName); + File file = new File(filename); + try (FileOutputStream fos = new FileOutputStream(file)) { + fos.write(csvFile); + } + exchange.setProperty(LOCAL_FILE_PATH, file.getAbsolutePath()); + logger.info("File downloaded"); + }); + + /** + * Uploads the file to cloud and returns the file name in cloud Input the local file path through exchange + * variable: [LOCAL_FILE_PATH] Output the server file name through exchange variable: [SERVER_FILE_NAME] + */ + from("direct:upload-file").id("direct:upload-file").log("Uploading file").process(exchange -> { + String filepath = exchange.getProperty(LOCAL_FILE_PATH, String.class); + String serverFileName = fileTransferService.uploadFile(new File(filepath), bucketName); + exchange.setProperty(SERVER_FILE_NAME, serverFileName); + logger.info("Uploaded file: {}", serverFileName); + }); + } +} diff --git a/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/camel/routes/FormattingRoute.java b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/camel/routes/FormattingRoute.java new file mode 100644 index 000000000..f88d8f620 --- /dev/null +++ b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/camel/routes/FormattingRoute.java @@ -0,0 +1,61 @@ +package org.mifos.processor.bulk.camel.routes; + +import static org.mifos.processor.bulk.camel.config.CamelProperties.OVERRIDE_HEADER; +import static org.mifos.processor.bulk.camel.config.CamelProperties.TRANSACTION_LIST; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.FORMATTING_FAILED; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.FORMATTING_STANDARD; + +import java.util.List; +import org.mifos.processor.bulk.format.Standard; +import org.mifos.processor.bulk.format.helper.Mappers; +import org.mifos.processor.bulk.schema.Transaction; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +@Component +public class FormattingRoute extends BaseRouteBuilder { + + @Autowired + private Mappers mappers; + + @Value("${config.formatting.standard}") + private String standard; + + private Standard formattingStandard; + + @Override + public void configure() throws Exception { + // parsing enum from application.yaml string + formattingStandard = Standard.valueOf(standard); + + /** + * Base route for kicking off ordering logic. Performs below tasks. 1. Downloads the csv form cloud. 2. Builds + * the [Transaction] array using [direct:get-transaction-array] route. 3. Format the data based on the + * configuration provided in application.yaml. @see [Standard.java] 4. Update file with the updated data. 5. + * Uploads the updated file in cloud. + */ + from(RouteId.FORMATTING.getValue()).id(RouteId.FORMATTING.getValue()).log("Starting route " + RouteId.FORMATTING.name()).choice() + .when(exchange -> formattingStandard != Standard.DEFAULT).to("direct:download-file").to("direct:get-transaction-array") + .to("direct:format-data") + // making sure to override header as well, since data format is now updated + .process(exchange -> exchange.setProperty(OVERRIDE_HEADER, true)).to("direct:update-file").to("direct:upload-file") + .otherwise().log("Skipping formatting since standard is set to DEFAULT").end().process(exchange -> { + exchange.setProperty(FORMATTING_FAILED, false); + exchange.setProperty(FORMATTING_STANDARD, standard); + }); + + // formatting data based on configuration. Uses [Mappers] for converting data. + from("direct:format-data").id("direct:format-data").log("Starting route direct:format-data").process(exchange -> { + List transactionList = exchange.getProperty(TRANSACTION_LIST, List.class); + // replace with switch when multiple standards are added + if (formattingStandard == Standard.GSMA) { + logger.info("Formatting based on {} standard", formattingStandard.name()); + exchange.setProperty(TRANSACTION_LIST, mappers.gsmaMapper.convertList(transactionList)); + } else { + exchange.setProperty(TRANSACTION_LIST, transactionList); + } + }); + } + +} diff --git a/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/camel/routes/HealthRoute.java b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/camel/routes/HealthRoute.java new file mode 100644 index 000000000..e7a616869 --- /dev/null +++ b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/camel/routes/HealthRoute.java @@ -0,0 +1,19 @@ +package org.mifos.processor.bulk.camel.routes; + +import org.json.JSONObject; +import org.springframework.stereotype.Component; + +@Component +public class HealthRoute extends BaseRouteBuilder { + + @Override + public void configure() throws Exception { + + // todo remove once camel APIs are migrated to spring + from("rest:GET:/actuator/health/liveness").id("rest:GET:/actuator/health/liveness").setBody(exchange -> { + JSONObject jsonObject = new JSONObject(); + jsonObject.put("status", "UP"); + return jsonObject.toString(); + }); + } +} diff --git a/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/camel/routes/InitSubBatchRoute.java b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/camel/routes/InitSubBatchRoute.java new file mode 100644 index 000000000..5b876233e --- /dev/null +++ b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/camel/routes/InitSubBatchRoute.java @@ -0,0 +1,237 @@ +package org.mifos.processor.bulk.camel.routes; + +import static org.mifos.processor.bulk.camel.config.CamelProperties.BATCH_ID_HEADER; +import static org.mifos.processor.bulk.camel.config.CamelProperties.EXTERNAL_ENDPOINT; +import static org.mifos.processor.bulk.camel.config.CamelProperties.EXTERNAL_ENDPOINT_FAILED; +import static org.mifos.processor.bulk.camel.config.CamelProperties.HEADER_CLIENT_CORRELATION_ID; +import static org.mifos.processor.bulk.camel.config.CamelProperties.HEADER_REGISTERING_INSTITUTE_ID; +import static org.mifos.processor.bulk.camel.config.CamelProperties.IS_PAYMENT_MODE_VALID; +import static org.mifos.processor.bulk.camel.config.CamelProperties.LOCAL_FILE_PATH; +import static org.mifos.processor.bulk.camel.config.CamelProperties.OVERRIDE_HEADER; +import static org.mifos.processor.bulk.camel.config.CamelProperties.PAYMENT_MODE_TYPE; +import static org.mifos.processor.bulk.camel.config.CamelProperties.RESULT_TRANSACTION_LIST; +import static org.mifos.processor.bulk.camel.config.CamelProperties.SERVER_FILE_NAME; +import static org.mifos.processor.bulk.camel.config.CamelProperties.SUB_BATCH_ENTITY; +import static org.mifos.processor.bulk.camel.config.CamelProperties.TENANT_NAME; +import static org.mifos.processor.bulk.camel.config.CamelProperties.TRANSACTION_LIST; +import static org.mifos.processor.bulk.camel.config.CamelProperties.TRANSACTION_LIST_ELEMENT; +import static org.mifos.processor.bulk.camel.config.CamelProperties.TRANSACTION_LIST_LENGTH; +import static org.mifos.processor.bulk.camel.config.CamelProperties.ZEEBE_VARIABLE; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.BATCH_ID; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.COMPLETED_AMOUNT; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.DEBULKINGDFSPID; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.FAILED_AMOUNT; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.FILE_NAME; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.INIT_SUB_BATCH_FAILED; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.ONGOING_AMOUNT; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.PAYMENT_MODE; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.PURPOSE; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.REQUEST_ID; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.RESULT_FILE; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.TOTAL_AMOUNT; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.function.Function; +import org.apache.camel.Exchange; +import org.apache.camel.LoggingLevel; +import org.mifos.processor.bulk.config.ExternalApiPayloadConfig; +import org.mifos.processor.bulk.config.PaymentModeConfiguration; +import org.mifos.processor.bulk.config.PaymentModeMapping; +import org.mifos.processor.bulk.config.PaymentModeType; +import org.mifos.processor.bulk.schema.SubBatchEntity; +import org.mifos.processor.bulk.schema.Transaction; +import org.mifos.processor.bulk.schema.TransactionResult; +import org.mifos.processor.bulk.utility.Utils; +import org.mifos.processor.bulk.zeebe.BpmnConfig; +import org.mifos.processor.bulk.zeebe.ZeebeProcessStarter; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +@Component +public class InitSubBatchRoute extends BaseRouteBuilder { + + @Autowired + private ZeebeProcessStarter zeebeProcessStarter; + + @Autowired + private BpmnConfig bpmnConfig; + + @Autowired + private PaymentModeConfiguration paymentModeConfiguration; + + @Autowired + private ExternalApiPayloadConfig externalApiPayloadConfig; + + @Value("${channel.hostname}") + private String channelURL; + + @Override + public void configure() throws Exception { + + /** + * Base route for kicking off init sub batch logic. Performs below tasks. 1. Downloads the csv form cloud. 2. + * Builds the [Transaction] array using [direct:get-transaction-array] route. 3. Loops through each transaction + * and start the respective workflow + */ + from(RouteId.INIT_SUB_BATCH.getValue()).id(RouteId.INIT_SUB_BATCH.getValue()).log("Starting route " + RouteId.INIT_SUB_BATCH.name()) + .to("direct:download-file").to("direct:get-transaction-array").to("direct:start-workflow-step1"); + + // crates the zeebe variables map and starts the workflow by calling >> direct:start-workflow-step2 + from("direct:start-workflow-step1").id("direct:start-flow-step1").log("Starting route direct:start-flow-step1") + .process(exchange -> { + List transactionList = exchange.getProperty(TRANSACTION_LIST, List.class); + + Map variables = exchange.getProperty(ZEEBE_VARIABLE, Map.class); + variables.put(BATCH_ID, exchange.getProperty(BATCH_ID)); + variables.put(FILE_NAME, exchange.getProperty(SERVER_FILE_NAME)); + variables.put(REQUEST_ID, exchange.getProperty(REQUEST_ID)); + variables.put(PURPOSE, exchange.getProperty(PURPOSE)); + variables.put(TOTAL_AMOUNT, exchange.getProperty(TOTAL_AMOUNT)); + variables.put(ONGOING_AMOUNT, exchange.getProperty(ONGOING_AMOUNT)); + variables.put(FAILED_AMOUNT, exchange.getProperty(FAILED_AMOUNT)); + variables.put(COMPLETED_AMOUNT, exchange.getProperty(COMPLETED_AMOUNT)); + variables.put(RESULT_FILE, String.format("Result_%s", exchange.getProperty(SERVER_FILE_NAME))); + + exchange.setProperty(ZEEBE_VARIABLE, variables); + exchange.setProperty(PAYMENT_MODE, transactionList.get(0).getPaymentMode()); + + }).to("direct:start-workflow-step2"); + + from("direct:start-workflow-step2").id("direct:start-flow-step2").log("Starting route direct:start-flow-step2") + .to("direct:validate-payment-mode").choice() + // if invalid payment mode + .when(exchangeProperty(IS_PAYMENT_MODE_VALID).isEqualTo(false)).to("direct:payment-mode-missing") + .setProperty(INIT_SUB_BATCH_FAILED, constant(true)) + // else + .otherwise().to("direct:start-workflow-step3").endChoice(); + + from("direct:start-workflow-step3").id("direct:start-flow-step3").log("Starting route direct:start-flow-step3").choice() + // if type of payment mode is bulk + .when(exchangeProperty(PAYMENT_MODE_TYPE).isEqualTo(PaymentModeType.BULK)).process(exchange -> { + String paymentMode = exchange.getProperty(PAYMENT_MODE, String.class); + PaymentModeMapping mapping = paymentModeConfiguration.getByMode(paymentMode); + + String tenantName = exchange.getProperty(TENANT_NAME, String.class); + Map variables = exchange.getProperty(ZEEBE_VARIABLE, Map.class); + variables.put(PAYMENT_MODE, paymentMode); + variables.put(DEBULKINGDFSPID, mapping.getDebulkingDfspid() == null ? tenantName : mapping.getDebulkingDfspid()); + zeebeProcessStarter.startZeebeWorkflow( + Utils.getBulkConnectorBpmnName(mapping.getEndpoint(), mapping.getId().toLowerCase(), tenantName), variables); + exchange.setProperty(INIT_SUB_BATCH_FAILED, false); + }) + // if type of payment mode is payment todo // else case or else if case ? + .otherwise().loop(simple("${exchangeProperty." + TRANSACTION_LIST_LENGTH + "}")).process(exchange -> { + int index = exchange.getProperty(Exchange.LOOP_INDEX, Integer.class); + List transactionList = exchange.getProperty(TRANSACTION_LIST, List.class); + Transaction transaction = transactionList.get(index); + + exchange.setProperty(REQUEST_ID, transaction.getRequestId()); + exchange.setProperty("payeeDFSPId", transaction.getPayeeDfspId()); + logger.info("REQUEST_ID: {}", transaction.getRequestId()); + exchange.setProperty(TRANSACTION_LIST_ELEMENT, transaction); + }).setHeader("Platform-TenantId", exchangeProperty(TENANT_NAME)) + .setHeader("X-PayeeDFSP-ID", exchangeProperty("payeeDFSPId")).to("direct:dynamic-payload-setter") + .to("direct:external-api-call").to("direct:external-api-response-handler").end() // end loop block + .endChoice(); + + from("direct:dynamic-payload-setter").id("direct:runtime-payload-test").log("Starting route direct:runtime-payload-test") + .process(exchange -> { + String mode = exchange.getProperty(PAYMENT_MODE, String.class); + Function localPayloadVariable = externalApiPayloadConfig.getApiPayloadSetter(mode); + logger.info("MODE FOR API CALL : {}", mode); + logger.info("localPayloadVariable: {}", localPayloadVariable); + exchange.setProperty("body", localPayloadVariable.apply(exchange)); + }) + // this payload variable returns the body for respective payment modes + .setBody(simple("${exchangeProperty.body}")); + + // Loops through each transaction and start the respective workflow + from("direct:external-api-response-handler").id("direct:external-api-response-handler") + .log("Starting route direct:external-api-response-handler").choice().when(header("CamelHttpResponseCode").isEqualTo(200)) + .process(exchange -> { + logger.info("INIT_SUB_BATCH_FAILED is false"); + exchange.setProperty(INIT_SUB_BATCH_FAILED, false); + }).otherwise().process(exchange -> { + logger.info("INIT_SUB_BATCH_FAILED is false"); + exchange.setProperty(INIT_SUB_BATCH_FAILED, true); + }).endChoice(); + + from("direct:payment-mode-missing").id("direct:payment-mode-missing").log("Starting route direct:payment-mode-missing") + .process(exchange -> { + String serverFileName = exchange.getProperty(SERVER_FILE_NAME, String.class); + String resultFile = String.format("Result_%s", serverFileName); + + List transactionList = exchange.getProperty(TRANSACTION_LIST, List.class); + List transactionResultList = updateTransactionStatusToFailed(transactionList); + exchange.setProperty(RESULT_TRANSACTION_LIST, transactionResultList); + exchange.setProperty(RESULT_FILE, resultFile); + }) + // setting localfilepath as result file to make sure result file is uploaded + .setProperty(LOCAL_FILE_PATH, exchangeProperty(RESULT_FILE)).setProperty(OVERRIDE_HEADER, constant(true)) + .process(exchange -> { + logger.info("A1 {}", exchange.getProperty(RESULT_FILE)); + logger.info("A2 {}", exchange.getProperty(LOCAL_FILE_PATH)); + logger.info("A3 {}", exchange.getProperty(OVERRIDE_HEADER)); + }).to("direct:update-result-file").to("direct:upload-file"); + + from("direct:external-api-call").id("direct:external-api-call").log("Starting route direct:external-api-call").process(exchange -> { + String paymentMode = exchange.getProperty(PAYMENT_MODE, String.class); + PaymentModeMapping mapping = paymentModeConfiguration.getByMode(paymentMode); + if (mapping == null) { + exchange.setProperty(EXTERNAL_ENDPOINT_FAILED, true); + logger.info("Failed to get the payment mode config, check the configuration for payment mode"); + } else { + exchange.setProperty(EXTERNAL_ENDPOINT_FAILED, false); + exchange.setProperty(EXTERNAL_ENDPOINT, mapping.getEndpoint()); + logger.info("Got the config with routing to endpoint {}", mapping.getEndpoint()); + } + }).choice().when(exchangeProperty(EXTERNAL_ENDPOINT_FAILED).isEqualTo(false)) + .log(LoggingLevel.DEBUG, "Making API call to endpoint ${exchangeProperty.extEndpoint} and body: ${body}") + .setHeader(Exchange.CONTENT_TYPE, constant("application/json")).choice() + .when(exchange -> exchange.getProperty(SUB_BATCH_ENTITY, SubBatchEntity.class) != null) + .log("Sub batch entity is not null, hence passing subBatchId while calling channel API").process(exchange -> { + SubBatchEntity subBatchEntity = exchange.getProperty(SUB_BATCH_ENTITY, SubBatchEntity.class); + exchange.getIn().setHeader(BATCH_ID_HEADER, subBatchEntity.getSubBatchId()); + }).otherwise().log("Sub batch entity is null, hence passing batchId while calling channel API") + .setHeader(BATCH_ID_HEADER, simple("${exchangeProperty." + BATCH_ID + "}")).endChoice() + .setHeader(HEADER_CLIENT_CORRELATION_ID, simple("${exchangeProperty." + REQUEST_ID + "}")) + .setHeader(HEADER_REGISTERING_INSTITUTE_ID, simple("${exchangeProperty." + HEADER_REGISTERING_INSTITUTE_ID + "}")) + .process(exchange -> { + log.debug("Variables: {}", exchange.getProperties()); + log.debug("Emergency: {}", exchange.getIn().getHeaders()); + }) + + .toD(channelURL + "${exchangeProperty.extEndpoint}" + "?bridgeEndpoint=true&throwExceptionOnFailure=false") + .log(LoggingLevel.DEBUG, "Response body: ${body}").otherwise().endChoice(); + + from("direct:validate-payment-mode").id("direct:validate-payment-mode").log("Starting route direct:validate-payment-mode") + .process(exchange -> { + String paymentMde = exchange.getProperty(PAYMENT_MODE, String.class); + PaymentModeMapping mapping = paymentModeConfiguration.getByMode(paymentMde); + if (mapping == null) { + exchange.setProperty(IS_PAYMENT_MODE_VALID, false); + } else { + exchange.setProperty(IS_PAYMENT_MODE_VALID, true); + exchange.setProperty(PAYMENT_MODE_TYPE, mapping.getType()); + } + }); + } + + // update Transactions status to failed + private List updateTransactionStatusToFailed(List transactionList) { + List transactionResultList = new ArrayList<>(); + for (Transaction transaction : transactionList) { + TransactionResult transactionResult = Utils.mapToResultDTO(transaction); + transactionResult.setErrorCode("404"); + transactionResult.setErrorDescription("Payment mode not configured"); + transactionResult.setStatus("Failed"); + transactionResultList.add(transactionResult); + } + + return transactionResultList; + } + +} diff --git a/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/camel/routes/MergeBackRoute.java b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/camel/routes/MergeBackRoute.java new file mode 100644 index 000000000..db6d64566 --- /dev/null +++ b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/camel/routes/MergeBackRoute.java @@ -0,0 +1,101 @@ +package org.mifos.processor.bulk.camel.routes; + +import static org.mifos.processor.bulk.camel.config.CamelProperties.FILE_1; +import static org.mifos.processor.bulk.camel.config.CamelProperties.FILE_2; +import static org.mifos.processor.bulk.camel.config.CamelProperties.LOCAL_FILE_PATH; +import static org.mifos.processor.bulk.camel.config.CamelProperties.SERVER_FILE_NAME; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.BATCH_ID; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.MERGE_COMPLETED; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.MERGE_FAILED; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.MERGE_FILE_LIST; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.MERGE_ITERATION; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.RESULT_FILE; + +import java.io.File; +import java.util.List; +import org.apache.camel.Exchange; +import org.mifos.processor.bulk.utility.Utils; +import org.springframework.stereotype.Component; + +@Component +public class MergeBackRoute extends BaseRouteBuilder { + + @Override + public void configure() throws Exception { + + /** + * Base route for kicking off merge back logic. Performs below tasks. 1. Picks the top two files from the array + * of files to be merged. 2. Merges them into single CSV. 3. Uploads the CSV to S3. 4. Updated the exchange + * variables. + */ + from(RouteId.MERGE_BACK.getValue()).id(RouteId.MERGE_BACK.getValue()).log("Starting route " + RouteId.MERGE_BACK.name()).choice() + .when(exchange -> exchange.getProperty(MERGE_FILE_LIST, List.class).size() == 0).log("Nothing to merge") + .setProperty(MERGE_FAILED, constant(false)).setProperty(MERGE_COMPLETED, constant(true)) + .when(exchange -> exchange.getProperty(MERGE_FILE_LIST, List.class).size() == 1).process(exchange -> { + exchange.setProperty(MERGE_FAILED, false); + exchange.setProperty(MERGE_COMPLETED, true); + String resultFile = (String) exchange.getProperty(MERGE_FILE_LIST, List.class).get(0); + setResultFileProperty(exchange, resultFile); + }).otherwise().to("direct:start-merge").endChoice(); + + // starts the merge process, merges the file and uploads the file in s3 + from("direct:start-merge").id("direct:start-merge").log("Starting route direct:start-merge").to("direct:download-file-to-be-merged") + .process(exchange -> { + String file1 = exchange.getProperty(FILE_1, String.class); + String file2 = exchange.getProperty(FILE_2, String.class); + + String mergedFile = Utils.mergeCsvFile(file1, file2); + if (mergedFile == null) { + exchange.setProperty(MERGE_COMPLETED, false); + return; + } + if (exchange.getProperty(MERGE_ITERATION, Integer.class) == 1) { + // generate new name for merged file in case of first iteration + String newFileName = System.currentTimeMillis() + "_" + exchange.getProperty(BATCH_ID, String.class) + ".csv"; + new File(mergedFile).renameTo(new File(newFileName)); + exchange.setProperty(LOCAL_FILE_PATH, newFileName); + } else { + exchange.setProperty(LOCAL_FILE_PATH, mergedFile); + } + }).to("direct:upload-file").process(exchange -> { + String mergedFileServerName = exchange.getProperty(SERVER_FILE_NAME, String.class); + List mergeList = exchange.getProperty(MERGE_FILE_LIST, List.class); + String first = mergeList.remove(0); + String second = mergeList.remove(0); + logger.info("Merge iteration {}, for list, {}", exchange.getProperty(MERGE_ITERATION), mergeList); + log.info("Merged files {} and {}", first, second); + mergeList.add(0, mergedFileServerName); + + if (mergeList.size() == 1) { + exchange.setProperty(MERGE_FAILED, false); + exchange.setProperty(MERGE_COMPLETED, true); + setResultFileProperty(exchange, mergedFileServerName); + } else { + exchange.setProperty(MERGE_COMPLETED, false); + } + + exchange.setProperty(MERGE_FILE_LIST, mergeList); + + // make sures to remove the files from local storage + new File(exchange.getProperty(FILE_1, String.class)).delete(); + new File(exchange.getProperty(FILE_2, String.class)).delete(); + }); + + // downloads the two files(using FIFO access pattern) from s3 which is to be merged. + from("direct:download-file-to-be-merged").id("direct:download-file-to-be-merged") + .log("Starting route direct:download-file-to-be-merged").log("Downloading files to be merged").process(exchange -> { + List mergeList = exchange.getProperty(MERGE_FILE_LIST, List.class); + exchange.setProperty(SERVER_FILE_NAME, mergeList.get(0)); + }).to("direct:download-file") // downloading first file + .setProperty(FILE_1, exchangeProperty(LOCAL_FILE_PATH)).process(exchange -> { + List mergeList = exchange.getProperty(MERGE_FILE_LIST, List.class); + exchange.setProperty(SERVER_FILE_NAME, mergeList.get(1)); + }).to("direct:download-file") // downloading second file + .setProperty(FILE_2, exchangeProperty(LOCAL_FILE_PATH)); + } + + // set RESULT_FILE exchange property to the file url + public void setResultFileProperty(Exchange exchange, String fileName) { + exchange.setProperty(RESULT_FILE, Utils.getAwsFileUrl(awsS3BaseUrl, fileName)); + } +} diff --git a/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/camel/routes/OperationsAuthRoute.java b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/camel/routes/OperationsAuthRoute.java new file mode 100644 index 000000000..da073cc97 --- /dev/null +++ b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/camel/routes/OperationsAuthRoute.java @@ -0,0 +1,58 @@ +package org.mifos.processor.bulk.camel.routes; + +import static org.mifos.processor.bulk.camel.config.CamelProperties.HEADER_PLATFORM_TENANT_ID; +import static org.mifos.processor.bulk.camel.config.CamelProperties.OPS_APP_ACCESS_TOKEN; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.TENANT_ID; + +import java.util.HashMap; +import java.util.Map; +import org.apache.camel.Exchange; +import org.apache.camel.LoggingLevel; +import org.apache.camel.model.dataformat.JsonLibrary; +import org.springframework.stereotype.Component; + +@Component +public class OperationsAuthRoute extends BaseRouteBuilder { + + @Override + public void configure() throws Exception { + + from("rest:get:test/auth").to("direct:get-access-token"); + + /** + * Error handling route + */ + from("direct:access-token-error").id("access-token-error").process(exchange -> { + logger.error("Error while fetching Access Token from server: " + exchange.getIn().getBody()); + }); + + /** + * Save Access Token to AccessTokenStore + */ + from("direct:access-token-save").id("access-token-save").unmarshal().json(JsonLibrary.Jackson, HashMap.class).process(exchange -> { + // TODO: Figure out access token storage if required + Map jsonObject = exchange.getIn().getBody(HashMap.class); + exchange.setProperty(OPS_APP_ACCESS_TOKEN, jsonObject.get("access_token")); + logger.debug("Saved Access Token: " + exchange.getProperty(OPS_APP_ACCESS_TOKEN, String.class)); + exchange.getIn().setBody(jsonObject.toString()); + }); + + /** + * Fetch Access Token from SLCB + */ + getBaseExternalApiRequestRouteDefinition("access-token-fetch", HttpRequestMethod.POST) + .setHeader(Exchange.REST_HTTP_QUERY, + simpleF("username=%s&password=%s&grant_type=%s", operationsAppConfig.username, operationsAppConfig.password, + "password")) + .setHeader("Authorization", constant("Basic Y2xpZW50Og==")) + .setHeader(HEADER_PLATFORM_TENANT_ID, simple("${exchangeProperty." + TENANT_ID + "}")) + .toD(operationsAppConfig.authUrl + "?bridgeEndpoint=true").log(LoggingLevel.INFO, "Auth response: \n\n ${body}"); + + /** + * Access Token check validity and return value + */ + from("direct:get-access-token").id("get-access-token").to("direct:access-token-fetch").choice() + .when(header("CamelHttpResponseCode").isEqualTo("200")).log("Access Token Fetch Successful").to("direct:access-token-save") + .otherwise().log("Access Token Fetch Unsuccessful").to("direct:access-token-error"); + } +} diff --git a/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/camel/routes/OrderingRoute.java b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/camel/routes/OrderingRoute.java new file mode 100644 index 000000000..5f23e11c6 --- /dev/null +++ b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/camel/routes/OrderingRoute.java @@ -0,0 +1,79 @@ +package org.mifos.processor.bulk.camel.routes; + +import static org.mifos.processor.bulk.camel.config.CamelProperties.TRANSACTION_LIST; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.ORDERED_BY; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.ORDERING_FAILED; + +import java.util.HashMap; +import java.util.List; +import org.mifos.processor.bulk.schema.Transaction; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +@Component +public class OrderingRoute extends BaseRouteBuilder { + + @Value("${config.ordering.field}") + private String orderingField; + + @Override + public void configure() { + + /** + * Base route for kicking off ordering logic. Performs below tasks. 1. Downloads the csv form cloud. 2. Builds + * the [Transaction] array using CsvMapper. 3. Re-order the array generated in step1 based on [orderingField]. + * 4. Update file with the updated data. 5. Uploads the updated file in cloud. + */ + from(RouteId.ORDERING.getValue()).id(RouteId.ORDERING.getValue()).log("Starting route " + RouteId.ORDERING.name()) + .to("direct:download-file").to("direct:get-transaction-array").to("direct:order-data").to("direct:update-file") + .to("direct:upload-file").process(exchange -> { + exchange.setProperty(ORDERING_FAILED, false); + exchange.setProperty(ORDERED_BY, orderingField); + }); + + // re-order the array of [Transaction] based on [orderingField] + from("direct:order-data").id("direct:order-data").log("Starting route direct:order-data").process(exchange -> { + List transactionList = exchange.getProperty(TRANSACTION_LIST, List.class); + HashMap> stringListHashMap = new HashMap<>(); + transactionList.forEach((transaction) -> { + String key; + switch (orderingField) { + case "id": + key = "" + transaction.getId(); + break; + case "request_id": + key = transaction.getRequestId(); + break; + case "account_number": + key = transaction.getAccountNumber(); + break; + case "payee_identifier": + key = transaction.getPayeeIdentifier(); + break; + case "amount": + key = transaction.getAmount(); + break; + case "currency": + key = transaction.getCurrency(); + break; + case "note": + key = transaction.getNote(); + break; + default: + key = transaction.getPaymentMode(); + break; + } + + if (stringListHashMap.containsKey(key)) { + stringListHashMap.get(key).add(transaction); + } else { + transactionList.add(transaction); + stringListHashMap.put(key, transactionList); + } + }); + transactionList.clear(); + stringListHashMap.forEach((s, transactions) -> transactionList.addAll(transactions)); + exchange.setProperty(TRANSACTION_LIST, transactionList); + }); + } +} diff --git a/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/camel/routes/ProcessorStartRoute.java b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/camel/routes/ProcessorStartRoute.java new file mode 100644 index 000000000..3ea44b19c --- /dev/null +++ b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/camel/routes/ProcessorStartRoute.java @@ -0,0 +1,353 @@ +package org.mifos.processor.bulk.camel.routes; + +import static org.mifos.processor.bulk.camel.config.CamelProperties.BATCH_REQUEST_TYPE; +import static org.mifos.processor.bulk.camel.config.CamelProperties.HEADER_PLATFORM_TENANT_ID; +import static org.mifos.processor.bulk.camel.config.CamelProperties.IS_UPDATED; +import static org.mifos.processor.bulk.camel.config.CamelProperties.LOCAL_FILE_PATH; +import static org.mifos.processor.bulk.camel.config.CamelProperties.OVERRIDE_HEADER; +import static org.mifos.processor.bulk.camel.config.CamelProperties.TENANT_NAME; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.APPROVAL_ENABLED; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.AUTHORIZATION_ENABLED; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.BATCH_AGGREGATE_ENABLED; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.BATCH_ID; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.BULK_NOTIF_FAILURE; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.BULK_NOTIF_SUCCESS; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.CALLBACK; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.COMPLETION_THRESHOLD; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.COMPLETION_THRESHOLD_CHECK_ENABLED; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.DE_DUPLICATION_ENABLE; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.FILE_NAME; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.FORMATTING_ENABLED; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.MAX_CALLBACK_RETRY; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.MAX_STATUS_RETRY; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.MERGE_ENABLED; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.ORDERING_ENABLED; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.PARTY_LOOKUP_ENABLED; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.PURPOSE; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.REQUEST_ID; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.SPLITTING_ENABLED; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.THRESHOLD_DELAY; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.UUID; +import org.apache.camel.Exchange; +import org.apache.camel.LoggingLevel; +import org.apache.tika.Tika; +import org.json.JSONObject; +import org.mifos.processor.bulk.config.BudgetAccountConfig; +import org.mifos.processor.bulk.connectors.service.ProcessorStartRouteService; +import org.mifos.processor.bulk.file.FileTransferService; +import org.mifos.processor.bulk.properties.TenantImplementation; +import org.mifos.processor.bulk.properties.TenantImplementationProperties; +import org.mifos.processor.bulk.utility.PhaseUtils; +import org.mifos.processor.bulk.utility.Utils; +import org.mifos.processor.bulk.zeebe.ZeebeProcessStarter; +import org.mifos.processor.bulk.zeebe.worker.WorkerConfig; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +@Component +public class ProcessorStartRoute extends BaseRouteBuilder { + + @Autowired + private ZeebeProcessStarter zeebeProcessStarter; + @Autowired + TenantImplementationProperties tenantImplementationProperties; + + @Autowired + @Qualifier("awsStorage") + private FileTransferService fileTransferService; + + @Autowired + protected WorkerConfig workerConfig; + + @Value("${application.bucket-name}") + private String bucketName; + + @Value("${bpmn.flows.bulk-processor}") + private String workflowId; + + @Value("${config.completion-threshold-check.completion-threshold}") + private int completionThreshold; + + @Value("${config.completion-threshold-check.max-retry}") + private int maxThresholdCheckRetry; + + @Value("${config.completion-threshold-check.delay}") + private int thresholdCheckDelay; + + @Value("${callback.max-retry}") + private int maxCallbackRetry; + + @Value("${pollingApi.timer}") + private String pollApiTimer; + + @Value("#{'${csv.columnNames}'.split(',')}") + private List columnNames; + + @Value("${csv.size}") + private int csvSize; + + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Autowired + PhaseUtils phaseUtils; + + @Autowired + BudgetAccountConfig budgetAccountConfig; + + @Override + public void configure() { + setup(); + } + + private void setup() { + + from("direct:post-batch-transactions").id("rest:POST:/batchtransactions").log("Starting route rest:POST:/batchtransactions") + .to("direct:validate-file").choice().when(header("CamelHttpResponseCode").isNotEqualTo("200")) + .log(LoggingLevel.ERROR, "File upload failed").otherwise().process(exchange -> { + String batchId = UUID.randomUUID().toString(); + exchange.setProperty(BATCH_ID, batchId); + + }).bean(ProcessorStartRouteService.class, "validateFileSyncResponse").choice() + .when(header("CamelHttpResponseCode").isNotEqualTo("200")).log(LoggingLevel.ERROR, "File upload failed").otherwise() + .to("direct:executeBatch").endChoice().endChoice(); + + from("direct:post-bulk-transfer").unmarshal().mimeMultipart("multipart/*").to("direct:validate-tenant").process(exchange -> { + String fileName = System.currentTimeMillis() + "_" + exchange.getIn().getHeader("fileName", String.class); + String requestId = exchange.getIn().getHeader("requestId", String.class); + String purpose = exchange.getIn().getHeader("purpose", String.class); + String batchId = UUID.randomUUID().toString(); + String callbackUrl = exchange.getIn().getHeader("X-CallbackURL", String.class); + exchange.setProperty(CALLBACK, callbackUrl); + exchange.setProperty(BATCH_ID, batchId); + exchange.setProperty(FILE_NAME, fileName); + exchange.setProperty(REQUEST_ID, requestId); + exchange.setProperty(PURPOSE, purpose); + }).wireTap("direct:start-batch-process-csv"); + + from("direct:validate-tenant").id("direct:validate-tenant").log("Validating tenant").process(exchange -> { + String tenantName = exchange.getIn().getHeader(HEADER_PLATFORM_TENANT_ID, String.class); + // validation is disabled for now + /* + * if (tenantName == null || tenantName.isEmpty() || !tenants.contains(tenantName)) { throw new + * Exception("Invalid tenant value."); } + */ + exchange.setProperty(TENANT_NAME, tenantName); + }).setHeader("Content-Type", constant("application/json;charset=UTF-8")).log("Completed route direct:validate-tenant"); + + // this route is responsible for editing the incoming records based on configuration + // this step is done to make sure the file format of CSV is not altered and only the data is updated based on + // config + from("direct:update-incoming-data").id("direct:update-incoming-data").log("direct:update-incoming-data") + // [LOCAL_FILE_PATH] is already set in [direct:validateFileSyncResponse] route + .setProperty(LOCAL_FILE_PATH, exchangeProperty(FILE_NAME)).to("direct:get-transaction-array") + // make sure new data is set under the exchange variable [RESULT_TRANSACTION_LIST] + .bean(ProcessorStartRouteService.class, "updateIncomingData").choice() + // update only when previous(edit function) makes any changes to data + .when(exchange -> exchange.getProperty(IS_UPDATED, Boolean.class)) + // warning: changing this flag can break things + .setProperty(OVERRIDE_HEADER, constant(true)) // default header in CSV file will be used + .to("direct:update-file-v2").otherwise().log(LoggingLevel.INFO, "No update"); + + from("direct:start-batch-process-csv").id("direct:start-batch-process-csv").log("Starting route direct:start-batch-process-csv") + .to("direct:update-incoming-data").bean(ProcessorStartRouteService.class, "startBatchProcessCsv") + .log("Completed route direct:start-batch-process-csv").bean(ProcessorStartRouteService.class, "pollingOutput"); + + from("direct:start-batch-process-raw").id("direct:start-batch-process-raw").log("Starting route direct:start-batch-process-raw") + .process(exchange -> { + JSONObject response = new JSONObject(); + response.put("batch_id", UUID.randomUUID().toString()); + response.put("request_id", UUID.randomUUID().toString()); + response.put("status", "queued"); + exchange.getIn().setBody(response.toString()); + }).log("Completed route direct:start-batch-process-raw"); + + from("direct:executeBatch").id("direct:executeBatch").log("Starting route direct:executeBatch") + .bean(ProcessorStartRouteService.class, "validateTenant").bean(ProcessorStartRouteService.class, "executeBatch").choice() + .when(exchange -> exchange.getProperty(BATCH_REQUEST_TYPE, String.class).equalsIgnoreCase("raw")) + .bean(ProcessorStartRouteService.class, "startBatchProcessRaw") + .when(exchange -> exchange.getProperty(BATCH_REQUEST_TYPE, String.class).equalsIgnoreCase("csv")) + .to("direct:start-batch-process-csv").otherwise() + .setBody(exchange -> getUnsupportedTypeJson(exchange.getProperty(BATCH_REQUEST_TYPE, String.class)).toString()) + .log("Completed execution of route rest:POST:/batchtransactions"); + + from("direct:pollingOutput").id("direct:pollingOutput").log("Started pollingOutput route").process(exchange -> { + JSONObject json = new JSONObject(); + json.put("PollingPath", "/batch/Summary/" + exchange.getProperty(BATCH_ID)); + json.put("SuggestedCallbackSeconds", pollApiTimer); + exchange.getIn().setBody(json.toString()); + exchange.getIn().setHeader(Exchange.HTTP_RESPONSE_CODE, 202); + }); + + from("direct:validateFileSyncResponse").id("direct:validateFileSyncResponse").log("Starting route direct:validateFileSyncResponse") + .process(exchange -> { + // move this logic to spring + String fileName = exchange.getIn().getHeader(FILE_NAME, String.class); + File file = new File(fileName); + + // check the file structure + int fileSize = (int) file.length(); + if (fileSize > csvSize) { + setErrorResponse(exchange, 400, "File too big", + "The file uploaded is too big. " + "Please upload a file and try again."); + } else if (!verifyCsv(file)) { + setErrorResponse(exchange, 400, "Invalid file structure", + "The file uploaded contains wrong structure." + " Please upload correct file columns and try again."); + } else { + logger.debug("Filename: {}", fileName); + setResponse(exchange, 200); + } + + }).log("Completed route direct:validateFileSyncResponse"); + + from("direct:validate-file").id("direct:validate-file").log("Starting route direct:validate-file").process(exchange -> { + File f = new File(exchange.getIn().getHeader(FILE_NAME, String.class)); + logger.debug("File name: {} ", f.getName()); + Tika tika = new Tika(); + String fileType = tika.detect(f.getName()); + logger.debug("File type: {} ", fileType); + if (f.getName().isEmpty()) { + setErrorResponse(exchange, 400, "File not uploaded", + "There was no fie uploaded with the request. " + "Please upload a file and try again."); + } else if (!fileType.equalsIgnoreCase("text/csv")) { + setErrorResponse(exchange, 400, "Broken file", + "The file uploaded is broken as it has a different extension. " + "Please upload a csv file and try again."); + } else { + setResponse(exchange, 200); + } + + }); + + } + + public boolean verifyData(File file) throws IOException { + InputStream ips = new FileInputStream(file); + InputStreamReader ipsr = new InputStreamReader(ips); + BufferedReader br = new BufferedReader(ipsr); + String line; + br.readLine(); + while ((line = br.readLine()) != null) { + String[] row = line.split(","); + if (row.length != columnNames.size()) { + logger.debug("Row invalid {} {}", row.length, columnNames.size()); + return false; + } + if (!verifyRow(row)) { + return false; + } + } + return true; + } + + public String getWorkflowForTenant(String tenantId, String useCase) { + + for (TenantImplementation tenant : tenantImplementationProperties.getTenants()) { + if (tenant.getId().equals(tenantId)) { + return tenant.getFlows().getOrDefault(useCase, "default"); + } + } + return "default"; + } + + private boolean verifyRow(String[] row) { + for (int i = 1; i < row.length; i++) { + row[i] = row[i].trim(); + if (row[i].equalsIgnoreCase("MSISDN")) { + int j = row[i].indexOf("MSISDN"); + if (!(j == row.length)) { + if (!row[j + 1].matches("^[0-9]*$")) { + logger.debug("MSISDN invalid"); + return false; + } + } + } else if (row[i].contains("amount")) { + int j = row[i].indexOf("amount"); + if (!row[j].matches("^[0-9]*$")) { + logger.debug("Amount invalid"); + return false; + } + + } + } + return true; + } + + public boolean verifyCsv(File csvData) throws IOException { + BufferedReader br = new BufferedReader(new FileReader(csvData)); + String header = br.readLine(); + String[] columns = new String[0]; + if (header != null) { + columns = header.split(","); + logger.debug("Columns in the csv file are {}", Arrays.toString(columns)); + } + int i = 0; + while (i < columns.length) { + if (columnNames.contains(columns[i])) { + logger.debug("Column name {} is at index {} ", columns[i], columnNames.indexOf(columns[i])); + i++; + + } else { + return false; + } + } + return true; + } + + public void setErrorResponse(Exchange exchange, int responseCode, String errorInfo, String errorDescription) { + // TODO Auto-generated method stub + JSONObject json = new JSONObject(); + json.put("Error Information: ", errorInfo); + json.put("Error Description : ", errorDescription); + exchange.getIn().setHeader(Exchange.HTTP_RESPONSE_CODE, responseCode); + exchange.getIn().setBody(json.toString()); + exchange.setProperty("body", json); + logger.error("Error response is {}", json); + } + + public void setResponse(Exchange exchange, int responseCode) { + exchange.getIn().setHeader(Exchange.HTTP_RESPONSE_CODE, responseCode); + } + + public Map setConfigProperties(Map variables) { + variables.put(BATCH_AGGREGATE_ENABLED, workerConfig.isBatchAggregateEnabled); + variables.put(PARTY_LOOKUP_ENABLED, workerConfig.isPartyLookUpWorkerEnabled); + variables.put(AUTHORIZATION_ENABLED, workerConfig.isAuthorizationWorkerEnabled); + variables.put(APPROVAL_ENABLED, workerConfig.isApprovalWorkerEnabled); + variables.put(DE_DUPLICATION_ENABLE, workerConfig.isTransactionDeduplicationEnabled); + variables.put(ORDERING_ENABLED, workerConfig.isOrderingWorkerEnabled); + variables.put(SPLITTING_ENABLED, workerConfig.isSplittingWorkerEnabled); + variables.put(FORMATTING_ENABLED, workerConfig.isFormattingWorkerEnabled); + variables.put(COMPLETION_THRESHOLD_CHECK_ENABLED, workerConfig.isCompletionThresholdCheckEnabled); + variables.put(MERGE_ENABLED, workerConfig.isMergeBackWorkerEnabled); + variables.put(MAX_STATUS_RETRY, maxThresholdCheckRetry); + variables.put(COMPLETION_THRESHOLD, completionThreshold); + variables.put(THRESHOLD_DELAY, Utils.getZeebeTimerValue(thresholdCheckDelay)); + variables.put(BULK_NOTIF_SUCCESS, false); + variables.put(BULK_NOTIF_FAILURE, false); + variables.put(MAX_CALLBACK_RETRY, maxCallbackRetry); + + return variables; + } + + private JSONObject getUnsupportedTypeJson(String type) { + JSONObject response = new JSONObject(); + response.put("errorCode", 400); + response.put("errorDescription", String.format("Query parameter ?type=%s not supported", type)); + response.put("developerMessage", ""); + return response; + } +} diff --git a/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/camel/routes/PubSubRoute.java b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/camel/routes/PubSubRoute.java new file mode 100644 index 000000000..c108c360d --- /dev/null +++ b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/camel/routes/PubSubRoute.java @@ -0,0 +1,54 @@ +package org.mifos.processor.bulk.camel.routes; + +import static org.mifos.processor.bulk.camel.config.CamelProperties.ENDPOINT; +import static org.mifos.processor.bulk.camel.config.CamelProperties.EVENT_TYPE; +import static org.mifos.processor.bulk.camel.config.CamelProperties.HOST; + +import org.apache.camel.Exchange; +import org.mifos.processor.bulk.config.PubSubConfig; +import org.mifos.processor.bulk.config.SecurityServerConfig; +import org.mifos.processor.bulk.schema.SubscriptionDTO; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +@Component +public class PubSubRoute extends BaseRouteBuilder { + + private final PubSubConfig pubSubConfig; + private final SecurityServerConfig securityServerConfig; + + @Value("${gov-stack-client.header-key}") + private String govStackClientHeaderKey; + + @Value("${gov-stack-client.header-value}") + private String govStackClientHeaderValue; + + public PubSubRoute(PubSubConfig pubSubConfig, SecurityServerConfig securityServerConfig) { + this.pubSubConfig = pubSubConfig; + this.securityServerConfig = securityServerConfig; + } + + @Override + public void configure() throws Exception { + + // needs EVENT_TYPE input from exchange + from("direct:subscribe").id("direct:subscribe") + .setBody(exchange -> getEventTypeSpecificSubscriptionDTO(exchange.getProperty(EVENT_TYPE, String.class))) + .setHeader(Exchange.HTTP_METHOD, constant(HttpRequestMethod.POST.toString())) + .setHeader(govStackClientHeaderKey, constant(govStackClientHeaderValue)) + .setProperty(HOST, constant(securityServerConfig.host)).setProperty(ENDPOINT, constant(securityServerConfig.subscribingUrl)) + .to("direct:external-api-calling"); + + } + + private SubscriptionDTO getDefaultSubscriptionDTO() { + return SubscriptionDTO.subscriptionDTOBuilder.roomCode(pubSubConfig.roomCode).roomClass(pubSubConfig.roomClass) + .srcOperationId("bulkProcessing").srcServiceCode("bulk").dstOperationId("newRecord").dstServiceCode("bulk").build(); + } + + private SubscriptionDTO getEventTypeSpecificSubscriptionDTO(String eventType) { + SubscriptionDTO subscriptionDTO = getDefaultSubscriptionDTO(); + subscriptionDTO.setDstServiceCode(eventType); // todo update once confirmed which field is for eventType + return subscriptionDTO; + } +} diff --git a/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/camel/routes/RouteId.java b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/camel/routes/RouteId.java new file mode 100644 index 000000000..3a4879b3e --- /dev/null +++ b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/camel/routes/RouteId.java @@ -0,0 +1,20 @@ +package org.mifos.processor.bulk.camel.routes; + +public enum RouteId { + + PARTY_LOOKUP("direct:partyLookup"), APPROVAL("direct:approval"), ORDERING("direct:ordering"), SPLITTING("direct:splitting"), FORMATTING( + "direct:formatting"), BATCH_STATUS("direct:batchStatus"), SEND_CALLBACK("direct:sendCallback"), MERGE_BACK( + "direct:mergeSubBatch"), INIT_SUB_BATCH("direct:init-sub-batches"), BATCH_AGGREGATE( + "direct:batch-aggregate"), DE_DUPLICATION("direct:deDuplication"), ACCOUNT_LOOKUP( + "direct:accountLookup"), ACCOUNT_LOOKUP_CALLBACK("direct:accountLookupCallback"); + + private final String value; + + RouteId(String s) { + value = s; + } + + public String getValue() { + return value; + } +} diff --git a/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/camel/routes/Routes.java b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/camel/routes/Routes.java new file mode 100644 index 000000000..de537c0b9 --- /dev/null +++ b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/camel/routes/Routes.java @@ -0,0 +1,96 @@ +package org.mifos.processor.bulk.camel.routes; + +import static org.mifos.processor.bulk.camel.config.CamelProperties.IS_BATCH_READY; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.BATCH_ID; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.IS_SAMPLE_READY; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.SAMPLED_TX_IDS; + +import com.google.gson.Gson; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import org.json.JSONObject; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +@Component +public class Routes extends BaseRouteBuilder { + + @Value("${config.minimum-successful-tx-ratio}") + double minimumSuccessfulTxRatio; + + @Override + public void configure() throws Exception { + routeCheckTransactions(); + routeSampleTransactions(); + } + + private void routeCheckTransactions() { + String id = "check-transactions"; + from("direct:" + id).id(id).log("Fetching transaction details") + // set request params + .toD(operationsAppConfig.batchTransactionEndpoint).process(exchange -> { + // get response body + JSONObject transfers = new JSONObject(exchange.getIn().getBody(String.class)); + + int totalTransactions = transfers.length(); + int successfulTransactions = 0; + for (Iterator it = transfers.keys(); it.hasNext();) { + String transactionId = it.next(); + String transactionStatus = transfers.getString(transactionId); + if (transactionStatus.equals("COMPLETED")) { + successfulTransactions++; + } + } + + HashMap newVariables = new HashMap<>(); + // check successful transactions >= x% + if (((double) successfulTransactions / totalTransactions) >= minimumSuccessfulTxRatio) { + newVariables.put(IS_SAMPLE_READY, true); + } else { + newVariables.put(IS_SAMPLE_READY, false); + } + + zeebeClient.newSetVariablesCommand(Long.parseLong(exchange.getProperty(BATCH_ID).toString())).variables(newVariables) + .send().join(); + }); + } + + private void routeSampleTransactions() { + String id = "sample-transactions"; + from("direct:" + id).id(id).log("Fetching transaction details").process(exchange -> { + exchange.getIn().setHeader("batchId", exchange.getProperty(BATCH_ID)); + }).toD(operationsAppConfig.batchTransactionEndpoint).process(exchange -> { + // get response body + + // check if batch is ready for sampling + if (exchange.getProperty(IS_BATCH_READY, String.class).equals("false")) { + return; + } + // sample transactions + JSONObject transfers = new JSONObject(exchange.getIn().getBody(String.class)); + final ArrayList successfulTransactionIds = new ArrayList<>(); + final ArrayList sampledTransactionIds = new ArrayList<>(); + for (Iterator it = transfers.keys(); it.hasNext();) { + String transactionId = it.next(); + String transactionStatus = transfers.getString(transactionId); + if (transactionStatus.equals("COMPLETED")) { + successfulTransactionIds.add(transactionId); + } + } + Collections.shuffle(successfulTransactionIds); + int sampleSize = (int) (successfulTransactionIds.size() * 0.9); + for (int i = 0; i < sampleSize; i++) { + sampledTransactionIds.add(successfulTransactionIds.get(i)); + } + HashMap newVariables = new HashMap<>(); + newVariables.put(SAMPLED_TX_IDS, new Gson().toJson(sampledTransactionIds)); + + // store the sampled transaction ids in zeebe variable + zeebeClient.newSetVariablesCommand(Long.parseLong(exchange.getProperty(BATCH_ID).toString())).variables(newVariables).send() + .join(); + + }); + } +} diff --git a/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/camel/routes/SendCallbackRoute.java b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/camel/routes/SendCallbackRoute.java new file mode 100644 index 000000000..177a0a9d5 --- /dev/null +++ b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/camel/routes/SendCallbackRoute.java @@ -0,0 +1,97 @@ +package org.mifos.processor.bulk.camel.routes; + +import static org.mifos.processor.bulk.camel.config.CamelProperties.CALLBACK_RESPONSE_CODE; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.BATCH_ID; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.CALLBACK; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.CALLBACK_RETRY; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.CALLBACK_SUCCESS; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.CLIENT_CORRELATION_ID; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.COMPLETION_RATE; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.ERROR_CODE; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.ERROR_DESCRIPTION; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.MAX_CALLBACK_RETRY; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.PHASES; + +import com.fasterxml.jackson.databind.ObjectMapper; +import java.util.List; +import org.apache.camel.Exchange; +import org.apache.camel.LoggingLevel; +import org.mifos.processor.bulk.schema.BatchCallbackDTO; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +@Component +public class SendCallbackRoute extends BaseRouteBuilder { + + @Value("${callback.url}") + private String callbackUrl; + + @Override + public void configure() throws Exception { + + from("rest:get:test/send/callback").to(RouteId.SEND_CALLBACK.getValue()); + + /** + * Base route for kicking off callback. Performs below tasks. Sends Callback to the set url Checks of response + * code is anything not 2xx then retries + */ + + from(RouteId.SEND_CALLBACK.getValue()).id(RouteId.SEND_CALLBACK.getValue()).log("Starting route " + RouteId.SEND_CALLBACK.name()) + .log("Sending callback for Batch Processing").setHeader(Exchange.HTTP_METHOD, constant("POST")).process(exchange -> { + String message = String.format("The Batch Aggregation API was complete with : %s", + exchange.getProperty(COMPLETION_RATE).toString()); + callbackUrl = exchange.getProperty(CALLBACK, String.class); + logger.info("Callback URL: {}", callbackUrl); + logger.info("Callback Body: {}", message); + String batchId = exchange.getProperty(BATCH_ID, String.class); + String clientCorrelationId = exchange.getProperty(CLIENT_CORRELATION_ID, String.class); + BatchCallbackDTO batchCallbackDTO = new BatchCallbackDTO(clientCorrelationId, batchId, message); + ObjectMapper objectMapper = new ObjectMapper(); + String jsonString = objectMapper.writeValueAsString(batchCallbackDTO); + exchange.getIn().setBody(jsonString); + }).choice().when(exchangeProperty("X-CallbackURL").isNotNull()).setHeader(Exchange.HTTP_METHOD, constant("POST")) + .toD("${exchangeProperty.X-CallbackURL}?bridgeEndpoint=true&throwExceptionOnFailure=false") + .log(LoggingLevel.INFO, "Callback Response body: ${body}").endChoice().otherwise() + .log("Unable to send callback: callback url is null").choice().when(header(Exchange.HTTP_RESPONSE_CODE).regex("^2\\d{2}$")) + .when(exchangeProperty("X-CallbackURL").isNotNull()).log(LoggingLevel.INFO, "Callback sending was successful") + .process(exchange -> { + List phases = exchange.getProperty(PHASES, List.class); + exchange.setProperty(CALLBACK_RESPONSE_CODE, exchange.getIn().getHeader(Exchange.HTTP_RESPONSE_CODE)); + exchange.setProperty(CALLBACK_RETRY, 1); + exchange.setProperty(CALLBACK_SUCCESS, true); + eliminatePhases(exchange); + }).otherwise().log(LoggingLevel.ERROR, "Callback request was unsuccessful").process(exchange -> { + int retry = exchange.getProperty(CALLBACK_RETRY, Integer.class); + int maxRetry = exchange.getProperty(MAX_CALLBACK_RETRY, Integer.class); + if (retry >= maxRetry) { + List phases = exchange.getProperty(PHASES, List.class); + logger.info("Retry Exhausted, setting Callback as Failed"); + eliminatePhases(exchange); + exchange.setProperty(CALLBACK_RESPONSE_CODE, exchange.getIn().getHeader(Exchange.HTTP_RESPONSE_CODE)); + exchange.setProperty(CALLBACK_SUCCESS, false); + exchange.setProperty(ERROR_DESCRIPTION, exchange.getIn().getBody(String.class)); + exchange.setProperty(ERROR_CODE, exchange.getIn().getHeader(Exchange.HTTP_RESPONSE_CODE)); + } else { + retry++; + logger.info("Retry Left {}, Setting Callback as Failed and Retrying...", (maxRetry - retry)); + exchange.setProperty(CALLBACK_RETRY, retry); + + } + exchange.setProperty(CALLBACK_RESPONSE_CODE, exchange.getIn().getHeader(Exchange.HTTP_RESPONSE_CODE)); + exchange.setProperty(CALLBACK_SUCCESS, false); + exchange.setProperty(ERROR_DESCRIPTION, exchange.getIn().getBody(String.class)); + exchange.setProperty(ERROR_CODE, exchange.getIn().getHeader(Exchange.HTTP_RESPONSE_CODE)); + + }); + } + + public void eliminatePhases(Exchange exchange) { + List phases = exchange.getProperty(PHASES, List.class); + int completionRate = exchange.getProperty(COMPLETION_RATE, Integer.class); + + phases.removeIf(phase -> phase <= completionRate); + + exchange.setProperty(PHASES, phases); + } + +} diff --git a/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/camel/routes/SplittingRoute.java b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/camel/routes/SplittingRoute.java new file mode 100644 index 000000000..269d59b77 --- /dev/null +++ b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/camel/routes/SplittingRoute.java @@ -0,0 +1,235 @@ +package org.mifos.processor.bulk.camel.routes; + +import static org.mifos.processor.bulk.camel.config.CamelProperties.LOCAL_FILE_PATH; +import static org.mifos.processor.bulk.camel.config.CamelProperties.OVERRIDE_HEADER; +import static org.mifos.processor.bulk.camel.config.CamelProperties.REGISTERING_INSTITUTE_ID; +import static org.mifos.processor.bulk.camel.config.CamelProperties.RESULT_TRANSACTION_LIST; +import static org.mifos.processor.bulk.camel.config.CamelProperties.SERVER_FILE_NAME; +import static org.mifos.processor.bulk.camel.config.CamelProperties.SERVER_SUB_BATCH_FILE_NAME_ARRAY; +import static org.mifos.processor.bulk.camel.config.CamelProperties.SUB_BATCH_COUNT; +import static org.mifos.processor.bulk.camel.config.CamelProperties.SUB_BATCH_CREATED; +import static org.mifos.processor.bulk.camel.config.CamelProperties.SUB_BATCH_DETAILS; +import static org.mifos.processor.bulk.camel.config.CamelProperties.SUB_BATCH_FILE_ARRAY; +import static org.mifos.processor.bulk.camel.config.CamelProperties.TRANSACTION_LIST; +import static org.mifos.processor.bulk.camel.config.CamelProperties.ZEEBE_VARIABLE; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.BATCH_ID; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.CLIENT_CORRELATION_ID; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.PAYER_IDENTIFIER; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.REQUEST_ID; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.SPLITTING_FAILED; + +import com.fasterxml.jackson.databind.SequenceWriter; +import com.fasterxml.jackson.dataformat.csv.CsvMapper; +import com.fasterxml.jackson.dataformat.csv.CsvSchema; +import java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.UUID; +import java.util.stream.Collectors; +import org.apache.camel.LoggingLevel; +import org.mifos.processor.bulk.schema.SubBatchEntity; +import org.mifos.processor.bulk.schema.Transaction; +import org.mifos.processor.bulk.utility.TransactionParser; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +@Component +public class SplittingRoute extends BaseRouteBuilder { + + @Value("${config.splitting.sub-batch-size}") + private int subBatchSize; + @Autowired + private CsvMapper csvMapper; + @Value("${config.partylookup.enable}") + private boolean isPartyLookupEnabled; + + @Override + public void configure() throws Exception { + + /** + * Base route for starting the splitting process. Refer below routes for more info 1. + * direct:create-sub-batch-file 2. direct:upload-sub-batch-file + */ + from(RouteId.SPLITTING.getValue()).id(RouteId.SPLITTING.getValue()).log("Starting route " + RouteId.SPLITTING.name()) + .to("direct:download-file").to("direct:get-transaction-array").to("direct:create-sub-batch-file").choice() + .when(exchange -> exchange.getProperty(SUB_BATCH_CREATED, Boolean.class)).to("direct:upload-sub-batch-file").otherwise() + .log("No sub batch created, so skipping upload").end().process(exchange -> exchange.setProperty(SPLITTING_FAILED, false)); + + // Creates the sub-batch CSVs + from("direct:create-sub-batch-file").id("direct:create-sub-batch-file").log("Creating sub-batch file").process(exchange -> { + String filepath = exchange.getProperty(LOCAL_FILE_PATH, String.class); + BufferedReader reader = new BufferedReader(new FileReader(filepath)); + String header = reader.readLine() + System.lineSeparator(); + List transactionList = exchange.getProperty(TRANSACTION_LIST, List.class); + List subBatchFile = new ArrayList<>(); + Set distinctPayeeIds = transactionList.stream().map(Transaction::getPayeeDfspId).collect(Collectors.toSet()); + logger.info("Payee id {}", distinctPayeeIds); + logger.info("Number of payeeId {}", distinctPayeeIds.size()); + Boolean isBatchAccountLookupEnabled = (Boolean) exchange.getProperty("batchAccountLookup"); + if (isPartyLookupEnabled && isBatchAccountLookupEnabled) { + // Create a map to store transactions for each payeeid + Map> transactionsByPayeeId = new HashMap<>(); + + // Split the list based on distinct payeeids + Map> subBatchIdMap = new HashMap<>(); + List subBatchIdList = new ArrayList<>(); + Map transactionBatchMap = new HashMap<>(); + for (String payeeId : distinctPayeeIds) { + List transactionsForPayee = transactionList.stream() + .filter(transaction -> payeeId.equals(transaction.getPayeeDfspId())).collect(Collectors.toList()); + + String subBatchId = UUID.randomUUID().toString(); + transactionsByPayeeId.put(payeeId, transactionsForPayee); + + // Assign batch IDs to transactions and store in a map for easy lookup + transactionsForPayee.forEach(transaction -> { + transaction.setBatchId(subBatchId); + transactionBatchMap.put(transaction, subBatchId); + }); + + // Create CSV file for the current payee + String filename = UUID.randomUUID() + "_sub-batch-" + payeeId + ".csv"; + logger.info("Created sub-batch with file name {}", filename); + CsvSchema csvSchema = csvMapper.schemaFor(Transaction.class).withHeader(); + File file = new File(filename); + SequenceWriter writer = csvMapper.writerWithSchemaFor(Transaction.class).with(csvSchema).writeValues(file); + for (Transaction transaction : transactionsForPayee) { + writer.write(transaction); + } + subBatchFile.add(filename); + } + // Set properties + transactionList.forEach(transaction -> transaction.setBatchId(transactionBatchMap.get(transaction))); + exchange.setProperty(RESULT_TRANSACTION_LIST, transactionList); + exchange.setProperty(TRANSACTION_LIST, transactionList); + } else { + List lines = new ArrayList<>(); + String line = null; + while ((line = reader.readLine()) != null) { + lines.add(line); + } + reader.close(); + + if (lines.size() <= subBatchSize) { + exchange.setProperty(SUB_BATCH_CREATED, false); + exchange.setProperty(SERVER_SUB_BATCH_FILE_NAME_ARRAY, new ArrayList()); + logger.info("Skipping creating sub batch, as batch size is less than configured sub-batch size"); + return; + } + + int subBatchCount = 1; + CsvSchema csvSchema = csvMapper.schemaFor(Transaction.class); + csvSchema = csvSchema.withHeader(); + for (int i = 0; i < lines.size(); i += subBatchSize) { + String subBatchId = UUID.randomUUID().toString(); + String filename = UUID.randomUUID() + "_" + "sub-batch-" + subBatchCount + ".csv"; + logger.info("SubBatch Id {}", subBatchId); + + List subBatchTransactions = new ArrayList<>(); + for (int j = i; j < Math.min(i + subBatchSize, lines.size()); j++) { + Transaction transaction = TransactionParser.parseLineToTransaction(lines.get(j)); + assert transaction != null; + transaction.setBatchId(subBatchId); // Set the subBatchId for the transaction + subBatchTransactions.add(transaction); + } + + // Write the list of Transactions to the file + File file = new File(filename); + try (SequenceWriter writer = csvMapper.writer(csvSchema).writeValues(file)) { + writer.writeAll(subBatchTransactions); + } catch (IOException e) { + logger.error("Failed to write sub-batch file: " + filename, e); + } + logger.info("Created sub-batch with file name {}", filename); + subBatchFile.add(filename); // Ensure this list is declared and accessible + subBatchCount++; + } + } + exchange.setProperty(SUB_BATCH_FILE_ARRAY, subBatchFile); + exchange.setProperty(SUB_BATCH_COUNT, subBatchFile.size()); + exchange.setProperty(SUB_BATCH_CREATED, true); + exchange.setProperty(SERVER_SUB_BATCH_FILE_NAME_ARRAY, new ArrayList()); + }).log("updating orignal").setProperty(LOCAL_FILE_PATH, exchangeProperty(SERVER_FILE_NAME)) + .setProperty(OVERRIDE_HEADER, constant(true)) // default header in CSV file will be used + .to("direct:update-file-v2").to("direct:upload-file"); + + // Iterate through each CSVs of sub-batches and uploads in cloud + from("direct:upload-sub-batch-file").id("direct:upload-sub-batch-file").log("Starting upload of sub-batch file") + .loopDoWhile(exchange -> exchange.getProperty(SUB_BATCH_FILE_ARRAY, List.class).size() > 0).process(exchange -> { + List subBatchFile = exchange.getProperty(SUB_BATCH_FILE_ARRAY, List.class); + String localFilePath = subBatchFile.remove(0); + exchange.setProperty(LOCAL_FILE_PATH, localFilePath); + exchange.setProperty(SUB_BATCH_FILE_ARRAY, subBatchFile); + logger.debug("Local file path: {}", localFilePath); + logger.debug("Sub batch file array: {}, ", subBatchFile); + }).log(LoggingLevel.DEBUG, "LOCAL_FILE_PATH: ${exchangeProperty." + LOCAL_FILE_PATH + "}") + .to("direct:generate-sub-batch-entity").log("direct:generate-sub-batch-entity completed").to("direct:upload-file") + .process(exchange -> { + String serverFilename = exchange.getProperty(SERVER_FILE_NAME, String.class); + List serverSubBatchFile = exchange.getProperty(SERVER_SUB_BATCH_FILE_NAME_ARRAY, List.class); + serverSubBatchFile.add(serverFilename); + exchange.setProperty(SERVER_SUB_BATCH_FILE_NAME_ARRAY, serverSubBatchFile); + logger.debug("Server subbatch filename array: {}", serverSubBatchFile); + }); + + // generate subBatchEntityDetails, make sure [LOCAL_FILE_PATH] has the absolute sub batch file path + from("direct:generate-sub-batch-entity").id("direct:generate-sub-batch-entity").log("Generating sub batch entity") + .to("direct:get-transaction-array").process(exchange -> { + List transactionList = exchange.getProperty(TRANSACTION_LIST, List.class); + Map zeebeVariables = exchange.getProperty(ZEEBE_VARIABLE, Map.class); + String serverFileName = exchange.getProperty(LOCAL_FILE_PATH, String.class); + + logger.info("Generating sub batch entity for file {}", serverFileName); + if (transactionList.isEmpty()) { + logger.info("Transaction list is empty"); + return; + } + + Long totalAmount = getTotalAmount(transactionList); + + SubBatchEntity subBatchEntity = getDefaultSubBatchEntity(); + subBatchEntity.setBatchId((String) zeebeVariables.get(BATCH_ID)); + subBatchEntity.setSubBatchId(transactionList.get(0).getBatchId()); + subBatchEntity.setRequestId((String) zeebeVariables.get(REQUEST_ID)); + subBatchEntity.setCorrelationId((String) zeebeVariables.get(CLIENT_CORRELATION_ID)); + subBatchEntity.setPayerFsp((String) zeebeVariables.get(PAYER_IDENTIFIER)); + subBatchEntity.setRegisteringInstitutionId((String) zeebeVariables.get(REGISTERING_INSTITUTE_ID)); + subBatchEntity.setPaymentMode(transactionList.get(0).getPaymentMode()); + subBatchEntity.setRequestFile(serverFileName); + subBatchEntity.setTotalTransactions((long) transactionList.size()); + subBatchEntity.setOngoing((long) transactionList.size()); + subBatchEntity.setTotalAmount(totalAmount); + subBatchEntity.setOngoingAmount(totalAmount); + subBatchEntity.setStartedAt(new Date(System.currentTimeMillis())); + + logger.debug("SubBatchEntity: {}", objectMapper.writeValueAsString(subBatchEntity)); + // update the sub batch details array + List subBatchEntityList = exchange.getProperty(SUB_BATCH_DETAILS, List.class); + subBatchEntityList.add(subBatchEntity); + exchange.setProperty(SUB_BATCH_DETAILS, subBatchEntityList); + logger.debug("generate-sub-batch-entity route end: {}", objectMapper.writeValueAsString(subBatchEntityList)); + }); + } + + private SubBatchEntity getDefaultSubBatchEntity() { + SubBatchEntity subBatchEntity = new SubBatchEntity(); + subBatchEntity.setAllEmptyAmount(); + return subBatchEntity; + } + + private long getTotalAmount(List transactionList) { + long totalAmount = 0L; + for (Transaction transaction : transactionList) { + totalAmount += Long.parseLong(transaction.getAmount()); + } + return totalAmount; + } +} diff --git a/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/config/BudgetAccountConfig.java b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/config/BudgetAccountConfig.java new file mode 100644 index 000000000..8b22c615f --- /dev/null +++ b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/config/BudgetAccountConfig.java @@ -0,0 +1,21 @@ +package org.mifos.processor.bulk.config; + +import java.util.ArrayList; +import java.util.List; +import lombok.Getter; +import lombok.Setter; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +@Getter +@Setter +@Component +@ConfigurationProperties(prefix = "budget-account") +public class BudgetAccountConfig { + + private List registeringInstitutions = new ArrayList<>(); + + public RegisteringInstitutionConfig getByRegisteringInstituteId(String id) { + return getRegisteringInstitutions().stream().filter(p -> p.getId().equals(id)).findFirst().orElse(null); + } +} diff --git a/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/config/ExternalApiPayloadConfig.java b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/config/ExternalApiPayloadConfig.java new file mode 100644 index 000000000..613e98d65 --- /dev/null +++ b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/config/ExternalApiPayloadConfig.java @@ -0,0 +1,45 @@ +package org.mifos.processor.bulk.config; + +import java.util.HashMap; +import java.util.Map; +import java.util.function.Function; +import javax.annotation.PostConstruct; +import lombok.Getter; +import org.apache.camel.Exchange; +import org.mifos.processor.bulk.camel.processor.GsmaApiPayload; +import org.mifos.processor.bulk.camel.processor.MojaloopApiPayload; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Configuration; + +@Configuration +@Getter +public class ExternalApiPayloadConfig { + + private Map> payloadMap = new HashMap<>(); + + @Autowired + GsmaApiPayload gsmaApiPayload; + + @Autowired + MojaloopApiPayload mojaloopApiPayload; + + @Autowired + PaymentModeConfiguration paymentModeConfiguration; + + @PostConstruct + private void registerApiProcessor() { + for (PaymentModeMapping paymentMode : paymentModeConfiguration.getMappings()) { + if (paymentMode.getId().equalsIgnoreCase("gsma")) { + payloadMap.put(paymentMode.getId(), gsmaApiPayload); + } else if (paymentMode.getId().equalsIgnoreCase("mojaloop")) { + payloadMap.put(paymentMode.getId(), mojaloopApiPayload); + } + } + } + + public Function getApiPayloadSetter(String paymentMode) { + PaymentModeMapping mapping = paymentModeConfiguration.getByMode(paymentMode); + return payloadMap.get(mapping.getId()); + } + +} diff --git a/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/config/PaymentModeConfiguration.java b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/config/PaymentModeConfiguration.java new file mode 100644 index 000000000..4597f0310 --- /dev/null +++ b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/config/PaymentModeConfiguration.java @@ -0,0 +1,22 @@ +package org.mifos.processor.bulk.config; + +import java.util.ArrayList; +import java.util.List; +import lombok.Getter; +import lombok.Setter; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Configuration; + +@Configuration +@ConfigurationProperties(prefix = "payment-mode") +@Setter +@Getter +public class PaymentModeConfiguration { + + private List mappings = new ArrayList<>(); + + public PaymentModeMapping getByMode(String paymentMode) { + return getMappings().stream().filter(p -> p.getId().equalsIgnoreCase(paymentMode)).findFirst().orElse(null); + } + +} diff --git a/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/config/PaymentModeMapping.java b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/config/PaymentModeMapping.java new file mode 100644 index 000000000..0d9d46630 --- /dev/null +++ b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/config/PaymentModeMapping.java @@ -0,0 +1,14 @@ +package org.mifos.processor.bulk.config; + +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public class PaymentModeMapping { + + private String id; + private String endpoint; + private String debulkingDfspid; + private PaymentModeType type; +} diff --git a/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/config/PaymentModeType.java b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/config/PaymentModeType.java new file mode 100644 index 000000000..bda7a1712 --- /dev/null +++ b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/config/PaymentModeType.java @@ -0,0 +1,16 @@ +package org.mifos.processor.bulk.config; + +import lombok.Getter; + +@Getter +public enum PaymentModeType { + + PAYMENT("PAYMENT"), BULK("BULK"); + + private String modeType; + + PaymentModeType(String modeType) { + this.modeType = modeType; + } + +} diff --git a/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/config/Program.java b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/config/Program.java new file mode 100644 index 000000000..46bd2e07c --- /dev/null +++ b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/config/Program.java @@ -0,0 +1,19 @@ +package org.mifos.processor.bulk.config; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +public class Program { + + private String id; + private String name; + private String identifierType; + private String identifierValue; + +} diff --git a/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/config/PubSubConfig.java b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/config/PubSubConfig.java new file mode 100644 index 000000000..23d39064c --- /dev/null +++ b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/config/PubSubConfig.java @@ -0,0 +1,18 @@ +package org.mifos.processor.bulk.config; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class PubSubConfig { + + @Value("${pubsub.room.code}") + public String roomCode; + + @Value("${pubsub.room.class}") + public String roomClass; + + @Value("${pubsub.event.type}") + public String eventType; + +} diff --git a/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/config/RegisteringInstitutionConfig.java b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/config/RegisteringInstitutionConfig.java new file mode 100644 index 000000000..cb71a9f71 --- /dev/null +++ b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/config/RegisteringInstitutionConfig.java @@ -0,0 +1,23 @@ +package org.mifos.processor.bulk.config; + +import java.util.ArrayList; +import java.util.List; +import lombok.Getter; +import lombok.Setter; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +@Getter +@Setter +@Component +@ConfigurationProperties(prefix = "budget-account.registering-institutions") +public class RegisteringInstitutionConfig { + + private String id; + private List programs = new ArrayList<>(); + + public Program getByProgramId(String id) { + return getPrograms().stream().filter(p -> p.getId().equals(id)).findFirst().orElse(null); + } + +} diff --git a/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/config/SecurityServerConfig.java b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/config/SecurityServerConfig.java new file mode 100644 index 000000000..fd27c6a1f --- /dev/null +++ b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/config/SecurityServerConfig.java @@ -0,0 +1,32 @@ +package org.mifos.processor.bulk.config; + +import javax.annotation.PostConstruct; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class SecurityServerConfig { + + @Value("${security-server.host}") + public String host; + + @Value("${security-server.baseuri}") + public String baseUri; + + @Value("${security-server.country}") + public String country; + + @Value("${security-server.organisation}") + public String organisation; + + @Value("${security-server.endpoints.subs}") + public String subscribingEndpoint; + + public String subscribingUrl; + + @PostConstruct + public void setup() { + subscribingUrl = host + baseUri + subscribingEndpoint; + subscribingUrl = subscribingUrl.replace("{country}", country).replace("{orgs}", organisation); + } +} diff --git a/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/connectors/api/AccountLookupApi.java b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/connectors/api/AccountLookupApi.java new file mode 100644 index 000000000..70985acb2 --- /dev/null +++ b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/connectors/api/AccountLookupApi.java @@ -0,0 +1,17 @@ +package org.mifos.processor.bulk.connectors.api; + +import java.util.Map; +import org.mifos.connector.common.identityaccountmapper.dto.AccountMapperRequestDTO; +import org.springframework.stereotype.Component; +import retrofit2.Call; +import retrofit2.http.Body; +import retrofit2.http.HeaderMap; +import retrofit2.http.POST; +import retrofit2.http.Url; + +@Component +public interface AccountLookupApi { + + @POST + Call batchAccountLookup(@Url String fullUrl, @Body AccountMapperRequestDTO requestBody, @HeaderMap Map headers); +} diff --git a/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/connectors/service/AccountLookupService.java b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/connectors/service/AccountLookupService.java new file mode 100644 index 000000000..aba71029b --- /dev/null +++ b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/connectors/service/AccountLookupService.java @@ -0,0 +1,44 @@ +package org.mifos.processor.bulk.connectors.service; + +import java.io.IOException; +import java.util.Map; +import org.mifos.connector.common.identityaccountmapper.dto.AccountMapperRequestDTO; +import org.mifos.processor.bulk.connectors.api.AccountLookupApi; +import org.mifos.processor.bulk.utility.Headers; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import retrofit2.Call; +import retrofit2.Retrofit; + +@Service +public class AccountLookupService { + + @Autowired + RetrofitService retrofitService; + + public Logger logger = LoggerFactory.getLogger(this.getClass()); + + public void accountLookupCall(String baseUrl, String fullUrl, AccountMapperRequestDTO requestBody, Map headers) + throws IOException { + Retrofit retrofit = retrofitService.createRetrofit(baseUrl); + + AccountLookupApi accountLookupApi = retrofit.create(AccountLookupApi.class); + + Call call = accountLookupApi.batchAccountLookup(fullUrl, requestBody, Headers.convertHeaders(headers)); + + try { + retrofit2.Response response = call.execute(); + if (response.isSuccessful()) { + Object apiResponse = response.body(); + logger.debug("API response is :: {}", apiResponse); + } else { + logger.error("Error occurred. HTTP status code: {}", response.code()); + } + } catch (IOException e) { + logger.error("Error making Retrofit API call", e); + throw e; + } + } +} diff --git a/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/connectors/service/ProcessorStartRouteService.java b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/connectors/service/ProcessorStartRouteService.java new file mode 100644 index 000000000..b51251596 --- /dev/null +++ b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/connectors/service/ProcessorStartRouteService.java @@ -0,0 +1,282 @@ +package org.mifos.processor.bulk.connectors.service; + +import static org.mifos.processor.bulk.camel.config.CamelProperties.BATCH_REQUEST_TYPE; +import static org.mifos.processor.bulk.camel.config.CamelProperties.CONTENT_TYPE; +import static org.mifos.processor.bulk.camel.config.CamelProperties.HEADER_CLIENT_CORRELATION_ID; +import static org.mifos.processor.bulk.camel.config.CamelProperties.HEADER_PLATFORM_TENANT_ID; +import static org.mifos.processor.bulk.camel.config.CamelProperties.HEADER_PROGRAM_ID; +import static org.mifos.processor.bulk.camel.config.CamelProperties.HEADER_REGISTERING_INSTITUTE_ID; +import static org.mifos.processor.bulk.camel.config.CamelProperties.IS_UPDATED; +import static org.mifos.processor.bulk.camel.config.CamelProperties.PROGRAM_ID; +import static org.mifos.processor.bulk.camel.config.CamelProperties.REGISTERING_INSTITUTE_ID; +import static org.mifos.processor.bulk.camel.config.CamelProperties.RESULT_TRANSACTION_LIST; +import static org.mifos.processor.bulk.camel.config.CamelProperties.TENANT_NAME; +import static org.mifos.processor.bulk.camel.config.CamelProperties.TRANSACTION_LIST; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.BATCH_ID; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.CALLBACK; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.CALLBACK_URL; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.CLIENT_CORRELATION_ID; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.FILE_NAME; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.IS_FILE_VALID; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.NOTE; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.PAYER_IDENTIFIER_TYPE; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.PAYER_IDENTIFIER_VALUE; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.PHASES; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.PHASE_COUNT; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.PROGRAM_NAME; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.PURPOSE; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.REQUEST_ID; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.TENANT_ID; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import io.camunda.zeebe.client.api.command.ClientStatusException; +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; +import org.apache.camel.Exchange; +import org.json.JSONObject; +import org.mifos.processor.bulk.camel.routes.ProcessorStartRoute; +import org.mifos.processor.bulk.config.BudgetAccountConfig; +import org.mifos.processor.bulk.config.Program; +import org.mifos.processor.bulk.config.RegisteringInstitutionConfig; +import org.mifos.processor.bulk.file.FileTransferService; +import org.mifos.processor.bulk.schema.Transaction; +import org.mifos.processor.bulk.utility.PhaseUtils; +import org.mifos.processor.bulk.zeebe.ZeebeProcessStarter; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; +import org.springframework.util.StringUtils; + +@Service +public class ProcessorStartRouteService { + + @Autowired + ProcessorStartRoute processorStartRoute; + @Autowired + @Qualifier("awsStorage") + private FileTransferService fileTransferService; + @Autowired + private ZeebeProcessStarter zeebeProcessStarter; + @Autowired + PhaseUtils phaseUtils; + @Autowired + public ObjectMapper objectMapper; + @Autowired + BudgetAccountConfig budgetAccountConfig; + @Value("${application.bucket-name}") + private String bucketName; + @Value("${csv.size}") + private int csvSize; + @Value("${pollingApi.path}") + private String pollApiPath; + @Value("${pollingApi.timer}") + private String pollApiTimer; + + public Logger logger = LoggerFactory.getLogger(this.getClass()); + + public void validateFileSyncResponse(Exchange exchange) throws IOException { + String fileName = exchange.getIn().getHeader(FILE_NAME, String.class); + File file = new File(fileName); + + // check the file structure + int fileSize = (int) file.length(); + if (fileSize > csvSize) { + processorStartRoute.setErrorResponse(exchange, 400, "File too big", + "The file uploaded is too big. " + "Please upload a file and try again."); + } else if (!processorStartRoute.verifyCsv(file)) { + processorStartRoute.setErrorResponse(exchange, 400, "Invalid file structure", + "The file uploaded contains wrong structure." + " Please upload correct file columns and try again."); + } else { + logger.debug("Filename: {}", fileName); + processorStartRoute.setResponse(exchange, 200); + } + } + + public void validateTenant(Exchange exchange) { + String tenantName = exchange.getIn().getHeader(HEADER_PLATFORM_TENANT_ID, String.class); + // validation is disabled for now + /* + * if (tenantName == null || tenantName.isEmpty() || !tenants.contains(tenantName)) { throw new + * Exception("Invalid tenant value."); } + */ + exchange.setProperty(TENANT_NAME, tenantName); + exchange.getIn().setHeader(CONTENT_TYPE, "application/json;charset=UTF-8"); + } + + public void pollingOutput(Exchange exchange) { + JSONObject json = new JSONObject(); + String pollingPath = String.format("%s%s", pollApiPath, exchange.getProperty(BATCH_ID)); + json.put("PollingPath", pollingPath); + json.put("SuggestedCallbackSeconds", pollApiTimer); + exchange.getIn().setBody(json.toString()); + exchange.getIn().setHeader(Exchange.HTTP_RESPONSE_CODE, 202); + } + + public void executeBatch(Exchange exchange) { + String filename = exchange.getIn().getHeader("filename", String.class); + String requestId = exchange.getIn().getHeader("X-CorrelationID", String.class); + String purpose = exchange.getIn().getHeader("Purpose", String.class); + String type = exchange.getIn().getHeader("Type", String.class); + String clientCorrelationId = exchange.getIn().getHeader(HEADER_CLIENT_CORRELATION_ID, String.class); + String registeringInstitutionId = exchange.getIn().getHeader(HEADER_REGISTERING_INSTITUTE_ID, String.class); + logger.info("registeringInstitutionId {}", registeringInstitutionId); + String programId = exchange.getIn().getHeader(HEADER_PROGRAM_ID, String.class); + String callbackUrl = exchange.getIn().getHeader("X-CallbackURL", String.class); + exchange.setProperty(FILE_NAME, filename); + exchange.setProperty(REQUEST_ID, requestId); + exchange.setProperty(PURPOSE, purpose); + exchange.setProperty(BATCH_REQUEST_TYPE, type); + exchange.setProperty(CLIENT_CORRELATION_ID, clientCorrelationId); + exchange.setProperty(REGISTERING_INSTITUTE_ID, registeringInstitutionId); + exchange.setProperty(PROGRAM_ID, programId); + exchange.setProperty(CALLBACK, callbackUrl); + } + + public void startBatchProcessRaw(Exchange exchange) { + JSONObject response = new JSONObject(); + response.put("batch_id", UUID.randomUUID().toString()); + response.put("request_id", UUID.randomUUID().toString()); + response.put("status", "queued"); + exchange.getIn().setBody(response.toString()); + } + + public void updateIncomingData(Exchange exchange) { + String registeringInstituteId = exchange.getProperty(REGISTERING_INSTITUTE_ID, String.class); + String programId = exchange.getProperty(PROGRAM_ID, String.class); + logger.debug("Inst id: {}, prog id: {}", registeringInstituteId, programId); + if (!(StringUtils.hasText(registeringInstituteId) && StringUtils.hasText(programId))) { + // this will make sure the file is not updated since there is no update in data + logger.debug("InstitutionId or programId is null"); + + exchange.setProperty(IS_UPDATED, false); + return; + } + List transactionList = exchange.getProperty(TRANSACTION_LIST, List.class); + logger.debug("Size: {}", transactionList.size()); + RegisteringInstitutionConfig registeringInstitutionConfig = budgetAccountConfig.getByRegisteringInstituteId(registeringInstituteId); + if (registeringInstitutionConfig == null) { + logger.debug("Element in nested in config: {}", budgetAccountConfig.getRegisteringInstitutions().get(0).getPrograms().size()); + logger.debug("Registering institute id is null"); + + exchange.setProperty(IS_UPDATED, false); + return; + } + Program program = registeringInstitutionConfig.getByProgramId(programId); + if (program == null) { + // this will make sure the file is not updated since there is no update in data + logger.debug("Program is null"); + exchange.setProperty(IS_UPDATED, false); + return; + } + List resultTransactionList = new ArrayList<>(); + + transactionList.forEach(transaction -> { + transaction.setPayerIdentifierType(program.getIdentifierType()); + transaction.setPayerIdentifier(program.getIdentifierValue()); + resultTransactionList.add(transaction); + try { + logger.debug("Txn: {}", objectMapper.writeValueAsString(transaction)); + } catch (JsonProcessingException e) { + throw new RuntimeException(e); + } + }); + exchange.setProperty(RESULT_TRANSACTION_LIST, resultTransactionList); + exchange.setProperty(IS_UPDATED, true); + exchange.setProperty(PROGRAM_NAME, program.getName()); + exchange.setProperty(PAYER_IDENTIFIER_TYPE, program.getIdentifierType()); + exchange.setProperty(PAYER_IDENTIFIER_VALUE, program.getIdentifierValue()); + } + + public void startBatchProcessCsv(Exchange exchange) throws IOException { + String fileName = exchange.getProperty(FILE_NAME, String.class); + String requestId = exchange.getProperty(REQUEST_ID, String.class); + String purpose = exchange.getProperty(PURPOSE, String.class); + String batchId = exchange.getProperty(BATCH_ID, String.class); + String callbackUrl = exchange.getProperty(CALLBACK, String.class); + String note = null; + + if (purpose == null || purpose.isEmpty()) { + purpose = "test payment"; + } + + logger.debug("\n\n Filename: {}", fileName); + logger.debug("\n\n BatchId: {} ", batchId); + + File file = new File(fileName); + file.setWritable(true); + file.setReadable(true); + + logger.debug("File absolute path: {}", file.getAbsolutePath()); + + boolean verifyData = processorStartRoute.verifyData(file); + logger.debug("Data verification result {}", verifyData); + if (!verifyData) { + note = "Invalid data in file data processing stopped"; + } + + String nm = fileTransferService.uploadFile(file, bucketName); + + logger.debug("File uploaded {}", nm); + + // extracting and setting callback Url + exchange.setProperty(CALLBACK_URL, callbackUrl); + + List phases = phaseUtils.getValues(); + logger.debug(phases.toString()); + Map variables = new HashMap<>(); + variables.put(BATCH_ID, batchId); + variables.put(FILE_NAME, fileName); + variables.put(REQUEST_ID, requestId); + variables.put(PURPOSE, purpose); + variables.put(TENANT_ID, exchange.getProperty(TENANT_NAME)); + variables.put(CALLBACK, callbackUrl); + variables.put(PHASES, phases); + variables.put(PHASE_COUNT, phases.size()); + variables.put(NOTE, note); + variables.put(CLIENT_CORRELATION_ID, exchange.getProperty(CLIENT_CORRELATION_ID)); + variables.put(PROGRAM_NAME, exchange.getProperty(PROGRAM_NAME)); + variables.put(PAYER_IDENTIFIER_TYPE, exchange.getProperty(PAYER_IDENTIFIER_TYPE)); + variables.put(PAYER_IDENTIFIER_VALUE, exchange.getProperty(PAYER_IDENTIFIER_VALUE)); + variables.put(REGISTERING_INSTITUTE_ID, exchange.getProperty(REGISTERING_INSTITUTE_ID)); + variables.put(IS_FILE_VALID, true); + processorStartRoute.setConfigProperties(variables); + + logger.debug("Zeebe variables published: {}", variables); + logger.debug("Variables published to zeebe: {}", variables); + + JSONObject response = new JSONObject(); + String bpmn = processorStartRoute.getWorkflowForTenant(exchange.getProperty(TENANT_NAME).toString(), "batch-transactions"); + + try { + String tenantSpecificWorkflowId = bpmn.replace("{dfspid}", exchange.getProperty(TENANT_NAME).toString()); + String txnId = zeebeProcessStarter.startZeebeWorkflow(tenantSpecificWorkflowId, "", variables); + if (txnId == null || txnId.isEmpty()) { + response.put("errorCode", 500); + response.put("errorDescription", "Unable to start zeebe workflow"); + response.put("developerMessage", "Issue in starting the zeebe workflow, check the zeebe configuration"); + } else { + response.put("batch_id", batchId); + response.put("request_id", requestId); + response.put("status", "queued"); + } + } catch (ClientStatusException c) { + logger.error("Got ClientStatusException : {}", c.getMessage()); + throw c; + } catch (Exception e) { + response.put("errorCode", 500); + response.put("errorDescription", "Unable to start zeebe workflow"); + response.put("developerMessage", e.getLocalizedMessage()); + } + + exchange.getIn().setBody(response.toString()); + } +} diff --git a/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/connectors/service/RetrofitService.java b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/connectors/service/RetrofitService.java new file mode 100644 index 000000000..8dc80da5f --- /dev/null +++ b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/connectors/service/RetrofitService.java @@ -0,0 +1,13 @@ +package org.mifos.processor.bulk.connectors.service; + +import org.springframework.stereotype.Component; +import retrofit2.Retrofit; +import retrofit2.converter.gson.GsonConverterFactory; + +@Component +public class RetrofitService { + + public Retrofit createRetrofit(String baseUrl) { + return new Retrofit.Builder().baseUrl(baseUrl).addConverterFactory(GsonConverterFactory.create()).build(); + } +} diff --git a/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/file/AwsFileTransferImpl.java b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/file/AwsFileTransferImpl.java new file mode 100644 index 000000000..ec9dcd56c --- /dev/null +++ b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/file/AwsFileTransferImpl.java @@ -0,0 +1,78 @@ +package org.mifos.processor.bulk.file; + +import com.amazonaws.services.s3.AmazonS3; +import com.amazonaws.services.s3.model.PutObjectRequest; +import com.amazonaws.services.s3.model.S3Object; +import com.amazonaws.services.s3.model.S3ObjectInputStream; +import com.amazonaws.util.IOUtils; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.stereotype.Service; +import org.springframework.web.multipart.MultipartFile; + +@Service +@Qualifier("awsStorage") +public class AwsFileTransferImpl implements FileTransferService { + + private Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Autowired + private AmazonS3 s3Client; + + @Override + public byte[] downloadFile(String fileName, String bucketName) { + S3Object s3Object = s3Client.getObject(bucketName, fileName); + S3ObjectInputStream inputStream = s3Object.getObjectContent(); + try { + byte[] content = IOUtils.toByteArray(inputStream); + return content; + } catch (IOException e) { + logger.debug("{}", e.getMessage()); + } + return null; + } + + @Override + public String uploadFile(MultipartFile file, String bucketName) { + + File fileObj = convertMultiPartFileToFile(file); + return uploadFile(fileObj, bucketName); + } + + @Override + public String uploadFile(File file, String bucketName) { + String fileName = file.getName(); + s3Client.putObject(new PutObjectRequest(bucketName, fileName, file)); + file.delete(); + + return fileName; + } + + @Override + public InputStream streamFile(String fileName, String bucketName) { + S3Object s3Object = s3Client.getObject(bucketName, fileName); + S3ObjectInputStream inputStream = s3Object.getObjectContent(); + return inputStream; + } + + @Override + public void deleteFile(String fileName, String bucketName) { + s3Client.deleteObject(bucketName, fileName); + } + + private File convertMultiPartFileToFile(MultipartFile file) { + File convertedFile = new File(file.getOriginalFilename()); + try (FileOutputStream fos = new FileOutputStream(convertedFile)) { + fos.write(file.getBytes()); + } catch (IOException e) { + logger.error("Error converting multipartFile to file", e); + } + return convertedFile; + } +} diff --git a/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/file/AzureFileTransferImpl.java b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/file/AzureFileTransferImpl.java new file mode 100644 index 000000000..33df0fa3e --- /dev/null +++ b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/file/AzureFileTransferImpl.java @@ -0,0 +1,88 @@ +package org.mifos.processor.bulk.file; + +import com.azure.storage.blob.BlobClientBuilder; +import com.azure.storage.blob.models.BlobProperties; +import com.azure.storage.blob.specialized.BlobInputStream; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.Paths; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.stereotype.Service; +import org.springframework.web.multipart.MultipartFile; + +@Service +@Qualifier("azureStorage") +@ConditionalOnProperty(value = "cloud.azure.enabled", havingValue = "true") +public class AzureFileTransferImpl implements FileTransferService { + + private Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Autowired + BlobClientBuilder client; + + @Override + public byte[] downloadFile(String fileName, String bucketName) { + try { + File temp = new File("/temp/" + fileName); + BlobProperties properties = client.containerName(bucketName).blobName(fileName).buildClient().downloadToFile(temp.getPath()); + byte[] content = Files.readAllBytes(Paths.get(temp.getPath())); + temp.delete(); + return content; + } catch (Exception e) { + logger.debug("{}", e.getMessage()); + } + return null; + } + + @Override + public String uploadFile(MultipartFile file, String bucketName) { + + try { + String fileName = System.currentTimeMillis() + "_" + file.getOriginalFilename(); + client.containerName(bucketName).blobName(fileName).buildClient().upload(file.getInputStream(), file.getSize()); + return fileName; + } catch (IOException e) { + logger.error("Error uploading file to Azure", e); + } + + return null; + } + + @Override + public String uploadFile(File file, String bucketName) { + try { + String fileName = System.currentTimeMillis() + "_" + file.getName(); + client.containerName(bucketName).blobName(fileName).buildClient().upload(Files.newInputStream(file.toPath()), file.length()); + return fileName; + } catch (IOException e) { + logger.error("Error uploading file to Azure", e); + } + return null; + } + + @Override + public InputStream streamFile(String fileName, String bucketName) { + try { + File temp = new File("/temp/" + fileName); + BlobInputStream csvInputStream = client.containerName(bucketName).blobName(fileName).buildClient().openInputStream(); + // byte[] content = Files.Paths.get(temp.getPath())); + // temp.delete(); + return csvInputStream; + } catch (Exception e) { + logger.debug(e.getMessage()); + } + return null; + } + + @Override + public void deleteFile(String fileName, String bucketName) { + client.containerName(bucketName).blobName(fileName).buildClient().delete(); + } + +} diff --git a/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/file/FileStorageService.java b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/file/FileStorageService.java new file mode 100644 index 000000000..01682f1f2 --- /dev/null +++ b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/file/FileStorageService.java @@ -0,0 +1,16 @@ +package org.mifos.processor.bulk.file; + +import java.io.InputStream; +import org.springframework.stereotype.Service; +import org.springframework.web.multipart.MultipartFile; + +@Service +public interface FileStorageService { + + String save(MultipartFile file); + + String save(InputStream file, String filename); + + String save(String data, String filename); + +} diff --git a/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/file/FileStorageServiceImpl.java b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/file/FileStorageServiceImpl.java new file mode 100644 index 000000000..2196cf214 --- /dev/null +++ b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/file/FileStorageServiceImpl.java @@ -0,0 +1,54 @@ +package org.mifos.processor.bulk.file; + +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Objects; +import java.util.UUID; +import org.springframework.stereotype.Service; +import org.springframework.web.multipart.MultipartFile; + +@Service +public class FileStorageServiceImpl implements FileStorageService { + + private final Path root = Paths.get(""); + + @Override + public String save(MultipartFile file) { + String filename = UUID.randomUUID() + "_" + Objects.requireNonNull(file.getOriginalFilename()); + try { + Files.copy(file.getInputStream(), this.root.resolve(filename)); + } catch (Exception e) { + throw new RuntimeException("Failed to save file: " + e.getMessage(), e); + } + return filename; + } + + @Override + public String save(InputStream inputStream, String filename) { + String uniqueFileName = getUniqueFileName(filename); + try { + Files.copy(inputStream, this.root.resolve(uniqueFileName)); + } catch (Exception e) { + throw new RuntimeException("Failed to save file: " + e.getMessage(), e); + } + return uniqueFileName; + } + + @Override + public String save(String data, String filename) { + String uniqueFileName = getUniqueFileName(filename); + try { + Files.writeString(this.root.resolve(uniqueFileName), data); + } catch (IOException e) { + throw new RuntimeException(e); + } + return uniqueFileName; + } + + private String getUniqueFileName(String filename) { + return UUID.randomUUID() + "_" + Objects.requireNonNull(filename); + } +} diff --git a/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/file/FileTransferService.java b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/file/FileTransferService.java new file mode 100644 index 000000000..f7e9f3eec --- /dev/null +++ b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/file/FileTransferService.java @@ -0,0 +1,21 @@ +package org.mifos.processor.bulk.file; + +import java.io.File; +import java.io.InputStream; +import org.springframework.stereotype.Service; +import org.springframework.web.multipart.MultipartFile; + +@Service +public interface FileTransferService { + + byte[] downloadFile(String fileName, String bucketName); + + String uploadFile(MultipartFile file, String bucketName); + + String uploadFile(File file, String bucketName); + + InputStream streamFile(String fileName, String bucketName); + + void deleteFile(String fileName, String bucketName); + +} diff --git a/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/file/config/AwsStorageConfig.java b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/file/config/AwsStorageConfig.java new file mode 100644 index 000000000..25b1ebe2a --- /dev/null +++ b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/file/config/AwsStorageConfig.java @@ -0,0 +1,38 @@ +package org.mifos.processor.bulk.file.config; + +import com.amazonaws.auth.AWSCredentials; +import com.amazonaws.auth.AWSStaticCredentialsProvider; +import com.amazonaws.auth.BasicAWSCredentials; +import com.amazonaws.client.builder.AwsClientBuilder; +import com.amazonaws.services.s3.AmazonS3; +import com.amazonaws.services.s3.AmazonS3ClientBuilder; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class AwsStorageConfig { + + @Value("${cloud.aws.credentials.access-key}") + private String accessKey; + + @Value("${cloud.aws.credentials.secret-key}") + private String accessSecret; + + @Value("${cloud.aws.region.static}") + private String region; + @Value("${cloud.aws.s3BaseUrl}") + private String endpoint; + + @Bean + @ConditionalOnProperty(value = "cloud.aws.enabled", havingValue = "true") + public AmazonS3 s3Client() { + AWSCredentials credentials = new BasicAWSCredentials(accessKey, accessSecret); + return AmazonS3ClientBuilder.standard().withCredentials(new AWSStaticCredentialsProvider(credentials)) + .withPathStyleAccessEnabled(true).withEndpointConfiguration(new AwsClientBuilder.EndpointConfiguration(endpoint, region)) + .build(); + + } + +} diff --git a/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/file/config/AzureStorageConfig.java b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/file/config/AzureStorageConfig.java new file mode 100644 index 000000000..f7ffa9989 --- /dev/null +++ b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/file/config/AzureStorageConfig.java @@ -0,0 +1,23 @@ +package org.mifos.processor.bulk.file.config; + +import com.azure.storage.blob.BlobClientBuilder; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class AzureStorageConfig { + + @Value("${cloud.azure.blob.connection-string}") + String connectionString; + + @Bean + @ConditionalOnProperty(value = "cloud.azure.enabled", havingValue = "true") + public BlobClientBuilder getClient() { + BlobClientBuilder client = new BlobClientBuilder(); + client.connectionString(connectionString); + return client; + } + +} diff --git a/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/format/EntityMapper.java b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/format/EntityMapper.java new file mode 100644 index 000000000..61eb1dc6d --- /dev/null +++ b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/format/EntityMapper.java @@ -0,0 +1,14 @@ +package org.mifos.processor.bulk.format; + +import java.util.List; + +public interface EntityMapper { + + T convertTo(K object); + + K convertFrom(T object); + + List convertListTo(List objects); + + List convertListFrom(List objects); +} diff --git a/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/format/RestRequestConvertor.java b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/format/RestRequestConvertor.java new file mode 100644 index 000000000..8186bafeb --- /dev/null +++ b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/format/RestRequestConvertor.java @@ -0,0 +1,80 @@ +package org.mifos.processor.bulk.format; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; +import org.mifos.processor.bulk.schema.BatchRequestDTO; +import org.mifos.processor.bulk.schema.Party; +import org.mifos.processor.bulk.schema.PartyType; +import org.mifos.processor.bulk.schema.Transaction; +import org.springframework.stereotype.Component; + +@Component +public class RestRequestConvertor implements EntityMapper { + + @Override + public BatchRequestDTO convertTo(Transaction object) { + Party creditParty = new Party(); + creditParty.setKey(PartyType.fromValue(object.getPayeeIdentifierType()).getValue()); + creditParty.setValue(object.getPayeeIdentifier()); + + Party debitParty = new Party(); + debitParty.setKey(PartyType.fromValue(object.getPayerIdentifierType()).getValue()); + debitParty.setValue(object.getPayerIdentifier()); + + // creating the DTO + BatchRequestDTO batchRequestDTO = new BatchRequestDTO(); + batchRequestDTO.setAmount(object.getAmount()); + batchRequestDTO.setCurrency(object.getCurrency()); + batchRequestDTO.setCreditParty(List.of(creditParty)); + batchRequestDTO.setDebitParty(List.of(debitParty)); + batchRequestDTO.setDescriptionText(object.getNote()); + batchRequestDTO.setPaymentMode(object.getPaymentMode()); + batchRequestDTO.setRequestId(object.getRequestId()); + + return batchRequestDTO; + } + + @Override + public Transaction convertFrom(BatchRequestDTO object) { + + // creating the transaction + Transaction transaction = new Transaction(); + transaction.setCurrency(object.getCurrency()); + transaction.setAmount(object.getAmount()); + if (object.getDebitParty() != null && object.getDebitParty().size() > 0) { + transaction.setPayerIdentifierType(object.getDebitParty().get(0).getKey()); + transaction.setPayerIdentifier(object.getDebitParty().get(0).getValue()); + } + if (object.getCreditParty() != null && object.getCreditParty().size() > 0) { + transaction.setPayeeIdentifierType(object.getCreditParty().get(0).getKey()); + transaction.setPayeeIdentifier(object.getCreditParty().get(0).getValue()); + } + transaction.setNote(object.getDescriptionText()); + transaction.setPaymentMode(object.getPaymentMode()); + transaction.setRequestId(object.getRequestId()); + return transaction; + } + + @Override + public List convertListTo(List objects) { + List batchRequestDTOList = new ArrayList<>(); + objects.forEach(e -> batchRequestDTOList.add(convertTo(e))); + return batchRequestDTOList; + } + + @Override + public List convertListFrom(List objects) { + List transactionList = new ArrayList<>(); + for (int i = 0; i < objects.size(); i++) { + Transaction transaction = convertFrom(objects.get(i)); + transaction.setId(i); + if (transaction.getRequestId() == null) { + transaction.setRequestId(UUID.randomUUID().toString()); + } + transactionList.add(transaction); + } + return transactionList; + } + +} diff --git a/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/format/Standard.java b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/format/Standard.java new file mode 100644 index 000000000..394670fad --- /dev/null +++ b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/format/Standard.java @@ -0,0 +1,17 @@ +package org.mifos.processor.bulk.format; + +public enum Standard { + + GSMA(StandardValue.GSMA), DEFAULT(StandardValue.DEFAULT); + + private final String value; + + Standard(String s) { + value = s; + } + + public String getValue() { + return value; + } + +} diff --git a/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/format/StandardValue.java b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/format/StandardValue.java new file mode 100644 index 000000000..d00371573 --- /dev/null +++ b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/format/StandardValue.java @@ -0,0 +1,10 @@ +package org.mifos.processor.bulk.format; + +public final class StandardValue { + + private StandardValue() {} + + public static final String GSMA = "GSMA"; + + public static final String DEFAULT = "DEFAULT"; +} diff --git a/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/format/helper/BaseMapper.java b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/format/helper/BaseMapper.java new file mode 100644 index 000000000..bae652907 --- /dev/null +++ b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/format/helper/BaseMapper.java @@ -0,0 +1,17 @@ +package org.mifos.processor.bulk.format.helper; + +import java.util.ArrayList; +import java.util.List; +import org.mifos.processor.bulk.schema.CsvSchema; + +public abstract class BaseMapper implements Mapper { + + @Override + public List convertList(List objects) { + List list = new ArrayList<>(); + objects.forEach(transaction -> { + list.add(convert(transaction)); + }); + return list; + } +} diff --git a/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/format/helper/GSMAMapper.java b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/format/helper/GSMAMapper.java new file mode 100644 index 000000000..3cb4f4274 --- /dev/null +++ b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/format/helper/GSMAMapper.java @@ -0,0 +1,21 @@ +package org.mifos.processor.bulk.format.helper; + +import org.mifos.processor.bulk.schema.GSMATransaction; +import org.mifos.processor.bulk.schema.Transaction; +import org.springframework.stereotype.Component; + +@Component +public class GSMAMapper extends BaseMapper { + + @Override + public GSMATransaction convert(Transaction object) { + GSMATransaction gsmaTransaction = new GSMATransaction(); + gsmaTransaction.setId(object.getId()); + gsmaTransaction.setRequestId("test"); + gsmaTransaction.setPaymentMode(object.getPaymentMode()); + gsmaTransaction.setAccountNumber(object.getAccountNumber()); + gsmaTransaction.setAmount(object.getAmount()); + gsmaTransaction.setNote(object.getNote()); + return gsmaTransaction; + } +} diff --git a/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/format/helper/Mapper.java b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/format/helper/Mapper.java new file mode 100644 index 000000000..e6743117d --- /dev/null +++ b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/format/helper/Mapper.java @@ -0,0 +1,26 @@ +package org.mifos.processor.bulk.format.helper; + +import java.util.List; +import org.mifos.processor.bulk.schema.CsvSchema; + +public interface Mapper { + + /** + * Use for converting the object of type [FROM] to an object of type [TO] + * + * @param object + * of type [FROM] + * @return object of type [To] + */ + TO convert(FROM object); + + /** + * Use for converting the list of objects of type [FROM] to an object of type [TO] + * + * @param objects + * lost of object of type [FROM] + * @return objects of type [To] + */ + List convertList(List objects); + +} diff --git a/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/format/helper/Mappers.java b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/format/helper/Mappers.java new file mode 100644 index 000000000..351157ff3 --- /dev/null +++ b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/format/helper/Mappers.java @@ -0,0 +1,12 @@ +package org.mifos.processor.bulk.format.helper; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component +public class Mappers { + + @Autowired + public GSMAMapper gsmaMapper; + +} diff --git a/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/kafka/Consumers.java b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/kafka/Consumers.java new file mode 100644 index 000000000..03769b77f --- /dev/null +++ b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/kafka/Consumers.java @@ -0,0 +1,116 @@ +package org.mifos.processor.bulk.kafka; + +import static org.mifos.connector.common.mojaloop.type.InitiatorType.CONSUMER; +import static org.mifos.connector.common.mojaloop.type.Scenario.TRANSFER; +import static org.mifos.connector.common.mojaloop.type.TransactionRole.PAYER; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.BATCH_ID; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.GSMA_CHANNEL_REQUEST; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.INITIATOR_FSPID; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.IS_RTP_REQUEST; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.PARTY_ID; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.PARTY_ID_TYPE; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.PARTY_LOOKUP_FSPID; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.TENANT_ID; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.TRANSACTION_TYPE; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import java.util.HashMap; +import java.util.Map; +import lombok.extern.slf4j.Slf4j; +import org.mifos.connector.common.channel.dto.TransactionChannelRequestDTO; +import org.mifos.connector.common.gsma.dto.GSMATransaction; +import org.mifos.connector.common.gsma.dto.GsmaParty; +import org.mifos.connector.common.mojaloop.dto.MoneyData; +import org.mifos.connector.common.mojaloop.dto.Party; +import org.mifos.connector.common.mojaloop.dto.PartyIdInfo; +import org.mifos.connector.common.mojaloop.dto.TransactionType; +import org.mifos.connector.common.mojaloop.type.IdentifierType; +import org.mifos.processor.bulk.schema.TransactionOlder; +import org.mifos.processor.bulk.zeebe.ZeebeProcessStarter; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.kafka.annotation.KafkaListener; +import org.springframework.stereotype.Service; + +@Service +@Slf4j +public class Consumers { + + @Value("${bpmn.flows.international-remittance-payer}") + private String internationalRemittancePayer; + + @Autowired + private ObjectMapper objectMapper; + + @Autowired + private ZeebeProcessStarter zeebeProcessStarter; + + @KafkaListener(topics = "${kafka.topic.gsma.name}", groupId = "group_id") + public void listenTopicGsma(String message) throws JsonProcessingException { + log.debug("Received Message in topic GSMA and group group_id: {}", message); + TransactionOlder transaction = objectMapper.readValue(message, TransactionOlder.class); + String tenantId = "ibank-usa"; + + GSMATransaction gsmaChannelRequest = new GSMATransaction(); + gsmaChannelRequest.setAmount(transaction.getAmount()); + gsmaChannelRequest.setCurrency(transaction.getCurrency()); + gsmaChannelRequest.setRequestingLei("ibank-usa"); + gsmaChannelRequest.setReceivingLei("ibank-india"); + GsmaParty creditParty = new GsmaParty(); + creditParty.setKey("msisdn"); + creditParty.setValue(transaction.getAccountNumber()); + GsmaParty debitParty = new GsmaParty(); + debitParty.setKey("msisdn"); + debitParty.setValue(transaction.getAccountNumber()); + gsmaChannelRequest.setCreditParty(new GsmaParty[] { creditParty }); + gsmaChannelRequest.setDebitParty(new GsmaParty[] { debitParty }); + // gsmaChannelRequest.setInternationalTransferInformation().setReceivingAmount(gsmaChannelRequest.getAmount()); + + TransactionChannelRequestDTO channelRequest = new TransactionChannelRequestDTO(); // Fineract Object + Party payee = new Party(new PartyIdInfo(IdentifierType.MSISDN, transaction.getAccountNumber())); + Party payer = new Party(new PartyIdInfo(IdentifierType.MSISDN, "7543010")); + + MoneyData moneyData = new MoneyData(); + moneyData.setAmount(transaction.getAmount()); + moneyData.setCurrency(transaction.getCurrency()); + + channelRequest.setPayer(payer); + channelRequest.setPayee(payee); + channelRequest.setAmount(moneyData); + + TransactionType transactionType = new TransactionType(); + transactionType.setInitiator(PAYER); + transactionType.setInitiatorType(CONSUMER); + transactionType.setScenario(TRANSFER); + + Map extraVariables = new HashMap<>(); + extraVariables.put(IS_RTP_REQUEST, false); + extraVariables.put(TRANSACTION_TYPE, "inttransfer"); + extraVariables.put(TENANT_ID, tenantId); + + extraVariables.put(BATCH_ID, transaction.getBatchId()); + + String tenantSpecificBpmn = internationalRemittancePayer.replace("{dfspid}", tenantId); + channelRequest.setTransactionType(transactionType); + + PartyIdInfo requestedParty = (boolean) extraVariables.get(IS_RTP_REQUEST) ? channelRequest.getPayer().getPartyIdInfo() + : channelRequest.getPayee().getPartyIdInfo(); + extraVariables.put(PARTY_ID_TYPE, requestedParty.getPartyIdType()); + extraVariables.put(PARTY_ID, requestedParty.getPartyIdentifier()); + + extraVariables.put(GSMA_CHANNEL_REQUEST, objectMapper.writeValueAsString(gsmaChannelRequest)); + extraVariables.put(PARTY_LOOKUP_FSPID, gsmaChannelRequest.getReceivingLei()); + extraVariables.put(INITIATOR_FSPID, gsmaChannelRequest.getRequestingLei()); + + String transactionId = zeebeProcessStarter.startZeebeWorkflow(tenantSpecificBpmn, objectMapper.writeValueAsString(channelRequest), + extraVariables); + + log.debug("GSMA Transaction Started with:{} ", transactionId); + } + + @KafkaListener(topics = "${kafka.topic.slcb.name}", groupId = "group_id") + public void listenTopicSlcb(String message) { + log.debug("Received Message in topic SLCB and group group_id:{} ", message); + } +} diff --git a/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/kafka/config/KafkaConsumerConfig.java b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/kafka/config/KafkaConsumerConfig.java new file mode 100644 index 000000000..e9694b897 --- /dev/null +++ b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/kafka/config/KafkaConsumerConfig.java @@ -0,0 +1,39 @@ +package org.mifos.processor.bulk.kafka.config; + +import java.util.HashMap; +import java.util.Map; +import org.apache.kafka.clients.consumer.ConsumerConfig; +import org.apache.kafka.common.serialization.StringDeserializer; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.kafka.annotation.EnableKafka; +import org.springframework.kafka.config.ConcurrentKafkaListenerContainerFactory; +import org.springframework.kafka.core.ConsumerFactory; +import org.springframework.kafka.core.DefaultKafkaConsumerFactory; + +@EnableKafka +@Configuration +public class KafkaConsumerConfig { + + @Value(value = "${kafka.bootstrapAddress}") + private String bootstrapAddress; + + @Bean + public ConsumerFactory consumerFactory() { + Map props = new HashMap<>(); + props.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapAddress); + props.put(ConsumerConfig.GROUP_ID_CONFIG, "group_id"); + props.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class); + props.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class); + return new DefaultKafkaConsumerFactory<>(props); + } + + @Bean + public ConcurrentKafkaListenerContainerFactory kafkaListenerContainerFactory() { + ConcurrentKafkaListenerContainerFactory factory = new ConcurrentKafkaListenerContainerFactory<>(); + factory.setConsumerFactory(consumerFactory()); + return factory; + } + +} diff --git a/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/kafka/config/KafkaProducerConfig.java b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/kafka/config/KafkaProducerConfig.java new file mode 100644 index 000000000..11b9aa2a1 --- /dev/null +++ b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/kafka/config/KafkaProducerConfig.java @@ -0,0 +1,34 @@ +package org.mifos.processor.bulk.kafka.config; + +import java.util.HashMap; +import java.util.Map; +import org.apache.kafka.clients.producer.ProducerConfig; +import org.apache.kafka.common.serialization.StringSerializer; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.kafka.core.DefaultKafkaProducerFactory; +import org.springframework.kafka.core.KafkaTemplate; +import org.springframework.kafka.core.ProducerFactory; + +@Configuration +public class KafkaProducerConfig { + + @Value(value = "${kafka.bootstrapAddress}") + private String bootstrapAddress; + + @Bean + public ProducerFactory producerFactory() { + Map configProps = new HashMap<>(); + configProps.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapAddress); + configProps.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class); + configProps.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, StringSerializer.class); + return new DefaultKafkaProducerFactory<>(configProps); + } + + @Bean + public KafkaTemplate kafkaTemplate() { + return new KafkaTemplate<>(producerFactory()); + } + +} diff --git a/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/kafka/config/KafkaTopicConfig.java b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/kafka/config/KafkaTopicConfig.java new file mode 100644 index 000000000..7d2f2ff78 --- /dev/null +++ b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/kafka/config/KafkaTopicConfig.java @@ -0,0 +1,40 @@ +package org.mifos.processor.bulk.kafka.config; + +import java.util.HashMap; +import java.util.Map; +import org.apache.kafka.clients.admin.AdminClientConfig; +import org.apache.kafka.clients.admin.NewTopic; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.kafka.core.KafkaAdmin; + +@Configuration +public class KafkaTopicConfig { + + @Value(value = "${kafka.bootstrapAddress}") + private String bootstrapAddress; + + @Value(value = "${kafka.topic.gsma.name}") + private String gsmaTopicName; + + @Value(value = "${kafka.topic.slcb.name}") + private String slcbTopicName; + + @Bean + public KafkaAdmin kafkaAdmin() { + Map configs = new HashMap<>(); + configs.put(AdminClientConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapAddress); + return new KafkaAdmin(configs); + } + + @Bean + public NewTopic gsmaTopic() { + return new NewTopic(gsmaTopicName, 1, (short) 1); + } + + @Bean + public NewTopic slcbTopic() { + return new NewTopic(slcbTopicName, 1, (short) 1); + } +} diff --git a/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/properties/TenantImplementation.java b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/properties/TenantImplementation.java new file mode 100644 index 000000000..4d8083549 --- /dev/null +++ b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/properties/TenantImplementation.java @@ -0,0 +1,26 @@ +package org.mifos.processor.bulk.properties; + +import java.util.HashMap; + +public class TenantImplementation { + + String id; + HashMap flows; + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public HashMap getFlows() { + return flows; + } + + public void setFlows(HashMap flows) { + this.flows = flows; + } + +} diff --git a/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/properties/TenantImplementationProperties.java b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/properties/TenantImplementationProperties.java new file mode 100644 index 000000000..4c1a2fd3a --- /dev/null +++ b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/properties/TenantImplementationProperties.java @@ -0,0 +1,21 @@ +package org.mifos.processor.bulk.properties; + +import java.util.List; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +@Component +@ConfigurationProperties(prefix = "bpmns") +public class TenantImplementationProperties { + + List tenants; + + public List getTenants() { + return tenants; + } + + public void setTenants(List tenants) { + this.tenants = tenants; + } + +} diff --git a/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/schema/AccountLookupResponseDTO.java b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/schema/AccountLookupResponseDTO.java new file mode 100644 index 000000000..e511edf18 --- /dev/null +++ b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/schema/AccountLookupResponseDTO.java @@ -0,0 +1,21 @@ +package org.mifos.processor.bulk.schema; + +import java.io.Serializable; +import java.util.List; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +public class AccountLookupResponseDTO implements Serializable { + + private String requestId; + private String payeeIdentity; + private List paymentModalityList; + private Boolean isValidated; + +} diff --git a/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/schema/AuthorizationRequest.java b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/schema/AuthorizationRequest.java new file mode 100644 index 000000000..5f479dc14 --- /dev/null +++ b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/schema/AuthorizationRequest.java @@ -0,0 +1,21 @@ +package org.mifos.processor.bulk.schema; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +public class AuthorizationRequest { + + private String batchId; + + private String payerIdentifier; + + private String currency; + + private String amount; +} diff --git a/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/schema/AuthorizationResponse.java b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/schema/AuthorizationResponse.java new file mode 100644 index 000000000..809f9d049 --- /dev/null +++ b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/schema/AuthorizationResponse.java @@ -0,0 +1,19 @@ +package org.mifos.processor.bulk.schema; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +public class AuthorizationResponse { + + private String clientCorrelationId; + + private String status; + + private String reason; +} diff --git a/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/schema/BatchAccountLookupResponseDTO.java b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/schema/BatchAccountLookupResponseDTO.java new file mode 100644 index 000000000..939fda60e --- /dev/null +++ b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/schema/BatchAccountLookupResponseDTO.java @@ -0,0 +1,18 @@ +package org.mifos.processor.bulk.schema; + +import java.util.List; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +public class BatchAccountLookupResponseDTO { + + private String requestId; + private String registeringInstitutionId; + private List beneficiaryDTOList; +} diff --git a/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/schema/BatchCallbackDTO.java b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/schema/BatchCallbackDTO.java new file mode 100644 index 000000000..735890ddc --- /dev/null +++ b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/schema/BatchCallbackDTO.java @@ -0,0 +1,17 @@ +package org.mifos.processor.bulk.schema; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +public class BatchCallbackDTO { + + String clientCorrelationId; + String batchId; + String message; +} diff --git a/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/schema/BatchDTO.java b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/schema/BatchDTO.java new file mode 100644 index 000000000..4212c75cf --- /dev/null +++ b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/schema/BatchDTO.java @@ -0,0 +1,57 @@ +package org.mifos.processor.bulk.schema; + +import java.math.BigDecimal; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +public class BatchDTO { + + private String batchId; + + private String requestId; + + private Long total; + + private Long ongoing; + + private Long failed; + + private Long successful; + + private BigDecimal totalAmount; + + private BigDecimal successfulAmount; + + private BigDecimal pendingAmount; + + private BigDecimal failedAmount; + + private String file; + + private String notes; + + private String createdAt; + + private String status; + + private String modes; + + private String purpose; + + private String failPercentage; + + private String successPercentage; + + private String registeringInstitutionId; + + private String payerFsp; + + private String correlationId; + +} diff --git a/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/schema/BatchRequestDTO.java b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/schema/BatchRequestDTO.java new file mode 100644 index 000000000..3ccce3f52 --- /dev/null +++ b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/schema/BatchRequestDTO.java @@ -0,0 +1,24 @@ +package org.mifos.processor.bulk.schema; + +import java.util.List; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +public class BatchRequestDTO { + + String requestId; + List creditParty; + List debitParty; + + String paymentMode; + String amount; + String currency; + String descriptionText; + +} diff --git a/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/schema/BeneficiaryDTO.java b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/schema/BeneficiaryDTO.java new file mode 100644 index 000000000..b82db5232 --- /dev/null +++ b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/schema/BeneficiaryDTO.java @@ -0,0 +1,19 @@ +package org.mifos.processor.bulk.schema; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +public class BeneficiaryDTO { + + private String payeeIdentity; + private String paymentModality; + private String financialAddress; + private String bankingInstitutionCode; + +} diff --git a/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/schema/CamelApiResponse.java b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/schema/CamelApiResponse.java new file mode 100644 index 000000000..4fe289525 --- /dev/null +++ b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/schema/CamelApiResponse.java @@ -0,0 +1,14 @@ +package org.mifos.processor.bulk.schema; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +@AllArgsConstructor +public class CamelApiResponse { + + String body; + int status; +} diff --git a/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/schema/CsvSchema.java b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/schema/CsvSchema.java new file mode 100644 index 000000000..95531f8af --- /dev/null +++ b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/schema/CsvSchema.java @@ -0,0 +1,9 @@ +package org.mifos.processor.bulk.schema; + +public interface CsvSchema { + + String getCsvString(); + + String getCsvHeader(); + +} diff --git a/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/schema/ExceptionMapperDTO.java b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/schema/ExceptionMapperDTO.java new file mode 100644 index 000000000..8b0ad44f2 --- /dev/null +++ b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/schema/ExceptionMapperDTO.java @@ -0,0 +1,18 @@ +package org.mifos.processor.bulk.schema; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import lombok.ToString; + +@Getter +@Setter +@ToString +@NoArgsConstructor +@AllArgsConstructor +public class ExceptionMapperDTO { + + private String responseCode; + private String responseDescription; +} diff --git a/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/schema/GSMATransaction.java b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/schema/GSMATransaction.java new file mode 100644 index 000000000..4d6af3ea0 --- /dev/null +++ b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/schema/GSMATransaction.java @@ -0,0 +1,73 @@ +package org.mifos.processor.bulk.schema; + +import com.fasterxml.jackson.annotation.JsonPropertyOrder; + +@JsonPropertyOrder({ "id", "requestId", "paymentMode", "accountNumber", "amount", "note" }) +public class GSMATransaction implements CsvSchema { + + private int id; + private String requestId; + private String paymentMode; + private String accountNumber; + private String amount; + + private String note; + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getAmount() { + return amount; + } + + public void setAmount(String amount) { + this.amount = amount; + } + + public String getNote() { + return note; + } + + public void setNote(String note) { + this.note = note; + } + + public String getRequestId() { + return requestId; + } + + public void setRequestId(String requestId) { + this.requestId = requestId; + } + + public String getPaymentMode() { + return paymentMode; + } + + public void setPaymentMode(String paymentMode) { + this.paymentMode = paymentMode; + } + + public String getAccountNumber() { + return accountNumber; + } + + public void setAccountNumber(String accountNumber) { + this.accountNumber = accountNumber; + } + + @Override + public String getCsvString() { + return String.format("%s,%s,%s,%s,%s,%s", id, requestId, paymentMode, accountNumber, amount, note); + } + + @Override + public String getCsvHeader() { + return "id,requestId,paymentMode,accountNumber,amount,note"; + } +} diff --git a/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/schema/Party.java b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/schema/Party.java new file mode 100644 index 000000000..a795fc78e --- /dev/null +++ b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/schema/Party.java @@ -0,0 +1,17 @@ +package org.mifos.processor.bulk.schema; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +public class Party { + + String key; + String value; + +} diff --git a/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/schema/PartyType.java b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/schema/PartyType.java new file mode 100644 index 000000000..36fbe0606 --- /dev/null +++ b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/schema/PartyType.java @@ -0,0 +1,26 @@ +package org.mifos.processor.bulk.schema; + +import java.util.Arrays; + +public enum PartyType { + + MSISDN("msisdn"), ACCOUNT_NUMBER("accountnumber"), EMPTY(""); + + private String value; + + PartyType(String value) { + this.value = value; + } + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } + + public static PartyType fromValue(String value) { + return Arrays.stream(values()).filter(ec -> ec.getValue().equalsIgnoreCase(value)).findFirst().orElseGet(() -> PartyType.EMPTY); + } +} diff --git a/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/schema/PaymentModalityDTO.java b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/schema/PaymentModalityDTO.java new file mode 100644 index 000000000..035e61192 --- /dev/null +++ b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/schema/PaymentModalityDTO.java @@ -0,0 +1,17 @@ +package org.mifos.processor.bulk.schema; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +public class PaymentModalityDTO { + + private String paymentModality; + private String financialAddress; + private String bankingInstitutionCode; +} diff --git a/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/schema/SubBatchEntity.java b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/schema/SubBatchEntity.java new file mode 100644 index 000000000..5aa98f413 --- /dev/null +++ b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/schema/SubBatchEntity.java @@ -0,0 +1,55 @@ +package org.mifos.processor.bulk.schema; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import java.util.Date; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@NoArgsConstructor +public class SubBatchEntity { + + private String batchId; + private String subBatchId; + private String requestId; + private String requestFile; + private String resultFile; + private String note; + private String paymentMode; + private String registeringInstitutionId; + private String payerFsp; + private String correlationId; + + private Long totalTransactions; + private Long ongoing; + private Long failed; + private Long completed; + private Long totalAmount; + private Long ongoingAmount; + private Long failedAmount; + private Long completedAmount; + private Long workflowKey; + private Long workflowInstanceKey; + private Long approvedAmount; + private Long approvedCount; + + private Date resultGeneratedAt; + private Date startedAt; + private Date completedAt; + + @JsonIgnore + public void setAllEmptyAmount() { + setTotalTransactions(0L); + setOngoing(0L); + setFailed(0L); + setCompleted(0L); + setTotalAmount(0L); + setOngoingAmount(0L); + setFailedAmount(0L); + setCompletedAmount(0L); + setApprovedAmount(0L); + setApprovedCount(0L); + } +} diff --git a/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/schema/SubscriptionDTO.java b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/schema/SubscriptionDTO.java new file mode 100644 index 000000000..645fd957f --- /dev/null +++ b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/schema/SubscriptionDTO.java @@ -0,0 +1,123 @@ +package org.mifos.processor.bulk.schema; + +import java.util.UUID; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +public class SubscriptionDTO { + + private String id; + + private String roomClass; + + private String roomCode; + + private String srcServiceCode; + + private String srcOperationId; + + private String dstServiceCode; + + private String dstOperationId; + + private String delivery; + + private SubscriptionOptionsDTO options; + + public static SubscriptionDTOBuilder subscriptionDTOBuilder = new SubscriptionDTOBuilder(); + + public static class SubscriptionDTOBuilder { + + private String id; + private String roomClass; + private String roomCode; + private String srcServiceCode; + private String srcOperationId; + private String dstServiceCode; + private String dstOperationId; + private String delivery; + private SubscriptionOptionsDTO options; + + public SubscriptionDTOBuilder roomClass(String roomClass) { + this.roomClass = roomClass; + return this; + } + + public SubscriptionDTOBuilder roomCode(String roomCode) { + this.roomCode = roomCode; + return this; + } + + public SubscriptionDTOBuilder srcServiceCode(String srcServiceCode) { + this.srcServiceCode = srcServiceCode; + return this; + } + + public SubscriptionDTOBuilder srcOperationId(String srcOperationId) { + this.srcOperationId = srcOperationId; + return this; + } + + public SubscriptionDTOBuilder dstServiceCode(String dstServiceCode) { + this.dstServiceCode = dstServiceCode; + return this; + } + + public SubscriptionDTOBuilder dstOperationId(String dstOperationId) { + this.dstOperationId = dstOperationId; + return this; + } + + public SubscriptionDTOBuilder delivery(String delivery) { + this.delivery = delivery; + return this; + } + + public SubscriptionDTOBuilder options(SubscriptionOptionsDTO options) { + this.options = options; + return this; + } + + private void check() { + if (this.id == null) { + this.id = UUID.randomUUID().toString(); + } + if (this.options == null) { + this.options = SubscriptionOptionsDTO.subscriptionOptionsDTOBuilder.build(); + } + if (this.delivery == null) { + this.delivery = "PUSH"; + } + if (roomClass == null) { + throw new RuntimeException("roomClass field cant be null"); + } + if (roomCode == null) { + throw new RuntimeException("roomCode field cant be null"); + } + if (srcServiceCode == null) { + throw new RuntimeException("srcServiceCode field cant be null"); + } + if (srcOperationId == null) { + throw new RuntimeException("srcOperationId field cant be null"); + } + if (dstServiceCode == null) { + throw new RuntimeException("dstServiceCode field cant be null"); + } + if (dstOperationId == null) { + throw new RuntimeException("dstOperationId field cant be null"); + } + } + + public SubscriptionDTO build() { + check(); + return new SubscriptionDTO(this.id, this.roomClass, this.roomCode, this.srcServiceCode, this.srcOperationId, + this.dstServiceCode, this.dstOperationId, this.delivery, this.options); + } + } +} diff --git a/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/schema/SubscriptionOptionsDTO.java b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/schema/SubscriptionOptionsDTO.java new file mode 100644 index 000000000..9cb1858b2 --- /dev/null +++ b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/schema/SubscriptionOptionsDTO.java @@ -0,0 +1,50 @@ +package org.mifos.processor.bulk.schema; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +public class SubscriptionOptionsDTO { + + @JsonProperty("TTL") + private int ttl; + + @JsonProperty("FIFO") + private boolean fifo; + + public static SubscriptionOptionsDTOBuilder subscriptionOptionsDTOBuilder = new SubscriptionOptionsDTOBuilder(); + + public static class SubscriptionOptionsDTOBuilder { + + private Integer ttl; + + private Boolean fifo; + + public SubscriptionOptionsDTOBuilder tTL(int tTL) { + this.ttl = tTL; + return this; + } + + public SubscriptionOptionsDTOBuilder fIFO(boolean fIFO) { + this.fifo = fIFO; + return this; + } + + public SubscriptionOptionsDTO build() { + if (this.ttl == null) { + this.ttl = 3600; + } + if (this.fifo == null) { + this.fifo = false; + } + return new SubscriptionOptionsDTO(this.ttl, this.fifo); + } + } + +} diff --git a/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/schema/Transaction.java b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/schema/Transaction.java new file mode 100644 index 000000000..85e708004 --- /dev/null +++ b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/schema/Transaction.java @@ -0,0 +1,109 @@ +package org.mifos.processor.bulk.schema; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import java.util.Objects; +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonPropertyOrder({ "id", "request_id", "payment_mode", "payer_identifier_type", "payer_identifier", "payee_identifier_type", + "payee_identifier", "amount", "currency", "note", "program_shortcode", "cycle", "payee_dfsp_id", "batch_id", "account_number" }) +public class Transaction implements CsvSchema { + + @JsonProperty("id") + private int id; + + @JsonProperty("request_id") + private String requestId; + + @JsonProperty("payment_mode") + private String paymentMode; + + @JsonProperty("account_number") + private String accountNumber; + + @JsonProperty("amount") + private String amount; + + @JsonProperty("currency") + private String currency; + + @Override + public boolean equals(Object transaction) { + if (this == transaction) { + return true; + } + if ((transaction == null) || (getClass() != transaction.getClass())) { + return false; + } + Transaction that = (Transaction) transaction; + return (id == that.id) && (Objects.equals(requestId, that.requestId)) && (Objects.equals(paymentMode, that.paymentMode)) + && (Objects.equals(accountNumber, that.accountNumber)) && (Objects.equals(amount, that.amount)) + && (Objects.equals(payeeDfspId, that.payeeDfspId)); + } + + @Override + public int hashCode() { + return Objects.hash(id, requestId, paymentMode, accountNumber, amount, currency, note, payerIdentifierType, payerIdentifier, + payeeIdentifierType, payeeIdentifier, payeeDfspId); + } + + @JsonProperty("note") + private String note; + + @JsonProperty(value = "payer_identifier_type") + private String payerIdentifierType; + + @JsonProperty("payer_identifier") + private String payerIdentifier; + + @JsonProperty("payee_identifier_type") + private String payeeIdentifierType; + + @JsonProperty("payee_identifier") + private String payeeIdentifier; + + @JsonProperty("program_shortcode") + private String programShortCode; + + @JsonProperty("cycle") + private String cycle; + + @JsonProperty("payee_dfsp_id") + private String payeeDfspId; + + @JsonProperty("batch_id") + private String batchId; + + @Override + public String toString() { + StringBuilder buffer = new StringBuilder("Transaction{"); + buffer.append("id=").append(id); + buffer.append(", request_id='").append(requestId); + buffer.append(", payment_mode='").append(paymentMode); + buffer.append(", account_number='").append(accountNumber); + buffer.append(", amount='").append(amount); + buffer.append(", currency='").append(currency); + buffer.append(", note='").append(note); + buffer.append(", batchId='").append(batchId); + buffer.append(", status='").append(id).append('}'); + return buffer.toString(); + } + + @JsonIgnore + @Override + public String getCsvString() { + return String.format("%s,%s,%s,%s,%s,%s,%s", id, requestId, paymentMode, accountNumber, amount, currency, note); + } + + @JsonIgnore + @Override + public String getCsvHeader() { + return "id,request_id,payment_mode,account_number,amount,currency,note,status"; + } +} diff --git a/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/schema/TransactionOlder.java b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/schema/TransactionOlder.java new file mode 100644 index 000000000..a783105a1 --- /dev/null +++ b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/schema/TransactionOlder.java @@ -0,0 +1,14 @@ +package org.mifos.processor.bulk.schema; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public class TransactionOlder extends Transaction { + + @JsonProperty("batchId") + private String batchId; + +} diff --git a/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/schema/TransactionResult.java b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/schema/TransactionResult.java new file mode 100644 index 000000000..185f2213e --- /dev/null +++ b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/schema/TransactionResult.java @@ -0,0 +1,41 @@ +package org.mifos.processor.bulk.schema; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonPropertyOrder({ "id", "request_id", "payment_mode", "payer_identifier_type", "payer_identifier", "payee_identifier_type", + "payee_identifier", "amount", "currency", "note", "program_shortcode", "cycle", "status", "error_code", "error_description" }) +public class TransactionResult extends Transaction { + + @JsonProperty("status") + private String status; + + @JsonProperty("error_code") + private String errorCode; + + @JsonProperty("error_description") + private String errorDescription; + + @JsonProperty("account_number") + @JsonIgnore + private String accountNumber; + + @JsonIgnore + @Override + public void setAccountNumber(String accountNumber) { + super.setAccountNumber(accountNumber); + } + + @JsonIgnore + @Override + public String getAccountNumber() { + return super.getAccountNumber(); + } +} diff --git a/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/service/BatchAccountLookup.java b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/service/BatchAccountLookup.java new file mode 100644 index 000000000..77ea2f995 --- /dev/null +++ b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/service/BatchAccountLookup.java @@ -0,0 +1,63 @@ +package org.mifos.processor.bulk.service; + +import static org.mifos.processor.bulk.camel.config.CamelProperties.HEADER_REGISTERING_INSTITUTE_ID; +import static org.mifos.processor.bulk.camel.config.CamelProperties.TRANSACTION_LIST; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.CALLBACK; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.REGISTERING_INSTITUTION_ID; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.REQUEST_ID; + +import com.fasterxml.jackson.databind.ObjectMapper; +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.apache.camel.Exchange; +import org.mifos.connector.common.identityaccountmapper.dto.AccountMapperRequestDTO; +import org.mifos.connector.common.identityaccountmapper.dto.BeneficiaryDTO; +import org.mifos.processor.bulk.connectors.service.AccountLookupService; +import org.mifos.processor.bulk.schema.Transaction; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; + +public class BatchAccountLookup { + + @Autowired + private ObjectMapper objectMapper; + @Autowired + private AccountLookupService accountLookupService; + @Value("${identity_account_mapper.hostname}") + private String identityEndpoint; + @Value("${identity_account_mapper.batch_account_lookup}") + private String batchAccountLookup; + + public Logger logger = LoggerFactory.getLogger(this.getClass()); + + public void doBatchAccountLookup(Exchange exchange) throws IOException { + List transactionList = exchange.getProperty(TRANSACTION_LIST, List.class); + HashMap> stringListHashMap = new HashMap<>(); + List beneficiaryDTOList = new ArrayList<>(); + transactionList.forEach(transaction -> { + beneficiaryDTOList.add(new BeneficiaryDTO(transaction.getPayeeIdentifier(), "", "", "")); + }); + String requestId = exchange.getProperty(REQUEST_ID, String.class); + String callbackUrl = exchange.getProperty(CALLBACK, String.class); + String registeringInstitutionId = exchange.getProperty(HEADER_REGISTERING_INSTITUTE_ID, String.class); + AccountMapperRequestDTO accountMapperRequestDTO = new AccountMapperRequestDTO(requestId, registeringInstitutionId, + beneficiaryDTOList); + String requestBody = objectMapper.writeValueAsString(accountMapperRequestDTO); + + exchange.getIn().setHeader(CALLBACK, callbackUrl); + exchange.getIn().setHeader(REGISTERING_INSTITUTION_ID, registeringInstitutionId); + exchange.getIn().setHeader("Content-type", "application/json"); + exchange.getIn().setBody(requestBody); + + Map headers = new HashMap<>(); + headers = exchange.getIn().getHeaders(); + + String fullUrl = identityEndpoint + batchAccountLookup; + accountLookupService.accountLookupCall(identityEndpoint, fullUrl, accountMapperRequestDTO, headers); + } +} diff --git a/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/service/FileProcessingRouteService.java b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/service/FileProcessingRouteService.java new file mode 100644 index 000000000..4a8039200 --- /dev/null +++ b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/service/FileProcessingRouteService.java @@ -0,0 +1,90 @@ +package org.mifos.processor.bulk.service; + +import static org.mifos.processor.bulk.camel.config.CamelProperties.LOCAL_FILE_PATH; +import static org.mifos.processor.bulk.camel.config.CamelProperties.OVERRIDE_HEADER; +import static org.mifos.processor.bulk.camel.config.CamelProperties.RESULT_TRANSACTION_LIST; +import static org.mifos.processor.bulk.camel.config.CamelProperties.TRANSACTION_LIST; +import static org.mifos.processor.bulk.camel.config.CamelProperties.TRANSACTION_LIST_LENGTH; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.COMPLETED_AMOUNT; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.FAILED_AMOUNT; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.ONGOING_AMOUNT; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.TOTAL_AMOUNT; + +import com.fasterxml.jackson.databind.MappingIterator; +import com.fasterxml.jackson.databind.SequenceWriter; +import com.fasterxml.jackson.dataformat.csv.CsvMapper; +import com.fasterxml.jackson.dataformat.csv.CsvSchema; +import java.io.File; +import java.io.FileReader; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import lombok.extern.slf4j.Slf4j; +import org.apache.camel.Exchange; +import org.mifos.processor.bulk.schema.Transaction; +import org.mifos.processor.bulk.schema.TransactionResult; +import org.mifos.processor.bulk.utility.CsvWriter; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +@Service +@Slf4j +public class FileProcessingRouteService { + + @Autowired + private CsvMapper csvMapper; + + public void getTxnArray(Exchange exchange) throws IOException { + Double totalAmount = 0.0; + Long failedAmount = 0L; + Long completedAmount = 0L; + String filename = exchange.getProperty(LOCAL_FILE_PATH, String.class); + log.debug("Local file path: {}", filename); + CsvSchema schema = CsvSchema.emptySchema().withHeader(); + log.info("Filename: {}", filename); + FileReader reader = new FileReader(filename); + MappingIterator readValues = csvMapper.readerWithSchemaFor(Transaction.class).with(schema).readValues(reader); + List transactionList = new ArrayList<>(); + while (readValues.hasNext()) { + Transaction current = readValues.next(); + transactionList.add(current); + totalAmount += Double.parseDouble(current.getAmount()); + } + reader.close(); + exchange.setProperty(TRANSACTION_LIST, transactionList); + exchange.setProperty(TRANSACTION_LIST_LENGTH, transactionList.size()); + exchange.setProperty(TOTAL_AMOUNT, totalAmount); + exchange.setProperty(ONGOING_AMOUNT, totalAmount); + exchange.setProperty(FAILED_AMOUNT, failedAmount); + exchange.setProperty(COMPLETED_AMOUNT, completedAmount); + } + + public void updateResultFile(Exchange exchange) throws IOException { + String filepath = exchange.getProperty(LOCAL_FILE_PATH, String.class); + List transactionList = exchange.getProperty(RESULT_TRANSACTION_LIST, List.class); + + Boolean overrideHeader = exchange.getProperty(OVERRIDE_HEADER, Boolean.class); + + CsvWriter.writeToCsv(transactionList, TransactionResult.class, csvMapper, overrideHeader, filepath); + } + + public void updateFile(Exchange exchange) throws IOException { + String filepath = exchange.getProperty(LOCAL_FILE_PATH, String.class); + List transactionList = exchange.getProperty(TRANSACTION_LIST, List.class); + + // getting header + Boolean overrideHeader = exchange.getProperty(OVERRIDE_HEADER, Boolean.class); + CsvSchema csvSchema = csvMapper.schemaFor(Transaction.class); + if (overrideHeader) { + csvSchema = csvSchema.withHeader(); + } else { + csvSchema = csvSchema.withoutHeader(); + } + + File file = new File(filepath); + SequenceWriter writer = csvMapper.writerWithSchemaFor(Transaction.class).with(csvSchema).writeValues(file); + for (Transaction transaction : transactionList) { + writer.write(transaction); + } + } +} diff --git a/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/service/FileRouteService.java b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/service/FileRouteService.java new file mode 100644 index 000000000..ec50c22b9 --- /dev/null +++ b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/service/FileRouteService.java @@ -0,0 +1,48 @@ +package org.mifos.processor.bulk.service; + +import static org.mifos.processor.bulk.camel.config.CamelProperties.LOCAL_FILE_PATH; +import static org.mifos.processor.bulk.camel.config.CamelProperties.SERVER_FILE_NAME; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import lombok.extern.slf4j.Slf4j; +import org.apache.camel.Exchange; +import org.mifos.processor.bulk.file.FileTransferService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; + +@Service +@Slf4j +public class FileRouteService { + + @Autowired + @Qualifier("awsStorage") + private FileTransferService fileTransferService; + @Value("${application.bucket-name}") + private String bucketName; + private Logger logger = LoggerFactory.getLogger(this.getClass()); + + public void downloadFile(Exchange exchange) throws IOException { + String filename = exchange.getProperty(SERVER_FILE_NAME, String.class); + + byte[] csvFile = fileTransferService.downloadFile(filename, bucketName); + File file = new File(filename); + try (FileOutputStream fos = new FileOutputStream(file)) { + fos.write(csvFile); + } + exchange.setProperty(LOCAL_FILE_PATH, file.getAbsolutePath()); + logger.info("File downloaded"); + } + + public void uploadFile(Exchange exchange) { + String filepath = exchange.getProperty(LOCAL_FILE_PATH, String.class); + String serverFileName = fileTransferService.uploadFile(new File(filepath), bucketName); + exchange.setProperty(SERVER_FILE_NAME, serverFileName); + logger.info("Uploaded file: {}", serverFileName); + } +} diff --git a/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/service/SubscriptionService.java b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/service/SubscriptionService.java new file mode 100644 index 000000000..6c067201a --- /dev/null +++ b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/service/SubscriptionService.java @@ -0,0 +1,10 @@ +package org.mifos.processor.bulk.service; + +import org.springframework.stereotype.Service; + +@Service +public interface SubscriptionService { + + void subscribeToEvent(); + +} diff --git a/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/service/SubscriptionServiceImpl.java b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/service/SubscriptionServiceImpl.java new file mode 100644 index 000000000..774a0f607 --- /dev/null +++ b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/service/SubscriptionServiceImpl.java @@ -0,0 +1,34 @@ +package org.mifos.processor.bulk.service; + +import static org.mifos.processor.bulk.camel.config.CamelProperties.EVENT_TYPE; + +import javax.annotation.PostConstruct; +import org.apache.camel.CamelContext; +import org.apache.camel.Exchange; +import org.apache.camel.ProducerTemplate; +import org.apache.camel.support.DefaultExchange; +import org.springframework.stereotype.Service; + +@Service +public class SubscriptionServiceImpl implements SubscriptionService { + + private final ProducerTemplate producerTemplate; + + protected final CamelContext camelContext; + + public String eventType; + + public SubscriptionServiceImpl(ProducerTemplate producerTemplate, CamelContext camelContext) { + this.producerTemplate = producerTemplate; + this.camelContext = camelContext; + } + + @PostConstruct + @Override + public void subscribeToEvent() { + Exchange exchange = new DefaultExchange(camelContext); + exchange.setProperty(EVENT_TYPE, eventType); + producerTemplate.send("direct:subscribe", exchange); + } + +} diff --git a/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/utility/CsvWriter.java b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/utility/CsvWriter.java new file mode 100644 index 000000000..9012cded4 --- /dev/null +++ b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/utility/CsvWriter.java @@ -0,0 +1,33 @@ +package org.mifos.processor.bulk.utility; + +import com.fasterxml.jackson.databind.SequenceWriter; +import com.fasterxml.jackson.dataformat.csv.CsvMapper; +import com.fasterxml.jackson.dataformat.csv.CsvSchema; +import java.io.File; +import java.io.IOException; +import java.util.List; + +public final class CsvWriter { + + private CsvWriter() {} + + public static void writeToCsv(List data, Class tClass, CsvMapper csvMapper, boolean overrideHeader, String filepath) + throws IOException { + CsvSchema csvSchema = csvMapper.schemaFor(tClass); + if (overrideHeader) { + csvSchema = csvSchema.withHeader(); + } else { + csvSchema = csvSchema.withoutHeader(); + } + + File file = new File(filepath); + if (!file.exists()) { + file.createNewFile(); + } + SequenceWriter writer = csvMapper.writerWithSchemaFor(tClass).with(csvSchema).writeValues(file); + for (T object : data) { + writer.write(object); + } + } + +} diff --git a/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/utility/Headers.java b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/utility/Headers.java new file mode 100644 index 000000000..f46aba916 --- /dev/null +++ b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/utility/Headers.java @@ -0,0 +1,53 @@ +package org.mifos.processor.bulk.utility; + +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +public final class Headers { + + private Map headers; + + private Headers() {} + + private void setHeaders(Map headers) { + this.headers = headers; + } + + public Map getHeaders() { + return headers; + } + + public Set getHeadersKey() { + return this.headers.keySet(); + } + + public Object get(String key) { + return this.headers.get(key); + } + + public static Map convertHeaders(Map headers) { + Map stringHeaders = new HashMap<>(); + for (Map.Entry entry : headers.entrySet()) { + stringHeaders.put(entry.getKey(), entry.getValue().toString()); + } + return stringHeaders; + } + + public static class HeaderBuilder { + + private Map headers = new HashMap<>(); + + public HeaderBuilder addHeader(String key, Object value) { + headers.put(key, value); + return this; + } + + public Headers build() { + Headers headersClassInstance = new Headers(); + headersClassInstance.setHeaders(this.headers); + + return headersClassInstance; + } + } +} diff --git a/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/utility/PhaseUtils.java b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/utility/PhaseUtils.java new file mode 100644 index 000000000..ccbe3539a --- /dev/null +++ b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/utility/PhaseUtils.java @@ -0,0 +1,22 @@ +package org.mifos.processor.bulk.utility; + +import java.util.List; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +@Component +@ConfigurationProperties(prefix = "callbackphases") +public class PhaseUtils { + + private List values; + + public List getValues() { + return values; + } + + public void setValues(List values) { + this.values = values; + + } + +} diff --git a/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/utility/SpringWrapperUtil.java b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/utility/SpringWrapperUtil.java new file mode 100644 index 000000000..ca60bcb9c --- /dev/null +++ b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/utility/SpringWrapperUtil.java @@ -0,0 +1,21 @@ +package org.mifos.processor.bulk.utility; + +import org.apache.camel.CamelContext; +import org.apache.camel.Exchange; +import org.apache.camel.support.DefaultExchange; + +public final class SpringWrapperUtil { + + private SpringWrapperUtil() {} + + public static Exchange getDefaultWrappedExchange(CamelContext camelContext, Headers headers) { + Exchange exchange = new DefaultExchange(camelContext); + + // Setting headers + for (String headerKey : headers.getHeadersKey()) { + exchange.getIn().setHeader(headerKey, headers.get(headerKey)); + } + + return exchange; + } +} diff --git a/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/utility/TransactionParser.java b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/utility/TransactionParser.java new file mode 100644 index 000000000..03f4138f6 --- /dev/null +++ b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/utility/TransactionParser.java @@ -0,0 +1,66 @@ +package org.mifos.processor.bulk.utility; + +import org.mifos.processor.bulk.schema.Transaction; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public final class TransactionParser { + + private static final Logger logger = LoggerFactory.getLogger(TransactionParser.class); + + private TransactionParser() { + throw new IllegalStateException("Utility class"); + } + + public static Transaction parseLineToTransaction(String line) { + try { + String[] parts = line.split(",", -1); + Transaction transaction = new Transaction(); + + if (parts.length > 0 && !parts[0].isEmpty()) { + transaction.setId(Integer.parseInt(parts[0])); + } + if (parts.length > 1) { + transaction.setRequestId(parts[1]); + } + if (parts.length > 2) { + transaction.setPaymentMode(parts[2]); + } + if (parts.length > 4) { + transaction.setPayerIdentifierType(parts[3]); + } + if (parts.length > 5) { + transaction.setPayerIdentifier(parts[4]); + } + if (parts.length > 6) { + transaction.setPayeeIdentifierType(parts[5]); + } + if (parts.length > 7) { + transaction.setPayeeIdentifier(parts[6]); + } + if (parts.length > 8) { + transaction.setAmount(parts[7]); + } + if (parts.length > 9) { + transaction.setCurrency(parts[8]); + } + if (parts.length > 10) { + transaction.setNote(parts[9]); + } + if (parts.length > 11) { + transaction.setProgramShortCode(parts[10]); + } + if (parts.length > 12) { + transaction.setCycle(parts[11]); + } + if (parts.length > 13) { + transaction.setPayeeDfspId(parts[12]); + } + + return transaction; + } catch (Exception e) { + logger.error("Error parsing line to Transaction object: {}", line, e); + return null; + } + } +} diff --git a/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/utility/Utils.java b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/utility/Utils.java new file mode 100644 index 000000000..b896bc9df --- /dev/null +++ b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/utility/Utils.java @@ -0,0 +1,233 @@ +package org.mifos.processor.bulk.utility; + +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.IOException; +import lombok.extern.slf4j.Slf4j; +import org.mifos.connector.common.channel.dto.TransactionChannelRequestDTO; +import org.mifos.connector.common.gsma.dto.Fee; +import org.mifos.connector.common.gsma.dto.GSMATransaction; +import org.mifos.connector.common.gsma.dto.GsmaParty; +import org.mifos.connector.common.gsma.dto.IdDocument; +import org.mifos.connector.common.gsma.dto.InternationalTransferInformation; +import org.mifos.connector.common.gsma.dto.Kyc; +import org.mifos.connector.common.gsma.dto.PostalAddress; +import org.mifos.connector.common.gsma.dto.SubjectName; +import org.mifos.connector.common.mojaloop.dto.MoneyData; +import org.mifos.connector.common.mojaloop.dto.Party; +import org.mifos.connector.common.mojaloop.dto.PartyIdInfo; +import org.mifos.connector.common.mojaloop.type.IdentifierType; +import org.mifos.processor.bulk.schema.Transaction; +import org.mifos.processor.bulk.schema.TransactionResult; + +@Slf4j +public final class Utils { + + private Utils() {} + + public static String getTenantSpecificWorkflowId(String originalWorkflowName, String tenantName) { + return originalWorkflowName.replace("{dfspid}", tenantName); + } + + public static String getBulkConnectorBpmnName(String originalWorkflowName, String paymentMode, String tenantName) { + return originalWorkflowName.replace("{MODE}", paymentMode.toLowerCase()).replace("{dfspid}", tenantName); + } + + public static String mergeCsvFile(String file1, String file2) { + try { + // create a writer for permFile + BufferedWriter out = new BufferedWriter(new FileWriter(file1, true)); + // create a reader for tmpFile + BufferedReader in = new BufferedReader(new FileReader(file2)); + String str; + boolean isFirstLine = true; + while ((str = in.readLine()) != null) { + if (isFirstLine) { + // used for skipping header writing + isFirstLine = false; + continue; + } + out.write(str + "\n"); + } + in.close(); + out.close(); + } catch (IOException e) { + log.debug(e.getMessage()); + return null; + } + + return file1; + } + + public static String getAwsFileUrl(String baseUrl, String filename) { + return String.format("%s/%s", baseUrl, filename); + } + + /** + * takes initial timer in the ISO 8601 durations format for more info check + * https://docs.camunda.io/docs/0.26/reference/bpmn-workflows/timer-events/#time-duration + * + * @param initialTimer + * initial timer in the ISO 8601 durations format, ex: PT45S + * @return next timer value in the ISO 8601 durations format + */ + public static String getNextTimer(String initialTimer) { + String stringSecondsValue = initialTimer.split("T")[1].split("S")[0]; + int initialSeconds = Integer.parseInt(stringSecondsValue); + + int currentPower = (int) (Math.log(initialSeconds) / Math.log(2)); + int next = (int) Math.pow(2, ++currentPower); + + return String.format("PT%sS", next); + } + + public static String getZeebeTimerValue(int timer) { + return String.format("PT%sS", timer); + } + + public static TransactionResult mapToResultDTO(Transaction transaction) { + TransactionResult transactionResult = new TransactionResult(); + transactionResult.setId(transaction.getId()); + transactionResult.setRequestId(transaction.getRequestId()); + transactionResult.setPaymentMode(transaction.getPaymentMode()); + transactionResult.setPayerIdentifierType("accountNumber"); + transactionResult.setPayerIdentifier(transaction.getPayerIdentifier()); + transactionResult.setAmount(transaction.getAmount()); + transactionResult.setCurrency(transactionResult.getCurrency()); + transactionResult.setNote(transactionResult.getNote()); + transactionResult.setPayeeIdentifierType("accountNumber"); + if (transaction.getAccountNumber() != null) { + transactionResult.setPayeeIdentifier(transaction.getAccountNumber()); + } else { + transactionResult.setPayeeIdentifier(transaction.getPayeeIdentifier()); + } + transactionResult.setProgramShortCode(transaction.getProgramShortCode()); + transactionResult.setCycle(transactionResult.getCycle()); + return transactionResult; + } + + public static GSMATransaction convertTxnToGSMA(Transaction transaction) { + GSMATransaction gsmaTransaction = new GSMATransaction(); + gsmaTransaction.setAmount(transaction.getAmount()); + gsmaTransaction.setCurrency(transaction.getCurrency()); + GsmaParty payer = new GsmaParty(); + // logger.info("Payer {} {}", transaction.getPayerIdentifier(),payer[0].); + payer.setKey("msisdn"); + payer.setValue(transaction.getPayerIdentifier()); + GsmaParty payee = new GsmaParty(); + payee.setKey("msisdn"); + payee.setValue(transaction.getPayeeIdentifier()); + GsmaParty[] debitParty = new GsmaParty[1]; + GsmaParty[] creditParty = new GsmaParty[1]; + debitParty[0] = payer; + creditParty[0] = payee; + gsmaTransaction.setDebitParty(debitParty); + gsmaTransaction.setCreditParty(creditParty); + gsmaTransaction.setRequestingOrganisationTransactionReference("string"); + gsmaTransaction.setSubType("string"); + gsmaTransaction.setDescriptionText("string"); + Fee fees = new Fee(); + fees.setFeeType(transaction.getAmount()); + fees.setFeeCurrency(transaction.getCurrency()); + fees.setFeeType("string"); + Fee[] fee = new Fee[1]; + fee[0] = fees; + gsmaTransaction.setFees(fee); + gsmaTransaction.setGeoCode("37.423825,-122.082900"); + InternationalTransferInformation internationalTransferInformation = new InternationalTransferInformation(); + internationalTransferInformation.setQuotationReference("string"); + internationalTransferInformation.setQuoteId("string"); + internationalTransferInformation.setDeliveryMethod("directtoaccount"); + internationalTransferInformation.setOriginCountry("USA"); + internationalTransferInformation.setReceivingCountry("USA"); + internationalTransferInformation.setRelationshipSender("string"); + internationalTransferInformation.setRemittancePurpose("string"); + gsmaTransaction.setInternationalTransferInformation(internationalTransferInformation); + gsmaTransaction.setOneTimeCode("string"); + IdDocument idDocument = new IdDocument(); + idDocument.setIdType("passport"); + idDocument.setIdNumber("string"); + idDocument.setIssuerCountry("USA"); + idDocument.setExpiryDate("2022-09-28T12:51:19.260+00:00"); + idDocument.setIssueDate("2022-09-28T12:51:19.260+00:00"); + idDocument.setIssuer("string"); + idDocument.setIssuerPlace("string"); + IdDocument[] idDocuments = new IdDocument[1]; + idDocuments[0] = idDocument; + PostalAddress postalAddress = new PostalAddress(); + postalAddress.setAddressLine1("string"); + postalAddress.setAddressLine2("string"); + postalAddress.setAddressLine3("string"); + postalAddress.setCity("string"); + postalAddress.setCountry("USA"); + postalAddress.setPostalCode("string"); + postalAddress.setStateProvince("string"); + SubjectName subjectName = new SubjectName(); + subjectName.setFirstName("string"); + subjectName.setLastName("string"); + subjectName.setMiddleName("string"); + subjectName.setTitle("string"); + subjectName.setNativeName("string"); + Kyc recieverKyc = new Kyc(); + recieverKyc.setBirthCountry("USA"); + recieverKyc.setDateOfBirth("2000-11-20"); + recieverKyc.setContactPhone("string"); + recieverKyc.setEmailAddress("string"); + recieverKyc.setEmployerName("string"); + recieverKyc.setGender('m'); + recieverKyc.setIdDocument(idDocuments); + recieverKyc.setNationality("USA"); + recieverKyc.setOccupation("string"); + recieverKyc.setPostalAddress(postalAddress); + recieverKyc.setSubjectName(subjectName); + Kyc senderKyc = new Kyc(); + senderKyc.setBirthCountry("USA"); + senderKyc.setDateOfBirth("2000-11-20"); + senderKyc.setContactPhone("string"); + senderKyc.setEmailAddress("string"); + senderKyc.setEmployerName("string"); + senderKyc.setGender('m'); + senderKyc.setIdDocument(idDocuments); + senderKyc.setNationality("USA"); + senderKyc.setOccupation("string"); + senderKyc.setPostalAddress(postalAddress); + senderKyc.setSubjectName(subjectName); + gsmaTransaction.setReceiverKyc(recieverKyc); + gsmaTransaction.setSenderKyc(senderKyc); + gsmaTransaction.setServicingIdentity("string"); + gsmaTransaction.setRequestDate("2022-09-28T12:51:19.260+00:00"); + + return gsmaTransaction; + } + + public static TransactionChannelRequestDTO convertTxnToInboundTransferPayload(Transaction transaction) { + TransactionChannelRequestDTO requestDTO = new TransactionChannelRequestDTO(); + + MoneyData moneyData = new MoneyData(); + moneyData.setCurrency(transaction.getCurrency()); + moneyData.setAmount(transaction.getAmount()); + requestDTO.setAmount(moneyData); + + IdentifierType identifierType; + try { + identifierType = IdentifierType.valueOf(transaction.getPaymentMode().toUpperCase()); + } catch (Exception e) { + identifierType = IdentifierType.MSISDN; + } + + // PAYER SETUP + Party payerParty = new Party(new PartyIdInfo(identifierType, transaction.getPayerIdentifier())); + + // PAYEE SETUP + Party payeeParty = new Party(new PartyIdInfo(identifierType, transaction.getPayeeIdentifier())); + + requestDTO.setPayer(payerParty); + requestDTO.setPayee(payeeParty); + requestDTO.setNote(transaction.getNote()); + + return requestDTO; + } + +} diff --git a/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/zeebe/BpmnConfig.java b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/zeebe/BpmnConfig.java new file mode 100644 index 000000000..f32387413 --- /dev/null +++ b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/zeebe/BpmnConfig.java @@ -0,0 +1,12 @@ +package org.mifos.processor.bulk.zeebe; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +@Component +public class BpmnConfig { + + @Value("${bpmn.flows.slcb}") + public String slcbBpmn; + +} diff --git a/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/zeebe/ZeebeClientConfiguration.java b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/zeebe/ZeebeClientConfiguration.java new file mode 100644 index 000000000..585c5b5c1 --- /dev/null +++ b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/zeebe/ZeebeClientConfiguration.java @@ -0,0 +1,27 @@ +package org.mifos.processor.bulk.zeebe; + +import io.camunda.zeebe.client.ZeebeClient; +import java.time.Duration; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class ZeebeClientConfiguration { + + @Value("${zeebe.broker.contactpoint}") + private String zeebeBrokerContactpoint; + + @Value("${zeebe.client.max-execution-threads}") + private int zeebeClientMaxThreads; + + @Value("${zeebe.client.poll-interval}") + private int zeebeClientPollInterval; + + @Bean + public ZeebeClient setup() { + return ZeebeClient.newClientBuilder().gatewayAddress(zeebeBrokerContactpoint).usePlaintext() + .defaultJobPollInterval(Duration.ofMillis(zeebeClientPollInterval)).defaultJobWorkerMaxJobsActive(2000) + .numJobWorkerExecutionThreads(zeebeClientMaxThreads).build(); + } +} diff --git a/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/zeebe/ZeebeMessages.java b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/zeebe/ZeebeMessages.java new file mode 100644 index 000000000..ee6e9fb75 --- /dev/null +++ b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/zeebe/ZeebeMessages.java @@ -0,0 +1,12 @@ +package org.mifos.processor.bulk.zeebe; + +public final class ZeebeMessages { + + private ZeebeMessages() {} + + public static final String OPERATOR_MANUAL_RECOVERY = "operator-manual-recovery"; + public static final String ACCOUNT_LOOKUP = "account-lookup"; + + public static final String AUTHORIZATION_RESPONSE = "authorization-response"; + +} diff --git a/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/zeebe/ZeebeProcessStarter.java b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/zeebe/ZeebeProcessStarter.java new file mode 100644 index 000000000..538b8280e --- /dev/null +++ b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/zeebe/ZeebeProcessStarter.java @@ -0,0 +1,82 @@ +package org.mifos.processor.bulk.zeebe; + +import io.camunda.zeebe.client.ZeebeClient; +import io.camunda.zeebe.client.api.response.ProcessInstanceEvent; +import java.time.Instant; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; +import org.apache.camel.Exchange; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component +public class ZeebeProcessStarter { + + private static final Logger logger = LoggerFactory.getLogger(ZeebeProcessStarter.class); + + @Autowired + private ZeebeClient zeebeClient; + + public static void zeebeVariablesToCamelHeaders(Map variables, Exchange exchange, String... names) { + for (String name : names) { + Object value = variables.get(name); + if (value == null) { + logger.error("failed to find Zeebe variable name {}", name); + } + exchange.getIn().setHeader(name, value); + } + } + + public static void camelHeadersToZeebeVariables(Exchange exchange, Map variables, String... names) { + for (String name : names) { + String header = exchange.getIn().getHeader(name, String.class); + if (header == null) { + logger.error("failed to find Camel Exchange header {}", name); + } + variables.put(name, header); + } + } + + public void startZeebeWorkflow(String workflowId, Map extraVariables) { + + Map variables = new HashMap<>(); + variables.put(ZeebeVariables.ORIGIN_DATE, Instant.now().toEpochMilli()); + if (extraVariables != null) { + variables.putAll(extraVariables); + } + + // TODO if successful transfer response arrives in X timeout return it otherwise do callback + ProcessInstanceEvent join = zeebeClient.newCreateInstanceCommand().bpmnProcessId(workflowId).latestVersion().variables(variables) + .send().join(); + + logger.info("zeebee workflow instance from process {}", workflowId); + } + + public String startZeebeWorkflow(String workflowId, String request, Map extraVariables) { + String transactionId = generateTransactionId(); + + Map variables = new HashMap<>(); + variables.put(ZeebeVariables.TRANSACTION_ID, transactionId); + variables.put(ZeebeVariables.CHANNEL_REQUEST, request); + variables.put(ZeebeVariables.ORIGIN_DATE, Instant.now().toEpochMilli()); + if (extraVariables != null) { + variables.putAll(extraVariables); + } + + // TODO if successful transfer response arrives in X timeout return it otherwise do callback + ProcessInstanceEvent join = zeebeClient.newCreateInstanceCommand().bpmnProcessId(workflowId).latestVersion().variables(variables) + .send().join(); + + logger.info("zeebee workflow instance from process {} started with transactionId {}", workflowId, transactionId); + logger.debug("Variables published in initial workflow initialisation: {}", variables); + return transactionId; + } + + // TODO generate proper cluster-safe transaction id + private String generateTransactionId() { + return UUID.randomUUID().toString(); + } +} diff --git a/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/zeebe/ZeebeVariables.java b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/zeebe/ZeebeVariables.java new file mode 100644 index 000000000..83fdf99e4 --- /dev/null +++ b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/zeebe/ZeebeVariables.java @@ -0,0 +1,169 @@ +package org.mifos.processor.bulk.zeebe; + +public final class ZeebeVariables { + + private ZeebeVariables() {} + + public static final String ACCOUNT = "account"; + public static final String AUTH_RETRIES_LEFT = "authRetriesLeft"; + public static final String CHANNEL_REQUEST = "channelRequest"; + public static final String ERROR_INFORMATION = "errorInformation"; + public static final String IS_AUTHORISATION_REQUIRED = "isAuthorisationRequired"; + public static final String IS_RTP_REQUEST = "isRtpRequest"; + public static final String OPERATOR_MANUAL_OVERRIDE = "operatorManualOverride"; // TODO validate in request? + public static final String ORIGIN_DATE = "originDate"; + public static final String PARTY_ID = "partyId"; + public static final String PARTY_ID_TYPE = "partyIdType"; + public static final String TENANT_ID = "tenantId"; + public static final String TRANSACTION_ID = "transactionId"; + public static final String GSMA_CHANNEL_REQUEST = "gsmaChannelRequest"; + public static final String PARTY_LOOKUP_FSPID = "partyLookupFspId"; + public static final String INITIATOR_FSPID = "initiatorFspId"; + public static final String TRANSACTION_TYPE = "transactionType"; + public static final String BATCH_ID = "batchId"; + public static final String SUB_BATCH_ID = "subBatchId"; + public static final String IS_SAMPLE_READY = "isSampleReady"; + public static final String SAMPLED_TX_IDS = "sampledTransactionIds"; + + public static final String PARTY_LOOKUP_FAILED = "partyLookupFailed"; + public static final String APPROVAL_FAILED = "approvalFailed"; + public static final String DE_DUPLICATION_FAILED = "deduplicationFailed"; + public static final String ORDERING_FAILED = "orderingFailed"; + public static final String SPLITTING_FAILED = "splittingFailed"; + public static final String FORMATTING_FAILED = "formattingFailed"; + public static final String INIT_SUB_BATCH_FAILED = "initSubBatchFailed"; + public static final String MERGE_FAILED = "mergeFailed"; + + public static final String FILE_NAME = "filename"; + + public static final String REQUEST_ID = "requestId"; + + public static final String SUB_BATCHES = "subBatches"; + public static final String PURPOSE = "purpose"; + + public static final String INIT_SUCCESS_SUB_BATCHES = "initSuccessSubBatches"; + + public static final String INIT_FAILURE_SUB_BATCHES = "initFailureSubBatches"; + + public static final String PARTY_LOOKUP_ENABLED = "partyLookupEnabled"; + + public static final String APPROVAL_ENABLED = "approvalEnabled"; + + public static final String DE_DUPLICATION_ENABLE = "deduplicationEnabled"; + + public static final String ORDERING_ENABLED = "orderingEnabled"; + + public static final String SPLITTING_ENABLED = "splittingEnabled"; + + public static final String FORMATTING_ENABLED = "formattingEnabled"; + + public static final String BATCH_AGGREGATE_ENABLED = "batchAggregateEnabled"; + + public static final String COMPLETION_THRESHOLD_CHECK_ENABLED = "completionThresholdCheckEnabled"; + + public static final String MERGE_ENABLED = "mergeEnabled"; + + public static final String ORDERED_BY = "orderedBy"; + + public static final String FORMATTING_STANDARD = "formattingStandard"; + + public static final String REMAINING_SUB_BATCH = "remainingSubBatch"; + + public static final String TRANSACTION_REQUEST = "transactionRequest"; + + public static final String TOTAL_AMOUNT = "totalAmount"; + + public static final String ONGOING_AMOUNT = "ongoingAmount"; + + public static final String FAILED_AMOUNT = "failedAmount"; + + public static final String COMPLETED_AMOUNT = "completedAmount"; + + public static final String MERGE_FILE_LIST = "mergeFiles"; + + public static final String MERGE_ITERATION = "mergeIteration"; + + public static final String MERGE_COMPLETED = "mergeCompleted"; + + public static final String RESULT_FILE = "resultFile"; + + public static final String MAX_STATUS_RETRY = "maxStatusRetry"; + + public static final String RETRY = "retry"; + + public static final String CALLBACK_RETRY = "callbackRetryCount"; + + public static final String COMPLETION_THRESHOLD = "completionThreshold"; + + public static final String COMPLETION_RATE = "completionRate"; + + public static final String ERROR_CODE = "errorCode"; + + public static final String ERROR_DESCRIPTION = "errorDescription"; + + public static final String THRESHOLD_DELAY = "thresholdDelay"; + + public static final String PAYMENT_MODE = "paymentMode"; + + public static final String CALLBACK_SUCCESS = "callbackSuccessful"; + + public static final String CALLBACK_URL = "X-CallbackURL"; + + public static final String MAX_CALLBACK_RETRY = "maxCallbackRetry"; + + public static final String BULK_NOTIF_SUCCESS = "isNotificationsSuccessEnabled"; + + public static final String BULK_NOTIF_FAILURE = "isNotificationsFailureEnabled"; + + public static final String PHASES = "phases"; + + public static final String PHASE_COUNT = "phaseCount"; + + public static final String INITIATOR_FSP_ID = "initiatorFspId"; + public static final String ACCOUNT_LOOKUP_RETRY_COUNT = "accountLookupRetryCount"; + public static final String ACCOUNT_LOOKUP_FAILED = "accountLookupFailed"; + public static final String ORIGIN_CHANNEL_REQUEST = "originChannelRequest"; + public static final String CALLBACK = "X-CallbackURL"; + + public static final String DEBULKINGDFSPID = "debulkingDfspid"; + + public static final String IS_FILE_VALID = "isFileValid"; + + public static final String NOTE = "note"; + public static final String PARTY_LOOKUP_FSP_ID = "partyLookupFspId"; + public static final String PROGRAM_NAME = "programName"; + public static final String PAYER_IDENTIFIER_TYPE = "payerIdentifierType"; + public static final String PAYER_IDENTIFIER_VALUE = "payerIdentifier"; + public static final String HEADER_CLIENT_CORRELATION_ID = "X-CorrelationID"; + public static final String HEADER_TYPE = "Type"; + public static final String HEADER_PLATFORM_TENANT_ID = "Platform-TenantId"; + + public static final String AUTHORIZATION_SUCCESSFUL = "authorizationSuccessful"; + + public static final String AUTHORIZATION_ACCEPTED = "authorizationAccepted"; + + public static final String APPROVED_AMOUNT = "approvedAmount"; + + public static final String AUTHORIZATION_ENABLED = "authorizationEnabled"; + + public static final String CLIENT_CORRELATION_ID = "clientCorrelationId"; + + public static final String AUTHORIZATION_STATUS = "authorizationStatus"; + + public static final String AUTHORIZATION_FAIL_REASON = "authorizationFailReason"; + + public static final String PAYER_IDENTIFIER = "payerIdentifier"; + public static final String CURRENCY = "currency"; + + public static final String AUTHORIZATION_RESPONSE = "authorizationResponse"; + + public static final String FAILED_TRANSACTION_FILE = "failedTransactionFile"; + + public static final String DUPLICATE_TRANSACTION_COUNT = "duplicateTransactionCount"; + + public static final String BATCH_ACCOUNT_LOOKUP_RESPONSE = "batchAccountLookupResponse"; + public static final String PARTY_LOOKUP_SUCCESSFUL_TRANSACTION_AMOUNT = "totalApprovedAmount"; + public static final String PARTY_LOOKUP_SUCCESSFUL_TRANSACTION_COUNT = "totalApprovedCount"; + public static final String REGISTERING_INSTITUTION_ID = "X-Registering-Institution-ID"; + +} diff --git a/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/zeebe/ZeebeWorkers.java b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/zeebe/ZeebeWorkers.java new file mode 100644 index 000000000..3805f907b --- /dev/null +++ b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/zeebe/ZeebeWorkers.java @@ -0,0 +1,123 @@ +package org.mifos.processor.bulk.zeebe; + +import static org.mifos.processor.bulk.camel.config.CamelProperties.IS_BATCH_READY; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.BATCH_ID; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.IS_SAMPLE_READY; + +import com.fasterxml.jackson.databind.MappingIterator; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.dataformat.csv.CsvMapper; +import com.fasterxml.jackson.dataformat.csv.CsvSchema; +import io.camunda.zeebe.client.ZeebeClient; +import java.io.InputStream; +import java.util.Map; +import org.apache.camel.CamelContext; +import org.apache.camel.Exchange; +import org.apache.camel.ProducerTemplate; +import org.apache.camel.support.DefaultExchange; +import org.mifos.processor.bulk.file.FileTransferService; +import org.mifos.processor.bulk.schema.Transaction; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +@Component +@Deprecated +public class ZeebeWorkers { + + private Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Autowired + private ZeebeClient zeebeClient; + + @Autowired + private CsvMapper csvMapper; + + @Autowired + private ObjectMapper objectMapper; + + @Autowired + @Qualifier("awsStorage") + private FileTransferService fileTransferService; + + @Value("${application.bucket-name}") + private String bucketName; + + @Value("${zeebe.client.evenly-allocated-max-jobs}") + private int workerMaxJobs; + + @Autowired + private CamelContext camelContext; + + @Autowired + private ProducerTemplate producerTemplate; + + // @PostConstruct + public void setupWorkers() { + workerBulkProcessor(); + workerCheckTransactions(); + workerSampleTransactions(); + } + + private void workerBulkProcessor() { + zeebeClient.newWorker().jobType("bulk-processor").handler((client, job) -> { + logger.info("Job '{}' started from process '{}' with key {}", job.getType(), job.getBpmnProcessId(), job.getKey()); + + Map variables = job.getVariablesAsMap(); + String batchId = (String) variables.get(BATCH_ID); + String fileName = (String) variables.get("fileName"); + + // TODO: How to get sender information? Hard coded in Channel connector? + InputStream csvFileInputStream = fileTransferService.streamFile(fileName, bucketName); + + CsvSchema schema = CsvSchema.emptySchema().withHeader(); + MappingIterator readValues = csvMapper.readerWithSchemaFor(Transaction.class).with(schema) + .readValues(csvFileInputStream); + + /* + * while (readValues.hasNext()) { Transaction current = readValues.next(); current.setBatchId(batchId); if + * (current.getPayment_mode().equals("gsma")) kafkaTemplate.send(gsmaTopicName, + * objectMapper.writeValueAsString(current)); else if (current.getPayment_mode().equals("sclb")) + * kafkaTemplate.send(slcbTopicName, objectMapper.writeValueAsString(current)); } + */ + + client.newCompleteCommand(job.getKey()).send(); + }).name("bulk-processor").maxJobsActive(workerMaxJobs).open(); + } + + private void workerCheckTransactions() { + String jobType = "check-transactions"; + zeebeClient.newWorker().jobType(jobType).handler((client, job) -> { + logger.info("Job '{}' started from process '{}' with key {}", job.getType(), job.getBpmnProcessId(), job.getKey()); + + Map variables = job.getVariablesAsMap(); + String batchId = (String) variables.get(BATCH_ID); + + Exchange exchange = new DefaultExchange(camelContext); + exchange.setProperty(BATCH_ID, batchId); + producerTemplate.send("direct:check-transactions", exchange); + + client.newCompleteCommand(job.getKey()).send(); + }).name(jobType).maxJobsActive(workerMaxJobs).open(); + } + + private void workerSampleTransactions() { + String jobType = "sample-transactions"; + zeebeClient.newWorker().jobType(jobType).handler((client, job) -> { + logger.info("Job '{}' started from process '{}' with key {}", job.getType(), job.getBpmnProcessId(), job.getKey()); + + Map variables = job.getVariablesAsMap(); + String batchId = (String) variables.get(BATCH_ID); + + Exchange exchange = new DefaultExchange(camelContext); + exchange.setProperty(BATCH_ID, batchId); + exchange.setProperty(IS_BATCH_READY, variables.get(IS_SAMPLE_READY)); + producerTemplate.send("direct:sample-transactions", exchange); + + client.newCompleteCommand(job.getKey()).send(); + }).name(jobType).maxJobsActive(workerMaxJobs).open(); + } +} diff --git a/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/zeebe/worker/AccountLookupCallbackWorker.java b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/zeebe/worker/AccountLookupCallbackWorker.java new file mode 100644 index 000000000..a424dc2f7 --- /dev/null +++ b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/zeebe/worker/AccountLookupCallbackWorker.java @@ -0,0 +1,48 @@ +package org.mifos.processor.bulk.zeebe.worker; + +import static org.mifos.processor.bulk.camel.config.CamelProperties.PAYEE_PARTY_ID; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.CHANNEL_REQUEST; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.ORIGIN_CHANNEL_REQUEST; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.PARTY_LOOKUP_FSP_ID; +import static org.mifos.processor.bulk.zeebe.worker.Worker.ACCOUNT_LOOKUP_CALLBACK; + +import com.fasterxml.jackson.databind.ObjectMapper; +import io.camunda.zeebe.client.ZeebeClient; +import java.util.Map; +import org.apache.camel.CamelContext; +import org.mifos.connector.common.channel.dto.TransactionChannelRequestDTO; +import org.mifos.connector.common.mojaloop.dto.Party; +import org.mifos.connector.common.mojaloop.dto.PartyIdInfo; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component +public class AccountLookupCallbackWorker extends BaseWorker { + + @Autowired + private ZeebeClient zeebeClient; + @Autowired + private CamelContext camelContext; + @Autowired + private ObjectMapper objectMapper; + + @Override + public void setup() { + logger.info("## generating " + ACCOUNT_LOOKUP_CALLBACK + "zeebe worker"); + zeebeClient.newWorker().jobType(ACCOUNT_LOOKUP_CALLBACK.getValue()).handler((client, job) -> { + logger.info("Job '{}' started from process '{}' with key {}", job.getType(), job.getBpmnProcessId(), job.getKey()); + Map existingVariables = job.getVariablesAsMap(); + existingVariables.put(ORIGIN_CHANNEL_REQUEST, existingVariables.get(CHANNEL_REQUEST)); + TransactionChannelRequestDTO transactionChannelRequestDTO = objectMapper + .readValue((String) existingVariables.get(CHANNEL_REQUEST), TransactionChannelRequestDTO.class); + String payeeId = existingVariables.get(PAYEE_PARTY_ID).toString(); + String payeeFspId = existingVariables.get(PARTY_LOOKUP_FSP_ID).toString(); + PartyIdInfo partyIdInfo = new PartyIdInfo(transactionChannelRequestDTO.getPayee().getPartyIdInfo().getPartyIdType(), payeeId); + partyIdInfo.setFspId(payeeFspId); + Party payee = new Party(partyIdInfo); + transactionChannelRequestDTO.setPayee(payee); + existingVariables.put(CHANNEL_REQUEST, objectMapper.writeValueAsString(transactionChannelRequestDTO)); + client.newCompleteCommand(job.getKey()).variables(existingVariables).send().join(); + }).name(ACCOUNT_LOOKUP_CALLBACK.getValue()).open(); + } +} diff --git a/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/zeebe/worker/AccountLookupWorker.java b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/zeebe/worker/AccountLookupWorker.java new file mode 100644 index 000000000..6107c6048 --- /dev/null +++ b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/zeebe/worker/AccountLookupWorker.java @@ -0,0 +1,89 @@ +package org.mifos.processor.bulk.zeebe.worker; + +import static org.mifos.processor.bulk.camel.config.CamelProperties.CACHED_TRANSACTION_ID; +import static org.mifos.processor.bulk.camel.config.CamelProperties.HEADER_REGISTERING_INSTITUTE_ID; +import static org.mifos.processor.bulk.camel.config.CamelProperties.HOST; +import static org.mifos.processor.bulk.camel.config.CamelProperties.PAYEE_IDENTITY; +import static org.mifos.processor.bulk.camel.config.CamelProperties.PAYMENT_MODALITY; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.ACCOUNT_LOOKUP_RETRY_COUNT; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.CALLBACK; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.CHANNEL_REQUEST; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.INITIATOR_FSP_ID; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.IS_RTP_REQUEST; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.ORIGIN_DATE; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.TENANT_ID; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.TRANSACTION_ID; +import static org.mifos.processor.bulk.zeebe.worker.Worker.ACCOUNT_LOOKUP; + +import com.fasterxml.jackson.databind.ObjectMapper; +import io.camunda.zeebe.client.ZeebeClient; +import java.util.Map; +import org.apache.camel.CamelContext; +import org.apache.camel.Exchange; +import org.apache.camel.ProducerTemplate; +import org.apache.camel.support.DefaultExchange; +import org.mifos.connector.common.channel.dto.TransactionChannelRequestDTO; +import org.mifos.connector.common.mojaloop.dto.PartyIdInfo; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +@Component +public class AccountLookupWorker extends BaseWorker { + + @Autowired + private ZeebeClient zeebeClient; + + @Autowired + private ProducerTemplate producerTemplate; + @Autowired + private CamelContext camelContext; + @Autowired + private ObjectMapper objectMapper; + @Value("${identity_account_mapper.hostname}") + private String identityMapperURL; + @Value("${identity_account_mapper.account_lookup_callback}") + private String accountLookupCallback; + @Value("${identity_account_mapper.account_lookup}") + private String accountLookupEndpoint; + + @Override + public void setup() { + logger.info("## generating " + ACCOUNT_LOOKUP + "zeebe worker"); + zeebeClient.newWorker().jobType(ACCOUNT_LOOKUP.getValue()).handler((client, job) -> { + logger.info("Job '{}' started from process '{}' with key {}", job.getType(), job.getBpmnProcessId(), job.getKey()); + Map existingVariables = job.getVariablesAsMap(); + logger.info(existingVariables.toString()); + existingVariables.put(ACCOUNT_LOOKUP_RETRY_COUNT, 1); + existingVariables.put(CACHED_TRANSACTION_ID, job.getKey()); + + boolean isTransactionRequest = (boolean) existingVariables.get(IS_RTP_REQUEST); + String tenantId = (String) existingVariables.get(TENANT_ID); + Object channelRequest = existingVariables.get(CHANNEL_REQUEST); + TransactionChannelRequestDTO request = objectMapper.readValue((String) channelRequest, TransactionChannelRequestDTO.class); + + existingVariables.put(INITIATOR_FSP_ID, tenantId); + PartyIdInfo requestedParty = isTransactionRequest ? request.getPayer().getPartyIdInfo() : request.getPayee().getPartyIdInfo(); + + String payeeIdentity = requestedParty.getPartyIdentifier(); + String paymentModality = requestedParty.getPartyIdType().toString(); + + Exchange exchange = new DefaultExchange(camelContext); + exchange.setProperty(HOST, identityMapperURL); + exchange.setProperty(PAYEE_IDENTITY, payeeIdentity); + exchange.setProperty(PAYMENT_MODALITY, paymentModality); + exchange.setProperty(CALLBACK, identityMapperURL + accountLookupCallback); + exchange.setProperty(TRANSACTION_ID, existingVariables.get(TRANSACTION_ID)); + exchange.setProperty("requestId", job.getKey()); + exchange.setProperty(CHANNEL_REQUEST, channelRequest); + exchange.setProperty(ORIGIN_DATE, existingVariables.get(ORIGIN_DATE)); + exchange.setProperty(TENANT_ID, tenantId); + exchange.setProperty(HEADER_REGISTERING_INSTITUTE_ID, existingVariables.get(HEADER_REGISTERING_INSTITUTE_ID)); + producerTemplate.send("direct:send-account-lookup", exchange); + + client.newCompleteCommand(job.getKey()).variables(existingVariables).send(); + }).name(String.valueOf(ACCOUNT_LOOKUP)).open(); + + } + +} diff --git a/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/zeebe/worker/AggregateWorker.java b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/zeebe/worker/AggregateWorker.java new file mode 100644 index 000000000..9bdd5d3fa --- /dev/null +++ b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/zeebe/worker/AggregateWorker.java @@ -0,0 +1,73 @@ +package org.mifos.processor.bulk.zeebe.worker; + +import static org.mifos.processor.bulk.camel.config.CamelProperties.BATCH_STATUS_FAILED; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.BATCH_ID; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.CALLBACK; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.CALLBACK_RETRY; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.CLIENT_CORRELATION_ID; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.COMPLETION_RATE; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.ERROR_CODE; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.ERROR_DESCRIPTION; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.MAX_CALLBACK_RETRY; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.PHASES; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.PHASE_COUNT; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.RETRY; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.TENANT_ID; + +import java.util.Map; +import org.apache.camel.Exchange; +import org.apache.camel.support.DefaultExchange; +import org.mifos.processor.bulk.camel.routes.RouteId; +import org.springframework.stereotype.Component; + +@Component +public class AggregateWorker extends BaseWorker { + + @Override + public void setup() { + // newWorker(Worker.BATCH_STATUS, (client, job) -> { + newWorker(Worker.BATCH_AGGREGATE, (client, job) -> { + logger.info("Started batchAggregateWorker"); + logger.debug("Job '{}' started from process '{}' with key {}", job.getType(), job.getBpmnProcessId(), job.getKey()); + Map variables = job.getVariablesAsMap(); + + int retry = (int) variables.getOrDefault(RETRY, 0); + int successRate = (int) variables.getOrDefault(COMPLETION_RATE, 0); + + Exchange exchange = new DefaultExchange(camelContext); + exchange.setProperty(CLIENT_CORRELATION_ID, variables.get(CLIENT_CORRELATION_ID)); + exchange.setProperty(BATCH_ID, variables.get(BATCH_ID)); + exchange.setProperty(TENANT_ID, variables.get(TENANT_ID)); + exchange.setProperty(MAX_CALLBACK_RETRY, variables.get(MAX_CALLBACK_RETRY)); + exchange.setProperty(CALLBACK_RETRY, variables.getOrDefault(CALLBACK_RETRY, 0)); + exchange.setProperty(CALLBACK, variables.get(CALLBACK)); + // exchange.setProperty(COMPLETION_RATE, variables.get(COMPLETION_RATE)); + exchange.setProperty(PHASES, variables.get(PHASES)); + exchange.setProperty(PHASE_COUNT, variables.get(PHASE_COUNT)); + sendToCamelRoute(RouteId.BATCH_AGGREGATE, exchange); + + Boolean batchStatusFailed = exchange.getProperty(BATCH_STATUS_FAILED, Boolean.class); + if (batchStatusFailed == null || !batchStatusFailed) { + if (exchange.getException() != null && exchange.getException().getMessage() != null + && exchange.getException().getMessage().contains("404")) { + logger.error("An error occurred, retrying"); + successRate = 0; + } else { + successRate = exchange.getProperty(COMPLETION_RATE, Long.class).intValue(); + } + } else { + variables.put(ERROR_CODE, exchange.getProperty(ERROR_CODE)); + variables.put(ERROR_DESCRIPTION, exchange.getProperty(ERROR_DESCRIPTION)); + logger.info("Error: {}, {}", variables.get(ERROR_CODE), variables.get(ERROR_DESCRIPTION)); + } + + variables.put(COMPLETION_RATE, successRate); + variables.put(RETRY, ++retry); + + logger.info("Retry: {} and Success Rate: {}", retry, successRate); + client.newCompleteCommand(job.getKey()).variables(variables).send(); + logger.info("Completed batchAggregateWorker"); + }); + } + +} diff --git a/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/zeebe/worker/ApprovalWorker.java b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/zeebe/worker/ApprovalWorker.java new file mode 100644 index 000000000..302197cf5 --- /dev/null +++ b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/zeebe/worker/ApprovalWorker.java @@ -0,0 +1,25 @@ +package org.mifos.processor.bulk.zeebe.worker; + +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.APPROVAL_FAILED; + +import java.util.Map; +import org.springframework.stereotype.Component; + +@Component +public class ApprovalWorker extends BaseWorker { + + @Override + public void setup() { + newWorker(Worker.APPROVAL, (client, job) -> { + logger.debug("Job '{}' started from process '{}' with key {}", job.getType(), job.getBpmnProcessId(), job.getKey()); + Map variables = job.getVariablesAsMap(); + + if (workerConfig.isApprovalWorkerEnabled) { + variables.put(APPROVAL_FAILED, false); + } + + client.newCompleteCommand(job.getKey()).variables(variables).send(); + }); + } + +} diff --git a/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/zeebe/worker/AuthorizationWorker.java b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/zeebe/worker/AuthorizationWorker.java new file mode 100644 index 000000000..b8f221325 --- /dev/null +++ b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/zeebe/worker/AuthorizationWorker.java @@ -0,0 +1,97 @@ +package org.mifos.processor.bulk.zeebe.worker; + +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.APPROVED_AMOUNT; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.AUTHORIZATION_ACCEPTED; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.AUTHORIZATION_SUCCESSFUL; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.BATCH_ID; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.CLIENT_CORRELATION_ID; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import io.micrometer.core.instrument.util.StringUtils; +import java.util.Map; +import org.mifos.processor.bulk.schema.AuthorizationRequest; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Component; +import org.springframework.web.client.RestTemplate; + +@Component +public class AuthorizationWorker extends BaseWorker { + + @Value("${batch-authorization.callback-url}") + private String callbackURLPath; + + @Value("${mock-payment-schema.contactpoint}") + private String mockPaymentSchemaContactPoint; + + @Value("${mock-payment-schema.endpoints.authorization}") + private String authorizationEndpoint; + + private static final String X_CLIENT_CORRELATION_ID = "X-Client-Correlation-ID"; + + private static final String X_CALLBACK_URL = "X-CallbackURL"; + + @Autowired + ObjectMapper objectMapper; + + @Override + public void setup() { + newWorker(Worker.AUTHORIZATION, (client, job) -> { + logger.info("Job '{}' started from process '{}' with key {}", job.getType(), job.getBpmnProcessId(), job.getKey()); + Map variables = job.getVariablesAsMap(); + + if (!workerConfig.isAuthorizationWorkerEnabled) { + variables.put(AUTHORIZATION_SUCCESSFUL, true); + client.newCompleteCommand(job.getKey()).variables(variables).send(); + return; + } + + logger.debug("Variables: {}", variables); + + String payerIdentifier = (String) variables.get("payerIdentifier"); + String totalBatchAmount = (String) variables.get("partyLookupSuccessfulTransactionAmount"); + String currency = (String) variables.get("currency"); + + String batchId = (String) variables.get(BATCH_ID); + String clientCorrelationId = Long.toString(job.getKey()); + + AuthorizationRequest requestPayload = new AuthorizationRequest(batchId, payerIdentifier, currency, totalBatchAmount); + HttpStatus httpStatus = invokeBatchAuthorizationApi(batchId, requestPayload, clientCorrelationId); + + logger.info("Httpstatus: {}", httpStatus); + + variables.put(APPROVED_AMOUNT, totalBatchAmount); + variables.put(CLIENT_CORRELATION_ID, clientCorrelationId); + variables.put(AUTHORIZATION_ACCEPTED, httpStatus.is2xxSuccessful()); + client.newCompleteCommand(job.getKey()).variables(variables).send(); + }); + } + + private HttpStatus invokeBatchAuthorizationApi(String batchId, AuthorizationRequest requestPayload, String clientCorrelationId) + throws JsonProcessingException { + logger.info("Calling auth API"); + if (StringUtils.isBlank(requestPayload.getAmount())) { + requestPayload.setAmount("0"); + } + RestTemplate restTemplate = new RestTemplate(); + HttpHeaders headers = new HttpHeaders(); + headers.add(X_CLIENT_CORRELATION_ID, clientCorrelationId); + headers.add(X_CALLBACK_URL, callbackURLPath); + + HttpEntity requestEntity = new HttpEntity<>(requestPayload, headers); + String endpoint = mockPaymentSchemaContactPoint + authorizationEndpoint + batchId; + endpoint = endpoint + "?command=authorize"; + + logger.debug("Auth API request headers: {}", headers); + logger.info("MockPaymentSchema endpoint: {}", endpoint); + logger.debug("Body: {}", objectMapper.writeValueAsString(requestPayload)); + ResponseEntity responseEntity = restTemplate.exchange(endpoint, HttpMethod.POST, requestEntity, String.class); + return responseEntity.getStatusCode(); + } +} diff --git a/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/zeebe/worker/BaseWorker.java b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/zeebe/worker/BaseWorker.java new file mode 100644 index 000000000..8262561fe --- /dev/null +++ b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/zeebe/worker/BaseWorker.java @@ -0,0 +1,58 @@ +package org.mifos.processor.bulk.zeebe.worker; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.dataformat.csv.CsvMapper; +import io.camunda.zeebe.client.ZeebeClient; +import io.camunda.zeebe.client.api.worker.JobHandler; +import javax.annotation.PostConstruct; +import org.apache.camel.CamelContext; +import org.apache.camel.Exchange; +import org.apache.camel.ProducerTemplate; +import org.mifos.processor.bulk.camel.routes.RouteId; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +@Component +public abstract class BaseWorker { + + @Autowired + private ZeebeClient zeebeClient; + + @Autowired + private CsvMapper csvMapper; + + @Autowired + private ObjectMapper objectMapper; + + @Value("${application.bucket-name}") + private String bucketName; + + @Value("${zeebe.client.evenly-allocated-max-jobs}") + private int workerMaxJobs; + + @Autowired + protected CamelContext camelContext; + + @Autowired + private ProducerTemplate producerTemplate; + + @Autowired + protected WorkerConfig workerConfig; + + protected Logger logger = LoggerFactory.getLogger(this.getClass()); + + @PostConstruct + public abstract void setup(); + + public void newWorker(Worker worker, JobHandler handler) { + zeebeClient.newWorker().jobType(worker.getValue()).handler(handler).name(worker.getValue()).maxJobsActive(workerMaxJobs).open(); + } + + public void sendToCamelRoute(RouteId routeId, Exchange exchange) { + producerTemplate.send(routeId.getValue(), exchange); + } + +} diff --git a/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/zeebe/worker/BatchAccountLookupCallbackWorker.java b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/zeebe/worker/BatchAccountLookupCallbackWorker.java new file mode 100644 index 000000000..f99c070b2 --- /dev/null +++ b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/zeebe/worker/BatchAccountLookupCallbackWorker.java @@ -0,0 +1,45 @@ +package org.mifos.processor.bulk.zeebe.worker; + +import static org.mifos.processor.bulk.camel.config.CamelProperties.SERVER_FILE_NAME; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.FILE_NAME; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.PARTY_LOOKUP_FAILED; +import static org.mifos.processor.bulk.zeebe.worker.Worker.BATCH_ACCOUNT_LOOKUP_CALLBACK; + +import com.fasterxml.jackson.databind.ObjectMapper; +import io.camunda.zeebe.client.ZeebeClient; +import java.util.Map; +import org.apache.camel.CamelContext; +import org.apache.camel.Exchange; +import org.apache.camel.support.DefaultExchange; +import org.mifos.processor.bulk.camel.routes.RouteId; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component +public class BatchAccountLookupCallbackWorker extends BaseWorker { + + @Autowired + private ZeebeClient zeebeClient; + @Autowired + private CamelContext camelContext; + @Autowired + private ObjectMapper objectMapper; + + @Override + public void setup() { + logger.info("## generating " + BATCH_ACCOUNT_LOOKUP_CALLBACK + "zeebe worker"); + newWorker(BATCH_ACCOUNT_LOOKUP_CALLBACK, ((client, job) -> { + Map variables = job.getVariablesAsMap(); + Exchange exchange = new DefaultExchange(camelContext); + String filename = (String) variables.get(FILE_NAME); + String batchAccountLookupCallback = (String) variables.get("batchAccountLookupCallback"); + variables.put(PARTY_LOOKUP_FAILED, false); + variables.put("batchAccountLookup", true); + exchange.setProperty(SERVER_FILE_NAME, filename); + exchange.setProperty("batchAccountLookupCallback", batchAccountLookupCallback); + exchange.setProperty("workflowInstanceKey", job.getProcessInstanceKey()); + sendToCamelRoute(RouteId.ACCOUNT_LOOKUP_CALLBACK, exchange); + client.newCompleteCommand(job.getKey()).variables(variables).send(); + })); + } +} diff --git a/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/zeebe/worker/BatchAccountLookupWorker.java b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/zeebe/worker/BatchAccountLookupWorker.java new file mode 100644 index 000000000..a4861ba45 --- /dev/null +++ b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/zeebe/worker/BatchAccountLookupWorker.java @@ -0,0 +1,68 @@ +package org.mifos.processor.bulk.zeebe.worker; + +import static org.mifos.processor.bulk.camel.config.CamelProperties.CACHED_TRANSACTION_ID; +import static org.mifos.processor.bulk.camel.config.CamelProperties.HEADER_REGISTERING_INSTITUTE_ID; +import static org.mifos.processor.bulk.camel.config.CamelProperties.REGISTERING_INSTITUTE_ID; +import static org.mifos.processor.bulk.camel.config.CamelProperties.SERVER_FILE_NAME; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.CALLBACK; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.FILE_NAME; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.PARTY_LOOKUP_FAILED; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.REQUEST_ID; +import static org.mifos.processor.bulk.zeebe.worker.Worker.BATCH_ACCOUNT_LOOKUP; + +import com.fasterxml.jackson.databind.ObjectMapper; +import io.camunda.zeebe.client.ZeebeClient; +import java.util.Map; +import org.apache.camel.CamelContext; +import org.apache.camel.Exchange; +import org.apache.camel.ProducerTemplate; +import org.apache.camel.support.DefaultExchange; +import org.mifos.processor.bulk.camel.routes.RouteId; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +@Component +public class BatchAccountLookupWorker extends BaseWorker { + + @Autowired + private ZeebeClient zeebeClient; + + @Autowired + private ProducerTemplate producerTemplate; + @Autowired + private CamelContext camelContext; + @Autowired + private ObjectMapper objectMapper; + @Value("${identity_account_mapper.hostname}") + private String identityMapperURL; + @Value("${bulk-processor.hostname}") + private String bulkURL; + @Value("${identity_account_mapper.batch_account_lookup_callback}") + private String batchAccountLookupCallback; + + @Override + public void setup() { + + newWorker(BATCH_ACCOUNT_LOOKUP, ((client, job) -> { + logger.info("Job '{}' started from process '{}' with key {}", job.getType(), job.getBpmnProcessId(), job.getKey()); + Map variables = job.getVariablesAsMap(); + Exchange exchange = new DefaultExchange(camelContext); + String filename = (String) variables.get(FILE_NAME); + String registeringInstituteId = variables.get(REGISTERING_INSTITUTE_ID).toString(); + logger.info("registeringInstituteId in worker {}", registeringInstituteId); + variables.put(CACHED_TRANSACTION_ID, job.getKey()); + exchange.setProperty(HEADER_REGISTERING_INSTITUTE_ID, registeringInstituteId); + exchange.setProperty(SERVER_FILE_NAME, filename); + exchange.setProperty(REQUEST_ID, job.getKey()); + exchange.setProperty(CALLBACK, identityMapperURL + batchAccountLookupCallback); + + try { + sendToCamelRoute(RouteId.ACCOUNT_LOOKUP, exchange); + } catch (Exception e) { + variables.put(PARTY_LOOKUP_FAILED, true); + } + client.newCompleteCommand(job.getKey()).variables(variables).send(); + })); + } +} diff --git a/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/zeebe/worker/BatchStatusWorker.java b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/zeebe/worker/BatchStatusWorker.java new file mode 100644 index 000000000..600f571bc --- /dev/null +++ b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/zeebe/worker/BatchStatusWorker.java @@ -0,0 +1,71 @@ +package org.mifos.processor.bulk.zeebe.worker; + +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.BATCH_ID; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.COMPLETION_RATE; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.TENANT_ID; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import java.util.Map; +import org.mifos.processor.bulk.OperationsAppConfig; +import org.mifos.processor.bulk.schema.BatchDTO; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.ResponseEntity; +import org.springframework.web.client.RestTemplate; +import org.springframework.web.util.UriComponentsBuilder; + +public class BatchStatusWorker extends BaseWorker { + + @Autowired + public OperationsAppConfig operationsAppConfig; + + @Override + public void setup() { + + newWorker(Worker.BATCH_STATUS, ((client, job) -> { + logger.info("Started batchStatusWorker"); + logger.debug("Job '{}' started from process '{}' with key {}", job.getType(), job.getBpmnProcessId(), job.getKey()); + + Map variables = job.getVariablesAsMap(); + String batchId = (String) variables.get(BATCH_ID); + String tenantId = (String) variables.get(TENANT_ID); + BatchDTO batchDTOResponse = invokeBatchAggregationApi(batchId, tenantId); + float successRate = calculateSuccessPercentage(batchDTOResponse); + variables.put(COMPLETION_RATE, successRate); + client.newCompleteCommand(job.getKey()).variables(variables).send(); + logger.info("Completed batchStatusWorker"); + })); + } + + private float calculateSuccessPercentage(BatchDTO batchDTO) { + if (batchDTO.getTotal() != null && batchDTO.getTotal() != 0) { + return (((float) batchDTO.getSuccessful() / batchDTO.getTotal()) * 100); + } + return 0; + } + + private BatchDTO invokeBatchAggregationApi(String batchId, String tenantId) { + RestTemplate restTemplate = new RestTemplate(); + HttpHeaders headers = new HttpHeaders(); + headers.set("Platform-TenantId", tenantId); + String url = operationsAppConfig.batchSummaryUrl; + + UriComponentsBuilder uriBuilder = UriComponentsBuilder.fromUriString(url).queryParam("batchId", batchId); + String finalUrl = uriBuilder.toUriString(); + + ResponseEntity response = restTemplate.exchange(finalUrl, HttpMethod.GET, new HttpEntity<>(null, headers), String.class); + String batchAggregationResponse = response != null ? response.getBody() : null; + ObjectMapper objectMapper = new ObjectMapper(); + BatchDTO batchDTO = null; + try { + batchDTO = objectMapper.readValue(batchAggregationResponse, BatchDTO.class); + } catch (JsonProcessingException e) { + throw new RuntimeException(e); + } + logger.info("Batch summary response: {}", batchDTO); + return batchDTO; + } +} diff --git a/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/zeebe/worker/DeDuplicationWorker.java b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/zeebe/worker/DeDuplicationWorker.java new file mode 100644 index 000000000..5448dcdd8 --- /dev/null +++ b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/zeebe/worker/DeDuplicationWorker.java @@ -0,0 +1,55 @@ +package org.mifos.processor.bulk.zeebe.worker; + +import static org.mifos.processor.bulk.camel.config.CamelProperties.SERVER_FILE_NAME; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.DE_DUPLICATION_ENABLE; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.DE_DUPLICATION_FAILED; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.DUPLICATE_TRANSACTION_COUNT; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.FAILED_TRANSACTION_FILE; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.FILE_NAME; + +import java.util.Map; +import org.apache.camel.Exchange; +import org.apache.camel.support.DefaultExchange; +import org.mifos.processor.bulk.camel.routes.RouteId; +import org.springframework.stereotype.Component; + +@Component +public class DeDuplicationWorker extends BaseWorker { + + @Override + public void setup() { + newWorker(Worker.DE_DEPLICATION, (client, job) -> { + logger.debug("Job '{}' started from process '{}' with key {}", job.getType(), job.getBpmnProcessId(), job.getKey()); + logger.info("Started {} worker", Worker.DE_DEPLICATION.getValue()); + Map variables = job.getVariablesAsMap(); + + if ((Boolean) variables.get(DE_DUPLICATION_ENABLE)) { + variables.put(DE_DUPLICATION_FAILED, false); + } + + Exchange exchange = new DefaultExchange(camelContext); + + String filename = (String) variables.get(FILE_NAME); + + logger.info("Filename in worker before duplication is: {}", filename); + + exchange.setProperty(SERVER_FILE_NAME, filename); + + sendToCamelRoute(RouteId.DE_DUPLICATION, exchange); + + boolean deDuplicationFailed = (Boolean) exchange.getProperty(DE_DUPLICATION_FAILED); + int duplicateTransactionCount = exchange.getProperty(DUPLICATE_TRANSACTION_COUNT, Integer.class); + if (duplicateTransactionCount > 0) { + // if duplicate txn exist + variables.put(FAILED_TRANSACTION_FILE, exchange.getProperty(FAILED_TRANSACTION_FILE, String.class)); + } + variables.put(DE_DUPLICATION_FAILED, deDuplicationFailed); + variables.put(DUPLICATE_TRANSACTION_COUNT, duplicateTransactionCount); + + logger.debug("Zeebe variables in dedup: {}", variables); + client.newCompleteCommand(job.getKey()).variables(variables).send(); + logger.info("Completed {} worker", Worker.DE_DEPLICATION); + }); + + } +} diff --git a/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/zeebe/worker/FormattingWorker.java b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/zeebe/worker/FormattingWorker.java new file mode 100644 index 000000000..34c40d580 --- /dev/null +++ b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/zeebe/worker/FormattingWorker.java @@ -0,0 +1,50 @@ +package org.mifos.processor.bulk.zeebe.worker; + +import static org.mifos.processor.bulk.camel.config.CamelProperties.SERVER_FILE_NAME; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.FILE_NAME; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.FORMATTING_FAILED; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.FORMATTING_STANDARD; + +import java.util.Map; +import org.apache.camel.Exchange; +import org.apache.camel.support.DefaultExchange; +import org.mifos.processor.bulk.camel.routes.RouteId; +import org.springframework.stereotype.Component; + +@Component +public class FormattingWorker extends BaseWorker { + + @Override + public void setup() { + + /** + * Starts the new worker for formatting of the data. Performs below tasks 1. Downloads the file from cloud. 2. + * Parse the data into POJO. 3. Format the data based on field configured in application.yaml 4. Uploads the + * updated file in cloud + */ + newWorker(Worker.FORMATTING, (client, job) -> { + logger.debug("Job '{}' started from process '{}' with key {}", job.getType(), job.getBpmnProcessId(), job.getKey()); + Map variables = job.getVariablesAsMap(); + if (workerConfig.isFormattingWorkerEnabled) { + variables.put(FORMATTING_FAILED, false); + } + + String filename = (String) variables.get(FILE_NAME); + Exchange exchange = new DefaultExchange(camelContext); + exchange.setProperty(SERVER_FILE_NAME, filename); + + try { + sendToCamelRoute(RouteId.FORMATTING, exchange); + assert !exchange.getProperty(FORMATTING_FAILED, Boolean.class); + } catch (Exception e) { + variables.put(FORMATTING_FAILED, true); + } + + variables.put(FORMATTING_FAILED, false); + variables.put(FORMATTING_STANDARD, exchange.getProperty(FORMATTING_STANDARD)); + + client.newCompleteCommand(job.getKey()).variables(variables).send(); + }); + } + +} diff --git a/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/zeebe/worker/InitSubBatchWorker.java b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/zeebe/worker/InitSubBatchWorker.java new file mode 100644 index 000000000..2f31567df --- /dev/null +++ b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/zeebe/worker/InitSubBatchWorker.java @@ -0,0 +1,113 @@ +package org.mifos.processor.bulk.zeebe.worker; + +import static org.mifos.processor.bulk.camel.config.CamelProperties.SERVER_FILE_NAME; +import static org.mifos.processor.bulk.camel.config.CamelProperties.SUB_BATCH_DETAILS; +import static org.mifos.processor.bulk.camel.config.CamelProperties.SUB_BATCH_ENTITY; +import static org.mifos.processor.bulk.camel.config.CamelProperties.TENANT_NAME; +import static org.mifos.processor.bulk.camel.config.CamelProperties.ZEEBE_VARIABLE; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.BATCH_ID; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.FILE_NAME; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.INIT_FAILURE_SUB_BATCHES; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.INIT_SUB_BATCH_FAILED; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.INIT_SUCCESS_SUB_BATCHES; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.PURPOSE; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.REMAINING_SUB_BATCH; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.REQUEST_ID; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.SPLITTING_ENABLED; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.SUB_BATCHES; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.TENANT_ID; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import org.apache.camel.Exchange; +import org.apache.camel.support.DefaultExchange; +import org.mifos.processor.bulk.camel.routes.RouteId; +import org.mifos.processor.bulk.schema.SubBatchEntity; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component +public class InitSubBatchWorker extends BaseWorker { + + @Autowired + private ObjectMapper objectMapper; + + @Override + public void setup() { + + /** + * Starts the new worker for initialising sub batches. Performs below tasks 1. Downloads the file from cloud. 2. + * Parse the data into POJO. 3. Initiates workflow based on the payment_mode + */ + newWorker(Worker.INIT_SUB_BATCH, (client, job) -> { + logger.info("Started INIT_SUB_BATCH worker"); + logger.debug("Job '{}' started from process '{}' with key {}", job.getType(), job.getBpmnProcessId(), job.getKey()); + Map variables = job.getVariablesAsMap(); + + List subBatches = (List) variables.get(SUB_BATCHES); + if (subBatches == null) { + subBatches = new ArrayList<>(); + } + List successSubBatches = (List) variables.get(INIT_SUCCESS_SUB_BATCHES); + if (successSubBatches == null) { + successSubBatches = new ArrayList<>(); + } + List failureSubBatches = (List) variables.get(INIT_FAILURE_SUB_BATCHES); + if (failureSubBatches == null) { + failureSubBatches = new ArrayList<>(); + } + boolean isSplittingEnabled = (boolean) variables.get(SPLITTING_ENABLED); + + if (!isSplittingEnabled) { + subBatches.add((String) variables.get(FILE_NAME)); + } + + List subBatchObjectList = (List) variables.get(SUB_BATCH_DETAILS); + logger.debug("Subbatch entity list in init sub batch worker: {}", subBatchObjectList); + + List subBatchEntityList = objectMapper.convertValue(subBatchObjectList, new TypeReference<>() {}); + + String fileName = subBatches.remove(0); + SubBatchEntity subBatchEntity = null; + if (isSplittingEnabled) { + for (SubBatchEntity subBatch : subBatchEntityList) { + if (subBatch.getRequestFile().contains(fileName)) { + subBatchEntity = subBatch; + logger.info("SubBatchEntity found"); + break; + } + } + logger.debug("BatchEntity for this subbatch is {}", objectMapper.writeValueAsString(subBatchEntity)); + } + Exchange exchange = new DefaultExchange(camelContext); + exchange.setProperty(TENANT_NAME, variables.get(TENANT_ID)); + exchange.setProperty(SERVER_FILE_NAME, fileName); + exchange.setProperty(BATCH_ID, variables.get(BATCH_ID)); + exchange.setProperty(REQUEST_ID, variables.get(REQUEST_ID)); + exchange.setProperty(PURPOSE, variables.get(PURPOSE)); + exchange.setProperty(ZEEBE_VARIABLE, variables); + exchange.setProperty(SUB_BATCH_ENTITY, subBatchEntity); + + sendToCamelRoute(RouteId.INIT_SUB_BATCH, exchange); + + Boolean subBatchFailed = exchange.getProperty(INIT_SUB_BATCH_FAILED, Boolean.class); + if (subBatchFailed != null && subBatchFailed) { + failureSubBatches.add(fileName); + } else { + successSubBatches.add(fileName); + } + + variables.put(REMAINING_SUB_BATCH, subBatches.size()); + variables.put(SUB_BATCHES, subBatches); + variables.put(INIT_SUCCESS_SUB_BATCHES, successSubBatches); + variables.put(INIT_FAILURE_SUB_BATCHES, failureSubBatches); + + client.newCompleteCommand(job.getKey()).variables(variables).send(); + logger.info("Completed INIT_SUB_BATCH worker. Remaining subbatches {}", subBatches.size()); + }); + } + +} diff --git a/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/zeebe/worker/MergeBackWorker.java b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/zeebe/worker/MergeBackWorker.java new file mode 100644 index 000000000..fd55824f2 --- /dev/null +++ b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/zeebe/worker/MergeBackWorker.java @@ -0,0 +1,81 @@ +package org.mifos.processor.bulk.zeebe.worker; + +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.BATCH_ID; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.INIT_FAILURE_SUB_BATCHES; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.INIT_SUCCESS_SUB_BATCHES; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.MERGE_COMPLETED; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.MERGE_FAILED; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.MERGE_FILE_LIST; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.MERGE_ITERATION; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.RESULT_FILE; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.SUB_BATCHES; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import org.apache.camel.Exchange; +import org.apache.camel.support.DefaultExchange; +import org.mifos.processor.bulk.camel.routes.RouteId; +import org.springframework.stereotype.Component; + +@Component +public class MergeBackWorker extends BaseWorker { + + @Override + public void setup() { + newWorker(Worker.MERGE_BACK, (client, job) -> { + logger.debug("Job '{}' started from process '{}' with key {}", job.getType(), job.getBpmnProcessId(), job.getKey()); + Map variables = job.getVariablesAsMap(); + if (workerConfig.isMergeBackWorkerEnabled) { + variables.put(MERGE_FAILED, false); + } + + int mergeIteration = (int) variables.getOrDefault(MERGE_ITERATION, 1); + List subBatches = (List) variables.get(SUB_BATCHES); + List successSubBatches = (List) variables.get(INIT_SUCCESS_SUB_BATCHES); + List failureSubBatches = (List) variables.get(INIT_FAILURE_SUB_BATCHES); + + for (int i = 0; i < successSubBatches.size(); i++) { + String initFile = successSubBatches.remove(i); + successSubBatches.add(i, String.format("Result_%s", initFile)); + } + for (int i = 0; i < failureSubBatches.size(); i++) { + String initFile = failureSubBatches.remove(i); + failureSubBatches.add(i, String.format("Result_%s", initFile)); + } + + List mergeFileList = (List) variables.get(MERGE_FILE_LIST); + if (mergeFileList == null) { + mergeFileList = new ArrayList<>(); + mergeFileList.addAll(successSubBatches); + mergeFileList.addAll(failureSubBatches); + mergeFileList.addAll(subBatches); + } + + Exchange exchange = new DefaultExchange(camelContext); + exchange.setProperty(MERGE_FILE_LIST, mergeFileList); + exchange.setProperty(MERGE_ITERATION, mergeIteration); + exchange.setProperty(BATCH_ID, variables.get(BATCH_ID)); + + logger.info("Merge list: {}", mergeFileList); + + sendToCamelRoute(RouteId.MERGE_BACK, exchange); + + boolean mergeCompleted = exchange.getProperty(MERGE_COMPLETED, Boolean.class); + if (mergeCompleted) { + variables.put(MERGE_FAILED, exchange.getProperty(MERGE_FAILED, Boolean.class)); + String resultFile = exchange.getProperty(RESULT_FILE, String.class); + if (resultFile != null && !resultFile.isEmpty()) { + variables.put(RESULT_FILE, resultFile); + } + } + + variables.put(MERGE_FILE_LIST, exchange.getProperty(MERGE_FILE_LIST, List.class)); + variables.put(MERGE_COMPLETED, mergeCompleted); + variables.put(MERGE_ITERATION, ++mergeIteration); + + client.newCompleteCommand(job.getKey()).variables(variables).send(); + }); + } + +} diff --git a/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/zeebe/worker/OrderingWorker.java b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/zeebe/worker/OrderingWorker.java new file mode 100644 index 000000000..d8970e776 --- /dev/null +++ b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/zeebe/worker/OrderingWorker.java @@ -0,0 +1,105 @@ +package org.mifos.processor.bulk.zeebe.worker; + +import static org.mifos.processor.bulk.camel.config.CamelProperties.SERVER_FILE_NAME; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.FILE_NAME; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.ORDERED_BY; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.ORDERING_FAILED; + +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import org.apache.camel.Exchange; +import org.apache.camel.support.DefaultExchange; +import org.mifos.processor.bulk.camel.routes.RouteId; +import org.mifos.processor.bulk.schema.Transaction; +import org.springframework.stereotype.Component; + +@Component +public class OrderingWorker extends BaseWorker { + + @Override + public void setup() { + + /** + * This worker is responsible for ordering the data set based on field configuration. Performs below tasks. 1. + * Downloads the file from cloud. 2. Parse the data into POJO. 3. Re-order the data based on field configured in + * application.yaml 4. Uploads the updated file in cloud + */ + newWorker(Worker.ORDERING, (client, job) -> { + logger.debug("Job '{}' started from process '{}' with key {}", job.getType(), job.getBpmnProcessId(), job.getKey()); + Map variables = job.getVariablesAsMap(); + Exchange exchange = new DefaultExchange(camelContext); + + if (workerConfig.isOrderingWorkerEnabled) { + variables.put(ORDERING_FAILED, false); + String filename = (String) variables.get(FILE_NAME); + exchange.setProperty(SERVER_FILE_NAME, filename); + + try { + sendToCamelRoute(RouteId.ORDERING, exchange); + assert !exchange.getProperty(ORDERING_FAILED, Boolean.class); + } catch (Exception e) { + variables.put(ORDERING_FAILED, true); + } + variables.put(ORDERING_FAILED, false); + variables.put(ORDERED_BY, exchange.getProperty(ORDERED_BY)); + } + client.newCompleteCommand(job.getKey()).variables(variables).send(); + }); + } + + private void removeDuplicates(List transactionList, boolean orderingEnabled) { + if (orderingEnabled) { + removeDuplicatesIfOrderingEnabled(transactionList); + return; + } + removeDuplicatesIfOrderingDisabled(transactionList); + } + + private void removeDuplicatesIfOrderingEnabled(List transactionList) { + + for (int i = 0; i < transactionList.size() - 1; i++) { + Transaction currentTransaction = transactionList.get(i); + Transaction nextTransaction = transactionList.get(i + 1); + + if (currentTransaction == null || nextTransaction == null) { + continue; + } + String currentPayeeDetail = fetchPayeeDetail(currentTransaction); + String nextPayeeDetail = fetchPayeeDetail(nextTransaction); + + if (currentPayeeDetail.equals(nextPayeeDetail)) { + currentTransaction.setNote("Duplicate transaction."); + } + } + } + + private void removeDuplicatesIfOrderingDisabled(List transactionList) { + Set set = new HashSet<>(); + + if (Objects.isNull(transactionList)) { + return; + } + + for (Transaction transaction : transactionList) { + String payeeDetail = fetchPayeeDetail(transaction); + if (set.contains(payeeDetail)) { + transaction.setNote("Duplicate transaction."); + } else { + set.add(payeeDetail); + } + } + } + + private String fetchPayeeDetail(Transaction transaction) { + String payeeIdentifier = transaction.getPayeeIdentifier(); + String payeeIdentifierType = transaction.getPayeeIdentifierType(); + String amount = transaction.getAmount(); + String currency = transaction.getCurrency(); + + return String.format("%s%s%s%s", payeeIdentifier, payeeIdentifierType, amount, currency); + } + +} diff --git a/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/zeebe/worker/PartyLookupWorker.java b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/zeebe/worker/PartyLookupWorker.java new file mode 100644 index 000000000..0b8a03017 --- /dev/null +++ b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/zeebe/worker/PartyLookupWorker.java @@ -0,0 +1,25 @@ +package org.mifos.processor.bulk.zeebe.worker; + +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.PARTY_LOOKUP_FAILED; + +import java.util.Map; +import org.springframework.stereotype.Component; + +@Component +public class PartyLookupWorker extends BaseWorker { + + @Override + public void setup() { + newWorker(Worker.PARTY_LOOKUP, (client, job) -> { + logger.debug("Job '{}' started from process '{}' with key {}", job.getType(), job.getBpmnProcessId(), job.getKey()); + Map variables = job.getVariablesAsMap(); + + if (workerConfig.isPartyLookUpWorkerEnabled) { + variables.put(PARTY_LOOKUP_FAILED, false); + } + + client.newCompleteCommand(job.getKey()).variables(variables).send(); + }); + } + +} diff --git a/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/zeebe/worker/SendCallbackWorker.java b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/zeebe/worker/SendCallbackWorker.java new file mode 100644 index 000000000..723e64b26 --- /dev/null +++ b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/zeebe/worker/SendCallbackWorker.java @@ -0,0 +1,78 @@ +package org.mifos.processor.bulk.zeebe.worker; + +import static org.mifos.processor.bulk.camel.config.CamelProperties.CALLBACK_RESPONSE_CODE; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.BATCH_ID; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.CALLBACK; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.CALLBACK_RETRY; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.CALLBACK_SUCCESS; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.CLIENT_CORRELATION_ID; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.COMPLETION_RATE; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.COMPLETION_THRESHOLD; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.ERROR_CODE; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.ERROR_DESCRIPTION; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.MAX_CALLBACK_RETRY; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.MAX_STATUS_RETRY; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.PHASES; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.PHASE_COUNT; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.RETRY; + +import java.util.Map; +import org.apache.camel.Exchange; +import org.apache.camel.support.DefaultExchange; +import org.mifos.processor.bulk.camel.routes.RouteId; +import org.springframework.stereotype.Component; + +@Component +public class SendCallbackWorker extends BaseWorker { + + @Override + public void setup() { + newWorker(Worker.SEND_CALLBACK, (client, job) -> { + logger.debug("Job '{}' started from process '{}' with key {}", job.getType(), job.getBpmnProcessId(), job.getKey()); + Map variables = job.getVariablesAsMap(); + + int retry = variables.getOrDefault(CALLBACK_RETRY, 0).equals(variables.get(MAX_STATUS_RETRY)) ? 0 + : (int) variables.getOrDefault(CALLBACK_RETRY, 0); + Exchange exchange = new DefaultExchange(camelContext); + if (variables.get(CALLBACK_RETRY) != null && variables.get(CALLBACK_RETRY).equals(variables.get(MAX_CALLBACK_RETRY))) { + exchange.setProperty(CALLBACK_SUCCESS, false); + exchange.setProperty(CALLBACK_RESPONSE_CODE, variables.get(CALLBACK_RESPONSE_CODE)); + } else { + exchange = new DefaultExchange(camelContext); + exchange.setProperty(MAX_CALLBACK_RETRY, variables.get(MAX_CALLBACK_RETRY)); + exchange.setProperty(CALLBACK_RETRY, variables.getOrDefault(CALLBACK_RETRY, 0)); + exchange.setProperty(CALLBACK, variables.get(CALLBACK)); + exchange.setProperty(COMPLETION_RATE, variables.get(COMPLETION_RATE)); + exchange.setProperty(PHASES, variables.get(PHASES)); + exchange.setProperty(PHASE_COUNT, variables.get(PHASE_COUNT)); + exchange.setProperty(BATCH_ID, variables.get(BATCH_ID)); + exchange.setProperty(CLIENT_CORRELATION_ID, variables.get(CLIENT_CORRELATION_ID)); + Integer maxRetry = Integer.parseInt(variables.get(MAX_STATUS_RETRY).toString()); + Integer completionRate = Integer.parseInt(variables.get(COMPLETION_RATE).toString()); + Integer completionThreshold = Integer.parseInt(variables.get(COMPLETION_THRESHOLD).toString()); + Integer statusRetry = Integer.parseInt(variables.get(RETRY).toString()); + if (statusRetry >= maxRetry || completionRate >= completionThreshold) { + sendToCamelRoute(RouteId.SEND_CALLBACK, exchange); + } + } + Boolean callbackSuccess = exchange.getProperty(CALLBACK_SUCCESS, Boolean.class); + if (callbackSuccess == null || !callbackSuccess) { + variables.put(ERROR_CODE, exchange.getProperty(ERROR_CODE)); + variables.put(ERROR_DESCRIPTION, exchange.getProperty(ERROR_DESCRIPTION)); + logger.info("Error: {}, {}", variables.get(ERROR_CODE), variables.get(ERROR_DESCRIPTION)); + } else { + variables.put(CALLBACK_SUCCESS, true); + } + + variables.put(CALLBACK_RETRY, exchange.getProperty(CALLBACK_RETRY)); + variables.put(CALLBACK_RESPONSE_CODE, exchange.getProperty(CALLBACK_RESPONSE_CODE)); + variables.put(PHASE_COUNT, exchange.getProperty(PHASE_COUNT)); + variables.put(PHASES, exchange.getProperty(PHASES)); + + logger.debug("Retry: {} and Response Code {}", exchange.getProperty(CALLBACK_RETRY), + exchange.getProperty(CALLBACK_RESPONSE_CODE)); + client.newCompleteCommand(job.getKey()).variables(variables).send(); + }); + } + +} diff --git a/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/zeebe/worker/SplittingWorker.java b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/zeebe/worker/SplittingWorker.java new file mode 100644 index 000000000..f3bd3088b --- /dev/null +++ b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/zeebe/worker/SplittingWorker.java @@ -0,0 +1,80 @@ +package org.mifos.processor.bulk.zeebe.worker; + +import static org.mifos.processor.bulk.camel.config.CamelProperties.SERVER_FILE_NAME; +import static org.mifos.processor.bulk.camel.config.CamelProperties.SERVER_SUB_BATCH_FILE_NAME_ARRAY; +import static org.mifos.processor.bulk.camel.config.CamelProperties.SUB_BATCH_CREATED; +import static org.mifos.processor.bulk.camel.config.CamelProperties.SUB_BATCH_DETAILS; +import static org.mifos.processor.bulk.camel.config.CamelProperties.ZEEBE_VARIABLE; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.FILE_NAME; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.INIT_FAILURE_SUB_BATCHES; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.INIT_SUCCESS_SUB_BATCHES; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.PARTY_LOOKUP_FAILED; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.SPLITTING_FAILED; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.SUB_BATCHES; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import org.apache.camel.Exchange; +import org.apache.camel.support.DefaultExchange; +import org.mifos.processor.bulk.camel.routes.RouteId; +import org.mifos.processor.bulk.schema.SubBatchEntity; +import org.springframework.stereotype.Component; + +@Component +public class SplittingWorker extends BaseWorker { + + @Override + public void setup() { + + /** + * This worker performs below tasks 1. Downloads the original CSV from cloud 2. Splits entire CSV into multiple + * CSV of sub-batches, based on configured sub-batch size. 3. Uploads the sub-batch CSVs to cloud 4. Sets + * zeebeVariable [SPLITTING_FAILED, SUB_BATCHES, SUB_BATCH_CREATED] + */ + newWorker(Worker.SPLITTING, (client, job) -> { + logger.info("Job '{}' started from process '{}' with key {}", job.getType(), job.getBpmnProcessId(), job.getKey()); + Map variables = job.getVariablesAsMap(); + if (workerConfig.isSplittingWorkerEnabled) { + variables.put(SPLITTING_FAILED, false); + } + + String filename = (String) variables.get(FILE_NAME); + Boolean partyLookupFailed = (Boolean) variables.get(PARTY_LOOKUP_FAILED); + Exchange exchange = new DefaultExchange(camelContext); + exchange.setProperty(SERVER_FILE_NAME, filename); + exchange.setProperty(ZEEBE_VARIABLE, variables); + exchange.setProperty("partyLookupFailed", partyLookupFailed); + exchange.setProperty("batchAccountLookup", + variables.get("batchAccountLookup") != null ? variables.get("batchAccountLookup") : false); + + exchange.setProperty(SUB_BATCH_DETAILS, new ArrayList()); + + try { + sendToCamelRoute(RouteId.SPLITTING, exchange); + assert !exchange.getProperty(SPLITTING_FAILED, Boolean.class); + } catch (Exception e) { + variables.put(SPLITTING_FAILED, true); + } + + Boolean subBatchCreated = exchange.getProperty(SUB_BATCH_CREATED, Boolean.class); + List serverSubBatchFileList = exchange.getProperty(SERVER_SUB_BATCH_FILE_NAME_ARRAY, List.class); + if (subBatchCreated != null && !subBatchCreated && serverSubBatchFileList != null && serverSubBatchFileList.isEmpty()) { + // if no sub-batches is created, insert the original filename in sub batch array + serverSubBatchFileList.add(filename); + subBatchCreated = false; + } + + variables.put(SPLITTING_FAILED, false); + variables.put(SUB_BATCHES, serverSubBatchFileList); + variables.put(SUB_BATCH_DETAILS, exchange.getProperty(SUB_BATCH_DETAILS, ArrayList.class)); + variables.put(INIT_SUCCESS_SUB_BATCHES, new ArrayList()); + variables.put(INIT_FAILURE_SUB_BATCHES, new ArrayList()); + variables.put(SUB_BATCH_CREATED, subBatchCreated); + + client.newCompleteCommand(job.getKey()).variables(variables).send(); + logger.info("Splitting worker completed"); + }); + } + +} diff --git a/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/zeebe/worker/Worker.java b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/zeebe/worker/Worker.java new file mode 100644 index 000000000..f508dca59 --- /dev/null +++ b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/zeebe/worker/Worker.java @@ -0,0 +1,21 @@ +package org.mifos.processor.bulk.zeebe.worker; + +public enum Worker { + + PARTY_LOOKUP("partyLookup"), APPROVAL("approval"), ORDERING("ordering"), SPLITTING("splitting"), FORMATTING("formatting"), BATCH_STATUS( + "batchStatus"), SEND_CALLBACK("sendCallback"), MERGE_BACK("mergeSubBatch"), INIT_SUB_BATCH("initSubBatch"), ACCOUNT_LOOKUP( + "accountLookup"), ACCOUNT_LOOKUP_CALLBACK("accountLookupCallback"), BATCH_AGGREGATE("batchAggregate"), AUTHORIZATION( + "authorization"), DE_DEPLICATION("deduplicate"), BATCH_ACCOUNT_LOOKUP( + "batchAccountLookup"), BATCH_ACCOUNT_LOOKUP_CALLBACK("batchAccountLookupCallback"); + + private final String value; + + Worker(String s) { + value = s; + } + + public String getValue() { + return value; + } + +} diff --git a/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/zeebe/worker/WorkerConfig.java b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/zeebe/worker/WorkerConfig.java new file mode 100644 index 000000000..29da28403 --- /dev/null +++ b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/bulk/zeebe/worker/WorkerConfig.java @@ -0,0 +1,39 @@ +package org.mifos.processor.bulk.zeebe.worker; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +@Component +public class WorkerConfig { + + @Value("${config.batchAggregate.enable}") + public boolean isBatchAggregateEnabled; + + @Value("${config.partylookup.enable}") + public boolean isPartyLookUpWorkerEnabled; + + @Value("${config.approval.enable}") + public boolean isApprovalWorkerEnabled; + + @Value("${config.ordering.enable}") + public boolean isOrderingWorkerEnabled; + + @Value("${config.splitting.enable}") + public boolean isSplittingWorkerEnabled; + + @Value("${config.formatting.enable}") + public boolean isFormattingWorkerEnabled; + + @Value("${config.mergeback.enable}") + public boolean isMergeBackWorkerEnabled; + + @Value("${config.completion-threshold-check.enable}") + public boolean isCompletionThresholdCheckEnabled; + + @Value("${config.deduplication.enabled}") + public boolean isTransactionDeduplicationEnabled; + + @Value("${config.authorization.enabled}") + public boolean isAuthorizationWorkerEnabled; + +} diff --git a/ph-ee-bulk-processor/src/main/java/org/mifos/processor/exceptionmapper/GlobalExceptionMapper.java b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/exceptionmapper/GlobalExceptionMapper.java new file mode 100644 index 000000000..5b35c2881 --- /dev/null +++ b/ph-ee-bulk-processor/src/main/java/org/mifos/processor/exceptionmapper/GlobalExceptionMapper.java @@ -0,0 +1,25 @@ +package org.mifos.processor.exceptionmapper; + +import io.camunda.zeebe.client.api.command.ClientStatusException; +import org.mifos.processor.bulk.schema.ExceptionMapperDTO; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.RestControllerAdvice; + +@RestControllerAdvice +public class GlobalExceptionMapper { + + @ExceptionHandler(ClientStatusException.class) + public ResponseEntity handleClientStatusException(ClientStatusException ex) { + ExceptionMapperDTO dto = new ExceptionMapperDTO("01", "Process definition not found"); + return ResponseEntity.status(HttpStatus.PRECONDITION_FAILED).contentType(MediaType.APPLICATION_JSON).body(dto); + } + + @ExceptionHandler(Exception.class) + public ResponseEntity handleException(Exception ex) { + ExceptionMapperDTO dto = new ExceptionMapperDTO("01", ex.getMessage()); + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).contentType(MediaType.APPLICATION_JSON).body(dto); + } +} diff --git a/ph-ee-bulk-processor/src/main/resources/application-paymentmode.yaml b/ph-ee-bulk-processor/src/main/resources/application-paymentmode.yaml new file mode 100644 index 000000000..3159888ac --- /dev/null +++ b/ph-ee-bulk-processor/src/main/resources/application-paymentmode.yaml @@ -0,0 +1,15 @@ +payment-mode: + mappings: + - id: "GSMA" + type: "PAYMENT" + endpoint: "/channel/gsma/transfer" + - id: "MOJALOOP" + type: "PAYMENT" + endpoint: "/channel/transfer" + - id: "SLCB" + type: "BULK" + endpoint: "bulk_connector_{MODE}-{dfspid}" + - id: "CLOSEDLOOP" + type: "BULK" + endpoint: "bulk_connector_{MODE}-{dfspid}" + debulkingDfspid: "lion" \ No newline at end of file diff --git a/ph-ee-bulk-processor/src/main/resources/application-test.yaml b/ph-ee-bulk-processor/src/main/resources/application-test.yaml new file mode 100644 index 000000000..2b80f7858 --- /dev/null +++ b/ph-ee-bulk-processor/src/main/resources/application-test.yaml @@ -0,0 +1,9 @@ +camel: + server-port: 5002 + +kafka: + bootstrapAddress: "localhost:9092" + +zeebe: + broker: + contactpoint: "localhost:26500" diff --git a/ph-ee-bulk-processor/src/main/resources/application.yaml b/ph-ee-bulk-processor/src/main/resources/application.yaml new file mode 100644 index 000000000..8ed37cf50 --- /dev/null +++ b/ph-ee-bulk-processor/src/main/resources/application.yaml @@ -0,0 +1,237 @@ +camel: + server-port: 5000 + disable-ssl: false + springboot: + main-run-controller: true + dataformat: + json-jackson: + auto-discover-object-mapper: true + +kafka: + bootstrapAddress: "kafka:9092" + topic: + gsma: + name: gsma + slcb: + name: slcb + +application: + bucket-name: paymenthub-ee + +zeebe: + client: + max-execution-threads: 50 + evenly-allocated-max-jobs: 1000 + poll-interval: 10 + # max-execution-threads: 100 + # number-of-workers: 8 + # evenly-allocated-max-jobs: "#{${zeebe.client.max-execution-threads} / ${zeebe.client.number-of-workers}}" + broker: + contactpoint: "zeebe-zeebe-gateway:26500" + +operations-app: + contactpoint: "https://ops-bk.sandbox.mifos.io" + username: "mifos" + password: "password" + endpoints: + auth: "/oauth/token" + batch-summary: "/api/v1/batch" + batch-transaction: "/api/v1/batch/transactions" + batch-aggregate: "/api/v1/batch/" + +mock-payment-schema: + contactpoint: "http://ph-ee-connector-mock-payment-schema:8080" + endpoints: + authorization: "/batches/" + +channel: + hostname: "https://ph-ee-connector-channel:8443" + +cloud: + aws: + enabled: true + s3BaseUrl: "https://s3.ap-south-1.amazonaws.com" + credentials: + access-key: ${AWS_ACCESS_KEY:access_key_from_aws} + secret-key: ${AWS_SECRET_KEY:secret_key_from_aws} + + region: + static: ap-south-1 + stack: + auto: false + azure: + enabled: false + blob: + connection-string: + + +tenants: "ibank-usa,ibank-india" + +bpmn: + flows: + payment-transfer: "PayerFundTransfer-{dfspid}" + transaction-request: "PayeeTransactionRequest-{dfspid}" + party-registration: "PartyRegistration-{dfspid}" + gsma-base-transaction: "gsma_base_transaction-{dfspid}" + gsma-int-transfer: "gsma_int_transfer-{dfspid}" + gsma-payee-process: "gsma_payee_process" + gsma-bill-payment: "gsma_bill_payment" + gsma-link-based-payment: "gsma_link_transfer" + international-remittance-payee: "international_remittance_payee_process-{dfspid}" + international-remittance-payer: "international_remittance_payer_process-{dfspid}" + debit-party-process: "debit_party_process-{dfspid}" + bulk-processor: "bulk_processor-{dfspid}" + slcb: "slcb-{dfspid}" + +#payment mode moved to a separate application property file for helm rewrite + +config: + minimum-successful-tx-ratio: 0.90 + batchAggregate: + enable: true + partylookup: + enable: true + authorization: + enabled: true + approval: + enable: true + ordering: + enable: true + field: "payerIdentifier" + splitting: + enable: true + sub-batch-size: 5 + formatting: + enable: false + standard: "DEFAULT" + mergeback: + enable: false + backpressure: + enable: false + completion-threshold-check: + enable: false + completion-threshold: 95 # in percentage + max-retry: 3 #can be as high as 30 + delay: 2 # in seconds + deduplication: + enabled: true + +callback: + max-retry: 3 + url: "http://httpstat.us/503" + +pollingApi: + path : "/batch/Summary/" + timer: "120" + +callback-phases: + values: + - 20 + - 40 + - 60 + - 80 + - 100 + +server: + ssl: + key-alias: "tomcat-https" + key-store: "classpath:keystore.jks" + key-store-type: JKS + key-password: "password" + key-store-password: "password" + port: 8443 + + +security: + jws: + enable: true + response: + enable: true + +identity_account_mapper: + hostname : "http://ph-ee-identity-account-mapper:80" + account_lookup: /beneficiary + account_lookup_callback: /accountLookupCallback + batch_account_lookup: /accountLookup + batch_account_lookup_callback: /batchAccountLookupCallback + +bulk_processor: + hostname : "https://ph-ee-connector-bulk:8443" + +csv: + columnNames: "id,request_id,payment_mode,payer_identifier_type,payer_identifier,payee_identifier_type,payee_identifier,amount,currency,note,account_number,program_shortcode,cycle,payee_dfsp_id,batch_id" + size : 100000 # in bytes + +budget-account: + registeringInstitutions: + - id: "123" + programs: + - id: "SocialWelfare" + name: "Social Welfare" + identifierType: "ACCOUNT" + identifierValue: "123456789" + + +management: + endpoint: + health: + enabled: true + probes: + enabled: true + liveness: + enabled: true + readiness: + enabled: true + +payment-mode: + mappings: + - id: "GSMA" + type: "PAYMENT" + endpoint: "/channel/gsma/transfer" + - id: "MOJALOOP" + type: "PAYMENT" + endpoint: "/channel/transfer" + - id: "SLCB" + type: "BULK" + endpoint: "bulk_connector_{MODE}-{dfspid}" + - id: "CLOSEDLOOP" + type: "BULK" + endpoint: "bulk_connector_{MODE}-{dfspid}" + debulkingDfspid: "wakanda" +batch-authorization: + callback-url: "https://ph-ee-connector-bulk:8443/authorization/callback" + +pubsub: + room: + code: "covid-19" + class: "GOV" + event: + type: "bulk" + +security-server: + country: "INDIA" + organisation: mifos + host: https://SECURITYSERVER + baseuri: /r1/{country}/GOV/{orgs} + endpoints: + subs: /room/subs + +gov-stack-client: + header-key: "X-GovStack-Client" + header-value: "PAYMENT-BB" + + +bpmns: + tenants: + - id: "gorilla" + flows: + batch-transactions: "bulk_processor-{dfspid}" + - id: "wakanda" + flows: + batch-transactions: "bulk_processor-{dfspid}" + - id: "rhino" + flows: + batch-transactions: "bulk_processor_account_lookup-{dfspid}" + - id: "lion" + flows: + batch-transactions: "bulk_processor-{dfspid}" \ No newline at end of file diff --git a/ph-ee-bulk-processor/src/main/resources/keystore.jks b/ph-ee-bulk-processor/src/main/resources/keystore.jks new file mode 100644 index 000000000..f0040c545 Binary files /dev/null and b/ph-ee-bulk-processor/src/main/resources/keystore.jks differ diff --git a/ph-ee-bulk-processor/src/test/java/org/mifos/processor/BulkProcessorApplicationTests.java b/ph-ee-bulk-processor/src/test/java/org/mifos/processor/BulkProcessorApplicationTests.java new file mode 100644 index 000000000..a6473dd90 --- /dev/null +++ b/ph-ee-bulk-processor/src/test/java/org/mifos/processor/BulkProcessorApplicationTests.java @@ -0,0 +1,21 @@ +package org.mifos.processor; + +import java.util.UUID; +import org.junit.jupiter.api.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.ActiveProfiles; + +@SpringBootTest +@ActiveProfiles("test") +class BulkProcessorApplicationTests { + + public Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Test + void contextLoads() { + logger.debug("{}", UUID.randomUUID()); + } + +} diff --git a/ph-ee-bulk-processor/src/test/java/org/mifos/processor/cucumber/CucumberContext.java b/ph-ee-bulk-processor/src/test/java/org/mifos/processor/cucumber/CucumberContext.java new file mode 100644 index 000000000..dd58ba782 --- /dev/null +++ b/ph-ee-bulk-processor/src/test/java/org/mifos/processor/cucumber/CucumberContext.java @@ -0,0 +1,29 @@ +package org.mifos.processor.cucumber; + +import static com.google.common.truth.Truth.assertThat; + +import io.cucumber.spring.CucumberContextConfiguration; +import org.apache.camel.ProducerTemplate; +import org.apache.camel.test.spring.junit5.CamelSpringBootTest; +import org.apache.camel.test.spring.junit5.UseAdviceWith; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.ActiveProfiles; + +@CucumberContextConfiguration +@SpringBootTest +@CamelSpringBootTest +@UseAdviceWith +@ActiveProfiles("test") +public class CucumberContext { + + @Autowired + private ProducerTemplate producerTemplate; + + @Test + void contextLoads() { + assertThat(producerTemplate).isNotNull(); + } + +} diff --git a/ph-ee-bulk-processor/src/test/java/org/mifos/processor/cucumber/stepdef/BaseStepDef.java b/ph-ee-bulk-processor/src/test/java/org/mifos/processor/cucumber/stepdef/BaseStepDef.java new file mode 100644 index 000000000..5d00142de --- /dev/null +++ b/ph-ee-bulk-processor/src/test/java/org/mifos/processor/cucumber/stepdef/BaseStepDef.java @@ -0,0 +1,40 @@ +package org.mifos.processor.cucumber.stepdef; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.apache.camel.CamelContext; +import org.apache.camel.Exchange; +import org.apache.camel.ProducerTemplate; +import org.mifos.processor.bulk.config.ExternalApiPayloadConfig; +import org.mifos.processor.bulk.config.PaymentModeConfiguration; +import org.mifos.processor.bulk.config.PaymentModeMapping; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; + +// this class is the base for all the cucumber step definitions +public class BaseStepDef { + + @Autowired + ProducerTemplate template; + + @Autowired + CamelContext context; + + @Autowired + ObjectMapper objectMapper; + + @Autowired + PaymentModeConfiguration paymentModeConfiguration; + + @Autowired + ExternalApiPayloadConfig externalApiPayloadConfig; + + Logger logger = LoggerFactory.getLogger(this.getClass()); + + protected static String tenant; + protected static String paymentMode; + protected static PaymentModeMapping paymentModeMapping; + + protected static Exchange exchange; + +} diff --git a/ph-ee-bulk-processor/src/test/java/org/mifos/processor/cucumber/stepdef/ConfigurationTestStepDef.java b/ph-ee-bulk-processor/src/test/java/org/mifos/processor/cucumber/stepdef/ConfigurationTestStepDef.java new file mode 100644 index 000000000..c4957f46a --- /dev/null +++ b/ph-ee-bulk-processor/src/test/java/org/mifos/processor/cucumber/stepdef/ConfigurationTestStepDef.java @@ -0,0 +1,81 @@ +package org.mifos.processor.cucumber.stepdef; + +import static com.google.common.truth.Truth.assertThat; + +import io.cucumber.java.en.And; +import io.cucumber.java.en.Given; +import io.cucumber.java.en.Then; +import io.cucumber.java.en.When; +import java.util.function.Function; +import org.apache.camel.Exchange; +import org.mifos.processor.bulk.config.PaymentModeMapping; +import org.mifos.processor.bulk.config.PaymentModeType; +import org.mifos.processor.bulk.utility.Utils; + +public class ConfigurationTestStepDef extends BaseStepDef { + + @Given("Application context is loaded") + public void applicationContextIsLoaded() { + assertThat(context).isNotNull(); + } + + @When("I assert the payment mode config") + public void paymentModeConfigAssert() { + assertThat(paymentModeConfiguration).isNotNull(); + } + + @Then("I should get the non empty payment modes") + public void nonEmptyPaymentModesCheck() { + assertThat(paymentModeConfiguration.getMappings()).isNotEmpty(); + } + + @And("I should be able fetch the mapping for mode {string}") + public void fetchMappingForMode(String mode) { + PaymentModeMapping mapping = paymentModeConfiguration.getByMode(mode); + assertThat(mapping).isNotNull(); + BaseStepDef.paymentModeMapping = mapping; + } + + @And("I should get enum value {} for mode {string}") + public void getEnumValueForMode(PaymentModeType modeType, String mode) { + PaymentModeMapping mapping = paymentModeConfiguration.getByMode(mode); + assertThat(mapping.getType()).isEqualTo(modeType); + } + + @When("I have payment mode {string}") + public void setPaymentMode(String paymentMode) { + BaseStepDef.paymentMode = paymentMode; + assertThat(BaseStepDef.paymentMode).isNotEmpty(); + } + + @Then("I should get the bulk connector bpmn name {string}") + public void validateBulkConnectorBpmnName(String bpmnName) { + PaymentModeMapping mapping = BaseStepDef.paymentModeMapping; + String generatedBpmnName = Utils.getBulkConnectorBpmnName(mapping.getEndpoint(), mapping.getId(), BaseStepDef.tenant); + assertThat(bpmnName).isEqualTo(generatedBpmnName); + } + + @And("I have tenant as {string}") + public void setTenant(String tenant) { + BaseStepDef.tenant = tenant; + assertThat(BaseStepDef.tenant).isNotEmpty(); + } + + @When("I assert the external api payload config") + public void externalApiPayloadConfigAssert() { + assertThat(externalApiPayloadConfig).isNotNull(); + } + + @Then("I should get the non empty external api payload config") + public void nonEmptyExternalApiPayloadConfigCheck() { + int size = externalApiPayloadConfig.getPayloadMap().keySet().size(); + assertThat(size).isGreaterThan(0); + } + + @And("I should be able fetch the payload setter for mode {string}") + public void fetchPayloadSetterForMode(String mode) { + Function payloadSetter = externalApiPayloadConfig.getApiPayloadSetter(mode); + assertThat(payloadSetter).isNotNull(); + } + +} diff --git a/ph-ee-bulk-processor/src/test/java/org/mifos/processor/cucumber/stepdef/InitRouteStepDef.java b/ph-ee-bulk-processor/src/test/java/org/mifos/processor/cucumber/stepdef/InitRouteStepDef.java new file mode 100644 index 000000000..97717ba66 --- /dev/null +++ b/ph-ee-bulk-processor/src/test/java/org/mifos/processor/cucumber/stepdef/InitRouteStepDef.java @@ -0,0 +1,95 @@ +package org.mifos.processor.cucumber.stepdef; + +import static com.google.common.truth.Truth.assertThat; +import static org.mifos.processor.bulk.camel.config.CamelProperties.TRANSACTION_LIST_ELEMENT; +import static org.mifos.processor.bulk.zeebe.ZeebeVariables.PAYMENT_MODE; + +import com.fasterxml.jackson.core.JsonProcessingException; +import io.cucumber.java.en.And; +import io.cucumber.java.en.Given; +import io.cucumber.java.en.Then; +import io.cucumber.java.en.When; +import java.util.UUID; +import org.mifos.connector.common.channel.dto.TransactionChannelRequestDTO; +import org.mifos.connector.common.gsma.dto.GSMATransaction; +import org.mifos.processor.bulk.schema.Transaction; + +public class InitRouteStepDef extends BaseStepDef { + + @Given("I can load camel context") + public void loadCamelContext() { + context.start(); + assertThat(template).isNotNull(); + assertThat(context).isNotNull(); + } + + @When("I call the payment-mode-validation route with {string} payment mode") + public void callPaymentModeValidationRoute(String paymentMode) { + exchange = template.send("direct:validate-payment-mode", exchange -> { + exchange.setProperty(PAYMENT_MODE, paymentMode); + }); + } + + @Then("I should get a non null exchange variable") + public void exchangeVariableNullCheck() { + assertThat(exchange).isNotNull(); + } + + @And("{string} exchange variable should be {string}") + public void exchangeVariableBooleanCheck(String variableKey, String variableValue) { + if (variableValue.equalsIgnoreCase("true")) { + assertThat(exchange.getProperty(variableKey, Boolean.class)).isTrue(); + } else { + assertThat(exchange.getProperty(variableKey, Boolean.class)).isFalse(); + } + } + + @When("I call the runtime-payload route with {string} payment mode") + public void callRuntimePayloadTestRoute(String paymentMode) { + exchange = template.send("direct:dynamic-payload-setter", exchange -> { + exchange.setProperty(PAYMENT_MODE, paymentMode); + + Transaction transaction = new Transaction(); + transaction.setId(0); + transaction.setRequestId(UUID.randomUUID().toString()); + transaction.setPaymentMode(paymentMode); + transaction.setAmount("100"); + transaction.setPayerIdentifierType("MSISDN"); + transaction.setPayeeIdentifierType("MSISDN"); + transaction.setPayerIdentifier("1234567890"); + transaction.setPayeeIdentifier("0987654321"); + transaction.setCurrency("INR"); + exchange.setProperty(TRANSACTION_LIST_ELEMENT, new Transaction()); + + }); + + } + + @And("The body should be of GSMA parcelable") + public void gsmaBodyDeserializeCheck() { + String body = exchange.getIn().getBody(String.class); + assertThat(body).isNotNull(); + + GSMATransaction gsmaTransaction; + try { + gsmaTransaction = objectMapper.readValue(body, GSMATransaction.class); + } catch (JsonProcessingException e) { + throw new RuntimeException(e); + } + assertThat(gsmaTransaction).isNotNull(); + } + + @And("The body should be of MOJALOOP parcelable") + public void mojaloopBodyDeserializeCheck() { + String body = exchange.getIn().getBody(String.class); + assertThat(body).isNotNull(); + + TransactionChannelRequestDTO payload; + try { + payload = objectMapper.readValue(body, TransactionChannelRequestDTO.class); + } catch (JsonProcessingException e) { + throw new RuntimeException(e); + } + assertThat(payload).isNotNull(); + } +} diff --git a/ph-ee-bulk-processor/src/test/java/resources/configuration.feature b/ph-ee-bulk-processor/src/test/java/resources/configuration.feature new file mode 100644 index 000000000..24c16a13f --- /dev/null +++ b/ph-ee-bulk-processor/src/test/java/resources/configuration.feature @@ -0,0 +1,21 @@ +Feature: configuration test + + Scenario: Payment mode config test + Given Application context is loaded + When I assert the payment mode config + Then I should get the non empty payment modes + And I should be able fetch the mapping for mode "GSMA" + And I should get enum value PAYMENT for mode "MOJALOOP" + + Scenario: Bulk connector bpmn name test + Given Application context is loaded + When I have payment mode "SLCB" + And I have tenant as "gorilla" + And I should be able fetch the mapping for mode "SLCB" + Then I should get the bulk connector bpmn name "bulk_connector_slcb-gorilla" + + Scenario: External api payload config test + Given Application context is loaded + When I assert the external api payload config + Then I should get the non empty external api payload config + And I should be able fetch the payload setter for mode "GSMA" diff --git a/ph-ee-bulk-processor/src/test/java/resources/init_route_test.feature b/ph-ee-bulk-processor/src/test/java/resources/init_route_test.feature new file mode 100644 index 000000000..453505ae2 --- /dev/null +++ b/ph-ee-bulk-processor/src/test/java/resources/init_route_test.feature @@ -0,0 +1,31 @@ +Feature: init route test + + Scenario: payment mode +ve validation route test + Given I can load camel context + When I call the payment-mode-validation route with "GSMA" payment mode + Then I should get a non null exchange variable + And "isPaymentModeValid" exchange variable should be "true" + + Scenario: payment mode -ve validation route test + Given I can load camel context + When I call the payment-mode-validation route with "P2P" payment mode + Then I should get a non null exchange variable + And "isPaymentModeValid" exchange variable should be "false" + + Scenario: runtime payload test with GSMA mode + Given I can load camel context + When I call the runtime-payload route with "GSMA" payment mode + Then I should get a non null exchange variable + And The body should be of GSMA parcelable + + Scenario: runtime payload test with gsma mode + Given I can load camel context + When I call the runtime-payload route with "gsma" payment mode + Then I should get a non null exchange variable + And The body should be of GSMA parcelable + + Scenario: runtime payload test with MOJALOOP mode + Given I can load camel context + When I call the runtime-payload route with "MOJALOOP" payment mode + Then I should get a non null exchange variable + And The body should be of MOJALOOP parcelable diff --git a/ph-ee-connector-ams-mifos/.circleci/config.yml b/ph-ee-connector-ams-mifos/.circleci/config.yml new file mode 100644 index 000000000..51a5bbaa7 --- /dev/null +++ b/ph-ee-connector-ams-mifos/.circleci/config.yml @@ -0,0 +1,100 @@ +version: 2.1 +executors: + docker-executor: + docker: + - image: circleci/openjdk:13.0-buster-node-browsers-legacy + +jobs: + build_and_push_tag_image: + executor: docker-executor + environment: + JVM_OPTS: -Xmx512m + TERM: dumb + GITHUB_TOKEN: ${GITHUB_TOKEN} # Add the GitHub token as an environment variable + + steps: + - checkout + - setup_remote_docker: + version: 20.10.24 + - run: + name: Build and Push Docker tag Image + command: | + # Set environment variables + IMAGE_TAG=$CIRCLE_TAG + + # Check if the Docker image with the same tag already exists in Docker Hub + if curl -s -f -u "$DOCKERHUB_USERNAME":"$DOCKERHUB_PASSWORD" "https://hub.docker.com/v2/repositories/fynarfin/ph-ee-connector-ams-mifos/tags/$IMAGE_TAG" > /dev/null; then + echo "Skipping the build and push as the tag $IMAGE_TAG already exists in Docker Hub." + exit 0 + fi + + # Build and tag the Docker image + ./gradlew bootJar + docker build -t "fynarfin/ph-ee-connector-ams-mifos:$IMAGE_TAG" . + + # Push the Docker image to Docker Hub + docker login -u "$DOCKERHUB_USERNAME" -p "$DOCKERHUB_PASSWORD" + docker push "fynarfin/ph-ee-connector-ams-mifos:$IMAGE_TAG" + + # when: always # The job will be executed even if there's no match for the tag filter + + build_and_push_latest_image: + executor: docker-executor + environment: + JVM_OPTS: -Xmx512m + TERM: dumb + + steps: + - checkout + # Install Docker to build and push the image + - setup_remote_docker: + version: 20.10.24 + + # Build the Docker image + - run: + name: Build Docker image + command: | + #Check for PR title Validity + + IMAGE_TAG=$CIRCLE_TAG + ./gradlew checkstyleMain + ./gradlew clean bootJar + docker build -t fynarfin/ph-ee-connector-ams-mifos:latest . + if [ "$CIRCLE_BRANCH" != "develop" ]; then + PR_NUMBER=$(basename $CIRCLE_PULL_REQUEST) + PR_TITLE=$(curl -sSL "https://api.github.com/repos/fynarfin/$CIRCLE_PR_REPONAME/pulls/$PR_NUMBER" | jq -r '.title') + JIRA_STORY=$(echo $PR_TITLE | cut -d "[" -f2 | cut -d "]" -f1 | tr '[A-Z]' '[a-z]') + if [ -z "$JIRA_STORY" ]; then echo "Invalid PR title" && exit 1; else echo "Ticket NO: $JIRA_STORY"; fi + docker image tag fynarfin/$CIRCLE_PR_REPONAME:latest fynarfin/$CIRCLE_PR_REPONAME:$JIRA_STORY + fi + # Log in to DockerHub using environment variables + - run: + name: Login to DockerHub + command: echo "${DOCKERHUB_PASSWORD}" | docker login -u "${DOCKERHUB_USERNAME}" --password-stdin + + # Push the Docker image to DockerHub + - run: + name: Push Docker image to DockerHub + command: | + if [ "$CIRCLE_BRANCH" = "develop" ]; then + docker push fynarfin/ph-ee-connector-ams-mifos:latest + fi + if [ "$CIRCLE_BRANCH" != "develop" ]; then + PR_NUMBER=$(basename $CIRCLE_PULL_REQUEST) + PR_TITLE=$(curl -sSL "https://api.github.com/repos/fynarfin/$CIRCLE_PR_REPONAME/pulls/$PR_NUMBER" | jq -r '.title') + JIRA_STORY=$(echo $PR_TITLE | cut -d "[" -f2 | cut -d "]" -f1 | tr '[A-Z]' '[a-z]') + docker push fynarfin/$CIRCLE_PR_REPONAME:${JIRA_STORY} + fi +workflows: + version: 2 + build-and-push: + jobs: + - build_and_push_tag_image: + filters: + tags: + only: /^v\d+\.\d+\.\d+$/ # Match tags in the format v1.2.3 + context: + - DOCKER + - build_and_push_latest_image: + context: + - DOCKER diff --git a/ph-ee-connector-ams-mifos/.github/pull_request_template.md b/ph-ee-connector-ams-mifos/.github/pull_request_template.md new file mode 100644 index 000000000..1d44d4817 --- /dev/null +++ b/ph-ee-connector-ams-mifos/.github/pull_request_template.md @@ -0,0 +1,22 @@ +## Description + +* PR title should have jira ticket enclosed in `[]`.
+ Format: ``` [jira_ticket] description```
+ ex: [phee-123] PR title. +* Add a link to the Jira ticket. +* Describe the changes made and why they were made. + +## Checklist + +Please make sure these boxes are checked before submitting your pull request - thanks! +- [ ] Followed the PR title naming convention mentioned above. + +- [ ] Design related bullet points or design document link related to this PR added in the description above. + +- [ ] Updated corresponding Postman Collection or Api documentation for the changes in this PR. + +- [ ] Create/update unit or integration tests for verifying the changes made. + +- [ ] Add required Swagger annotation and update API documentation with details of any API changes if applicable + +- [ ] Followed the naming conventions as given in https://docs.google.com/document/d/1Q4vaMSzrTxxh9TS0RILuNkSkYCxotuYk1Xe0CMIkkCU/edit?usp=sharing diff --git a/ph-ee-connector-ams-mifos/.github/workflows/test.yaml b/ph-ee-connector-ams-mifos/.github/workflows/test.yaml new file mode 100644 index 000000000..f24192801 --- /dev/null +++ b/ph-ee-connector-ams-mifos/.github/workflows/test.yaml @@ -0,0 +1,12 @@ +name: Test +on: [push, pull_request] +jobs: + Assemble: + runs-on: ubuntu-latest + steps: + - name: Check out repository code + uses: actions/checkout@v2 + - name: Assemble project + run: ./gradlew clean build + - name: Build Docker image + run: docker build . -t paymenthubee.mifos.io/phee/connector-ams-mifos diff --git a/ph-ee-connector-ams-mifos/.gitignore b/ph-ee-connector-ams-mifos/.gitignore new file mode 100644 index 000000000..cf4d8d116 --- /dev/null +++ b/ph-ee-connector-ams-mifos/.gitignore @@ -0,0 +1,33 @@ +target/ +catalina* +.gradle +build/ +!gradle/wrapper/gradle-wrapper.jar + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ + +### VS Code ### +.vscode/ + +.DS_Store diff --git a/ph-ee-connector-ams-mifos/Dockerfile b/ph-ee-connector-ams-mifos/Dockerfile new file mode 100644 index 000000000..615c284dc --- /dev/null +++ b/ph-ee-connector-ams-mifos/Dockerfile @@ -0,0 +1,7 @@ +FROM openjdk:13 +EXPOSE 5000 + +COPY build/libs/*.jar . +COPY build/resources/main/keystore.jks . +CMD java -jar *.jar + diff --git a/ph-ee-connector-ams-mifos/Jenkinsfile b/ph-ee-connector-ams-mifos/Jenkinsfile new file mode 100644 index 000000000..04e99416d --- /dev/null +++ b/ph-ee-connector-ams-mifos/Jenkinsfile @@ -0,0 +1,17 @@ +pipeline { + agent any + stages { + stage('build') { + steps { + sh 'mvn --version' + sh 'mvn -U clean package' + } + } + stage('docker') { + steps { + sh 'docker build . -t paymenthubee.azurecr.io/phee/connector-ams-mifos' + sh 'docker push paymenthubee.azurecr.io/phee/connector-ams-mifos' + } + } + } +} diff --git a/ph-ee-connector-ams-mifos/LICENSE b/ph-ee-connector-ams-mifos/LICENSE new file mode 100644 index 000000000..a612ad981 --- /dev/null +++ b/ph-ee-connector-ams-mifos/LICENSE @@ -0,0 +1,373 @@ +Mozilla Public License Version 2.0 +================================== + +1. Definitions +-------------- + +1.1. "Contributor" + means each individual or legal entity that creates, contributes to + the creation of, or owns Covered Software. + +1.2. "Contributor Version" + means the combination of the Contributions of others (if any) used + by a Contributor and that particular Contributor's Contribution. + +1.3. "Contribution" + means Covered Software of a particular Contributor. + +1.4. "Covered Software" + means Source Code Form to which the initial Contributor has attached + the notice in Exhibit A, the Executable Form of such Source Code + Form, and Modifications of such Source Code Form, in each case + including portions thereof. + +1.5. "Incompatible With Secondary Licenses" + means + + (a) that the initial Contributor has attached the notice described + in Exhibit B to the Covered Software; or + + (b) that the Covered Software was made available under the terms of + version 1.1 or earlier of the License, but not also under the + terms of a Secondary License. + +1.6. "Executable Form" + means any form of the work other than Source Code Form. + +1.7. "Larger Work" + means a work that combines Covered Software with other material, in + a separate file or files, that is not Covered Software. + +1.8. "License" + means this document. + +1.9. "Licensable" + means having the right to grant, to the maximum extent possible, + whether at the time of the initial grant or subsequently, any and + all of the rights conveyed by this License. + +1.10. "Modifications" + means any of the following: + + (a) any file in Source Code Form that results from an addition to, + deletion from, or modification of the contents of Covered + Software; or + + (b) any new file in Source Code Form that contains any Covered + Software. + +1.11. "Patent Claims" of a Contributor + means any patent claim(s), including without limitation, method, + process, and apparatus claims, in any patent Licensable by such + Contributor that would be infringed, but for the grant of the + License, by the making, using, selling, offering for sale, having + made, import, or transfer of either its Contributions or its + Contributor Version. + +1.12. "Secondary License" + means either the GNU General Public License, Version 2.0, the GNU + Lesser General Public License, Version 2.1, the GNU Affero General + Public License, Version 3.0, or any later versions of those + licenses. + +1.13. "Source Code Form" + means the form of the work preferred for making modifications. + +1.14. "You" (or "Your") + means an individual or a legal entity exercising rights under this + License. For legal entities, "You" includes any entity that + controls, is controlled by, or is under common control with You. For + purposes of this definition, "control" means (a) the power, direct + or indirect, to cause the direction or management of such entity, + whether by contract or otherwise, or (b) ownership of more than + fifty percent (50%) of the outstanding shares or beneficial + ownership of such entity. + +2. License Grants and Conditions +-------------------------------- + +2.1. Grants + +Each Contributor hereby grants You a world-wide, royalty-free, +non-exclusive license: + +(a) under intellectual property rights (other than patent or trademark) + Licensable by such Contributor to use, reproduce, make available, + modify, display, perform, distribute, and otherwise exploit its + Contributions, either on an unmodified basis, with Modifications, or + as part of a Larger Work; and + +(b) under Patent Claims of such Contributor to make, use, sell, offer + for sale, have made, import, and otherwise transfer either its + Contributions or its Contributor Version. + +2.2. Effective Date + +The licenses granted in Section 2.1 with respect to any Contribution +become effective for each Contribution on the date the Contributor first +distributes such Contribution. + +2.3. Limitations on Grant Scope + +The licenses granted in this Section 2 are the only rights granted under +this License. No additional rights or licenses will be implied from the +distribution or licensing of Covered Software under this License. +Notwithstanding Section 2.1(b) above, no patent license is granted by a +Contributor: + +(a) for any code that a Contributor has removed from Covered Software; + or + +(b) for infringements caused by: (i) Your and any other third party's + modifications of Covered Software, or (ii) the combination of its + Contributions with other software (except as part of its Contributor + Version); or + +(c) under Patent Claims infringed by Covered Software in the absence of + its Contributions. + +This License does not grant any rights in the trademarks, service marks, +or logos of any Contributor (except as may be necessary to comply with +the notice requirements in Section 3.4). + +2.4. Subsequent Licenses + +No Contributor makes additional grants as a result of Your choice to +distribute the Covered Software under a subsequent version of this +License (see Section 10.2) or under the terms of a Secondary License (if +permitted under the terms of Section 3.3). + +2.5. Representation + +Each Contributor represents that the Contributor believes its +Contributions are its original creation(s) or it has sufficient rights +to grant the rights to its Contributions conveyed by this License. + +2.6. Fair Use + +This License is not intended to limit any rights You have under +applicable copyright doctrines of fair use, fair dealing, or other +equivalents. + +2.7. Conditions + +Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted +in Section 2.1. + +3. Responsibilities +------------------- + +3.1. Distribution of Source Form + +All distribution of Covered Software in Source Code Form, including any +Modifications that You create or to which You contribute, must be under +the terms of this License. You must inform recipients that the Source +Code Form of the Covered Software is governed by the terms of this +License, and how they can obtain a copy of this License. You may not +attempt to alter or restrict the recipients' rights in the Source Code +Form. + +3.2. Distribution of Executable Form + +If You distribute Covered Software in Executable Form then: + +(a) such Covered Software must also be made available in Source Code + Form, as described in Section 3.1, and You must inform recipients of + the Executable Form how they can obtain a copy of such Source Code + Form by reasonable means in a timely manner, at a charge no more + than the cost of distribution to the recipient; and + +(b) You may distribute such Executable Form under the terms of this + License, or sublicense it under different terms, provided that the + license for the Executable Form does not attempt to limit or alter + the recipients' rights in the Source Code Form under this License. + +3.3. Distribution of a Larger Work + +You may create and distribute a Larger Work under terms of Your choice, +provided that You also comply with the requirements of this License for +the Covered Software. If the Larger Work is a combination of Covered +Software with a work governed by one or more Secondary Licenses, and the +Covered Software is not Incompatible With Secondary Licenses, this +License permits You to additionally distribute such Covered Software +under the terms of such Secondary License(s), so that the recipient of +the Larger Work may, at their option, further distribute the Covered +Software under the terms of either this License or such Secondary +License(s). + +3.4. Notices + +You may not remove or alter the substance of any license notices +(including copyright notices, patent notices, disclaimers of warranty, +or limitations of liability) contained within the Source Code Form of +the Covered Software, except that You may alter any license notices to +the extent required to remedy known factual inaccuracies. + +3.5. Application of Additional Terms + +You may choose to offer, and to charge a fee for, warranty, support, +indemnity or liability obligations to one or more recipients of Covered +Software. However, You may do so only on Your own behalf, and not on +behalf of any Contributor. You must make it absolutely clear that any +such warranty, support, indemnity, or liability obligation is offered by +You alone, and You hereby agree to indemnify every Contributor for any +liability incurred by such Contributor as a result of warranty, support, +indemnity or liability terms You offer. You may include additional +disclaimers of warranty and limitations of liability specific to any +jurisdiction. + +4. Inability to Comply Due to Statute or Regulation +--------------------------------------------------- + +If it is impossible for You to comply with any of the terms of this +License with respect to some or all of the Covered Software due to +statute, judicial order, or regulation then You must: (a) comply with +the terms of this License to the maximum extent possible; and (b) +describe the limitations and the code they affect. Such description must +be placed in a text file included with all distributions of the Covered +Software under this License. Except to the extent prohibited by statute +or regulation, such description must be sufficiently detailed for a +recipient of ordinary skill to be able to understand it. + +5. Termination +-------------- + +5.1. The rights granted under this License will terminate automatically +if You fail to comply with any of its terms. However, if You become +compliant, then the rights granted under this License from a particular +Contributor are reinstated (a) provisionally, unless and until such +Contributor explicitly and finally terminates Your grants, and (b) on an +ongoing basis, if such Contributor fails to notify You of the +non-compliance by some reasonable means prior to 60 days after You have +come back into compliance. Moreover, Your grants from a particular +Contributor are reinstated on an ongoing basis if such Contributor +notifies You of the non-compliance by some reasonable means, this is the +first time You have received notice of non-compliance with this License +from such Contributor, and You become compliant prior to 30 days after +Your receipt of the notice. + +5.2. If You initiate litigation against any entity by asserting a patent +infringement claim (excluding declaratory judgment actions, +counter-claims, and cross-claims) alleging that a Contributor Version +directly or indirectly infringes any patent, then the rights granted to +You by any and all Contributors for the Covered Software under Section +2.1 of this License shall terminate. + +5.3. In the event of termination under Sections 5.1 or 5.2 above, all +end user license agreements (excluding distributors and resellers) which +have been validly granted by You or Your distributors under this License +prior to termination shall survive termination. + +************************************************************************ +* * +* 6. Disclaimer of Warranty * +* ------------------------- * +* * +* Covered Software is provided under this License on an "as is" * +* basis, without warranty of any kind, either expressed, implied, or * +* statutory, including, without limitation, warranties that the * +* Covered Software is free of defects, merchantable, fit for a * +* particular purpose or non-infringing. The entire risk as to the * +* quality and performance of the Covered Software is with You. * +* Should any Covered Software prove defective in any respect, You * +* (not any Contributor) assume the cost of any necessary servicing, * +* repair, or correction. This disclaimer of warranty constitutes an * +* essential part of this License. No use of any Covered Software is * +* authorized under this License except under this disclaimer. * +* * +************************************************************************ + +************************************************************************ +* * +* 7. Limitation of Liability * +* -------------------------- * +* * +* Under no circumstances and under no legal theory, whether tort * +* (including negligence), contract, or otherwise, shall any * +* Contributor, or anyone who distributes Covered Software as * +* permitted above, be liable to You for any direct, indirect, * +* special, incidental, or consequential damages of any character * +* including, without limitation, damages for lost profits, loss of * +* goodwill, work stoppage, computer failure or malfunction, or any * +* and all other commercial damages or losses, even if such party * +* shall have been informed of the possibility of such damages. This * +* limitation of liability shall not apply to liability for death or * +* personal injury resulting from such party's negligence to the * +* extent applicable law prohibits such limitation. Some * +* jurisdictions do not allow the exclusion or limitation of * +* incidental or consequential damages, so this exclusion and * +* limitation may not apply to You. * +* * +************************************************************************ + +8. Litigation +------------- + +Any litigation relating to this License may be brought only in the +courts of a jurisdiction where the defendant maintains its principal +place of business and such litigation shall be governed by laws of that +jurisdiction, without reference to its conflict-of-law provisions. +Nothing in this Section shall prevent a party's ability to bring +cross-claims or counter-claims. + +9. Miscellaneous +---------------- + +This License represents the complete agreement concerning the subject +matter hereof. If any provision of this License is held to be +unenforceable, such provision shall be reformed only to the extent +necessary to make it enforceable. Any law or regulation which provides +that the language of a contract shall be construed against the drafter +shall not be used to construe this License against a Contributor. + +10. Versions of the License +--------------------------- + +10.1. New Versions + +Mozilla Foundation is the license steward. Except as provided in Section +10.3, no one other than the license steward has the right to modify or +publish new versions of this License. Each version will be given a +distinguishing version number. + +10.2. Effect of New Versions + +You may distribute the Covered Software under the terms of the version +of the License under which You originally received the Covered Software, +or under the terms of any subsequent version published by the license +steward. + +10.3. Modified Versions + +If you create software not governed by this License, and you want to +create a new license for such software, you may create and use a +modified version of this License if you rename the license and remove +any references to the name of the license steward (except to note that +such modified license differs from this License). + +10.4. Distributing Source Code Form that is Incompatible With Secondary +Licenses + +If You choose to distribute Source Code Form that is Incompatible With +Secondary Licenses under the terms of this version of the License, the +notice described in Exhibit B of this License must be attached. + +Exhibit A - Source Code Form License Notice +------------------------------------------- + + This Source Code Form is subject to the terms of the Mozilla Public + License, v. 2.0. If a copy of the MPL was not distributed with this + file, You can obtain one at http://mozilla.org/MPL/2.0/. + +If it is not possible or desirable to put the notice in a particular +file, then You may include the notice in a location (such as a LICENSE +file in a relevant directory) where a recipient would be likely to look +for such a notice. + +You may add additional accurate notices of copyright ownership. + +Exhibit B - "Incompatible With Secondary Licenses" Notice +--------------------------------------------------------- + + This Source Code Form is "Incompatible With Secondary Licenses", as + defined by the Mozilla Public License, v. 2.0. diff --git a/ph-ee-connector-ams-mifos/README.md b/ph-ee-connector-ams-mifos/README.md new file mode 100644 index 000000000..5a7159589 --- /dev/null +++ b/ph-ee-connector-ams-mifos/README.md @@ -0,0 +1,32 @@ +# ph-ee-connector-ams-mifos +Payment Hub Enterprise Edition connector for local AMS. +By default local quote is disabled and only empty Zeebe workers are started. +Currently supported AMS backends: (configure corresponding yml files to modify properties) +* Fineract 1.2 -> use spring profile fin12 + +**Important:** Use filesystem path to set keystore for TLS Client configuration. + +# Zeebe worker api mapping +| Route | Endpoint | HTTP Method | +|-----------------------------------------------|----------------------------------------------------------------------------------------|-------------| +| direct:get-external-account | /interoperation/accounts/{externalAccountId} | GET | +| direct:send-local-quote | /interoperation/quotes | GET | +| direct:send-transfers | /transfers | POST | +| direct:get-party | /customers/{customerIdentifier} | GET | +| direct:register-party-finx | /interoperation/parties/{idType}/{idValue} | POST | +| direct:register-party-fincn | /parties/{idType}/{idValue} | POST | +| direct:add-interop-identifier-to-account | adds interoperability identifier depending upon fineract cloud native or fineract X | POST | +| direct:remove-interop-identifier-from-account | removes interoperability identifier depending upon fineract cloud native of fineract X | PUT | +| rest:POST:/transfer/deposit | calls send transfer | POST | + +# Routes to worker and bpmn mapping + +| Route | Worker | BPMN | +|-------------------------|-------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| direct:send-transfers | book-funds,block-funds | debit-party-process-DFSPID.bpmn,gsma-bill-payment.bpmn,gsma-inttransfer-payer.bpmn,gsma-link-based-transfer.bpmn,gsma-p2p-wo-local-quote.bpmn,gsma-p2p.bpmn,international-remittance-payer-process-DFSPID.bpmn,payer-fund-transfer-DFSPID.bpmn,payer-fund-transfer-terminate-DFSPID.bpmn,payer-transaction-request-DFSPID.bpmn | +| | release-block | gsma-bill-payment.bpmn,gsma-inttransfer-payer.bpmn,gsma-link-based-transfer.bpmn,gsma-p2p-wo-local-quote.bpmn,gsma-p2p.bpmn,international-remittance-payer-process-DFSPID.bpmn,payer-fund-transfer-DFSPID.bpmn,payer-fund-transfer-terminate-DFSPID.bpmn,payer-transaction-request-DFSPID.bpmn | +| | payee-commit-transfer-dfspId | payee-quote-transfer-DFSPID.bpmn,payer-quote-transfer-DFSPID.bpmn | +| | payee-deposit-transfer-dfspId | international-remittance-payee-process-DFSPID.bpmn | +| direct:get-party | party-lookup-local-dfspId | debit-party-process-DFSPID.bpmn,gsma-bill-payment.bpmn,gsma-inttransfer-payer.bpmn,gsma-link-based-transfer.bpmn,gsma-p2p-wo-local-quote.bpmn,gsma-p2p.bpmn,payee-party-lookup-DFSPID.bpmn | +| direct:send-local-quote | payer-local-quote-dfspId | gsma-p2p.bpmn,payer-fund-transfer-DFSPID.bpmn,payer-fund-transfer-terminate-DFSPID.bpmn,orchestration/feel/payer-transaction-request-DFSPID.bpmn | +| | payee-quote-dfspId | gsma-payee-process.bpmn,payee-quote-transfer-DFSPID.bpmn | diff --git a/ph-ee-connector-ams-mifos/build.gradle b/ph-ee-connector-ams-mifos/build.gradle new file mode 100644 index 000000000..95b39e06e --- /dev/null +++ b/ph-ee-connector-ams-mifos/build.gradle @@ -0,0 +1,301 @@ +/* + * This file was generated by the Gradle 'init' task. + */ + +plugins { + id 'java' + id 'maven-publish' + id 'eclipse' + id 'checkstyle' + id 'org.springframework.boot' version '2.6.2' + id 'com.diffplug.spotless' version '6.19.0' + id 'net.ltgt.errorprone' version '3.1.0' +} + +repositories { + mavenLocal() + maven { + url = uri('https://repo.maven.apache.org/maven2') + } + + maven { + url = uri('https://jfrog.sandbox.fynarfin.io/artifactory/fyn-libs-snapshot') + } +} + +apply plugin:'com.diffplug.spotless' +spotless { + format 'misc', { + target '**/*.md', '**/*.properties', '**/.gitignore', '**/.openapi-generator-ignore', '**/*.yml', '**/*.xml', '**/**.json', '**/*.sql' + targetExclude '**/build/**', '**/bin/**', '**/.settings/**', '**/.idea/**', '**/.gradle/**', '**/gradlew.bat', '**/licenses/**', '**/banner.txt', '.vscode/**' + indentWithSpaces(4) + endWithNewline() + trimTrailingWhitespace() + } + + groovyGradle { + target '*.gradle', '**/*.gradle' + targetExclude '**/build/**' + greclipse() + indentWithSpaces(4) + endWithNewline() + trimTrailingWhitespace() + } + + lineEndings 'UNIX' +} + + +dependencies { + implementation 'org.mifos:ph-ee-connector-common:1.5.1-SNAPSHOT' + implementation 'com.sun.xml.ws:jaxws-ri:2.3.2' + implementation 'org.apache.camel.springboot:camel-spring-boot-starter:3.4.0' + implementation 'org.apache.camel:camel-endpointdsl:3.4.0' + implementation 'org.apache.camel:camel-undertow:3.4.0' + implementation 'org.apache.camel:camel-cxf:3.4.0' + implementation 'org.apache.camel.springboot:camel-jackson-starter:3.4.0' + implementation 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.6.0' + implementation 'org.json:json:20210307' + implementation 'org.apache.cxf:cxf-rt-rs-client:3.2.5' + implementation 'org.apache.cxf:cxf-rt-frontend-jaxrs:3.2.5' + implementation 'io.camunda:zeebe-client-java:8.1.23' + testImplementation 'org.springframework.boot:spring-boot-starter-test:2.2.2.RELEASE' + testImplementation 'org.junit.jupiter:junit-jupiter-api:5.6.0' + testImplementation 'org.junit.jupiter:junit-jupiter-engine:5.6.0' + compileOnly 'org.projectlombok:lombok:1.18.24' + annotationProcessor 'org.projectlombok:lombok:1.18.24' + implementation group: 'org.springframework', name: 'spring-web', version: '3.0.2.RELEASE' + checkstyle 'com.puppycrawl.tools:checkstyle:10.9.3' + checkstyle 'com.github.sevntu-checkstyle:sevntu-checks:1.44.1' + implementation 'org.springframework.boot:spring-boot-starter:2.5.2' + implementation 'org.springframework.boot:spring-boot-starter-actuator:2.6.2' + implementation 'org.springframework.boot:spring-boot-starter-web:2.5.2' + implementation 'org.springframework.boot:spring-boot-starter-tomcat:2.5.2' +} + +dependencies { + implementation "io.springfox:springfox-oas:3.0.0" + implementation "io.springfox:springfox-swagger-ui:3.0.0" + implementation "com.github.joschi.jackson:jackson-datatype-threetenbp:2.6.4" + implementation "javax.validation:validation-api:*" + implementation "org.springframework.plugin:spring-plugin-core:2.0.0.RELEASE" + implementation 'io.swagger.codegen.v3:swagger-codegen-maven-plugin:3.0.16' +} + +configure(this) { + // NOTE: order matters! + apply plugin: 'java' + apply plugin: 'idea' + apply plugin: 'eclipse' + apply plugin: 'checkstyle' + apply plugin: 'net.ltgt.errorprone' + configurations { + implementation.setCanBeResolved(true) + api.setCanBeResolved(true) + } + tasks.withType(JavaCompile) { + options.compilerArgs += [ + "-Xlint:unchecked", + "-Xlint:cast", + "-Xlint:auxiliaryclass", + "-Xlint:deprecation", + "-Xlint:dep-ann", + "-Xlint:divzero", + "-Xlint:empty", + "-Xlint:exports", + "-Xlint:fallthrough", + "-Xlint:finally", + "-Xlint:module", + "-Xlint:opens", + "-Xlint:options", + "-Xlint:overloads", + "-Xlint:overrides", + "-Xlint:path", + "-Xlint:processing", + "-Xlint:removal", + "-Xlint:requires-automatic", + "-Xlint:requires-transitive-automatic", + "-Xlint:try", + "-Xlint:varargs", + "-Xlint:preview", + "-Xlint:static", + // -Werror needs to be disabled because EclipseLink's static weaving doesn't generate warning-free code + // and during an IntelliJ recompilation, it fails + //"-Werror", + "-Xmaxwarns", + 1500, + "-Xmaxerrs", + 1500 + ] + options.deprecation = true + } + // Configuration for the spotless plugin + // https://github.com/diffplug/spotless/tree/main/plugin-gradle + spotless { + java { + targetExclude '**/build/**', '**/bin/**', '**/out/**' + importOrder() //sort imports alphabetically + removeUnusedImports() + eclipse().configFile "$rootDir/ph-ee-connector-ams-mifos/config/ams-formatter.xml" + endWithNewline() + trimTrailingWhitespace() + // Enforce style modifier order + custom 'Modifier ordering', { + def modifierRanking = [ + public : 1, + protected : 2, + private : 3, + abstract : 4, + default : 5, + static : 6, + final : 7, + transient : 8, + volatile : 9, + synchronized: 10, + native : 11, + strictfp : 12] + // Find any instance of multiple modifiers. Lead with a non-word character to avoid + // accidental matching against for instance, "an alternative default value" + it.replaceAll(/\W(?:public |protected |private |abstract |default |static |final |transient |volatile |synchronized |native |strictfp ){2,}/, { + // Do not replace the leading non-word character. Identify the modifiers + it.replaceAll(/(?:public |protected |private |abstract |default |static |final |transient |volatile |synchronized |native |strictfp ){2,}/, { + // Sort the modifiers according to the ranking above + it.split().sort({ modifierRanking[it] }).join(' ') + ' ' + } + ) + } + ) + } + } + lineEndings 'UNIX' + } + // If we are running Gradle within Eclipse to enhance classes, + // set the classes directory to point to Eclipse's default build directory + if (project.hasProperty('env') && project.getProperty('env') == 'eclipse') { + sourceSets.main.java.outputDir = file("$projectDir/bin/main") + } + // Configuration for the Checkstyle plugin + // https://docs.gradle.org/current/userguide/checkstyle_plugin.html + dependencies { + checkstyle 'com.puppycrawl.tools:checkstyle:10.3.1' + checkstyle 'com.github.sevntu-checkstyle:sevntu-checks:1.42.0' + } + // Configuration for the errorprone plugin + // https://github.com/tbroyer/gradle-errorprone-plugin + dependencies { + errorprone "com.google.errorprone:error_prone_core:2.20.0" + } + + tasks.withType(JavaCompile) { + options.errorprone { + enabled = project.gradle.startParameter.taskNames.contains('build') || project.gradle.startParameter.taskNames.contains('check') + disableWarningsInGeneratedCode = true + excludedPaths = ".*/build/.*" + disable( + // TODO Remove disabled checks from this list, by fixing remaining usages + "UnusedVariable", + "TypeParameterUnusedInFormals", + "EmptyBlockTag", + "MissingSummary", + "InvalidParam", + "ReturnFromVoid", + "AlmostJavadoc", + "InvalidBlockTag", + "JavaUtilDate", // TODO FINERACT-1298 + "ReturnValueIgnored", + "DirectInvocationOnMock", + "CanIgnoreReturnValueSuggester", + "SameNameButDifferent", // Until errorprone recognizes Lombok + "MultiVariableDeclaration", // Until errorprone recognizes Lombok + "UnnecessaryDefaultInEnumSwitch" // FINERACT-1911 + ) + error( + "DefaultCharset", + "RemoveUnusedImports", + "WaitNotInLoop", + "ThreeLetterTimeZoneID", + "VariableNameSameAsType", + "UnnecessaryParentheses", + "MultipleTopLevelClasses", + "MixedMutabilityReturnType", + "AssertEqualsArgumentOrderChecker", + "EmptySetMultibindingContributions", + "BigDecimalEquals", + "MixedArrayDimensions", + "PackageLocation", + "UseBinds", + "BadImport", + "IntLongMath", + "FloatCast", + "ReachabilityFenceUsage", + "StreamResourceLeak", + "TruthIncompatibleType", + "ByteBufferBackingArray", + "OrphanedFormatString", + "CatchAndPrintStackTrace", + "ObjectToString", + "StringSplitter", + "AssertThrowsMultipleStatements", + "BoxedPrimitiveConstructor", + "EmptyCatch", + "BoxedPrimitiveEquality", + "SynchronizeOnNonFinalField", + "WildcardImport", + "PrivateConstructorForNoninstantiableModule", + "ClassCanBeStatic", + "ClassNewInstance", + "UnnecessaryStaticImport", + "UnsafeFinalization", + "JavaTimeDefaultTimeZone", + "JodaPlusMinusLong", + "SwitchDefault", + "VarTypeName", + "ArgumentSelectionDefectChecker", + "CompareToZero", + "InjectOnConstructorOfAbstractClass", + "ImmutableEnumChecker", + "NarrowingCompoundAssignment", + "MissingCasesInEnumSwitch", + "ReferenceEquality", + "UnescapedEntity", + "ModifyCollectionInEnhancedForLoop", + "NonCanonicalType", + "InvalidInlineTag", + "MutablePublicArray", + "StaticAssignmentInConstructor", + "ProtectedMembersInFinalClass", + "OperatorPrecedence", + "EqualsUnsafeCast", + "DoubleBraceInitialization", + "UnusedNestedClass", + "UnusedMethod", + "ModifiedButNotUsed", + "InconsistentCapitalization", + ) + } + } +} +group = 'org.mifos' +version = '1.0.0-SNAPSHOT' +sourceCompatibility = JavaVersion.VERSION_13 + +checkstyle { + checkstyleMain.exclude '**/fineractstub/**' +} + + +publishing { + publications { + maven(MavenPublication) { + from(components.java) + } + } +} + +test { + useJUnitPlatform() +} + +tasks.withType(JavaCompile) { + options.encoding = 'UTF-8' +} diff --git a/ph-ee-connector-ams-mifos/config/ams-cleanup.xml b/ph-ee-connector-ams-mifos/config/ams-cleanup.xml new file mode 100644 index 000000000..42a5314f6 --- /dev/null +++ b/ph-ee-connector-ams-mifos/config/ams-cleanup.xml @@ -0,0 +1,71 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ph-ee-connector-ams-mifos/config/ams-formatter.xml b/ph-ee-connector-ams-mifos/config/ams-formatter.xml new file mode 100644 index 000000000..c437e7332 --- /dev/null +++ b/ph-ee-connector-ams-mifos/config/ams-formatter.xml @@ -0,0 +1,366 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ph-ee-connector-ams-mifos/config/checkstyle/checkstyle.xml b/ph-ee-connector-ams-mifos/config/checkstyle/checkstyle.xml new file mode 100644 index 000000000..aa4f9c22e --- /dev/null +++ b/ph-ee-connector-ams-mifos/config/checkstyle/checkstyle.xml @@ -0,0 +1,240 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ph-ee-connector-ams-mifos/config/checkstyle/suppressions.xml b/ph-ee-connector-ams-mifos/config/checkstyle/suppressions.xml new file mode 100644 index 000000000..f4e5b54c3 --- /dev/null +++ b/ph-ee-connector-ams-mifos/config/checkstyle/suppressions.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + diff --git a/ph-ee-connector-ams-mifos/gradle/wrapper/gradle-wrapper.jar b/ph-ee-connector-ams-mifos/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 000000000..490fda857 Binary files /dev/null and b/ph-ee-connector-ams-mifos/gradle/wrapper/gradle-wrapper.jar differ diff --git a/ph-ee-connector-ams-mifos/gradle/wrapper/gradle-wrapper.properties b/ph-ee-connector-ams-mifos/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 000000000..e750102e0 --- /dev/null +++ b/ph-ee-connector-ams-mifos/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-7.3-bin.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/ph-ee-connector-ams-mifos/gradlew b/ph-ee-connector-ams-mifos/gradlew new file mode 100755 index 000000000..2fe81a7d9 --- /dev/null +++ b/ph-ee-connector-ams-mifos/gradlew @@ -0,0 +1,183 @@ +#!/usr/bin/env sh + +# +# Copyright 2015 the original author or authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn () { + echo "$*" +} + +die () { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin or MSYS, switch paths to Windows format before running java +if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=`expr $i + 1` + done + case $i in + 0) set -- ;; + 1) set -- "$args0" ;; + 2) set -- "$args0" "$args1" ;; + 3) set -- "$args0" "$args1" "$args2" ;; + 4) set -- "$args0" "$args1" "$args2" "$args3" ;; + 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=`save "$@"` + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +exec "$JAVACMD" "$@" diff --git a/ph-ee-connector-ams-mifos/gradlew.bat b/ph-ee-connector-ams-mifos/gradlew.bat new file mode 100644 index 000000000..9109989e3 --- /dev/null +++ b/ph-ee-connector-ams-mifos/gradlew.bat @@ -0,0 +1,103 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windows variants + +if not "%OS%" == "Windows_NT" goto win9xME_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/ph-ee-connector-ams-mifos/keystore.jks b/ph-ee-connector-ams-mifos/keystore.jks new file mode 100644 index 000000000..b2455d0a3 Binary files /dev/null and b/ph-ee-connector-ams-mifos/keystore.jks differ diff --git a/ph-ee-connector-ams-mifos/settings.gradle b/ph-ee-connector-ams-mifos/settings.gradle new file mode 100644 index 000000000..756584450 --- /dev/null +++ b/ph-ee-connector-ams-mifos/settings.gradle @@ -0,0 +1,5 @@ +/* + * This file was generated by the Gradle 'init' task. + */ + +rootProject.name = 'ph-ee-connector-ams-mifos' diff --git a/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/AmsConnectorApplication.java b/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/AmsConnectorApplication.java new file mode 100644 index 000000000..13397932a --- /dev/null +++ b/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/AmsConnectorApplication.java @@ -0,0 +1,40 @@ +package org.mifos.connector; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; +import org.apache.camel.Processor; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.Bean; +import org.springframework.web.client.RestTemplate; + +@SpringBootApplication +public class AmsConnectorApplication { + + public static void main(String[] args) { + SpringApplication.run(AmsConnectorApplication.class, args); + } + + @Bean + public ObjectMapper objectMapper() { + ObjectMapper objectMapper = new ObjectMapper(); + objectMapper.registerModule(new JavaTimeModule()); + objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false); + return objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL) + .configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true) + .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + } + + @Bean + public Processor pojoToString(ObjectMapper objectMapper) { + return exchange -> exchange.getIn().setBody(objectMapper.writeValueAsString(exchange.getIn().getBody())); + } + + @Bean + public RestTemplate getRestTemplate() { + return new RestTemplate(); + } +} diff --git a/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/ams/AmsConfiguration.java b/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/ams/AmsConfiguration.java new file mode 100644 index 000000000..e7bf1d658 --- /dev/null +++ b/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/ams/AmsConfiguration.java @@ -0,0 +1,20 @@ +package org.mifos.connector.ams; + +import org.apache.camel.support.jsse.SSLContextParameters; +import org.mifos.connector.ams.camel.cxfrs.SSLConfig; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.ImportResource; +import org.springframework.context.annotation.Profile; + +@Profile({ "fin12", "fincn" }) +@Configuration +// @ConditionalOnExpression("${ams.local.enabled}") +@ImportResource("classpath:endpoints.xml") +public class AmsConfiguration { + + @Bean + public SSLContextParameters sslContextParameters(SSLConfig sslConfig) { + return sslConfig.provideSSLContextParameters(); + } +} diff --git a/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/ams/HealthCheck.java b/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/ams/HealthCheck.java new file mode 100644 index 000000000..27c3df190 --- /dev/null +++ b/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/ams/HealthCheck.java @@ -0,0 +1,14 @@ +package org.mifos.connector.ams; + +import org.apache.camel.Exchange; +import org.apache.camel.builder.RouteBuilder; +import org.springframework.stereotype.Component; + +@Component +public class HealthCheck extends RouteBuilder { + + @Override + public void configure() { + from("rest:GET:/").setHeader(Exchange.HTTP_RESPONSE_CODE, constant(200)).setBody(constant("")); + } +} diff --git a/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/ams/camel/config/CamelContextConfig.java b/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/ams/camel/config/CamelContextConfig.java new file mode 100644 index 000000000..b15754e6e --- /dev/null +++ b/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/ams/camel/config/CamelContextConfig.java @@ -0,0 +1,45 @@ +package org.mifos.connector.ams.camel.config; + +import java.util.HashMap; +import org.apache.camel.CamelContext; +import org.apache.camel.spi.RestConfiguration; +import org.apache.camel.spring.boot.CamelContextConfiguration; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class CamelContextConfig { + + @Value("${camel.server-port:5000}") + private int serverPort; + + @Bean + CamelContextConfiguration contextConfiguration() { + return new CamelContextConfiguration() { + + @Override + public void beforeApplicationStart(CamelContext camelContext) { + camelContext.setTracing(false); + camelContext.setMessageHistory(false); + camelContext.setStreamCaching(true); + camelContext.disableJMX(); + + RestConfiguration rest = new RestConfiguration(); + camelContext.setRestConfiguration(rest); + rest.setComponent("undertow"); + rest.setProducerComponent("undertow"); + rest.setPort(serverPort); + rest.setBindingMode(RestConfiguration.RestBindingMode.json); + rest.setDataFormatProperties(new HashMap<>()); + rest.getDataFormatProperties().put("prettyPrint", "true"); + rest.setScheme("http"); + } + + @Override + public void afterApplicationStart(CamelContext camelContext) { + // empty + } + }; + } +} diff --git a/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/ams/camel/config/CamelProperties.java b/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/ams/camel/config/CamelProperties.java new file mode 100644 index 000000000..61ce3d8e7 --- /dev/null +++ b/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/ams/camel/config/CamelProperties.java @@ -0,0 +1,24 @@ +package org.mifos.connector.ams.camel.config; + +public final class CamelProperties { + + private CamelProperties() {} + + public static final String CLIENT_ID = "clientId"; + public static final String IDENTIFIER_ID = "identifierId"; + public static final String CONTINUE_PROCESSING = "continueProcessing"; + public static final String DEFINITON_ID = "definitonId"; + public static final String EXISTING_EXTERNAL_ACCOUNT_ID = "existingExternalAccountId"; + public static final String INTEROP_ACCOUNT_TO_REGISTER = "interopAccountId"; + public static final String LOGIN_USERNAME = "loginUsername"; + public static final String LOGIN_PASSWORD = "loginPassword"; + public static final String QUOTE_AMOUNT_TYPE = "quoteAmountType"; + public static final String TRANSACTION_ROLE = "transactionRole"; + public static final String TRANSFER_ACTION = "transferAction"; + public static final String ZEEBE_JOB_KEY = "zeebeJobKey"; + public static final String PROCESS_TYPE = "processType"; + + public static final String IS_ERROR_SET_MANUALLY = "isErrorSetManually"; + public static final String X_CALLBACKURL = "X-CallbackURL"; + +} diff --git a/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/ams/camel/cxfrs/CfxRsNotStreamingBinding.java b/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/ams/camel/cxfrs/CfxRsNotStreamingBinding.java new file mode 100644 index 000000000..89aff8460 --- /dev/null +++ b/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/ams/camel/cxfrs/CfxRsNotStreamingBinding.java @@ -0,0 +1,21 @@ +package org.mifos.connector.ams.camel.cxfrs; + +import java.io.InputStream; +import org.apache.camel.Exchange; +import org.apache.camel.component.cxf.jaxrs.DefaultCxfRsBinding; +import org.apache.cxf.helpers.IOUtils; +import org.apache.cxf.jaxrs.impl.ResponseImpl; +import org.springframework.stereotype.Component; + +@Component +public class CfxRsNotStreamingBinding extends DefaultCxfRsBinding { + + @Override + public Object bindResponseToCamelBody(Object response, Exchange camelExchange) throws Exception { + if (response instanceof ResponseImpl && ((ResponseImpl) response).getEntity() instanceof InputStream) { + InputStream inputStream = (InputStream) ((ResponseImpl) response).getEntity(); + return IOUtils.toString(inputStream); + } + return super.bindResponseToCamelBody(response, camelExchange); + } +} diff --git a/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/ams/camel/cxfrs/CompositeX509TrustManager.java b/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/ams/camel/cxfrs/CompositeX509TrustManager.java new file mode 100644 index 000000000..52744be8a --- /dev/null +++ b/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/ams/camel/cxfrs/CompositeX509TrustManager.java @@ -0,0 +1,54 @@ +package org.mifos.connector.ams.camel.cxfrs; + +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.stream.Stream; +import javax.net.ssl.X509TrustManager; + +public class CompositeX509TrustManager implements X509TrustManager { + + private final List trustManagers; + private boolean checkServerCert; + + public CompositeX509TrustManager(List trustManagers, boolean checkServerCert) { + this.trustManagers = Collections.unmodifiableList(new ArrayList<>(trustManagers)); + this.checkServerCert = checkServerCert; + } + + @Override + public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { + for (X509TrustManager trustManager : trustManagers) { + try { + trustManager.checkClientTrusted(chain, authType); + return; // someone trusts them. success! + } catch (CertificateException e) { + // maybe someone else will trust them + } + } + throw new CertificateException("None of the TrustManagers trust the clients certificate chain!"); + } + + @Override + public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { + if (checkServerCert) { + for (X509TrustManager trustManager : trustManagers) { + try { + trustManager.checkServerTrusted(chain, authType); + return; // someone trusts them. success! + } catch (CertificateException e) { + // maybe someone else will trust them + } + } + throw new CertificateException("None of the TrustManagers trust the servers certificate chain!"); + } + } + + @Override + public X509Certificate[] getAcceptedIssuers() { + return trustManagers.stream().flatMap(it -> Stream.of(it.getAcceptedIssuers())).toArray(X509Certificate[]::new); + } + +} diff --git a/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/ams/camel/cxfrs/CxfrsUtil.java b/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/ams/camel/cxfrs/CxfrsUtil.java new file mode 100644 index 000000000..cead63ff1 --- /dev/null +++ b/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/ams/camel/cxfrs/CxfrsUtil.java @@ -0,0 +1,30 @@ +package org.mifos.connector.ams.camel.cxfrs; + +import java.util.Map; +import org.apache.camel.Exchange; +import org.apache.camel.ExchangePattern; +import org.apache.camel.ProducerTemplate; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component +public class CxfrsUtil { + + @Autowired + private ProducerTemplate template; + + /** + * Warning! Clears IN headers. + */ + public void sendInOut(String endpoint, Exchange ex, Map headers, Object body) { + ExchangePattern oldPattern = ex.getPattern(); + if (body != null) { + ex.getIn().setBody(body); + } + ex.getIn().removeHeaders("*"); + ex.getIn().setHeaders(headers); + ex.setPattern(ExchangePattern.InOut); + template.send(endpoint, ex); + ex.setPattern(oldPattern); + } +} diff --git a/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/ams/camel/cxfrs/HeaderBasedInterceptor.java b/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/ams/camel/cxfrs/HeaderBasedInterceptor.java new file mode 100644 index 000000000..279044b08 --- /dev/null +++ b/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/ams/camel/cxfrs/HeaderBasedInterceptor.java @@ -0,0 +1,22 @@ +package org.mifos.connector.ams.camel.cxfrs; + +import java.util.List; +import java.util.Map; +import java.util.Optional; +import org.apache.cxf.message.Message; + +public interface HeaderBasedInterceptor { + + String CXF_TRACE_HEADER = "cxfTrace"; + + default boolean isCxfTraceEnabled(Message message) { + return Optional.ofNullable(message.getExchange().get(Message.PROTOCOL_HEADERS)).filter(Map.class::isInstance).map(it -> { + try { + Object headerValue = ((List) ((Map) it).get(CXF_TRACE_HEADER)).get(0); + return Boolean.TRUE.equals(headerValue instanceof String ? Boolean.valueOf((String) headerValue) : (Boolean) headerValue); + } catch (Exception ex) { + return false; + } + }).orElse(false); + } +} diff --git a/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/ams/camel/cxfrs/InboundInterceptor.java b/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/ams/camel/cxfrs/InboundInterceptor.java new file mode 100644 index 000000000..d638d85d0 --- /dev/null +++ b/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/ams/camel/cxfrs/InboundInterceptor.java @@ -0,0 +1,17 @@ +package org.mifos.connector.ams.camel.cxfrs; + +import org.apache.cxf.ext.logging.LoggingInInterceptor; +import org.apache.cxf.interceptor.Fault; +import org.apache.cxf.message.Message; +import org.springframework.stereotype.Component; + +@Component +public class InboundInterceptor extends LoggingInInterceptor implements HeaderBasedInterceptor { + + @Override + public void handleMessage(Message message) throws Fault { + if (isCxfTraceEnabled(message)) { + super.handleMessage(message); + } + } +} diff --git a/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/ams/camel/cxfrs/OutboundInterceptor.java b/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/ams/camel/cxfrs/OutboundInterceptor.java new file mode 100644 index 000000000..76f2ed61b --- /dev/null +++ b/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/ams/camel/cxfrs/OutboundInterceptor.java @@ -0,0 +1,17 @@ +package org.mifos.connector.ams.camel.cxfrs; + +import org.apache.cxf.ext.logging.LoggingOutInterceptor; +import org.apache.cxf.interceptor.Fault; +import org.apache.cxf.message.Message; +import org.springframework.stereotype.Component; + +@Component +public class OutboundInterceptor extends LoggingOutInterceptor implements HeaderBasedInterceptor { + + @Override + public void handleMessage(Message message) throws Fault { + if (isCxfTraceEnabled(message)) { + super.handleMessage(message); + } + } +} diff --git a/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/ams/camel/cxfrs/SSLConfig.java b/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/ams/camel/cxfrs/SSLConfig.java new file mode 100644 index 000000000..a93e7e947 --- /dev/null +++ b/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/ams/camel/cxfrs/SSLConfig.java @@ -0,0 +1,133 @@ +package org.mifos.connector.ams.camel.cxfrs; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.cert.CertificateException; +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import javax.net.ssl.KeyManagerFactory; +import javax.net.ssl.TrustManager; +import javax.net.ssl.TrustManagerFactory; +import javax.net.ssl.X509TrustManager; +import org.apache.camel.support.jsse.ClientAuthentication; +import org.apache.camel.support.jsse.KeyManagersParameters; +import org.apache.camel.support.jsse.KeyStoreParameters; +import org.apache.camel.support.jsse.SSLContextParameters; +import org.apache.camel.support.jsse.SSLContextServerParameters; +import org.apache.camel.support.jsse.TrustManagersParameters; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.core.io.FileSystemResource; +import org.springframework.stereotype.Component; + +@Component +// @ConditionalOnExpression("${ams.local.enabled}") +public class SSLConfig { + + private final Logger logger = LoggerFactory.getLogger(getClass()); + private String keystorePassword; + private File keyStoreFile; + private boolean checkServerCert; + + public SSLConfig(@Value("${ams.local.keystore-path}") String keystorePath, + @Value("${ams.local.keystore-password}") String keystorePassword, + @Value("${ams.local.server-cert-check}") boolean checkServerCert) { + this.keystorePassword = keystorePassword; + keyStoreFile = new FileSystemResource(keystorePath).getFile(); + this.checkServerCert = checkServerCert; + } + + public SSLContextParameters provideSSLContextParameters() { + Optional keyManagerParameter = getKeyManagerParameter(); + TrustManagersParameters trustManagerParameter = getTrustManagerParameter(); + + SSLContextParameters ssl = new SSLContextParameters(); + keyManagerParameter.ifPresent(ssl::setKeyManagers); + ssl.setTrustManagers(trustManagerParameter); + + SSLContextServerParameters serverParameters = new SSLContextServerParameters(); + serverParameters.setClientAuthentication(ClientAuthentication.REQUIRE.name()); + ssl.setServerParameters(serverParameters); + + return ssl; + } + + private TrustManagersParameters getTrustManagerParameter() { + TrustManagersParameters trustManagers = new TrustManagersParameters(); + trustManagers.setTrustManager(createCompositeTrustManager()); + return trustManagers; + } + + private CompositeX509TrustManager createCompositeTrustManager() { + List trustManagers = Stream + .concat(Stream.of(tryToGetApplicationTrustManagerTrustManager()), Stream.of(tryToGetJavaTrustManager())) + .filter(X509TrustManager.class::isInstance).map(X509TrustManager.class::cast).collect(Collectors.toList()); + return new CompositeX509TrustManager(trustManagers, checkServerCert); + } + + private X509TrustManager[] tryToGetJavaTrustManager() { + try { + return getJavaDefaultTrustStore(); + } catch (NoSuchAlgorithmException | KeyStoreException e) { + logger.error("Cannot get Java TrustManager", e); + return new X509TrustManager[0]; + } + } + + private X509TrustManager[] getJavaDefaultTrustStore() throws NoSuchAlgorithmException, KeyStoreException { + String defaultAlgorithm = KeyManagerFactory.getDefaultAlgorithm(); + TrustManagerFactory factory = TrustManagerFactory.getInstance(defaultAlgorithm); + factory.init((KeyStore) null); + return Stream.of(factory.getTrustManagers()).filter(X509TrustManager.class::isInstance).map(X509TrustManager.class::cast) + .findFirst().map(it -> new X509TrustManager[] { it }).orElse(new X509TrustManager[0]); + } + + private Optional getKeyManagerParameter() { + if (keyStoreFile != null) { + KeyStoreParameters keyStore = new KeyStoreParameters(); + keyStore.setResource(keyStoreFile.toString()); + keyStore.setPassword(keystorePassword); + + KeyManagersParameters keyManagers = new KeyManagersParameters(); + keyManagers.setKeyStore(keyStore); + keyManagers.setKeyPassword(keystorePassword); + return Optional.of(keyManagers); + } else { + return Optional.empty(); + } + } + + private TrustManager[] tryToGetApplicationTrustManagerTrustManager() { + try { + return getApplicationTrustManager(); + } catch (InterruptedException | CertificateException | NoSuchAlgorithmException | KeyStoreException | IOException e) { + throw new RuntimeException("Cannot replace the TrustManager", e); + } + } + + private TrustManager[] getApplicationTrustManager() + throws KeyStoreException, CertificateException, NoSuchAlgorithmException, IOException, InterruptedException { + if (keyStoreFile == null) { + return new TrustManager[0]; + } + + InputStream trustStream = new FileInputStream(keyStoreFile); + char[] trustPassword = keystorePassword.toCharArray(); + + KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType()); + trustStore.load(trustStream, trustPassword); + + TrustManagerFactory trustFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); + trustFactory.init(trustStore); + + return trustFactory.getTrustManagers(); + } +} diff --git a/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/ams/errorhandler/AmsMifosErrorMapper.java b/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/ams/errorhandler/AmsMifosErrorMapper.java new file mode 100644 index 000000000..dbab0a3e9 --- /dev/null +++ b/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/ams/errorhandler/AmsMifosErrorMapper.java @@ -0,0 +1,31 @@ +package org.mifos.connector.ams.errorhandler; + +import org.mifos.connector.common.exception.PaymentHubError; +import org.mifos.connector.common.exception.mapper.ErrorMapper; +import org.springframework.stereotype.Component; + +@Component +public class AmsMifosErrorMapper extends ErrorMapper { + + @Override + public void configure() { + add("error.msg.interop.account.not.found", PaymentHubError.PayerNotFound); + add("validation.msg.interoperation.transfer.accountId.cannot.be.blank", PaymentHubError.PayerNotFound); + + add("error.msg.savingsaccount.transaction.insufficient.account.balance.withdraw", PaymentHubError.PayerInsufficientBalance); + add("error.msg.savingsaccount.transaction.insufficient.account.balance", PaymentHubError.PayerInsufficientBalance); + + add("validation.msg.savingsaccount.transaction.transactionAmount.not.greater.than.zero", PaymentHubError.ExtValidationError); + add("validation.msg.invalid.decimal.format", PaymentHubError.ExtValidationError); + + add(PaymentHubError.PayeeFspNotConfigured.getErrorCode(), PaymentHubError.PayeeFspNotConfigured); + + add("error.msg.currency.currencyCode.invalid", PaymentHubError.PayeeCurrencyInvalid); + add("error.msg.currency.currencyCode.invalid.or.not.supported", PaymentHubError.PayeeCurrencyInvalid); + add("error.msg.currency.currencyCode.inUse", PaymentHubError.PayeeCurrencyInvalid); + + // 404 httpstatus and response is empty -> payerFspNotFound + // payeefsp and payerfsp not configured + // currency invalid + } +} diff --git a/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/ams/errorhandler/ErrorTranslator.java b/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/ams/errorhandler/ErrorTranslator.java new file mode 100644 index 000000000..8c5d492e6 --- /dev/null +++ b/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/ams/errorhandler/ErrorTranslator.java @@ -0,0 +1,88 @@ +package org.mifos.connector.ams.errorhandler; + +import static org.mifos.connector.ams.zeebe.ZeebeVariables.ERROR_CODE; +import static org.mifos.connector.ams.zeebe.ZeebeVariables.ERROR_INFORMATION; +import static org.mifos.connector.ams.zeebe.ZeebeVariables.ERROR_PAYLOAD; +import static org.mifos.connector.ams.zeebe.ZeebeVariables.FINERACT_RESPONSE_BODY; +import static org.mifos.connector.ams.zeebe.ZeebeVariables.IS_ERROR_HANDLED; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import java.util.Map; +import lombok.extern.slf4j.Slf4j; +import org.mifos.connector.ams.interop.errordto.ErrorResponse; +import org.mifos.connector.common.channel.dto.PhErrorDTO; +import org.mifos.connector.common.exception.PaymentHubError; +import org.mifos.connector.common.exception.mapper.ErrorMapper; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component +@Slf4j +public class ErrorTranslator { + + @Autowired + private ErrorMapper errorMapper; + + @Autowired + ObjectMapper objectMapper; + + public Map translateError(Map zeebeFinalVariables) { + checkIfErrorIsAlreadyMappedToInternal(zeebeFinalVariables); + String errorCode = (String) zeebeFinalVariables.get(ERROR_CODE); + if (errorCode == null) { + return zeebeFinalVariables; + } + + PaymentHubError paymentHubError; + // todo improve try catch logic + try { + paymentHubError = errorMapper.getInternalError(errorCode); + if (paymentHubError == null) { + throw new NullPointerException(); + } + } catch (Exception e) { + try { + paymentHubError = PaymentHubError.fromCode(errorCode); + } catch (Exception exc) { + return zeebeFinalVariables; + } + } + + PhErrorDTO phErrorDTO; + try { + ErrorResponse externalErrorObject = (ErrorResponse) zeebeFinalVariables.get(ERROR_PAYLOAD); + phErrorDTO = new PhErrorDTO.PhErrorDTOBuilder(paymentHubError) + .developerMessage(objectMapper.writeValueAsString(externalErrorObject)) + .defaultUserMessage((String) zeebeFinalVariables.get(ERROR_INFORMATION)).build(); + } catch (Exception e) { + phErrorDTO = new PhErrorDTO.PhErrorDTOBuilder(paymentHubError).developerMessage((String) zeebeFinalVariables.get(ERROR_PAYLOAD)) + .defaultUserMessage((String) zeebeFinalVariables.get(ERROR_INFORMATION)).build(); + } + + zeebeFinalVariables.put(ERROR_CODE, phErrorDTO.getErrorCode()); + zeebeFinalVariables.put(ERROR_INFORMATION, phErrorDTO.getErrorDescription()); + zeebeFinalVariables.put(FINERACT_RESPONSE_BODY, zeebeFinalVariables.get(ERROR_PAYLOAD)); + try { + zeebeFinalVariables.put(ERROR_INFORMATION, objectMapper.writeValueAsString(phErrorDTO)); + PhErrorDTO errorDTO = objectMapper.readValue((String) zeebeFinalVariables.get(ERROR_INFORMATION), PhErrorDTO.class); + } catch (JsonProcessingException e) { + log.debug(e.getMessage()); + zeebeFinalVariables.put(ERROR_INFORMATION, phErrorDTO.toString()); + } + + return zeebeFinalVariables; + } + + private void checkIfErrorIsAlreadyMappedToInternal(Map zeebeFinalVariables) { + boolean isErrorHandled; + try { + isErrorHandled = (boolean) zeebeFinalVariables.get(IS_ERROR_HANDLED); + } catch (Exception e) { + isErrorHandled = false; + } + if (!isErrorHandled) { + zeebeFinalVariables.put(IS_ERROR_HANDLED, true); + } + } +} diff --git a/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/ams/interop/AccountsRouteBuilder.java b/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/ams/interop/AccountsRouteBuilder.java new file mode 100644 index 000000000..9403f974e --- /dev/null +++ b/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/ams/interop/AccountsRouteBuilder.java @@ -0,0 +1,171 @@ +package org.mifos.connector.ams.interop; + +import static org.mifos.connector.ams.camel.config.CamelProperties.CLIENT_ID; +import static org.mifos.connector.ams.zeebe.ZeebeVariables.PARTY_ID; +import static org.mifos.connector.ams.zeebe.ZeebeVariables.PARTY_ID_TYPE; +import static org.mifos.connector.ams.zeebe.ZeebeVariables.TENANT_ID; + +import org.apache.camel.LoggingLevel; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.model.dataformat.JsonLibrary; +import org.json.JSONObject; +import org.mifos.connector.common.ams.dto.ClientData; +import org.mifos.connector.common.ams.dto.Customer; +import org.mifos.connector.common.ams.dto.InteropAccountDTO; +import org.mifos.connector.common.ams.dto.ProductInstance; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +@Component +public class AccountsRouteBuilder extends RouteBuilder { + + @Autowired(required = false) + private AmsService amsService; + @Value("${ams.local.version}") + private String amsVersion; + + @Override + public void configure() { + from("rest:GET:/ams/accounts/{IdentifierType}/{IdentifierId}/status").id("ams-connector-account-management-status-check") + .log(LoggingLevel.INFO, "##ams-connector-account-management-status-check").process(e -> { + String IdentifierType = e.getIn().getHeader("IdentifierType", String.class); + String IdentifierId = e.getIn().getHeader("IdentifierId", String.class); + String tenantId = e.getIn().getHeader("Platform-TenantId", String.class); + e.setProperty(PARTY_ID_TYPE, IdentifierType); + e.setProperty(PARTY_ID, IdentifierId); + e.setProperty(TENANT_ID, tenantId); + }) + .log(LoggingLevel.INFO, + "##ams-connector-account-management-status-check: ${exchangeProperty." + PARTY_ID_TYPE + + "} with value: ${exchangeProperty." + PARTY_ID + "}") + .to("direct:get-external-account").process(amsService::getSavingsAccount).unmarshal() + .json(JsonLibrary.Jackson, InteropAccountDTO.class).process(e -> { + InteropAccountDTO account = e.getIn().getBody(InteropAccountDTO.class); + JSONObject response = new JSONObject(); + response.put("accountStatus", account.getStatus().getCode()); + response.put("subStatus", account.getSubStatus().getCode()); + response.put("lei", ""); + e.getIn().setBody(response.toString()); + }); + // @formatter:off + from("rest:GET:/ams/accounts/{IdentifierType}/{IdentifierId}/accountname") + .id("ams-connector-account-management-get-name") + .log(LoggingLevel.INFO, "##ams-connector-account-management-get-name") + .process(e -> { + String IdentifierType = e.getIn().getHeader("IdentifierType", String.class); + String IdentifierId = e.getIn().getHeader("IdentifierId", String.class); + String tenantId = e.getIn().getHeader("Platform-TenantId", String.class); + e.setProperty(PARTY_ID_TYPE, IdentifierType); + e.setProperty(PARTY_ID,IdentifierId); + e.setProperty(TENANT_ID, tenantId); + }) + .log(LoggingLevel.INFO, "##ams-connector-account-management-status-check: ${exchangeProperty." + PARTY_ID_TYPE + "} with value: ${exchangeProperty." + PARTY_ID + "}") + .to("direct:get-external-account") + .process(amsService::getSavingsAccount) + .choice() + .when(e -> "1.2".equals(amsVersion)) + .unmarshal().json(JsonLibrary.Jackson, InteropAccountDTO.class) + .process(e -> e.setProperty(CLIENT_ID, e.getIn().getBody(InteropAccountDTO.class).getClientId())) + .process(amsService::getClientImage) + .process(e -> e.setProperty("client_image", e.getIn().getBody(String.class))) + .process(amsService::getClient) + .unmarshal().json(JsonLibrary.Jackson, ClientData.class) + .process(e -> { + ClientData customer = e.getIn().getBody(ClientData.class); + JSONObject response = new JSONObject(); + JSONObject name = new JSONObject(); + name.put("title", ""); + name.put("firstName", customer.getFirstname()); + name.put("middleName", customer.getMiddlename()); + name.put("lastName", customer.getLastname()); + name.put("fullName", customer.getFullname()); + name.put("nativeName", customer.getDisplayName()); + response.put("name", name); + response.put("lei", ""); + response.put("image", e.getProperty("client_image")); + e.getIn().setBody(response.toString()); + }) + .endChoice() + .otherwise() // cn + .unmarshal().json(JsonLibrary.Jackson, ProductInstance.class) + .process(e -> e.setProperty(CLIENT_ID, e.getIn().getBody(ProductInstance.class).getCustomerIdentifier())) + .process(amsService::getClient) + .unmarshal().json(JsonLibrary.Jackson, Customer.class) + .process(e -> { + Customer customer = e.getIn().getBody(Customer.class); + JSONObject response = new JSONObject(); + JSONObject name = new JSONObject(); + name.put("title",""); + name.put("firstName", ""); + name.put("middleName", ""); + name.put("lastName", customer.getSurname()); + name.put("fullName", customer.getGivenName()); + name.put("nativeName", customer.getGivenName()); + response.put("name", name); + response.put("lei", ""); + e.getIn().setBody(response.toString()); + }) + .endChoice() + .end(); + from("rest:GET:/ams/accounts/{IdentifierType}/{IdentifierId}/balance") + .id("ams-connector-account-management-balance-check") + .log(LoggingLevel.INFO, "## ams-connector-account-management-balance-check") + .process(e -> { + String IdentifierType = e.getIn().getHeader("IdentifierType", String.class); + String IdentifierId = e.getIn().getHeader("IdentifierId", String.class); + String tenantId = e.getIn().getHeader("Platform-TenantId", String.class); + e.setProperty(PARTY_ID_TYPE, IdentifierType); + e.setProperty(PARTY_ID,IdentifierId); + e.setProperty(TENANT_ID, tenantId); + }) + .log(LoggingLevel.INFO, "##ams-connector-account-management-status-check: ${exchangeProperty." + PARTY_ID_TYPE + "} with value: ${exchangeProperty." + PARTY_ID + "}") + .to("direct:get-external-account") + .process(amsService::getSavingsAccount) + .unmarshal().json(JsonLibrary.Jackson, InteropAccountDTO.class) + .process(e -> { + InteropAccountDTO account = e.getIn().getBody(InteropAccountDTO.class); + JSONObject response = new JSONObject(); + response.put("currentBalance", account.getAccountBalance().toString()); + response.put("availableBalance", account.getAvailableBalance().toString()); + response.put("reservedBalance", ""); + response.put("unclearedBalance", ""); + response.put("currency", account.getCurrency()); + response.put("accountStatus", account.getStatus().getCode()); + e.getIn().setBody(response.toString()); + }); + from("rest:GET:/ams/accounts/{IdentifierType}/{IdentifierId}/transactions") + .id("ams-connector-account-management-get-transactions") + .log(LoggingLevel.INFO, "## ams-connector-account-management-get-transactions") + .process(e -> { + String IdentifierType = e.getIn().getHeader("IdentifierType", String.class); + String IdentifierId = e.getIn().getHeader("IdentifierId", String.class); + String tenantId = e.getIn().getHeader("Platform-TenantId", String.class); + e.setProperty(PARTY_ID_TYPE, IdentifierType); + e.setProperty(PARTY_ID,IdentifierId); + e.setProperty(TENANT_ID, tenantId); + }) + .log(LoggingLevel.INFO, "##ams-connector-account-management-status-check: ${exchangeProperty." + PARTY_ID_TYPE + "} with value: ${exchangeProperty." + PARTY_ID + "}") + .to("direct:get-external-account") + .process(amsService::getSavingsAccountsTransactions) + .process(e -> { + e.getIn().setBody(e.getIn().getBody()); + }); + /*. + .unmarshal().json(JsonLibrary.Jackson, List.class) + .process(e -> { + List transactions = e.getIn().getBody(List.class); + JSONArray response = + e.getIn().setBody(response.toString()); + });*/ + from("rest:GET:/ams/accounts/{IdentifierType}/{IdentifierId}/statemententries") + .id("account-management-get-statemententries") + .log(LoggingLevel.INFO, "## account-management-get-statemententries") + .process(e -> { + String IdentifierType = e.getIn().getHeader("IdentifierType", String.class); + String IdentifierId = e.getIn().getHeader("IdentifierId", String.class); + String tenantId = e.getIn().getHeader("Platform-TenantId", String.class); + }) + .setBody(constant(null)); + } +} diff --git a/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/ams/interop/AmsCommonService.java b/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/ams/interop/AmsCommonService.java new file mode 100644 index 000000000..bd2848fae --- /dev/null +++ b/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/ams/interop/AmsCommonService.java @@ -0,0 +1,173 @@ +package org.mifos.connector.ams.interop; + +import static org.apache.camel.Exchange.HTTP_METHOD; +import static org.apache.camel.Exchange.HTTP_PATH; +import static org.mifos.connector.ams.camel.config.CamelProperties.TRANSFER_ACTION; +import static org.mifos.connector.ams.camel.cxfrs.HeaderBasedInterceptor.CXF_TRACE_HEADER; +import static org.mifos.connector.ams.zeebe.ZeebeVariables.ACCOUNT_NUMBER; +import static org.mifos.connector.ams.zeebe.ZeebeVariables.PARTY_ID; +import static org.mifos.connector.ams.zeebe.ZeebeVariables.PARTY_ID_TYPE; +import static org.mifos.connector.ams.zeebe.ZeebeVariables.TENANT_ID; + +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.Map; +import org.apache.camel.Exchange; +import org.apache.camel.component.cxf.common.message.CxfConstants; +import org.mifos.connector.ams.camel.cxfrs.CxfrsUtil; +import org.mifos.connector.ams.tenant.TenantService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Component; +import org.springframework.web.client.RestTemplate; + +@Component +// @ConditionalOnExpression("${ams.local.enabled}") +public class AmsCommonService { + + @Value("${ams.local.interop.quotes-path}") + private String amsInteropQuotesPath; + + @Value("${ams.local.interop.parties-path}") + private String amsInteropPartiesPath; + + @Value("${ams.local.interop.transfers-path}") + private String amsInteropTransfersPath; + + @Value("${ams.local.loan.repayment-path}") + private String amsLoanRepaymentPath; + + @Autowired + private TenantService tenantService; + + @Autowired + private CxfrsUtil cxfrsUtil; + @Autowired + RestTemplate restTemplate; + + @Value("${ams.local.enabled}") + private boolean isAmsLocalEnabled; + + @Value("${mock-service.local.loan.repayment-path}") + private String mockServiceLoanRepaymentPath; + @Value("${mock-service.local.interop.transfers-path}") + private String mockServiceInteropTransfersPath; + @Value("${mock-service.local.interop.parties-path}") + private String mockServiceAmsInteropPartiesPath; + + private Logger logger = LoggerFactory.getLogger(this.getClass()); + + private static final String APPLICATION_TYPE = "application/json"; + + public void getLocalQuote(Exchange e) { + Map headers = new HashMap<>(); + headers.put(CXF_TRACE_HEADER, true); + headers.put(HTTP_METHOD, "POST"); + headers.put(HTTP_PATH, amsInteropQuotesPath); + headers.put("Content-Type", "application/json"); + headers.putAll(tenantService.getHeaders(e.getProperty(TENANT_ID, String.class))); + cxfrsUtil.sendInOut("cxfrs:bean:ams.local.interop", e, headers, e.getIn().getBody()); + } + + public void getExternalAccount(Exchange e) { + Map headers = new HashMap<>(); + headers.put(CXF_TRACE_HEADER, true); + headers.put(HTTP_METHOD, "GET"); + logger.debug(":{}", e.getProperty(PARTY_ID_TYPE, String.class)); + logger.debug(":{}", e.getProperty(PARTY_ID, String.class)); + headers.put(HTTP_PATH, amsInteropPartiesPath.replace("{idType}", e.getProperty(PARTY_ID_TYPE, String.class)).replace("{idValue}", + e.getProperty(PARTY_ID, String.class))); + headers.putAll(tenantService.getHeaders(e.getProperty(TENANT_ID, String.class))); + if (isAmsLocalEnabled) { + cxfrsUtil.sendInOut("cxfrs:bean:ams.local.interop", e, headers, null); + } else { + logger.info("-------------- Calling Mock external Account API --------------"); + headers.put(HTTP_PATH, mockServiceAmsInteropPartiesPath); + cxfrsUtil.sendInOut("cxfrs:bean:mock-service.local.interop", e, headers, null); + } + // cxfrsUtil.sendInOut("cxfrs:bean:ams.local.interop", e, headers, null); + } + + public void sendTransfer(Exchange e) { + Map headers = new HashMap<>(); + headers.put(CXF_TRACE_HEADER, true); + headers.put(HTTP_METHOD, "POST"); + headers.put(HTTP_PATH, amsInteropTransfersPath); + logger.info("Send Transfer Body: {}", e.getIn().getBody()); + Map queryMap = new LinkedHashMap<>(); + queryMap.put("action", e.getProperty(TRANSFER_ACTION, String.class)); + headers.put(CxfConstants.CAMEL_CXF_RS_QUERY_MAP, queryMap); + headers.put("Content-Type", "application/json"); + headers.putAll(tenantService.getHeaders(e.getProperty(TENANT_ID, String.class))); + if (isAmsLocalEnabled) { + cxfrsUtil.sendInOut("cxfrs:bean:ams.local.interop", e, headers, e.getIn().getBody()); + } else { + logger.info("-------------- Calling Mock transfers APIs --------------"); + headers.put(HTTP_PATH, mockServiceInteropTransfersPath); + cxfrsUtil.sendInOut("cxfrs:bean:mock-service.local.interop", e, headers, e.getIn().getBody().toString()); + } + } + + public void repayLoan(Exchange e) { + Map headers = new HashMap<>(); + headers.put(CXF_TRACE_HEADER, true); + headers.put(HTTP_METHOD, "POST"); + headers.put(HTTP_PATH, amsLoanRepaymentPath.replace("{accountNumber}", e.getProperty(ACCOUNT_NUMBER, String.class))); + logger.debug("Loan Repayment Body: {}", e.getIn().getBody()); + headers.put("Content-Type", APPLICATION_TYPE); + headers.putAll(tenantService.getHeaders(e.getProperty(TENANT_ID, String.class))); + if (isAmsLocalEnabled) { + cxfrsUtil.sendInOut("cxfrs:bean:ams.local.loan", e, headers, e.getIn().getBody()); + } else { + logger.info("-------------- Calling Mock Loan repayment APIs --------------"); + headers.put(HTTP_PATH, mockServiceLoanRepaymentPath); + cxfrsUtil.sendInOut("cxfrs:bean:mock-service.local.loan", e, headers, e.getIn().getBody().toString()); + } + // cxfrsUtil.sendInOut("cxfrs:bean:ams.local.loan", e, headers, e.getIn().getBody()); + } + + public boolean sendCallback(String callbackURL, String body) { + logger.info("Sending Callback..."); + ResponseEntity responseEntity; + try { + responseEntity = restTemplate.postForEntity(callbackURL, body, null); + if (responseEntity.getStatusCode().is2xxSuccessful()) { + logger.info("Callback sent"); + return true; + } else { + logger.info("Callback failed!!!"); + return false; + } + } catch (Exception exception) { + logger.info("Callback failed!!!"); + logger.debug(exception.getMessage()); + } + return false; + } + + public void registerInteropIdentifier(Exchange e) { + Map headers = new HashMap<>(); + headers.put(CXF_TRACE_HEADER, true); + headers.put(HTTP_METHOD, "POST"); + headers.put(HTTP_PATH, amsInteropPartiesPath.replace("{idType}", e.getProperty(PARTY_ID_TYPE, String.class)).replace("{idValue}", + e.getProperty(PARTY_ID, String.class))); + headers.put("Content-Type", "application/json"); + headers.putAll(tenantService.getHeaders(e.getProperty(TENANT_ID, String.class))); + cxfrsUtil.sendInOut("cxfrs:bean:ams.local.interop", e, headers, e.getIn().getBody()); + } + + public void removeInteropIdentifier(Exchange e) { + Map headers = new HashMap<>(); + headers.put(CXF_TRACE_HEADER, true); + headers.put(HTTP_METHOD, "DELETE"); + headers.put(HTTP_PATH, amsInteropPartiesPath.replace("{idType}", e.getProperty(PARTY_ID_TYPE, String.class)).replace("{idValue}", + e.getProperty(PARTY_ID, String.class))); + headers.put("Content-Type", "application/json"); + headers.putAll(tenantService.getHeaders(e.getProperty(TENANT_ID, String.class))); + e.getIn().setBody(null); + cxfrsUtil.sendInOut("cxfrs:bean:ams.local.interop", e, headers, null); + } +} diff --git a/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/ams/interop/AmsFinCNService.java b/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/ams/interop/AmsFinCNService.java new file mode 100644 index 000000000..92501a7c1 --- /dev/null +++ b/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/ams/interop/AmsFinCNService.java @@ -0,0 +1,112 @@ +package org.mifos.connector.ams.interop; + +import static java.nio.charset.StandardCharsets.UTF_8; +import static org.apache.camel.Exchange.HTTP_METHOD; +import static org.apache.camel.Exchange.HTTP_PATH; +import static org.mifos.connector.ams.camel.config.CamelProperties.CLIENT_ID; +import static org.mifos.connector.ams.camel.config.CamelProperties.DEFINITON_ID; +import static org.mifos.connector.ams.camel.config.CamelProperties.IDENTIFIER_ID; +import static org.mifos.connector.ams.camel.config.CamelProperties.LOGIN_PASSWORD; +import static org.mifos.connector.ams.camel.config.CamelProperties.LOGIN_USERNAME; +import static org.mifos.connector.ams.camel.cxfrs.HeaderBasedInterceptor.CXF_TRACE_HEADER; +import static org.mifos.connector.ams.tenant.TenantService.X_TENANT_IDENTIFIER_HEADER; +import static org.mifos.connector.ams.zeebe.ZeebeVariables.ACCOUNT_ID; +import static org.mifos.connector.ams.zeebe.ZeebeVariables.TENANT_ID; + +import java.util.Base64; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.Map; +import org.apache.camel.Exchange; +import org.apache.camel.component.cxf.common.message.CxfConstants; +import org.mifos.connector.ams.camel.cxfrs.CxfrsUtil; +import org.mifos.connector.ams.tenant.TenantService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; +import org.springframework.stereotype.Component; + +@Component +@ConditionalOnExpression("'${ams.local.version}'.equals('cn')") +public class AmsFinCNService extends AmsCommonService implements AmsService { + + @Value("${ams.local.account.instances-path}") + private String amsAccountInstancesPath; + + @Value("${ams.local.account.definitons-path}") + private String amsAccountDefinitionsPath; + + @Value("${ams.local.customer.path}") + private String amsLocalCustomerPath; + + @Value("${ams.local.auth.path}") + private String amsLocalAuthPath; + + @Autowired + private TenantService tenantService; + + @Autowired + private CxfrsUtil cxfrsUtil; + + public void getSavingsAccount(Exchange e) { + Map headers = new HashMap<>(); + headers.put(CXF_TRACE_HEADER, true); + headers.put(HTTP_METHOD, "GET"); + headers.put(HTTP_PATH, amsAccountInstancesPath.replace("{accountId}", e.getProperty(ACCOUNT_ID, String.class))); + headers.putAll(tenantService.getHeaders(e.getProperty(TENANT_ID, String.class))); + cxfrsUtil.sendInOut("cxfrs:bean:ams.local.account", e, headers, null); + } + + public void getSavingsAccountDefiniton(Exchange e) { + Map headers = new HashMap<>(); + headers.put(CXF_TRACE_HEADER, true); + headers.put(HTTP_METHOD, "GET"); + headers.put(HTTP_PATH, amsAccountDefinitionsPath.replace("{definitionId}", e.getProperty(DEFINITON_ID, String.class))); + headers.putAll(tenantService.getHeaders(e.getProperty(TENANT_ID, String.class))); + cxfrsUtil.sendInOut("cxfrs:bean:ams.local.account", e, headers, null); + } + + public void getSavingsAccounts(Exchange e) { + throw new RuntimeException("getSavingsAccounts not implemented for FineractCN"); + } + + public void getClient(Exchange e) { + Map headers = new HashMap<>(); + headers.put(CXF_TRACE_HEADER, true); + headers.put(HTTP_METHOD, "GET"); + headers.put(HTTP_PATH, amsLocalCustomerPath.replace("{customerIdentifier}", e.getProperty(CLIENT_ID, String.class))); + headers.putAll(tenantService.getHeaders(e.getProperty(TENANT_ID, String.class))); + cxfrsUtil.sendInOut("cxfrs:bean:ams.local.customer", e, headers, null); + } + + public void getClientByMobileNo(Exchange e) { + Map headers = new HashMap<>(); + headers.put(CXF_TRACE_HEADER, true); + headers.put(HTTP_METHOD, "GET"); + headers.put(HTTP_PATH, amsLocalCustomerPath.replace("{customerIdentifier}", e.getProperty(IDENTIFIER_ID, String.class))); + headers.putAll(tenantService.getHeaders(e.getProperty(TENANT_ID, String.class))); + cxfrsUtil.sendInOut("cxfrs:bean:ams.local.customer", e, headers, null); + } + + public void login(Exchange e) { + Map headers = new HashMap<>(); + headers.put(CXF_TRACE_HEADER, true); + headers.put(HTTP_METHOD, "POST"); + headers.put(HTTP_PATH, amsLocalAuthPath); + headers.put(X_TENANT_IDENTIFIER_HEADER, e.getProperty(TENANT_ID)); + headers.put("Content-Type", "application/x-www-form-urlencoded"); + + Map queryMap = new LinkedHashMap<>(); + queryMap.put("grant_type", "password"); + queryMap.put("username", e.getProperty(LOGIN_USERNAME, String.class)); + queryMap.put("password", Base64.getEncoder().encodeToString(e.getProperty(LOGIN_PASSWORD, String.class).getBytes(UTF_8))); + headers.put(CxfConstants.CAMEL_CXF_RS_QUERY_MAP, queryMap); + + cxfrsUtil.sendInOut("cxfrs:bean:ams.local.auth", e, headers, null); + } + + public void getSavingsAccountsTransactions(Exchange e) { + // need this to be filled + + } +} diff --git a/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/ams/interop/AmsFinXService.java b/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/ams/interop/AmsFinXService.java new file mode 100644 index 000000000..57e228194 --- /dev/null +++ b/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/ams/interop/AmsFinXService.java @@ -0,0 +1,115 @@ +package org.mifos.connector.ams.interop; + +import static org.apache.camel.Exchange.HTTP_METHOD; +import static org.apache.camel.Exchange.HTTP_PATH; +import static org.mifos.connector.ams.camel.config.CamelProperties.CLIENT_ID; +import static org.mifos.connector.ams.camel.config.CamelProperties.IDENTIFIER_ID; +import static org.mifos.connector.ams.camel.cxfrs.HeaderBasedInterceptor.CXF_TRACE_HEADER; +import static org.mifos.connector.ams.zeebe.ZeebeVariables.EXTERNAL_ACCOUNT_ID; +import static org.mifos.connector.ams.zeebe.ZeebeVariables.TENANT_ID; + +import java.util.HashMap; +import java.util.Map; +import org.apache.camel.Exchange; +import org.mifos.connector.ams.camel.cxfrs.CxfrsUtil; +import org.mifos.connector.ams.tenant.TenantService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; +import org.springframework.stereotype.Component; + +@Component +@ConditionalOnExpression("'${ams.local.version}'.equals('1.2')") +public class AmsFinXService extends AmsCommonService implements AmsService { + + @Value("${ams.local.interop.accounts-path}") + private String amsInteropAccountsPath; + + @Value("${ams.local.customer.path}") + private String amsClientsPath; + + @Value("${ams.local.customer.image}") + private String amsImagePath; + + @Value("${ams.local.account.savingsaccounts-path}") + private String amsSavingsAccountsPath; + + @Autowired + private TenantService tenantService; + + @Autowired + private CxfrsUtil cxfrsUtil; + + private Logger logger = LoggerFactory.getLogger(this.getClass()); + + public void getSavingsAccount(Exchange e) { + Map headers = new HashMap<>(); + headers.put(CXF_TRACE_HEADER, true); + headers.put(HTTP_METHOD, "GET"); + logger.debug(":{}", amsInteropAccountsPath); + logger.debug(":{}", e.getProperty(EXTERNAL_ACCOUNT_ID, String.class)); + headers.put(HTTP_PATH, amsInteropAccountsPath.replace("{externalAccountId}", e.getProperty(EXTERNAL_ACCOUNT_ID, String.class))); + headers.putAll(tenantService.getHeaders(e.getProperty(TENANT_ID, String.class))); + cxfrsUtil.sendInOut("cxfrs:bean:ams.local.interop", e, headers, null); + } + + public void getSavingsAccountDefiniton(Exchange e) { + throw new RuntimeException("getSavingsAccountDefiniton not implemented for FineractX"); + } + + public void getSavingsAccounts(Exchange e) { + Map headers = new HashMap<>(); + headers.put(CXF_TRACE_HEADER, true); + headers.put(HTTP_METHOD, "GET"); + headers.put(HTTP_PATH, amsSavingsAccountsPath); + headers.putAll(tenantService.getHeaders(e.getProperty(TENANT_ID, String.class))); + cxfrsUtil.sendInOut("cxfrs:bean:ams.local.account", e, headers, null); + } + + public void getSavingsAccountsTransactions(Exchange e) { + Map headers = new HashMap<>(); + headers.put(CXF_TRACE_HEADER, true); + headers.put(HTTP_METHOD, "GET"); + headers.put(HTTP_PATH, + amsInteropAccountsPath.replace("{externalAccountId}", e.getProperty(EXTERNAL_ACCOUNT_ID, String.class) + "/transactions")); + headers.putAll(tenantService.getHeaders(e.getProperty(TENANT_ID, String.class))); + cxfrsUtil.sendInOut("cxfrs:bean:ams.local.account", e, headers, null); + } + + public void getClient(Exchange e) { + Map headers = new HashMap<>(); + headers.put(CXF_TRACE_HEADER, true); + headers.put(HTTP_METHOD, "GET"); + headers.put(HTTP_PATH, amsClientsPath.replace("{clientId}", e.getProperty(CLIENT_ID, String.class))); + headers.putAll(tenantService.getHeaders(e.getProperty(TENANT_ID, String.class))); + cxfrsUtil.sendInOut("cxfrs:bean:ams.local.customer", e, headers, null); + } + + public void getClientImage(Exchange e) { + Map headers = new HashMap<>(); + headers.put(CXF_TRACE_HEADER, true); + headers.put(HTTP_METHOD, "GET"); + headers.put(HTTP_PATH, amsImagePath.replace("{clientId}", e.getProperty(CLIENT_ID, String.class))); + headers.putAll(tenantService.getHeaders(e.getProperty(TENANT_ID, String.class))); + cxfrsUtil.sendInOut("cxfrs:bean:ams.local.customer.image", e, headers, null); + } + + @Override + public void getClientByMobileNo(Exchange e) { + Map headers = new HashMap<>(); + headers.put(CXF_TRACE_HEADER, true); + headers.put(HTTP_METHOD, "GET"); + String path = amsClientsPath.replace("/{clientId}", ""); + path += "?mobileNo=" + e.getProperty(IDENTIFIER_ID, String.class); + headers.put(HTTP_PATH, path); + headers.putAll(tenantService.getHeaders(e.getProperty(TENANT_ID, String.class))); + cxfrsUtil.sendInOut("cxfrs:bean:ams.local.customer", e, headers, null); + } + + @Override + public void login(Exchange e) { + // basic auth + } +} diff --git a/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/ams/interop/AmsService.java b/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/ams/interop/AmsService.java new file mode 100644 index 000000000..85de567b3 --- /dev/null +++ b/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/ams/interop/AmsService.java @@ -0,0 +1,39 @@ +package org.mifos.connector.ams.interop; + +import org.apache.camel.Exchange; +import org.springframework.stereotype.Service; + +@Service +public interface AmsService { + + void getLocalQuote(Exchange e); + + void getExternalAccount(Exchange e); + + void registerInteropIdentifier(Exchange e); + + void removeInteropIdentifier(Exchange e); + + void sendTransfer(Exchange e); + + void repayLoan(Exchange e); + + void login(Exchange e); + + void getSavingsAccount(Exchange e); + + void getSavingsAccountDefiniton(Exchange e); + + void getSavingsAccounts(Exchange e); + + void getClient(Exchange e); + + void getClientByMobileNo(Exchange e); + + void getSavingsAccountsTransactions(Exchange e); + + boolean sendCallback(String callbackURL, String body); + + default void getClientImage(Exchange e) {} + +} diff --git a/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/ams/interop/ClientResponseProcessor.java b/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/ams/interop/ClientResponseProcessor.java new file mode 100644 index 000000000..cd140ca32 --- /dev/null +++ b/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/ams/interop/ClientResponseProcessor.java @@ -0,0 +1,109 @@ +package org.mifos.connector.ams.interop; + +import static org.mifos.connector.ams.camel.config.CamelProperties.ZEEBE_JOB_KEY; +import static org.mifos.connector.ams.zeebe.ZeebeVariables.PARTY_ID; +import static org.mifos.connector.ams.zeebe.ZeebeVariables.PARTY_ID_TYPE; +import static org.mifos.connector.ams.zeebe.ZeebeVariables.PAYEE_PARTY_RESPONSE; +import static org.mifos.connector.ams.zeebe.ZeebeVariables.TENANT_ID; +import static org.mifos.connector.common.ams.dto.LegalForm.PERSON; + +import com.fasterxml.jackson.databind.ObjectMapper; +import io.camunda.zeebe.client.ZeebeClient; +import java.util.HashMap; +import java.util.Map; +import org.apache.camel.Exchange; +import org.apache.camel.Processor; +import org.mifos.connector.ams.errorhandler.ErrorTranslator; +import org.mifos.connector.ams.properties.TenantProperties; +import org.mifos.connector.ams.utils.Utils; +import org.mifos.connector.common.ams.dto.ClientData; +import org.mifos.connector.common.ams.dto.Customer; +import org.mifos.connector.common.ams.dto.EnumOptionData; +import org.mifos.connector.common.ams.dto.LegalForm; +import org.mifos.connector.common.mojaloop.dto.ComplexName; +import org.mifos.connector.common.mojaloop.dto.Party; +import org.mifos.connector.common.mojaloop.dto.PartyIdInfo; +import org.mifos.connector.common.mojaloop.dto.PersonalInfo; +import org.mifos.connector.common.mojaloop.type.IdentifierType; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +@Component +// @ConditionalOnExpression("${ams.local.enabled}") +public class ClientResponseProcessor implements Processor { + + private Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Value("${ams.local.version}") + private String amsVersion; + + @Autowired + private TenantProperties tenantProperties; + + @Autowired + private ObjectMapper objectMapper; + + @Autowired(required = false) + private ZeebeClient zeebeClient; + + @Autowired + private ErrorTranslator errorTranslator; + + @Override + public void process(Exchange exchange) throws Exception { + Integer responseCode = exchange.getIn().getHeader(Exchange.HTTP_RESPONSE_CODE, Integer.class); + String partyIdType = exchange.getProperty(PARTY_ID_TYPE, String.class); + String partyId = exchange.getProperty(PARTY_ID, String.class); + + if (responseCode > 202) { + + Map variables = Utils.getDefaultZeebeErrorVariable(exchange, errorTranslator); + logger.info("Setting error info: {}", variables); + zeebeClient.newCompleteCommand(exchange.getProperty(ZEEBE_JOB_KEY, Long.class)).variables(variables).send(); + } else { + Party mojaloopParty = new Party(new PartyIdInfo(IdentifierType.valueOf(partyIdType), partyId, null, + tenantProperties.getTenant(exchange.getProperty(TENANT_ID, String.class)).getFspId()), null, null, null); + + if ("1.2".equals(amsVersion)) { + ClientData client = exchange.getIn().getBody(ClientData.class); + EnumOptionData legalForm = client.getLegalForm(); + if (legalForm == null + || (legalForm.getValue() != null && PERSON.equals(LegalForm.valueOf(legalForm.getValue().toUpperCase())))) { + PersonalInfo pi = new PersonalInfo(); + pi.setDateOfBirth(client.getDateOfBirth() != null ? client.getDateOfBirth().toString() : null); + ComplexName cn = new ComplexName(); + cn.setFirstName(client.getFirstname()); + cn.setLastName(client.getLastname()); + if (client.getMiddlename() != null && client.getMiddlename().length() > 1) { + cn.setMiddleName(client.getMiddlename()); + } + pi.setComplexName(cn); + mojaloopParty.setPersonalInfo(pi); + } else { // entity + mojaloopParty.setName(client.getFullname()); + } + } else { // cn + Customer client = exchange.getIn().getBody(Customer.class); + if (PERSON.equals(client.getType())) { + PersonalInfo pi = new PersonalInfo(); + pi.setDateOfBirth(client.getDateOfBirth() != null ? client.getDateOfBirth().toString() : null); + ComplexName cn = new ComplexName(); + cn.setFirstName(client.getGivenName()); + cn.setLastName(client.getSurname()); + cn.setMiddleName(client.getMiddleName()); + pi.setComplexName(cn); + mojaloopParty.setPersonalInfo(pi); + } else { + mojaloopParty.setName(client.getGivenName()); + } + } + + Map variables = new HashMap<>(); + variables.put(PAYEE_PARTY_RESPONSE, objectMapper.writeValueAsString(mojaloopParty)); + zeebeClient.newCompleteCommand(exchange.getProperty(ZEEBE_JOB_KEY, Long.class)).variables(variables).send(); + } + } +} diff --git a/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/ams/interop/ErrorParserRouteBuilder.java b/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/ams/interop/ErrorParserRouteBuilder.java new file mode 100644 index 000000000..40a2bb6d2 --- /dev/null +++ b/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/ams/interop/ErrorParserRouteBuilder.java @@ -0,0 +1,51 @@ +package org.mifos.connector.ams.interop; + +import static org.mifos.connector.ams.zeebe.ZeebeVariables.ERROR_CODE; +import static org.mifos.connector.ams.zeebe.ZeebeVariables.ERROR_INFORMATION; +import static org.mifos.connector.ams.zeebe.ZeebeVariables.ERROR_PAYLOAD; +import static org.mifos.connector.ams.zeebe.ZeebeVariables.FINERACT_RESPONSE_BODY; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.apache.camel.Exchange; +import org.apache.camel.LoggingLevel; +import org.apache.camel.model.dataformat.JsonLibrary; +import org.mifos.connector.ams.interop.errordto.ErrorResponse; +import org.mifos.connector.ams.interop.errordto.FineractError; +import org.mifos.connector.common.camel.ErrorHandlerRouteBuilder; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component +// @ConditionalOnExpression("${ams.local.enabled}") +public class ErrorParserRouteBuilder extends ErrorHandlerRouteBuilder { + + @Autowired + private ObjectMapper objectMapper; + + private Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Override + public void configure() { + + // parses error payload from fineract and sets relevant error related variable if error exist + from("direct:error-handler").id("error-handler").log(LoggingLevel.INFO, "Error handler for response ${body}").choice() + // check if http status code is >= 202 + .when(e -> e.getIn().getHeader(Exchange.HTTP_RESPONSE_CODE, Integer.class) >= 400).unmarshal() + .json(JsonLibrary.Jackson, ErrorResponse.class).process(exchange -> { + ErrorResponse errorResponse = exchange.getIn().getBody(ErrorResponse.class); + logger.info("Error response parsed: {}", errorResponse); + try { + FineractError fineractError = errorResponse.getErrors().get(0); + exchange.setProperty(ERROR_CODE, fineractError.getUserMessageGlobalisationCode()); + exchange.setProperty(ERROR_INFORMATION, fineractError.getDefaultUserMessage()); + } catch (Exception e) { + exchange.setProperty(ERROR_CODE, errorResponse.getUserMessageGlobalisationCode()); + exchange.setProperty(ERROR_INFORMATION, errorResponse.getDefaultUserMessage()); + } + exchange.setProperty(ERROR_PAYLOAD, errorResponse); + exchange.setProperty(FINERACT_RESPONSE_BODY, errorResponse); + }).otherwise().endChoice(); + } +} diff --git a/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/ams/interop/InteropPartyResponseProcessor.java b/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/ams/interop/InteropPartyResponseProcessor.java new file mode 100644 index 000000000..bf7b805c3 --- /dev/null +++ b/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/ams/interop/InteropPartyResponseProcessor.java @@ -0,0 +1,65 @@ +package org.mifos.connector.ams.interop; + +import static org.mifos.connector.ams.camel.config.CamelProperties.CONTINUE_PROCESSING; +import static org.mifos.connector.ams.camel.config.CamelProperties.ZEEBE_JOB_KEY; +import static org.mifos.connector.ams.zeebe.ZeebeVariables.ACCOUNT; +import static org.mifos.connector.ams.zeebe.ZeebeVariables.ACCOUNT_CURRENCY; +import static org.mifos.connector.ams.zeebe.ZeebeVariables.ERROR_INFORMATION; +import static org.mifos.connector.ams.zeebe.ZeebeVariables.INTEROP_REGISTRATION_FAILED; +import static org.mifos.connector.ams.zeebe.ZeebeVariables.PARTY_ID; +import static org.mifos.connector.ams.zeebe.ZeebeVariables.PARTY_ID_TYPE; +import static org.mifos.connector.common.camel.ErrorHandlerRouteBuilder.createError; +import static org.mifos.connector.common.mojaloop.type.ErrorCode.INTERNAL_SERVER_ERROR; + +import io.camunda.zeebe.client.ZeebeClient; +import java.util.HashMap; +import java.util.Map; +import org.apache.camel.Exchange; +import org.apache.camel.Processor; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +@Component +// @ConditionalOnExpression("${ams.local.enabled}") +public class InteropPartyResponseProcessor implements Processor { + + private Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Value("${ams.local.version}") + private String amsVersion; + + @Autowired(required = false) + private ZeebeClient zeebeClient; + + @Override + public void process(Exchange e) { + Integer responseCode = e.getIn().getHeader(Exchange.HTTP_RESPONSE_CODE, Integer.class); + + Map variables = new HashMap<>(); + variables.put(INTEROP_REGISTRATION_FAILED, false); + boolean isRequestFailed = false; + if (responseCode > 202) { + isRequestFailed = true; + String errorMsg = String.format( + "Invalid responseCode %s at interop identifier registration, partyIdType: %s partyId: %s account: %s\nExchange:\n%s", + responseCode, e.getProperty(PARTY_ID_TYPE, String.class), e.getProperty(PARTY_ID, String.class), + e.getProperty(ACCOUNT, String.class), e.getIn().getBody(String.class)); + logger.error(errorMsg); + + variables.put(ERROR_INFORMATION, createError(String.valueOf(INTERNAL_SERVER_ERROR.getCode()), errorMsg).toString()); + variables.put(INTEROP_REGISTRATION_FAILED, true); + } + + Boolean continueProcessing = e.getProperty(CONTINUE_PROCESSING, Boolean.class); + if (isRequestFailed || continueProcessing == null || !continueProcessing) { + variables.put(ACCOUNT_CURRENCY, e.getProperty(ACCOUNT_CURRENCY, String.class)); + zeebeClient.newCompleteCommand(e.getProperty(ZEEBE_JOB_KEY, Long.class)).variables(variables).send(); + if (isRequestFailed) { + e.setRouteStop(true); + } + } + } +} diff --git a/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/ams/interop/InteroperationRouteBuilder.java b/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/ams/interop/InteroperationRouteBuilder.java new file mode 100644 index 000000000..572a68e78 --- /dev/null +++ b/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/ams/interop/InteroperationRouteBuilder.java @@ -0,0 +1,391 @@ +package org.mifos.connector.ams.interop; + +import static java.util.Spliterator.ORDERED; +import static java.util.Spliterators.spliteratorUnknownSize; +import static java.util.stream.StreamSupport.stream; +import static org.mifos.connector.ams.camel.config.CamelProperties.CLIENT_ID; +import static org.mifos.connector.ams.camel.config.CamelProperties.CONTINUE_PROCESSING; +import static org.mifos.connector.ams.camel.config.CamelProperties.DEFINITON_ID; +import static org.mifos.connector.ams.camel.config.CamelProperties.EXISTING_EXTERNAL_ACCOUNT_ID; +import static org.mifos.connector.ams.camel.config.CamelProperties.INTEROP_ACCOUNT_TO_REGISTER; +import static org.mifos.connector.ams.camel.config.CamelProperties.IS_ERROR_SET_MANUALLY; +import static org.mifos.connector.ams.camel.config.CamelProperties.PROCESS_TYPE; +import static org.mifos.connector.ams.camel.config.CamelProperties.TRANSACTION_ROLE; +import static org.mifos.connector.ams.camel.config.CamelProperties.TRANSFER_ACTION; +import static org.mifos.connector.ams.camel.config.CamelProperties.X_CALLBACKURL; +import static org.mifos.connector.ams.camel.config.CamelProperties.ZEEBE_JOB_KEY; +import static org.mifos.connector.ams.zeebe.ZeebeVariables.ACCOUNT; +import static org.mifos.connector.ams.zeebe.ZeebeVariables.ACCOUNT_CURRENCY; +import static org.mifos.connector.ams.zeebe.ZeebeVariables.ACCOUNT_ID; +import static org.mifos.connector.ams.zeebe.ZeebeVariables.ACCOUNT_NUMBER; +import static org.mifos.connector.ams.zeebe.ZeebeVariables.CHANNEL_REQUEST; +import static org.mifos.connector.ams.zeebe.ZeebeVariables.ERROR_CODE; +import static org.mifos.connector.ams.zeebe.ZeebeVariables.ERROR_INFORMATION; +import static org.mifos.connector.ams.zeebe.ZeebeVariables.ERROR_PAYLOAD; +import static org.mifos.connector.ams.zeebe.ZeebeVariables.EXTERNAL_ACCOUNT_ID; +import static org.mifos.connector.ams.zeebe.ZeebeVariables.FINERACT_RESPONSE_BODY; +import static org.mifos.connector.ams.zeebe.ZeebeVariables.PARTY_ID; +import static org.mifos.connector.ams.zeebe.ZeebeVariables.PARTY_ID_TYPE; +import static org.mifos.connector.ams.zeebe.ZeebeVariables.TENANT_ID; +import static org.mifos.connector.ams.zeebe.ZeebeVariables.TRANSACTION_ID; +import static org.mifos.connector.ams.zeebe.ZeebeVariables.TRANSFER_CODE; +import static org.mifos.connector.ams.zeebe.ZeebeVariables.TRANSFER_CREATE_FAILED; +import static org.mifos.connector.ams.zeebe.ZeebeVariables.TRANSFER_PREPARE_FAILED; +import static org.mifos.connector.common.ams.dto.TransferActionType.CREATE; + +import com.fasterxml.jackson.databind.ObjectMapper; +import io.camunda.zeebe.client.ZeebeClient; +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; +import java.util.UUID; +import org.apache.camel.Exchange; +import org.apache.camel.LoggingLevel; +import org.apache.camel.Processor; +import org.apache.camel.model.dataformat.JsonLibrary; +import org.json.JSONObject; +import org.mifos.connector.ams.errorhandler.ErrorTranslator; +import org.mifos.connector.ams.tenant.TenantNotExistException; +import org.mifos.connector.ams.utils.Utils; +import org.mifos.connector.ams.zeebe.ZeebeUtil; +import org.mifos.connector.common.ams.dto.ClientData; +import org.mifos.connector.common.ams.dto.Customer; +import org.mifos.connector.common.ams.dto.InteropAccountDTO; +import org.mifos.connector.common.ams.dto.LoanRepaymentDTO; +import org.mifos.connector.common.ams.dto.LoginFineractCnResponseDTO; +import org.mifos.connector.common.ams.dto.PartyFspResponseDTO; +import org.mifos.connector.common.ams.dto.ProductDefinition; +import org.mifos.connector.common.ams.dto.ProductInstance; +import org.mifos.connector.common.camel.ErrorHandlerRouteBuilder; +import org.mifos.connector.common.channel.dto.TransactionChannelRequestDTO; +import org.mifos.connector.common.exception.PaymentHubError; +import org.mifos.connector.common.mojaloop.dto.TransactionType; +import org.mifos.connector.common.mojaloop.type.InitiatorType; +import org.mifos.connector.common.mojaloop.type.Scenario; +import org.mifos.connector.common.mojaloop.type.TransactionRole; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +@Component +// @ConditionalOnExpression("${ams.local.enabled}") +public class InteroperationRouteBuilder extends ErrorHandlerRouteBuilder { + + @Value("${ams.local.version}") + private String amsVersion; + + @Autowired + private Processor pojoToString; + + @Autowired(required = false) + private AmsService amsService; + + @Autowired + private PrepareLocalQuoteRequest prepareLocalQuoteRequest; + + @Autowired + private QuoteResponseProcessor quoteResponseProcessor; + + @Autowired + private PrepareTransferRequest prepareTransferRequest; + + @Autowired + private TransfersResponseProcessor transfersResponseProcessor; + + @Autowired + private ClientResponseProcessor clientResponseProcessor; + + @Autowired + private InteropPartyResponseProcessor interopPartyResponseProcessor; + + @Autowired + private ObjectMapper objectMapper; + + @Autowired + private ZeebeClient zeebeClient; + + @Autowired + private ErrorTranslator errorTranslator; + + private Logger logger = LoggerFactory.getLogger(this.getClass()); + private String callbackUrl; + private String fineractResponseBody; + + public InteroperationRouteBuilder() { + super.configure(); + } + + @Override + public void configure() { + onException(TenantNotExistException.class).process(e -> { + e.getIn().setHeader(Exchange.HTTP_RESPONSE_CODE, 404); + Exception exception = e.getException(); + if (exception != null) { + e.getIn().setBody(exception.getMessage()); + } + }).process(clientResponseProcessor).stop(); + + from("direct:get-external-account").id("get-external-account") + .log(LoggingLevel.INFO, + "Get externalAccount with identifierType: ${exchangeProperty." + PARTY_ID_TYPE + "} with value: ${exchangeProperty." + + PARTY_ID + "}") + // .process(amsService::getExternalAccount) + .process(exchange -> { + try { + amsService.getExternalAccount(exchange); + } catch (TenantNotExistException e) { + log.debug(e.getMessage()); + exchange.setProperty(ERROR_CODE, PaymentHubError.PayeeFspNotConfigured.getErrorCode()); + exchange.setProperty(ERROR_INFORMATION, PaymentHubError.PayeeFspNotConfigured.getErrorDescription()); + exchange.setProperty(ERROR_PAYLOAD, PaymentHubError.PayeeFspNotConfigured.getErrorDescription()); + exchange.getIn().setHeader(Exchange.HTTP_RESPONSE_CODE, 404); + exchange.setProperty(IS_ERROR_SET_MANUALLY, true); + } + }).log("Response body from get-external-account").choice() + + // check if http status code is <= 202 + .when(e -> e.getIn().getHeader(Exchange.HTTP_RESPONSE_CODE, Integer.class) <= 202).unmarshal() + .json(JsonLibrary.Jackson, PartyFspResponseDTO.class) + .process(e -> e.setProperty(EXTERNAL_ACCOUNT_ID, e.getIn().getBody(PartyFspResponseDTO.class).getAccountId())) + .process(exchange -> { + PartyFspResponseDTO dto = exchange.getIn().getBody(PartyFspResponseDTO.class); + + logger.info("Account Id: {}", dto.getAccountId()); + logger.info("Http response code: {}", exchange.getIn().getHeader(Exchange.HTTP_RESPONSE_CODE, Integer.class)); + }).when(e -> e.getProperty(IS_ERROR_SET_MANUALLY, Boolean.class) == null + || !e.getProperty(IS_ERROR_SET_MANUALLY, Boolean.class)) + .to("direct:error-handler").otherwise().endChoice(); + + from("direct:send-local-quote").id("send-local-quote").to("direct:get-external-account") + .log(LoggingLevel.INFO, "Sending local quote request for transaction: ${exchangeProperty." + TRANSACTION_ID + "}") + .process(prepareLocalQuoteRequest).process(pojoToString).process(amsService::getLocalQuote).process(quoteResponseProcessor); + + from("direct:send-transfers").id("send-transfers") + .log(LoggingLevel.INFO, + "Sending transfer with action: ${exchangeProperty." + TRANSFER_ACTION + "} " + + " for transaction: ${exchangeProperty." + TRANSACTION_ID + "}") + .to("direct:get-external-account").process(prepareTransferRequest).process(pojoToString).process(amsService::sendTransfer) + .to("direct:error-handler") // this route will parse and set error field if exist + .log("Process type: ${exchangeProperty." + PROCESS_TYPE + "}").choice() + .when(exchange -> exchange.getProperty(PROCESS_TYPE) != null && exchange.getProperty(PROCESS_TYPE).equals("api")) + .process(exchange -> { + int statusCode = exchange.getIn().getHeader(Exchange.HTTP_RESPONSE_CODE, Integer.class); + if (statusCode > 202) { + Map variables = Utils.getDefaultZeebeErrorVariable(exchange, errorTranslator); + variables.put(FINERACT_RESPONSE_BODY, exchange.getIn().getBody(String.class)); + zeebeClient.newCompleteCommand(exchange.getProperty(ZEEBE_JOB_KEY, Long.class)).variables(variables).send(); + + logger.error("{}", variables.get(ERROR_INFORMATION)); + } else { + Map variables = new HashMap<>(); + JSONObject responseJson = new JSONObject(exchange.getIn().getBody(String.class)); + variables.put(TRANSFER_PREPARE_FAILED, false); + variables.put(TRANSFER_CREATE_FAILED, false); + variables.put("payeeTenantId", exchange.getProperty("payeeTenantId")); + variables.put(TRANSFER_CODE, responseJson.getString("transferCode")); + logger.info("API call successful. Response Body: " + exchange.getIn().getBody(String.class)); + variables.put(FINERACT_RESPONSE_BODY, exchange.getIn().getBody(String.class)); + zeebeClient.newCompleteCommand(exchange.getProperty(ZEEBE_JOB_KEY, Long.class)).variables(variables).send(); + } + + logger.info("End of process in send-transfers"); + }).otherwise().process(transfersResponseProcessor).end(); + + from("direct:send-transfers-loan").id("send-transfers-loan") + .log(LoggingLevel.DEBUG, + "Sending transfer with action: ${exchangeProperty." + TRANSFER_ACTION + "} " + + " for transaction: ${exchangeProperty." + TRANSACTION_ID + "}") + .log("Process type: ${exchangeProperty." + PROCESS_TYPE + "}").process(exchange -> { + LoanRepaymentDTO loanRepaymentDTO = ZeebeUtil.setLoanRepaymentBody(exchange); + String requestBody = objectMapper.writeValueAsString(loanRepaymentDTO); + logger.debug("Request Body : {}", requestBody); + exchange.getIn().setBody(requestBody); + exchange.setProperty("accountNumber", exchange.getProperty(ACCOUNT_NUMBER)); + }).process(amsService::repayLoan).to("direct:error-handler") // this route will parse and set error + // field if exist + .log("Process type: ${exchangeProperty." + PROCESS_TYPE + "}").choice() + .when(exchange -> exchange.getProperty(PROCESS_TYPE) != null && exchange.getProperty(PROCESS_TYPE).equals("api")) + .process(exchange -> { + int statusCode = exchange.getIn().getHeader(Exchange.HTTP_RESPONSE_CODE, Integer.class); + if (statusCode > 202) { + Map variables = Utils.getDefaultZeebeErrorVariable(exchange, errorTranslator); + variables.put(FINERACT_RESPONSE_BODY, exchange.getIn().getBody(String.class)); + zeebeClient.newCompleteCommand(exchange.getProperty(ZEEBE_JOB_KEY, Long.class)).variables(variables).send(); + + logger.error("{}", variables.get(ERROR_INFORMATION)); + } else { + Map variables = new HashMap<>(); + JSONObject responseJson = new JSONObject(exchange.getIn().getBody(String.class)); + variables.put(TRANSFER_PREPARE_FAILED, false); + variables.put(TRANSFER_CREATE_FAILED, false); + variables.put("payeeTenantId", exchange.getProperty("payeeTenantId")); + variables.put(TRANSFER_CODE, responseJson.getString("transferCode")); + logger.info("API call successful. Response Body: " + exchange.getIn().getBody(String.class)); + variables.put(FINERACT_RESPONSE_BODY, exchange.getIn().getBody(String.class)); + zeebeClient.newCompleteCommand(exchange.getProperty(ZEEBE_JOB_KEY, Long.class)).variables(variables).send(); + } + + logger.info("End of process in send-transfers-loan"); + }).otherwise().process(transfersResponseProcessor).end(); + + from("direct:fincn-oauth").id("fincn-oauth") + .log(LoggingLevel.INFO, "Fineract CN oauth request for tenant: ${exchangeProperty." + TENANT_ID + "}") + .process(amsService::login).unmarshal().json(JsonLibrary.Jackson, LoginFineractCnResponseDTO.class); + + // @formatter:off + from("direct:get-party") + .id("get-party") + .log(LoggingLevel.INFO, "Get party information for identifierType: ${exchangeProperty." + PARTY_ID_TYPE + "} with value: ${exchangeProperty." + PARTY_ID + "}") + .to("direct:get-external-account") + .process(e -> e.setProperty(ACCOUNT_ID, e.getProperty(EXTERNAL_ACCOUNT_ID))) + .choice() + .when(e -> e.getProperty(ACCOUNT_ID) == null) + .log(LoggingLevel.INFO, "AccountId is null") + .process(clientResponseProcessor) + .otherwise() + .process(amsService::getSavingsAccount) + .choice() + .when(e -> "1.2".equals(amsVersion)) + .unmarshal().json(JsonLibrary.Jackson, InteropAccountDTO.class) + .process(e -> e.setProperty(CLIENT_ID, e.getIn().getBody(InteropAccountDTO.class).getClientId())) + .process(amsService::getClient) + .unmarshal().json(JsonLibrary.Jackson, ClientData.class) + .endChoice() + .otherwise() // cn + .unmarshal().json(JsonLibrary.Jackson, ProductInstance.class) + .process(e -> e.setProperty(CLIENT_ID, e.getIn().getBody(ProductInstance.class).getCustomerIdentifier())) + .process(amsService::getClient) + .unmarshal().json(JsonLibrary.Jackson, Customer.class) + .endChoice() + .end() + .process(clientResponseProcessor); + // @formatter:on + + // @formatter:off + from("direct:register-party") + .id("register-party") + .log(LoggingLevel.INFO, "Register party with type: ${exchangeProperty." + PARTY_ID_TYPE + "} identifier: ${exchangeProperty." + PARTY_ID + "} account ${exchangeProperty." + ACCOUNT + "}") + .choice() + .when(e -> "1.2".equals(amsVersion)) + .to("direct:register-party-finx") + .endChoice() + .otherwise() + .to("direct:register-party-fincn") + .endChoice() + .end(); + + from("direct:register-party-finx") + .process(amsService::getSavingsAccounts) + .setProperty(CONTINUE_PROCESSING, constant(true)) + .process(interopPartyResponseProcessor) + .process(e -> { + Optional account = stream(spliteratorUnknownSize(// TODO this solution is potentially bad if there are too many accounts in the system + new JSONObject(e.getIn().getBody(String.class)).getJSONArray("pageItems").iterator(), + ORDERED), false) + .filter(sa -> e.getProperty(ACCOUNT, String.class).equals(((JSONObject)sa).getString("accountNo"))) + .findFirst(); + if (!account.isPresent()) { + e.getIn().setHeader(Exchange.HTTP_RESPONSE_CODE, 404); + } else { + JSONObject jsonAccount = (JSONObject)account.get(); + e.setProperty(ACCOUNT_ID, jsonAccount.getString("accountNo")); + e.setProperty(ACCOUNT_CURRENCY, jsonAccount.getJSONObject("currency").getString("code")); + e.setProperty(EXISTING_EXTERNAL_ACCOUNT_ID, jsonAccount.getString("externalId")); + e.setProperty(INTEROP_ACCOUNT_TO_REGISTER, jsonAccount.getString("externalId")); + } + }) + .process(interopPartyResponseProcessor) + .to("direct:get-external-account") + .choice() + .when(e -> e.getProperty(EXTERNAL_ACCOUNT_ID) == null) // identifier not registered to any account + .setProperty(CONTINUE_PROCESSING, constant(false)) + .to("direct:add-interop-identifier-to-account") + .endChoice() + .when(e -> !e.getProperty(EXTERNAL_ACCOUNT_ID, String.class).equals(e.getProperty(EXISTING_EXTERNAL_ACCOUNT_ID, String.class))) // identifier registered to other account + .to("direct:remove-interop-identifier-from-account") + .setProperty(CONTINUE_PROCESSING, constant(false)) + .to("direct:add-interop-identifier-to-account") + .endChoice() + .otherwise() + .setProperty(CONTINUE_PROCESSING, constant(false)) + .process(interopPartyResponseProcessor) // identifier already registered to the selected account + .endChoice() + .end(); + + from("direct:register-party-fincn") + .process(e -> e.setProperty(ACCOUNT_ID, e.getProperty(ACCOUNT))) + .process(amsService::getSavingsAccount) + .setProperty(CONTINUE_PROCESSING, constant(true)) + .process(interopPartyResponseProcessor) + .unmarshal().json(JsonLibrary.Jackson, ProductInstance.class) + .process(e -> e.setProperty(DEFINITON_ID, e.getIn().getBody(ProductInstance.class).getProductIdentifier())) + .process(amsService::getSavingsAccountDefiniton) + .process(interopPartyResponseProcessor) + .unmarshal().json(JsonLibrary.Jackson, ProductDefinition.class) + .process(e -> e.setProperty(ACCOUNT_CURRENCY, e.getIn().getBody(ProductDefinition.class).getCurrency().getCode())) + .setProperty(INTEROP_ACCOUNT_TO_REGISTER, simple("${exchangeProperty." + ACCOUNT_ID + "}")) + .to("direct:get-external-account") + .choice() + .when(e -> e.getProperty(EXTERNAL_ACCOUNT_ID) == null) // identifier not registered to any account + .setProperty(CONTINUE_PROCESSING, constant(false)) + .to("direct:add-interop-identifier-to-account") + .endChoice() + .when(e -> !e.getProperty(EXTERNAL_ACCOUNT_ID, String.class).equals(e.getProperty(ACCOUNT_ID, String.class))) // identifier registered to other account + .to("direct:remove-interop-identifier-from-account") + .setProperty(CONTINUE_PROCESSING, constant(false)) + .to("direct:add-interop-identifier-to-account") + .endChoice() + .otherwise() // identifier already registered to the account + .setProperty(CONTINUE_PROCESSING, constant(false)) + .process(interopPartyResponseProcessor) + .endChoice() + .end(); + // @formatter:on + + from("direct:add-interop-identifier-to-account").id("add-interop-identifier-to-account").process(e -> { + JSONObject request = new JSONObject(); + request.put("accountId", e.getProperty(INTEROP_ACCOUNT_TO_REGISTER)); + e.getIn().setBody(request.toString()); + }).process(amsService::registerInteropIdentifier).process(interopPartyResponseProcessor); + + from("direct:remove-interop-identifier-from-account").id("remove-interop-identifier-from-account") + .process(amsService::removeInteropIdentifier).process(interopPartyResponseProcessor); + + // Direct API to deposit PAYEE initiated money + from("rest:POST:/transfer/deposit").log(LoggingLevel.INFO, "Deposit call: ${body}").unmarshal() + .json(JsonLibrary.Jackson, TransactionChannelRequestDTO.class).process(exchange -> { + exchange.setProperty(PROCESS_TYPE, "api"); + exchange.setProperty(TRANSACTION_ID, UUID.randomUUID().toString()); + exchange.setProperty(TENANT_ID, exchange.getIn().getHeader("Platform-TenantId")); + exchange.setProperty(TRANSFER_ACTION, CREATE.name()); + + TransactionChannelRequestDTO transactionRequest = exchange.getIn().getBody(TransactionChannelRequestDTO.class); + TransactionType transactionType = new TransactionType(); + transactionType.setInitiator(TransactionRole.PAYEE); + transactionType.setInitiatorType(InitiatorType.CONSUMER); + transactionType.setScenario(Scenario.DEPOSIT); + transactionRequest.setTransactionType(transactionType); + + exchange.setProperty(CHANNEL_REQUEST, objectMapper.writeValueAsString(transactionRequest)); + exchange.setProperty(TRANSACTION_ROLE, TransactionRole.PAYEE.name()); + + exchange.setProperty(PARTY_ID_TYPE, transactionRequest.getPayee().getPartyIdInfo().getPartyIdType()); + exchange.setProperty(PARTY_ID, transactionRequest.getPayee().getPartyIdInfo().getPartyIdentifier()); + }).to("direct:send-transfers"); + + from("direct:send-callback").id("send-callback") + .log(LoggingLevel.DEBUG, + "Sending callback with action: ${exchangeProperty." + TRANSFER_ACTION + "} " + + " for transaction: ${exchangeProperty." + TRANSACTION_ID + "}") + .log("Process type: ${exchangeProperty." + PROCESS_TYPE + "}").process(exchange -> { + if (exchange.getProperties().containsKey(FINERACT_RESPONSE_BODY)) { + fineractResponseBody = exchange.getProperty(FINERACT_RESPONSE_BODY).toString(); + } + callbackUrl = exchange.getProperty(X_CALLBACKURL).toString(); + boolean callbackSent = amsService.sendCallback(callbackUrl, fineractResponseBody); + exchange.setProperty("callbackSent", callbackSent); + }); + } +} diff --git a/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/ams/interop/PrepareLocalQuoteRequest.java b/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/ams/interop/PrepareLocalQuoteRequest.java new file mode 100644 index 000000000..4802d5fe4 --- /dev/null +++ b/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/ams/interop/PrepareLocalQuoteRequest.java @@ -0,0 +1,44 @@ +package org.mifos.connector.ams.interop; + +import static org.mifos.connector.ams.camel.config.CamelProperties.QUOTE_AMOUNT_TYPE; +import static org.mifos.connector.ams.camel.config.CamelProperties.TRANSACTION_ROLE; +import static org.mifos.connector.ams.zeebe.ZeebeVariables.CHANNEL_REQUEST; +import static org.mifos.connector.ams.zeebe.ZeebeVariables.EXTERNAL_ACCOUNT_ID; +import static org.mifos.connector.ams.zeebe.ZeebeVariables.TRANSACTION_ID; + +import com.fasterxml.jackson.databind.ObjectMapper; +import java.util.UUID; +import org.apache.camel.Exchange; +import org.apache.camel.Processor; +import org.mifos.connector.common.ams.dto.QuoteFspRequestDTO; +import org.mifos.connector.common.channel.dto.TransactionChannelRequestDTO; +import org.mifos.connector.common.mojaloop.dto.FspMoneyData; +import org.mifos.connector.common.mojaloop.type.AmountType; +import org.mifos.connector.common.mojaloop.type.TransactionRole; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component +// @ConditionalOnExpression("${ams.local.enabled}") +public class PrepareLocalQuoteRequest implements Processor { + + @Autowired + private ObjectMapper objectMapper; + + @Override + public void process(Exchange exchange) throws Exception { + TransactionChannelRequestDTO channelRequest = objectMapper.readValue(exchange.getProperty(CHANNEL_REQUEST, String.class), + TransactionChannelRequestDTO.class); + + String requestCode = UUID.randomUUID().toString(); + String quoteId = UUID.randomUUID().toString(); + + FspMoneyData amount = new FspMoneyData(channelRequest.getAmount().getAmountDecimal(), channelRequest.getAmount().getCurrency()); + QuoteFspRequestDTO request = new QuoteFspRequestDTO(exchange.getProperty(TRANSACTION_ID, String.class), requestCode, quoteId, + exchange.getProperty(EXTERNAL_ACCOUNT_ID, String.class), amount, + AmountType.valueOf(exchange.getProperty(QUOTE_AMOUNT_TYPE, String.class)), + TransactionRole.valueOf(exchange.getProperty(TRANSACTION_ROLE, String.class)), channelRequest.getTransactionType()); + + exchange.getIn().setBody(request); + } +} diff --git a/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/ams/interop/PrepareTransferRequest.java b/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/ams/interop/PrepareTransferRequest.java new file mode 100644 index 000000000..64609d9fb --- /dev/null +++ b/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/ams/interop/PrepareTransferRequest.java @@ -0,0 +1,84 @@ +package org.mifos.connector.ams.interop; + +import static org.mifos.connector.ams.camel.config.CamelProperties.TRANSACTION_ROLE; +import static org.mifos.connector.ams.zeebe.ZeebeUtil.zeebeVariable; +import static org.mifos.connector.ams.zeebe.ZeebeVariables.BOOK_TRANSACTION_ID; +import static org.mifos.connector.ams.zeebe.ZeebeVariables.EXTERNAL_ACCOUNT_ID; +import static org.mifos.connector.ams.zeebe.ZeebeVariables.NOTE; +import static org.mifos.connector.ams.zeebe.ZeebeVariables.TRANSACTION_ID; +import static org.mifos.connector.ams.zeebe.ZeebeVariables.TRANSFER_CODE; + +import com.fasterxml.jackson.databind.ObjectMapper; +import java.util.UUID; +import org.apache.camel.Exchange; +import org.apache.camel.Processor; +import org.mifos.connector.common.ams.dto.TransferFspRequestDTO; +import org.mifos.connector.common.mojaloop.dto.FspMoneyData; +import org.mifos.connector.common.mojaloop.dto.TransactionType; +import org.mifos.connector.common.mojaloop.type.InitiatorType; +import org.mifos.connector.common.mojaloop.type.Scenario; +import org.mifos.connector.common.mojaloop.type.TransactionRole; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component +// @ConditionalOnExpression("${ams.local.enabled}") +public class PrepareTransferRequest implements Processor { + + private Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Autowired + private ObjectMapper objectMapper; + + @Override + public void process(Exchange exchange) throws Exception { + String initiator = zeebeVariable(exchange, "initiator", String.class); + String initiatorType = zeebeVariable(exchange, "initiatorType", String.class); + String scenario = zeebeVariable(exchange, "scenario", String.class); + + logger.info("Preparing transfer request for initiator: {}, initiatorType: {}, scenario: {}", initiator, initiatorType, scenario); + + TransactionType transactionType = new TransactionType(); + transactionType.setInitiator(TransactionRole.valueOf(initiator)); + transactionType.setInitiatorType(InitiatorType.valueOf(initiatorType)); + transactionType.setScenario(Scenario.valueOf(scenario)); + + String note = zeebeVariable(exchange, NOTE, String.class); + FspMoneyData amount = zeebeVariable(exchange, "amount", FspMoneyData.class); + FspMoneyData fspFee = zeebeVariable(exchange, "fspFee", FspMoneyData.class); + FspMoneyData fspCommission = zeebeVariable(exchange, "fspCommission", FspMoneyData.class); + + String existingTransferCode = exchange.getProperty(TRANSFER_CODE, String.class); + String transferCode; + if (existingTransferCode != null) { + logger.info("Existing code not null"); + transferCode = existingTransferCode; + } else { + logger.info("Existing code null"); + transferCode = UUID.randomUUID().toString(); + exchange.setProperty(TRANSFER_CODE, transferCode); + } + + String transactionCode = exchange.getProperty(BOOK_TRANSACTION_ID, String.class) != null + ? exchange.getProperty(BOOK_TRANSACTION_ID, String.class) + : exchange.getProperty(TRANSACTION_ID, String.class); + logger.debug("using transaction code {}", transactionCode); + + TransferFspRequestDTO transferRequestDTO = null; + + if (fspFee != null || fspCommission != null) { + transferRequestDTO = new TransferFspRequestDTO(transactionCode, transferCode, + exchange.getProperty(EXTERNAL_ACCOUNT_ID, String.class), amount, fspFee, fspCommission, + TransactionRole.valueOf(exchange.getProperty(TRANSACTION_ROLE, String.class)), transactionType, note); + } else { + transferRequestDTO = new TransferFspRequestDTO(transactionCode, transferCode, + exchange.getProperty(EXTERNAL_ACCOUNT_ID, String.class), amount, + TransactionRole.valueOf(exchange.getProperty(TRANSACTION_ROLE, String.class))); + } + + logger.debug("prepared transferRequestDTO: {}", objectMapper.writeValueAsString(transferRequestDTO)); + exchange.getIn().setBody(transferRequestDTO); + } +} diff --git a/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/ams/interop/QuoteResponseProcessor.java b/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/ams/interop/QuoteResponseProcessor.java new file mode 100644 index 000000000..b543370f8 --- /dev/null +++ b/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/ams/interop/QuoteResponseProcessor.java @@ -0,0 +1,80 @@ +package org.mifos.connector.ams.interop; + +import static org.mifos.connector.ams.camel.config.CamelProperties.TRANSACTION_ROLE; +import static org.mifos.connector.ams.camel.config.CamelProperties.ZEEBE_JOB_KEY; +import static org.mifos.connector.ams.zeebe.ZeebeVariables.ERROR_INFORMATION; +import static org.mifos.connector.ams.zeebe.ZeebeVariables.EXTERNAL_ACCOUNT_ID; +import static org.mifos.connector.ams.zeebe.ZeebeVariables.LOCAL_QUOTE_FAILED; +import static org.mifos.connector.ams.zeebe.ZeebeVariables.LOCAL_QUOTE_RESPONSE; +import static org.mifos.connector.ams.zeebe.ZeebeVariables.QUOTE_FAILED; +import static org.mifos.connector.ams.zeebe.ZeebeVariables.TENANT_ID; +import static org.mifos.connector.ams.zeebe.ZeebeVariables.TRANSACTION_ID; +import static org.mifos.connector.common.camel.ErrorHandlerRouteBuilder.createError; +import static org.mifos.connector.common.mojaloop.type.ErrorCode.PAYEE_FSP_REJECTED_QUOTE; +import static org.mifos.connector.common.mojaloop.type.ErrorCode.PAYER_FSP_INSUFFICIENT_LIQUIDITY; + +import com.fasterxml.jackson.databind.ObjectMapper; +import io.camunda.zeebe.client.ZeebeClient; +import java.util.HashMap; +import java.util.Map; +import org.apache.camel.Exchange; +import org.apache.camel.Processor; +import org.mifos.connector.common.ams.dto.QuoteFspResponseDTO; +import org.mifos.connector.common.mojaloop.type.TransactionRole; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component +// @ConditionalOnExpression("${ams.local.enabled}") +public class QuoteResponseProcessor implements Processor { + + private Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Autowired(required = false) + private ZeebeClient zeebeClient; + + @Autowired + private ObjectMapper objectMapper; + + @Override + public void process(Exchange exchange) throws Exception { + Integer responseCode = exchange.getIn().getHeader(Exchange.HTTP_RESPONSE_CODE, Integer.class); + Long jobKey = exchange.getProperty(ZEEBE_JOB_KEY, Long.class); + String transactionRole = exchange.getProperty(TRANSACTION_ROLE, String.class); + if (responseCode > 202) { + String errorMsg = String.format("Invalid responseCode %s for quote on %s side, transactionId: %s Message: %s", responseCode, + transactionRole, exchange.getProperty(TRANSACTION_ID), exchange.getIn().getBody(String.class)); + + logger.error(errorMsg); + + final String errorCode; + final String errorKey; + if (transactionRole.equals(TransactionRole.PAYER.name())) { + errorCode = String.valueOf(PAYER_FSP_INSUFFICIENT_LIQUIDITY.getCode()); + errorKey = LOCAL_QUOTE_FAILED; + } else { // payee + errorCode = String.valueOf(PAYEE_FSP_REJECTED_QUOTE.getCode()); + errorKey = QUOTE_FAILED; + } + + Map variables = new HashMap<>(); + variables.put(ERROR_INFORMATION, createError(errorCode, errorMsg).toString()); + variables.put(errorKey, true); + + zeebeClient.newCompleteCommand(jobKey).variables(variables).send(); + } else { + Map variables = new HashMap<>(); + QuoteFspResponseDTO quoteResponse = objectMapper.readValue(exchange.getIn().getBody(String.class), QuoteFspResponseDTO.class); + variables.put(LOCAL_QUOTE_RESPONSE, objectMapper.writeValueAsString(quoteResponse)); + variables.put("fspFee", quoteResponse.getFspFee()); + variables.put("fspCommission", quoteResponse.getFspCommission()); + variables.put(EXTERNAL_ACCOUNT_ID, exchange.getProperty(EXTERNAL_ACCOUNT_ID)); + variables.put(TENANT_ID, exchange.getProperty(TENANT_ID)); + variables.put(transactionRole.equals(TransactionRole.PAYER.name()) ? LOCAL_QUOTE_FAILED : QUOTE_FAILED, false); + + zeebeClient.newCompleteCommand(jobKey).variables(variables).send(); + } + } +} diff --git a/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/ams/interop/TransfersResponseProcessor.java b/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/ams/interop/TransfersResponseProcessor.java new file mode 100644 index 000000000..112a9b6cd --- /dev/null +++ b/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/ams/interop/TransfersResponseProcessor.java @@ -0,0 +1,66 @@ +package org.mifos.connector.ams.interop; + +import static org.mifos.connector.ams.camel.config.CamelProperties.TRANSFER_ACTION; +import static org.mifos.connector.ams.camel.config.CamelProperties.ZEEBE_JOB_KEY; +import static org.mifos.connector.ams.zeebe.ZeebeVariables.ACTION_FAILURE_MAP; +import static org.mifos.connector.ams.zeebe.ZeebeVariables.ERROR_CODE; +import static org.mifos.connector.ams.zeebe.ZeebeVariables.ERROR_INFORMATION; +import static org.mifos.connector.ams.zeebe.ZeebeVariables.ERROR_PAYLOAD; +import static org.mifos.connector.ams.zeebe.ZeebeVariables.FINERACT_RESPONSE_BODY; +import static org.mifos.connector.ams.zeebe.ZeebeVariables.TRANSFER_CODE; +import static org.mifos.connector.ams.zeebe.ZeebeVariables.TRANSFER_CREATE_FAILED; +import static org.mifos.connector.ams.zeebe.ZeebeVariables.TRANSFER_RESPONSE_PREFIX; +import static org.mifos.connector.common.ams.dto.TransferActionType.PREPARE; + +import io.camunda.zeebe.client.ZeebeClient; +import java.util.HashMap; +import java.util.Map; +import org.apache.camel.Exchange; +import org.apache.camel.Processor; +import org.mifos.connector.ams.errorhandler.ErrorTranslator; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component +// @ConditionalOnExpression("${ams.local.enabled}") +public class TransfersResponseProcessor implements Processor { + + private Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Autowired(required = false) + private ZeebeClient zeebeClient; + + @Autowired + private ErrorTranslator errorTranslator; + + @Override + public void process(Exchange exchange) { + Integer responseCode = exchange.getIn().getHeader(Exchange.HTTP_RESPONSE_CODE, Integer.class); + String transferAction = exchange.getProperty(TRANSFER_ACTION, String.class); + + Map variables = new HashMap<>(); + variables.put(TRANSFER_CREATE_FAILED, responseCode > 202); + + if (responseCode > 202) { + + variables.put(ERROR_CODE, exchange.getProperty(ERROR_CODE)); + variables.put(ERROR_INFORMATION, exchange.getProperty(ERROR_INFORMATION)); + variables.put(ERROR_PAYLOAD, exchange.getProperty(ERROR_PAYLOAD)); + variables = errorTranslator.translateError(variables); + + variables.put(ACTION_FAILURE_MAP.get(transferAction), true); + + } else { + variables.put(TRANSFER_RESPONSE_PREFIX + "-" + transferAction, exchange.getIn().getBody()); + if (PREPARE.name().equals(transferAction)) { + variables.put(TRANSFER_CODE, exchange.getProperty(TRANSFER_CODE)); + } + variables.put(ACTION_FAILURE_MAP.get(transferAction), false); + } + variables.put(FINERACT_RESPONSE_BODY, exchange.getIn().getBody()); + zeebeClient.newCompleteCommand(exchange.getProperty(ZEEBE_JOB_KEY, Long.class)).variables(variables).send(); + logger.info("Completed job with key: {}", exchange.getProperty(ZEEBE_JOB_KEY, Long.class)); + } +} diff --git a/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/ams/interop/errordto/Args.java b/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/ams/interop/errordto/Args.java new file mode 100644 index 000000000..78217673c --- /dev/null +++ b/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/ams/interop/errordto/Args.java @@ -0,0 +1,13 @@ +package org.mifos.connector.ams.interop.errordto; + +import lombok.Getter; +import lombok.Setter; +import lombok.ToString; + +@Getter +@Setter +@ToString +public class Args { + + private Object value; +} diff --git a/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/ams/interop/errordto/ErrorResponse.java b/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/ams/interop/errordto/ErrorResponse.java new file mode 100644 index 000000000..3f0a5e4d3 --- /dev/null +++ b/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/ams/interop/errordto/ErrorResponse.java @@ -0,0 +1,19 @@ +package org.mifos.connector.ams.interop.errordto; + +import java.util.ArrayList; +import lombok.Getter; +import lombok.Setter; +import lombok.ToString; + +@Getter +@Setter +@ToString +public class ErrorResponse { + + public String developerMessage; + public String httpStatusCode; + public String defaultUserMessage; + public String userMessageGlobalisationCode; + public ArrayList errors; + +} diff --git a/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/ams/interop/errordto/FineractError.java b/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/ams/interop/errordto/FineractError.java new file mode 100644 index 000000000..0870169a7 --- /dev/null +++ b/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/ams/interop/errordto/FineractError.java @@ -0,0 +1,20 @@ +package org.mifos.connector.ams.interop.errordto; + +import java.util.ArrayList; +import lombok.Getter; +import lombok.Setter; +import lombok.ToString; + +@Getter +@Setter +@ToString +public class FineractError { + + public String developerMessage; + public String defaultUserMessage; + public String userMessageGlobalisationCode; + public String parameterName; + public String value; + public ArrayList args; + +} diff --git a/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/ams/properties/Tenant.java b/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/ams/properties/Tenant.java new file mode 100644 index 000000000..e092435df --- /dev/null +++ b/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/ams/properties/Tenant.java @@ -0,0 +1,52 @@ +package org.mifos.connector.ams.properties; + +public class Tenant { + + private String name; + private String user; + private String password; + private String authtype; + private String fspId; + + public Tenant() {} + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getUser() { + return user; + } + + public void setUser(String user) { + this.user = user; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + + public String getAuthtype() { + return authtype; + } + + public void setAuthtype(String authtype) { + this.authtype = authtype; + } + + public String getFspId() { + return fspId; + } + + public void setFspId(String fspId) { + this.fspId = fspId; + } +} diff --git a/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/ams/properties/TenantProperties.java b/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/ams/properties/TenantProperties.java new file mode 100644 index 000000000..a6fe4794b --- /dev/null +++ b/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/ams/properties/TenantProperties.java @@ -0,0 +1,29 @@ +package org.mifos.connector.ams.properties; + +import java.util.ArrayList; +import java.util.List; +import org.mifos.connector.ams.tenant.TenantNotExistException; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +@Component +@ConfigurationProperties(prefix = "ams.local") +public class TenantProperties { + + private List tenants = new ArrayList<>(); + + public TenantProperties() {} + + public List getTenants() { + return tenants; + } + + public void setTenants(List tenants) { + this.tenants = tenants; + } + + public Tenant getTenant(String name) { + return getTenants().stream().filter(t -> t.getName().equals(name)).findFirst() + .orElseThrow(() -> new TenantNotExistException("Tenant with name: " + name + ", not configuerd!")); + } +} diff --git a/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/ams/tenant/CachedTenantAuth.java b/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/ams/tenant/CachedTenantAuth.java new file mode 100644 index 000000000..3f59e85b9 --- /dev/null +++ b/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/ams/tenant/CachedTenantAuth.java @@ -0,0 +1,40 @@ +package org.mifos.connector.ams.tenant; + +import java.util.Date; +import java.util.Objects; + +public class CachedTenantAuth { + + private String token; + private Date accessTokenExpiration; + + public CachedTenantAuth(String token, Date accessTokenExpiration) { + this.token = token; + this.accessTokenExpiration = accessTokenExpiration; + } + + public String getToken() { + return token; + } + + public Date getAccessTokenExpiration() { + return accessTokenExpiration; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + CachedTenantAuth that = (CachedTenantAuth) o; + return Objects.equals(token, that.token) && Objects.equals(accessTokenExpiration, that.accessTokenExpiration); + } + + @Override + public int hashCode() { + return Objects.hash(token, accessTokenExpiration); + } +} diff --git a/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/ams/tenant/TenantNotExistException.java b/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/ams/tenant/TenantNotExistException.java new file mode 100644 index 000000000..4cb83f9f3 --- /dev/null +++ b/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/ams/tenant/TenantNotExistException.java @@ -0,0 +1,8 @@ +package org.mifos.connector.ams.tenant; + +public class TenantNotExistException extends RuntimeException { + + public TenantNotExistException(String message) { + super(message); + } +} diff --git a/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/ams/tenant/TenantService.java b/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/ams/tenant/TenantService.java new file mode 100644 index 000000000..d5d79bd7e --- /dev/null +++ b/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/ams/tenant/TenantService.java @@ -0,0 +1,109 @@ +package org.mifos.connector.ams.tenant; + +import static java.nio.charset.StandardCharsets.UTF_8; +import static org.mifos.connector.ams.camel.config.CamelProperties.LOGIN_PASSWORD; +import static org.mifos.connector.ams.camel.config.CamelProperties.LOGIN_USERNAME; +import static org.mifos.connector.ams.zeebe.ZeebeVariables.TENANT_ID; + +import java.util.Base64; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import javax.ws.rs.core.HttpHeaders; +import org.apache.camel.CamelContext; +import org.apache.camel.Exchange; +import org.apache.camel.ProducerTemplate; +import org.apache.camel.support.DefaultExchange; +import org.mifos.connector.ams.properties.Tenant; +import org.mifos.connector.ams.properties.TenantProperties; +import org.mifos.connector.common.ams.dto.LoginFineractCnResponseDTO; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +@Component +// @ConditionalOnExpression("${ams.local.enabled}") +public class TenantService { + + public static final String X_TENANT_IDENTIFIER_HEADER = "X-Tenant-Identifier"; + public static final String USER_HEADER = "User"; + public static final String FINERACT_PLATFORM_TENANT_ID_HEADER = "Fineract-Platform-TenantId"; + + private Logger logger = LoggerFactory.getLogger(this.getClass()); + + private ProducerTemplate producerTemplate; + + @Autowired + private TenantProperties tenantProperties; + + @Autowired + private CamelContext camelContext; + + @Value("${ams.local.version}") + private String amsLocalVersion; + + private final Map cachedTenantAuths = new ConcurrentHashMap<>(); + + public Map getHeaders(String tenantName) { + logger.info("Getting headers for tenant: {}", tenantName); + Tenant tenant = tenantProperties.getTenant(tenantName); + Map headers = new HashMap<>(); + + if ("1.2".equals(amsLocalVersion)) { + headers.put(FINERACT_PLATFORM_TENANT_ID_HEADER, tenantName); + } else if ("cn".equals(amsLocalVersion)) { + headers.put(X_TENANT_IDENTIFIER_HEADER, tenantName); + headers.put(USER_HEADER, tenant.getUser()); + } else { + throw new RuntimeException("Unsupported Fineract version: " + amsLocalVersion); + } + + headers.put(HttpHeaders.AUTHORIZATION, getTenantAuthData(tenant).getToken()); + + return headers; + } + + private CachedTenantAuth getTenantAuthData(Tenant tenant) { + CachedTenantAuth cachedTenantAuth = cachedTenantAuths.get(tenant.getName()); + if (cachedTenantAuth == null || isAccessTokenExpired(cachedTenantAuth.getAccessTokenExpiration())) { + cachedTenantAuth = login(tenant); + cachedTenantAuths.put(tenant.getName(), cachedTenantAuth); + } + return cachedTenantAuth; + } + + private CachedTenantAuth login(Tenant tenant) { + String tenantAuthtype = tenant.getAuthtype(); + if ("1.2".equals(amsLocalVersion) && "basic".equals(tenantAuthtype)) { + return new CachedTenantAuth( + "Basic " + Base64.getEncoder().encodeToString((tenant.getUser() + ":" + tenant.getPassword()).getBytes(UTF_8)), null); + } else if ("1.2".equals(amsLocalVersion) && "oauth".equals(tenantAuthtype)) { + // TODO implement + throw new RuntimeException("Unsupported authType: " + tenantAuthtype + ", for local fsp version: " + amsLocalVersion + + ", for tenant: " + tenant.getName()); + } else if ("cn".equals(amsLocalVersion) && "oauth".equals(tenantAuthtype)) { + Exchange ex = new DefaultExchange(camelContext); + ex.setProperty(TENANT_ID, tenant.getName()); + ex.setProperty(LOGIN_USERNAME, tenant.getUser()); + ex.setProperty(LOGIN_PASSWORD, tenant.getPassword()); + producerTemplate.send("direct:fincn-oauth", ex); + LoginFineractCnResponseDTO response = ex.getOut().getBody(LoginFineractCnResponseDTO.class); + return new CachedTenantAuth(response.getAccessToken(), response.getAccessTokenExpiration()); + } else { + throw new RuntimeException("Unsupported authType: " + tenantAuthtype + ", for local fsp version: " + amsLocalVersion + + ", for tenant: " + tenant.getName()); + } + } + + private boolean isAccessTokenExpired(Date accessTokenExpiration) { + if (accessTokenExpiration == null) { // basic is stateless and has no expiration + return false; + } + + Date fiveMinsFromNow = new Date(System.currentTimeMillis() + 300 * 1000); + return accessTokenExpiration.before(fiveMinsFromNow); + } +} diff --git a/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/ams/utils/Utils.java b/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/ams/utils/Utils.java new file mode 100644 index 000000000..cf80198bd --- /dev/null +++ b/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/ams/utils/Utils.java @@ -0,0 +1,28 @@ +package org.mifos.connector.ams.utils; + +import static org.mifos.connector.ams.zeebe.ZeebeVariables.ERROR_CODE; +import static org.mifos.connector.ams.zeebe.ZeebeVariables.ERROR_INFORMATION; +import static org.mifos.connector.ams.zeebe.ZeebeVariables.ERROR_PAYLOAD; + +import com.fasterxml.jackson.core.JsonProcessingException; +import java.util.HashMap; +import java.util.Map; +import org.apache.camel.Exchange; +import org.mifos.connector.ams.errorhandler.ErrorTranslator; + +public final class Utils { + + private Utils() {} + + // use this utility method only if exchange has ERROR_CODE, ERROR_INFORMATION & ERROR_PAYLOAD variables + public static Map getDefaultZeebeErrorVariable(Exchange exchange, ErrorTranslator translator) + throws JsonProcessingException { + Map variables = new HashMap<>(); + variables.put(ERROR_CODE, exchange.getProperty(ERROR_CODE)); + variables.put(ERROR_INFORMATION, exchange.getProperty(ERROR_INFORMATION)); + variables.put(ERROR_PAYLOAD, exchange.getProperty(ERROR_PAYLOAD)); + + return translator.translateError(variables); + } + +} diff --git a/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/ams/zeebe/ZeebeClientConfiguration.java b/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/ams/zeebe/ZeebeClientConfiguration.java new file mode 100644 index 000000000..a0da0c890 --- /dev/null +++ b/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/ams/zeebe/ZeebeClientConfiguration.java @@ -0,0 +1,29 @@ +package org.mifos.connector.ams.zeebe; + +import io.camunda.zeebe.client.ZeebeClient; +import java.time.Duration; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +@ConditionalOnExpression("${zeebe.enabled:true}") +public class ZeebeClientConfiguration { + + @Value("${zeebe.broker.contactpoint}") + private String zeebeBrokerContactpoint; + + @Value("${zeebe.client.max-execution-threads}") + private int zeebeClientMaxThreads; + + @Value("${zeebe.client.poll-interval}") + private int zeebeClientPollInterval; + + @Bean + public ZeebeClient setup() { + return ZeebeClient.newClientBuilder().gatewayAddress(zeebeBrokerContactpoint).usePlaintext() + .defaultJobPollInterval(Duration.ofMillis(zeebeClientPollInterval)).defaultJobWorkerMaxJobsActive(2000) + .numJobWorkerExecutionThreads(zeebeClientMaxThreads).build(); + } +} diff --git a/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/ams/zeebe/ZeebeUtil.java b/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/ams/zeebe/ZeebeUtil.java new file mode 100644 index 000000000..ce5743382 --- /dev/null +++ b/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/ams/zeebe/ZeebeUtil.java @@ -0,0 +1,184 @@ +package org.mifos.connector.ams.zeebe; + +import static org.mifos.connector.ams.camel.config.CamelProperties.TRANSACTION_ROLE; +import static org.mifos.connector.ams.camel.config.CamelProperties.TRANSFER_ACTION; +import static org.mifos.connector.ams.zeebe.ZeebeVariables.ACCOUNT_IDENTIFIER; +import static org.mifos.connector.ams.zeebe.ZeebeVariables.ACCOUNT_NUMBER; +import static org.mifos.connector.ams.zeebe.ZeebeVariables.CHANNEL_REQUEST; +import static org.mifos.connector.ams.zeebe.ZeebeVariables.EXTERNAL_ACCOUNT_ID; +import static org.mifos.connector.ams.zeebe.ZeebeVariables.PARTY_ID; +import static org.mifos.connector.ams.zeebe.ZeebeVariables.PARTY_ID_TYPE; +import static org.mifos.connector.ams.zeebe.ZeebeVariables.REQUESTED_DATE; +import static org.mifos.connector.ams.zeebe.ZeebeVariables.TENANT_ID; +import static org.mifos.connector.common.ams.dto.TransferActionType.CREATE; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.List; +import java.util.Map; +import org.apache.camel.Exchange; +import org.mifos.connector.common.ams.dto.LoanRepaymentDTO; +import org.mifos.connector.common.channel.dto.TransactionChannelRequestDTO; +import org.mifos.connector.common.gsma.dto.CustomData; +import org.mifos.connector.common.gsma.dto.GsmaTransfer; +import org.mifos.connector.common.mojaloop.dto.FspMoneyData; +import org.mifos.connector.common.mojaloop.dto.MoneyData; +import org.mifos.connector.common.mojaloop.dto.Party; +import org.mifos.connector.common.mojaloop.dto.PartyIdInfo; +import org.mifos.connector.common.mojaloop.dto.TransactionType; +import org.mifos.connector.common.mojaloop.type.IdentifierType; +import org.mifos.connector.common.mojaloop.type.InitiatorType; +import org.mifos.connector.common.mojaloop.type.Scenario; +import org.mifos.connector.common.mojaloop.type.TransactionRole; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +@Component +public class ZeebeUtil { + + private static Logger logger = LoggerFactory.getLogger(ZeebeUtil.class); + private static ObjectMapper objectMapper = new ObjectMapper(); + @Value("#{'${accountPrefixes}'.split(',')}") + public List accountPrefixes; + + public static void zeebeVariablesToCamelProperties(Map variables, Exchange exchange, String... names) { + exchange.setProperty("zeebeVariables", variables); + + for (String name : names) { + Object value = variables.get(name); + if (value == null) { + logger.error("failed to find Zeebe variable name {}", name); + } else { + exchange.setProperty(name, value); + } + } + } + + public static Map zeebeVariablesFrom(Exchange exchange) { + return exchange.getProperty("zeebeVariables", Map.class); + } + + public static T zeebeVariable(Exchange exchange, String name, Class clazz) throws Exception { + Object content = zeebeVariablesFrom(exchange).get(name); + if (content instanceof Map) { + return objectMapper.readValue(objectMapper.writeValueAsString(content), clazz); + } + return (T) content; + } + + public static String getCurrentDate(String requestedDate, String dateFormat) { + String dateFormatGiven = "yyyy-MM-dd'T'HH:mm:ss.SSSXXX"; + LocalDateTime datetime = LocalDateTime.parse(requestedDate, DateTimeFormatter.ofPattern(dateFormatGiven)); + String newDate = datetime.format(DateTimeFormatter.ofPattern(dateFormat)); + return newDate; + } + + public static LoanRepaymentDTO setLoanRepaymentBody(Exchange exchange) { + String dateFormat = "dd MMMM yyyy"; + LoanRepaymentDTO loanRepaymentDTO = new LoanRepaymentDTO(); + loanRepaymentDTO.setDateFormat(dateFormat); + loanRepaymentDTO.setLocale("en"); + loanRepaymentDTO.setTransactionAmount(exchange.getProperty("amount").toString()); + loanRepaymentDTO.setTransactionDate(exchange.getProperty("requestedDate").toString()); + return loanRepaymentDTO; + } + + public static void setZeebeVariables(Exchange e, Map variables, String requestDate, String accountHoldingInstitutionId, + String transactionChannelRequestDTO) { + String dateFormat = "dd MMMM yyyy"; + String currentDate = getCurrentDate(requestDate, dateFormat); + + variables.put(ACCOUNT_IDENTIFIER, e.getProperty(ACCOUNT_IDENTIFIER)); + variables.put(ACCOUNT_NUMBER, e.getProperty(ACCOUNT_NUMBER)); + // variables.put(TRANSACTION_ID, UUID.randomUUID().toString()); + variables.put(TENANT_ID, accountHoldingInstitutionId); + variables.put(TRANSFER_ACTION, CREATE.name()); + variables.put(CHANNEL_REQUEST, transactionChannelRequestDTO); + variables.put(REQUESTED_DATE, currentDate); + variables.put(EXTERNAL_ACCOUNT_ID, e.getProperty(ACCOUNT_NUMBER)); + variables.put("payeeTenantId", accountHoldingInstitutionId); + } + + public static void setZeebeVariablesLoanWorker(Map variables, TransactionChannelRequestDTO transactionRequest) { + TransactionType transactionType = new TransactionType(); + transactionType.setInitiator(TransactionRole.PAYEE); + transactionType.setInitiatorType(InitiatorType.CONSUMER); + transactionType.setScenario(Scenario.PAYMENT); + transactionRequest.setTransactionType(transactionType); + variables.put("initiator", transactionType.getInitiator().name()); + variables.put("initiatorType", transactionType.getInitiatorType().name()); + variables.put("scenario", transactionType.getScenario().name()); + variables.put("amount", + new FspMoneyData(transactionRequest.getAmount().getAmountDecimal(), transactionRequest.getAmount().getCurrency())); + variables.put("processType", "api"); + } + + public static void setExchangePropertyLoan(Exchange ex, String partyId, String partyIdType, + TransactionChannelRequestDTO transactionRequest, Map existingVariables) throws JsonProcessingException { + ex.setProperty(PARTY_ID_TYPE, partyIdType); + ex.setProperty(PARTY_ID, partyId); + + ex.setProperty(CHANNEL_REQUEST, objectMapper.writeValueAsString(transactionRequest)); + ex.setProperty(TRANSACTION_ROLE, TransactionRole.PAYEE.name()); + ex.setProperty("amount", transactionRequest.getAmount().getAmountDecimal()); + ex.setProperty(ACCOUNT_NUMBER, existingVariables.get(ACCOUNT_NUMBER)); + ex.setProperty(EXTERNAL_ACCOUNT_ID, "L"); + ex.setProperty(REQUESTED_DATE, existingVariables.get("requestedDate")); + } + + public Exchange setAccountTypeAndNumber(Exchange e, String accountNo) { + String accountTypeIdentifier = ""; + String accountNumber = ""; + int accountNoLength = accountNo.length(); + // Separating account id and prefix + for (String accountPrefix : accountPrefixes) { + if (accountNo.startsWith(accountPrefix)) { + accountNumber = accountNo.substring(accountPrefix.length(), accountNoLength); + accountTypeIdentifier = accountNo.substring(0, accountPrefix.length()); + break; + } + } + logger.debug("Accout number:{}, Identifier:{}", accountNumber, accountTypeIdentifier); + e.setProperty(ACCOUNT_NUMBER, accountNumber); + e.setProperty(ACCOUNT_IDENTIFIER, accountTypeIdentifier); + return e; + } + + public static String getValueofKey(List customData, String key) { + for (CustomData obj : customData) { + String keyString = obj.getKey(); + if (keyString.equalsIgnoreCase(key)) { + return obj.getValue().toString(); + } + } + return null; + } + + public static String convertGsmaTransfertoTransactionChannel(GsmaTransfer gsmaTransfer, Object property) + throws JsonProcessingException { + TransactionChannelRequestDTO transactionChannelRequestDTO = new TransactionChannelRequestDTO(); + String msisdn = gsmaTransfer.getPayer().get(0).getPartyIdIdentifier(); + String accountId = property.toString(); + + String amount = gsmaTransfer.getAmount().trim(); + List customData = gsmaTransfer.getCustomData(); + String currency = gsmaTransfer.getCurrency(); + + PartyIdInfo partyIdInfopayee = new PartyIdInfo(IdentifierType.ACCOUNT_ID, accountId); + PartyIdInfo partyIdInfopayer = new PartyIdInfo(IdentifierType.MSISDN, msisdn); + Party partyPayee = new Party(partyIdInfopayee); + Party partyPayer = new Party(partyIdInfopayer); + + MoneyData moneyData = new MoneyData(amount, currency); + + transactionChannelRequestDTO.setAmount(moneyData); + transactionChannelRequestDTO.setPayee(partyPayee); + transactionChannelRequestDTO.setPayer(partyPayer); + + return objectMapper.writeValueAsString(transactionChannelRequestDTO); + } +} diff --git a/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/ams/zeebe/ZeebeVariables.java b/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/ams/zeebe/ZeebeVariables.java new file mode 100644 index 000000000..f57dc2439 --- /dev/null +++ b/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/ams/zeebe/ZeebeVariables.java @@ -0,0 +1,52 @@ +package org.mifos.connector.ams.zeebe; + +import java.util.HashMap; +import java.util.Map; +import org.mifos.connector.common.ams.dto.TransferActionType; + +public final class ZeebeVariables { + + public static final Map ACTION_FAILURE_MAP = new HashMap<>(); + + public static final String ACCOUNT = "account"; + public static final String ACCOUNT_CURRENCY = "accountCurrency"; + public static final String ACCOUNT_ID = "accountId"; + public static final String CHANNEL_REQUEST = "channelRequest"; + public static final String ERROR_INFORMATION = "errorInformation"; + public static final String EXTERNAL_ACCOUNT_ID = "externalAccountId"; + public static final String INTEROP_REGISTRATION_FAILED = "interopRegistrationFailed"; + public static final String LOCAL_QUOTE_FAILED = "localQuoteFailed"; + public static final String LOCAL_QUOTE_RESPONSE = "localQuoteResponse"; + public static final String PARTY_ID = "partyId"; + public static final String PARTY_ID_TYPE = "partyIdType"; + public static final String PAYEE_PARTY_RESPONSE = "payeePartyResponse"; + public static final String QUOTE_FAILED = "quoteFailed"; + public static final String QUOTE_SWITCH_REQUEST = "quoteSwitchRequest"; + public static final String QUOTE_SWITCH_REQUEST_AMOUNT = "quoteSwitchRequestAmount"; + public static final String TENANT_ID = "tenantId"; + public static final String BOOK_TRANSACTION_ID = "bookTransactionId"; + public static final String TRANSACTION_ID = "transactionId"; + public static final String TRANSFER_CODE = "transferCode"; + public static final String TRANSFER_CREATE_FAILED = "transferCreateFailed"; + public static final String TRANSFER_PREPARE_FAILED = "transferPrepareFailed"; + public static final String TRANSFER_RELEASE_FAILED = "transferReleaseFailed"; + public static final String TRANSFER_RESPONSE_PREFIX = "transferResponse"; + public static final String FINERACT_RESPONSE_BODY = "fineractResponseBody"; + public static final String ACCOUNT_IDENTIFIER = "accountIdentifier"; + public static final String ACCOUNT_NUMBER = "accountNumber"; + + public static final String ERROR_CODE = "errorCode"; + public static final String ERROR_PAYLOAD = "errorPayload"; + public static final String IS_ERROR_HANDLED = "isErrorHandled"; + public static final String NOTE = "note"; + public static final String REQUESTED_DATE = "requestedDate"; + public static final String CALLBACK_SUCCESS = "callbackSuccessful"; + + static { + ACTION_FAILURE_MAP.put(TransferActionType.PREPARE.name(), TRANSFER_PREPARE_FAILED); + ACTION_FAILURE_MAP.put(TransferActionType.CREATE.name(), TRANSFER_CREATE_FAILED); + ACTION_FAILURE_MAP.put(TransferActionType.RELEASE.name(), TRANSFER_RELEASE_FAILED); + } + + private ZeebeVariables() {} +} diff --git a/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/ams/zeebe/ZeebeeWorkers.java b/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/ams/zeebe/ZeebeeWorkers.java new file mode 100644 index 000000000..cbf0d8564 --- /dev/null +++ b/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/ams/zeebe/ZeebeeWorkers.java @@ -0,0 +1,507 @@ +package org.mifos.connector.ams.zeebe; + +import static org.mifos.connector.ams.camel.config.CamelProperties.PROCESS_TYPE; +import static org.mifos.connector.ams.camel.config.CamelProperties.QUOTE_AMOUNT_TYPE; +import static org.mifos.connector.ams.camel.config.CamelProperties.TRANSACTION_ROLE; +import static org.mifos.connector.ams.camel.config.CamelProperties.TRANSFER_ACTION; +import static org.mifos.connector.ams.camel.config.CamelProperties.X_CALLBACKURL; +import static org.mifos.connector.ams.camel.config.CamelProperties.ZEEBE_JOB_KEY; +import static org.mifos.connector.ams.zeebe.ZeebeUtil.zeebeVariable; +import static org.mifos.connector.ams.zeebe.ZeebeUtil.zeebeVariablesToCamelProperties; +import static org.mifos.connector.ams.zeebe.ZeebeVariables.ACCOUNT; +import static org.mifos.connector.ams.zeebe.ZeebeVariables.ACCOUNT_CURRENCY; +import static org.mifos.connector.ams.zeebe.ZeebeVariables.ACCOUNT_IDENTIFIER; +import static org.mifos.connector.ams.zeebe.ZeebeVariables.ACCOUNT_NUMBER; +import static org.mifos.connector.ams.zeebe.ZeebeVariables.BOOK_TRANSACTION_ID; +import static org.mifos.connector.ams.zeebe.ZeebeVariables.CALLBACK_SUCCESS; +import static org.mifos.connector.ams.zeebe.ZeebeVariables.CHANNEL_REQUEST; +import static org.mifos.connector.ams.zeebe.ZeebeVariables.EXTERNAL_ACCOUNT_ID; +import static org.mifos.connector.ams.zeebe.ZeebeVariables.FINERACT_RESPONSE_BODY; +import static org.mifos.connector.ams.zeebe.ZeebeVariables.INTEROP_REGISTRATION_FAILED; +import static org.mifos.connector.ams.zeebe.ZeebeVariables.LOCAL_QUOTE_FAILED; +import static org.mifos.connector.ams.zeebe.ZeebeVariables.LOCAL_QUOTE_RESPONSE; +import static org.mifos.connector.ams.zeebe.ZeebeVariables.NOTE; +import static org.mifos.connector.ams.zeebe.ZeebeVariables.PARTY_ID; +import static org.mifos.connector.ams.zeebe.ZeebeVariables.PARTY_ID_TYPE; +import static org.mifos.connector.ams.zeebe.ZeebeVariables.PAYEE_PARTY_RESPONSE; +import static org.mifos.connector.ams.zeebe.ZeebeVariables.QUOTE_FAILED; +import static org.mifos.connector.ams.zeebe.ZeebeVariables.QUOTE_SWITCH_REQUEST; +import static org.mifos.connector.ams.zeebe.ZeebeVariables.TENANT_ID; +import static org.mifos.connector.ams.zeebe.ZeebeVariables.TRANSACTION_ID; +import static org.mifos.connector.ams.zeebe.ZeebeVariables.TRANSFER_CODE; +import static org.mifos.connector.ams.zeebe.ZeebeVariables.TRANSFER_PREPARE_FAILED; +import static org.mifos.connector.common.ams.dto.TransferActionType.CREATE; +import static org.mifos.connector.common.ams.dto.TransferActionType.PREPARE; +import static org.mifos.connector.common.ams.dto.TransferActionType.RELEASE; + +import com.fasterxml.jackson.databind.ObjectMapper; +import io.camunda.zeebe.client.ZeebeClient; +import io.camunda.zeebe.client.api.response.ActivatedJob; +import java.math.BigDecimal; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import javax.annotation.PostConstruct; +import org.apache.camel.CamelContext; +import org.apache.camel.Exchange; +import org.apache.camel.ProducerTemplate; +import org.apache.camel.support.DefaultExchange; +import org.json.JSONObject; +import org.mifos.connector.ams.properties.TenantProperties; +import org.mifos.connector.common.ams.dto.QuoteFspResponseDTO; +import org.mifos.connector.common.channel.dto.TransactionChannelRequestDTO; +import org.mifos.connector.common.gsma.dto.GsmaTransfer; +import org.mifos.connector.common.mojaloop.dto.FspMoneyData; +import org.mifos.connector.common.mojaloop.dto.MoneyData; +import org.mifos.connector.common.mojaloop.dto.Party; +import org.mifos.connector.common.mojaloop.dto.PartyIdInfo; +import org.mifos.connector.common.mojaloop.dto.QuoteSwitchRequestDTO; +import org.mifos.connector.common.mojaloop.dto.TransactionType; +import org.mifos.connector.common.mojaloop.type.AmountType; +import org.mifos.connector.common.mojaloop.type.IdentifierType; +import org.mifos.connector.common.mojaloop.type.InitiatorType; +import org.mifos.connector.common.mojaloop.type.Scenario; +import org.mifos.connector.common.mojaloop.type.TransactionRole; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +@Component +public class ZeebeeWorkers { + + public static final String WORKER_PARTY_LOOKUP_LOCAL = "party-lookup-local-"; + public static final String WORKER_PAYEE_COMMIT_TRANSFER = "payee-commit-transfer-"; + public static final String WORKER_PAYEE_QUOTE = "payee-quote-"; + public static final String WORKER_PAYER_LOCAL_QUOTE = "payer-local-quote-"; + public static final String WORKER_INTEROP_PARTY_REGISTRATION = "interop-party-registration-"; + public static final String WORKER_PAYEE_DEPOSIT_TRANSFER = "payee-deposit-transfer-"; + public static final String WORKER_PAYEE_LOAN_TRANSFER = "payee-loan-transfer-"; + public static final String WORKER_ACCOUNT_IDENTIFIER = "account-identifier-"; + public static final String WORKER_SEND_CALLBACK = "send-callback"; + + private Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Autowired(required = false) + private ZeebeClient zeebeClient; + + @Autowired + private ProducerTemplate producerTemplate; + + @Autowired + private CamelContext camelContext; + + @Autowired + private ZeebeUtil zeebeUtil; + + @Autowired + private ObjectMapper objectMapper; + + @Autowired + private TenantProperties tenantProperties; + + @Value("${ams.local.enabled:false}") + private boolean isAmsLocalEnabled; + + @Value("#{'${dfspids}'.split(',')}") + private List dfspids; + + @Value("${zeebe.client.evenly-allocated-max-jobs}") + private int workerMaxJobs; + + @Value("${zeebe.enabled:true}") + private boolean isZeebeEnabled; + + @Value("${interop-party-registration.enabled}") + private boolean interopPartyRegistrationEnabled; + + @PostConstruct + public void setupWorkers() { + if (isZeebeEnabled) { + zeebeClient.newWorker().jobType("block-funds").handler((client, job) -> { + logWorkerDetails(job); + if (isAmsLocalEnabled) { + Exchange ex = new DefaultExchange(camelContext); + zeebeVariablesToCamelProperties(job.getVariablesAsMap(), ex, TRANSACTION_ID, CHANNEL_REQUEST, EXTERNAL_ACCOUNT_ID, + TENANT_ID, LOCAL_QUOTE_RESPONSE, PROCESS_TYPE); + TransactionChannelRequestDTO channelRequest = objectMapper.readValue(ex.getProperty(CHANNEL_REQUEST, String.class), + TransactionChannelRequestDTO.class); + ex.setProperty(PARTY_ID_TYPE, channelRequest.getPayer().getPartyIdInfo().getPartyIdType().name()); + ex.setProperty(PARTY_ID, channelRequest.getPayer().getPartyIdInfo().getPartyIdentifier()); + ex.setProperty(TRANSFER_ACTION, PREPARE.name()); + ex.setProperty(ZEEBE_JOB_KEY, job.getKey()); + ex.setProperty(TRANSACTION_ROLE, TransactionRole.PAYER.name()); + ex.setProperty("payeeTenantId", job.getVariablesAsMap().get("payeeTenantId")); + logger.debug("Payee Id before block funds {}", job.getVariablesAsMap().get("payeeTenantId")); + producerTemplate.send("direct:send-transfers", ex); + logger.info("Zeebe variable {}", job.getVariablesAsMap()); + } else { + Map variables = new HashMap<>(); + variables.put(TRANSFER_PREPARE_FAILED, false); + zeebeClient.newCompleteCommand(job.getKey()).variables(variables).send(); + } + }).name("block-funds").maxJobsActive(workerMaxJobs).open(); + + zeebeClient.newWorker().jobType("book-funds").handler((client, job) -> { + logWorkerDetails(job); + if (isAmsLocalEnabled) { + Exchange ex = new DefaultExchange(camelContext); + zeebeVariablesToCamelProperties(job.getVariablesAsMap(), ex, TRANSACTION_ID, CHANNEL_REQUEST, TENANT_ID, + EXTERNAL_ACCOUNT_ID, LOCAL_QUOTE_RESPONSE, TRANSFER_CODE); + TransactionChannelRequestDTO channelRequest = objectMapper.readValue(ex.getProperty(CHANNEL_REQUEST, String.class), + TransactionChannelRequestDTO.class); + ex.setProperty(PARTY_ID_TYPE, channelRequest.getPayer().getPartyIdInfo().getPartyIdType().name()); + ex.setProperty(PARTY_ID, channelRequest.getPayer().getPartyIdInfo().getPartyIdentifier()); + ex.setProperty(TRANSFER_ACTION, CREATE.name()); + ex.setProperty(ZEEBE_JOB_KEY, job.getKey()); + ex.setProperty(TRANSACTION_ROLE, TransactionRole.PAYER.name()); + ex.setProperty("payeeTenantId", job.getVariablesAsMap().get("payeeTenantId")); + ex.setProperty("processType", "api"); + producerTemplate.send("direct:send-transfers", ex); + } else { + Map variables = new HashMap<>(); + variables.put("transferCreateFailed", false); + zeebeClient.newCompleteCommand(job.getKey()).variables(variables).send(); + } + }).name("book-funds").maxJobsActive(workerMaxJobs).open(); + + zeebeClient.newWorker().jobType("release-block").handler((client, job) -> { + logWorkerDetails(job); + if (isAmsLocalEnabled) { + Exchange ex = new DefaultExchange(camelContext); + zeebeVariablesToCamelProperties(job.getVariablesAsMap(), ex, TRANSACTION_ID, CHANNEL_REQUEST, TENANT_ID, + EXTERNAL_ACCOUNT_ID, LOCAL_QUOTE_RESPONSE, TRANSFER_CODE); + TransactionChannelRequestDTO channelRequest = objectMapper.readValue(ex.getProperty(CHANNEL_REQUEST, String.class), + TransactionChannelRequestDTO.class); + ex.setProperty(PARTY_ID_TYPE, channelRequest.getPayer().getPartyIdInfo().getPartyIdType().name()); + ex.setProperty(PARTY_ID, channelRequest.getPayer().getPartyIdInfo().getPartyIdentifier()); + ex.setProperty(TRANSFER_ACTION, RELEASE.name()); + ex.setProperty(ZEEBE_JOB_KEY, job.getKey()); + ex.setProperty(TRANSACTION_ROLE, TransactionRole.PAYEE.name()); + ex.setProperty("payeeTenantId", job.getVariablesAsMap().get("payeeTenantId")); + producerTemplate.send("direct:send-transfers", ex); + } else { + Map variables = new HashMap<>(); + variables.put("transferReleaseFailed", false); + zeebeClient.newCompleteCommand(job.getKey()).variables(variables).send(); + } + }).name("release-block").maxJobsActive(workerMaxJobs).open(); + + for (String dfspid : dfspids) { + logger.info("DFSPID {}", dfspid); + logger.info("## generating " + WORKER_PAYER_LOCAL_QUOTE + "{} worker", dfspid); + zeebeClient.newWorker().jobType(WORKER_PAYER_LOCAL_QUOTE + dfspid).handler((client, job) -> { + logWorkerDetails(job); + if (isAmsLocalEnabled) { + Map existingVariables = job.getVariablesAsMap(); + TransactionChannelRequestDTO channelRequest = objectMapper + .readValue((String) existingVariables.get(CHANNEL_REQUEST), TransactionChannelRequestDTO.class); + + Exchange ex = new DefaultExchange(camelContext); + zeebeVariablesToCamelProperties(existingVariables, ex, CHANNEL_REQUEST, TENANT_ID, TRANSACTION_ID); + + ex.setProperty(PARTY_ID_TYPE, channelRequest.getPayer().getPartyIdInfo().getPartyIdType().name()); + ex.setProperty(PARTY_ID, channelRequest.getPayer().getPartyIdInfo().getPartyIdentifier()); + ex.setProperty(ZEEBE_JOB_KEY, job.getKey()); + ex.setProperty(TRANSACTION_ROLE, TransactionRole.PAYER); + ex.setProperty(QUOTE_AMOUNT_TYPE, AmountType.SEND.name()); + producerTemplate.send("direct:send-local-quote", ex); + } else { + Map variables = new HashMap<>(); + variables.put(LOCAL_QUOTE_FAILED, false); + zeebeClient.newCompleteCommand(job.getKey()).variables(variables).send(); + } + }).name(WORKER_PAYER_LOCAL_QUOTE + dfspid).maxJobsActive(workerMaxJobs).open(); + + logger.info("## generating " + WORKER_PAYEE_QUOTE + "{} worker", dfspid); + zeebeClient.newWorker().jobType(WORKER_PAYEE_QUOTE + dfspid).handler((client, job) -> { + logWorkerDetails(job); + Map existingVariables = job.getVariablesAsMap(); + QuoteSwitchRequestDTO quoteRequest = objectMapper.readValue((String) existingVariables.get(QUOTE_SWITCH_REQUEST), + QuoteSwitchRequestDTO.class); + + if (isAmsLocalEnabled) { + TransactionChannelRequestDTO channelRequest = new TransactionChannelRequestDTO(); + TransactionType transactionType = new TransactionType(); + transactionType.setInitiator(TransactionRole.PAYEE); + transactionType.setInitiatorType(InitiatorType.CONSUMER); + transactionType.setScenario(Scenario.DEPOSIT); + channelRequest.setTransactionType(transactionType); + channelRequest.setAmountType(AmountType.RECEIVE); + MoneyData amount = new MoneyData(quoteRequest.getAmount().getAmount(), quoteRequest.getAmount().getCurrency()); + channelRequest.setAmount(amount); + + Exchange ex = new DefaultExchange(camelContext); + ex.setProperty(PARTY_ID, quoteRequest.getPayee().getPartyIdInfo().getPartyIdentifier()); + ex.setProperty(PARTY_ID_TYPE, quoteRequest.getPayee().getPartyIdInfo().getPartyIdType()); + ex.setProperty(TRANSACTION_ID, existingVariables.get(TRANSACTION_ID)); + ex.setProperty(TENANT_ID, existingVariables.get(TENANT_ID)); + ex.setProperty(TRANSACTION_ROLE, TransactionRole.PAYEE.name()); + ex.setProperty(CHANNEL_REQUEST, objectMapper.writeValueAsString(channelRequest)); + ex.setProperty(ZEEBE_JOB_KEY, job.getKey()); + ex.setProperty(QUOTE_AMOUNT_TYPE, quoteRequest.getAmountType().name()); + producerTemplate.send("direct:send-local-quote", ex); + } else { + Map variables = createFreeQuote(quoteRequest.getAmount().getCurrency()); + variables.put(QUOTE_FAILED, false); + zeebeClient.newCompleteCommand(job.getKey()).variables(variables).send(); + } + }).name(WORKER_PAYEE_QUOTE + dfspid).maxJobsActive(workerMaxJobs).open(); + + logger.info("## generating " + WORKER_PAYEE_COMMIT_TRANSFER + "{} worker", dfspid); + zeebeClient.newWorker().jobType(WORKER_PAYEE_COMMIT_TRANSFER + dfspid).handler((client, job) -> { + logWorkerDetails(job); + if (isAmsLocalEnabled) { + Exchange exchange = new DefaultExchange(camelContext); + Map variables = job.getVariablesAsMap(); + zeebeVariablesToCamelProperties(variables, exchange, BOOK_TRANSACTION_ID, TRANSACTION_ID, TENANT_ID, + EXTERNAL_ACCOUNT_ID, LOCAL_QUOTE_RESPONSE); + exchange.setProperty(TRANSFER_ACTION, CREATE.name()); + exchange.setProperty(ZEEBE_JOB_KEY, job.getKey()); + + // setting party related variables as exchange property + QuoteSwitchRequestDTO quoteRequest = objectMapper.readValue((String) variables.get(QUOTE_SWITCH_REQUEST), + QuoteSwitchRequestDTO.class); + exchange.setProperty(PARTY_ID, quoteRequest.getPayee().getPartyIdInfo().getPartyIdentifier()); + exchange.setProperty(PARTY_ID_TYPE, quoteRequest.getPayee().getPartyIdInfo().getPartyIdType()); + + FspMoneyData amountData = zeebeVariable(exchange, "amount", FspMoneyData.class); + MoneyData amount = new MoneyData(amountData.getAmount(), amountData.getCurrency()); + + TransactionChannelRequestDTO transactionRequest = new TransactionChannelRequestDTO(); + TransactionType transactionType = new TransactionType(); + transactionType.setInitiator(TransactionRole.PAYEE); + transactionType.setInitiatorType(InitiatorType.CONSUMER); + transactionType.setScenario(Scenario.DEPOSIT); + transactionRequest.setTransactionType(transactionType); + transactionRequest.setAmount(amount); + exchange.setProperty(CHANNEL_REQUEST, objectMapper.writeValueAsString(transactionRequest)); + exchange.setProperty(TRANSACTION_ROLE, TransactionRole.PAYEE.name()); + + logger.info("####### transaction request {}", objectMapper.writeValueAsString(transactionRequest)); + producerTemplate.send("direct:send-transfers", exchange); + } else { + Map variables = new HashMap<>(); + variables.put("transferCreateFailed", false); + zeebeClient.newCompleteCommand(job.getKey()).variables(variables).send(); + } + }).name(WORKER_PAYEE_COMMIT_TRANSFER + dfspid).maxJobsActive(workerMaxJobs).open(); + + logger.info("## generating " + WORKER_PARTY_LOOKUP_LOCAL + "{} worker", dfspid); + zeebeClient.newWorker().jobType(WORKER_PARTY_LOOKUP_LOCAL + dfspid).handler((client, job) -> { + logWorkerDetails(job); + Map existingVariables = job.getVariablesAsMap(); + String partyIdType = (String) existingVariables.get(PARTY_ID_TYPE); + String partyId = (String) existingVariables.get(PARTY_ID); + String tenantId = (String) existingVariables.get(TENANT_ID); // payer + if (isAmsLocalEnabled) { + Exchange ex = new DefaultExchange(camelContext); + ex.setProperty(PARTY_ID_TYPE, partyIdType); + ex.setProperty(PARTY_ID, partyId); + ex.setProperty(ZEEBE_JOB_KEY, job.getKey()); + if (dfspid.equalsIgnoreCase(existingVariables.get("payeeTenantId").toString())) { + ex.setProperty(TENANT_ID, existingVariables.get("payeeTenantId")); + } else { + ex.setProperty(TENANT_ID, tenantId); + } + ex.setProperty("payeeTenantId", existingVariables.get("payeeTenantId")); + + producerTemplate.send("direct:get-party", ex); + + /* + * payeeTenantId == dfspid => payee else payer + * + * a = payer tenant b = payee tenant + * + * debit -> gorilla credit -> gorilla + * + * PLATFORM-TENANT-ID -> PAYER/PAYEE + */ + } else { + Map variables = new HashMap<>(); + Party party = new Party(// only return fspId from configuration + new PartyIdInfo(IdentifierType.valueOf(partyIdType), partyId, null, + tenantProperties.getTenant(tenantId).getFspId()), + null, null, null); + + variables.put(PAYEE_PARTY_RESPONSE, objectMapper.writeValueAsString(party)); + variables.put("payeeTenantId", existingVariables.get("payeeTenantId")); + client.newCompleteCommand(job.getKey()).variables(variables).send(); + } + }).name(WORKER_PARTY_LOOKUP_LOCAL + dfspid).maxJobsActive(workerMaxJobs).open(); + + logger.info("## generating " + WORKER_INTEROP_PARTY_REGISTRATION + "{} worker", dfspid); + zeebeClient.newWorker().jobType(WORKER_INTEROP_PARTY_REGISTRATION + dfspid).handler((client, job) -> { + logWorkerDetails(job); + Map existingVariables = job.getVariablesAsMap(); + + if (!interopPartyRegistrationEnabled) { + Map variables = new HashMap<>(); + variables.put(ACCOUNT_CURRENCY, "USD"); + variables.put(INTEROP_REGISTRATION_FAILED, false); + client.newCompleteCommand(job.getKey()).variables(variables).send(); + logger.info("Interop disabled with variables {}", variables); + return; + } + + if (isAmsLocalEnabled) { + Exchange ex = new DefaultExchange(camelContext); + ex.setProperty(PARTY_ID_TYPE, existingVariables.get(PARTY_ID_TYPE)); + ex.setProperty(PARTY_ID, existingVariables.get(PARTY_ID)); + ex.setProperty(ACCOUNT, existingVariables.get(ACCOUNT)); + ex.setProperty(TENANT_ID, existingVariables.get(TENANT_ID)); + ex.setProperty(ZEEBE_JOB_KEY, job.getKey()); + producerTemplate.send("direct:register-party", ex); + } else { + Map variables = new HashMap<>(); + variables.put(ACCOUNT_CURRENCY, "TZS"); + client.newCompleteCommand(job.getKey()).variables(variables).send(); + } + }).name(WORKER_INTEROP_PARTY_REGISTRATION + dfspid).maxJobsActive(workerMaxJobs).open(); + + logger.info("## generating " + WORKER_PAYEE_DEPOSIT_TRANSFER + "{} worker", dfspid); + zeebeClient.newWorker().jobType(WORKER_PAYEE_DEPOSIT_TRANSFER + dfspid).handler((client, job) -> { + logWorkerDetails(job); + Map existingVariables = job.getVariablesAsMap(); + logger.info("Exisiting variables {}", existingVariables); + + String tenantId = (String) existingVariables.get(TENANT_ID); + + Exchange ex = new DefaultExchange(camelContext); + Map variables = job.getVariablesAsMap(); + zeebeVariablesToCamelProperties(variables, ex, TRANSACTION_ID, TENANT_ID, EXTERNAL_ACCOUNT_ID, CHANNEL_REQUEST); + ex.setProperty(TRANSFER_ACTION, CREATE.name()); + ex.setProperty("payeeTenantId", existingVariables.get("payeeTenantId")); + ex.setProperty(ZEEBE_JOB_KEY, job.getKey()); + + TransactionChannelRequestDTO transactionRequest = objectMapper.readValue((String) variables.get(CHANNEL_REQUEST), + TransactionChannelRequestDTO.class); + TransactionType transactionType = new TransactionType(); + transactionType.setInitiator(TransactionRole.PAYEE); + transactionType.setInitiatorType(InitiatorType.CONSUMER); + transactionType.setScenario(Scenario.DEPOSIT); + transactionRequest.setTransactionType(transactionType); + variables.put("initiator", transactionType.getInitiator().name()); + variables.put("initiatorType", transactionType.getInitiatorType().name()); + variables.put("scenario", transactionType.getScenario().name()); + variables.get(NOTE); + variables.put("amount", new FspMoneyData(transactionRequest.getAmount().getAmountDecimal(), + transactionRequest.getAmount().getCurrency())); + variables.put("processType", "api"); + + String partyIdType = transactionRequest.getPayee().getPartyIdInfo().getPartyIdType().name(); + String partyId = transactionRequest.getPayee().getPartyIdInfo().getPartyIdentifier(); + ex.setProperty(PARTY_ID_TYPE, partyIdType); + ex.setProperty(PARTY_ID, partyId); + logger.info("PartyIdType: {}, PartyId: {}", partyIdType, partyId); + + ex.setProperty(CHANNEL_REQUEST, objectMapper.writeValueAsString(transactionRequest)); + ex.setProperty(TRANSACTION_ROLE, TransactionRole.PAYEE.name()); + producerTemplate.send("direct:send-transfers", ex); + variables.put("transferCreateFailed", false); + variables.put("payeeTenantId", existingVariables.get("payeeTenantId")); + zeebeClient.newCompleteCommand(job.getKey()).variables(variables).send(); + }).name(WORKER_PAYEE_DEPOSIT_TRANSFER + dfspid).maxJobsActive(workerMaxJobs).open(); + + logger.info("## generating {}" + "{} worker", WORKER_PAYEE_LOAN_TRANSFER, dfspid); + zeebeClient.newWorker().jobType(WORKER_PAYEE_LOAN_TRANSFER + dfspid).handler((client, job) -> { + logWorkerDetails(job); + Map existingVariables = job.getVariablesAsMap(); + logger.debug("Exisiting variables {}", existingVariables); + + String tenantId = (String) existingVariables.get(TENANT_ID); + + Exchange ex = new DefaultExchange(camelContext); + Map variables = job.getVariablesAsMap(); + zeebeVariablesToCamelProperties(variables, ex, TRANSACTION_ID, TENANT_ID, CHANNEL_REQUEST); + ex.setProperty(TRANSFER_ACTION, CREATE.name()); + ex.setProperty("payeeTenantId", existingVariables.get("payeeTenantId")); + ex.setProperty(ZEEBE_JOB_KEY, job.getKey()); + + TransactionChannelRequestDTO transactionRequest = objectMapper.readValue((String) variables.get(CHANNEL_REQUEST), + TransactionChannelRequestDTO.class); + + ZeebeUtil.setZeebeVariablesLoanWorker(variables, transactionRequest); + + String partyIdType = transactionRequest.getPayee().getPartyIdInfo().getPartyIdType().name(); + String partyId = transactionRequest.getPayee().getPartyIdInfo().getPartyIdentifier(); + + ZeebeUtil.setExchangePropertyLoan(ex, partyId, partyIdType, transactionRequest, existingVariables); + + producerTemplate.send("direct:send-transfers-loan", ex); + variables.put("transferCreateFailed", false); + variables.put("payeeTenantId", existingVariables.get("payeeTenantId")); + zeebeClient.newCompleteCommand(job.getKey()).variables(variables).send(); + }).name(WORKER_PAYEE_LOAN_TRANSFER + dfspid).maxJobsActive(workerMaxJobs).open(); + + logger.info("## generating " + WORKER_ACCOUNT_IDENTIFIER + "{} worker", dfspid); + zeebeClient.newWorker().jobType(WORKER_ACCOUNT_IDENTIFIER + dfspid).handler((client, job) -> { + logWorkerDetails(job); + Map existingVariables = job.getVariablesAsMap(); + logger.debug("Exisiting variables {}", existingVariables); + String accountHoldingInstitutionId = (String) existingVariables.get(TENANT_ID); + Exchange ex = new DefaultExchange(camelContext); + Map variables = job.getVariablesAsMap(); + GsmaTransfer gsmaTransfer = objectMapper.readValue((String) variables.get(CHANNEL_REQUEST), GsmaTransfer.class); + logger.debug("GSMA Transfer Body:{}", gsmaTransfer); + String accountNo = gsmaTransfer.getPayee().get(0).getPartyIdIdentifier(); + Exchange e = zeebeUtil.setAccountTypeAndNumber(ex, accountNo); + String transactionChannelRequestDTO = ZeebeUtil.convertGsmaTransfertoTransactionChannel(gsmaTransfer, + e.getProperty(ACCOUNT_NUMBER)); + logger.debug("Transaction Channel Request DTO:{}", transactionChannelRequestDTO); + logger.debug("Account Identifier:{}", ACCOUNT_IDENTIFIER); + + ZeebeUtil.setZeebeVariables(e, variables, gsmaTransfer.getRequestDate(), accountHoldingInstitutionId, + transactionChannelRequestDTO); + + zeebeClient.newCompleteCommand(job.getKey()).variables(variables).send(); + }).name(WORKER_ACCOUNT_IDENTIFIER + dfspid).maxJobsActive(workerMaxJobs).open(); + + logger.info("## generating {} worker", WORKER_SEND_CALLBACK); + zeebeClient.newWorker().jobType(WORKER_SEND_CALLBACK).handler((client, job) -> { + logWorkerDetails(job); + Map existingVariables = job.getVariablesAsMap(); + logger.debug("Exisiting variables {}", existingVariables); + Exchange ex = new DefaultExchange(camelContext); + Map variables = job.getVariablesAsMap(); + + ex.setProperty(X_CALLBACKURL, existingVariables.get(X_CALLBACKURL)); + ex.setProperty(FINERACT_RESPONSE_BODY, existingVariables.get(FINERACT_RESPONSE_BODY)); + producerTemplate.send("direct:send-callback", ex); + variables.put(CALLBACK_SUCCESS, ex.getProperty("callbackSent").toString()); + zeebeClient.newCompleteCommand(job.getKey()).variables(variables).send(); + + }).name(WORKER_SEND_CALLBACK).maxJobsActive(workerMaxJobs).open(); + } + } + } + + private void logWorkerDetails(ActivatedJob job) { + JSONObject jsonJob = new JSONObject(); + jsonJob.put("bpmnProcessId", job.getBpmnProcessId()); + jsonJob.put("elementInstanceKey", job.getElementInstanceKey()); + jsonJob.put("jobKey", job.getKey()); + jsonJob.put("jobType", job.getType()); + jsonJob.put("workflowElementId", job.getElementId()); + jsonJob.put("workflowDefinitionVersion", job.getProcessDefinitionVersion()); + jsonJob.put("workflowKey", job.getProcessDefinitionKey()); + jsonJob.put("workflowInstanceKey", job.getProcessInstanceKey()); + logger.info("Job started: {}", jsonJob.toString(4)); + } + + private Map createFreeQuote(String currency) throws Exception { + FspMoneyData fspFee = new FspMoneyData(BigDecimal.ZERO, currency); + FspMoneyData fspCommission = new FspMoneyData(BigDecimal.ZERO, currency); + + QuoteFspResponseDTO response = new QuoteFspResponseDTO(); + response.setFspFee(fspFee); + response.setFspCommission(fspCommission); + + Map variables = new HashMap<>(); + variables.put(LOCAL_QUOTE_RESPONSE, objectMapper.writeValueAsString(response)); + variables.put("fspFee", fspFee); + variables.put("fspCommission", fspCommission); + return variables; + } +} diff --git a/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/fineractstub/RFC3339DateFormat.java b/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/fineractstub/RFC3339DateFormat.java new file mode 100644 index 000000000..98dcea98e --- /dev/null +++ b/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/fineractstub/RFC3339DateFormat.java @@ -0,0 +1,21 @@ +package org.mifos.connector.fineractstub; + +import com.fasterxml.jackson.databind.util.ISO8601DateFormat; +import com.fasterxml.jackson.databind.util.ISO8601Utils; +import java.text.FieldPosition; +import java.util.Date; + +@SuppressWarnings("checkstyle:Dynamic") +public class RFC3339DateFormat extends ISO8601DateFormat { + + private static final long serialVersionUID = 1L; + + // Same as ISO8601DateFormat but serializing milliseconds. + @Override + public StringBuffer format(Date date, StringBuffer toAppendTo, FieldPosition fieldPosition) { + String value = ISO8601Utils.format(date, true); + toAppendTo.append(value); + return toAppendTo; + } + +} diff --git a/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/fineractstub/api/ApiException.java b/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/fineractstub/api/ApiException.java new file mode 100644 index 000000000..a0765f6d3 --- /dev/null +++ b/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/fineractstub/api/ApiException.java @@ -0,0 +1,13 @@ +package org.mifos.connector.fineractstub.api; + +@SuppressWarnings("checkstyle:Dynamic") +@javax.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.SpringCodegen", date = "2023-08-10T10:13:07.472376795Z[GMT]") +public class ApiException extends Exception { + + private final int code; + + public ApiException(int code, String msg) { + super(msg); + this.code = code; + } +} diff --git a/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/fineractstub/api/ApiOriginFilter.java b/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/fineractstub/api/ApiOriginFilter.java new file mode 100644 index 000000000..238e85617 --- /dev/null +++ b/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/fineractstub/api/ApiOriginFilter.java @@ -0,0 +1,30 @@ +package org.mifos.connector.fineractstub.api; + +import java.io.IOException; +import javax.servlet.Filter; +import javax.servlet.FilterChain; +import javax.servlet.FilterConfig; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletResponse; + +@SuppressWarnings("checkstyle:Dynamic") +@javax.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.SpringCodegen", date = "2023-08-10T10:13:07.472376795Z[GMT]") +public class ApiOriginFilter implements Filter { + + @Override + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { + HttpServletResponse res = (HttpServletResponse) response; + res.addHeader("Access-Control-Allow-Origin", "*"); + res.addHeader("Access-Control-Allow-Methods", "GET, POST, DELETE, PUT"); + res.addHeader("Access-Control-Allow-Headers", "Content-Type"); + chain.doFilter(request, response); + } + + @Override + public void destroy() {} + + @Override + public void init(FilterConfig filterConfig) throws ServletException {} +} diff --git a/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/fineractstub/api/ApiResponseMessage.java b/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/fineractstub/api/ApiResponseMessage.java new file mode 100644 index 000000000..8783f1bf4 --- /dev/null +++ b/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/fineractstub/api/ApiResponseMessage.java @@ -0,0 +1,71 @@ +package org.mifos.connector.fineractstub.api; + +import javax.xml.bind.annotation.XmlTransient; + +@SuppressWarnings("checkstyle:Dynamic") +@javax.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.SpringCodegen", date = "2023-08-10T10:13:07.472376795Z[GMT]") +@javax.xml.bind.annotation.XmlRootElement +public class ApiResponseMessage { + + public static final int ERROR = 1; + public static final int WARNING = 2; + public static final int INFO = 3; + public static final int OK = 4; + public static final int TOO_BUSY = 5; + + int code; + String type; + String message; + + public ApiResponseMessage() {} + + public ApiResponseMessage(int code, String message) { + this.code = code; + switch (code) { + case ERROR: + setType("error"); + break; + case WARNING: + setType("warning"); + break; + case INFO: + setType("info"); + break; + case OK: + setType("ok"); + break; + case TOO_BUSY: + setType("too busy"); + break; + default: + setType("unknown"); + break; + } + this.message = message; + } + + @XmlTransient + public int getCode() { + return code; + } + + public void setCode(int code) { + this.code = code; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } +} diff --git a/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/fineractstub/api/NotFoundException.java b/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/fineractstub/api/NotFoundException.java new file mode 100644 index 000000000..e02c39935 --- /dev/null +++ b/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/fineractstub/api/NotFoundException.java @@ -0,0 +1,13 @@ +package org.mifos.connector.fineractstub.api; + +@SuppressWarnings("checkstyle:Dynamic") +@javax.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.SpringCodegen", date = "2023-08-10T10:13:07.472376795Z[GMT]") +public class NotFoundException extends ApiException { + + private final int code; + + public NotFoundException(int code, String msg) { + super(code, msg); + this.code = code; + } +} diff --git a/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/fineractstub/api/SavingsaccountApi.java b/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/fineractstub/api/SavingsaccountApi.java new file mode 100644 index 000000000..ef4ab08fc --- /dev/null +++ b/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/fineractstub/api/SavingsaccountApi.java @@ -0,0 +1,87 @@ +/** + * NOTE: This class is auto generated by the swagger code generator program (3.0.46). + * https://github.com/swagger-api/swagger-codegen + * Do not edit the class manually. + */ +package org.mifos.connector.fineractstub.api; + +import com.fasterxml.jackson.databind.ObjectMapper; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.enums.ParameterIn; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import java.io.IOException; +import java.util.Optional; +import javax.servlet.http.HttpServletRequest; +import javax.validation.Valid; +import org.mifos.connector.fineractstub.model.InteropIdentifier; +import org.mifos.connector.fineractstub.model.InteropTransfers; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; + +@SuppressWarnings("checkstyle:Dynamic") +@javax.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.SpringCodegen", date = "2023-08-10T10:13:07.472376795Z[GMT]") +@Validated +public interface SavingsaccountApi { + + Logger log = LoggerFactory.getLogger(SavingsaccountApi.class); + + default Optional getObjectMapper() { + return Optional.empty(); + } + + default Optional getRequest() { + return Optional.empty(); + } + + default Optional getAcceptHeader() { + return getRequest().map(r -> r.getHeader("Accept")); + } + + @Operation(summary = "Get savings Account", description = "Adds an item to the system", tags = { "developers" }) + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Get savings account", content = @Content(mediaType = "application/json", schema = @Schema(implementation = InteropIdentifier.class))) }) + @RequestMapping(value = "/savingsaccount", produces = { "application/json" }, method = RequestMethod.GET) + default ResponseEntity getSavingsAccount() { + if (getObjectMapper().isPresent() && getAcceptHeader().isPresent()) { + if (getAcceptHeader().get().contains("application/json")) { + try { + return new ResponseEntity<>(getObjectMapper().get().readValue( + "{\n \"accountId\" : \"cde3e5ee-214b-423f-97b0-0a0206aecaaf\",\n \"resourceId\" : \"1\",\n \"resourceIdentifier\" : \"1\"\n}", + InteropIdentifier.class), HttpStatus.OK); + } catch (IOException e) { + log.error("Couldn't serialize response for content type application/json", e); + return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR); + } + } + } else { + log.warn("ObjectMapper or HttpServletRequest not configured in default SavingsaccountApi interface so no example is generated"); + } + return new ResponseEntity<>(HttpStatus.OK); + } + + @Operation(summary = "savings account transfers", description = "Adds an item to the system", tags = { "developers" }) + @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "transfers created"), + + @ApiResponse(responseCode = "400", description = "invalid input, object invalid"), + + @ApiResponse(responseCode = "409", description = "an existing item already exists") }) + @RequestMapping(value = "/savingsaccount/transfers", consumes = { "application/json" }, method = RequestMethod.POST) + default ResponseEntity transfers( + @Parameter(in = ParameterIn.DEFAULT, description = "post savings Account transfers", schema = @Schema()) @Valid @RequestBody InteropTransfers body) { + if (getObjectMapper().isPresent() && getAcceptHeader().isPresent()) {} else { + log.warn("ObjectMapper or HttpServletRequest not configured in default SavingsaccountApi interface so no example is generated"); + } + return new ResponseEntity<>(HttpStatus.OK); + } + +} diff --git a/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/fineractstub/api/SavingsaccountApiController.java b/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/fineractstub/api/SavingsaccountApiController.java new file mode 100644 index 000000000..083b98df7 --- /dev/null +++ b/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/fineractstub/api/SavingsaccountApiController.java @@ -0,0 +1,65 @@ +package org.mifos.connector.fineractstub.api; + +import com.fasterxml.jackson.databind.ObjectMapper; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.enums.ParameterIn; +import io.swagger.v3.oas.annotations.media.Schema; +import java.io.IOException; +import java.util.Optional; +import javax.servlet.http.HttpServletRequest; +import javax.validation.Valid; +import org.mifos.connector.fineractstub.model.InteropIdentifier; +import org.mifos.connector.fineractstub.model.InteropTransfers; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; + +@SuppressWarnings("checkstyle:Dynamic") +@javax.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.SpringCodegen", date = "2023-08-10T10:13:07.472376795Z[GMT]") +@RestController +public class SavingsaccountApiController implements SavingsaccountApi { + + private static final Logger log = LoggerFactory.getLogger(SavingsaccountApiController.class); + + private final ObjectMapper objectMapper; + + private final HttpServletRequest request; + + @org.springframework.beans.factory.annotation.Autowired + public SavingsaccountApiController(ObjectMapper objectMapper, HttpServletRequest request) { + this.objectMapper = objectMapper; + this.request = request; + } + + @Override + public Optional getObjectMapper() { + return Optional.ofNullable(objectMapper); + } + + @Override + public Optional getRequest() { + return Optional.ofNullable(request); + } + + public ResponseEntity getSavingsAccount() { + String accept = request.getHeader("Accept"); + try { + return new ResponseEntity(objectMapper.readValue( + "{\n \"accountId\" : \"cde3e5ee-214b-423f-97b0-0a0206aecaaf\",\n \"resourceId\" : \"1\",\n \"resourceIdentifier\" : \"1\"\n}", + InteropIdentifier.class), HttpStatus.OK); + } catch (IOException e) { + log.error("Couldn't serialize response for content type application/json", e); + return new ResponseEntity(HttpStatus.INTERNAL_SERVER_ERROR); + } + } + + public ResponseEntity transfers( + @Parameter(in = ParameterIn.DEFAULT, description = "post savings Account transfers", schema = @Schema()) @Valid @RequestBody InteropTransfers body) { + String accept = request.getHeader("Accept"); + return new ResponseEntity(HttpStatus.OK); + } + +} diff --git a/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/fineractstub/api/TransactionsApi.java b/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/fineractstub/api/TransactionsApi.java new file mode 100644 index 000000000..55b398de4 --- /dev/null +++ b/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/fineractstub/api/TransactionsApi.java @@ -0,0 +1,78 @@ +/** + * NOTE: This class is auto generated by the swagger code generator program (3.0.46). + * https://github.com/swagger-api/swagger-codegen + * Do not edit the class manually. + */ +package org.mifos.connector.fineractstub.api; + +import com.fasterxml.jackson.databind.ObjectMapper; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.enums.ParameterIn; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import java.util.Optional; +import javax.servlet.http.HttpServletRequest; +import javax.validation.Valid; +import org.mifos.connector.fineractstub.model.LoanRepayment; +import org.mifos.connector.fineractstub.model.SavingsDeposit; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; + +@SuppressWarnings("checkstyle:Dynamic") +@javax.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.SpringCodegen", date = "2023-08-10T10:13:07.472376795Z[GMT]") +@Validated +public interface TransactionsApi { + + Logger log = LoggerFactory.getLogger(TransactionsApi.class); + + default Optional getObjectMapper() { + return Optional.empty(); + } + + default Optional getRequest() { + return Optional.empty(); + } + + default Optional getAcceptHeader() { + return getRequest().map(r -> r.getHeader("Accept")); + } + + @Operation(summary = "Deposit to savings Account", description = "Adds an item to the system", tags = { "developers" }) + @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "item created"), + + @ApiResponse(responseCode = "400", description = "invalid input, object invalid"), + + @ApiResponse(responseCode = "409", description = "an existing item already exists") }) + @RequestMapping(value = "/transactions/deposit", consumes = { "application/json" }, method = RequestMethod.POST) + default ResponseEntity deposit( + @Parameter(in = ParameterIn.DEFAULT, description = "Deposit to savings Account", schema = @Schema()) @Valid @RequestBody SavingsDeposit body) { + if (getObjectMapper().isPresent() && getAcceptHeader().isPresent()) {} else { + log.warn("ObjectMapper or HttpServletRequest not configured in default TransactionsApi interface so no example is generated"); + } + return new ResponseEntity<>(HttpStatus.OK); + } + + @Operation(summary = "Loan repayment", description = "Adds an item to the system", tags = { "developers" }) + @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "item created"), + + @ApiResponse(responseCode = "400", description = "invalid input, object invalid"), + + @ApiResponse(responseCode = "409", description = "an existing item already exists") }) + @RequestMapping(value = "/transactions/loanrepayment", consumes = { "application/json" }, method = RequestMethod.POST) + default ResponseEntity loanRepayment( + @Parameter(in = ParameterIn.DEFAULT, description = "Loan Repayment", schema = @Schema()) @Valid @RequestBody LoanRepayment body) { + if (getObjectMapper().isPresent() && getAcceptHeader().isPresent()) {} else { + log.warn("ObjectMapper or HttpServletRequest not configured in default TransactionsApi interface so no example is generated"); + } + return new ResponseEntity<>(HttpStatus.OK); + } + +} diff --git a/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/fineractstub/api/TransactionsApiController.java b/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/fineractstub/api/TransactionsApiController.java new file mode 100644 index 000000000..5eac4da8b --- /dev/null +++ b/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/fineractstub/api/TransactionsApiController.java @@ -0,0 +1,58 @@ +package org.mifos.connector.fineractstub.api; + +import com.fasterxml.jackson.databind.ObjectMapper; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.enums.ParameterIn; +import io.swagger.v3.oas.annotations.media.Schema; +import java.util.Optional; +import javax.servlet.http.HttpServletRequest; +import javax.validation.Valid; +import org.mifos.connector.fineractstub.model.LoanRepayment; +import org.mifos.connector.fineractstub.model.SavingsDeposit; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; + +@SuppressWarnings("checkstyle:Dynamic") +@javax.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.SpringCodegen", date = "2023-08-10T10:13:07.472376795Z[GMT]") +@RestController +public class TransactionsApiController implements TransactionsApi { + + private static final Logger log = LoggerFactory.getLogger(TransactionsApiController.class); + + private final ObjectMapper objectMapper; + + private final HttpServletRequest request; + + @org.springframework.beans.factory.annotation.Autowired + public TransactionsApiController(ObjectMapper objectMapper, HttpServletRequest request) { + this.objectMapper = objectMapper; + this.request = request; + } + + @Override + public Optional getObjectMapper() { + return Optional.ofNullable(objectMapper); + } + + @Override + public Optional getRequest() { + return Optional.ofNullable(request); + } + + public ResponseEntity deposit( + @Parameter(in = ParameterIn.DEFAULT, description = "Deposit to savings Account", schema = @Schema()) @Valid @RequestBody SavingsDeposit body) { + String accept = request.getHeader("Accept"); + return new ResponseEntity(HttpStatus.OK); + } + + public ResponseEntity loanRepayment( + @Parameter(in = ParameterIn.DEFAULT, description = "Loan Repayment", schema = @Schema()) @Valid @RequestBody LoanRepayment body) { + String accept = request.getHeader("Accept"); + return new ResponseEntity(HttpStatus.OK); + } + +} diff --git a/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/fineractstub/configuration/CustomInstantDeserializer.java b/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/fineractstub/configuration/CustomInstantDeserializer.java new file mode 100644 index 000000000..6dd54b026 --- /dev/null +++ b/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/fineractstub/configuration/CustomInstantDeserializer.java @@ -0,0 +1,223 @@ +package org.mifos.connector.fineractstub.configuration; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.JsonTokenId; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.JsonDeserializer; +import com.fasterxml.jackson.datatype.threetenbp.DecimalUtils; +import com.fasterxml.jackson.datatype.threetenbp.deser.ThreeTenDateTimeDeserializerBase; +import com.fasterxml.jackson.datatype.threetenbp.function.BiFunction; +import com.fasterxml.jackson.datatype.threetenbp.function.Function; +import java.io.IOException; +import java.math.BigDecimal; +import org.threeten.bp.DateTimeException; +import org.threeten.bp.DateTimeUtils; +import org.threeten.bp.Instant; +import org.threeten.bp.OffsetDateTime; +import org.threeten.bp.ZoneId; +import org.threeten.bp.ZonedDateTime; +import org.threeten.bp.format.DateTimeFormatter; +import org.threeten.bp.temporal.Temporal; +import org.threeten.bp.temporal.TemporalAccessor; + +/** + * Deserializer for ThreeTen temporal {@link Instant}s, {@link OffsetDateTime}, and {@link ZonedDateTime}s. Adapted from + * the jackson threetenbp InstantDeserializer to add support for deserializing rfc822 format. + * + * @author Nick Williams + */ +@SuppressWarnings("checkstyle:Dynamic") +public class CustomInstantDeserializer extends ThreeTenDateTimeDeserializerBase { + + private static final long serialVersionUID = 1L; + + public static final CustomInstantDeserializer INSTANT = new CustomInstantDeserializer(Instant.class, + DateTimeFormatter.ISO_INSTANT, new Function() { + + @Override + public Instant apply(TemporalAccessor temporalAccessor) { + return Instant.from(temporalAccessor); + } + }, new Function() { + + @Override + public Instant apply(FromIntegerArguments a) { + return Instant.ofEpochMilli(a.value); + } + }, new Function() { + + @Override + public Instant apply(FromDecimalArguments a) { + return Instant.ofEpochSecond(a.integer, a.fraction); + } + }, null); + + public static final CustomInstantDeserializer OFFSET_DATE_TIME = new CustomInstantDeserializer( + OffsetDateTime.class, DateTimeFormatter.ISO_OFFSET_DATE_TIME, new Function() { + + @Override + public OffsetDateTime apply(TemporalAccessor temporalAccessor) { + return OffsetDateTime.from(temporalAccessor); + } + }, new Function() { + + @Override + public OffsetDateTime apply(FromIntegerArguments a) { + return OffsetDateTime.ofInstant(Instant.ofEpochMilli(a.value), a.zoneId); + } + }, new Function() { + + @Override + public OffsetDateTime apply(FromDecimalArguments a) { + return OffsetDateTime.ofInstant(Instant.ofEpochSecond(a.integer, a.fraction), a.zoneId); + } + }, new BiFunction() { + + @Override + public OffsetDateTime apply(OffsetDateTime d, ZoneId z) { + return d.withOffsetSameInstant(z.getRules().getOffset(d.toLocalDateTime())); + } + }); + + public static final CustomInstantDeserializer ZONED_DATE_TIME = new CustomInstantDeserializer( + ZonedDateTime.class, DateTimeFormatter.ISO_ZONED_DATE_TIME, new Function() { + + @Override + public ZonedDateTime apply(TemporalAccessor temporalAccessor) { + return ZonedDateTime.from(temporalAccessor); + } + }, new Function() { + + @Override + public ZonedDateTime apply(FromIntegerArguments a) { + return ZonedDateTime.ofInstant(Instant.ofEpochMilli(a.value), a.zoneId); + } + }, new Function() { + + @Override + public ZonedDateTime apply(FromDecimalArguments a) { + return ZonedDateTime.ofInstant(Instant.ofEpochSecond(a.integer, a.fraction), a.zoneId); + } + }, new BiFunction() { + + @Override + public ZonedDateTime apply(ZonedDateTime zonedDateTime, ZoneId zoneId) { + return zonedDateTime.withZoneSameInstant(zoneId); + } + }); + + protected final Function fromMilliseconds; + + protected final Function fromNanoseconds; + + protected final Function parsedToValue; + + protected final BiFunction adjust; + + protected CustomInstantDeserializer(Class supportedType, DateTimeFormatter parser, Function parsedToValue, + Function fromMilliseconds, Function fromNanoseconds, + BiFunction adjust) { + super(supportedType, parser); + this.parsedToValue = parsedToValue; + this.fromMilliseconds = fromMilliseconds; + this.fromNanoseconds = fromNanoseconds; + this.adjust = adjust == null ? new BiFunction() { + + @Override + public T apply(T t, ZoneId zoneId) { + return t; + } + } : adjust; + } + + @SuppressWarnings("unchecked") + protected CustomInstantDeserializer(CustomInstantDeserializer base, DateTimeFormatter f) { + super((Class) base.handledType(), f); + parsedToValue = base.parsedToValue; + fromMilliseconds = base.fromMilliseconds; + fromNanoseconds = base.fromNanoseconds; + adjust = base.adjust; + } + + @Override + protected JsonDeserializer withDateFormat(DateTimeFormatter dtf) { + if (dtf == _formatter) { + return this; + } + return new CustomInstantDeserializer(this, dtf); + } + + @Override + public T deserialize(JsonParser parser, DeserializationContext context) throws IOException { + // NOTE: Timestamps contain no timezone info, and are always in configured TZ. Only + // string values have to be adjusted to the configured TZ. + switch (parser.getCurrentTokenId()) { + case JsonTokenId.ID_NUMBER_FLOAT: { + BigDecimal value = parser.getDecimalValue(); + long seconds = value.longValue(); + int nanoseconds = DecimalUtils.extractNanosecondDecimal(value, seconds); + return fromNanoseconds.apply(new FromDecimalArguments(seconds, nanoseconds, getZone(context))); + } + + case JsonTokenId.ID_NUMBER_INT: { + long timestamp = parser.getLongValue(); + if (context.isEnabled(DeserializationFeature.READ_DATE_TIMESTAMPS_AS_NANOSECONDS)) { + return this.fromNanoseconds.apply(new FromDecimalArguments(timestamp, 0, this.getZone(context))); + } + return this.fromMilliseconds.apply(new FromIntegerArguments(timestamp, this.getZone(context))); + } + + case JsonTokenId.ID_STRING: { + String string = parser.getText().trim(); + if (string.length() == 0) { + return null; + } + if (string.endsWith("+0000")) { + string = string.substring(0, string.length() - 5) + "Z"; + } + T value; + try { + TemporalAccessor acc = _formatter.parse(string); + value = parsedToValue.apply(acc); + if (context.isEnabled(DeserializationFeature.ADJUST_DATES_TO_CONTEXT_TIME_ZONE)) { + return adjust.apply(value, this.getZone(context)); + } + } catch (DateTimeException e) { + throw _peelDTE(e); + } + return value; + } + } + throw context.mappingException("Expected type float, integer, or string."); + } + + private ZoneId getZone(DeserializationContext context) { + // Instants are always in UTC, so don't waste compute cycles + return (_valueClass == Instant.class) ? null : DateTimeUtils.toZoneId(context.getTimeZone()); + } + + private static class FromIntegerArguments { + + public final long value; + public final ZoneId zoneId; + + private FromIntegerArguments(long value, ZoneId zoneId) { + this.value = value; + this.zoneId = zoneId; + } + } + + private static class FromDecimalArguments { + + public final long integer; + public final int fraction; + public final ZoneId zoneId; + + private FromDecimalArguments(long integer, int fraction, ZoneId zoneId) { + this.integer = integer; + this.fraction = fraction; + this.zoneId = zoneId; + } + } +} diff --git a/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/fineractstub/configuration/HomeController.java b/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/fineractstub/configuration/HomeController.java new file mode 100644 index 000000000..98babf118 --- /dev/null +++ b/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/fineractstub/configuration/HomeController.java @@ -0,0 +1,18 @@ +package org.mifos.connector.fineractstub.configuration; + +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.RequestMapping; + +/** + * Home redirection to swagger api documentation + */ +@SuppressWarnings("checkstyle:Dynamic") +@Controller +public class HomeController { + + @RequestMapping(value = "/") + public String index() { + System.out.println("/swagger-ui/index.html"); + return "redirect:/swagger-ui/"; + } +} diff --git a/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/fineractstub/configuration/JacksonConfiguration.java b/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/fineractstub/configuration/JacksonConfiguration.java new file mode 100644 index 000000000..4388a0567 --- /dev/null +++ b/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/fineractstub/configuration/JacksonConfiguration.java @@ -0,0 +1,24 @@ +package org.mifos.connector.fineractstub.configuration; + +import com.fasterxml.jackson.datatype.threetenbp.ThreeTenModule; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.threeten.bp.Instant; +import org.threeten.bp.OffsetDateTime; +import org.threeten.bp.ZonedDateTime; + +@SuppressWarnings("checkstyle:Dynamic") +@Configuration +public class JacksonConfiguration { + + @Bean + @ConditionalOnMissingBean(ThreeTenModule.class) + ThreeTenModule threeTenModule() { + ThreeTenModule module = new ThreeTenModule(); + module.addDeserializer(Instant.class, CustomInstantDeserializer.INSTANT); + module.addDeserializer(OffsetDateTime.class, CustomInstantDeserializer.OFFSET_DATE_TIME); + module.addDeserializer(ZonedDateTime.class, CustomInstantDeserializer.ZONED_DATE_TIME); + return module; + } +} diff --git a/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/fineractstub/configuration/LocalDateConverter.java b/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/fineractstub/configuration/LocalDateConverter.java new file mode 100644 index 000000000..20c558ddb --- /dev/null +++ b/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/fineractstub/configuration/LocalDateConverter.java @@ -0,0 +1,23 @@ +package org.mifos.connector.fineractstub.configuration; + +import java.time.LocalDate; +import java.time.format.DateTimeFormatter; +import org.springframework.core.convert.converter.Converter; + +@SuppressWarnings("checkstyle:Dynamic") +public class LocalDateConverter implements Converter { + + private final DateTimeFormatter formatter; + + public LocalDateConverter(String dateFormat) { + this.formatter = DateTimeFormatter.ofPattern(dateFormat); + } + + @Override + public LocalDate convert(String source) { + if (source == null || source.isEmpty()) { + return null; + } + return LocalDate.parse(source, this.formatter); + } +} diff --git a/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/fineractstub/configuration/LocalDateTimeConverter.java b/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/fineractstub/configuration/LocalDateTimeConverter.java new file mode 100644 index 000000000..413e4a960 --- /dev/null +++ b/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/fineractstub/configuration/LocalDateTimeConverter.java @@ -0,0 +1,23 @@ +package org.mifos.connector.fineractstub.configuration; + +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import org.springframework.core.convert.converter.Converter; + +@SuppressWarnings("checkstyle:Dynamic") +public class LocalDateTimeConverter implements Converter { + + private final DateTimeFormatter formatter; + + public LocalDateTimeConverter(String dateFormat) { + this.formatter = DateTimeFormatter.ofPattern(dateFormat); + } + + @Override + public LocalDateTime convert(String source) { + if (source == null || source.isEmpty()) { + return null; + } + return LocalDateTime.parse(source, this.formatter); + } +} diff --git a/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/fineractstub/configuration/SwaggerDocumentationConfig.java b/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/fineractstub/configuration/SwaggerDocumentationConfig.java new file mode 100644 index 000000000..980b1371a --- /dev/null +++ b/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/fineractstub/configuration/SwaggerDocumentationConfig.java @@ -0,0 +1,40 @@ +package org.mifos.connector.fineractstub.configuration; + +import io.swagger.v3.oas.models.OpenAPI; +import io.swagger.v3.oas.models.info.Info; +import io.swagger.v3.oas.models.info.License; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import springfox.documentation.builders.ApiInfoBuilder; +import springfox.documentation.builders.RequestHandlerSelectors; +import springfox.documentation.service.ApiInfo; +import springfox.documentation.service.Contact; +import springfox.documentation.spi.DocumentationType; +import springfox.documentation.spring.web.plugins.Docket; + +@SuppressWarnings("checkstyle:Dynamic") +@javax.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.SpringCodegen", date = "2023-08-10T10:13:07.472376795Z[GMT]") +@Configuration +public class SwaggerDocumentationConfig { + + @Bean + public Docket customImplementation() { + return new Docket(DocumentationType.OAS_30).select().apis(RequestHandlerSelectors.basePackage("io.swagger.api")).build() + .directModelSubstitute(org.threeten.bp.LocalDate.class, java.sql.Date.class) + .directModelSubstitute(org.threeten.bp.OffsetDateTime.class, java.util.Date.class).apiInfo(apiInfo()); + } + + ApiInfo apiInfo() { + return new ApiInfoBuilder().title("Simple Savings Deposit API").description("This is a simple API").license("Apache 2.0") + .licenseUrl("http://www.apache.org/licenses/LICENSE-2.0.html").termsOfServiceUrl("").version("1.0.0") + .contact(new Contact("", "", "you@your-company.com")).build(); + } + + @Bean + public OpenAPI openApi() { + return new OpenAPI().info(new Info().title("Simple Savings Deposit API").description("This is a simple API").termsOfService("") + .version("1.0.0").license(new License().name("Apache 2.0").url("http://www.apache.org/licenses/LICENSE-2.0.html")) + .contact(new io.swagger.v3.oas.models.info.Contact().email("you@your-company.com"))); + } + +} diff --git a/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/fineractstub/configuration/SwaggerUiConfiguration.java b/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/fineractstub/configuration/SwaggerUiConfiguration.java new file mode 100644 index 000000000..2ae9a6135 --- /dev/null +++ b/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/fineractstub/configuration/SwaggerUiConfiguration.java @@ -0,0 +1,23 @@ +package org.mifos.connector.fineractstub.configuration; + +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; +import org.springframework.web.servlet.config.annotation.ViewControllerRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +@SuppressWarnings("checkstyle:Dynamic") +@javax.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.SpringCodegen", date = "2023-08-10T10:13:07.472376795Z[GMT]") +@Configuration +public class SwaggerUiConfiguration implements WebMvcConfigurer { + + @Override + public void addResourceHandlers(ResourceHandlerRegistry registry) { + registry.addResourceHandler("/swagger-ui/**").addResourceLocations("classpath:/META-INF/resources/webjars/springfox-swagger-ui/") + .resourceChain(false); + } + + @Override + public void addViewControllers(ViewControllerRegistry registry) { + registry.addViewController("/swagger-ui/").setViewName("forward:/swagger-ui/index.html"); + } +} diff --git a/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/fineractstub/model/InteropIdentifier.java b/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/fineractstub/model/InteropIdentifier.java new file mode 100644 index 000000000..162809103 --- /dev/null +++ b/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/fineractstub/model/InteropIdentifier.java @@ -0,0 +1,125 @@ +package org.mifos.connector.fineractstub.model; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import java.util.Objects; +import org.springframework.validation.annotation.Validated; + +/** + * InteropIdentifier + */ +@SuppressWarnings("checkstyle:Dynamic") +@Validated +@javax.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.SpringCodegen", date = "2023-08-10T10:13:07.472376795Z[GMT]") + +public class InteropIdentifier { + + @JsonProperty("accountId") + private String accountId = null; + + @JsonProperty("resourceId") + private String resourceId = null; + + @JsonProperty("resourceIdentifier") + private String resourceIdentifier = null; + + public InteropIdentifier accountId(String accountId) { + this.accountId = accountId; + return this; + } + + /** + * Get accountId + * + * @return accountId + **/ + @Schema(example = "cde3e5ee-214b-423f-97b0-0a0206aecaaf", description = "") + + public String getAccountId() { + return accountId; + } + + public void setAccountId(String accountId) { + this.accountId = accountId; + } + + public InteropIdentifier resourceId(String resourceId) { + this.resourceId = resourceId; + return this; + } + + /** + * Get resourceId + * + * @return resourceId + **/ + @Schema(example = "1", description = "") + + public String getResourceId() { + return resourceId; + } + + public void setResourceId(String resourceId) { + this.resourceId = resourceId; + } + + public InteropIdentifier resourceIdentifier(String resourceIdentifier) { + this.resourceIdentifier = resourceIdentifier; + return this; + } + + /** + * Get resourceIdentifier + * + * @return resourceIdentifier + **/ + @Schema(example = "1", description = "") + + public String getResourceIdentifier() { + return resourceIdentifier; + } + + public void setResourceIdentifier(String resourceIdentifier) { + this.resourceIdentifier = resourceIdentifier; + } + + @Override + public boolean equals(java.lang.Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + InteropIdentifier interopIdentifier = (InteropIdentifier) o; + return Objects.equals(this.accountId, interopIdentifier.accountId) && Objects.equals(this.resourceId, interopIdentifier.resourceId) + && Objects.equals(this.resourceIdentifier, interopIdentifier.resourceIdentifier); + } + + @Override + public int hashCode() { + return Objects.hash(accountId, resourceId, resourceIdentifier); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class InteropIdentifier {\n"); + + sb.append(" accountId: ").append(toIndentedString(accountId)).append("\n"); + sb.append(" resourceId: ").append(toIndentedString(resourceId)).append("\n"); + sb.append(" resourceIdentifier: ").append(toIndentedString(resourceIdentifier)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces (except the first line). + */ + private String toIndentedString(java.lang.Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } +} diff --git a/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/fineractstub/model/InteropTransfers.java b/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/fineractstub/model/InteropTransfers.java new file mode 100644 index 000000000..dba4fe254 --- /dev/null +++ b/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/fineractstub/model/InteropTransfers.java @@ -0,0 +1,177 @@ +package org.mifos.connector.fineractstub.model; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import java.util.Objects; +import javax.validation.Valid; +import org.springframework.validation.annotation.Validated; + +/** + * InteropTransfers + */ +@SuppressWarnings("checkstyle:Dynamic") +@Validated +@javax.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.SpringCodegen", date = "2023-08-10T10:13:07.472376795Z[GMT]") + +public class InteropTransfers { + + @JsonProperty("transactionCode") + private String transactionCode = null; + + @JsonProperty("transferCode") + private String transferCode = null; + + @JsonProperty("accountId") + private String accountId = null; + + @JsonProperty("amount") + private InteropTransfersAmount amount = null; + + @JsonProperty("transactionRole") + private String transactionRole = null; + + public InteropTransfers transactionCode(String transactionCode) { + this.transactionCode = transactionCode; + return this; + } + + /** + * Get transactionCode + * + * @return transactionCode + **/ + @Schema(example = "bd7046b7-e463-47e8-81aa-ec1c952e7fff", description = "") + + public String getTransactionCode() { + return transactionCode; + } + + public void setTransactionCode(String transactionCode) { + this.transactionCode = transactionCode; + } + + public InteropTransfers transferCode(String transferCode) { + this.transferCode = transferCode; + return this; + } + + /** + * Get transferCode + * + * @return transferCode + **/ + @Schema(example = "c695b904-e0eb-45ab-889e-1522c286dc20", description = "") + + public String getTransferCode() { + return transferCode; + } + + public void setTransferCode(String transferCode) { + this.transferCode = transferCode; + } + + public InteropTransfers accountId(String accountId) { + this.accountId = accountId; + return this; + } + + /** + * Get accountId + * + * @return accountId + **/ + @Schema(example = "000000001", description = "") + + public String getAccountId() { + return accountId; + } + + public void setAccountId(String accountId) { + this.accountId = accountId; + } + + public InteropTransfers amount(InteropTransfersAmount amount) { + this.amount = amount; + return this; + } + + /** + * Get amount + * + * @return amount + **/ + @Schema(description = "") + + @Valid + public InteropTransfersAmount getAmount() { + return amount; + } + + public void setAmount(InteropTransfersAmount amount) { + this.amount = amount; + } + + public InteropTransfers transactionRole(String transactionRole) { + this.transactionRole = transactionRole; + return this; + } + + /** + * Get transactionRole + * + * @return transactionRole + **/ + @Schema(example = "PAYEE", description = "") + + public String getTransactionRole() { + return transactionRole; + } + + public void setTransactionRole(String transactionRole) { + this.transactionRole = transactionRole; + } + + @Override + public boolean equals(java.lang.Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + InteropTransfers interopTransfers = (InteropTransfers) o; + return Objects.equals(this.transactionCode, interopTransfers.transactionCode) + && Objects.equals(this.transferCode, interopTransfers.transferCode) + && Objects.equals(this.accountId, interopTransfers.accountId) && Objects.equals(this.amount, interopTransfers.amount) + && Objects.equals(this.transactionRole, interopTransfers.transactionRole); + } + + @Override + public int hashCode() { + return Objects.hash(transactionCode, transferCode, accountId, amount, transactionRole); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class InteropTransfers {\n"); + + sb.append(" transactionCode: ").append(toIndentedString(transactionCode)).append("\n"); + sb.append(" transferCode: ").append(toIndentedString(transferCode)).append("\n"); + sb.append(" accountId: ").append(toIndentedString(accountId)).append("\n"); + sb.append(" amount: ").append(toIndentedString(amount)).append("\n"); + sb.append(" transactionRole: ").append(toIndentedString(transactionRole)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces (except the first line). + */ + private String toIndentedString(java.lang.Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } +} diff --git a/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/fineractstub/model/InteropTransfersAmount.java b/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/fineractstub/model/InteropTransfersAmount.java new file mode 100644 index 000000000..34bf9b55e --- /dev/null +++ b/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/fineractstub/model/InteropTransfersAmount.java @@ -0,0 +1,100 @@ +package org.mifos.connector.fineractstub.model; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import java.util.Objects; +import org.springframework.validation.annotation.Validated; + +/** + * InteropTransfersAmount + */ +@SuppressWarnings("checkstyle:Dynamic") +@Validated +@javax.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.SpringCodegen", date = "2023-08-10T10:13:07.472376795Z[GMT]") + +public class InteropTransfersAmount { + + @JsonProperty("amount") + private String amount = null; + + @JsonProperty("currency") + private String currency = null; + + public InteropTransfersAmount amount(String amount) { + this.amount = amount; + return this; + } + + /** + * Get amount + * + * @return amount + **/ + @Schema(example = "400", description = "") + + public String getAmount() { + return amount; + } + + public void setAmount(String amount) { + this.amount = amount; + } + + public InteropTransfersAmount currency(String currency) { + this.currency = currency; + return this; + } + + /** + * Get currency + * + * @return currency + **/ + @Schema(example = "USD", description = "") + + public String getCurrency() { + return currency; + } + + public void setCurrency(String currency) { + this.currency = currency; + } + + @Override + public boolean equals(java.lang.Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + InteropTransfersAmount interopTransfersAmount = (InteropTransfersAmount) o; + return Objects.equals(this.amount, interopTransfersAmount.amount) && Objects.equals(this.currency, interopTransfersAmount.currency); + } + + @Override + public int hashCode() { + return Objects.hash(amount, currency); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class InteropTransfersAmount {\n"); + + sb.append(" amount: ").append(toIndentedString(amount)).append("\n"); + sb.append(" currency: ").append(toIndentedString(currency)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces (except the first line). + */ + private String toIndentedString(java.lang.Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } +} diff --git a/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/fineractstub/model/LoanRepayment.java b/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/fineractstub/model/LoanRepayment.java new file mode 100644 index 000000000..353537e0e --- /dev/null +++ b/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/fineractstub/model/LoanRepayment.java @@ -0,0 +1,181 @@ +package org.mifos.connector.fineractstub.model; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import java.util.Objects; +import javax.validation.constraints.NotNull; +import org.springframework.validation.annotation.Validated; + +/** + * LoanRepayment + */ +@SuppressWarnings("checkstyle:Dynamic") +@Validated +@javax.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.SpringCodegen", date = "2023-08-10T10:13:07.472376795Z[GMT]") + +public class LoanRepayment { + + @JsonProperty("transactionDate") + private String transactionDate = null; + + @JsonProperty("transactionAmount") + private String transactionAmount = null; + + @JsonProperty("paymentTypeId") + private String paymentTypeId = null; + + @JsonProperty("locale") + private String locale = null; + + @JsonProperty("dateFormat") + private String dateFormat = null; + + public LoanRepayment transactionDate(String transactionDate) { + this.transactionDate = transactionDate; + return this; + } + + /** + * Get transactionDate + * + * @return transactionDate + **/ + @Schema(example = "08 August 2023", required = true, description = "") + @NotNull + + public String getTransactionDate() { + return transactionDate; + } + + public void setTransactionDate(String transactionDate) { + this.transactionDate = transactionDate; + } + + public LoanRepayment transactionAmount(String transactionAmount) { + this.transactionAmount = transactionAmount; + return this; + } + + /** + * Get transactionAmount + * + * @return transactionAmount + **/ + @Schema(example = "10000", required = true, description = "") + @NotNull + + public String getTransactionAmount() { + return transactionAmount; + } + + public void setTransactionAmount(String transactionAmount) { + this.transactionAmount = transactionAmount; + } + + public LoanRepayment paymentTypeId(String paymentTypeId) { + this.paymentTypeId = paymentTypeId; + return this; + } + + /** + * Get paymentTypeId + * + * @return paymentTypeId + **/ + @Schema(example = "1", required = true, description = "") + @NotNull + + public String getPaymentTypeId() { + return paymentTypeId; + } + + public void setPaymentTypeId(String paymentTypeId) { + this.paymentTypeId = paymentTypeId; + } + + public LoanRepayment locale(String locale) { + this.locale = locale; + return this; + } + + /** + * Get locale + * + * @return locale + **/ + @Schema(example = "en", required = true, description = "") + @NotNull + + public String getLocale() { + return locale; + } + + public void setLocale(String locale) { + this.locale = locale; + } + + public LoanRepayment dateFormat(String dateFormat) { + this.dateFormat = dateFormat; + return this; + } + + /** + * Get dateFormat + * + * @return dateFormat + **/ + @Schema(example = "dd MMMM yyyy", required = true, description = "") + @NotNull + + public String getDateFormat() { + return dateFormat; + } + + public void setDateFormat(String dateFormat) { + this.dateFormat = dateFormat; + } + + @Override + public boolean equals(java.lang.Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + LoanRepayment loanRepayment = (LoanRepayment) o; + return Objects.equals(this.transactionDate, loanRepayment.transactionDate) + && Objects.equals(this.transactionAmount, loanRepayment.transactionAmount) + && Objects.equals(this.paymentTypeId, loanRepayment.paymentTypeId) && Objects.equals(this.locale, loanRepayment.locale) + && Objects.equals(this.dateFormat, loanRepayment.dateFormat); + } + + @Override + public int hashCode() { + return Objects.hash(transactionDate, transactionAmount, paymentTypeId, locale, dateFormat); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class LoanRepayment {\n"); + + sb.append(" transactionDate: ").append(toIndentedString(transactionDate)).append("\n"); + sb.append(" transactionAmount: ").append(toIndentedString(transactionAmount)).append("\n"); + sb.append(" paymentTypeId: ").append(toIndentedString(paymentTypeId)).append("\n"); + sb.append(" locale: ").append(toIndentedString(locale)).append("\n"); + sb.append(" dateFormat: ").append(toIndentedString(dateFormat)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces (except the first line). + */ + private String toIndentedString(java.lang.Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } +} diff --git a/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/fineractstub/model/SavingsDeposit.java b/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/fineractstub/model/SavingsDeposit.java new file mode 100644 index 000000000..a650f3252 --- /dev/null +++ b/ph-ee-connector-ams-mifos/src/main/java/org/mifos/connector/fineractstub/model/SavingsDeposit.java @@ -0,0 +1,181 @@ +package org.mifos.connector.fineractstub.model; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import java.util.Objects; +import javax.validation.constraints.NotNull; +import org.springframework.validation.annotation.Validated; + +/** + * SavingsDeposit + */ +@SuppressWarnings("checkstyle:Dynamic") +@Validated +@javax.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.SpringCodegen", date = "2023-08-10T10:13:07.472376795Z[GMT]") + +public class SavingsDeposit { + + @JsonProperty("transactionDate") + private String transactionDate = null; + + @JsonProperty("transactionAmount") + private String transactionAmount = null; + + @JsonProperty("paymentTypeId") + private String paymentTypeId = null; + + @JsonProperty("locale") + private String locale = null; + + @JsonProperty("dateFormat") + private String dateFormat = null; + + public SavingsDeposit transactionDate(String transactionDate) { + this.transactionDate = transactionDate; + return this; + } + + /** + * Get transactionDate + * + * @return transactionDate + **/ + @Schema(example = "08 August 2023", required = true, description = "") + @NotNull + + public String getTransactionDate() { + return transactionDate; + } + + public void setTransactionDate(String transactionDate) { + this.transactionDate = transactionDate; + } + + public SavingsDeposit transactionAmount(String transactionAmount) { + this.transactionAmount = transactionAmount; + return this; + } + + /** + * Get transactionAmount + * + * @return transactionAmount + **/ + @Schema(example = "10000", required = true, description = "") + @NotNull + + public String getTransactionAmount() { + return transactionAmount; + } + + public void setTransactionAmount(String transactionAmount) { + this.transactionAmount = transactionAmount; + } + + public SavingsDeposit paymentTypeId(String paymentTypeId) { + this.paymentTypeId = paymentTypeId; + return this; + } + + /** + * Get paymentTypeId + * + * @return paymentTypeId + **/ + @Schema(example = "1", required = true, description = "") + @NotNull + + public String getPaymentTypeId() { + return paymentTypeId; + } + + public void setPaymentTypeId(String paymentTypeId) { + this.paymentTypeId = paymentTypeId; + } + + public SavingsDeposit locale(String locale) { + this.locale = locale; + return this; + } + + /** + * Get locale + * + * @return locale + **/ + @Schema(example = "en", required = true, description = "") + @NotNull + + public String getLocale() { + return locale; + } + + public void setLocale(String locale) { + this.locale = locale; + } + + public SavingsDeposit dateFormat(String dateFormat) { + this.dateFormat = dateFormat; + return this; + } + + /** + * Get dateFormat + * + * @return dateFormat + **/ + @Schema(example = "dd MMMM yyyy", required = true, description = "") + @NotNull + + public String getDateFormat() { + return dateFormat; + } + + public void setDateFormat(String dateFormat) { + this.dateFormat = dateFormat; + } + + @Override + public boolean equals(java.lang.Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + SavingsDeposit savingsDeposit = (SavingsDeposit) o; + return Objects.equals(this.transactionDate, savingsDeposit.transactionDate) + && Objects.equals(this.transactionAmount, savingsDeposit.transactionAmount) + && Objects.equals(this.paymentTypeId, savingsDeposit.paymentTypeId) && Objects.equals(this.locale, savingsDeposit.locale) + && Objects.equals(this.dateFormat, savingsDeposit.dateFormat); + } + + @Override + public int hashCode() { + return Objects.hash(transactionDate, transactionAmount, paymentTypeId, locale, dateFormat); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class SavingsDeposit {\n"); + + sb.append(" transactionDate: ").append(toIndentedString(transactionDate)).append("\n"); + sb.append(" transactionAmount: ").append(toIndentedString(transactionAmount)).append("\n"); + sb.append(" paymentTypeId: ").append(toIndentedString(paymentTypeId)).append("\n"); + sb.append(" locale: ").append(toIndentedString(locale)).append("\n"); + sb.append(" dateFormat: ").append(toIndentedString(dateFormat)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces (except the first line). + */ + private String toIndentedString(java.lang.Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } +} diff --git a/ph-ee-connector-ams-mifos/src/main/resources/application-bb.yml b/ph-ee-connector-ams-mifos/src/main/resources/application-bb.yml new file mode 100644 index 000000000..1592baadc --- /dev/null +++ b/ph-ee-connector-ams-mifos/src/main/resources/application-bb.yml @@ -0,0 +1,39 @@ +ams: + local: + interop: + host: https://rhino.mifos.io:8443 + customer: + host: https://rhino.mifos.io:8443 + account: + host: https://rhino.mifos.io:8443 + auth: + host: https://rhino.mifos.io:8443 + tenants: + - name: "gorilla" + user: mifos + password: password + authtype: basic + fspId: payerfsp + - name: "wakanda" + user: mifos + password: password + authtype: basic + fspId: payerfsp + - name: "venus" + user: mifos + password: password + authtype: basic + fspId: payeefsp + - name: "jupiter" + user: mifos + password: password + authtype: basic + fspId: payeefsp + - name: "pluto" + user: mifos + password: password + authtype: basic + fspId: payeefsp + +# Savings : S , Loan : L +accountPrefixes: "S,L" diff --git a/ph-ee-connector-ams-mifos/src/main/resources/application-fin12.yml b/ph-ee-connector-ams-mifos/src/main/resources/application-fin12.yml new file mode 100644 index 000000000..8a956cc77 --- /dev/null +++ b/ph-ee-connector-ams-mifos/src/main/resources/application-fin12.yml @@ -0,0 +1,57 @@ +camel: + server-port: 5000 + springboot: + main-run-controller: true + dataformat: + json-jackson: + auto-discover-object-mapper: true + +dfspids: "DFSPID" + +zeebe: + broker: + contactpoint: "127.0.0.1:26500" + +ams: + local: + enabled: true + version: 1.2 + keystore-path: keystore.jks + keystore-password: openmf + interop: + host: https://localhost:8443 + base-url: /fineract-provider/api/v1 + quotes-path: ${ams.local.interop.base-url}/interoperation/quotes + parties-path: ${ams.local.interop.base-url}/interoperation/parties/{idType}/{idValue} + transfers-path: ${ams.local.interop.base-url}/interoperation/transfers + accounts-path: ${ams.local.interop.base-url}/interoperation/accounts/{externalAccountId} + customer: + host: https://localhost:8443 + base-url: /fineract-provider/api/v1 + path: ${ams.local.customer.base-url}/clients/{clientId} + image: ${ams.local.customer.base-url}/clients/{clientId}/images + account: + host: https://localhost:8443 + base-url: /fineract-provider/api/v1 + savingsaccounts-path: ${ams.local.account.base-url}/savingsaccounts + auth: + host: https://localhost:8443 + loan: + host: http://localhost:8443 + repayment-path: /fineract-provider/api/v1/interoperation/transactions/{accountNumber}/loanrepayment + +mock-service: + local: + loan: + host: http://localhost:7070 + base-url: /fineract + repayment-path: ${mock-service.local.loan.base-url}/transactions/loanrepayment + interop: + host: http://localhost:7070 + base-url: /fineract + quotes-path: ${mock-service.local.interop.base-url}/savingsaccount + parties-path: ${mock-service.local.interop.base-url}/savingsaccount + transfers-path: ${mock-service.local.interop.base-url}/savingsaccount/transfers + accounts-path: ${mock-service.local.interop.base-url}/savingsaccount +# Savings : S , Loan : L +accountPrefixes: "S,L" diff --git a/ph-ee-connector-ams-mifos/src/main/resources/application-fincn.yml b/ph-ee-connector-ams-mifos/src/main/resources/application-fincn.yml new file mode 100644 index 000000000..7784c0cdb --- /dev/null +++ b/ph-ee-connector-ams-mifos/src/main/resources/application-fincn.yml @@ -0,0 +1,39 @@ +camel: + server-port: 5000 + springboot: + main-run-controller: true + dataformat: + json-jackson: + auto-discover-object-mapper: true + +dfspids: "DFSPID" + +zeebe: + broker: + contactpoint: "ph-ee-zeebe:26500" + +ams: + local: + enabled: true + version: cn + keystore-path: keystore.jks + keystore-password: openmf + interop: + host: http://localhost:2034 + base-url: /interoperation/v1 + quotes-path: ${ams.local.interop.base-url}/quotes + parties-path: ${ams.local.interop.base-url}/parties/{idType}/{idValue} + transfers-path: ${ams.local.interop.base-url}/transfers + customer: + host: http://localhost:2024 + base-url: /customer/v1 + path: ${ams.local.customer.base-url}/customers/{customerIdentifier} + account: + host: http://localhost:2027 + base-url: /deposit/v1 + instances-path: ${ams.local.account.base-url}/instances/{accountId} + definitons-path: ${ams.local.account.base-url}/definitions/{definitionId} + auth: + host: http://localhost:2021 + base-url: /identity/v1 + path: ${ams.local.auth.base-url}/token diff --git a/ph-ee-connector-ams-mifos/src/main/resources/application-large.yml b/ph-ee-connector-ams-mifos/src/main/resources/application-large.yml new file mode 100644 index 000000000..858597b60 --- /dev/null +++ b/ph-ee-connector-ams-mifos/src/main/resources/application-large.yml @@ -0,0 +1,16 @@ +ams: + local: + interop: + host: http://buffalo.mifos.io:2034 + customer: + host: http://buffalo.mifos.io:2024 + account: + host: http://buffalo.mifos.io:2027 + auth: + host: http://buffalo.mifos.io:2021 + tenants: + - name: tn01 + user: interopUser + password: intop@d1 + authtype: oauth + fspId: in01tn01 diff --git a/ph-ee-connector-ams-mifos/src/main/resources/application-med.yml b/ph-ee-connector-ams-mifos/src/main/resources/application-med.yml new file mode 100644 index 000000000..e6b1e4677 --- /dev/null +++ b/ph-ee-connector-ams-mifos/src/main/resources/application-med.yml @@ -0,0 +1,21 @@ +ams: + local: + interop: + host: https://leopard.mifos.io:8443 + customer: + host: https://leopard.mifos.io:8443 + account: + host: https://leopard.mifos.io:8443 + auth: + host: https://leopard.mifos.io:8443 + tenants: + - name: tn05 + user: mifos + password: password + authtype: basic + fspId: in03tn05 + - name: tn06 + user: mifos + password: password + authtype: basic + fspId: in03tn06 diff --git a/ph-ee-connector-ams-mifos/src/main/resources/application.yml b/ph-ee-connector-ams-mifos/src/main/resources/application.yml new file mode 100644 index 000000000..d6c5fbfae --- /dev/null +++ b/ph-ee-connector-ams-mifos/src/main/resources/application.yml @@ -0,0 +1,64 @@ +camel: + server-port: 5000 + springboot: + main-run-controller: true + dataformat: + json-jackson: + auto-discover-object-mapper: true + +dfspids: "DFSPID" + +zeebe: + client: + max-execution-threads: 50 + evenly-allocated-max-jobs: 1000 + poll-interval: 10 +# number-of-workers: 8 +# evenly-allocated-max-jobs: "#{${zeebe.client.max-execution-threads} / ${zeebe.client.number-of-workers}}" + broker: + contactpoint: "127.0.0.1:26500" + +#ams: +# local: +# server-cert-check: false +# enabled: true + +ams: + local: + server-cert-check: false + enabled: false + +interop-party-registration: + enabled: false + +spring: + profiles: + active: "bb,fin12" + jackson: + date-format: org.mifos.connector.fineractstub.RFC3339DateFormat + serialization: + WRITE_DATES_AS_TIMESTAMPS: false + + +springfox: + documentation: + open-api: + v3: + path: /api-docs +server: + servlet: + contextPath: /fineract + port: 7070 + + + +management: + endpoint: + health: + enabled: true + probes: + enabled: true + liveness: + enabled: true + readiness: + enabled: true diff --git a/ph-ee-connector-ams-mifos/src/main/resources/endpoints.xml b/ph-ee-connector-ams-mifos/src/main/resources/endpoints.xml new file mode 100644 index 000000000..b1e26e842 --- /dev/null +++ b/ph-ee-connector-ams-mifos/src/main/resources/endpoints.xml @@ -0,0 +1,107 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ph-ee-connector-ams-mifos/src/main/resources/keystore.jks b/ph-ee-connector-ams-mifos/src/main/resources/keystore.jks new file mode 100644 index 000000000..b2455d0a3 Binary files /dev/null and b/ph-ee-connector-ams-mifos/src/main/resources/keystore.jks differ diff --git a/ph-ee-connector-ams-mifos/src/main/resources/logback.xml b/ph-ee-connector-ams-mifos/src/main/resources/logback.xml new file mode 100644 index 000000000..b2438ba8e --- /dev/null +++ b/ph-ee-connector-ams-mifos/src/main/resources/logback.xml @@ -0,0 +1,23 @@ + + + + + + + + + ${CONSOLE_LOG_PATTERN} + utf8 + + + + + + + + + + + + diff --git a/ph-ee-connector-ams-mifos/src/test/java/org/mifos/connector/ams/TestUtil.java b/ph-ee-connector-ams-mifos/src/test/java/org/mifos/connector/ams/TestUtil.java new file mode 100644 index 000000000..da4e9d107 --- /dev/null +++ b/ph-ee-connector-ams-mifos/src/test/java/org/mifos/connector/ams/TestUtil.java @@ -0,0 +1,16 @@ +package org.mifos.connector.ams; + +import java.util.UUID; +import org.junit.jupiter.api.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class TestUtil { + + public Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Test + public void test1() { + logger.info(UUID.randomUUID().toString()); + } +} diff --git a/ph-ee-connector-bulk/.circleci/config.yml b/ph-ee-connector-bulk/.circleci/config.yml new file mode 100644 index 000000000..a79cfc0fb --- /dev/null +++ b/ph-ee-connector-bulk/.circleci/config.yml @@ -0,0 +1,102 @@ +version: 2.1 +executors: + docker-executor: + docker: + - image: circleci/openjdk:17-buster-node-browsers-legacy + auth: + username: $DOCKERHUB_USERNAME + password: $DOCKERHUB_PASSWORD + +jobs: + build_and_push_tag_image: + executor: docker-executor + environment: + JVM_OPTS: -Xmx512m + TERM: dumb + GITHUB_TOKEN: ${GITHUB_TOKEN} # Add the GitHub token as an environment variable + + steps: + - checkout + - setup_remote_docker: + version: 20.10.14 + - run: + name: Build and Push Docker tag Image + command: | + # Set environment variables + IMAGE_TAG=$CIRCLE_TAG + + # Check if the Docker image with the same tag already exists in Docker Hub + if curl -s -f -u "$DOCKERHUB_USERNAME":"$DOCKERHUB_PASSWORD" "https://hub.docker.com/v2/repositories/fynarfin/ph-ee-connector-bulk/tags/$IMAGE_TAG" > /dev/null; then + echo "Skipping the build and push as the tag $IMAGE_TAG already exists in Docker Hub." + exit 0 + fi + + # Build and tag the Docker image + ./gradlew bootJar + docker build -t "fynarfin/ph-ee-connector-bulk:$IMAGE_TAG" . + + # Push the Docker image to Docker Hub + docker login -u "$DOCKERHUB_USERNAME" -p "$DOCKERHUB_PASSWORD" + docker push "fynarfin/ph-ee-connector-bulk:$IMAGE_TAG" + + # when: always # The job will be executed even if there's no match for the tag filter + + build_and_push_latest_image: + executor: docker-executor + environment: + JVM_OPTS: -Xmx512m + TERM: dumb + + steps: + - checkout + # Install Docker to build and push the image + - setup_remote_docker: + version: 20.10.14 + + # Build the Docker image + - run: + name: Build Docker image + command: | + ./gradlew bootJar + docker build -t fynarfin/ph-ee-connector-bulk:latest . + if [ "$CIRCLE_BRANCH" != "develop" ]; then + PR_NUMBER=$(basename $CIRCLE_PULL_REQUEST) + PR_TITLE=$(curl -sSL "https://api.github.com/repos/fynarfin/$CIRCLE_PR_REPONAME/pulls/$PR_NUMBER" | jq -r '.title') + JIRA_STORY=$(echo $PR_TITLE | cut -d "[" -f2 | cut -d "]" -f1 | tr '[A-Z]' '[a-z]') + if [ -z "$JIRA_STORY" ]; then echo "Invalid PR title" && exit 1; else echo "Ticket NO: $JIRA_STORY"; fi + docker image tag fynarfin/$CIRCLE_PR_REPONAME:latest fynarfin/$CIRCLE_PR_REPONAME:$JIRA_STORY + fi + + # Log in to DockerHub using environment variables + - run: + name: Login to DockerHub + command: echo "${DOCKERHUB_PASSWORD}" | docker login -u "${DOCKERHUB_USERNAME}" --password-stdin + + # Push the Docker image to DockerHub + - run: + name: Push Docker image to DockerHub + command: | + if [ "$CIRCLE_BRANCH" = "develop" ]; then + docker push fynarfin/ph-ee-connector-bulk:latest + fi + if [ "$CIRCLE_BRANCH" != "develop" ]; then + PR_NUMBER=$(basename $CIRCLE_PULL_REQUEST) + PR_TITLE=$(curl -sSL "https://api.github.com/repos/fynarfin/$CIRCLE_PR_REPONAME/pulls/$PR_NUMBER" | jq -r '.title') + JIRA_STORY=$(echo $PR_TITLE | cut -d "[" -f2 | cut -d "]" -f1 | tr '[A-Z]' '[a-z]') + docker push fynarfin/$CIRCLE_PR_REPONAME:${JIRA_STORY} + fi + + +workflows: + version: 2 + build-and-push: + jobs: + - build_and_push_tag_image: + filters: + tags: + only: /^v\d+\.\d+\.\d+$/ # Match tags in the format v1.2.3 + context: + - DOCKER + - build_and_push_latest_image: + context: + - DOCKER diff --git a/ph-ee-connector-bulk/.github/ISSUE_TEMPLATE/DMP_2024.yml b/ph-ee-connector-bulk/.github/ISSUE_TEMPLATE/DMP_2024.yml new file mode 100644 index 000000000..f729c7318 --- /dev/null +++ b/ph-ee-connector-bulk/.github/ISSUE_TEMPLATE/DMP_2024.yml @@ -0,0 +1,264 @@ +name: DMP 2024 Project Template +description: List a new project for Dedicated Mentoring Program (DMP) 2024 +title: "[DMP 2024]: " +labels: ["DMP 2024"] +body: + - type: textarea + id: ticket-description + validations: + required: true + attributes: + label: Ticket Contents + value: | + ## Description + [Provide a brief description of the feature, including why it is needed and what it will accomplish.] + + - type: textarea + id: ticket-goals + validations: + required: true + attributes: + label: Goals & Mid-Point Milestone + description: List the goals of the feature. Please add the goals that must be achieved by Mid-point check-in i.e 1.5 months into the coding period. + value: | + ## Goals + - [ ] [Goal 1] + - [ ] [Goal 2] + - [ ] [Goal 3] + - [ ] [Goal 4] + - [ ] [Goals Achieved By Mid-point Milestone] + + - type: textarea + id: ticket-setup + attributes: + label: Setup/Installation + description: Please list or link setup or installation guide (if any) + + - type: textarea + id: ticket-expected-outcome + attributes: + label: Expected Outcome + description: Describe in detail what the final product or result should look like and how it should behave. + + - type: textarea + id: ticket-acceptance-criteria + attributes: + label: Acceptance Criteria + description: List the acceptance criteria for this feature. + + - type: textarea + id: ticket-implementation-details + validations: + required: true + attributes: + label: Implementation Details + description: List any technical details about the proposed implementation, including any specific technologies that will be used. + + - type: textarea + id: ticket-mockups + attributes: + label: Mockups/Wireframes + description: Include links to any visual aids, mockups, wireframes, or diagrams that help illustrate what the final product should look like. This is not always necessary, but can be very helpful in many cases. + + - type: input + id: ticket-product + attributes: + label: Product Name + placeholder: Enter Product Name + validations: + required: true + + - type: dropdown + id: ticket-organisation + attributes: + label: Organisation Name + description: Enter Organisation Name + multiple: false + options: + - Bandhu + - Belongg + - Blockster Global (CREDBEL) + - Civis + - Dhwani + - Dhiway + - EGov + - EkShop Marketplace + - FIDE + - If Me + - Key Education Foundation + - Norwegian Meteorological Institute + - Planet Read + - Project Second Chance + - Reap Benefit + - SamagraX + - ShikshaLokam + - Tech4Dev + - Tekdi + - The Mifos Initiative + - Tibil + - Ushahidi + - Arghyam + - Piramal Swasthya Management Research Institute + - Belongg AI + validations: + required: true + + - type: dropdown + id: ticket-governance-domain + attributes: + label: Domain + options: + - ⁠Healthcare + - ⁠Education + - Financial Inclusion + - ⁠Livelihoods + - ⁠Skilling + - ⁠Learning & Development + - ⁠Agriculture + - ⁠Service Delivery + - Open Source Library + - Water + validations: + required: true + + + - type: dropdown + id: ticket-technical-skills-required + attributes: + label: Tech Skills Needed + description: Select the technologies needed for this ticket (use Ctrl or Command to select multiple) + multiple: true + options: + - .NET + - Angular + - Artificial Intelligence + - ASP.NET + - AWS + - Babel + - Bootstrap + - C# + - Chart.js + - CI/CD + - Computer Vision + - CORS + - cURL + - Cypress + - D3.js + - Database + - Debugging + - Design + - DevOps + - Django + - Docker + - Electron + - ESLint + - Express.js + - Feature + - Flask + - Go + - GraphQL + - HTML + - Ionic + - Jest + - Java + - JavaScript + - Jenkins + - JWT + - Kubernetes + - Laravel + - Machine Learning + - Maintenance + - Markdown + - Material-UI + - Microservices + - MongoDB + - Mobile + - Mockups + - Mocha + - Natural Language Processing + - NestJS + - Node.js + - NUnit + - OAuth + - Performance Improvement + - Prettier + - Python + - Question + - React + - React Native + - Redux + - RESTful APIs + - Ruby + - Ruby on Rails + - Rust + - Scala + - Security + - Selenium + - SEO + - Serverless + - Solidity + - Spring Boot + - SQL + - Swagger + - Tailwind CSS + - Test + - Testing Library + - Three.js + - TypeScript + - UI/UX/Design + - Virtual Reality + - Vue.js + - WebSockets + - Webpack + - Other + validations: + required: true + + - type: textarea + id: ticket-mentors + attributes: + label: Mentor(s) + description: Please tag relevant mentors for the ticket + validations: + required: true + + - type: dropdown + id: ticket-category + attributes: + label: Category + description: Choose the categories that best describe your ticket + multiple: true + options: + - API + - Analytics + - Accessibility + - Backend + - Breaking Change + - Beginner Friendly + - Configuration + - CI/CD + - Database + - Data Science + - Deprecation + - Documentation + - Delpoyment + - Frontend + - Internationalization + - Localization + - Machine Learning + - Maintenance + - Mobile + - Performance Improvement + - Question + - Refactoring + - Research + - Needs Reproduction + - SEO + - Security + - Testing + - AI + - Other + validations: + required: true + + diff --git a/ph-ee-connector-bulk/.gitignore b/ph-ee-connector-bulk/.gitignore new file mode 100644 index 000000000..245f53aff --- /dev/null +++ b/ph-ee-connector-bulk/.gitignore @@ -0,0 +1,34 @@ +target/ +.gradle +build/ +bin/ +!gradle/wrapper/gradle-wrapper.jar + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +/build/ + +### VS Code ### +.vscode/ + +### MAC +.DS_Store \ No newline at end of file diff --git a/ph-ee-connector-bulk/Dockerfile b/ph-ee-connector-bulk/Dockerfile new file mode 100644 index 000000000..4782d6bd1 --- /dev/null +++ b/ph-ee-connector-bulk/Dockerfile @@ -0,0 +1,5 @@ +FROM openjdk:17 +EXPOSE 8080 + +COPY build/libs/*.jar . +CMD java -jar *.jar diff --git a/ph-ee-connector-bulk/HELP.md b/ph-ee-connector-bulk/HELP.md new file mode 100644 index 000000000..cf3eaacae --- /dev/null +++ b/ph-ee-connector-bulk/HELP.md @@ -0,0 +1,14 @@ +# Getting Started + +### Reference Documentation +For further reference, please consider the following sections: + +* [Official Gradle documentation](https://docs.gradle.org) +* [Spring Boot Gradle Plugin Reference Guide](https://docs.spring.io/spring-boot/docs/3.0.6/gradle-plugin/reference/html/) +* [Create an OCI image](https://docs.spring.io/spring-boot/docs/3.0.6/gradle-plugin/reference/html/#build-image) + +### Additional Links +These additional references should also help you: + +* [Gradle Build Scans – insights for your project's build](https://scans.gradle.com#gradle) + diff --git a/ph-ee-connector-bulk/LICENSE b/ph-ee-connector-bulk/LICENSE new file mode 100644 index 000000000..a612ad981 --- /dev/null +++ b/ph-ee-connector-bulk/LICENSE @@ -0,0 +1,373 @@ +Mozilla Public License Version 2.0 +================================== + +1. Definitions +-------------- + +1.1. "Contributor" + means each individual or legal entity that creates, contributes to + the creation of, or owns Covered Software. + +1.2. "Contributor Version" + means the combination of the Contributions of others (if any) used + by a Contributor and that particular Contributor's Contribution. + +1.3. "Contribution" + means Covered Software of a particular Contributor. + +1.4. "Covered Software" + means Source Code Form to which the initial Contributor has attached + the notice in Exhibit A, the Executable Form of such Source Code + Form, and Modifications of such Source Code Form, in each case + including portions thereof. + +1.5. "Incompatible With Secondary Licenses" + means + + (a) that the initial Contributor has attached the notice described + in Exhibit B to the Covered Software; or + + (b) that the Covered Software was made available under the terms of + version 1.1 or earlier of the License, but not also under the + terms of a Secondary License. + +1.6. "Executable Form" + means any form of the work other than Source Code Form. + +1.7. "Larger Work" + means a work that combines Covered Software with other material, in + a separate file or files, that is not Covered Software. + +1.8. "License" + means this document. + +1.9. "Licensable" + means having the right to grant, to the maximum extent possible, + whether at the time of the initial grant or subsequently, any and + all of the rights conveyed by this License. + +1.10. "Modifications" + means any of the following: + + (a) any file in Source Code Form that results from an addition to, + deletion from, or modification of the contents of Covered + Software; or + + (b) any new file in Source Code Form that contains any Covered + Software. + +1.11. "Patent Claims" of a Contributor + means any patent claim(s), including without limitation, method, + process, and apparatus claims, in any patent Licensable by such + Contributor that would be infringed, but for the grant of the + License, by the making, using, selling, offering for sale, having + made, import, or transfer of either its Contributions or its + Contributor Version. + +1.12. "Secondary License" + means either the GNU General Public License, Version 2.0, the GNU + Lesser General Public License, Version 2.1, the GNU Affero General + Public License, Version 3.0, or any later versions of those + licenses. + +1.13. "Source Code Form" + means the form of the work preferred for making modifications. + +1.14. "You" (or "Your") + means an individual or a legal entity exercising rights under this + License. For legal entities, "You" includes any entity that + controls, is controlled by, or is under common control with You. For + purposes of this definition, "control" means (a) the power, direct + or indirect, to cause the direction or management of such entity, + whether by contract or otherwise, or (b) ownership of more than + fifty percent (50%) of the outstanding shares or beneficial + ownership of such entity. + +2. License Grants and Conditions +-------------------------------- + +2.1. Grants + +Each Contributor hereby grants You a world-wide, royalty-free, +non-exclusive license: + +(a) under intellectual property rights (other than patent or trademark) + Licensable by such Contributor to use, reproduce, make available, + modify, display, perform, distribute, and otherwise exploit its + Contributions, either on an unmodified basis, with Modifications, or + as part of a Larger Work; and + +(b) under Patent Claims of such Contributor to make, use, sell, offer + for sale, have made, import, and otherwise transfer either its + Contributions or its Contributor Version. + +2.2. Effective Date + +The licenses granted in Section 2.1 with respect to any Contribution +become effective for each Contribution on the date the Contributor first +distributes such Contribution. + +2.3. Limitations on Grant Scope + +The licenses granted in this Section 2 are the only rights granted under +this License. No additional rights or licenses will be implied from the +distribution or licensing of Covered Software under this License. +Notwithstanding Section 2.1(b) above, no patent license is granted by a +Contributor: + +(a) for any code that a Contributor has removed from Covered Software; + or + +(b) for infringements caused by: (i) Your and any other third party's + modifications of Covered Software, or (ii) the combination of its + Contributions with other software (except as part of its Contributor + Version); or + +(c) under Patent Claims infringed by Covered Software in the absence of + its Contributions. + +This License does not grant any rights in the trademarks, service marks, +or logos of any Contributor (except as may be necessary to comply with +the notice requirements in Section 3.4). + +2.4. Subsequent Licenses + +No Contributor makes additional grants as a result of Your choice to +distribute the Covered Software under a subsequent version of this +License (see Section 10.2) or under the terms of a Secondary License (if +permitted under the terms of Section 3.3). + +2.5. Representation + +Each Contributor represents that the Contributor believes its +Contributions are its original creation(s) or it has sufficient rights +to grant the rights to its Contributions conveyed by this License. + +2.6. Fair Use + +This License is not intended to limit any rights You have under +applicable copyright doctrines of fair use, fair dealing, or other +equivalents. + +2.7. Conditions + +Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted +in Section 2.1. + +3. Responsibilities +------------------- + +3.1. Distribution of Source Form + +All distribution of Covered Software in Source Code Form, including any +Modifications that You create or to which You contribute, must be under +the terms of this License. You must inform recipients that the Source +Code Form of the Covered Software is governed by the terms of this +License, and how they can obtain a copy of this License. You may not +attempt to alter or restrict the recipients' rights in the Source Code +Form. + +3.2. Distribution of Executable Form + +If You distribute Covered Software in Executable Form then: + +(a) such Covered Software must also be made available in Source Code + Form, as described in Section 3.1, and You must inform recipients of + the Executable Form how they can obtain a copy of such Source Code + Form by reasonable means in a timely manner, at a charge no more + than the cost of distribution to the recipient; and + +(b) You may distribute such Executable Form under the terms of this + License, or sublicense it under different terms, provided that the + license for the Executable Form does not attempt to limit or alter + the recipients' rights in the Source Code Form under this License. + +3.3. Distribution of a Larger Work + +You may create and distribute a Larger Work under terms of Your choice, +provided that You also comply with the requirements of this License for +the Covered Software. If the Larger Work is a combination of Covered +Software with a work governed by one or more Secondary Licenses, and the +Covered Software is not Incompatible With Secondary Licenses, this +License permits You to additionally distribute such Covered Software +under the terms of such Secondary License(s), so that the recipient of +the Larger Work may, at their option, further distribute the Covered +Software under the terms of either this License or such Secondary +License(s). + +3.4. Notices + +You may not remove or alter the substance of any license notices +(including copyright notices, patent notices, disclaimers of warranty, +or limitations of liability) contained within the Source Code Form of +the Covered Software, except that You may alter any license notices to +the extent required to remedy known factual inaccuracies. + +3.5. Application of Additional Terms + +You may choose to offer, and to charge a fee for, warranty, support, +indemnity or liability obligations to one or more recipients of Covered +Software. However, You may do so only on Your own behalf, and not on +behalf of any Contributor. You must make it absolutely clear that any +such warranty, support, indemnity, or liability obligation is offered by +You alone, and You hereby agree to indemnify every Contributor for any +liability incurred by such Contributor as a result of warranty, support, +indemnity or liability terms You offer. You may include additional +disclaimers of warranty and limitations of liability specific to any +jurisdiction. + +4. Inability to Comply Due to Statute or Regulation +--------------------------------------------------- + +If it is impossible for You to comply with any of the terms of this +License with respect to some or all of the Covered Software due to +statute, judicial order, or regulation then You must: (a) comply with +the terms of this License to the maximum extent possible; and (b) +describe the limitations and the code they affect. Such description must +be placed in a text file included with all distributions of the Covered +Software under this License. Except to the extent prohibited by statute +or regulation, such description must be sufficiently detailed for a +recipient of ordinary skill to be able to understand it. + +5. Termination +-------------- + +5.1. The rights granted under this License will terminate automatically +if You fail to comply with any of its terms. However, if You become +compliant, then the rights granted under this License from a particular +Contributor are reinstated (a) provisionally, unless and until such +Contributor explicitly and finally terminates Your grants, and (b) on an +ongoing basis, if such Contributor fails to notify You of the +non-compliance by some reasonable means prior to 60 days after You have +come back into compliance. Moreover, Your grants from a particular +Contributor are reinstated on an ongoing basis if such Contributor +notifies You of the non-compliance by some reasonable means, this is the +first time You have received notice of non-compliance with this License +from such Contributor, and You become compliant prior to 30 days after +Your receipt of the notice. + +5.2. If You initiate litigation against any entity by asserting a patent +infringement claim (excluding declaratory judgment actions, +counter-claims, and cross-claims) alleging that a Contributor Version +directly or indirectly infringes any patent, then the rights granted to +You by any and all Contributors for the Covered Software under Section +2.1 of this License shall terminate. + +5.3. In the event of termination under Sections 5.1 or 5.2 above, all +end user license agreements (excluding distributors and resellers) which +have been validly granted by You or Your distributors under this License +prior to termination shall survive termination. + +************************************************************************ +* * +* 6. Disclaimer of Warranty * +* ------------------------- * +* * +* Covered Software is provided under this License on an "as is" * +* basis, without warranty of any kind, either expressed, implied, or * +* statutory, including, without limitation, warranties that the * +* Covered Software is free of defects, merchantable, fit for a * +* particular purpose or non-infringing. The entire risk as to the * +* quality and performance of the Covered Software is with You. * +* Should any Covered Software prove defective in any respect, You * +* (not any Contributor) assume the cost of any necessary servicing, * +* repair, or correction. This disclaimer of warranty constitutes an * +* essential part of this License. No use of any Covered Software is * +* authorized under this License except under this disclaimer. * +* * +************************************************************************ + +************************************************************************ +* * +* 7. Limitation of Liability * +* -------------------------- * +* * +* Under no circumstances and under no legal theory, whether tort * +* (including negligence), contract, or otherwise, shall any * +* Contributor, or anyone who distributes Covered Software as * +* permitted above, be liable to You for any direct, indirect, * +* special, incidental, or consequential damages of any character * +* including, without limitation, damages for lost profits, loss of * +* goodwill, work stoppage, computer failure or malfunction, or any * +* and all other commercial damages or losses, even if such party * +* shall have been informed of the possibility of such damages. This * +* limitation of liability shall not apply to liability for death or * +* personal injury resulting from such party's negligence to the * +* extent applicable law prohibits such limitation. Some * +* jurisdictions do not allow the exclusion or limitation of * +* incidental or consequential damages, so this exclusion and * +* limitation may not apply to You. * +* * +************************************************************************ + +8. Litigation +------------- + +Any litigation relating to this License may be brought only in the +courts of a jurisdiction where the defendant maintains its principal +place of business and such litigation shall be governed by laws of that +jurisdiction, without reference to its conflict-of-law provisions. +Nothing in this Section shall prevent a party's ability to bring +cross-claims or counter-claims. + +9. Miscellaneous +---------------- + +This License represents the complete agreement concerning the subject +matter hereof. If any provision of this License is held to be +unenforceable, such provision shall be reformed only to the extent +necessary to make it enforceable. Any law or regulation which provides +that the language of a contract shall be construed against the drafter +shall not be used to construe this License against a Contributor. + +10. Versions of the License +--------------------------- + +10.1. New Versions + +Mozilla Foundation is the license steward. Except as provided in Section +10.3, no one other than the license steward has the right to modify or +publish new versions of this License. Each version will be given a +distinguishing version number. + +10.2. Effect of New Versions + +You may distribute the Covered Software under the terms of the version +of the License under which You originally received the Covered Software, +or under the terms of any subsequent version published by the license +steward. + +10.3. Modified Versions + +If you create software not governed by this License, and you want to +create a new license for such software, you may create and use a +modified version of this License if you rename the license and remove +any references to the name of the license steward (except to note that +such modified license differs from this License). + +10.4. Distributing Source Code Form that is Incompatible With Secondary +Licenses + +If You choose to distribute Source Code Form that is Incompatible With +Secondary Licenses under the terms of this version of the License, the +notice described in Exhibit B of this License must be attached. + +Exhibit A - Source Code Form License Notice +------------------------------------------- + + This Source Code Form is subject to the terms of the Mozilla Public + License, v. 2.0. If a copy of the MPL was not distributed with this + file, You can obtain one at http://mozilla.org/MPL/2.0/. + +If it is not possible or desirable to put the notice in a particular +file, then You may include the notice in a location (such as a LICENSE +file in a relevant directory) where a recipient would be likely to look +for such a notice. + +You may add additional accurate notices of copyright ownership. + +Exhibit B - "Incompatible With Secondary Licenses" Notice +--------------------------------------------------------- + + This Source Code Form is "Incompatible With Secondary Licenses", as + defined by the Mozilla Public License, v. 2.0. diff --git a/ph-ee-connector-bulk/README.md b/ph-ee-connector-bulk/README.md new file mode 100644 index 000000000..99a5913d8 --- /dev/null +++ b/ph-ee-connector-bulk/README.md @@ -0,0 +1,5 @@ +# payment-hub-ee +Payment Hub Enterprise Edition middleware for integration to real-time payment systems. + +For detailed documentation check the documentation: https://app.gitbook.com/@mifos/s/docs/payment-hub-ee/overview + diff --git a/ph-ee-connector-bulk/build.gradle b/ph-ee-connector-bulk/build.gradle new file mode 100644 index 000000000..6974525a2 --- /dev/null +++ b/ph-ee-connector-bulk/build.gradle @@ -0,0 +1,56 @@ +plugins { + id 'java' + id 'org.springframework.boot' version '2.5.5' + id 'io.spring.dependency-management' version '1.1.0' + id 'idea' + id "org.springdoc.openapi-gradle-plugin" version "1.6.0" + id 'eclipse' +} + +group = 'org.mifos' +version = '0.0.1-SNAPSHOT' +sourceCompatibility = '17' + +repositories { + mavenCentral() + maven { url "https://repo.spring.io/libs-release" } + maven { url "https://repository.jboss.org/nexus/content/repositories/releases" } + maven { url "https://jfrog.sandbox.fynarfin.io/artifactory/fyn-libs-snapshot"} + maven { + url = uri('https://jfrog.sandbox.fynarfin.io/artifactory/fyn-libs-snapshot') + } +} +ext { + camelVersion = '3.18.1' + zeebClientVersion = '1.3.1' +} + +dependencies { + implementation 'com.google.code.gson:gson:2.8.9' + implementation 'org.json:json:20210307' + implementation 'org.mifos:ph-ee-connector-common:1.8.1-SNAPSHOT' + implementation 'org.apache.camel.springboot:camel-spring-boot-starter:3.4.0' + implementation 'org.apache.camel:camel-undertow:3.4.0' + implementation 'org.springframework.boot:spring-boot-starter:2.5.2' + implementation 'org.springframework.boot:spring-boot-starter-web:2.5.2' + implementation 'org.springframework:spring-web:5.3.19' + implementation 'org.apache.camel:camel-http:3.4.0' + implementation 'com.amazonaws:aws-java-sdk:1.11.486' + implementation 'com.azure:azure-storage-blob:12.12.0' + implementation 'io.camunda:zeebe-client-java:1.1.0' + implementation 'com.fasterxml.jackson.dataformat:jackson-dataformat-csv:2.12.0' + //implementation 'org.springframework.kafka:spring-kafka:2.5.8.RELEASE' + implementation 'org.apache.camel:camel-jackson:3.4.0' + implementation 'org.apache.camel.springboot:camel-mail-starter:3.4.0' + implementation('io.rest-assured:rest-assured:4.4.0') + compileOnly 'org.projectlombok:lombok:1.18.24' + annotationProcessor 'org.projectlombok:lombok:1.18.24' + + implementation "org.springdoc:springdoc-openapi-ui:1.6.11" +} + +tasks.named('test') { + useJUnitPlatform() +} +task bootRun() { +} diff --git a/ph-ee-connector-bulk/gradle/wrapper/gradle-wrapper.jar b/ph-ee-connector-bulk/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 000000000..7454180f2 Binary files /dev/null and b/ph-ee-connector-bulk/gradle/wrapper/gradle-wrapper.jar differ diff --git a/ph-ee-connector-bulk/gradle/wrapper/gradle-wrapper.properties b/ph-ee-connector-bulk/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 000000000..ffed3a254 --- /dev/null +++ b/ph-ee-connector-bulk/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-bin.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/ph-ee-connector-bulk/gradlew b/ph-ee-connector-bulk/gradlew new file mode 100755 index 000000000..1b6c78733 --- /dev/null +++ b/ph-ee-connector-bulk/gradlew @@ -0,0 +1,234 @@ +#!/bin/sh + +# +# Copyright © 2015-2021 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit + +APP_NAME="Gradle" +APP_BASE_NAME=${0##*/} + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/ph-ee-connector-bulk/gradlew.bat b/ph-ee-connector-bulk/gradlew.bat new file mode 100644 index 000000000..ac1b06f93 --- /dev/null +++ b/ph-ee-connector-bulk/gradlew.bat @@ -0,0 +1,89 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/ph-ee-connector-bulk/settings.gradle b/ph-ee-connector-bulk/settings.gradle new file mode 100644 index 000000000..a88c9d46c --- /dev/null +++ b/ph-ee-connector-bulk/settings.gradle @@ -0,0 +1 @@ +rootProject.name = 'connector-bulk' diff --git a/ph-ee-connector-bulk/src/main/java/org/mifos/connector/phee/ConnectorPheeApplication.java b/ph-ee-connector-bulk/src/main/java/org/mifos/connector/phee/ConnectorPheeApplication.java new file mode 100644 index 000000000..d7c5fa19a --- /dev/null +++ b/ph-ee-connector-bulk/src/main/java/org/mifos/connector/phee/ConnectorPheeApplication.java @@ -0,0 +1,26 @@ +package org.mifos.connector.phee; + +import com.fasterxml.jackson.dataformat.csv.CsvMapper; +import org.mifos.connector.phee.camel.config.HttpClientConfigurerTrustAllCACerts; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.Bean; + +@SpringBootApplication +public class ConnectorPheeApplication { + + public static void main(String[] args) { + SpringApplication.run(ConnectorPheeApplication.class, args); + } + + @Bean + public CsvMapper csvMapper() { + return new CsvMapper(); + } + + @Bean + public HttpClientConfigurerTrustAllCACerts httpClientConfigurer() { + return new HttpClientConfigurerTrustAllCACerts(); + } + +} diff --git a/ph-ee-connector-bulk/src/main/java/org/mifos/connector/phee/api/definition/PayerRtpReqApi.java b/ph-ee-connector-bulk/src/main/java/org/mifos/connector/phee/api/definition/PayerRtpReqApi.java new file mode 100644 index 000000000..fd45f113c --- /dev/null +++ b/ph-ee-connector-bulk/src/main/java/org/mifos/connector/phee/api/definition/PayerRtpReqApi.java @@ -0,0 +1,30 @@ +package org.mifos.connector.phee.api.definition; + +import org.mifos.connector.phee.data.PayerRequestDTO; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.mifos.connector.phee.data.ResponseDTO; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestHeader; + +import java.util.concurrent.ExecutionException; + +@Tag(name = "GOV") +public interface PayerRtpReqApi { + + @Operation( + summary = "Bill RTP Req API from PBB to PFI") + @PostMapping(value = "/billTransferRequests", consumes = MediaType.APPLICATION_JSON_VALUE) + ResponseEntity payerRtpReq(@RequestHeader(value="X-Platform-TenantId") String tenantId, + @RequestHeader(value="X-Client-Correlation-ID") String correlationId, + @RequestHeader(value = "X-Callback-URL") + String callbackUrl, + @RequestHeader(value = "X-Biller-Id") String billerId, + @RequestBody String payerRequestDTO) + throws ExecutionException, InterruptedException; + +} \ No newline at end of file diff --git a/ph-ee-connector-bulk/src/main/java/org/mifos/connector/phee/api/implmentation/PayerRTPReqController.java b/ph-ee-connector-bulk/src/main/java/org/mifos/connector/phee/api/implmentation/PayerRTPReqController.java new file mode 100644 index 000000000..e4e06268e --- /dev/null +++ b/ph-ee-connector-bulk/src/main/java/org/mifos/connector/phee/api/implmentation/PayerRTPReqController.java @@ -0,0 +1,41 @@ +package org.mifos.connector.phee.api.implmentation; + +import org.mifos.connector.phee.api.definition.PayerRtpReqApi; +import org.mifos.connector.phee.data.PayerRequestDTO; +import org.mifos.connector.phee.data.ResponseDTO; +import org.mifos.connector.phee.service.BillRTPReqService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.RestController; + +import java.util.concurrent.ExecutionException; + + import static org.mifos.connector.phee.utils.BillPayrEnum.FAILED_RESPONSE; +import static org.mifos.connector.phee.utils.BillPayrEnum.SUCCESS_RESPONSE; + +@RestController +public class PayerRTPReqController implements PayerRtpReqApi { + + @Autowired + private BillRTPReqService billRTPReqService; + + @Override + public ResponseEntity payerRtpReq(String tenantId, String correlationId, + String callbackUrl, String billerId, String payerRequestDTO) + throws ExecutionException, InterruptedException { + try { + billRTPReqService.payerRtpReq(tenantId, correlationId,callbackUrl, billerId ,payerRequestDTO); + } catch (Exception e) { + //ResponseDTO responseDTO = new ResponseDTO(FAILED_RESPONSE.getValue(), FAILED_RESPONSE.getMessage(), correlationId); + String response = "{\"responseCode\": \"" + FAILED_RESPONSE.getValue() + "\", \"responseDescription\": \"" + + FAILED_RESPONSE.getMessage() + "\", \"requestID\": \"" + correlationId + "\"}"; + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(response); + } + //ResponseDTO responseDTO = new ResponseDTO(SUCCESS_RESPONSE.getValue(), SUCCESS_RESPONSE.getMessage(), correlationId); + String response = "{\"responseCode\": \"" + SUCCESS_RESPONSE.getValue() + "\", \"responseDescription\": \"" + + SUCCESS_RESPONSE.getMessage() + "\", \"requestID\": \"" + correlationId + "\"}"; + return ResponseEntity.status(HttpStatus.ACCEPTED).body(response); + } + +} diff --git a/ph-ee-connector-bulk/src/main/java/org/mifos/connector/phee/camel/config/CamelContextConfig.java b/ph-ee-connector-bulk/src/main/java/org/mifos/connector/phee/camel/config/CamelContextConfig.java new file mode 100644 index 000000000..9a5218bc4 --- /dev/null +++ b/ph-ee-connector-bulk/src/main/java/org/mifos/connector/phee/camel/config/CamelContextConfig.java @@ -0,0 +1,59 @@ +package org.mifos.connector.phee.camel.config; + +import org.apache.camel.CamelContext; +import org.apache.camel.component.http.HttpComponent; +import org.apache.camel.spi.RestConfiguration; +import org.apache.camel.spring.boot.CamelContextConfiguration; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import java.util.HashMap; + +@Configuration +public class CamelContextConfig { + + @Value("${camel.server-port}") + private int serverPort; + + @Value("${camel.disable-ssl}") + private boolean disableSSL; + + @Autowired + private HttpClientConfigurerTrustAllCACerts httpClientConfigurerTrustAllCACerts; + + @Bean + CamelContextConfiguration contextConfiguration() { + return new CamelContextConfiguration() { + @Override + public void beforeApplicationStart(CamelContext camelContext) { + camelContext.setTracing(false); + camelContext.setMessageHistory(false); + camelContext.setStreamCaching(true); + camelContext.disableJMX(); + + if (disableSSL) { + HttpComponent httpComponent = camelContext.getComponent("https", HttpComponent.class); + httpComponent.setHttpClientConfigurer(httpClientConfigurerTrustAllCACerts); + } + + + RestConfiguration rest = new RestConfiguration(); + camelContext.setRestConfiguration(rest); + rest.setComponent("undertow"); + rest.setProducerComponent("undertow"); + rest.setPort(serverPort); + rest.setBindingMode(RestConfiguration.RestBindingMode.json); + rest.setDataFormatProperties(new HashMap<>()); + rest.getDataFormatProperties().put("prettyPrint", "true"); + rest.setScheme("http"); + } + + @Override + public void afterApplicationStart(CamelContext camelContext) { + // empty + } + }; + } +} diff --git a/ph-ee-connector-bulk/src/main/java/org/mifos/connector/phee/camel/config/CamelProperties.java b/ph-ee-connector-bulk/src/main/java/org/mifos/connector/phee/camel/config/CamelProperties.java new file mode 100644 index 000000000..a6149fc83 --- /dev/null +++ b/ph-ee-connector-bulk/src/main/java/org/mifos/connector/phee/camel/config/CamelProperties.java @@ -0,0 +1,10 @@ +package org.mifos.connector.phee.camel.config; + +public class CamelProperties { + + private CamelProperties(){} + + public static final String CSV_FILE_NAME = "csvFileName"; + + public static final String TRANSACTION_COUNT = "transactionCount"; +} diff --git a/ph-ee-connector-bulk/src/main/java/org/mifos/connector/phee/camel/config/HttpClientConfigurerTrustAllCACerts.java b/ph-ee-connector-bulk/src/main/java/org/mifos/connector/phee/camel/config/HttpClientConfigurerTrustAllCACerts.java new file mode 100644 index 000000000..86d563a1f --- /dev/null +++ b/ph-ee-connector-bulk/src/main/java/org/mifos/connector/phee/camel/config/HttpClientConfigurerTrustAllCACerts.java @@ -0,0 +1,67 @@ +package org.mifos.connector.phee.camel.config; + +import org.apache.camel.component.http.HttpClientConfigurer; +import org.apache.http.config.Registry; +import org.apache.http.config.RegistryBuilder; +import org.apache.http.conn.socket.ConnectionSocketFactory; +import org.apache.http.conn.socket.PlainConnectionSocketFactory; +import org.apache.http.conn.ssl.SSLConnectionSocketFactory; +import org.apache.http.conn.ssl.TrustStrategy; +import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; +import org.apache.http.ssl.SSLContextBuilder; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.net.ssl.HostnameVerifier; +import javax.net.ssl.SSLContext; +import java.security.KeyManagementException; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; + +public class HttpClientConfigurerTrustAllCACerts implements HttpClientConfigurer { + + public Logger logger = LoggerFactory.getLogger(this.getClass()); + + public HttpClientConfigurerTrustAllCACerts() { + } + + @Override + public void configureHttpClient(HttpClientBuilder clientBuilder) { + // setup a Trust Strategy that allows all certificates. + // + SSLContext sslContext = null; + try { + sslContext = new SSLContextBuilder().loadTrustMaterial(null, new TrustStrategy() { + public boolean isTrusted(X509Certificate[] arg0, String arg1) throws CertificateException { + return true; + } + }).build(); + } catch (KeyManagementException | NoSuchAlgorithmException | KeyStoreException e) { + e.printStackTrace(); + } + clientBuilder.setSslcontext( sslContext); + + // don't check Hostnames, either. + // -- use SSLConnectionSocketFactory.getDefaultHostnameVerifier(), if you don't want to weaken + HostnameVerifier hostnameVerifier = SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER; + + // here's the special part: + // -- need to create an SSL Socket Factory, to use our weakened "trust strategy"; + // -- and create a Registry, to register it. + // + SSLConnectionSocketFactory sslSocketFactory = new SSLConnectionSocketFactory(sslContext, hostnameVerifier); + Registry socketFactoryRegistry = RegistryBuilder.create() + .register("http", PlainConnectionSocketFactory.getSocketFactory()) + .register("https", sslSocketFactory) + .build(); + + // now, we create connection-manager using our Registry. + // -- allows multi-threaded use + PoolingHttpClientConnectionManager connMgr = new PoolingHttpClientConnectionManager( socketFactoryRegistry); + clientBuilder.setConnectionManager(connMgr); + } + +} diff --git a/ph-ee-connector-bulk/src/main/java/org/mifos/connector/phee/camel/routes/BaseRouteBuilder.java b/ph-ee-connector-bulk/src/main/java/org/mifos/connector/phee/camel/routes/BaseRouteBuilder.java new file mode 100644 index 000000000..592bd4b7b --- /dev/null +++ b/ph-ee-connector-bulk/src/main/java/org/mifos/connector/phee/camel/routes/BaseRouteBuilder.java @@ -0,0 +1,68 @@ +package org.mifos.connector.phee.camel.routes; + +import com.fasterxml.jackson.databind.ObjectMapper; +import io.camunda.zeebe.client.ZeebeClient; +import org.apache.camel.Exchange; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.model.RouteDefinition; +import org.mifos.connector.phee.config.OperationsAppConfig; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +import java.time.ZoneOffset; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; + +@Component +public abstract class BaseRouteBuilder extends RouteBuilder { + + @Autowired + public ObjectMapper objectMapper; + + @Autowired + public OperationsAppConfig operationsAppConfig; + + @Autowired + ZeebeClient zeebeClient; + +// @Value("#{'${tenants}'.split(',')}") +// protected List tenants; + + @Value("${cloud.aws.s3-base-url}") + protected String awsS3BaseUrl; + + public Logger logger = LoggerFactory.getLogger(this.getClass()); + + public RouteDefinition getBaseExternalApiRequestRouteDefinition(String routeId, HttpRequestMethod httpMethod) { + return from(String.format("direct:%s", routeId)) + .id(routeId) + .log("Starting external API request route: " + routeId) + .removeHeader("*") + .setHeader(Exchange.HTTP_METHOD, constant(httpMethod.text)) + .setHeader("X-Date", simple(ZonedDateTime.now( ZoneOffset.UTC ).format( DateTimeFormatter.ISO_INSTANT ))) + .setHeader("Content-Type", constant("application/json;charset=UTF-8")) + .setHeader("Accept", constant("application/json, text/plain, */*")); + } + + protected enum HttpRequestMethod { + GET("GET"), + POST("POST"), + PUT("PUT"), + DELETE("DELETE") + ; + + private final String text; + + HttpRequestMethod(String text) { + this.text = text; + } + + @Override + public String toString() { + return text; + } + } +} diff --git a/ph-ee-connector-bulk/src/main/java/org/mifos/connector/phee/camel/routes/BatchDetailRoute.java b/ph-ee-connector-bulk/src/main/java/org/mifos/connector/phee/camel/routes/BatchDetailRoute.java new file mode 100644 index 000000000..7d89ac873 --- /dev/null +++ b/ph-ee-connector-bulk/src/main/java/org/mifos/connector/phee/camel/routes/BatchDetailRoute.java @@ -0,0 +1,190 @@ +package org.mifos.connector.phee.camel.routes; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.apache.camel.Exchange; +import org.apache.camel.LoggingLevel; +import org.mifos.connector.phee.config.MockPaymentSchemaConfig; +import org.mifos.connector.phee.schema.BatchDetailResponse; +import org.mifos.connector.phee.schema.Transaction; +import org.mifos.connector.phee.schema.TransactionResult; +import org.mifos.connector.phee.schema.Transfer; +import org.mifos.connector.phee.schema.TransferStatus; +import org.mifos.connector.phee.utils.Utils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static org.mifos.connector.phee.zeebe.ZeebeVariables.BATCH_DETAIL_SUCCESS; +import static org.mifos.connector.phee.zeebe.ZeebeVariables.BATCH_ID; +import static org.mifos.connector.phee.zeebe.ZeebeVariables.COMPLETED_TRANSACTION_COUNT; +import static org.mifos.connector.phee.zeebe.ZeebeVariables.CURRENT_TRANSACTION_COUNT; +import static org.mifos.connector.phee.zeebe.ZeebeVariables.ERROR_CODE; +import static org.mifos.connector.phee.zeebe.ZeebeVariables.ERROR_DESCRIPTION; +import static org.mifos.connector.phee.zeebe.ZeebeVariables.FAILED_TRANSACTION_COUNT; +import static org.mifos.connector.phee.zeebe.ZeebeVariables.FILE_NAME; +import static org.mifos.connector.phee.zeebe.ZeebeVariables.LOCAL_FILE_PATH; +import static org.mifos.connector.phee.zeebe.ZeebeVariables.ONGOING_TRANSACTION_COUNT; +import static org.mifos.connector.phee.zeebe.ZeebeVariables.OVERRIDE_HEADER; +import static org.mifos.connector.phee.zeebe.ZeebeVariables.PAGE_NO; +import static org.mifos.connector.phee.zeebe.ZeebeVariables.REQUEST_ID_STATUS_MAP; +import static org.mifos.connector.phee.zeebe.ZeebeVariables.RESULT_FILE; +import static org.mifos.connector.phee.zeebe.ZeebeVariables.RESULT_TRANSACTION_LIST; +import static org.mifos.connector.phee.zeebe.ZeebeVariables.TOTAL_TRANSACTION; +import static org.mifos.connector.phee.zeebe.ZeebeVariables.TRANSACTION_LIST; + + +@Component +public class BatchDetailRoute extends BaseRouteBuilder { + + @Value("${config.completion-threshold-check.completion-threshold}") + private int completionThreshold; + + @Value("${tenant}") + public String tenant; + + @Autowired + public MockPaymentSchemaConfig mockPaymentSchemaConfig; + private ObjectMapper objectMapper = new ObjectMapper(); + + @Override + public void configure() throws Exception { + + from(RouteId.BATCH_DETAIL.getValue()) + .id(RouteId.BATCH_DETAIL.getValue()) + .log("Starting route " + RouteId.BATCH_DETAIL.name()) + .to("direct:batch-detail-api-call") + .to("direct:batch-detail-response-handler"); + + from("direct:batch-detail-api-call") + .routeId("direct:batch-detail-api-call") + .setHeader("CamelHttpMethod", constant("GET")) + .setHeader("Accept", constant("application/json")) + .toD(mockPaymentSchemaConfig.mockPaymentSchemaContactPoint+"/batches/"+ "${exchangeProperty.batchId}"+"/detail"+ "?" + "pageNo" + "=${exchangeProperty.pageNo}&" + "pageSize" + + "=${exchangeProperty.pageSize}" ) + .log("API Response: ${body}") + .setProperty("apiResponse", body()) ; // Log the API response, you can modify this according to your needs + + + from("direct:batch-detail-response-handler") + .id("direct:batch-detail-response-handler") + .log("Starting route direct:batch-detail-response-handler") + .choice() + .when(header("CamelHttpResponseCode").isEqualTo("200")) + .log(LoggingLevel.INFO, "Batch detail request successful") + .process(exchange -> { + String apiResponse = exchange.getProperty("apiResponse", String.class); + logger.info(apiResponse); + BatchDetailResponse batchDetailResponse = objectMapper.readValue(apiResponse, BatchDetailResponse.class); + logger.info(batchDetailResponse.toString()); + + int pageNo = Integer.parseInt(exchange.getProperty(PAGE_NO, String.class)); + int currentTransferCount = exchange.getProperty(CURRENT_TRANSACTION_COUNT)!=null ? + Integer.parseInt(exchange.getProperty(CURRENT_TRANSACTION_COUNT, String.class)) : 0; + int completedTransferCount = exchange.getProperty(COMPLETED_TRANSACTION_COUNT)!=null ? + Integer.parseInt(exchange.getProperty(COMPLETED_TRANSACTION_COUNT, String.class)) : 0; + int failedTransferCount = exchange.getProperty(FAILED_TRANSACTION_COUNT)!=null ? + Integer.parseInt(exchange.getProperty(FAILED_TRANSACTION_COUNT, String.class)) : 0; + int ongoingTransferCount = exchange.getProperty(ONGOING_TRANSACTION_COUNT)!=null ? + Integer.parseInt(exchange.getProperty(ONGOING_TRANSACTION_COUNT, String.class)) : 0; + int totalTransferCount = exchange.getProperty(TOTAL_TRANSACTION)!=null ? + Integer.parseInt(exchange.getProperty(TOTAL_TRANSACTION, String.class)) : 0; + + List transfers = batchDetailResponse.getContent(); + int completedTransferCountPerPage = 0; + int ongoingTransferCountPerPage = 0; + int failedTransferCountPerPage = 0; + int transferCountPerPage = 0; + + Map requestIdStatusMap; + if(exchange.getProperty(REQUEST_ID_STATUS_MAP)!=null){ + requestIdStatusMap = (Map) exchange.getProperty(REQUEST_ID_STATUS_MAP); + } + else{ + requestIdStatusMap = new HashMap<>(); + } + + for(Transfer transfer : transfers){ + TransferStatus transferStatus = transfer.getStatus(); + requestIdStatusMap.put(transfer.getTransactionId(), transferStatus.toString()); + + if(TransferStatus.COMPLETED.equals(transferStatus)){ + completedTransferCountPerPage++; + } + else if(TransferStatus.FAILED.equals(transferStatus)){ + failedTransferCountPerPage++; + } + else if(TransferStatus.IN_PROGRESS.equals(transferStatus)){ + ongoingTransferCountPerPage++; + } + transferCountPerPage++; + } + + currentTransferCount += transferCountPerPage; + completedTransferCount += completedTransferCountPerPage; + failedTransferCount += failedTransferCountPerPage; + ongoingTransferCount += ongoingTransferCountPerPage; + + exchange.setProperty(CURRENT_TRANSACTION_COUNT, currentTransferCount); + exchange.setProperty(COMPLETED_TRANSACTION_COUNT, completedTransferCount); + exchange.setProperty(FAILED_TRANSACTION_COUNT, failedTransferCount); + exchange.setProperty(ONGOING_TRANSACTION_COUNT, ongoingTransferCount); + exchange.setProperty(REQUEST_ID_STATUS_MAP, requestIdStatusMap); + + if(currentTransferCount<=totalTransferCount){ + exchange.setProperty(BATCH_DETAIL_SUCCESS, true); + } + else { + exchange.setProperty(BATCH_DETAIL_SUCCESS, false); + } + + }) + .otherwise() + .log(LoggingLevel.ERROR, "Batch detail request unsuccessful") + .process(exchange -> { + exchange.setProperty(BATCH_DETAIL_SUCCESS, false); + exchange.setProperty(ERROR_DESCRIPTION, exchange.getIn().getBody(String.class)); + exchange.setProperty(ERROR_CODE, exchange.getIn().getHeader(Exchange.HTTP_RESPONSE_CODE)); + }); + + from("direct:upload-result-file") + .id("direct:upload-result-file") + .log("Starting route direct:upload-result-file") + .choice() + .when(exchange -> exchange.getProperty(BATCH_DETAIL_SUCCESS, Boolean.class)) + .to("direct:download-file") + .to("direct:get-transaction-array") + .process(exchange -> { + String serverFileName = exchange.getProperty(FILE_NAME, String.class); + String batchId = exchange.getProperty(BATCH_ID, String.class); + String resultFile = String.format("Result_%s", serverFileName); + List transactionList = exchange.getProperty(TRANSACTION_LIST, List.class); + Object property = exchange.getProperty(REQUEST_ID_STATUS_MAP); + Map requestIdStatusMap = (Map) property; + List transactionResultList = fetchTransactionResult(transactionList, requestIdStatusMap, requestIdStatusMap, batchId); + exchange.setProperty(RESULT_TRANSACTION_LIST, transactionResultList); + exchange.setProperty(RESULT_FILE, resultFile); + exchange.setProperty(LOCAL_FILE_PATH, exchange.getProperty(RESULT_FILE)); + exchange.setProperty(OVERRIDE_HEADER, constant(true)); + }) + .to("direct:update-result-file") + .to("direct:upload-file"); + } + + private List fetchTransactionResult(List transactionList, Object property, Map requestIdStatusMap, String batchId) { + List transactionResultList = new ArrayList<>(); + for (Transaction transaction : transactionList) { + TransactionResult transactionResult = Utils.mapToResultDTO(transaction); + transactionResult.setPaymentMode("CLOSEDLOOP"); + transactionResult.setBatchId(transaction.getBatchId()); + String status = requestIdStatusMap.get(transaction.getRequestId()); + transactionResult.setStatus(status); + transactionResultList.add(transactionResult); + } + return transactionResultList; + } +} diff --git a/ph-ee-connector-bulk/src/main/java/org/mifos/connector/phee/camel/routes/BatchSummaryRoute.java b/ph-ee-connector-bulk/src/main/java/org/mifos/connector/phee/camel/routes/BatchSummaryRoute.java new file mode 100644 index 000000000..a230989f8 --- /dev/null +++ b/ph-ee-connector-bulk/src/main/java/org/mifos/connector/phee/camel/routes/BatchSummaryRoute.java @@ -0,0 +1,119 @@ +package org.mifos.connector.phee.camel.routes; + +import org.apache.camel.Exchange; +import org.apache.camel.LoggingLevel; +import org.apache.camel.model.dataformat.JsonLibrary; +import org.mifos.connector.phee.config.MockPaymentSchemaConfig; +import org.mifos.connector.phee.schema.BatchDTO; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +import java.math.BigDecimal; + +import static org.mifos.connector.phee.zeebe.ZeebeVariables.BATCH_ID; +import static org.mifos.connector.phee.zeebe.ZeebeVariables.BATCH_SUMMARY_SUCCESS; +import static org.mifos.connector.phee.zeebe.ZeebeVariables.COMPLETED_AMOUNT; +import static org.mifos.connector.phee.zeebe.ZeebeVariables.COMPLETED_TRANSACTION; +import static org.mifos.connector.phee.zeebe.ZeebeVariables.COMPLETION_RATE; +import static org.mifos.connector.phee.zeebe.ZeebeVariables.ERROR_CODE; +import static org.mifos.connector.phee.zeebe.ZeebeVariables.ERROR_DESCRIPTION; +import static org.mifos.connector.phee.zeebe.ZeebeVariables.FAILED_AMOUNT; +import static org.mifos.connector.phee.zeebe.ZeebeVariables.FAILED_TRANSACTION; +import static org.mifos.connector.phee.zeebe.ZeebeVariables.ONGOING_AMOUNT; +import static org.mifos.connector.phee.zeebe.ZeebeVariables.ONGOING_TRANSACTION; +import static org.mifos.connector.phee.zeebe.ZeebeVariables.TOTAL_AMOUNT; +import static org.mifos.connector.phee.zeebe.ZeebeVariables.TOTAL_TRANSACTION; + + +@Component +public class BatchSummaryRoute extends BaseRouteBuilder { + + @Value("${config.completion-threshold-check.completion-threshold}") + private int completionThreshold; + + @Autowired + public MockPaymentSchemaConfig mockPaymentSchemaConfig; + + @Value("${tenant}") + public String tenant; + + @Override + public void configure() throws Exception { + + from(RouteId.BATCH_SUMMARY.getValue()) + .id(RouteId.BATCH_SUMMARY.getValue()) + .log("Starting route " + RouteId.BATCH_SUMMARY.name()) + .to("direct:batch-summary-api-call") + .to("direct:batch-summary-response-handler"); + + + getBaseExternalApiRequestRouteDefinition("batch-summary-api-call", HttpRequestMethod.GET) + .setHeader(Exchange.HTTP_METHOD, constant("GET")) + .setHeader(Exchange.HTTP_PATH, simple("/batches/${exchangeProperty." + BATCH_ID + "}/summary")) + .setHeader("Platform-TenantId", simple(tenant)) + .process(exchange -> { + logger.info(exchange.getIn().getHeaders().toString()); + }) + .toD("direct:callBatchSummaryEndpoint") // Use a direct endpoint to call the method + .log(LoggingLevel.INFO, "Batch summary API response: \n\n ${body}"); + +// Define a route to call the Spring method + from("direct:callBatchSummaryEndpoint") + .to(mockPaymentSchemaConfig.mockPaymentSchemaContactPoint+"/batches/${exchangeProperty." + BATCH_ID + "}/summary") + .log(LoggingLevel.INFO, "Batch summary API response: \n\n ${body}"); + + + from("direct:batch-summary-response-handler") + .id("direct:batch-summary-response-handler") + .log("Starting route direct:batch-summary-response-handler") + //.setBody(exchange -> exchange.getIn().getBody(String.class)) + .choice() + .when(header("CamelHttpResponseCode").isEqualTo("200")) + .log(LoggingLevel.INFO, "Batch summary request successful") + .unmarshal().json(JsonLibrary.Jackson, BatchDTO.class) + .process(exchange -> { + BatchDTO batchSummary = exchange.getIn().getBody(BatchDTO.class); + + long failedTransfersCount = batchSummary.getFailed(); + long ongoingTransfersCount = batchSummary.getOngoing(); + long totalTransfersCount = batchSummary.getTotal(); + long successfulTransfersCount = batchSummary.getSuccessful(); + BigDecimal failedAmount = batchSummary.getFailedAmount(); + BigDecimal pendingAmount = batchSummary.getPendingAmount(); + BigDecimal successfulAmount = batchSummary.getSuccessfulAmount(); + BigDecimal totalAmount = batchSummary.getTotalAmount(); + + long percentage = (long)(((double) + (batchSummary.getSuccessful() + batchSummary.getFailed())/batchSummary.getTotal()) *100); + + exchange.setProperty(COMPLETION_RATE, percentage); + exchange.setProperty(ONGOING_TRANSACTION, ongoingTransfersCount); + exchange.setProperty(FAILED_TRANSACTION, failedTransfersCount); + exchange.setProperty(COMPLETED_TRANSACTION, successfulTransfersCount); + exchange.setProperty(TOTAL_TRANSACTION, totalTransfersCount); + exchange.setProperty(ONGOING_AMOUNT, pendingAmount); + exchange.setProperty(FAILED_AMOUNT, failedAmount); + exchange.setProperty(COMPLETED_AMOUNT, successfulAmount); + exchange.setProperty(TOTAL_AMOUNT, totalAmount); + + if (percentage >= completionThreshold) { + exchange.setProperty(BATCH_SUMMARY_SUCCESS, true); + logger.info("Batch success threshold reached. Expected rate: {}, Actual Rate: {}", + completionThreshold, percentage); + } + else{ + exchange.setProperty(BATCH_SUMMARY_SUCCESS, false); + } + + }) + .otherwise() + .log(LoggingLevel.ERROR, "Batch summary request unsuccessful") + .process(exchange -> { + exchange.setProperty(BATCH_SUMMARY_SUCCESS, false); + exchange.setProperty(ERROR_DESCRIPTION, exchange.getIn().getBody(String.class)); + exchange.setProperty(ERROR_CODE, exchange.getIn().getHeader(Exchange.HTTP_RESPONSE_CODE)); + }); + + } +} \ No newline at end of file diff --git a/ph-ee-connector-bulk/src/main/java/org/mifos/connector/phee/camel/routes/FileProcessingRoute.java b/ph-ee-connector-bulk/src/main/java/org/mifos/connector/phee/camel/routes/FileProcessingRoute.java new file mode 100644 index 000000000..d8313bd39 --- /dev/null +++ b/ph-ee-connector-bulk/src/main/java/org/mifos/connector/phee/camel/routes/FileProcessingRoute.java @@ -0,0 +1,105 @@ +package org.mifos.connector.phee.camel.routes; + +import com.fasterxml.jackson.databind.MappingIterator; +import com.fasterxml.jackson.databind.SequenceWriter; +import com.fasterxml.jackson.dataformat.csv.CsvMapper; +import com.fasterxml.jackson.dataformat.csv.CsvSchema; +import org.mifos.connector.phee.schema.Transaction; +import org.mifos.connector.phee.schema.TransactionResult; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.io.File; +import java.io.FileReader; +import java.io.IOException; +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.List; + +import static org.mifos.connector.phee.zeebe.ZeebeVariables.FILE_NAME; + +@Component +public class FileProcessingRoute extends BaseRouteBuilder { + + private static final String TRANSACTION_LIST = "transactionList"; + private static final String TRANSACTION_LIST_LENGTH = "transactionListLength"; + private static final String TOTAL_AMOUNT = "totalAmount"; + private static final String ONGOING_AMOUNT = "ongoingAmount"; + private static final String FAILED_AMOUNT = "failedAmount"; + private static final String COMPLETED_AMOUNT = "completedAmount"; + private static final String LOCAL_FILE_PATH = "localFilePath"; + private static final String RESULT_TRANSACTION_LIST = "resultTransactionList"; + private static final String OVERRIDE_HEADER = "overrideHeader"; + + @Autowired + private CsvMapper csvMapper; + + @Override + public void configure() throws Exception { + + /** + * Parse the [Transaction] array from the csv file + * exchangeInput: [LOCAL_FILE_PATH] the absolute path to the csv file + * exchangeOutput: [TRANSACTION_LIST] containing the list of [Transaction] + */ + from("direct:get-transaction-array") + .id("direct:get-transaction-array") + .log("Starting route direct:get-transaction-array") + .process(exchange -> { + BigDecimal totalAmount = BigDecimal.ZERO; + BigDecimal failedAmount = BigDecimal.ZERO; + BigDecimal completedAmount = BigDecimal.ZERO; + String filename = exchange.getProperty(FILE_NAME, String.class); + CsvSchema schema = CsvSchema.emptySchema().withHeader(); + FileReader reader = new FileReader(filename); + MappingIterator readValues = csvMapper.readerWithSchemaFor(Transaction.class).with(schema).readValues(reader); + List transactionList = new ArrayList<>(); + while (readValues.hasNext()) { + Transaction current = readValues.next(); + transactionList.add(current); + totalAmount = totalAmount.add(new BigDecimal(current.getAmount())); + } + reader.close(); + exchange.setProperty(TRANSACTION_LIST, transactionList); + exchange.setProperty(TRANSACTION_LIST_LENGTH, transactionList.size()); + exchange.setProperty(TOTAL_AMOUNT, totalAmount); + exchange.setProperty(ONGOING_AMOUNT, totalAmount); // initially ongoing amount is same as total amount + exchange.setProperty(FAILED_AMOUNT, failedAmount); + exchange.setProperty(COMPLETED_AMOUNT, completedAmount); + }); + + /** + * updates the data in local file + * exchangeInput: + * [LOCAL_FILE_PATH] the absolute path to the csv file + * [RESULT_TRANSACTION_LIST] containing the list of [Transaction] + * [OVERRIDE_HEADER] if set to true will override the header or else use the existing once in csv file + */ + from("direct:update-result-file") + .id("direct:update-result-file") + .log("Starting route direct:update-result-file") + .process(exchange -> { + String filePath = exchange.getProperty(LOCAL_FILE_PATH, String.class); + List transactionList = exchange.getProperty(RESULT_TRANSACTION_LIST, List.class); + csvWriter(transactionList, TransactionResult.class, csvMapper, true, filePath); + }) + .log("Update complete"); + + } + + private void csvWriter(List data, Class tClass, CsvMapper csvMapper, + boolean overrideHeader, String filepath) throws IOException { + CsvSchema csvSchema = csvMapper.schemaFor(tClass); + if (overrideHeader) { + csvSchema = csvSchema.withHeader(); + } else { + csvSchema = csvSchema.withoutHeader(); + } + + File file = new File(filepath); + SequenceWriter writer = csvMapper.writerWithSchemaFor(tClass).with(csvSchema).writeValues(file); + for (T object: data) { + writer.write(object); + } + } +} diff --git a/ph-ee-connector-bulk/src/main/java/org/mifos/connector/phee/camel/routes/FileRoute.java b/ph-ee-connector-bulk/src/main/java/org/mifos/connector/phee/camel/routes/FileRoute.java new file mode 100644 index 000000000..ca2d108c4 --- /dev/null +++ b/ph-ee-connector-bulk/src/main/java/org/mifos/connector/phee/camel/routes/FileRoute.java @@ -0,0 +1,75 @@ +package org.mifos.connector.phee.camel.routes; + +import org.mifos.connector.phee.file.FileTransferService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +import java.io.File; +import java.io.FileOutputStream; + +import static org.mifos.connector.phee.zeebe.ZeebeVariables.FILE_NAME; + +@Component +public class FileRoute extends BaseRouteBuilder { + + private static final String LOCAL_FILE_PATH = "localFilePath"; + private static final String SERVER_FILE_NAME = "serverFileName"; + @Autowired + @Qualifier("awsStorage") + private FileTransferService fileTransferService; + + @Value("${application.bucket-name}") + private String bucketName; + + @Override + public void configure() throws Exception { + + from("direct:download-file") + .id("direct:download-file") + .log("Starting route: direct:download-file") + .process(exchange -> { + String filename = exchange.getProperty(FILE_NAME, String.class); + + byte[] csvFile = fileTransferService.downloadFile(filename, bucketName); + File file = new File(filename); + try (FileOutputStream fos = new FileOutputStream(file)) { + fos.write(csvFile); + } + exchange.setProperty(LOCAL_FILE_PATH, file.getAbsolutePath()); + logger.info("File downloaded"); + }); + + + /** + * Uploads the file to cloud and returns the file name in cloud + * Input the local file path through exchange variable: [LOCAL_FILE_PATH] + * Output the server file name through exchange variable: [SERVER_FILE_NAME] + */ + from("direct:upload-file") + .id("direct:upload-file") + .log("Starting route: direct:upload-file") + .process(exchange -> { + String filepath = exchange.getProperty(LOCAL_FILE_PATH, String.class); + String serverFileName = fileTransferService.uploadFile(new File(filepath), bucketName); + exchange.setProperty(SERVER_FILE_NAME, serverFileName); + logger.info("Uploaded file: {}", serverFileName); + }) + .to("direct:delete-local-file"); + + /** + * Deletes file at LOCAL_FILE_PATH + * Input the local file path through exchange variable: [LOCAL_FILE_PATH] + */ + from("direct:delete-local-file") + .id("direct:delete-local-file") + .log("Deleting local file") + .process(exchange -> { + String filepath = exchange.getProperty(LOCAL_FILE_PATH, String.class); + File file = new File(filepath); + boolean success = file.delete(); + logger.info("Delete file: {}, isSuccess: {}", filepath, success); + }); + } +} diff --git a/ph-ee-connector-bulk/src/main/java/org/mifos/connector/phee/camel/routes/RouteId.java b/ph-ee-connector-bulk/src/main/java/org/mifos/connector/phee/camel/routes/RouteId.java new file mode 100644 index 000000000..7da7d2863 --- /dev/null +++ b/ph-ee-connector-bulk/src/main/java/org/mifos/connector/phee/camel/routes/RouteId.java @@ -0,0 +1,23 @@ +package org.mifos.connector.phee.camel.routes; + +public enum RouteId { + INIT_BATCH_TRANSFER("direct:init-batch-transfer"), + + BATCH_SUMMARY("direct:batch-summary"), + + BATCH_DETAIL("direct:batch-detail"), + + UPLOAD_RESULT_FILE("direct:upload-result-file"); + + + private final String value; + + + private RouteId(String value) { + this.value = value; + } + + public String getValue() { + return value; + } +} diff --git a/ph-ee-connector-bulk/src/main/java/org/mifos/connector/phee/config/MockPaymentSchemaConfig.java b/ph-ee-connector-bulk/src/main/java/org/mifos/connector/phee/config/MockPaymentSchemaConfig.java new file mode 100644 index 000000000..d8c010bf0 --- /dev/null +++ b/ph-ee-connector-bulk/src/main/java/org/mifos/connector/phee/config/MockPaymentSchemaConfig.java @@ -0,0 +1,30 @@ +package org.mifos.connector.phee.config; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +import javax.annotation.PostConstruct; + +@Component +public class MockPaymentSchemaConfig { + + @Value("${mock-payment-schema.contactpoint}") + public String mockPaymentSchemaContactPoint; + + @Value("${mock-payment-schema.endpoints.batch-summary}") + public String mockBatchSummaryEndpoint; + + @Value("${mock-payment-schema.endpoints.batch-detail}") + public String mockBatchDetailEndpoint; + + public String batchSummaryUrl; + + public String batchDetailUrl; + + + @PostConstruct + private void setup() { + batchSummaryUrl = mockPaymentSchemaContactPoint + mockBatchSummaryEndpoint; + batchDetailUrl = mockPaymentSchemaContactPoint + mockBatchDetailEndpoint; + } +} diff --git a/ph-ee-connector-bulk/src/main/java/org/mifos/connector/phee/config/OperationsAppConfig.java b/ph-ee-connector-bulk/src/main/java/org/mifos/connector/phee/config/OperationsAppConfig.java new file mode 100644 index 000000000..64ab21d1b --- /dev/null +++ b/ph-ee-connector-bulk/src/main/java/org/mifos/connector/phee/config/OperationsAppConfig.java @@ -0,0 +1,50 @@ +package org.mifos.connector.phee.config; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +import javax.annotation.PostConstruct; + +@Component +public class OperationsAppConfig { + + @Value("${operations-app.contactpoint}") + public String operationAppContactPoint; + +// @Value("${bulk-processor.contactpoint}") +// public String bulkProcessorContactPoint; + + @Value("${bulk-processor.endpoints.batch-transaction}") + public String batchTransactionEndpoint; + + @Value("${operations-app.endpoints.batch-summary}") + public String batchSummaryEndpoint; + + @Value("${operations-app.endpoints.batch-detail") + public String batchDetailEndpoint; + + @Value("${operations-app.endpoints.auth}") + public String authEndpoint; + + @Value("${operations-app.username}") + public String username; + + @Value("${operations-app.password}") + public String password; + + public String batchTransactionUrl; + + public String batchSummaryUrl; + + public String batchDetailUrl; + + public String authUrl; + + @PostConstruct + private void setup() { + batchTransactionUrl = operationAppContactPoint + batchTransactionEndpoint; + batchSummaryUrl = operationAppContactPoint + batchSummaryEndpoint; + batchDetailUrl = operationAppContactPoint + batchDetailEndpoint; + authUrl = operationAppContactPoint + authEndpoint; + } +} diff --git a/ph-ee-connector-bulk/src/main/java/org/mifos/connector/phee/config/PaymentModeConfiguration.java b/ph-ee-connector-bulk/src/main/java/org/mifos/connector/phee/config/PaymentModeConfiguration.java new file mode 100644 index 000000000..a40f76a77 --- /dev/null +++ b/ph-ee-connector-bulk/src/main/java/org/mifos/connector/phee/config/PaymentModeConfiguration.java @@ -0,0 +1,26 @@ +package org.mifos.connector.phee.config; + +import lombok.Getter; +import lombok.Setter; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Configuration; + +import java.util.ArrayList; +import java.util.List; + +@Configuration +@ConfigurationProperties(prefix = "payment-mode") +@Setter +@Getter +public class PaymentModeConfiguration { + + private List mappings = new ArrayList<>(); + + public PaymentModeMapping getByMode(String paymentMode) { + return getMappings().stream() + .filter(p -> p.getId().equalsIgnoreCase(paymentMode)) + .findFirst() + .orElse(null); + } + +} diff --git a/ph-ee-connector-bulk/src/main/java/org/mifos/connector/phee/config/PaymentModeMapping.java b/ph-ee-connector-bulk/src/main/java/org/mifos/connector/phee/config/PaymentModeMapping.java new file mode 100644 index 000000000..8a40d9b6b --- /dev/null +++ b/ph-ee-connector-bulk/src/main/java/org/mifos/connector/phee/config/PaymentModeMapping.java @@ -0,0 +1,12 @@ +package org.mifos.connector.phee.config; + +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public class PaymentModeMapping { + + private String id, endpoint; + private PaymentModeType type; +} diff --git a/ph-ee-connector-bulk/src/main/java/org/mifos/connector/phee/config/PaymentModeType.java b/ph-ee-connector-bulk/src/main/java/org/mifos/connector/phee/config/PaymentModeType.java new file mode 100644 index 000000000..f5bf8329d --- /dev/null +++ b/ph-ee-connector-bulk/src/main/java/org/mifos/connector/phee/config/PaymentModeType.java @@ -0,0 +1,17 @@ +package org.mifos.connector.phee.config; + +import lombok.Getter; + +@Getter +public enum PaymentModeType { + + PAYMENT("PAYMENT"), + BULK("BULK"); + + private String modeType; + + PaymentModeType(String modeType) { + this.modeType = modeType; + } + +} diff --git a/ph-ee-connector-bulk/src/main/java/org/mifos/connector/phee/data/Bill.java b/ph-ee-connector-bulk/src/main/java/org/mifos/connector/phee/data/Bill.java new file mode 100644 index 000000000..0ea96902b --- /dev/null +++ b/ph-ee-connector-bulk/src/main/java/org/mifos/connector/phee/data/Bill.java @@ -0,0 +1,27 @@ +package org.mifos.connector.phee.data; + +public class Bill { + public String getBillerName() { + return billerName; + } + + public void setBillerName(String billerName) { + this.billerName = billerName; + } + + public double getAmount() { + return amount; + } + + public void setAmount(double amount) { + this.amount = amount; + } + + public Bill(String billerName, double amount) { + this.billerName = billerName; + this.amount = amount; + } + + private String billerName; + private double amount; +} diff --git a/ph-ee-connector-bulk/src/main/java/org/mifos/connector/phee/data/BillDetails.java b/ph-ee-connector-bulk/src/main/java/org/mifos/connector/phee/data/BillDetails.java new file mode 100644 index 000000000..6b73e9f9c --- /dev/null +++ b/ph-ee-connector-bulk/src/main/java/org/mifos/connector/phee/data/BillDetails.java @@ -0,0 +1,16 @@ +package org.mifos.connector.phee.data; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +public class BillDetails { + private String billId; + private String billerName; + private Integer amount; +} diff --git a/ph-ee-connector-bulk/src/main/java/org/mifos/connector/phee/data/BillInquiryResponseDTO.java b/ph-ee-connector-bulk/src/main/java/org/mifos/connector/phee/data/BillInquiryResponseDTO.java new file mode 100644 index 000000000..5bd881017 --- /dev/null +++ b/ph-ee-connector-bulk/src/main/java/org/mifos/connector/phee/data/BillInquiryResponseDTO.java @@ -0,0 +1,17 @@ +package org.mifos.connector.phee.data; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +import java.io.Serializable; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +public class BillInquiryResponseDTO implements Serializable { + private String transactionId; + //private List paymentModalityList; +} diff --git a/ph-ee-connector-bulk/src/main/java/org/mifos/connector/phee/data/BillPaymentsReqDTO.java b/ph-ee-connector-bulk/src/main/java/org/mifos/connector/phee/data/BillPaymentsReqDTO.java new file mode 100644 index 000000000..5a9bd92bd --- /dev/null +++ b/ph-ee-connector-bulk/src/main/java/org/mifos/connector/phee/data/BillPaymentsReqDTO.java @@ -0,0 +1,55 @@ +package org.mifos.connector.phee.data; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +import java.io.Serializable; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +public class BillPaymentsReqDTO implements Serializable { + + @Override + public String toString() { + return "BillPaymentsReqDTO{" + + "billInquiryRequestId='" + billInquiryRequestId + '\'' + + ", billId='" + billId + '\'' + + ", paymentReferenceID='" + paymentReferenceID + '\'' + + '}'; + } + + private String billInquiryRequestId; + private String billId; + private String paymentReferenceID; + + public String getBillInquiryRequestId() { + return billInquiryRequestId; + } + + public void setBillInquiryRequestId(String billInquiryRequestId) { + this.billInquiryRequestId = billInquiryRequestId; + } + + public String getBillId() { + return billId; + } + + public void setBillId(String billId) { + this.billId = billId; + } + + public String getPaymentReferenceID() { + return paymentReferenceID; + } + + public void setPaymentReferenceID(String paymentReferenceID) { + this.paymentReferenceID = paymentReferenceID; + } + + + +} diff --git a/ph-ee-connector-bulk/src/main/java/org/mifos/connector/phee/data/BillRTPReqDTO.java b/ph-ee-connector-bulk/src/main/java/org/mifos/connector/phee/data/BillRTPReqDTO.java new file mode 100644 index 000000000..0eddf6195 --- /dev/null +++ b/ph-ee-connector-bulk/src/main/java/org/mifos/connector/phee/data/BillRTPReqDTO.java @@ -0,0 +1,57 @@ +package org.mifos.connector.phee.data; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +import java.io.Serializable; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +public class BillRTPReqDTO implements Serializable { + + + private String clientCorrelationId; + private String billId; + private String requestType; + private Bill bill; + + public String getClientCorrelationId() { + return clientCorrelationId; + } + + public void setClientCorrelationId(String clientCorrelationId) { + this.clientCorrelationId = clientCorrelationId; + } + + public String getBillId() { + return billId; + } + + public void setBillId(String billId) { + this.billId = billId; + } + + public String getRequestType() { + return requestType; + } + + public void setRequestType(String requestType) { + this.requestType = requestType; + } + + public Bill getBill() { + return bill; + } + + public void setBill(Bill bill) { + this.bill = bill; + } + + + + +} diff --git a/ph-ee-connector-bulk/src/main/java/org/mifos/connector/phee/data/PayerRTPResponse.java b/ph-ee-connector-bulk/src/main/java/org/mifos/connector/phee/data/PayerRTPResponse.java new file mode 100644 index 000000000..b9a943d47 --- /dev/null +++ b/ph-ee-connector-bulk/src/main/java/org/mifos/connector/phee/data/PayerRTPResponse.java @@ -0,0 +1,18 @@ +package org.mifos.connector.phee.data; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +public class PayerRTPResponse { + + private String txnId; + private String billId; + private String rtpStatus; + private String rejectReason; +} diff --git a/ph-ee-connector-bulk/src/main/java/org/mifos/connector/phee/data/PayerRequestDTO.java b/ph-ee-connector-bulk/src/main/java/org/mifos/connector/phee/data/PayerRequestDTO.java new file mode 100644 index 000000000..4adf1c380 --- /dev/null +++ b/ph-ee-connector-bulk/src/main/java/org/mifos/connector/phee/data/PayerRequestDTO.java @@ -0,0 +1,17 @@ +package org.mifos.connector.phee.data; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +public class PayerRequestDTO { + private String requestId; + private String transactionId; + private Integer rtpId; + private BillDetails billDetails; +} diff --git a/ph-ee-connector-bulk/src/main/java/org/mifos/connector/phee/data/ResponseDTO.java b/ph-ee-connector-bulk/src/main/java/org/mifos/connector/phee/data/ResponseDTO.java new file mode 100644 index 000000000..5630e0576 --- /dev/null +++ b/ph-ee-connector-bulk/src/main/java/org/mifos/connector/phee/data/ResponseDTO.java @@ -0,0 +1,17 @@ +package org.mifos.connector.phee.data; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +public class ResponseDTO { + private String responseCode; + private String responseDescription; + private String requestID; + +} diff --git a/ph-ee-connector-bulk/src/main/java/org/mifos/connector/phee/file/AwsFileTransferImpl.java b/ph-ee-connector-bulk/src/main/java/org/mifos/connector/phee/file/AwsFileTransferImpl.java new file mode 100644 index 000000000..e0817a1ca --- /dev/null +++ b/ph-ee-connector-bulk/src/main/java/org/mifos/connector/phee/file/AwsFileTransferImpl.java @@ -0,0 +1,94 @@ +package org.mifos.connector.phee.file; + +import com.amazonaws.services.s3.AmazonS3; +import com.amazonaws.services.s3.model.PutObjectRequest; +import com.amazonaws.services.s3.model.S3Object; +import com.amazonaws.services.s3.model.S3ObjectInputStream; +import com.amazonaws.util.IOUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.stereotype.Service; +import org.springframework.web.multipart.MultipartFile; + +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; + +@Service +@Qualifier("awsStorage") +public class AwsFileTransferImpl implements FileTransferService { + private Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Autowired + private AmazonS3 s3Client; + + @Override + public String uploadFile(MultipartFile file, String bucketName) { + + File fileObj = convertMultiPartFileToFile(file); + return uploadFile(fileObj, bucketName); + } + + @Override + public String uploadFile(File file, String bucketName) { + String fileName = file.getName(); + s3Client.putObject(new PutObjectRequest(bucketName, fileName, file)); + file.delete(); + + return fileName; + } + + @Override + public byte[] downloadFile(String fileName, String bucketName) { + S3Object s3Object = s3Client.getObject(bucketName, fileName); + S3ObjectInputStream inputStream = s3Object.getObjectContent(); + try { + byte[] content = IOUtils.toByteArray(inputStream); + return content; + } catch (IOException e) { + e.printStackTrace(); + } + return null; + } + + @Override + public void deleteFile(String fileName, String bucketName) { + s3Client.deleteObject(bucketName, fileName); + } + + @Override + public byte[] downloadFileAsStream(String fileName, String bucketName){ + S3Object s3Object = s3Client.getObject(bucketName, fileName); + S3ObjectInputStream inputStream = s3Object.getObjectContent(); + + try{ + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + int numberOfBytesToWrite; + byte[] data = new byte[1024]; + + while ((numberOfBytesToWrite = inputStream.read(data, 0, data.length)) != -1){ + outputStream.write(data, 0, numberOfBytesToWrite); + } + inputStream.close(); + outputStream.close(); + return outputStream.toByteArray(); + } + catch (IOException e) { + e.printStackTrace(); + } + return new byte[0]; + } + + private File convertMultiPartFileToFile(MultipartFile file) { + File convertedFile = new File(file.getOriginalFilename()); + try (FileOutputStream fos = new FileOutputStream(convertedFile)) { + fos.write(file.getBytes()); + } catch (IOException e) { + logger.error("Error converting multipartFile to file", e); + } + return convertedFile; + } +} diff --git a/ph-ee-connector-bulk/src/main/java/org/mifos/connector/phee/file/AzureFileTransferImpl.java b/ph-ee-connector-bulk/src/main/java/org/mifos/connector/phee/file/AzureFileTransferImpl.java new file mode 100644 index 000000000..0b371888d --- /dev/null +++ b/ph-ee-connector-bulk/src/main/java/org/mifos/connector/phee/file/AzureFileTransferImpl.java @@ -0,0 +1,78 @@ +package org.mifos.connector.phee.file; + +import com.azure.storage.blob.BlobClientBuilder; +import com.azure.storage.blob.models.BlobProperties; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.stereotype.Service; +import org.springframework.web.multipart.MultipartFile; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Paths; + +@Service +@Qualifier("azureStorage") +@ConditionalOnProperty( + value="cloud.azure.enabled", + havingValue = "true") +public class AzureFileTransferImpl implements FileTransferService { + private Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Autowired + BlobClientBuilder client; + + @Override + public String uploadFile(MultipartFile file, String bucketName) { + + try { + String fileName = System.currentTimeMillis() + "_" + file.getOriginalFilename(); + client.containerName(bucketName).blobName(fileName).buildClient().upload(file.getInputStream(), file.getSize()); + return fileName; + } catch (IOException e) { + logger.error("Error uploading file to Azure", e); + } + + return null; + } + + @Override + public String uploadFile(File file, String bucketName) { + try { + String fileName = System.currentTimeMillis() + "_" + file.getName(); + client.containerName(bucketName).blobName(fileName).buildClient().upload(Files.newInputStream(file.toPath()), file.length()); + return fileName; + } catch (IOException e) { + logger.error("Error uploading file to Azure", e); + } + return null; + } + + @Override + public byte[] downloadFile(String fileName, String bucketName) { + try { + File temp = new File("/temp/"+fileName); + BlobProperties properties = client.containerName(bucketName).blobName(fileName).buildClient().downloadToFile(temp.getPath()); + byte[] content = Files.readAllBytes(Paths.get(temp.getPath())); + temp.delete(); + return content; + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + + @Override + public void deleteFile(String fileName, String bucketName) { + client.containerName(bucketName).blobName(fileName).buildClient().delete(); + } + + @Override + public byte[] downloadFileAsStream(String fileName, String bucketName) { + return new byte[0]; + } +} diff --git a/ph-ee-connector-bulk/src/main/java/org/mifos/connector/phee/file/FileTransferService.java b/ph-ee-connector-bulk/src/main/java/org/mifos/connector/phee/file/FileTransferService.java new file mode 100644 index 000000000..21fc7cdf5 --- /dev/null +++ b/ph-ee-connector-bulk/src/main/java/org/mifos/connector/phee/file/FileTransferService.java @@ -0,0 +1,20 @@ +package org.mifos.connector.phee.file; + +import org.springframework.web.multipart.MultipartFile; + +import java.io.File; + +// TODO: Duplicate file (Also exists in ) +public interface FileTransferService { + + String uploadFile(MultipartFile file, String bucketName); + + String uploadFile(File file, String bucketName); + + byte[] downloadFile(String fileName, String bucketName); + + void deleteFile(String fileName, String bucketName); + + byte[] downloadFileAsStream(String fileName, String bucketName); + +} diff --git a/ph-ee-connector-bulk/src/main/java/org/mifos/connector/phee/file/config/AwsStorageConfig.java b/ph-ee-connector-bulk/src/main/java/org/mifos/connector/phee/file/config/AwsStorageConfig.java new file mode 100644 index 000000000..490a2cad6 --- /dev/null +++ b/ph-ee-connector-bulk/src/main/java/org/mifos/connector/phee/file/config/AwsStorageConfig.java @@ -0,0 +1,40 @@ +package org.mifos.connector.phee.file.config; + +import com.amazonaws.auth.AWSCredentials; +import com.amazonaws.auth.AWSStaticCredentialsProvider; +import com.amazonaws.auth.BasicAWSCredentials; +import com.amazonaws.client.builder.AwsClientBuilder; +import com.amazonaws.services.s3.AmazonS3; +import com.amazonaws.services.s3.AmazonS3ClientBuilder; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +// TODO: Duplicate file (Also exists in ) +@Configuration +public class AwsStorageConfig { + + @Value("${cloud.aws.credentials.access-key}") + private String accessKey; + + @Value("${cloud.aws.credentials.secret-key}") + private String accessSecret; + + @Value("${cloud.aws.region.static}") + private String region; + + @Value("${cloud.aws.s3BaseUrl}") + private String endpoint; + + @Bean + @ConditionalOnProperty(value = "cloud.aws.enabled", havingValue = "true") + public AmazonS3 s3Client() { + AWSCredentials credentials = new BasicAWSCredentials(accessKey, accessSecret); + return AmazonS3ClientBuilder.standard().withCredentials(new AWSStaticCredentialsProvider(credentials)) + .withPathStyleAccessEnabled(true).withEndpointConfiguration(new AwsClientBuilder.EndpointConfiguration(endpoint, region)) + .build(); + + } + +} diff --git a/ph-ee-connector-bulk/src/main/java/org/mifos/connector/phee/schema/BatchDTO.java b/ph-ee-connector-bulk/src/main/java/org/mifos/connector/phee/schema/BatchDTO.java new file mode 100644 index 000000000..65dfc9304 --- /dev/null +++ b/ph-ee-connector-bulk/src/main/java/org/mifos/connector/phee/schema/BatchDTO.java @@ -0,0 +1,53 @@ +package org.mifos.connector.phee.schema; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +import java.math.BigDecimal; + +// TODO: Duplicate file (Also exists in ) +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +public class BatchDTO { + + + private String batchId; + + private String requestId; + + private Long total; + + private Long ongoing; + + private Long failed; + + private Long successful; + + private BigDecimal totalAmount; + + private BigDecimal successfulAmount; + + private BigDecimal pendingAmount; + + private BigDecimal failedAmount; + + private String file; + + private String notes; + + private String createdAt; + + private String status; + + private String modes; + + private String purpose; + + private String failPercentage; + + private String successPercentage; +} \ No newline at end of file diff --git a/ph-ee-connector-bulk/src/main/java/org/mifos/connector/phee/schema/BatchDetailResponse.java b/ph-ee-connector-bulk/src/main/java/org/mifos/connector/phee/schema/BatchDetailResponse.java new file mode 100644 index 000000000..0e821edc7 --- /dev/null +++ b/ph-ee-connector-bulk/src/main/java/org/mifos/connector/phee/schema/BatchDetailResponse.java @@ -0,0 +1,38 @@ +package org.mifos.connector.phee.schema; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +import java.util.List; + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +public class BatchDetailResponse { + + private List content; + + private PageableDTO pageable; + + private Long totalPages; + + private Long totalElements; + + private boolean last; + + private boolean first; + + private SortDTO sort; + + private Long numberOfElements; + + private Long size; + + private Long number; + + private boolean empty; + +} diff --git a/ph-ee-connector-bulk/src/main/java/org/mifos/connector/phee/schema/CsvSchema.java b/ph-ee-connector-bulk/src/main/java/org/mifos/connector/phee/schema/CsvSchema.java new file mode 100644 index 000000000..99576e29e --- /dev/null +++ b/ph-ee-connector-bulk/src/main/java/org/mifos/connector/phee/schema/CsvSchema.java @@ -0,0 +1,10 @@ +package org.mifos.connector.phee.schema; + +// TODO: Duplicate file (Also exists in ) +public interface CsvSchema { + + String getCsvString(); + + String getCsvHeader(); + +} diff --git a/ph-ee-connector-bulk/src/main/java/org/mifos/connector/phee/schema/PageableDTO.java b/ph-ee-connector-bulk/src/main/java/org/mifos/connector/phee/schema/PageableDTO.java new file mode 100644 index 000000000..34a6a9e99 --- /dev/null +++ b/ph-ee-connector-bulk/src/main/java/org/mifos/connector/phee/schema/PageableDTO.java @@ -0,0 +1,75 @@ +package org.mifos.connector.phee.schema; + +public class PageableDTO { + + private SortDTO sort; + + private Long pageSize; + + private Long pageNumber; + + private Long offset; + + private boolean unpaged; + + private boolean paged; + + public PageableDTO(){} + + public PageableDTO(SortDTO sort, Long pageSize, Long pageNumber, Long offset, boolean unpaged, boolean paged) { + this.sort = sort; + this.pageSize = pageSize; + this.pageNumber = pageNumber; + this.offset = offset; + this.unpaged = unpaged; + this.paged = paged; + } + + public SortDTO getSort() { + return sort; + } + + public void setSort(SortDTO sort) { + this.sort = sort; + } + + public Long getPageSize() { + return pageSize; + } + + public void setPageSize(Long pageSize) { + this.pageSize = pageSize; + } + + public Long getPageNumber() { + return pageNumber; + } + + public void setPageNumber(Long pageNumber) { + this.pageNumber = pageNumber; + } + + public Long getOffset() { + return offset; + } + + public void setOffset(Long offset) { + this.offset = offset; + } + + public boolean isUnpaged() { + return unpaged; + } + + public void setUnpaged(boolean unpaged) { + this.unpaged = unpaged; + } + + public boolean isPaged() { + return paged; + } + + public void setPaged(boolean paged) { + this.paged = paged; + } +} diff --git a/ph-ee-connector-bulk/src/main/java/org/mifos/connector/phee/schema/SortDTO.java b/ph-ee-connector-bulk/src/main/java/org/mifos/connector/phee/schema/SortDTO.java new file mode 100644 index 000000000..430ef966a --- /dev/null +++ b/ph-ee-connector-bulk/src/main/java/org/mifos/connector/phee/schema/SortDTO.java @@ -0,0 +1,42 @@ +package org.mifos.connector.phee.schema; + +public class SortDTO { + + private boolean sorted; + + private boolean unsorted; + + private boolean empty; + + public SortDTO(){} + + public SortDTO(boolean sorted, boolean unsorted, boolean empty) { + this.sorted = sorted; + this.unsorted = unsorted; + this.empty = empty; + } + + public boolean isSorted() { + return sorted; + } + + public void setSorted(boolean sorted) { + this.sorted = sorted; + } + + public boolean isUnsorted() { + return unsorted; + } + + public void setUnsorted(boolean unsorted) { + this.unsorted = unsorted; + } + + public boolean isEmpty() { + return empty; + } + + public void setEmpty(boolean empty) { + this.empty = empty; + } +} diff --git a/ph-ee-connector-bulk/src/main/java/org/mifos/connector/phee/schema/Transaction.java b/ph-ee-connector-bulk/src/main/java/org/mifos/connector/phee/schema/Transaction.java new file mode 100644 index 000000000..2be6ab372 --- /dev/null +++ b/ph-ee-connector-bulk/src/main/java/org/mifos/connector/phee/schema/Transaction.java @@ -0,0 +1,84 @@ +package org.mifos.connector.phee.schema; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonPropertyOrder({ "id", "request_id", "payment_mode", "payer_identifier_type", "payer_identifier", "payee_identifier_type", "payee_identifier", "amount", "currency", "note", "program_shortcode", "cycle", "batch_id", "account_number" }) +public class Transaction implements CsvSchema { + + @JsonProperty("id") + private int id; + + @JsonProperty("request_id") + private String requestId; + + @JsonProperty("payment_mode") + private String paymentMode; + + @JsonProperty("account_number") + private String accountNumber; + + @JsonProperty("amount") + private String amount; + + @JsonProperty("currency") + private String currency; + + @JsonProperty("note") + private String note; + + @JsonProperty(value = "payer_identifier_type") + private String payerIdentifierType; + + @JsonProperty("payer_identifier") + private String payerIdentifier; + + @JsonProperty("payee_identifier_type") + private String payeeIdentifierType; + + @JsonProperty("payee_identifier") + private String payeeIdentifier; + + @JsonProperty("program_shortcode") + private String programShortCode; + + @JsonProperty("cycle") + private String cycle; + + @JsonProperty("batch_id") + private String batchId; + + @Override + public String toString() { + StringBuilder buffer = new StringBuilder("Transaction{"); + buffer.append("id=").append(id); + buffer.append(", request_id='").append(requestId); + buffer.append(", payment_mode='").append(paymentMode); + buffer.append(", account_number='").append(accountNumber); + buffer.append(", amount='").append(amount); + buffer.append(", currency='").append(currency); + buffer.append(", note='").append(note); + buffer.append(", batchId='").append(batchId); + buffer.append(", status='").append(id).append('}'); + return buffer.toString(); + } + + @JsonIgnore + @Override + public String getCsvString() { + return String.format("%s,%s,%s,%s,%s,%s,%s", id, requestId, paymentMode, accountNumber, amount, currency, note); + } + + @JsonIgnore + @Override + public String getCsvHeader() { + return "id,request_id,payment_mode,account_number,amount,currency,note,status"; + } +} diff --git a/ph-ee-connector-bulk/src/main/java/org/mifos/connector/phee/schema/TransactionResult.java b/ph-ee-connector-bulk/src/main/java/org/mifos/connector/phee/schema/TransactionResult.java new file mode 100644 index 000000000..5ba5a80af --- /dev/null +++ b/ph-ee-connector-bulk/src/main/java/org/mifos/connector/phee/schema/TransactionResult.java @@ -0,0 +1,42 @@ +package org.mifos.connector.phee.schema; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonPropertyOrder({ "id", "request_id", "payment_mode", "payer_identifier_type", "payer_identifier", + "payee_identifier_type", "payee_identifier", "amount", "currency", "note", "program_shortcode", "cycle", "batch_id", + "status", "error_code", "error_description"}) +public class TransactionResult extends Transaction { + + @JsonProperty("status") + private String status; + + @JsonProperty("error_code") + private String errorCode; + + @JsonProperty("error_description") + private String errorDescription; + + @JsonProperty("account_number") + @JsonIgnore + private String accountNumber; + + @JsonIgnore + @Override + public void setAccountNumber(String accountNumber) { + super.setAccountNumber(accountNumber); + } + + @JsonIgnore + @Override + public String getAccountNumber() { + return super.getAccountNumber(); + } +} diff --git a/ph-ee-connector-bulk/src/main/java/org/mifos/connector/phee/schema/Transfer.java b/ph-ee-connector-bulk/src/main/java/org/mifos/connector/phee/schema/Transfer.java new file mode 100644 index 000000000..8e5124e55 --- /dev/null +++ b/ph-ee-connector-bulk/src/main/java/org/mifos/connector/phee/schema/Transfer.java @@ -0,0 +1,300 @@ +package org.mifos.connector.phee.schema; + +import java.math.BigDecimal; +import java.util.Date; + +public class Transfer { + + private String id; + + private Long workflowInstanceKey; + + private String transactionId; + + private Date startedAt; + + private Date completedAt; + + private TransferStatus status; + + private String statusDetail; + + private String payeeDfspId; + + private String payeePartyId; + + private String payeePartyIdType; + + private BigDecimal payeeFee; + + private String payeeFeeCurrency; + + private String payeeQuoteCode; + + + private String payerDfspId; + + private String payerPartyId; + + private String payerPartyIdType; + + private BigDecimal payerFee; + + private String payerFeeCurrency; + + private String payerQuoteCode; + + private BigDecimal amount; + + private String currency; + + private String direction; + + private String errorInformation; + + private String batchId; + + private String clientCorrelationId; + + public Transfer() { + } + + public Transfer(Long workflowInstanceKey) { + this.workflowInstanceKey = workflowInstanceKey; + this.status = TransferStatus.IN_PROGRESS; + } + + public Transfer(String id, Long workflowInstanceKey, String transactionId, Date startedAt, Date completedAt, +// public Transfer(Long workflowInstanceKey, String transactionId, Date startedAt, Date completedAt, + TransferStatus status, String statusDetail, String payeeDfspId, String payeePartyId, + String payeePartyIdType, BigDecimal payeeFee, String payeeFeeCurrency, String payeeQuoteCode, + String payerDfspId, String payerPartyId, String payerPartyIdType, BigDecimal payerFee, + String payerFeeCurrency, String payerQuoteCode, BigDecimal amount, String currency, String direction, + String errorInformation, String batchId, String clientCorrelationId) { + this.id = id; + this.workflowInstanceKey = workflowInstanceKey; + this.transactionId = transactionId; + this.startedAt = startedAt; + this.completedAt = completedAt; + this.status = status; + this.statusDetail = statusDetail; + this.payeeDfspId = payeeDfspId; + this.payeePartyId = payeePartyId; + this.payeePartyIdType = payeePartyIdType; + this.payeeFee = payeeFee; + this.payeeFeeCurrency = payeeFeeCurrency; + this.payeeQuoteCode = payeeQuoteCode; + this.payerDfspId = payerDfspId; + this.payerPartyId = payerPartyId; + this.payerPartyIdType = payerPartyIdType; + this.payerFee = payerFee; + this.payerFeeCurrency = payerFeeCurrency; + this.payerQuoteCode = payerQuoteCode; + this.amount = amount; + this.currency = currency; + this.direction = direction; + this.errorInformation = errorInformation; + this.batchId = batchId; + this.clientCorrelationId = clientCorrelationId; + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public Date getCompletedAt() { + return completedAt; + } + + public void setCompletedAt(Date completedAt) { + this.completedAt = completedAt; + } + + public Date getStartedAt() { + return startedAt; + } + + public void setStartedAt(Date startedAt) { + this.startedAt = startedAt; + } + + public BigDecimal getPayeeFee() { + return payeeFee; + } + + public void setPayeeFee(BigDecimal payeeFee) { + this.payeeFee = payeeFee; + } + + public String getPayeeQuoteCode() { + return payeeQuoteCode; + } + + public void setPayeeQuoteCode(String payeeQuoteCode) { + this.payeeQuoteCode = payeeQuoteCode; + } + + public BigDecimal getPayerFee() { + return payerFee; + } + + public void setPayerFee(BigDecimal payerFee) { + this.payerFee = payerFee; + } + + public String getPayerQuoteCode() { + return payerQuoteCode; + } + + public void setPayerQuoteCode(String payerQuoteCode) { + this.payerQuoteCode = payerQuoteCode; + } + + public String getTransactionId() { + return transactionId; + } + + public void setTransactionId(String transactionId) { + this.transactionId = transactionId; + } + + public Long getWorkflowInstanceKey() { + return workflowInstanceKey; + } + + public void setWorkflowInstanceKey(Long paymentProcessId) { + this.workflowInstanceKey = paymentProcessId; + } + + public TransferStatus getStatus() { + return status; + } + + public void setStatus(TransferStatus status) { + this.status = status; + } + + public String getPayeePartyId() { + return payeePartyId; + } + + public void setPayeePartyId(String payeePartyId) { + this.payeePartyId = payeePartyId; + } + + public String getPayeePartyIdType() { + return payeePartyIdType; + } + + public void setPayeePartyIdType(String payeePartyType) { + this.payeePartyIdType = payeePartyType; + } + + public String getPayerPartyId() { + return payerPartyId; + } + + public void setPayerPartyId(String payerPartyId) { + this.payerPartyId = payerPartyId; + } + + public String getPayerPartyIdType() { + return payerPartyIdType; + } + + public void setPayerPartyIdType(String payerPartyType) { + this.payerPartyIdType = payerPartyType; + } + + public String getPayeeFeeCurrency() { + return payeeFeeCurrency; + } + + public void setPayeeFeeCurrency(String payeeFeeCurrency) { + this.payeeFeeCurrency = payeeFeeCurrency; + } + + public String getPayerFeeCurrency() { + return payerFeeCurrency; + } + + public void setPayerFeeCurrency(String payerFeeCurrency) { + this.payerFeeCurrency = payerFeeCurrency; + } + + public BigDecimal getAmount() { + return amount; + } + + public void setAmount(BigDecimal amount) { + this.amount = amount; + } + + public String getPayeeDfspId() { + return payeeDfspId; + } + + public void setPayeeDfspId(String payeeDfspId) { + this.payeeDfspId = payeeDfspId; + } + + public String getPayerDfspId() { + return payerDfspId; + } + + public void setPayerDfspId(String payerDfspId) { + this.payerDfspId = payerDfspId; + } + + public String getCurrency() { + return currency; + } + + public void setCurrency(String currency) { + this.currency = currency; + } + + public String getStatusDetail() { + return statusDetail; + } + + public void setStatusDetail(String statusDetail) { + this.statusDetail = statusDetail; + } + + public String getDirection() { + return direction; + } + + public void setDirection(String direction) { + this.direction = direction; + } + + public String getErrorInformation() { + return errorInformation; + } + + public void setErrorInformation(String errorInformation) { + this.errorInformation = errorInformation; + } + + public String getBatchId() { + return batchId; + } + + public void setBatchId(String batchId) { + this.batchId = batchId; + } + + public String getClientCorrelationId() { + return clientCorrelationId; + } + + public void setClientCorrelationId(String clientCorrelationId) { + this.clientCorrelationId = clientCorrelationId; + } +} diff --git a/ph-ee-connector-bulk/src/main/java/org/mifos/connector/phee/schema/TransferStatus.java b/ph-ee-connector-bulk/src/main/java/org/mifos/connector/phee/schema/TransferStatus.java new file mode 100644 index 000000000..abbae7b40 --- /dev/null +++ b/ph-ee-connector-bulk/src/main/java/org/mifos/connector/phee/schema/TransferStatus.java @@ -0,0 +1,8 @@ +package org.mifos.connector.phee.schema; + +public enum TransferStatus { + COMPLETED, + FAILED, + IN_PROGRESS, + UNKNOWN +} diff --git a/ph-ee-connector-bulk/src/main/java/org/mifos/connector/phee/service/BillRTPReqService.java b/ph-ee-connector-bulk/src/main/java/org/mifos/connector/phee/service/BillRTPReqService.java new file mode 100644 index 000000000..1e1d8d088 --- /dev/null +++ b/ph-ee-connector-bulk/src/main/java/org/mifos/connector/phee/service/BillRTPReqService.java @@ -0,0 +1,46 @@ +package org.mifos.connector.phee.service; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.json.JSONObject; +import org.mifos.connector.common.channel.dto.TransactionChannelRequestDTO; +import org.mifos.connector.phee.data.BillRTPReqDTO; +import org.mifos.connector.phee.data.PayerRTPResponse; +import org.mifos.connector.phee.data.PayerRequestDTO; +import org.mifos.connector.phee.data.ResponseDTO; +import org.mifos.connector.phee.zeebe.ZeebeProcessStarter; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Service; +import org.springframework.web.client.RestTemplate; + +import java.util.HashMap; +import java.util.Map; + +import static org.mifos.connector.phee.zeebe.ZeebeVariables.CLIENTCORRELATIONID; +import static org.mifos.connector.phee.zeebe.ZeebeVariables.TENANT_ID; + + +@Service +public class BillRTPReqService { + @Autowired + private ZeebeProcessStarter zeebeProcessStarter; + @Autowired + private ObjectMapper objectMapper; + + String transactionId; + + public String payerRtpReq(String tenantId, String correlationId, String callBackUrl, + String billerId, String requestBody) throws JsonProcessingException { + return transactionId; + } + + +} diff --git a/ph-ee-connector-bulk/src/main/java/org/mifos/connector/phee/utils/BillPayrEnum.java b/ph-ee-connector-bulk/src/main/java/org/mifos/connector/phee/utils/BillPayrEnum.java new file mode 100644 index 000000000..126fce309 --- /dev/null +++ b/ph-ee-connector-bulk/src/main/java/org/mifos/connector/phee/utils/BillPayrEnum.java @@ -0,0 +1,22 @@ +package org.mifos.connector.phee.utils; + +public enum BillPayrEnum { + SUCCESS_RESPONSE("00", "Request successfully received by Pay-BB"), FAILED_RESPONSE("01", "Request not acknowledged by Pay-BB"); + + private final String value; + private final String message; + + BillPayrEnum(String value, String message) { + this.value = value; + this.message = message; + } + + + public String getValue() { + return this.value; + } + + public String getMessage() { + return message; + } +} diff --git a/ph-ee-connector-bulk/src/main/java/org/mifos/connector/phee/utils/Utils.java b/ph-ee-connector-bulk/src/main/java/org/mifos/connector/phee/utils/Utils.java new file mode 100644 index 000000000..128d0d6b7 --- /dev/null +++ b/ph-ee-connector-bulk/src/main/java/org/mifos/connector/phee/utils/Utils.java @@ -0,0 +1,100 @@ +package org.mifos.connector.phee.utils; + +import org.mifos.connector.phee.schema.Transaction; +import org.mifos.connector.phee.schema.TransactionResult; +import org.mifos.connector.common.channel.dto.TransactionChannelRequestDTO; +import org.mifos.connector.common.gsma.dto.*; +import org.mifos.connector.common.mojaloop.dto.MoneyData; +import org.mifos.connector.common.mojaloop.dto.Party; +import org.mifos.connector.common.mojaloop.dto.PartyIdInfo; +import org.mifos.connector.common.mojaloop.type.IdentifierType; + +import java.io.*; + +// TODO: Duplicate file (Also exists in ) +public class Utils { + + public static String getTenantSpecificWorkflowId(String originalWorkflowName, String tenantName) { + return originalWorkflowName.replace("{dfspid}", tenantName); + } + + public static String getBulkConnectorBpmnName(String originalWorkflowName, + String paymentMode, String tenantName) { + return originalWorkflowName.replace("{MODE}", paymentMode.toLowerCase()).replace("{dfspid}", tenantName); + } + + public static String mergeCsvFile(String file1, String file2) { + try { + // create a writer for permFile + BufferedWriter out = new BufferedWriter(new FileWriter(file1, true)); + // create a reader for tmpFile + BufferedReader in = new BufferedReader(new FileReader(file2)); + String str; + boolean isFirstLine = true; + while ((str = in.readLine()) != null) { + if (isFirstLine) { + // used for skipping header writing + isFirstLine = false; + continue; + } + out.write(str+"\n"); + } + in.close(); + out.close(); + } catch (IOException e) { + e.printStackTrace(); + return null; + } + + return file1; + } + + public static String getAwsFileUrl(String baseUrl, String filename) { + return String.format("%s/%s", baseUrl, filename); + } + + /** + * takes initial timer in the ISO 8601 durations format + * for more info check + * https://docs.camunda.io/docs/0.26/reference/bpmn-workflows/timer-events/#time-duration + * + * @param initialTimer initial timer in the ISO 8601 durations format, ex: PT45S + * @return next timer value in the ISO 8601 durations format + */ + public static String getNextTimer(String initialTimer){ + String stringSecondsValue = initialTimer.split("T")[1].split("S")[0]; + int initialSeconds = Integer.parseInt(stringSecondsValue); + + int currentPower = (int) ( Math.log(initialSeconds) / Math.log(2) ); + int next = (int) Math.pow(2, ++currentPower); + + return String.format("PT%sS", next); + } + + public static String getZeebeTimerValue(int timer) { + return String.format("PT%sS", timer); + } + + public static TransactionResult mapToResultDTO(Transaction transaction) { + TransactionResult transactionResult = new TransactionResult(); + transactionResult.setId(transaction.getId()); + transactionResult.setRequestId(transaction.getRequestId()); + transactionResult.setPaymentMode(transaction.getPaymentMode()); + transactionResult.setPayerIdentifierType(transaction.getPayerIdentifierType()); + transactionResult.setPayerIdentifier(transaction.getPayerIdentifier()); + transactionResult.setAmount(transaction.getAmount()); + transactionResult.setCurrency(transaction.getCurrency()); + transactionResult.setNote(transaction.getNote()); + transactionResult.setBatchId(transaction.getBatchId()); + transactionResult.setPayeeIdentifierType(transaction.getPayeeIdentifierType()); + if (transaction.getAccountNumber() != null) { + transactionResult.setPayeeIdentifier(transaction.getAccountNumber()); + } else { + transactionResult.setPayeeIdentifier(transaction.getPayeeIdentifier()); + } + transactionResult.setProgramShortCode(transaction.getProgramShortCode()); + transactionResult.setCycle(transactionResult.getCycle()); + return transactionResult; + } + +} diff --git a/ph-ee-connector-bulk/src/main/java/org/mifos/connector/phee/zeebe/ZeebeClientConfiguration.java b/ph-ee-connector-bulk/src/main/java/org/mifos/connector/phee/zeebe/ZeebeClientConfiguration.java new file mode 100644 index 000000000..2a9ccaf11 --- /dev/null +++ b/ph-ee-connector-bulk/src/main/java/org/mifos/connector/phee/zeebe/ZeebeClientConfiguration.java @@ -0,0 +1,33 @@ +package org.mifos.connector.phee.zeebe; + +import io.camunda.zeebe.client.ZeebeClient; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import java.time.Duration; + +@Configuration +public class ZeebeClientConfiguration { + + @Value("${zeebe.broker.contactpoint}") + private String zeebeBrokerContactPoint; + + @Value("${zeebe.client.max-execution-threads}") + private int zeebeClientMaxThreads; + + @Value("${zeebe.client.max-jobs-active}") + private int zeebeMaxJobsActive; + + @Bean + public ZeebeClient setup() { + return ZeebeClient.newClientBuilder() + .gatewayAddress(zeebeBrokerContactPoint) + .usePlaintext() + .defaultJobPollInterval(Duration.ofMillis(1)) + .defaultJobWorkerMaxJobsActive(zeebeMaxJobsActive) + .numJobWorkerExecutionThreads(zeebeClientMaxThreads) + .build(); + } + +} diff --git a/ph-ee-connector-bulk/src/main/java/org/mifos/connector/phee/zeebe/ZeebeProcessStarter.java b/ph-ee-connector-bulk/src/main/java/org/mifos/connector/phee/zeebe/ZeebeProcessStarter.java new file mode 100644 index 000000000..38ffa49d1 --- /dev/null +++ b/ph-ee-connector-bulk/src/main/java/org/mifos/connector/phee/zeebe/ZeebeProcessStarter.java @@ -0,0 +1,93 @@ +package org.mifos.connector.phee.zeebe; + +import io.camunda.zeebe.client.ZeebeClient; +import org.apache.camel.Exchange; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.time.Instant; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + + +@Component +public class ZeebeProcessStarter { + + private static final Logger logger = LoggerFactory.getLogger(ZeebeProcessStarter.class); + + @Autowired + private ZeebeClient zeebeClient; + + public static void zeebeVariablesToCamelHeaders(Map variables, Exchange exchange, String... names) { + Arrays.stream(names).forEach(name -> { + Object value = variables.get(name); + if (value == null) { + logger.error("failed to find Zeebe variable name {}", name); + } + exchange.getIn().setHeader(name, value); + }); + } + + public static void camelHeadersToZeebeVariables(Exchange exchange, Map variables, String... names) { + Arrays.stream(names).forEach(name -> { + String header = exchange.getIn().getHeader(name, String.class); + if (header == null) { + logger.error("failed to find Camel Exchange header {}", name); + } + variables.put(name, header); + }); + } + + public void startZeebeWorkflow(String workflowId, Map extraVariables) { + + Map variables = new HashMap<>(); + variables.put(ZeebeVariables.ORIGIN_DATE, Instant.now().toEpochMilli()); + if(extraVariables != null) { + variables.putAll(extraVariables); + } + + // TODO if successful transfer response arrives in X timeout return it otherwise do callback + zeebeClient.newCreateInstanceCommand() + .bpmnProcessId(workflowId) + .latestVersion() + .variables(variables) + .send() + .join(); + + + logger.info("zeebee workflow instance from process {}", workflowId); + } + + public String startZeebeWorkflow(String workflowId, String request, Map extraVariables) { + String transactionId = generateTransactionId(); + + Map variables = new HashMap<>(); + variables.put(ZeebeVariables.TRANSACTION_ID, transactionId); + variables.put(ZeebeVariables.CHANNEL_REQUEST, request); + variables.put(ZeebeVariables.ORIGIN_DATE, Instant.now().toEpochMilli()); + if(extraVariables != null) { + variables.putAll(extraVariables); + } + + // TODO if successful transfer response arrives in X timeout return it otherwise do callback + zeebeClient.newCreateInstanceCommand() + .bpmnProcessId(workflowId) + .latestVersion() + .variables(variables) + .send() + .join(); + + + logger.info("zeebee workflow instance from process {} started with transactionId {}", workflowId, transactionId); + return transactionId; + } + + // TODO generate proper cluster-safe transaction id + private String generateTransactionId() { + return UUID.randomUUID().toString(); + } +} diff --git a/ph-ee-connector-bulk/src/main/java/org/mifos/connector/phee/zeebe/ZeebeVariables.java b/ph-ee-connector-bulk/src/main/java/org/mifos/connector/phee/zeebe/ZeebeVariables.java new file mode 100644 index 000000000..a296237c2 --- /dev/null +++ b/ph-ee-connector-bulk/src/main/java/org/mifos/connector/phee/zeebe/ZeebeVariables.java @@ -0,0 +1,120 @@ +package org.mifos.connector.phee.zeebe; + +public class ZeebeVariables { + + public static final String REQUEST_ID_STATUS_MAP = "requestIdStatusMap"; + + private ZeebeVariables(){} + + public static final String PURPOSE = "purpose"; + + public static final String TOTAL_TRANSACTION = "totalTransactions"; + + public static final String ONGOING_TRANSACTION = "ongoingTransactions"; + + public static final String FAILED_TRANSACTION = "failedTransactions"; + + public static final String COMPLETED_TRANSACTION = "completedTransaction"; + + public static final String ONGOING_AMOUNT = "ongoingAmount"; + + public static final String FAILED_AMOUNT = "failedAmount"; + + public static final String COMPLETED_AMOUNT = "completedAmount"; + + public static final String TOTAL_AMOUNT = "totalAmount"; + + public static final String PAGE_NUMBER = "pageNumber"; + + public static final String CURRENT_TRANSACTION_COUNT = "currentTransactionCount"; + + public static final String ORIGIN_DATE = "originDate"; + + public static final String CHANNEL_REQUEST = "channelRequest"; + + public static final String PAGE_SIZE = "pageSize"; + + public static final String TOTAL_TRANSACTION_COUNT = "totalTransactionCount"; + + public static final String COMPLETED_TRANSACTION_COUNT = "completedTransactionCount"; + + public static final String FAILED_TRANSACTION_COUNT = "failedTransactionCount"; + + public static final String BATCH_DETAIL_SUCCESS = "batchDetailSuccess"; + + public static final String ONGOING_TRANSACTION_COUNT = "ongoingTransactionCount"; + + public static final String MAX_RETRY_COUNT = "maxRetryCount"; + + public static final String BATCH_ID = "batchId"; + + public static final String WAIT_TIMER = "waitTimer"; + + public static final String CURRENT_RETRY_COUNT = "currentRetryCount"; + + public static final String CURRENT_RECONCILIATION_RETRY_COUNT = "currentReconciliationRetryCount"; + + public static final String TOTAL_RETRY_COUNT = "totalRetryCount"; + + public static final String TOTAL_RECONCILIATION_RETRY_COUNT = "totalReconciliationRetryCount"; + + public static final String FILE_NAME = "filename"; + + public static final String TENANT_ID = "tenantId"; + + public static final String REQUEST_ID = "requestId"; + + public static final String ERROR_CODE = "errorCode"; + + public static final String ERROR_DESCRIPTION = "errorDescription"; + + public static final String TRANSACTION_ID = "transactionId"; + + public static final String RECONCILIATION_SUCCESS = "reconciliationSuccess"; + + public static final String TRANSACTION_LIST = "transactionList"; + + public static final String RESULT_FILE = "resultFile"; + + public static final String PAYMENT_MODE = "paymentMode"; + + public static final String INIT_BATCH_TRANSFER_SUCCESS = "initBatchTransferSuccess"; + + public static final String TENANT_NAME = "tenantName"; + + public static final String COMPLETION_RATE = "completionRate"; + + public static final String BATCH_SUMMARY_SUCCESS = "batchSummarySuccess"; + + public static final String PAGE_NO = "pageNo"; + + public static final String RESULT_TRANSACTION_LIST = "resultTransactionList"; + + public static final String LOCAL_FILE_PATH = "localFilePath"; + + public static final String OVERRIDE_HEADER = "overrideHeader"; + + public static final String ACCOUNT = "account"; + + public static final String ERROR_INFORMATION = "errorInformation"; + + public static final String IS_AUTHORISATION_REQUIRED = "isAuthorisationRequired"; + + public static final String IS_RTP_REQUEST = "isRtpRequest"; + + public static final String PARTY_ID = "partyId"; + + public static final String PARTY_ID_TYPE = "partyIdType"; + + public static final String TRANSACTION_TYPE = "transactionType"; + + public static final String CLIENTCORRELATIONID = "X-CorrelationID"; + + public static final String RTP_STATUS = "rtpStatus"; + public static final String HEADER_TENANT = "X-Platform-TenantId"; + public static final String HEADER_BILLER_ID = "X-Biller-Id"; + public static final String HEADER_CLIENTCORRELATIONID = "X-Client-Correlation-ID"; + public static final String DEBULKINGDFSPID = "debulkingDfspid"; + + +} diff --git a/ph-ee-connector-bulk/src/main/java/org/mifos/connector/phee/zeebe/workers/BaseWorker.java b/ph-ee-connector-bulk/src/main/java/org/mifos/connector/phee/zeebe/workers/BaseWorker.java new file mode 100644 index 000000000..5d5d01b1b --- /dev/null +++ b/ph-ee-connector-bulk/src/main/java/org/mifos/connector/phee/zeebe/workers/BaseWorker.java @@ -0,0 +1,65 @@ +package org.mifos.connector.phee.zeebe.workers; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.dataformat.csv.CsvMapper; +import io.camunda.zeebe.client.ZeebeClient; +import io.camunda.zeebe.client.api.worker.JobHandler; +import org.apache.camel.CamelContext; +import org.apache.camel.Exchange; +import org.apache.camel.ProducerTemplate; +import org.mifos.connector.phee.camel.routes.RouteId; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +import javax.annotation.PostConstruct; + +// TODO: Duplicate file (Also exists in ) +@Component +public abstract class BaseWorker { + + @Autowired + private ZeebeClient zeebeClient; + + @Autowired + private CsvMapper csvMapper; + + @Autowired + private ObjectMapper objectMapper; + + @Value("${application.bucket-name}") + private String bucketName; + + @Value("${zeebe.client.evenly-allocated-max-jobs}") + private int workerMaxJobs; + + @Autowired + protected CamelContext camelContext; + + @Autowired + private ProducerTemplate producerTemplate; + + @Autowired + protected WorkerConfig workerConfig; + + protected Logger logger = LoggerFactory.getLogger(this.getClass()); + + @PostConstruct + public abstract void setup(); + + public void newWorker(Worker worker, JobHandler handler) { + zeebeClient.newWorker() + .jobType(worker.getValue()) + .handler(handler) + .name(worker.getValue()) + .maxJobsActive(workerMaxJobs) + .open(); + } + + public void sendToCamelRoute(RouteId routeId, Exchange exchange) { + producerTemplate.send(routeId.getValue(), exchange); + } + +} diff --git a/ph-ee-connector-bulk/src/main/java/org/mifos/connector/phee/zeebe/workers/Worker.java b/ph-ee-connector-bulk/src/main/java/org/mifos/connector/phee/zeebe/workers/Worker.java new file mode 100644 index 000000000..048ad4037 --- /dev/null +++ b/ph-ee-connector-bulk/src/main/java/org/mifos/connector/phee/zeebe/workers/Worker.java @@ -0,0 +1,21 @@ +package org.mifos.connector.phee.zeebe.workers; + +public enum Worker { + + INIT_BATCH_TRANSFER("initBatchTransfer"), + + BATCH_SUMMARY("batchSummary"), + + BATCH_DETAILS("batchDetails"), + PAYER_RTP_RESPONSE("payerRtpResponse"); + + private final String value; + + private Worker(String value) { + this.value = value; + } + + public String getValue() { + return value; + } +} diff --git a/ph-ee-connector-bulk/src/main/java/org/mifos/connector/phee/zeebe/workers/WorkerConfig.java b/ph-ee-connector-bulk/src/main/java/org/mifos/connector/phee/zeebe/workers/WorkerConfig.java new file mode 100644 index 000000000..15551bc69 --- /dev/null +++ b/ph-ee-connector-bulk/src/main/java/org/mifos/connector/phee/zeebe/workers/WorkerConfig.java @@ -0,0 +1,7 @@ +package org.mifos.connector.phee.zeebe.workers; + +import org.springframework.stereotype.Component; + +@Component +public class WorkerConfig { +} diff --git a/ph-ee-connector-bulk/src/main/java/org/mifos/connector/phee/zeebe/workers/implementation/BatchDetailWorker.java b/ph-ee-connector-bulk/src/main/java/org/mifos/connector/phee/zeebe/workers/implementation/BatchDetailWorker.java new file mode 100644 index 000000000..906d02bbc --- /dev/null +++ b/ph-ee-connector-bulk/src/main/java/org/mifos/connector/phee/zeebe/workers/implementation/BatchDetailWorker.java @@ -0,0 +1,217 @@ +package org.mifos.connector.phee.zeebe.workers.implementation; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.apache.camel.Exchange; +import org.apache.camel.support.DefaultExchange; +import org.mifos.connector.phee.camel.routes.RouteId; +import org.mifos.connector.phee.config.MockPaymentSchemaConfig; +import org.mifos.connector.phee.schema.BatchDetailResponse; +import org.mifos.connector.phee.schema.Transaction; +import org.mifos.connector.phee.schema.TransactionResult; +import org.mifos.connector.phee.zeebe.workers.BaseWorker; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Component; +import org.springframework.web.client.RestTemplate; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static org.mifos.connector.phee.zeebe.ZeebeVariables.BATCH_DETAIL_SUCCESS; +import static org.mifos.connector.phee.zeebe.ZeebeVariables.BATCH_ID; +import static org.mifos.connector.phee.zeebe.ZeebeVariables.COMPLETED_TRANSACTION_COUNT; +import static org.mifos.connector.phee.zeebe.ZeebeVariables.CURRENT_TRANSACTION_COUNT; +import static org.mifos.connector.phee.zeebe.ZeebeVariables.ERROR_CODE; +import static org.mifos.connector.phee.zeebe.ZeebeVariables.ERROR_DESCRIPTION; +import static org.mifos.connector.phee.zeebe.ZeebeVariables.FAILED_TRANSACTION_COUNT; +import static org.mifos.connector.phee.zeebe.ZeebeVariables.FILE_NAME; +import static org.mifos.connector.phee.zeebe.ZeebeVariables.ONGOING_TRANSACTION_COUNT; +import static org.mifos.connector.phee.zeebe.ZeebeVariables.PAGE_NO; +import static org.mifos.connector.phee.zeebe.ZeebeVariables.PAGE_SIZE; +import static org.mifos.connector.phee.zeebe.ZeebeVariables.REQUEST_ID_STATUS_MAP; +import static org.mifos.connector.phee.zeebe.ZeebeVariables.TENANT_ID; +import static org.mifos.connector.phee.zeebe.ZeebeVariables.TOTAL_TRANSACTION; +import static org.mifos.connector.phee.zeebe.workers.Worker.BATCH_DETAILS; + + +@Component +public class BatchDetailWorker extends BaseWorker { + @Autowired + public MockPaymentSchemaConfig mockPaymentSchemaConfig; + private ObjectMapper objectMapper = new ObjectMapper(); + + @Override + public void setup() { + logger.info("## generating {} zeebe worker", BATCH_DETAILS ); + newWorker(BATCH_DETAILS, (client, job) -> { + logger.info("Job '{}' started from process '{}' with key {}", job.getType(), job.getBpmnProcessId(), job.getKey()); + Map variables = job.getVariablesAsMap(); + + int pageNumber = (int) variables.getOrDefault(PAGE_NO, 1); + int pageSize = (int) variables.getOrDefault(PAGE_SIZE, 5); + int currentTransactionCount = (int) variables.getOrDefault(CURRENT_TRANSACTION_COUNT, 0); + int completedTransactionCount = (int) variables.getOrDefault(COMPLETED_TRANSACTION_COUNT, 0); + int failedTransactionCount = (int) variables.getOrDefault(FAILED_TRANSACTION_COUNT, 0); + int ongoingTransactionCount = (int) variables.getOrDefault(ONGOING_TRANSACTION_COUNT, 0); + + Exchange exchange = new DefaultExchange(camelContext); + exchange.setProperty(BATCH_ID, variables.get(BATCH_ID)); + exchange.setProperty(PAGE_NO, pageNumber); + exchange.setProperty(PAGE_SIZE, pageSize); + exchange.setProperty(TENANT_ID, variables.get(TENANT_ID)); + exchange.setProperty(TOTAL_TRANSACTION, variables.get(TOTAL_TRANSACTION)); + exchange.setProperty(CURRENT_TRANSACTION_COUNT, currentTransactionCount); + exchange.setProperty(COMPLETED_TRANSACTION_COUNT, completedTransactionCount); + exchange.setProperty(FAILED_TRANSACTION_COUNT, failedTransactionCount); + exchange.setProperty(ONGOING_TRANSACTION_COUNT, ongoingTransactionCount); + exchange.setProperty(FILE_NAME, variables.get(FILE_NAME)); + exchange.setProperty(REQUEST_ID_STATUS_MAP, variables.getOrDefault(REQUEST_ID_STATUS_MAP, new HashMap<>())); + + sendToCamelRoute(RouteId.BATCH_DETAIL, exchange); + + boolean isReconciliationSuccess = exchange.getProperty(BATCH_DETAIL_SUCCESS, Boolean.class); + + if (!isReconciliationSuccess) { + variables.put(ERROR_CODE, exchange.getProperty(ERROR_CODE)); + variables.put(ERROR_DESCRIPTION, exchange.getProperty(ERROR_DESCRIPTION)); + } + else{ + exchange.setProperty(FILE_NAME, variables.get(FILE_NAME)); + sendToCamelRoute(RouteId.UPLOAD_RESULT_FILE, exchange); + } + + variables.put(BATCH_DETAIL_SUCCESS, isReconciliationSuccess); + variables.put(CURRENT_TRANSACTION_COUNT, exchange.getProperty(CURRENT_TRANSACTION_COUNT)); + variables.put(COMPLETED_TRANSACTION_COUNT, exchange.getProperty(COMPLETED_TRANSACTION_COUNT)); + variables.put(FAILED_TRANSACTION_COUNT, exchange.getProperty(FAILED_TRANSACTION_COUNT)); + variables.put(ONGOING_TRANSACTION_COUNT, exchange.getProperty(ONGOING_TRANSACTION_COUNT)); + variables.put(PAGE_NO, ++pageNumber); + variables.put(REQUEST_ID_STATUS_MAP, exchange.getProperty(REQUEST_ID_STATUS_MAP)); + + client.newCompleteCommand(job.getKey()).variables(variables).send(); + }); + + } + + public BatchDetailResponse callApi(String batchId, int pageNo, int pageSize, String tenant) { + // Set up the RestTemplate + RestTemplate restTemplate = new RestTemplate(); + + // Set headers + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_JSON); + headers.set("Platform-TenantId", tenant); + + // Construct URL with query parameters + String apiUrl = String.format("%s?%s=%s&%s=%s&%s=%s", + mockPaymentSchemaConfig.batchDetailUrl, + BATCH_ID, batchId, + PAGE_NO, pageNo, + PAGE_SIZE, pageSize); + + // Construct request entity with headers + HttpEntity requestEntity = new HttpEntity<>(headers); + BatchDetailResponse batchDetailResponse = null; + + try { + // Make the API call + ResponseEntity response = restTemplate.exchange( + apiUrl, + HttpMethod.GET, + requestEntity, + String.class + ); + batchDetailResponse = objectMapper.readValue(response.getBody(), BatchDetailResponse.class); + + // Log response + logger.debug("Batch detail API response: {}", response.getBody()); + } catch (Exception e) { + // Handle exceptions + logger.warn("Exception occurred: " + e.getMessage()); + } + return batchDetailResponse; + } + + public void processBatchDetail(String batchId, int pageNo, int pageSize) { + String apiResponse = callBatchDetailApi(batchId, pageNo, pageSize); + if (apiResponse != null) { + handleBatchDetailApiResponse(apiResponse, pageNo, pageSize); + uploadResultFile(); + } else { + // Handle API call failure + logger.info("CallBatchDetailApi response is null"); + } + } + + private String callBatchDetailApi(String batchId, int pageNo, int pageSize) { + // Make API call and return the response as a String + // Replace Camel code with your API call logic here + return null; // Placeholder for API response (replace with actual logic) + } + private void handleBatchDetailApiResponse(String apiResponse, int pageNo, int pageSize) { + try { + BatchDetailResponse batchDetailResponse = objectMapper.readValue(apiResponse, BatchDetailResponse.class); + // Process batch details and update properties accordingly + // Logic from direct:batch-detail-response-handler can be moved here + // I'll create a dummy implementation for demonstration purposes + int currentTransferCount = 10; // Replace with your logic + int totalTransferCount = 100; // Replace with your logic + + if (currentTransferCount >= totalTransferCount) { + // Set property for successful batch detail + } else { + // Set property for unsuccessful batch detail + } + } catch (Exception e) { + // Handle exception during API response handling + } + } + private void uploadResultFile() { + // Logic for uploading result file + // Logic from direct:upload-result-file can be moved here + // I'll create a dummy implementation for demonstration purposes + boolean batchDetailSuccess = true; // Replace with your logic + if (batchDetailSuccess) { + downloadFile(); + getTransactionArray(); + String serverFileName = "ServerFile.txt"; // Replace with actual file name + String batchId = "12345"; // Replace with actual batch ID + String resultFile = String.format("Result_%s", serverFileName); + List transactionList = new ArrayList<>(); // Replace with your list of transactions + Map requestIdStatusMap = new HashMap<>(); // Replace with your map + List transactionResultList = fetchTransactionResult(transactionList, requestIdStatusMap, batchId); + updateResultFile(resultFile, transactionResultList); + uploadFile(resultFile); + } else { + // Handle unsuccessful batch detail + } + } + private void downloadFile() { + // Logic for downloading file + } + + private void getTransactionArray() { + // Logic for getting transaction array + } + + private List fetchTransactionResult(List transactionList, Map requestIdStatusMap, String batchId) { + List transactionResultList = new ArrayList<>(); + // Logic for fetching transaction result + return transactionResultList; + } + + private void updateResultFile(String resultFile, List transactionResultList) { + // Logic for updating result file + } + + private void uploadFile(String resultFile) { + // Logic for uploading file + } + +} diff --git a/ph-ee-connector-bulk/src/main/java/org/mifos/connector/phee/zeebe/workers/implementation/BatchSummaryWorker.java b/ph-ee-connector-bulk/src/main/java/org/mifos/connector/phee/zeebe/workers/implementation/BatchSummaryWorker.java new file mode 100644 index 000000000..a9a240504 --- /dev/null +++ b/ph-ee-connector-bulk/src/main/java/org/mifos/connector/phee/zeebe/workers/implementation/BatchSummaryWorker.java @@ -0,0 +1,138 @@ +package org.mifos.connector.phee.zeebe.workers.implementation; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.apache.camel.Exchange; +import org.apache.camel.support.DefaultExchange; +import org.apache.http.conn.ssl.NoopHostnameVerifier; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClients; +import org.apache.http.ssl.SSLContextBuilder; +import org.mifos.connector.phee.config.MockPaymentSchemaConfig; +import org.mifos.connector.phee.schema.BatchDTO; +import org.mifos.connector.phee.zeebe.workers.BaseWorker; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; +import org.springframework.stereotype.Component; +import org.springframework.web.client.RestTemplate; + +import java.security.KeyManagementException; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.util.Map; + +import static org.mifos.connector.phee.zeebe.ZeebeVariables.BATCH_ID; +import static org.mifos.connector.phee.zeebe.ZeebeVariables.BATCH_SUMMARY_SUCCESS; +import static org.mifos.connector.phee.zeebe.ZeebeVariables.COMPLETED_AMOUNT; +import static org.mifos.connector.phee.zeebe.ZeebeVariables.COMPLETED_TRANSACTION; +import static org.mifos.connector.phee.zeebe.ZeebeVariables.COMPLETION_RATE; +import static org.mifos.connector.phee.zeebe.ZeebeVariables.CURRENT_RETRY_COUNT; +import static org.mifos.connector.phee.zeebe.ZeebeVariables.ERROR_CODE; +import static org.mifos.connector.phee.zeebe.ZeebeVariables.ERROR_DESCRIPTION; +import static org.mifos.connector.phee.zeebe.ZeebeVariables.FAILED_AMOUNT; +import static org.mifos.connector.phee.zeebe.ZeebeVariables.FAILED_TRANSACTION; +import static org.mifos.connector.phee.zeebe.ZeebeVariables.MAX_RETRY_COUNT; +import static org.mifos.connector.phee.zeebe.ZeebeVariables.ONGOING_AMOUNT; +import static org.mifos.connector.phee.zeebe.ZeebeVariables.ONGOING_TRANSACTION; +import static org.mifos.connector.phee.zeebe.ZeebeVariables.TENANT_ID; +import static org.mifos.connector.phee.zeebe.ZeebeVariables.TOTAL_AMOUNT; +import static org.mifos.connector.phee.zeebe.ZeebeVariables.TOTAL_TRANSACTION; +import static org.mifos.connector.phee.zeebe.workers.Worker.BATCH_SUMMARY; + + +@Component +public class BatchSummaryWorker extends BaseWorker { + + @Value("${config.completion-threshold-check.max-retry-count}") + public int maxRetryCount; + @Autowired + public MockPaymentSchemaConfig mockPaymentSchemaConfig; + private ObjectMapper objectMapper = new ObjectMapper(); + + @Override + public void setup() { + logger.info("## generating " + BATCH_SUMMARY + "zeebe worker"); + newWorker(BATCH_SUMMARY, (client, job)->{ + Map variables = job.getVariablesAsMap(); + int currentRetryCount = (int) variables.getOrDefault(CURRENT_RETRY_COUNT, 1); + + Exchange exchange = new DefaultExchange(camelContext); + exchange.setProperty(BATCH_ID, variables.get(BATCH_ID)); + exchange.setProperty(TENANT_ID, variables.get(TENANT_ID)); + //BatchDTO batchDTO = new BatchDTO(); + BatchDTO batchDTO = callApi(variables.get(BATCH_ID).toString(), variables.get(TENANT_ID).toString()); + logger.info("Batch Summary: {}", objectMapper.writeValueAsString(batchDTO)); + + //sendToCamelRoute(RouteId.BATCH_SUMMARY, exchange); + + // boolean isBatchSummarySuccess = (boolean) exchange.getProperty(BATCH_SUMMARY_SUCCESS); + + variables.put(MAX_RETRY_COUNT, maxRetryCount); + variables.put(CURRENT_RETRY_COUNT, ++currentRetryCount); + variables.put(ONGOING_TRANSACTION, batchDTO.getOngoing()); + variables.put(FAILED_TRANSACTION, batchDTO.getFailed()); + variables.put(TOTAL_TRANSACTION, batchDTO.getTotal()); + variables.put(COMPLETED_TRANSACTION, batchDTO.getSuccessful()); + variables.put(ONGOING_AMOUNT, batchDTO.getPendingAmount()); + variables.put(FAILED_AMOUNT, batchDTO.getFailedAmount()); + variables.put(COMPLETED_AMOUNT, batchDTO.getSuccessfulAmount()); + variables.put(TOTAL_AMOUNT, batchDTO.getTotalAmount()); + long percentage = (long)(((double) + (batchDTO.getSuccessful() + batchDTO.getFailed())/batchDTO.getTotal()) *100); + variables.put(COMPLETION_RATE, percentage); + + if(batchDTO!=null) { + + variables.put(BATCH_SUMMARY_SUCCESS, true); + } else { + variables.put(ERROR_CODE, exchange.getProperty(ERROR_CODE)); + variables.put(ERROR_DESCRIPTION, exchange.getProperty(ERROR_DESCRIPTION)); + logger.info("Error: {}, {}", variables.get(ERROR_CODE), variables.get(ERROR_DESCRIPTION)); + } + + client.newCompleteCommand(job.getKey()).variables(variables).send(); + }); + } + + public BatchDTO callApi(String batchId, String tenant) throws NoSuchAlgorithmException, KeyStoreException, KeyManagementException { + RestTemplate restTemplate = new RestTemplate(); + CloseableHttpClient httpClient = HttpClients.custom() + .setSSLContext(new SSLContextBuilder().loadTrustMaterial(null, (certificate, authType) -> true).build()) + .setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE) + .build(); + restTemplate.setRequestFactory(new HttpComponentsClientHttpRequestFactory(httpClient)); + + + // Set headers + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_JSON); + headers.set("Platform-TenantId", tenant); + + // Construct URL + String apiUrl = mockPaymentSchemaConfig.mockPaymentSchemaContactPoint + "/batches/" + batchId + "/summary"; + + // Construct request entity with headers + HttpEntity requestEntity = new HttpEntity<>(headers); + BatchDTO batchDTO = null; + + try { + // Make the API call + ResponseEntity response = restTemplate.exchange(apiUrl, HttpMethod.GET, requestEntity, BatchDTO.class); + //batchDTO = objectMapper.readValue(response.getBody(), BatchDTO.class); + batchDTO = response.getBody(); + // Log response + logger.info("Batch summary API response: \n\n" + response.getBody()); + return batchDTO; + + } catch (Exception e) { + // Handle exceptions + logger.warn("Exception occurred: " + e.getMessage()); + } + return batchDTO; + } +} \ No newline at end of file diff --git a/ph-ee-connector-bulk/src/main/java/org/mifos/connector/phee/zeebe/workers/implementation/BatchTransferWorker.java b/ph-ee-connector-bulk/src/main/java/org/mifos/connector/phee/zeebe/workers/implementation/BatchTransferWorker.java new file mode 100644 index 000000000..bb41e3d82 --- /dev/null +++ b/ph-ee-connector-bulk/src/main/java/org/mifos/connector/phee/zeebe/workers/implementation/BatchTransferWorker.java @@ -0,0 +1,308 @@ +package org.mifos.connector.phee.zeebe.workers.implementation; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SequenceWriter; +import com.fasterxml.jackson.dataformat.csv.CsvMapper; +import com.fasterxml.jackson.dataformat.csv.CsvSchema; +import org.apache.http.conn.ssl.NoopHostnameVerifier; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClients; +import org.apache.http.ssl.SSLContextBuilder; +import org.mifos.connector.common.util.JsonWebSignature; +import org.mifos.connector.phee.config.PaymentModeConfiguration; +import org.mifos.connector.phee.config.PaymentModeMapping; +import org.mifos.connector.phee.file.FileTransferService; +import org.mifos.connector.phee.schema.Transaction; +import org.mifos.connector.phee.schema.TransactionResult; +import org.mifos.connector.phee.utils.Utils; +import org.mifos.connector.phee.zeebe.workers.BaseWorker; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.*; +import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; +import org.springframework.stereotype.Component; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; +import org.springframework.util.ObjectUtils; +import org.springframework.web.client.RestTemplate; +import org.springframework.web.util.UriComponentsBuilder; + +import javax.crypto.BadPaddingException; +import javax.crypto.IllegalBlockSizeException; +import javax.crypto.NoSuchPaddingException; +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.security.InvalidKeyException; +import java.security.KeyManagementException; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.spec.InvalidKeySpecException; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +import static org.mifos.connector.phee.zeebe.ZeebeVariables.*; +import static org.mifos.connector.phee.zeebe.workers.Worker.INIT_BATCH_TRANSFER; + + +@Component +public class BatchTransferWorker extends BaseWorker { + + @Autowired + @Qualifier("awsStorage") + private FileTransferService fileTransferService; + + @Value("${application.bucket-name}") + private String bucketName; + + @Value("${config.completion-threshold-check.wait-timer}") + private String waitTimer; + + @Value("${bulk-processor.contactpoint}") + private String bulkProcessorContactPoint; + + @Value("${bulk-processor.endpoints.batch-transaction}") + private String batchTransactionEndpoint; + + @Value("${json_web_signature.privateKey}") + private String privateKeyString; + + @Autowired + private PaymentModeConfiguration paymentModeConfiguration; + + @Value("${tenant}") + public String tenant; + + @Autowired + private CsvMapper csvMapper; + + @Override + public void setup() { + logger.info("## generating " + INIT_BATCH_TRANSFER + "zeebe worker"); + newWorker(INIT_BATCH_TRANSFER, (client, job) ->{ + Map variables = job.getVariablesAsMap(); + String debulkingDfspId = variables.get(DEBULKINGDFSPID).toString(); + variables.put("waitTimer", waitTimer); + + String paymentMode = (String) variables.get(PAYMENT_MODE); + String fileName = (String) variables.get(FILE_NAME); + + byte[] bytes = fileTransferService.downloadFileAsStream((String) variables.get(FILE_NAME), bucketName); + String csvData = new String(bytes); + List transactionList = parseCSVDataToList(csvData); + String rootDirectory = System.getProperty("user.dir"); + + // Create the file path using the root directory and file name + String filePath = rootDirectory + File.separator + fileName; + + if(!isPaymentModeValid(paymentMode)){ + String serverFileName = (String) variables.get(FILE_NAME); + String resultFile = String.format("Result_%s", serverFileName); + uploadResultFileWithError(transactionList, resultFile); + variables.put(INIT_BATCH_TRANSFER_SUCCESS, false); + } + else{ + String updatedCsvData = updateCsvDataPaymentMode(csvData, filePath); + String clientCorrelationId = String.valueOf(UUID.randomUUID()); + String batchId = invokeBatchTransactionApi(fileName, updatedCsvData, filePath, clientCorrelationId, debulkingDfspId); + logger.info("invokeBatchTransactionApi: {}", batchId); + if(!ObjectUtils.isEmpty(batchId)){ + variables.put(INIT_BATCH_TRANSFER_SUCCESS, true); + logger.info("Source batchId: {}", variables.get(BATCH_ID)); + logger.info("Destination batchId: {}", batchId); + } + } + client.newCompleteCommand(job.getKey()).variables(variables).send(); + }); + + } + + private String updateCsvDataPaymentMode(String csvData, String filePath) { + + String[] lines = csvData.split("\n"); + StringBuilder updatedCsvData = new StringBuilder(); + updatedCsvData.append(lines[0]); + updatedCsvData.append("\n"); + + for(int i=1; i transactionList, String resultFile) { + List transactionResultList = updateTransactionStatusToFailed(transactionList); + + try { + csvWriter(transactionResultList, TransactionResult.class, csvMapper, true, resultFile); + } catch (IOException e) { + throw new RuntimeException(e); + } + fileTransferService.uploadFile(new File(resultFile), bucketName); + } + + private boolean isPaymentModeValid(String paymentMode) { + PaymentModeMapping mapping = paymentModeConfiguration.getByMode(paymentMode); + return mapping != null; + } + public String invokeBatchTransactionApi(String filename, String csvData, String filePath, String clientCorrelationId, String tenant) throws Exception { + String signature = generateSignature(clientCorrelationId, tenant, csvData, true, filePath); + String batchTransactionUrl = bulkProcessorContactPoint + batchTransactionEndpoint; + String url = UriComponentsBuilder.fromHttpUrl(batchTransactionUrl) + .queryParam("type", "csv").toUriString(); + + HttpEntity> requestEntity = createHttpEntity(filename, csvData, filePath, clientCorrelationId, tenant, signature); + return executeBatchTransactionRequest(url, requestEntity); + } + + + private RestTemplate createRestTemplate() throws NoSuchAlgorithmException, KeyStoreException, KeyManagementException { + RestTemplate restTemplate = new RestTemplate(); + CloseableHttpClient httpClient = createHttpClient(); + restTemplate.setRequestFactory(new HttpComponentsClientHttpRequestFactory(httpClient)); + return restTemplate; + } + + private CloseableHttpClient createHttpClient() throws NoSuchAlgorithmException, KeyStoreException, KeyManagementException { + return HttpClients.custom() + .setSSLContext(new SSLContextBuilder().loadTrustMaterial(null, (certificate, authType) -> true).build()) + .setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE) + .build(); + } + + private HttpEntity> createHttpEntity(String filename, String csvData, String filePath, String clientCorrelationId, String tenant, String signature) throws IOException { + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.MULTIPART_FORM_DATA); + headers.set("purpose", "test payment"); + headers.set("filename", filename); + headers.set("X-CorrelationID", clientCorrelationId); + headers.set("Platform-TenantId", tenant); + headers.set("X-SIGNATURE", signature); + headers.set("Type", "csv"); + + MultiValueMap body = new LinkedMultiValueMap<>(); + body.add("data", Files.readString(Paths.get(filePath))); + + return new HttpEntity<>(body, headers); + } + + private String executeBatchTransactionRequest(String url, HttpEntity> requestEntity) throws JsonProcessingException, NoSuchAlgorithmException, KeyStoreException, KeyManagementException { + RestTemplate restTemplate = createRestTemplate(); + ResponseEntity response = restTemplate.exchange(url, HttpMethod.POST, requestEntity, String.class); + + String batchTransactionResponse = response != null ? response.getBody() : null; + ObjectMapper objectMapper = new ObjectMapper(); + JsonNode jsonNode = objectMapper.readTree(batchTransactionResponse); + return jsonNode.get("PollingPath").asText().split("/")[3]; + } + + public String getListAsCsvString(List list){ + StringBuilder stringBuilder = new StringBuilder(); + stringBuilder.append("id,request_id,payment_mode,payer_identifier_type,payer_identifier,payee_identifier_type,payee_identifier,amount,currency,note\n"); + for(Transaction transaction : list){ + stringBuilder.append(transaction.getId()).append(",") + .append(transaction.getRequestId()).append(",") + .append(transaction.getPaymentMode()).append(",") + .append(transaction.getPayerIdentifierType()).append(",") + .append(transaction.getPayerIdentifier()).append(",") + .append(transaction.getPayeeIdentifierType()).append(",") + .append(transaction.getPayeeIdentifier()).append(",") + .append(transaction.getAmount()).append(",") + .append(transaction.getCurrency()).append(",") + .append(transaction.getNote()).append("\n"); + } + return stringBuilder.toString(); + } + + private List parseCSVDataToList(String csvData) { + List transactionList = new ArrayList<>(); + String[] lines = csvData.split("\n"); + + for(int i=1; i updateTransactionStatusToFailed(List transactionList) { + List transactionResultList = new ArrayList<>(); + for (Transaction transaction : transactionList) { + TransactionResult transactionResult = Utils.mapToResultDTO(transaction); + transactionResult.setErrorCode("404"); + transactionResult.setErrorDescription("Payment mode not configured"); + transactionResult.setStatus("Failed"); + transactionResultList.add(transactionResult); + } + return transactionResultList; + } + + private void csvWriter(List data, Class tClass, CsvMapper csvMapper, + boolean overrideHeader, String filepath) throws IOException { + CsvSchema csvSchema = csvMapper.schemaFor(tClass); + if (overrideHeader) { + csvSchema = csvSchema.withHeader(); + } else { + csvSchema = csvSchema.withoutHeader(); + } + File file = new File(filepath); + SequenceWriter writer = csvMapper.writerWithSchemaFor(tClass).with(csvSchema).writeValues(file); + for (T object: data) { + writer.write(object); + } + } + protected String generateSignature(String clientCorrelationId, String tenant, String filename, boolean isDataAFile, String filePath) throws IOException, + NoSuchPaddingException, IllegalBlockSizeException, NoSuchAlgorithmException, + BadPaddingException, InvalidKeySpecException, InvalidKeyException { + + + JsonWebSignature jsonWebSignature = new JsonWebSignature.JsonWebSignatureBuilder() + .setClientCorrelationId(clientCorrelationId) + .setTenantId(tenant) + .setIsDataAsFile(isDataAFile) + .setData(filePath) + .build(); + + return jsonWebSignature.getSignature(privateKeyString); + } + + +} \ No newline at end of file diff --git a/ph-ee-connector-bulk/src/main/java/org/mifos/connector/phee/zeebe/workers/implementation/PayerRtpResponseWorker.java b/ph-ee-connector-bulk/src/main/java/org/mifos/connector/phee/zeebe/workers/implementation/PayerRtpResponseWorker.java new file mode 100644 index 000000000..d0db14053 --- /dev/null +++ b/ph-ee-connector-bulk/src/main/java/org/mifos/connector/phee/zeebe/workers/implementation/PayerRtpResponseWorker.java @@ -0,0 +1,80 @@ +package org.mifos.connector.phee.zeebe.workers.implementation; + +import org.apache.http.conn.ssl.NoopHostnameVerifier; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.http.impl.client.HttpClients; +import org.apache.http.ssl.SSLContextBuilder; +import org.mifos.connector.phee.data.PayerRTPResponse; +import org.mifos.connector.phee.data.ResponseDTO; +import org.mifos.connector.phee.zeebe.workers.BaseWorker; +import org.mifos.connector.phee.zeebe.workers.Worker; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; +import org.springframework.stereotype.Component; +import org.springframework.web.client.RestTemplate; + +import java.util.Map; + +import static org.mifos.connector.phee.zeebe.ZeebeVariables.HEADER_BILLER_ID; +import static org.mifos.connector.phee.zeebe.ZeebeVariables.HEADER_CLIENTCORRELATIONID; +import static org.mifos.connector.phee.zeebe.ZeebeVariables.HEADER_TENANT; +import static org.mifos.connector.phee.zeebe.ZeebeVariables.RTP_STATUS; + +@Component +public class PayerRtpResponseWorker extends BaseWorker { + @Override + public void setup() { + + newWorker(Worker.PAYER_RTP_RESPONSE, (client, job) -> { + Map variables = job.getVariablesAsMap(); + variables.put("billAccepted", true); + variables.put("state", "IN_PROGRESS"); + variables.put(RTP_STATUS ,"00"); + RestTemplate restTemplate = new RestTemplate(); + HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory(); + CloseableHttpClient httpClient = HttpClients.custom() + .setSSLContext(new SSLContextBuilder().loadTrustMaterial(null, (certificate, authType) -> true).build()) + .setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE) + .build(); + restTemplate.setRequestFactory(new HttpComponentsClientHttpRequestFactory(httpClient)); + String billId = (String) variables.get("billId"); + String transactionId = (String) variables.get("transactionId"); + String callbackUrl = (String) variables.get("payerCallbackUrl"); + String tenantId = (String) variables.get("payerTenantId"); + + HttpHeaders headers = new HttpHeaders(); + headers.set(HEADER_TENANT, tenantId); + headers.set(HEADER_CLIENTCORRELATIONID, (String) variables.get("X-CorrelationID")); + headers.set(HEADER_BILLER_ID, (String) variables.get("billerId")); + headers.setContentType(MediaType.APPLICATION_JSON); + PayerRTPResponse payerRTPResponse = createMockBody(billId, transactionId); + + + HttpEntity request = new HttpEntity<>(payerRTPResponse, headers); + + + ResponseEntity response = restTemplate.exchange( + callbackUrl, + HttpMethod.PUT, + request, + ResponseDTO.class + ); + client.newCompleteCommand(job.getKey()).variables(variables).send(); + }); + } + public PayerRTPResponse createMockBody(String billId, String transactionId){ + PayerRTPResponse payerRTPResponse = new PayerRTPResponse(); + payerRTPResponse.setBillId(billId); + payerRTPResponse.setTxnId(transactionId); + payerRTPResponse.setRtpStatus("00"); + payerRTPResponse.setRejectReason(""); + return payerRTPResponse; + + } + +} diff --git a/ph-ee-connector-bulk/src/main/resources/application.yaml b/ph-ee-connector-bulk/src/main/resources/application.yaml new file mode 100644 index 000000000..c1eaf9f1e --- /dev/null +++ b/ph-ee-connector-bulk/src/main/resources/application.yaml @@ -0,0 +1,97 @@ +camel: + server-port: 5000 + disable-ssl: false + springboot: + main-run-controller: true + dataformat: + json-jackson: + auto-discover-object-mapper: true + +server: + port: 8080 + +zeebe: + client: + max-execution-threads: 100 + number-of-workers: 8 + evenly-allocated-max-jobs: "#{${zeebe.client.max-execution-threads} / ${zeebe.client.number-of-workers}}" + ttl: 30000 + max-jobs-active: 2000 + broker: + contactpoint: "127.0.0.1:26500" + + +cloud: + aws: + enabled: true + s3BaseUrl: "https://s3.ap-south-1.amazonaws.com" + credentials: + access-key: ${AWS_ACCESS_KEY:access_key_from_aws} + secret-key: ${AWS_SECRET_KEY:secret_key_from_aws} + region: + static: ap-south-1 + stack: + auto: false + + +config: + completion-threshold-check: + completion-threshold: 90 + max-retry-count: 10 + wait-timer: PT10S + date-format: "yyyy-MM-dd'T'hh:mm:ssXXX" + reconciliation: + enable: false + +dfspids: "DFSPID" + + +operations-app: + contactpoint: "https://ops-bk.sandbox.mifos.io" + username: "mifos" + password: "password" + endpoints: + auth: "/oauth/token" + batch-summary: "/api/v1/batch" + batch-detail: "/api/v1/batch/detail" + +mock-payment-schema: + contactpoint: "http://ph-ee-connector-mock-payment-schema:8080" + endpoints: + batch-summary: "/mockapi/v1/batch/summary" + batch-detail: "/mockapi/v1/batch/detail" + +bulk-processor: + contactpoint: "https://ph-ee-processor-bulk:8443" + endpoints: + batch-transaction: "/batchtransactions" + +payment-mode: + default: "MOJALOOP" + mappings: + - id: "GSMA" + type: "PAYMENT" + endpoint: "/channel/gsma/transfer" + - id: "MOJALOOP" + type: "PAYMENT" + endpoint: "/channel/transfer" + - id: "SLCB" + type: "BULK" + endpoint: "bulk_connector_{MODE}-{dfspid}" + - id: "CLOSEDLOOP" + type: "BULK" + endpoint: "bulk_connector_{MODE}-{dfspid}" + +application: + bucket-name: paymenthub-ee + +tenant: "rhino" + +bill-pay: + contactpoint: "http://ph-ee-connector-bill-pay:8080" + endpoint: + +json_web_signature: + privateKey: "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC07fxdEQlsvWvggBgrork401cdyZ9MqV6FF/RgX6+Om23gP/rME5sE5//OoG61KU3dEj9phcHH845TuyNEyc4Vhqxe1gzl4VIZkOj+/2qxYvCsP1Sv3twTs+fDfFv5NA1ZXqiswTlgjR2Lpf1tevFQEOzB9WYvH/Bu9kgr2AlHMPV6+b7gcJij/7W1hndiCk2ahbi7oXjjODF4yEU9yNAhopibe4zzMX+FO4eFYpUmrjS5wvv6aAanfoeIMTwhF81Gj9V3rHf4UsD3VEx773q7GPuXlZSLyiNrUCdvxITh+dW8Y9ICuCTy3bFbp1/HzoPdzkkUlzPNKLlLiV2w4EcxAgMBAAECggEAMjqHfwbFyQxlMHQfQa3xIdd6LejVcqDqfqSB0Wd/A2YfAMyCQbmHpbsKh0B+u4h191OjixX5EBuLfa9MQUKNFejHXaSq+/6rnjFenbwm0IwZKJiEWDbUfhvJ0blqhypuMktXJG6YETfb5fL1AjnJWGL6d3Y7IgYJ56QzsQhOuxZidSqw468xc4sIF0CoTeJdrSC2yDCVuVlLNifm/2SXBJD8mgc1WCz0rkJhvvpW4k5G9rRSkS5f0013ZNfsfiDXoqiKkafoYNEbk7TZQNInqSuONm/UECn5GLm6IXdXSGfm1O2Lt0Kk7uxW/3W00mIPeZD+hiOObheRm/2HoOEKiQKBgQDreVFQihXAEDviIB2s6fphvPcMw/IonE8tX565i3303ubQMDIyZmsi3apN5pqSjm1TKq1KIgY2D4vYTu6vO5x9MhEO2CCZWNwC+awrIYa32FwiT8D8eZ9g+DJ4/IwXyz1fG38RCz/eIsJ0NsS9z8RKBIbfMmM+WnXRez3Fq+cbRwKBgQDEs35qXThbbFUYo1QkO0vIo85iczu9NllRxo1nAqQkfu1oTYQQobxcGk/aZk0B02r9kt2eob8zfG+X3LadIhQ0/LalnGNKI9jWLkdW4dxi7xMU99MYc3NRXmR49xGxgOVkLzKyGMisUvkTnE5v/S1nhu5uFr3JPkWcCScLOTjVxwKBgHNWsDq3+GFkUkC3pHF/BhJ7wbLyA5pavfmmnZOavO6FhB8zjFLdkdq5IuMXcl0ZAHm9LLZkJhCy2rfwKb+RflxgerR/rrAOM24Np4RU3q0MgEyaLhg85pFT4T0bzu8UsRH14O6TSQxgkEjmTsX+j9IFl56aCryPCKi8Kgy53/CfAoGAdV2kUFLPDb3WCJ1r1zKKRW1398ZKHtwO73xJYu1wg1Y40cNuyX23pj0M6IOh7zT24dZ/5ecc7tuQukw3qgprhDJFyQtHMzWwbBuw9WZO2blM6XX1vuEkLajkykihhggi12RSG3IuSqQ3ejwJkUi/jsYz/fwTwcAmSLQtV8UM5IECgYEAh4h1EkMx3NXzVFmLsb4QLMXw8+Rnn9oG+NGObldQ+nmknUPu7iz5kl9lTJy+jWtqHlHL8ZtV1cZZSZnFxX5WQH5/lcz/UD+GqWoSlWuTU34PPTJqLKSYgkoOJQDEZVMVphLySS9tuo+K/h10lRS1r9KDm3RZASa1JnnWopBZIz4=" + x509Certificate: "MIIDvDCCAqQCCQDZK/l5vKIt7jANBgkqhkiG9w0BAQsFADCBnzELMAkGA1UEBhMCSU4xEjAQBgNVBAgMCUtBUk5BVEFLQTETMBEGA1UEBwwKRE9NQVNBTkRSQTERMA8GA1UECgwIRllOQVJGSU4xFDASBgNVBAsMC0RFVkVMT1BNRU5UMR0wGwYDVQQDDBRodHRwczovL2Z5bmFyZmluLmlvLzEfMB0GCSqGSIb3DQEJARYQYXZpa0BmeW5hcmZpbi5pbzAeFw0yMzA0MDUwNjExMDNaFw0yMzA1MDUwNjExMDNaMIGfMQswCQYDVQQGEwJJTjESMBAGA1UECAwJS0FSTkFUQUtBMRMwEQYDVQQHDApET01BU0FORFJBMREwDwYDVQQKDAhGWU5BUkZJTjEUMBIGA1UECwwLREVWRUxPUE1FTlQxHTAbBgNVBAMMFGh0dHBzOi8vZnluYXJmaW4uaW8vMR8wHQYJKoZIhvcNAQkBFhBhdmlrQGZ5bmFyZmluLmlvMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtO38XREJbL1r4IAYK6K5ONNXHcmfTKlehRf0YF+vjptt4D/6zBObBOf/zqButSlN3RI/aYXBx/OOU7sjRMnOFYasXtYM5eFSGZDo/v9qsWLwrD9Ur97cE7Pnw3xb+TQNWV6orME5YI0di6X9bXrxUBDswfVmLx/wbvZIK9gJRzD1evm+4HCYo/+1tYZ3YgpNmoW4u6F44zgxeMhFPcjQIaKYm3uM8zF/hTuHhWKVJq40ucL7+mgGp36HiDE8IRfNRo/Vd6x3+FLA91RMe+96uxj7l5WUi8oja1Anb8SE4fnVvGPSArgk8t2xW6dfx86D3c5JFJczzSi5S4ldsOBHMQIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQBPhTd+DhzbUGqAvsU6T34Iu3k+6Br4N6m90dkvBeMgYL8J7J6Fa7hm7f6xEeDqM+RTPhuFXNlS5swjqUYg/j85jKqVtgYAB6IE7z7BTwBAtF4tJ+jVOV4PfS/lSqvfxwo/qThqU1iXFz9xU38zlqxH5JuWZjeV58uUP/vZC8Ys44RDhU4X1qDbt51Vs8E+DeV1A4aweoEVc/txEdShbxnR2MVpPpca1NOElYW2cTAWjJypgw5bJZX4G0gZmHCZhQtgXSIMC1KSqMM7DK+HA7xTfKNJ+vnD08FOzBAb6nl2cHVb/zySdNWwsPu6w3FmzgFit9Hq2zE2F41167GvRBEL" + diff --git a/ph-ee-connector-channel/.circleci/config.yml b/ph-ee-connector-channel/.circleci/config.yml new file mode 100644 index 000000000..8d01dc29a --- /dev/null +++ b/ph-ee-connector-channel/.circleci/config.yml @@ -0,0 +1,263 @@ +version: 2.1 +orbs: + slack: circleci/slack@4.12.5 + aws-ecr: circleci/aws-ecr@8.2.1 + helm: circleci/helm@2.0.1 + aws-eks: circleci/aws-eks@2.2.0 + kubernetes: circleci/kubernetes@1.3 + fynarfin-orb: fynarfin/docker-image-availability-check-and-upgrade@1.0.0 +executors: + docker-executor: + docker: + - image: circleci/openjdk:17-buster-node-browsers-legacy + auth: + username: $DOCKERHUB_USERNAME + password: $DOCKERHUB_PASSWORD + +jobs: + build_and_push_tag_image: + executor: docker-executor + environment: + JVM_OPTS: -Xmx512m + TERM: dumb + GITHUB_TOKEN: ${GITHUB_TOKEN} # Add the GitHub token as an environment variable + + steps: + - checkout + - setup_remote_docker: + version: 20.10.14 + - run: + name: Build and Push Docker tag Image + command: | + # Set environment variables + IMAGE_TAG=$CIRCLE_TAG + + # Check if the Docker image with the same tag already exists in Docker Hub + if curl -s -f -u "$DOCKERHUB_USERNAME":"$DOCKERHUB_PASSWORD" "https://hub.docker.com/v2/repositories/fynarfin/ph-ee-connector-channel/tags/$IMAGE_TAG" > /dev/null; then + echo "Skipping the build and push as the tag $IMAGE_TAG already exists in Docker Hub." + exit 0 + fi + + # Build and tag the Docker image + ./gradlew bootJar + docker build -t "fynarfin/ph-ee-connector-channel:$IMAGE_TAG" . + + # Push the Docker image to Docker Hub + docker login -u "$DOCKERHUB_USERNAME" -p "$DOCKERHUB_PASSWORD" + docker push "fynarfin/ph-ee-connector-channel:$IMAGE_TAG" + + # when: always # The job will be executed even if there's no match for the tag filter + + build_and_push_latest_image: + executor: docker-executor + environment: + JVM_OPTS: -Xmx512m + TERM: dumb + + steps: + - checkout + # Install Docker to build and push the image + - setup_remote_docker: + version: 20.10.14 + - kubernetes/install-kubectl + - checkout + - aws-eks/update-kubeconfig-with-authenticator: + cluster-name: "sit" + aws-region: "$REGION" + # Build the Docker image + - run: + name: Build Docker image + command: | + #Check for PR title Validity + ./gradlew checkstyleMain + ./gradlew clean bootJar + docker build -t fynarfin/ph-ee-connector-channel:latest . + if [ "$CIRCLE_BRANCH" != "develop" ]; then + PR_NUMBER=$(basename $CIRCLE_PULL_REQUEST) + PR_TITLE=$(curl -sSL "https://api.github.com/repos/fynarfin/$CIRCLE_PROJECT_REPONAME/pulls/$PR_NUMBER" | jq -r '.title') + JIRA_STORY=$(echo $PR_TITLE | cut -d "[" -f2 | cut -d "]" -f1 | tr '[A-Z]' '[a-z]') + if [ -z "$JIRA_STORY" ]; then echo "Invalid PR title" && exit 1; else echo "Ticket NO: $JIRA_STORY"; fi + docker image tag fynarfin/$CIRCLE_PROJECT_REPONAME:latest fynarfin/$CIRCLE_PROJECT_REPONAME:$JIRA_STORY + fi + # Log in to DockerHub using environment variables + - run: + name: Login to DockerHub + command: echo "${DOCKERHUB_PASSWORD}" | docker login -u "${DOCKERHUB_USERNAME}" --password-stdin + + # Push the Docker image to DockerHub + - run: + name: Push Docker image to DockerHub + command: | + if [ "$CIRCLE_BRANCH" = "develop" ]; then + docker push fynarfin/ph-ee-connector-channel:latest + fi + if [ "$CIRCLE_BRANCH" != "develop" ]; then + PR_NUMBER=$(basename $CIRCLE_PULL_REQUEST) + PR_TITLE=$(curl -sSL "https://api.github.com/repos/fynarfin/$CIRCLE_PROJECT_REPONAME/pulls/$PR_NUMBER" | jq -r '.title') + JIRA_STORY=$(echo $PR_TITLE | cut -d "[" -f2 | cut -d "]" -f1 | tr '[A-Z]' '[a-z]') + docker push fynarfin/$CIRCLE_PROJECT_REPONAME:${JIRA_STORY} + fi + docker-image-availability-check-and-upgrade: + docker: + - image: cimg/python:3.10 + steps: + - fynarfin-orb/docker-image-availability-check-and-upgrade: + namespace: paymenthub + chart-base-url: https://fynarfin.io/images + chart-name: ph-ee-g2psandbox-fynarfin + chart-version: 0.2.0 + release-name: g2p-sandbox + cluster-name: "sit" + aws-region: "$REGION" + service-file-path: https://raw.githubusercontent.com/fynarfin/ph-ee-env-labs/develop/.circleci/services.txt + build-and-host-engine: + docker: + - image: cimg/python:3.10 + working_directory: ~/repo + environment: + TERM: dumb + steps: + - run: git clone https://github.com/fynarfin/ph-ee-env-template + - run: rm -f helm/ph-ee-engine/Chart.lock helm/ph-ee-engine/requirements.lock helm/ph-ee-engine/charts/* + - helm/install-helm-client: + version: "v3.8.2" +# - run: "sed -i '2s/.*/appVersion: 0.0.0/' helm/ph-ee-engine/Chart.yaml" +# - run: "sed -i '5s/.*/version: 0.0.0-SNAPSHOT/' helm/ph-ee-engine/Chart.yaml" + - run: helm dep up ph-ee-env-template/helm/ph-ee-engine + - run: helm package ph-ee-env-template/helm/ph-ee-engine + - run: helm repo index . + - run: echo "$CERT_FILE" | base64 --decode > b64encoded.pem + - run: chmod 400 b64encoded.pem + - run: scp -o StrictHostKeyChecking=No -i b64encoded.pem index.yaml ph-ee-engine-0.0.0-SNAPSHOT.tgz ec2-user@13.233.68.128:~/ + - run: ssh -i b64encoded.pem -o StrictHostKeyChecking=No ec2-user@13.233.68.128 sudo cp -t /apps/apache-tomcat-7.0.82/webapps/ROOT/images/ph-ee-engine-0.0.0-SNAPSHOT index.yaml ph-ee-engine-0.0.0-SNAPSHOT.tgz + + build-and-host-g2p-sandbox: + docker: + - image: cimg/python:3.10 + working_directory: ~/repo + environment: + TERM: dumb + steps: + - run: git clone https://github.com/fynarfin/ph-ee-env-template + - run: rm -f ph-ee-env-template/helm/g2p-sandbox/Chart.lock ph-ee-env-template/helm/g2p-sandbox/requirements.lock ph-ee-env-template/helm/g2p-sandbox/charts/* + - helm/install-helm-client: + version: "v3.8.2" +# - run: "sed -i '6s/.*/appVersion: 0.0.0/' helm/g2p-sandbox/Chart.yaml" +# - run: "sed -i '7s/.*/version: 0.0.0/' helm/g2p-sandbox/Chart.yaml" + # - run: "sed -i '4s/.*/version: 0.0.0-SNAPSHOT/' helm/g2p-sandbox/requirements.yaml" + # SED & replace dependency with 0.0.0 + - run: helm dep up ph-ee-env-template/helm/g2p-sandbox + - run: helm package ph-ee-env-template/helm/g2p-sandbox + - run: helm repo index . + - run: echo "$CERT_FILE" | base64 --decode > b64encoded.pem + - run: chmod 400 b64encoded.pem + - run: scp -o StrictHostKeyChecking=No -i b64encoded.pem index.yaml ph-ee-g2psandbox-0.0.0.tgz ec2-user@13.233.68.128:~/ + - run: ssh -i b64encoded.pem -o StrictHostKeyChecking=No ec2-user@13.233.68.128 sudo cp -t /apps/apache-tomcat-7.0.82/webapps/ROOT/images/ph-ee-g2psandbox-0.0.0 index.yaml ph-ee-g2psandbox-0.0.0.tgz + + build-host-g2p-fyn-chart: + docker: + - image: cimg/python:3.10 + working_directory: ~/repo + environment: + TERM: dumb + steps: + - run: git clone https://github.com/fynarfin/ph-ee-env-labs + - run: rm -f ph-ee-env-labs/helm/g2p-sandbox-fynarfin-SIT/Chart.lock ph-ee-env-labs/helm/g2p-sandbox-fynarfin-SIT/requirements.lock ph-ee-env-labs/helm/g2p-sandbox-fynarfin-SIT/charts/* + - helm/install-helm-client: + version: "v3.8.2" + # - run: "sed -i '12s/.*/version: 0.0.0/' helm/g2p-sandbox-fynarfin-SIT/Chart.yaml" + - run: cat ph-ee-env-labs/helm/g2p-sandbox-fynarfin-SIT/Chart.yaml + - run: helm dep up ph-ee-env-labs/helm/g2p-sandbox-fynarfin-SIT + - run: helm package ph-ee-env-labs/helm/g2p-sandbox-fynarfin-SIT + - run: helm repo index . + - run: echo "$CERT_FILE" | base64 --decode > b64encoded.pem + - run: chmod 400 b64encoded.pem + - run: scp -o StrictHostKeyChecking=No -i b64encoded.pem index.yaml ph-ee-g2psandbox-fynarfin-0.2.0.tgz ec2-user@13.233.68.128:~/ + - run: ssh -i b64encoded.pem -o StrictHostKeyChecking=No ec2-user@13.233.68.128 sudo mv -t /apps/apache-tomcat-7.0.82/webapps/ROOT/images/ph-ee-g2psandbox-fynarfin index.yaml ph-ee-g2psandbox-fynarfin-0.2.0.tgz + + + test-chart-gov: + docker: + - image: cimg/openjdk:17.0.0 + steps: + - run: git clone https://github.com/fynarfin/ph-ee-integration-test + - run: + name: Ngrok setup + command: curl -s https://ngrok-agent.s3.amazonaws.com/ngrok.asc | sudo tee /etc/apt/trusted.gpg.d/ngrok.asc >/dev/null && echo "deb https://ngrok-agent.s3.amazonaws.com buster main" | sudo tee /etc/apt/sources.list.d/ngrok.list && sudo apt update && sudo apt install ngrok + - run: + name: Test execution + command: | + ngrok config add-authtoken $AUTH_TOKEN + echo "web_addr: $LOCAL_PORT" >> /home/circleci/.config/ngrok/ngrok.yml + ngrok http 53013 > /dev/null & + echo -n "Extracting ngrok public url ." + NGROK_PUBLIC_URL="" + while [ -z "$NGROK_PUBLIC_URL" ]; do + # Run 'curl' against ngrok API and extract public (using 'sed' command) + export NGROK_PUBLIC_URL=$(curl --silent --max-time 10 --connect-timeout 5 \ + --show-error http://127.0.0.1:$LOCAL_PORT/api/tunnels | \ + sed -nE 's/.*public_url":"https:..([^"]*).*/\1/p') + sleep 1 + echo -n "." + done + + export CALLBACK_URL="https://$NGROK_PUBLIC_URL" + echo -n "Public url ." + echo $CALLBACK_URL + cd ph-ee-integration-test && ./gradlew test -Dcucumber.filter.tags="@gov" + echo -n "Test execution is completed, kill ngrok" + pkill ngrok + - store_test_results: + path: ph-ee-integration-test/build/cucumber.xml + - store_artifacts: + path: ph-ee-integration-test/build/reports/tests/test + test-chart-ams: + docker: + - image: cimg/openjdk:17.0.0 + steps: + - run: git clone https://github.com/fynarfin/ph-ee-integration-test + - run: + name: Ngrok setup + command: curl -s https://ngrok-agent.s3.amazonaws.com/ngrok.asc | sudo tee /etc/apt/trusted.gpg.d/ngrok.asc >/dev/null && echo "deb https://ngrok-agent.s3.amazonaws.com buster main" | sudo tee /etc/apt/sources.list.d/ngrok.list && sudo apt update && sudo apt install ngrok + - run: + name: Test execution + command: | + ngrok config add-authtoken $AUTH_TOKEN + echo "web_addr: $LOCAL_PORT" >> /home/circleci/.config/ngrok/ngrok.yml + ngrok http 53013 > /dev/null & + echo -n "Extracting ngrok public url ." + NGROK_PUBLIC_URL="" + while [ -z "$NGROK_PUBLIC_URL" ]; do + # Run 'curl' against ngrok API and extract public (using 'sed' command) + export NGROK_PUBLIC_URL=$(curl --silent --max-time 10 --connect-timeout 5 \ + --show-error http://127.0.0.1:$LOCAL_PORT/api/tunnels | \ + sed -nE 's/.*public_url":"https:..([^"]*).*/\1/p') + sleep 1 + echo -n "." + done + + export CALLBACK_URL="https://$NGROK_PUBLIC_URL" + echo -n "Public url ." + echo $CALLBACK_URL + cd ph-ee-integration-test && ./gradlew test -Dcucumber.filter.tags="@amsIntegration" + echo -n "Test execution is completed, kill ngrok" + pkill ngrok + - store_test_results: + path: ph-ee-integration-test/build/cucumber.xml + - store_artifacts: + path: ph-ee-integration-test/build/reports/tests/test + +workflows: + version: 2 + build-and-push: + jobs: + - build_and_push_tag_image: + filters: + tags: + only: /^v\d+\.\d+\.\d+([-rc.0-9]+)*?$/ # Match tags in the format v1.2.3 + context: + - DOCKER + - build_and_push_latest_image: + context: + - DOCKER + - AWS diff --git a/ph-ee-connector-channel/.github/pull_request_template.md b/ph-ee-connector-channel/.github/pull_request_template.md new file mode 100644 index 000000000..1d44d4817 --- /dev/null +++ b/ph-ee-connector-channel/.github/pull_request_template.md @@ -0,0 +1,22 @@ +## Description + +* PR title should have jira ticket enclosed in `[]`.
+ Format: ``` [jira_ticket] description```
+ ex: [phee-123] PR title. +* Add a link to the Jira ticket. +* Describe the changes made and why they were made. + +## Checklist + +Please make sure these boxes are checked before submitting your pull request - thanks! +- [ ] Followed the PR title naming convention mentioned above. + +- [ ] Design related bullet points or design document link related to this PR added in the description above. + +- [ ] Updated corresponding Postman Collection or Api documentation for the changes in this PR. + +- [ ] Create/update unit or integration tests for verifying the changes made. + +- [ ] Add required Swagger annotation and update API documentation with details of any API changes if applicable + +- [ ] Followed the naming conventions as given in https://docs.google.com/document/d/1Q4vaMSzrTxxh9TS0RILuNkSkYCxotuYk1Xe0CMIkkCU/edit?usp=sharing diff --git a/ph-ee-connector-channel/.github/workflows/test.yaml b/ph-ee-connector-channel/.github/workflows/test.yaml new file mode 100644 index 000000000..0dd2612c9 --- /dev/null +++ b/ph-ee-connector-channel/.github/workflows/test.yaml @@ -0,0 +1,20 @@ +name: Test +on: [push, pull_request] +jobs: + Assemble: + runs-on: ubuntu-latest + steps: + - name: Check out repository code + uses: actions/checkout@v3 + with: + path: master + - name: Check out repository code + uses: actions/checkout@v3 + with: + repository: openmf/ph-ee-connector-integration-test + path: ph-ee-connector-integration-test + - name: Assemble project + run: ./gradlew clean build + - name: Build Docker image + run: docker build . -t paymenthubee.mifos.io/phee/connector-channel + diff --git a/ph-ee-connector-channel/.gitignore b/ph-ee-connector-channel/.gitignore new file mode 100644 index 000000000..80cab67c6 --- /dev/null +++ b/ph-ee-connector-channel/.gitignore @@ -0,0 +1,33 @@ +target/ +.gradle +build/ +!gradle/wrapper/gradle-wrapper.jar + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ + +### VS Code ### +.vscode/ + +### MAC +.DS_Store diff --git a/ph-ee-connector-channel/Dockerfile b/ph-ee-connector-channel/Dockerfile new file mode 100644 index 000000000..7477fba78 --- /dev/null +++ b/ph-ee-connector-channel/Dockerfile @@ -0,0 +1,5 @@ +FROM openjdk:17 +EXPOSE 8080 + +COPY build/libs/*.jar ./ +CMD java -jar *.jar diff --git a/ph-ee-connector-channel/Jenkinsfile b/ph-ee-connector-channel/Jenkinsfile new file mode 100644 index 000000000..dd54e0a96 --- /dev/null +++ b/ph-ee-connector-channel/Jenkinsfile @@ -0,0 +1,18 @@ +pipeline { + agent any + stages { + stage('build') { + steps { + sh 'mvn --version' + sh 'mvn -U clean package' + } + } + + stage('docker build and push') { + steps { + sh 'docker build . -t paymenthubee.azurecr.io/phee/connector-channel' + sh 'docker push paymenthubee.azurecr.io/phee/connector-channel' + } + } + } +} diff --git a/ph-ee-connector-channel/LICENSE b/ph-ee-connector-channel/LICENSE new file mode 100644 index 000000000..a612ad981 --- /dev/null +++ b/ph-ee-connector-channel/LICENSE @@ -0,0 +1,373 @@ +Mozilla Public License Version 2.0 +================================== + +1. Definitions +-------------- + +1.1. "Contributor" + means each individual or legal entity that creates, contributes to + the creation of, or owns Covered Software. + +1.2. "Contributor Version" + means the combination of the Contributions of others (if any) used + by a Contributor and that particular Contributor's Contribution. + +1.3. "Contribution" + means Covered Software of a particular Contributor. + +1.4. "Covered Software" + means Source Code Form to which the initial Contributor has attached + the notice in Exhibit A, the Executable Form of such Source Code + Form, and Modifications of such Source Code Form, in each case + including portions thereof. + +1.5. "Incompatible With Secondary Licenses" + means + + (a) that the initial Contributor has attached the notice described + in Exhibit B to the Covered Software; or + + (b) that the Covered Software was made available under the terms of + version 1.1 or earlier of the License, but not also under the + terms of a Secondary License. + +1.6. "Executable Form" + means any form of the work other than Source Code Form. + +1.7. "Larger Work" + means a work that combines Covered Software with other material, in + a separate file or files, that is not Covered Software. + +1.8. "License" + means this document. + +1.9. "Licensable" + means having the right to grant, to the maximum extent possible, + whether at the time of the initial grant or subsequently, any and + all of the rights conveyed by this License. + +1.10. "Modifications" + means any of the following: + + (a) any file in Source Code Form that results from an addition to, + deletion from, or modification of the contents of Covered + Software; or + + (b) any new file in Source Code Form that contains any Covered + Software. + +1.11. "Patent Claims" of a Contributor + means any patent claim(s), including without limitation, method, + process, and apparatus claims, in any patent Licensable by such + Contributor that would be infringed, but for the grant of the + License, by the making, using, selling, offering for sale, having + made, import, or transfer of either its Contributions or its + Contributor Version. + +1.12. "Secondary License" + means either the GNU General Public License, Version 2.0, the GNU + Lesser General Public License, Version 2.1, the GNU Affero General + Public License, Version 3.0, or any later versions of those + licenses. + +1.13. "Source Code Form" + means the form of the work preferred for making modifications. + +1.14. "You" (or "Your") + means an individual or a legal entity exercising rights under this + License. For legal entities, "You" includes any entity that + controls, is controlled by, or is under common control with You. For + purposes of this definition, "control" means (a) the power, direct + or indirect, to cause the direction or management of such entity, + whether by contract or otherwise, or (b) ownership of more than + fifty percent (50%) of the outstanding shares or beneficial + ownership of such entity. + +2. License Grants and Conditions +-------------------------------- + +2.1. Grants + +Each Contributor hereby grants You a world-wide, royalty-free, +non-exclusive license: + +(a) under intellectual property rights (other than patent or trademark) + Licensable by such Contributor to use, reproduce, make available, + modify, display, perform, distribute, and otherwise exploit its + Contributions, either on an unmodified basis, with Modifications, or + as part of a Larger Work; and + +(b) under Patent Claims of such Contributor to make, use, sell, offer + for sale, have made, import, and otherwise transfer either its + Contributions or its Contributor Version. + +2.2. Effective Date + +The licenses granted in Section 2.1 with respect to any Contribution +become effective for each Contribution on the date the Contributor first +distributes such Contribution. + +2.3. Limitations on Grant Scope + +The licenses granted in this Section 2 are the only rights granted under +this License. No additional rights or licenses will be implied from the +distribution or licensing of Covered Software under this License. +Notwithstanding Section 2.1(b) above, no patent license is granted by a +Contributor: + +(a) for any code that a Contributor has removed from Covered Software; + or + +(b) for infringements caused by: (i) Your and any other third party's + modifications of Covered Software, or (ii) the combination of its + Contributions with other software (except as part of its Contributor + Version); or + +(c) under Patent Claims infringed by Covered Software in the absence of + its Contributions. + +This License does not grant any rights in the trademarks, service marks, +or logos of any Contributor (except as may be necessary to comply with +the notice requirements in Section 3.4). + +2.4. Subsequent Licenses + +No Contributor makes additional grants as a result of Your choice to +distribute the Covered Software under a subsequent version of this +License (see Section 10.2) or under the terms of a Secondary License (if +permitted under the terms of Section 3.3). + +2.5. Representation + +Each Contributor represents that the Contributor believes its +Contributions are its original creation(s) or it has sufficient rights +to grant the rights to its Contributions conveyed by this License. + +2.6. Fair Use + +This License is not intended to limit any rights You have under +applicable copyright doctrines of fair use, fair dealing, or other +equivalents. + +2.7. Conditions + +Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted +in Section 2.1. + +3. Responsibilities +------------------- + +3.1. Distribution of Source Form + +All distribution of Covered Software in Source Code Form, including any +Modifications that You create or to which You contribute, must be under +the terms of this License. You must inform recipients that the Source +Code Form of the Covered Software is governed by the terms of this +License, and how they can obtain a copy of this License. You may not +attempt to alter or restrict the recipients' rights in the Source Code +Form. + +3.2. Distribution of Executable Form + +If You distribute Covered Software in Executable Form then: + +(a) such Covered Software must also be made available in Source Code + Form, as described in Section 3.1, and You must inform recipients of + the Executable Form how they can obtain a copy of such Source Code + Form by reasonable means in a timely manner, at a charge no more + than the cost of distribution to the recipient; and + +(b) You may distribute such Executable Form under the terms of this + License, or sublicense it under different terms, provided that the + license for the Executable Form does not attempt to limit or alter + the recipients' rights in the Source Code Form under this License. + +3.3. Distribution of a Larger Work + +You may create and distribute a Larger Work under terms of Your choice, +provided that You also comply with the requirements of this License for +the Covered Software. If the Larger Work is a combination of Covered +Software with a work governed by one or more Secondary Licenses, and the +Covered Software is not Incompatible With Secondary Licenses, this +License permits You to additionally distribute such Covered Software +under the terms of such Secondary License(s), so that the recipient of +the Larger Work may, at their option, further distribute the Covered +Software under the terms of either this License or such Secondary +License(s). + +3.4. Notices + +You may not remove or alter the substance of any license notices +(including copyright notices, patent notices, disclaimers of warranty, +or limitations of liability) contained within the Source Code Form of +the Covered Software, except that You may alter any license notices to +the extent required to remedy known factual inaccuracies. + +3.5. Application of Additional Terms + +You may choose to offer, and to charge a fee for, warranty, support, +indemnity or liability obligations to one or more recipients of Covered +Software. However, You may do so only on Your own behalf, and not on +behalf of any Contributor. You must make it absolutely clear that any +such warranty, support, indemnity, or liability obligation is offered by +You alone, and You hereby agree to indemnify every Contributor for any +liability incurred by such Contributor as a result of warranty, support, +indemnity or liability terms You offer. You may include additional +disclaimers of warranty and limitations of liability specific to any +jurisdiction. + +4. Inability to Comply Due to Statute or Regulation +--------------------------------------------------- + +If it is impossible for You to comply with any of the terms of this +License with respect to some or all of the Covered Software due to +statute, judicial order, or regulation then You must: (a) comply with +the terms of this License to the maximum extent possible; and (b) +describe the limitations and the code they affect. Such description must +be placed in a text file included with all distributions of the Covered +Software under this License. Except to the extent prohibited by statute +or regulation, such description must be sufficiently detailed for a +recipient of ordinary skill to be able to understand it. + +5. Termination +-------------- + +5.1. The rights granted under this License will terminate automatically +if You fail to comply with any of its terms. However, if You become +compliant, then the rights granted under this License from a particular +Contributor are reinstated (a) provisionally, unless and until such +Contributor explicitly and finally terminates Your grants, and (b) on an +ongoing basis, if such Contributor fails to notify You of the +non-compliance by some reasonable means prior to 60 days after You have +come back into compliance. Moreover, Your grants from a particular +Contributor are reinstated on an ongoing basis if such Contributor +notifies You of the non-compliance by some reasonable means, this is the +first time You have received notice of non-compliance with this License +from such Contributor, and You become compliant prior to 30 days after +Your receipt of the notice. + +5.2. If You initiate litigation against any entity by asserting a patent +infringement claim (excluding declaratory judgment actions, +counter-claims, and cross-claims) alleging that a Contributor Version +directly or indirectly infringes any patent, then the rights granted to +You by any and all Contributors for the Covered Software under Section +2.1 of this License shall terminate. + +5.3. In the event of termination under Sections 5.1 or 5.2 above, all +end user license agreements (excluding distributors and resellers) which +have been validly granted by You or Your distributors under this License +prior to termination shall survive termination. + +************************************************************************ +* * +* 6. Disclaimer of Warranty * +* ------------------------- * +* * +* Covered Software is provided under this License on an "as is" * +* basis, without warranty of any kind, either expressed, implied, or * +* statutory, including, without limitation, warranties that the * +* Covered Software is free of defects, merchantable, fit for a * +* particular purpose or non-infringing. The entire risk as to the * +* quality and performance of the Covered Software is with You. * +* Should any Covered Software prove defective in any respect, You * +* (not any Contributor) assume the cost of any necessary servicing, * +* repair, or correction. This disclaimer of warranty constitutes an * +* essential part of this License. No use of any Covered Software is * +* authorized under this License except under this disclaimer. * +* * +************************************************************************ + +************************************************************************ +* * +* 7. Limitation of Liability * +* -------------------------- * +* * +* Under no circumstances and under no legal theory, whether tort * +* (including negligence), contract, or otherwise, shall any * +* Contributor, or anyone who distributes Covered Software as * +* permitted above, be liable to You for any direct, indirect, * +* special, incidental, or consequential damages of any character * +* including, without limitation, damages for lost profits, loss of * +* goodwill, work stoppage, computer failure or malfunction, or any * +* and all other commercial damages or losses, even if such party * +* shall have been informed of the possibility of such damages. This * +* limitation of liability shall not apply to liability for death or * +* personal injury resulting from such party's negligence to the * +* extent applicable law prohibits such limitation. Some * +* jurisdictions do not allow the exclusion or limitation of * +* incidental or consequential damages, so this exclusion and * +* limitation may not apply to You. * +* * +************************************************************************ + +8. Litigation +------------- + +Any litigation relating to this License may be brought only in the +courts of a jurisdiction where the defendant maintains its principal +place of business and such litigation shall be governed by laws of that +jurisdiction, without reference to its conflict-of-law provisions. +Nothing in this Section shall prevent a party's ability to bring +cross-claims or counter-claims. + +9. Miscellaneous +---------------- + +This License represents the complete agreement concerning the subject +matter hereof. If any provision of this License is held to be +unenforceable, such provision shall be reformed only to the extent +necessary to make it enforceable. Any law or regulation which provides +that the language of a contract shall be construed against the drafter +shall not be used to construe this License against a Contributor. + +10. Versions of the License +--------------------------- + +10.1. New Versions + +Mozilla Foundation is the license steward. Except as provided in Section +10.3, no one other than the license steward has the right to modify or +publish new versions of this License. Each version will be given a +distinguishing version number. + +10.2. Effect of New Versions + +You may distribute the Covered Software under the terms of the version +of the License under which You originally received the Covered Software, +or under the terms of any subsequent version published by the license +steward. + +10.3. Modified Versions + +If you create software not governed by this License, and you want to +create a new license for such software, you may create and use a +modified version of this License if you rename the license and remove +any references to the name of the license steward (except to note that +such modified license differs from this License). + +10.4. Distributing Source Code Form that is Incompatible With Secondary +Licenses + +If You choose to distribute Source Code Form that is Incompatible With +Secondary Licenses under the terms of this version of the License, the +notice described in Exhibit B of this License must be attached. + +Exhibit A - Source Code Form License Notice +------------------------------------------- + + This Source Code Form is subject to the terms of the Mozilla Public + License, v. 2.0. If a copy of the MPL was not distributed with this + file, You can obtain one at http://mozilla.org/MPL/2.0/. + +If it is not possible or desirable to put the notice in a particular +file, then You may include the notice in a location (such as a LICENSE +file in a relevant directory) where a recipient would be likely to look +for such a notice. + +You may add additional accurate notices of copyright ownership. + +Exhibit B - "Incompatible With Secondary Licenses" Notice +--------------------------------------------------------- + + This Source Code Form is "Incompatible With Secondary Licenses", as + defined by the Mozilla Public License, v. 2.0. diff --git a/ph-ee-connector-channel/README.md b/ph-ee-connector-channel/README.md new file mode 100644 index 000000000..62583ca5d --- /dev/null +++ b/ph-ee-connector-channel/README.md @@ -0,0 +1,15 @@ +# payment-hub-ee +Payment Hub Enterprise Edition middleware for integration to real-time payment systems. +#Auto-Trigger + +# Checkstyle +Use below command to execute the checkstyle test. +```shell +./gradlew checkstyleMain +``` + +## Spotless +Use below command to execute the spotless apply. +```shell +./gradlew spotlessApply +``` diff --git a/ph-ee-connector-channel/build.gradle b/ph-ee-connector-channel/build.gradle new file mode 100644 index 000000000..5325a6cd2 --- /dev/null +++ b/ph-ee-connector-channel/build.gradle @@ -0,0 +1,328 @@ +/* + * This file was generated by the Gradle 'init' task. + */ + +plugins { + id 'java' + id 'maven-publish' + id 'eclipse' + id 'checkstyle' + id 'org.springframework.boot' version '2.6.2' + id 'com.diffplug.spotless' version '6.19.0' + id 'net.ltgt.errorprone' version '3.1.0' + id("org.springdoc.openapi-gradle-plugin") version "1.9.0" +} + +openApi { + apiDocsUrl.set("http://channel.sandbox.fynarfin.io//v3/api-docs") + outputDir.set(file("src/main/java/docs")) + outputFileName.set("channel-api-swagger.json") +} + +repositories { + mavenLocal() + maven { + url = uri('https://repo.maven.apache.org/maven2') + } + + maven { + url = uri('https://jfrog.sandbox.fynarfin.io/artifactory/fyn-libs-snapshot') + } +} + +apply plugin:'com.diffplug.spotless' +spotless { + format 'misc', { + target '**/*.md', '**/*.properties', '**/.gitignore', '**/.openapi-generator-ignore', '**/*.yml', '**/*.xml', '**/**.json', '**/*.sql' + targetExclude '**/build/**','**/gsmastub/**', '**/bin/**', '**/.settings/**', '**/.idea/**', '**/.gradle/**', '**/gradlew.bat', '**/licenses/**', '**/banner.txt', '.vscode/**' + indentWithSpaces(4) + endWithNewline() + trimTrailingWhitespace() + } + + groovyGradle { + target '*.gradle', '**/*.gradle' + targetExclude '**/build/**', '**/gsmastub/**' + greclipse() + indentWithSpaces(4) + endWithNewline() + trimTrailingWhitespace() + } + + lineEndings 'UNIX' +} + +ext { + springBootVersion = '2.6.2' +} + +dependencies { + implementation 'com.google.code.gson:gson:2.8.9' + implementation 'org.mifos:ph-ee-connector-common:1.10.0-SNAPSHOT' + implementation 'org.apache.camel.springboot:camel-spring-boot-starter:3.12.0' + implementation "org.springframework.boot:spring-boot-starter:$springBootVersion" + implementation "org.springframework.boot:spring-boot-starter-web:$springBootVersion" + implementation "org.springframework.boot:spring-boot-starter-actuator:$springBootVersion" + implementation 'org.apache.camel:camel-endpointdsl:3.12.0' + implementation 'org.apache.camel:camel-jetty:3.12.0' + implementation 'org.apache.camel:camel-http:3.12.0' + implementation 'org.springframework:spring-web:5.3.15' + implementation 'org.apache.camel:camel-bean-validator:3.12.0' + implementation 'org.apache.camel:camel-undertow:3.12.0' + implementation 'org.apache.camel.springboot:camel-jackson-starter:3.12.0' + implementation 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.13.1' + implementation 'org.json:json:20211205' + implementation 'io.camunda:zeebe-client-java:8.1.1' + testImplementation 'org.springframework.boot:spring-boot-starter-test:2.6.2' + testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.2' + testImplementation 'org.junit.jupiter:junit-jupiter-engine:5.8.2' + testImplementation 'org.springframework.boot:spring-boot-starter-test:2.6.2' + testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.2' + testImplementation 'org.junit.jupiter:junit-jupiter-engine:5.8.2' + implementation 'javax.servlet:javax.servlet-api:3.1.0' + implementation 'commons-codec:commons-codec:1.15' + implementation 'commons-io:commons-io:2.11.0' + implementation ("org.apache.camel:camel-spring-redis:3.12.0") + implementation "org.springframework.boot:spring-boot-starter-data-redis:2.6.2" + implementation 'io.springfox:springfox-swagger-ui:3.0.0' + implementation 'io.springfox:springfox-oas:3.0.0' + implementation 'com.github.joschi.jackson:jackson-datatype-threetenbp:2.6.4' + implementation "org.springdoc:springdoc-openapi-ui:1.6.11" + implementation 'org.projectlombok:lombok:1.18.22' + annotationProcessor 'org.projectlombok:lombok:1.18.24' + checkstyle 'com.puppycrawl.tools:checkstyle:10.9.3' + checkstyle 'com.github.sevntu-checkstyle:sevntu-checks:1.44.1' + implementation 'com.diffplug.gradle.spotless:spotless:2.4.1' + implementation 'com.diffplug.spotless:spotless-plugin-gradle:6.17.0' + implementation 'org.springframework.boot:spring-boot-starter-webflux:2.4.1' + implementation 'org.springdoc:springdoc-openapi-ui:1.5.12' + implementation 'org.springdoc:springdoc-openapi-data-rest:1.5.12' +} + +configure(this) { + // NOTE: order matters! + apply plugin: 'java' + apply plugin: 'idea' + apply plugin: 'eclipse' + apply plugin: 'checkstyle' + apply plugin: 'net.ltgt.errorprone' + configurations { + implementation.setCanBeResolved(true) + api.setCanBeResolved(true) + } + tasks.withType(JavaCompile) { + options.compilerArgs += [ + "-Xlint:unchecked", + "-Xlint:cast", + "-Xlint:auxiliaryclass", + "-Xlint:deprecation", + "-Xlint:dep-ann", + "-Xlint:divzero", + "-Xlint:empty", + "-Xlint:exports", + "-Xlint:fallthrough", + "-Xlint:finally", + "-Xlint:module", + "-Xlint:opens", + "-Xlint:options", + "-Xlint:overloads", + "-Xlint:overrides", + "-Xlint:path", + "-Xlint:processing", + "-Xlint:removal", + "-Xlint:requires-automatic", + "-Xlint:requires-transitive-automatic", + "-Xlint:try", + "-Xlint:varargs", + "-Xlint:preview", + "-Xlint:static", + // -Werror needs to be disabled because EclipseLink's static weaving doesn't generate warning-free code + // and during an IntelliJ recompilation, it fails + //"-Werror", + "-Xmaxwarns", + 1500, + "-Xmaxerrs", + 1500 + ] + options.deprecation = true + } + // Configuration for the spotless plugin + // https://github.com/diffplug/spotless/tree/main/plugin-gradle + spotless { + java { + targetExclude '**/build/**', '**/bin/**', '**/out/**', '**/gsmastub/**' + importOrder() //sort imports alphabetically + removeUnusedImports() + eclipse().configFile "$rootDir/ph-ee-connector-channel/config/channel-formatter.xml" + endWithNewline() + trimTrailingWhitespace() + // Enforce style modifier order + custom 'Modifier ordering', { + def modifierRanking = [ + public : 1, + protected : 2, + private : 3, + abstract : 4, + default : 5, + static : 6, + final : 7, + transient : 8, + volatile : 9, + synchronized: 10, + native : 11, + strictfp : 12] + // Find any instance of multiple modifiers. Lead with a non-word character to avoid + // accidental matching against for instance, "an alternative default value" + it.replaceAll(/\W(?:public |protected |private |abstract |default |static |final |transient |volatile |synchronized |native |strictfp ){2,}/, { + // Do not replace the leading non-word character. Identify the modifiers + it.replaceAll(/(?:public |protected |private |abstract |default |static |final |transient |volatile |synchronized |native |strictfp ){2,}/, { + // Sort the modifiers according to the ranking above + it.split().sort({ modifierRanking[it] }).join(' ') + ' ' + } + ) + } + ) + } + } + lineEndings 'UNIX' + } + // If we are running Gradle within Eclipse to enhance classes, + // set the classes directory to point to Eclipse's default build directory + if (project.hasProperty('env') && project.getProperty('env') == 'eclipse') { + sourceSets.main.java.outputDir = file("$projectDir/bin/main") + } + // Configuration for the Checkstyle plugin + // https://docs.gradle.org/current/userguide/checkstyle_plugin.html + dependencies { + checkstyle 'com.puppycrawl.tools:checkstyle:10.3.1' + checkstyle 'com.github.sevntu-checkstyle:sevntu-checks:1.42.0' + } + // Configuration for the errorprone plugin + // https://github.com/tbroyer/gradle-errorprone-plugin + dependencies { + errorprone "com.google.errorprone:error_prone_core:2.20.0" + } + + tasks.withType(JavaCompile) { + options.errorprone { + enabled = project.gradle.startParameter.taskNames.contains('build') || project.gradle.startParameter.taskNames.contains('check') + disableWarningsInGeneratedCode = true + excludedPaths = ".*/build/.*" + excludedPaths = ".*/gsmastub/.*" + disable( + // TODO Remove disabled checks from this list, by fixing remaining usages + "UnusedVariable", + "TypeParameterUnusedInFormals", + "EmptyBlockTag", + "MissingSummary", + "InvalidParam", + "ReturnFromVoid", + "AlmostJavadoc", + "InvalidBlockTag", + "JavaUtilDate", // TODO FINERACT-1298 + "ReturnValueIgnored", + "DirectInvocationOnMock", + "CanIgnoreReturnValueSuggester", + "SameNameButDifferent", // Until errorprone recognizes Lombok + "MultiVariableDeclaration", // Until errorprone recognizes Lombok + "UnnecessaryDefaultInEnumSwitch" // FINERACT-1911 + ) + error( + "DefaultCharset", + "RemoveUnusedImports", + "WaitNotInLoop", + "ThreeLetterTimeZoneID", + "VariableNameSameAsType", + "UnnecessaryParentheses", + "MultipleTopLevelClasses", + "MixedMutabilityReturnType", + "AssertEqualsArgumentOrderChecker", + "EmptySetMultibindingContributions", + "BigDecimalEquals", + "MixedArrayDimensions", + "PackageLocation", + "UseBinds", + "BadImport", + "IntLongMath", + "FloatCast", + "ReachabilityFenceUsage", + "StreamResourceLeak", + "TruthIncompatibleType", + "ByteBufferBackingArray", + "OrphanedFormatString", + "CatchAndPrintStackTrace", + "ObjectToString", + "StringSplitter", + "AssertThrowsMultipleStatements", + "BoxedPrimitiveConstructor", + "EmptyCatch", + "BoxedPrimitiveEquality", + "SynchronizeOnNonFinalField", + "WildcardImport", + "PrivateConstructorForNoninstantiableModule", + "ClassCanBeStatic", + "ClassNewInstance", + "UnnecessaryStaticImport", + "UnsafeFinalization", + "JavaTimeDefaultTimeZone", + "JodaPlusMinusLong", + "SwitchDefault", + "VarTypeName", + "ArgumentSelectionDefectChecker", + "CompareToZero", + "InjectOnConstructorOfAbstractClass", + "ImmutableEnumChecker", + "NarrowingCompoundAssignment", + "MissingCasesInEnumSwitch", + "ReferenceEquality", + "UndefinedEquals", + "UnescapedEntity", + "ModifyCollectionInEnhancedForLoop", + "NonCanonicalType", + "InvalidInlineTag", + "MutablePublicArray", + "StaticAssignmentInConstructor", + "ProtectedMembersInFinalClass", + "OperatorPrecedence", + "EqualsGetClass", + "EqualsUnsafeCast", + "DoubleBraceInitialization", + "UnusedNestedClass", + "UnusedMethod", + "ModifiedButNotUsed", + "InconsistentCapitalization", + "MissingOverride", + ) + } + } +} + + +checkstyle { + checkstyleMain.exclude '**/gsmastub/**' +} + + + +group = 'org.mifos' +version = '1.0.0-SNAPSHOT' +sourceCompatibility = JavaVersion.VERSION_17 +targetCompatibility = JavaVersion.VERSION_17 + +test { + useJUnitPlatform() +} + +publishing { + publications { + maven(MavenPublication) { + from(components.java) + } + } +} + + + +tasks.withType(JavaCompile) { + options.encoding = 'UTF-8' +} diff --git a/ph-ee-connector-channel/config/channel-cleanup.xml b/ph-ee-connector-channel/config/channel-cleanup.xml new file mode 100644 index 000000000..0042addbb --- /dev/null +++ b/ph-ee-connector-channel/config/channel-cleanup.xml @@ -0,0 +1,71 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ph-ee-connector-channel/config/channel-formatter.xml b/ph-ee-connector-channel/config/channel-formatter.xml new file mode 100644 index 000000000..07085327a --- /dev/null +++ b/ph-ee-connector-channel/config/channel-formatter.xml @@ -0,0 +1,366 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ph-ee-connector-channel/config/checkstyle/checkstyle.xml b/ph-ee-connector-channel/config/checkstyle/checkstyle.xml new file mode 100644 index 000000000..5183efef5 --- /dev/null +++ b/ph-ee-connector-channel/config/checkstyle/checkstyle.xml @@ -0,0 +1,266 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ph-ee-connector-channel/config/checkstyle/suppressions.xml b/ph-ee-connector-channel/config/checkstyle/suppressions.xml new file mode 100644 index 000000000..f4e5b54c3 --- /dev/null +++ b/ph-ee-connector-channel/config/checkstyle/suppressions.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + diff --git a/ph-ee-connector-channel/gradle/wrapper/gradle-wrapper.jar b/ph-ee-connector-channel/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 000000000..41d9927a4 Binary files /dev/null and b/ph-ee-connector-channel/gradle/wrapper/gradle-wrapper.jar differ diff --git a/ph-ee-connector-channel/gradle/wrapper/gradle-wrapper.properties b/ph-ee-connector-channel/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 000000000..e750102e0 --- /dev/null +++ b/ph-ee-connector-channel/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-7.3-bin.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/ph-ee-connector-channel/gradlew b/ph-ee-connector-channel/gradlew new file mode 100755 index 000000000..1b6c78733 --- /dev/null +++ b/ph-ee-connector-channel/gradlew @@ -0,0 +1,234 @@ +#!/bin/sh + +# +# Copyright © 2015-2021 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit + +APP_NAME="Gradle" +APP_BASE_NAME=${0##*/} + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/ph-ee-connector-channel/gradlew.bat b/ph-ee-connector-channel/gradlew.bat new file mode 100644 index 000000000..ac1b06f93 --- /dev/null +++ b/ph-ee-connector-channel/gradlew.bat @@ -0,0 +1,89 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/ph-ee-connector-channel/guide_gsma_stub.md b/ph-ee-connector-channel/guide_gsma_stub.md new file mode 100644 index 000000000..92fd93787 --- /dev/null +++ b/ph-ee-connector-channel/guide_gsma_stub.md @@ -0,0 +1,113 @@ +# How to add GSMA server side STUB api from OAS + +### Step 1 - Import YAML + +Import the [OAS YAML file](https://www.gsma.com/mobilefordevelopment/mobile-money/mobile-money-api/) in [swagger hub](https://app.swaggerhub.com/). Make sure there is no change made in the YAML file before importing it in swagger hub. After success import you will get a screen something like this. + +Screenshot 2022-09-28 at 12 54 33 PM + + +### Step 2 - Update YAML +Remove all the existing `allOf` property from OAS yaml. +To achieve this task click on the editor section and use the find and replace feature(CTRL + F) to search for the existing `allOf` and replace it with empty string. +To bring the replace box click on the `+ plus` icon as shown in below screen shot. + +Screenshot 2022-09-28 at 12 54 33 PM + +Make sure you do not messes with the YAML syntax while making the above changes. To check this make sure the bottom bar always says the `VALID`, as shown in below screen shot. If any-time while making changes it shows `ERROR` then you can expand the bottom section to see the exact error and resolve it. + +Screenshot 2022-09-28 at 12 54 33 PM + +### Step 3 - Generate STUB Project +In the swagger hub page click on the `Export` :point_right: `Server Stub` :point_right: `Sring`. +As shown in the below screen shot. + +Screenshot 2022-09-28 at 12 54 33 PM + +Be patient after clicking on the `spring` since it can take some time to download the project. Once the donwload is complete you will find a file named `spring-server-generated.zip` in your donwload folder. Exatract it andn open in you favourite IDE or Intellij Idea which support spring java project. Make sure the build is succesfull. + +### Step 4 - Add Dependency In Channel Connector +Add below depedency in `channel-connector`, these dependency are borrowed from `spring-server-generated` project. +Sync the `channel-connector` gradle project and make sure all dependency resolves and build is success. + +```gradle +implementation 'io.springfox:springfox-swagger-ui:3.0.0' +implementation 'io.springfox:springfox-oas:3.0.0' +implementation 'com.github.joschi.jackson:jackson-datatype-threetenbp:2.6.4' +``` + +### Step 5 - Add APIs, Config and Model in Channel Connector + +Copy the packages `api`, `configuration` and `model` from `spring-server-generated` project and paste it inside the `channel-connector` under the package `org.mifos.connector.gsmastub`. +Also copy the `RFC3339DateFormat.java` file from `spring-server-generated` project and paste it in `channel-connector` under the package `org.mifos.connector.gsmastub`. + +Make sure all the imports are resolved in all the files in newly pasted packages `api`, `configuration` and `model`. + +### Step 6 - Update ChannelConnectorApplication.java + +Add date configuration for webMvc as mentioned below. +```java +@Configuration +static class CustomDateConfig implements WebMvcConfigurer { + @Override + public void addFormatters(FormatterRegistry registry) { + registry.addConverter(new LocalDateConverter("yyyy-MM-dd")); + registry.addConverter(new LocalDateTimeConverter("yyyy-MM-dd'T'HH:mm:ss.SSS")); + } +} +``` + +Add deserializer for type `Instant.class`, `OffsetDateTime.class`, `LocalDate.class` and `ZonedDateTime.class` in the existing `objectMapper` initializer. Refer below code snippet. + +```java +JavaTimeModule javaTimeModule = new JavaTimeModule(); +javaTimeModule.addDeserializer(Instant.class, CustomInstantDeserializer.INSTANT); +javaTimeModule.addDeserializer(OffsetDateTime.class, CustomInstantDeserializer.OFFSET_DATE_TIME); +javaTimeModule.addDeserializer(ZonedDateTime.class, CustomInstantDeserializer.ZONED_DATE_TIME); +javaTimeModule.addDeserializer(LocalDate.class, new CustomInstantDeserializer.LocalDateDeserializer()); +ObjectMapper objectMapper = new ObjectMapper(); +objectMapper.registerModule(javaTimeModule); +``` + +In case the deserializer is not generated for any of the type you can use below code snippet, as per your need. + +```java +public static class LocalDateDeserializer extends JsonDeserializer { + @Override + public LocalDate deserialize(JsonParser arg0, DeserializationContext arg1) throws IOException { + try { + return LocalDate.parse(arg0.getText(), DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSXXX")); + } catch (Exception e) { + return LocalDate.parse(arg0.getText(), DateTimeFormatter.ofPattern("yyyy-MM-dd")); + } + } +} +``` + +### Step 7 - Remove Void auto generated Classes + +Delete the below-mentioned models from `model` package and replace there uses with `String.class`. +`AvailableBalance.java`
+`CurrentBalance.java`
+`ReservedBalance.java`
+`UnclearedBalance.java` + + + + +### PS +* The endpoint are available on tomcat server port and not on the camel server port. So by default all the camle endpoints are accesible on `5000` port whereas WebMvc endpoints are accesible on `8080` port. +* To make sure endpoints are working fine, try running the below curl request. + ```bash + # for localhost + curl --location --request GET 'http://localhost:8080/heartbeat' \ + --header 'Accept: application/json' + + # for SIT cluster + curl --location --request GET 'https://channel-gsma.sandbox.fynarfin.io/heartbeat/' \ + --header 'Accept: application/json' + ``` + +## Resources +:point_right: [OAS for GSMA latest version](https://www.gsma.com/mobilefordevelopment/mobile-money/mobile-money-api/) +:point_right: [Swagger Hub](https://app.swaggerhub.com/home) diff --git a/ph-ee-connector-channel/settings.gradle b/ph-ee-connector-channel/settings.gradle new file mode 100644 index 000000000..9fb3abbdc --- /dev/null +++ b/ph-ee-connector-channel/settings.gradle @@ -0,0 +1,5 @@ +/* + * This file was generated by the Gradle 'init' task. + */ + +rootProject.name = 'ph-ee-connector-channel' diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/ChannelConnectorApplication.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/ChannelConnectorApplication.java new file mode 100644 index 000000000..8d1e196e4 --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/ChannelConnectorApplication.java @@ -0,0 +1,106 @@ +package org.mifos.connector; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; +import io.swagger.v3.oas.annotations.OpenAPIDefinition; +import io.swagger.v3.oas.annotations.info.Info; +import org.mifos.connector.channel.interceptor.config.RedisRouteConfig; +import org.mifos.connector.gsmastub.api.ApiOriginFilter; +import org.mifos.connector.gsmastub.configuration.CustomInstantDeserializer; +import org.mifos.connector.gsmastub.configuration.LocalDateConverter; +import org.mifos.connector.gsmastub.configuration.LocalDateTimeConverter; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.web.client.RestTemplateBuilder; +import org.springframework.boot.web.servlet.FilterRegistrationBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.redis.connection.jedis.JedisConnectionFactory; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.serializer.GenericToStringSerializer; +import org.springframework.data.redis.serializer.StringRedisSerializer; +import org.springframework.format.FormatterRegistry; +import org.springframework.web.client.RestTemplate; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; +import org.threeten.bp.Instant; +import org.threeten.bp.LocalDate; +import org.threeten.bp.OffsetDateTime; +import org.threeten.bp.ZonedDateTime; + +@SpringBootApplication +@OpenAPIDefinition(info = @Info(title = "Channel connector APIs")) +public class ChannelConnectorApplication { + + @Autowired + RedisRouteConfig redisRouteConfig; + + @Value("${redis.database}") + private int redisDatabase; + + @Bean + public ObjectMapper objectMapper() { + JavaTimeModule javaTimeModule = new JavaTimeModule(); + javaTimeModule.addDeserializer(Instant.class, CustomInstantDeserializer.INSTANT); + javaTimeModule.addDeserializer(OffsetDateTime.class, CustomInstantDeserializer.OFFSET_DATE_TIME); + javaTimeModule.addDeserializer(ZonedDateTime.class, CustomInstantDeserializer.ZONED_DATE_TIME); + /* javaTimeModule.addSerializer(LocalDate.class, new CustomInstantDeserializer.LocalDateSerializer()); */ + javaTimeModule.addDeserializer(LocalDate.class, new CustomInstantDeserializer.LocalDateDeserializer()); + ObjectMapper objectMapper = new ObjectMapper(); + objectMapper.registerModule(javaTimeModule); + objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false); + return objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL) + .configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true) + .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + } + + @Bean + public RestTemplate restTemplate(RestTemplateBuilder builder) { + return builder.build(); + } + + @Configuration + static class CustomDateConfig implements WebMvcConfigurer { + + @Override + public void addFormatters(FormatterRegistry registry) { + registry.addConverter(new LocalDateConverter("yyyy-MM-dd")); + registry.addConverter(new LocalDateTimeConverter("yyyy-MM-dd'T'HH:mm:ss.SSS")); + // registry.addConverter(new LocalDateTimeConverter("yyyy-MM-dd'T'HH:mm:ss.SSSXXX")); + } + } + + @Bean + JedisConnectionFactory jedisConnectionFactory() { + JedisConnectionFactory jedisConnectionFactory = redisRouteConfig.setupConnector(); + jedisConnectionFactory.setDatabase(redisDatabase); + return jedisConnectionFactory; + } + + @Bean + public RedisTemplate redisTemplate() { + RedisTemplate template = new RedisTemplate<>(); + template.setKeySerializer(new StringRedisSerializer()); + template.setValueSerializer(new GenericToStringSerializer<>(String.class)); + template.setConnectionFactory(jedisConnectionFactory()); + return template; + } + + @Bean + public FilterRegistrationBean apiOriginFilter() { + FilterRegistrationBean registration = new FilterRegistrationBean<>(); + registration.setFilter(new ApiOriginFilter()); + registration.addUrlPatterns("/**"); + registration.setName("apiOriginFilter"); + registration.setOrder(Integer.MIN_VALUE + 1); + return registration; + } + + public static void main(String[] args) { + SpringApplication.run(ChannelConnectorApplication.class, args); + } +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/HealthCheck.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/HealthCheck.java new file mode 100644 index 000000000..d32fbe1cf --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/HealthCheck.java @@ -0,0 +1,28 @@ +// package org.mifos.connector; +// +// +// import org.apache.camel.Exchange; +// import org.apache.camel.LoggingLevel; +// import org.apache.camel.builder.RouteBuilder; +// import org.springframework.stereotype.Component; +// +// @Component +// public class HealthCheck extends RouteBuilder { +// +// +// @Override +// public void configure() throws Exception { +// from("rest:GET:/") +//// .to("http://localhost:5001/accounts/paygops") +// .setHeader(Exchange.HTTP_RESPONSE_CODE, constant(200)) +// .setBody(constant("GET Good")); +// +// from("rest:POST:/") +// //.to("direct:transfer-settlement-base") +//// .to("http://localhost:5001/accounts/paygops") +// .log(LoggingLevel.INFO, "POST Body: ${body}") +// .setHeader(Exchange.HTTP_RESPONSE_CODE, constant(200)) +// .setBody(constant("All Post Good")); +// +// } +// } diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/api/definition/CollectionApi.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/api/definition/CollectionApi.java new file mode 100644 index 000000000..2834afa6f --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/api/definition/CollectionApi.java @@ -0,0 +1,28 @@ +package org.mifos.connector.channel.api.definition; + +import static org.mifos.connector.channel.camel.config.CamelProperties.PAYMENT_SCHEME_HEADER; + +import com.fasterxml.jackson.core.JsonProcessingException; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import java.util.concurrent.ExecutionException; +import org.mifos.connector.channel.examples.SuccessfulTransferResponseDto; +import org.mifos.connector.channel.gsma_api.GsmaP2PResponseDto; +import org.mifos.connector.channel.model.CollectionRequestDTO; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestHeader; + +public interface CollectionApi { + + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Accepted: Transaction id generated", content = @Content(mediaType = "application/json", schema = @Schema(implementation = SuccessfulTransferResponseDto.class))) }) + @PostMapping("/channel/collection") + GsmaP2PResponseDto collection(@RequestHeader(value = "Platform-TenantId") String tenant, + @RequestHeader(value = "X-CorrelationID") String correlationId, + @RequestHeader(value = PAYMENT_SCHEME_HEADER, required = false) String paymentScheme, + @RequestBody CollectionRequestDTO requestBody) throws ExecutionException, InterruptedException, JsonProcessingException; + +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/api/definition/GSMATransactionApi.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/api/definition/GSMATransactionApi.java new file mode 100644 index 000000000..45f0b2199 --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/api/definition/GSMATransactionApi.java @@ -0,0 +1,29 @@ +package org.mifos.connector.channel.api.definition; + +import static org.mifos.connector.channel.camel.config.CamelProperties.CLIENTCORRELATIONID; + +import com.fasterxml.jackson.core.JsonProcessingException; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import org.mifos.connector.channel.examples.InvalidRequestBodyResponseDto; +import org.mifos.connector.channel.examples.SuccessfulTransferResponseDto; +import org.mifos.connector.channel.gsma_api.GsmaP2PResponseDto; +import org.mifos.connector.common.gsma.dto.GsmaTransfer; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestHeader; + +public interface GSMATransactionApi { + + @ApiResponses(value = { + @ApiResponse(responseCode = "202", description = "Accepted: Transaction id generated", content = @Content(mediaType = "application/json", schema = @Schema(implementation = SuccessfulTransferResponseDto.class))), + @ApiResponse(responseCode = "400", description = "Bad Request", content = @Content(mediaType = "application/json", schema = @Schema(implementation = InvalidRequestBodyResponseDto.class))) }) + @PostMapping("/channel/gsma/transaction") + ResponseEntity gsmatransaction(@RequestBody GsmaTransfer requestBody, + @RequestHeader(value = CLIENTCORRELATIONID, required = false) String correlationId, + @RequestHeader(value = "amsName") String amsName, @RequestHeader(value = "accountHoldingInstitutionId") String accountHoldId, + @RequestHeader(value = "X-CallbackURL") String callbackURL) throws JsonProcessingException; +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/api/definition/IndexApi.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/api/definition/IndexApi.java new file mode 100644 index 000000000..c3f9cc273 --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/api/definition/IndexApi.java @@ -0,0 +1,11 @@ +package org.mifos.connector.channel.api.definition; + +import javax.servlet.http.HttpServletResponse; +import org.springframework.web.bind.annotation.GetMapping; + +public interface IndexApi { + + @GetMapping("/") + String index(HttpServletResponse response) throws Exception; + +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/api/definition/JobApi.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/api/definition/JobApi.java new file mode 100644 index 000000000..69ef7c382 --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/api/definition/JobApi.java @@ -0,0 +1,10 @@ +package org.mifos.connector.channel.api.definition; + +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; + +public interface JobApi { + + @PostMapping("/channel/job/resolve") + Object job(@RequestBody String requestBody); +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/api/definition/PartyRegistrationApi.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/api/definition/PartyRegistrationApi.java new file mode 100644 index 000000000..3d7c5e714 --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/api/definition/PartyRegistrationApi.java @@ -0,0 +1,14 @@ +package org.mifos.connector.channel.api.definition; + +import com.fasterxml.jackson.core.JsonProcessingException; +import org.mifos.connector.common.channel.dto.RegisterAliasRequestDTO; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestHeader; + +public interface PartyRegistrationApi { + + @PostMapping("/channel/partyRegistration") + void partyRegistration(@RequestHeader(value = "Platform-TenantId") String tenant, @RequestBody RegisterAliasRequestDTO requestBody) + throws JsonProcessingException; +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/api/definition/TransactionApi.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/api/definition/TransactionApi.java new file mode 100644 index 000000000..cf151b523 --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/api/definition/TransactionApi.java @@ -0,0 +1,32 @@ +package org.mifos.connector.channel.api.definition; + +import static org.mifos.connector.channel.camel.config.CamelProperties.CLIENTCORRELATIONID; +import static org.mifos.connector.channel.zeebe.ZeebeVariables.TRANSACTION_ID; + +import com.fasterxml.jackson.core.JsonProcessingException; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import org.mifos.connector.channel.examples.InvalidRequestBodyResponseDto; +import org.mifos.connector.channel.examples.SuccessfulTransferResponseDto; +import org.mifos.connector.channel.gsma_api.GsmaP2PResponseDto; +import org.mifos.connector.common.channel.dto.TransactionChannelRequestDTO; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestHeader; + +public interface TransactionApi { + + @ApiResponses(value = { + @ApiResponse(responseCode = "202", description = "Accepted: Transaction id generated", content = @Content(mediaType = "application/json", schema = @Schema(implementation = SuccessfulTransferResponseDto.class))), + @ApiResponse(responseCode = "400", description = "Bad Request", content = @Content(mediaType = "application/json", schema = @Schema(implementation = InvalidRequestBodyResponseDto.class))) }) + @PostMapping("/channel/transactionRequest") + ResponseEntity transaction(@RequestHeader(value = "Platform-TenantId") String tenant, + @RequestHeader(value = CLIENTCORRELATIONID, required = false) String correlationId, + @RequestBody TransactionChannelRequestDTO requestBody) throws JsonProcessingException; + + @PostMapping("/channel/transaction/{" + TRANSACTION_ID + "}/resolve") + void transactionResolve(@RequestBody String requestBody) throws JsonProcessingException; +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/api/definition/TransferApi.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/api/definition/TransferApi.java new file mode 100644 index 000000000..3378d91d5 --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/api/definition/TransferApi.java @@ -0,0 +1,41 @@ +package org.mifos.connector.channel.api.definition; + +import static org.mifos.connector.channel.camel.config.CamelProperties.BATCH_ID_HEADER; +import static org.mifos.connector.channel.camel.config.CamelProperties.CLIENTCORRELATIONID; +import static org.mifos.connector.channel.camel.config.CamelProperties.PAYEE_DFSP_ID; +import static org.mifos.connector.channel.camel.config.CamelProperties.REGISTERING_INSTITUTION_ID; + +import com.fasterxml.jackson.core.JsonProcessingException; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import org.mifos.connector.channel.examples.InvalidRequestBodyResponseDto; +import org.mifos.connector.channel.examples.SuccessfulTransferResponseDto; +import org.mifos.connector.channel.gsma_api.GsmaP2PResponseDto; +import org.mifos.connector.common.channel.dto.TransactionChannelRequestDTO; +import org.mifos.connector.common.channel.dto.TransactionStatusResponseDTO; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestHeader; + +public interface TransferApi { + + @ApiResponses(value = { + @ApiResponse(responseCode = "202", description = "Accepted: Transaction id generated", content = @Content(mediaType = "application/json", schema = @Schema(implementation = SuccessfulTransferResponseDto.class))), + @ApiResponse(responseCode = "400", description = "Bad Request", content = @Content(mediaType = "application/json", schema = @Schema(implementation = InvalidRequestBodyResponseDto.class))) }) + @PostMapping("/channel/transfer") + ResponseEntity transfer(@RequestHeader(value = "Platform-TenantId") String tenant, + @RequestHeader(value = BATCH_ID_HEADER, required = false) String batchId, + @RequestHeader(value = CLIENTCORRELATIONID, required = false) String correlationId, + @RequestHeader(value = REGISTERING_INSTITUTION_ID, required = false) String registeringInstitutionId, + @RequestHeader(value = PAYEE_DFSP_ID, required = false) String payeeDfspId, + @RequestBody TransactionChannelRequestDTO requestBody) throws JsonProcessingException; + + @GetMapping("/channel/transfer/{transactionId}") + TransactionStatusResponseDTO transferId(@PathVariable String transactionId, @RequestHeader(value = "Platform-TenantId") String tenant) + throws JsonProcessingException; +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/api/definition/TxnStateApi.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/api/definition/TxnStateApi.java new file mode 100644 index 000000000..897b673bb --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/api/definition/TxnStateApi.java @@ -0,0 +1,24 @@ +package org.mifos.connector.channel.api.definition; + +import static org.mifos.connector.channel.camel.config.CamelProperties.CLIENTCORRELATIONID; + +import com.fasterxml.jackson.core.JsonProcessingException; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import org.mifos.connector.channel.examples.SuccessfulTxnStateResponseDTO; +import org.mifos.connector.channel.model.TxnStateResponseDTO; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestHeader; + +public interface TxnStateApi { + + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "OK", content = @Content(mediaType = "application/json", schema = @Schema(implementation = SuccessfulTxnStateResponseDTO.class))) }) + @GetMapping("/channel/txnState/{X-CorrelationID}") + TxnStateResponseDTO txnState(@RequestHeader(value = "Platform-TenantId") String tenant, + @PathVariable(value = CLIENTCORRELATIONID) String correlationId, @RequestHeader(value = "requestType") String requestType) + throws JsonProcessingException; +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/api/definition/ValidationApi.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/api/definition/ValidationApi.java new file mode 100644 index 000000000..216ddc3eb --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/api/definition/ValidationApi.java @@ -0,0 +1,21 @@ +package org.mifos.connector.channel.api.definition; + +import static org.apache.camel.Exchange.CONTENT_TYPE; + +import com.fasterxml.jackson.core.JsonProcessingException; +import org.mifos.connector.channel.model.ValidationRequestDTO; +import org.mifos.connector.channel.model.ValidationResponseDTO; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestHeader; + +public interface ValidationApi { + + @PostMapping("/accounts/validate/{primaryIdentifierName}/{primaryIdentifierVal}") + ValidationResponseDTO validation(@RequestHeader("amsUrl") String amsUrl, @RequestHeader("amsName") String amsName, + @RequestHeader("accountHoldingInstitutionId") String accountHoldingInstitutionId, + @RequestHeader(CONTENT_TYPE) String contentTypeVal, @RequestBody ValidationRequestDTO validationRequestDTO, + @PathVariable String primaryIdentifierName, @PathVariable String primaryIdentifierVal) throws JsonProcessingException; + +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/api/definition/WorkflowApi.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/api/definition/WorkflowApi.java new file mode 100644 index 000000000..a08901cf1 --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/api/definition/WorkflowApi.java @@ -0,0 +1,14 @@ +package org.mifos.connector.channel.api.definition; + +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; + +public interface WorkflowApi { + + @PostMapping("/channel/workflow/resolve") + Object workflow(@RequestBody String requestBody); + + @PostMapping("/channel/workflow/{workflowInstanceKey}/cancel") + Object workflowKey(@PathVariable String workflowInstanceKey); +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/api/implementation/CollectionApiController.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/api/implementation/CollectionApiController.java new file mode 100644 index 000000000..5d02b723e --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/api/implementation/CollectionApiController.java @@ -0,0 +1,46 @@ +package org.mifos.connector.channel.api.implementation; + +import static org.mifos.connector.channel.camel.config.CamelProperties.PAYMENT_SCHEME_HEADER; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import io.camunda.zeebe.client.api.command.ClientStatusException; +import io.grpc.Status; +import java.util.concurrent.ExecutionException; +import org.apache.camel.Exchange; +import org.apache.camel.ProducerTemplate; +import org.mifos.connector.channel.api.definition.CollectionApi; +import org.mifos.connector.channel.gsma_api.GsmaP2PResponseDto; +import org.mifos.connector.channel.model.CollectionRequestDTO; +import org.mifos.connector.channel.utils.Headers; +import org.mifos.connector.channel.utils.SpringWrapperUtil; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.RestController; + +@RestController +public class CollectionApiController implements CollectionApi { + + @Autowired + private ProducerTemplate producerTemplate; + + @Autowired + private ObjectMapper objectMapper; + + @Override + public GsmaP2PResponseDto collection(String tenant, String correlationId, String paymentScheme, CollectionRequestDTO requestBody) + throws ExecutionException, InterruptedException, JsonProcessingException { + Headers headers = new Headers.HeaderBuilder().addHeader("Platform-TenantId", tenant).addHeader("X-CorrelationID", correlationId) + .addHeader(PAYMENT_SCHEME_HEADER, paymentScheme).build(); + Exchange exchange = SpringWrapperUtil.getDefaultWrappedExchange(producerTemplate.getCamelContext(), headers, + objectMapper.writeValueAsString(requestBody)); + Exchange ex = producerTemplate.send("direct:post-collection", exchange); + Exception cause = exchange.getProperty(Exchange.EXCEPTION_CAUGHT, Exception.class); + if (cause instanceof ClientStatusException) { + throw new ClientStatusException(Status.FAILED_PRECONDITION, cause); + } + + String body = exchange.getIn().getBody(String.class); + return objectMapper.readValue(body, GsmaP2PResponseDto.class); + } + +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/api/implementation/GSMATransactionApiController.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/api/implementation/GSMATransactionApiController.java new file mode 100644 index 000000000..4e6592c88 --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/api/implementation/GSMATransactionApiController.java @@ -0,0 +1,64 @@ +package org.mifos.connector.channel.api.implementation; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import io.camunda.zeebe.client.api.command.ClientStatusException; +import io.grpc.Status; +import org.apache.camel.Exchange; +import org.apache.camel.ProducerTemplate; +import org.mifos.connector.channel.api.definition.GSMATransactionApi; +import org.mifos.connector.channel.gsma_api.GsmaP2PResponseDto; +import org.mifos.connector.channel.service.ValidateHeaders; +import org.mifos.connector.channel.utils.HeaderConstants; +import org.mifos.connector.channel.utils.Headers; +import org.mifos.connector.channel.utils.SpringWrapperUtil; +import org.mifos.connector.channel.validator.ChannelValidator; +import org.mifos.connector.channel.validator.HeaderValidator; +import org.mifos.connector.common.exception.ValidationException; +import org.mifos.connector.common.gsma.dto.GsmaTransfer; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.RestController; + +@RestController +public class GSMATransactionApiController implements GSMATransactionApi { + + @Autowired + private ProducerTemplate producerTemplate; + + @Autowired + ObjectMapper objectMapper; + private Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Override + @ValidateHeaders(requiredHeaders = { HeaderConstants.AMS_NAME, HeaderConstants.ACCOUNT_HOLDING_INSTITUTION_ID, + HeaderConstants.X_Callback_URL, + HeaderConstants.CLIENT_CORRELATION_ID }, validatorClass = HeaderValidator.class, validationFunction = "validateGsmaTransaction") + public ResponseEntity gsmatransaction(GsmaTransfer requestBody, String correlationId, String amsName, + String accountHoldId, String callbackURL) throws JsonProcessingException { + + try { + ChannelValidator.validateTransaction(requestBody); + } catch (ValidationException e) { + throw e; + } + + Headers headers = new Headers.HeaderBuilder().addHeader("X-CorrelationID", correlationId).addHeader("amsName", amsName) + .addHeader("accountHoldingInstitutionId", accountHoldId).addHeader("X-CallbackURL", callbackURL).build(); + Exchange exchange = SpringWrapperUtil.getDefaultWrappedExchange(producerTemplate.getCamelContext(), headers, + objectMapper.writeValueAsString(requestBody)); + producerTemplate.send("direct:post-gsma-transaction", exchange); + + Exception cause = exchange.getProperty(Exchange.EXCEPTION_CAUGHT, Exception.class); + if (cause instanceof ClientStatusException) { + throw new ClientStatusException(Status.FAILED_PRECONDITION, cause); + } + + String body = exchange.getIn().getBody(String.class); + GsmaP2PResponseDto responseDto = objectMapper.readValue(body, GsmaP2PResponseDto.class); + return ResponseEntity.status(HttpStatus.ACCEPTED).body(responseDto); + } +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/api/implementation/IndexApiController.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/api/implementation/IndexApiController.java new file mode 100644 index 000000000..f1a7e3983 --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/api/implementation/IndexApiController.java @@ -0,0 +1,28 @@ +package org.mifos.connector.channel.api.implementation; + +import javax.servlet.http.HttpServletResponse; +import org.apache.camel.Exchange; +import org.apache.camel.ProducerTemplate; +import org.mifos.connector.channel.api.definition.IndexApi; +import org.mifos.connector.channel.utils.Headers; +import org.mifos.connector.channel.utils.SpringWrapperUtil; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.RestController; + +@RestController +public class IndexApiController implements IndexApi { + + @Autowired + private ProducerTemplate producerTemplate; + + @Override + public String index(HttpServletResponse response) throws Exception { + Headers headers = new Headers.HeaderBuilder().build(); + Exchange exchange = SpringWrapperUtil.getDefaultWrappedExchange(producerTemplate.getCamelContext(), headers, null); + producerTemplate.send("direct:get-index", exchange); + response.setStatus(exchange.getIn().getHeader(Exchange.HTTP_RESPONSE_CODE, Integer.class)); + + return exchange.getIn().getBody(String.class); + } + +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/api/implementation/JobApiController.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/api/implementation/JobApiController.java new file mode 100644 index 000000000..0798df3e1 --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/api/implementation/JobApiController.java @@ -0,0 +1,24 @@ +package org.mifos.connector.channel.api.implementation; + +import org.apache.camel.Exchange; +import org.apache.camel.ProducerTemplate; +import org.mifos.connector.channel.api.definition.JobApi; +import org.mifos.connector.channel.utils.Headers; +import org.mifos.connector.channel.utils.SpringWrapperUtil; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.RestController; + +@RestController +public class JobApiController implements JobApi { + + @Autowired + private ProducerTemplate producerTemplate; + + @Override + public Object job(String requestBody) { + Headers headers = new Headers.HeaderBuilder().build(); + Exchange exchange = SpringWrapperUtil.getDefaultWrappedExchange(producerTemplate.getCamelContext(), headers, requestBody); + producerTemplate.send("direct:post-job-resolve", exchange); + return exchange.getIn().getBody(null); + } +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/api/implementation/PartyRegistrationApiController.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/api/implementation/PartyRegistrationApiController.java new file mode 100644 index 000000000..a7f4f8a71 --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/api/implementation/PartyRegistrationApiController.java @@ -0,0 +1,37 @@ +package org.mifos.connector.channel.api.implementation; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import io.camunda.zeebe.client.api.command.ClientStatusException; +import io.grpc.Status; +import org.apache.camel.Exchange; +import org.apache.camel.ProducerTemplate; +import org.mifos.connector.channel.api.definition.PartyRegistrationApi; +import org.mifos.connector.channel.utils.Headers; +import org.mifos.connector.channel.utils.SpringWrapperUtil; +import org.mifos.connector.common.channel.dto.RegisterAliasRequestDTO; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.RestController; + +@RestController +public class PartyRegistrationApiController implements PartyRegistrationApi { + + @Autowired + private ProducerTemplate producerTemplate; + + @Autowired + ObjectMapper objectMapper; + + @Override + public void partyRegistration(String tenant, RegisterAliasRequestDTO requestBody) throws JsonProcessingException { + Headers headers = new Headers.HeaderBuilder().addHeader("Platform-TenantId", tenant).build(); + Exchange exchange = SpringWrapperUtil.getDefaultWrappedExchange(producerTemplate.getCamelContext(), headers, + objectMapper.writeValueAsString(requestBody)); + producerTemplate.send("direct:post-party-registration", exchange); + Exception cause = exchange.getProperty(Exchange.EXCEPTION_CAUGHT, Exception.class); + if (cause instanceof ClientStatusException) { + throw new ClientStatusException(Status.FAILED_PRECONDITION, cause); + } + + } +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/api/implementation/TransactionApiController.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/api/implementation/TransactionApiController.java new file mode 100644 index 000000000..7f9bf0054 --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/api/implementation/TransactionApiController.java @@ -0,0 +1,69 @@ +package org.mifos.connector.channel.api.implementation; + +import static org.mifos.connector.channel.camel.config.CamelProperties.CLIENTCORRELATIONID; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import io.camunda.zeebe.client.api.command.ClientStatusException; +import io.grpc.Status; +import org.apache.camel.Exchange; +import org.apache.camel.ProducerTemplate; +import org.mifos.connector.channel.api.definition.TransactionApi; +import org.mifos.connector.channel.gsma_api.GsmaP2PResponseDto; +import org.mifos.connector.channel.service.ValidateHeaders; +import org.mifos.connector.channel.utils.HeaderConstants; +import org.mifos.connector.channel.utils.Headers; +import org.mifos.connector.channel.utils.SpringWrapperUtil; +import org.mifos.connector.channel.validator.ChannelValidator; +import org.mifos.connector.channel.validator.HeaderValidator; +import org.mifos.connector.common.channel.dto.TransactionChannelRequestDTO; +import org.mifos.connector.common.exception.ValidationException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.RestController; + +@RestController +public class TransactionApiController implements TransactionApi { + + @Autowired + ObjectMapper objectMapper; + @Autowired + private ProducerTemplate producerTemplate; + + @Override + @ValidateHeaders(requiredHeaders = { HeaderConstants.PLATFORM_TENANT_ID, + HeaderConstants.CLIENT_CORRELATION_ID }, validatorClass = HeaderValidator.class, validationFunction = "validateTransactionRequest") + public ResponseEntity transaction(String tenant, String correlationId, TransactionChannelRequestDTO requestBody) + throws JsonProcessingException { + + try { + ChannelValidator.validateTransfer(requestBody); + } catch (ValidationException e) { + throw e; + } + + Headers headers = new Headers.HeaderBuilder().addHeader("Platform-TenantId", tenant).addHeader(CLIENTCORRELATIONID, correlationId) + .build(); + Exchange exchange = SpringWrapperUtil.getDefaultWrappedExchange(producerTemplate.getCamelContext(), headers, + objectMapper.writeValueAsString(requestBody)); + producerTemplate.send("direct:post-transaction-request", exchange); + + Exception cause = exchange.getProperty(Exchange.EXCEPTION_CAUGHT, Exception.class); + if (cause instanceof ClientStatusException) { + throw new ClientStatusException(Status.FAILED_PRECONDITION, cause); + } + + String body = exchange.getIn().getBody(String.class); + GsmaP2PResponseDto responseDto = objectMapper.readValue(body, GsmaP2PResponseDto.class); + return ResponseEntity.status(HttpStatus.ACCEPTED).body(responseDto); + } + + @Override + public void transactionResolve(String requestBody) throws JsonProcessingException { + Headers headers = new Headers.HeaderBuilder().build(); + Exchange exchange = SpringWrapperUtil.getDefaultWrappedExchange(producerTemplate.getCamelContext(), null, requestBody); + producerTemplate.send("direct:post-transaction-resolve", exchange); + + } +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/api/implementation/TransferApiController.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/api/implementation/TransferApiController.java new file mode 100644 index 000000000..c986cff28 --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/api/implementation/TransferApiController.java @@ -0,0 +1,84 @@ +package org.mifos.connector.channel.api.implementation; + +import static org.mifos.connector.channel.camel.config.CamelProperties.BATCH_ID; +import static org.mifos.connector.channel.camel.config.CamelProperties.CLIENTCORRELATIONID; +import static org.mifos.connector.channel.camel.config.CamelProperties.PAYEE_DFSP_ID; +import static org.mifos.connector.channel.camel.config.CamelProperties.REGISTERING_INSTITUTION_ID; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import io.camunda.zeebe.client.api.command.ClientStatusException; +import io.grpc.Status; +import org.apache.camel.Exchange; +import org.apache.camel.ProducerTemplate; +import org.mifos.connector.channel.api.definition.TransferApi; +import org.mifos.connector.channel.gsma_api.GsmaP2PResponseDto; +import org.mifos.connector.channel.service.ValidateHeaders; +import org.mifos.connector.channel.utils.HeaderConstants; +import org.mifos.connector.channel.utils.Headers; +import org.mifos.connector.channel.utils.SpringWrapperUtil; +import org.mifos.connector.channel.validator.ChannelValidator; +import org.mifos.connector.channel.validator.HeaderValidator; +import org.mifos.connector.common.channel.dto.TransactionChannelRequestDTO; +import org.mifos.connector.common.channel.dto.TransactionStatusResponseDTO; +import org.mifos.connector.common.exception.ValidationException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.RestController; + +@RestController +public class TransferApiController implements TransferApi { + + @Autowired + private ProducerTemplate producerTemplate; + + @Autowired + ObjectMapper objectMapper; + + private Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Override + @ValidateHeaders(requiredHeaders = { HeaderConstants.PLATFORM_TENANT_ID, HeaderConstants.BATCH_ID_HEADER, HeaderConstants.PAYEE_DFSP_ID, + HeaderConstants.CLIENT_CORRELATION_ID, + HeaderConstants.REGISTERING_INSTITUTION_ID }, validatorClass = HeaderValidator.class, validationFunction = "validateTransfer") + public ResponseEntity transfer(String tenant, String batchId, String correlationId, String registeringInstitutionId, + String payeeDfspId, TransactionChannelRequestDTO requestBody) throws JsonProcessingException { + + try { + ChannelValidator.validateTransfer(requestBody); + } catch (ValidationException e) { + throw e; + } + + Headers headers = new Headers.HeaderBuilder().addHeader("Platform-TenantId", tenant).addHeader(BATCH_ID, batchId) + .addHeader(CLIENTCORRELATIONID, correlationId).addHeader(REGISTERING_INSTITUTION_ID, registeringInstitutionId) + .addHeader(PAYEE_DFSP_ID, payeeDfspId).build(); + Exchange exchange = SpringWrapperUtil.getDefaultWrappedExchange(producerTemplate.getCamelContext(), headers, + objectMapper.writeValueAsString(requestBody)); + logger.info("Client correlation id: " + correlationId); + logger.info("Batch id: " + batchId); + producerTemplate.send("direct:post-transfer", exchange); + Exception cause = exchange.getProperty(Exchange.EXCEPTION_CAUGHT, Exception.class); + if (cause instanceof ClientStatusException) { + throw new ClientStatusException(Status.FAILED_PRECONDITION, cause); + } + + String responseBody = exchange.getIn().getBody(String.class); + GsmaP2PResponseDto responseDto = objectMapper.readValue(responseBody, GsmaP2PResponseDto.class); + return ResponseEntity.status(HttpStatus.ACCEPTED).body(responseDto); + } + + @Override + public TransactionStatusResponseDTO transferId(String transactionId, String tenant) throws JsonProcessingException { + Headers headers = new Headers.HeaderBuilder().addHeader("Platform-TenantId", tenant).addHeader("transactionId", transactionId) + .build(); + Exchange exchange = SpringWrapperUtil.getDefaultWrappedExchange(producerTemplate.getCamelContext(), headers, null); + producerTemplate.send("direct:get-transfer-transaction-id", exchange); + + String body = exchange.getIn().getBody(String.class); + return objectMapper.readValue(body, TransactionStatusResponseDTO.class); + } +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/api/implementation/TxnStateApiController.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/api/implementation/TxnStateApiController.java new file mode 100644 index 000000000..a8153608b --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/api/implementation/TxnStateApiController.java @@ -0,0 +1,35 @@ +package org.mifos.connector.channel.api.implementation; + +import static org.mifos.connector.channel.camel.config.CamelProperties.CLIENTCORRELATIONID; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.apache.camel.ProducerTemplate; +import org.mifos.connector.channel.api.definition.TxnStateApi; +import org.mifos.connector.channel.model.TxnStateResponseDTO; +import org.mifos.connector.channel.service.TxnStateService; +import org.mifos.connector.channel.utils.Headers; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.RestController; + +@RestController +public class TxnStateApiController implements TxnStateApi { + + @Autowired + private ProducerTemplate producerTemplate; + + @Autowired + ObjectMapper objectMapper; + + @Autowired + TxnStateService service; + + @Override + public TxnStateResponseDTO txnState(String tenant, String correlationId, String requestType) throws JsonProcessingException { + Headers headers = new Headers.HeaderBuilder().addHeader("Platform-TenantId", tenant).addHeader("requestType", requestType) + .addHeader(CLIENTCORRELATIONID, correlationId).build(); + + TxnStateResponseDTO response = service.getTxnState(headers, correlationId, requestType); + return response; + } +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/api/implementation/ValidationApiController.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/api/implementation/ValidationApiController.java new file mode 100644 index 000000000..cb5e89590 --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/api/implementation/ValidationApiController.java @@ -0,0 +1,43 @@ +package org.mifos.connector.channel.api.implementation; + +import static org.apache.camel.Exchange.CONTENT_TYPE; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.apache.camel.Exchange; +import org.apache.camel.ProducerTemplate; +import org.mifos.connector.channel.api.definition.ValidationApi; +import org.mifos.connector.channel.model.ValidationRequestDTO; +import org.mifos.connector.channel.model.ValidationResponseDTO; +import org.mifos.connector.channel.utils.Headers; +import org.mifos.connector.channel.utils.SpringWrapperUtil; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.RestController; + +@RestController +public class ValidationApiController implements ValidationApi { + + @Autowired + private ProducerTemplate producerTemplate; + + @Autowired + ObjectMapper objectMapper; + + private Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Override + public ValidationResponseDTO validation(String amsUrl, String amsName, String accountHoldingInstitutionId, String contentTypeVal, + ValidationRequestDTO validationRequestDTO, String primaryIdentifierName, String primaryIdentifierVal) + throws JsonProcessingException { + Headers headers = new Headers.HeaderBuilder().addHeader("amsUrl", amsUrl).addHeader("amsName", amsName) + .addHeader("accountHoldingInstitutionId", accountHoldingInstitutionId).addHeader(CONTENT_TYPE, contentTypeVal).build(); + + Exchange exchange = SpringWrapperUtil.getDefaultWrappedExchange(producerTemplate.getCamelContext(), headers, + objectMapper.writeValueAsString(validationRequestDTO)); + producerTemplate.send("direct:post-validation-ams", exchange); + String body = exchange.getIn().getBody(String.class); + return objectMapper.readValue(body, ValidationResponseDTO.class); + } +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/api/implementation/WorkflowApiController.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/api/implementation/WorkflowApiController.java new file mode 100644 index 000000000..c1d173877 --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/api/implementation/WorkflowApiController.java @@ -0,0 +1,31 @@ +package org.mifos.connector.channel.api.implementation; + +import org.apache.camel.Exchange; +import org.apache.camel.ProducerTemplate; +import org.apache.camel.support.DefaultExchange; +import org.mifos.connector.channel.api.definition.WorkflowApi; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.RestController; + +@RestController +public class WorkflowApiController implements WorkflowApi { + + @Autowired + private ProducerTemplate producerTemplate; + + @Override + public Object workflow(String requestBody) { + Exchange exchange = new DefaultExchange(producerTemplate.getCamelContext()); + producerTemplate.send("direct:post-workflow-resolve", exchange); + + return exchange.getIn().getBody(); + } + + @Override + public Object workflowKey(String workflowInstanceKey) { + Exchange exchange = new DefaultExchange(producerTemplate.getCamelContext()); + producerTemplate.send("direct:post-workflow-instanceKey-cancel", exchange); + + return exchange.getIn().getBody(); + } +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/camel/config/CamelContextConfig.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/camel/config/CamelContextConfig.java new file mode 100644 index 000000000..78582ff40 --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/camel/config/CamelContextConfig.java @@ -0,0 +1,45 @@ +package org.mifos.connector.channel.camel.config; + +import java.util.HashMap; +import org.apache.camel.CamelContext; +import org.apache.camel.spi.RestConfiguration; +import org.apache.camel.spring.boot.CamelContextConfiguration; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class CamelContextConfig { + + @Value("${camel.server-port}") + private int serverPort; + + @Bean + CamelContextConfiguration contextConfiguration() { + return new CamelContextConfiguration() { + + @Override + public void beforeApplicationStart(CamelContext camelContext) { + camelContext.setTracing(false); + camelContext.setMessageHistory(false); + camelContext.setStreamCaching(true); + camelContext.disableJMX(); + + RestConfiguration rest = new RestConfiguration(); + camelContext.setRestConfiguration(rest); + rest.setComponent("undertow"); + rest.setProducerComponent("undertow"); + rest.setPort(serverPort); + rest.setBindingMode(RestConfiguration.RestBindingMode.json); + rest.setDataFormatProperties(new HashMap<>()); + rest.getDataFormatProperties().put("prettyPrint", "true"); + rest.setScheme("http"); + } + + @Override + public void afterApplicationStart(CamelContext camelContext) { + // empty + } + }; + } +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/camel/config/CamelProperties.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/camel/config/CamelProperties.java new file mode 100644 index 000000000..544bebb73 --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/camel/config/CamelProperties.java @@ -0,0 +1,18 @@ +package org.mifos.connector.channel.camel.config; + +public final class CamelProperties { + + private CamelProperties() {} + + public static final String AUTH_TYPE = "authType"; + public static final String BATCH_ID = "batchId"; + public static final String PARTY_LOOKUP_FAILED = "partyLookupFailed"; + public static final String CLIENTCORRELATIONID = "X-CorrelationID"; + public static final String BATCH_ID_HEADER = "X-BatchID"; + public static final String PLATFORM_TENANT_ID = "Platform-TenantId"; + public static final String PAYMENT_SCHEME_HEADER = "X-Payment-Scheme"; + public static final String REGISTERING_INSTITUTION_ID = "X-Registering-Institution-ID"; + public static final String PARTY_LOOKUP_FSP_ID = "partyLookupFspId"; + public static final String PAYEE_DFSP_ID = "X-PayeeDFSP-ID"; + +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/camel/config/Client.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/camel/config/Client.java new file mode 100644 index 000000000..c6c0d91aa --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/camel/config/Client.java @@ -0,0 +1,34 @@ +package org.mifos.connector.channel.camel.config; + +public class Client { + + private String tenant; + private String clientId; + private String clientSecret; + + public Client() {} + + public String getTenant() { + return tenant; + } + + public void setTenant(String tenant) { + this.tenant = tenant; + } + + public String getClientId() { + return clientId; + } + + public void setClientId(String clientId) { + this.clientId = clientId; + } + + public String getClientSecret() { + return clientSecret; + } + + public void setClientSecret(String clientSecret) { + this.clientSecret = clientSecret; + } +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/camel/config/ClientProperties.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/camel/config/ClientProperties.java new file mode 100644 index 000000000..ee408885a --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/camel/config/ClientProperties.java @@ -0,0 +1,28 @@ +package org.mifos.connector.channel.camel.config; + +import java.util.ArrayList; +import java.util.List; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +@Component +@ConfigurationProperties(prefix = "identity.channel") +public class ClientProperties { + + private List clients = new ArrayList<>(); + + public ClientProperties() {} + + public List getClients() { + return clients; + } + + public void setClients(List clients) { + this.clients = clients; + } + + public Client getClient(String tenant) { + return getClients().stream().filter(t -> t.getTenant().equals(tenant)).findFirst() + .orElseThrow(() -> new RuntimeException("Client for tenant: " + tenant + ", not configuerd!")); + } +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/camel/routes/BaseErrorHandlerRoute.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/camel/routes/BaseErrorHandlerRoute.java new file mode 100644 index 000000000..ca1e25353 --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/camel/routes/BaseErrorHandlerRoute.java @@ -0,0 +1,43 @@ +package org.mifos.connector.channel.camel.routes; + +import com.fasterxml.jackson.databind.exc.InvalidFormatException; +import org.apache.camel.Exchange; +import org.apache.camel.component.bean.validator.BeanValidationException; +import org.json.JSONArray; +import org.json.JSONObject; +import org.mifos.connector.common.camel.ErrorHandlerRouteBuilder; + +public abstract class BaseErrorHandlerRoute extends ErrorHandlerRouteBuilder { + + @Override + public void configure() { + super.configure(); + handleExceptions(); + configureRoutes(); + } + + abstract void configureRoutes(); + + private void handleExceptions() { + onException(BeanValidationException.class).process(e -> { + JSONArray violations = new JSONArray(); + e.getProperty(Exchange.EXCEPTION_CAUGHT, BeanValidationException.class).getConstraintViolations() + .forEach(v -> violations.put(v.getPropertyPath() + " --- " + v.getMessage())); + JSONObject response = new JSONObject(); + response.put("violations", violations); + e.getIn().setBody(response.toString()); + e.removeProperties("*"); + }).setHeader(Exchange.HTTP_RESPONSE_CODE, constant(400)).stop(); + + onException(InvalidFormatException.class).process(e -> { + JSONArray violations = new JSONArray(); + violations.put(e.getProperty(Exchange.EXCEPTION_CAUGHT, InvalidFormatException.class).getMessage()); + + JSONObject response = new JSONObject(); + response.put("violations", violations); + e.getIn().setBody(response.toString()); + e.removeProperties("*"); + }).setHeader(Exchange.HTTP_RESPONSE_CODE, constant(400)).stop(); + } + +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/camel/routes/BeneficiaryRouteBuilder.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/camel/routes/BeneficiaryRouteBuilder.java new file mode 100644 index 000000000..ae110aff7 --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/camel/routes/BeneficiaryRouteBuilder.java @@ -0,0 +1,41 @@ +package org.mifos.connector.channel.camel.routes; + +import org.apache.camel.LoggingLevel; +import org.mifos.connector.channel.utils.CamelDslString; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; + +@Component +public class BeneficiaryRouteBuilder extends BaseErrorHandlerRoute { + + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + private final String basePath = "/channel/beneficiary"; + private final CamelDslString path = new CamelDslString(basePath); + + @Override + void configureRoutes() { + // All Beneficiary + // todo implement the redirection to the dmt-connector + from(path.getPath("")).id("get-all-beneficiary").log(LoggingLevel.INFO, "## CHANNEL -> Get all beneficiaries request: ${body}") + .setBody(constant("This API will fetch all the beneficiaries")); + + // Get Beneficiary + // todo implement the redirection to the dmt-connector + from(path.getPath("{beneficiaryId}")).id("get-beneficiary") + .log(LoggingLevel.INFO, "## CHANNEL -> Get beneficiaries request for id: ${header.beneficiaryId} with body: ${body}") + .setBody(constant("This API will fetch the beneficiary based on beneficiary id: ${header.beneficiaryId}")); + + // Add Beneficiary + // todo implement the redirection to the dmt-connector + from(path.postPath("")).id("add-beneficiary").log(LoggingLevel.INFO, "## CHANNEL -> Add beneficiary request: ${body}") + .setBody(constant("This API will add the beneficiary: ${body}")); + + // Delete Beneficiary + // todo implement the redirection to the dmt-connector + from(path.deletePath("{beneficiaryId}")).id("delete-beneficiary") + .log(LoggingLevel.INFO, "## CHANNEL -> Delete beneficiary request for id: ${header.beneficiaryId} with body: ${body}") + .setBody(constant("This API will delete the beneficiary based on beneficiary id: ${header.beneficiaryId}")); + } + +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/camel/routes/ChannelRouteBuilder.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/camel/routes/ChannelRouteBuilder.java new file mode 100644 index 000000000..dd583f247 --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/camel/routes/ChannelRouteBuilder.java @@ -0,0 +1,783 @@ +package org.mifos.connector.channel.camel.routes; + +import static java.util.Base64.getEncoder; +import static java.util.Spliterators.spliteratorUnknownSize; +import static java.util.stream.StreamSupport.stream; +import static org.mifos.connector.channel.camel.config.CamelProperties.AUTH_TYPE; +import static org.mifos.connector.channel.camel.config.CamelProperties.BATCH_ID; +import static org.mifos.connector.channel.camel.config.CamelProperties.CLIENTCORRELATIONID; +import static org.mifos.connector.channel.camel.config.CamelProperties.PAYEE_DFSP_ID; +import static org.mifos.connector.channel.camel.config.CamelProperties.PAYMENT_SCHEME_HEADER; +import static org.mifos.connector.channel.camel.config.CamelProperties.REGISTERING_INSTITUTION_ID; +import static org.mifos.connector.channel.zeebe.ZeebeMessages.OPERATOR_MANUAL_RECOVERY; +import static org.mifos.connector.channel.zeebe.ZeebeVariables.ACCOUNT; +import static org.mifos.connector.channel.zeebe.ZeebeVariables.AMS; +import static org.mifos.connector.channel.zeebe.ZeebeVariables.CHANNEL_REQUEST; +import static org.mifos.connector.channel.zeebe.ZeebeVariables.IS_AUTHORISATION_REQUIRED; +import static org.mifos.connector.channel.zeebe.ZeebeVariables.IS_RTP_REQUEST; +import static org.mifos.connector.channel.zeebe.ZeebeVariables.PARTY_ID; +import static org.mifos.connector.channel.zeebe.ZeebeVariables.PARTY_ID_TYPE; +import static org.mifos.connector.channel.zeebe.ZeebeVariables.PAYMENT_SCHEME; +import static org.mifos.connector.channel.zeebe.ZeebeVariables.TENANT_ID; +import static org.mifos.connector.channel.zeebe.ZeebeVariables.TRANSACTION_ID; +import static org.mifos.connector.common.mojaloop.type.InitiatorType.CONSUMER; +import static org.mifos.connector.common.mojaloop.type.Scenario.TRANSFER; +import static org.mifos.connector.common.mojaloop.type.TransactionRole.PAYEE; +import static org.mifos.connector.common.mojaloop.type.TransactionRole.PAYER; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.exc.InvalidFormatException; +import io.camunda.zeebe.client.ZeebeClient; +import java.nio.charset.StandardCharsets; +import java.time.Duration; +import java.time.Instant; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Spliterator; +import javax.net.ssl.HttpsURLConnection; +import org.apache.camel.Exchange; +import org.apache.camel.LoggingLevel; +import org.apache.camel.component.bean.validator.BeanValidationException; +import org.apache.camel.model.dataformat.JsonLibrary; +import org.json.JSONArray; +import org.json.JSONObject; +import org.mifos.connector.channel.camel.config.Client; +import org.mifos.connector.channel.camel.config.ClientProperties; +import org.mifos.connector.channel.gsma_api.GsmaP2PResponseDto; +import org.mifos.connector.channel.model.OpsTxnResponseDTO; +import org.mifos.connector.channel.model.ValidationResponseDTO; +import org.mifos.connector.channel.properties.TenantImplementation; +import org.mifos.connector.channel.properties.TenantImplementationProperties; +import org.mifos.connector.channel.utils.AMSProps; +import org.mifos.connector.channel.utils.AMSUtils; +import org.mifos.connector.channel.utils.Constants; +import org.mifos.connector.channel.zeebe.ZeebeProcessStarter; +import org.mifos.connector.common.camel.AuthProcessor; +import org.mifos.connector.common.camel.AuthProperties; +import org.mifos.connector.common.camel.ErrorHandlerRouteBuilder; +import org.mifos.connector.common.channel.dto.RegisterAliasRequestDTO; +import org.mifos.connector.common.channel.dto.TransactionChannelRequestDTO; +import org.mifos.connector.common.channel.dto.TransactionStatusResponseDTO; +import org.mifos.connector.common.gsma.dto.GsmaTransfer; +import org.mifos.connector.common.mojaloop.dto.FspMoneyData; +import org.mifos.connector.common.mojaloop.dto.TransactionType; +import org.mifos.connector.common.mojaloop.type.TransferState; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Component; +import org.springframework.web.client.RestTemplate; +import org.springframework.web.reactive.function.client.WebClient; +import org.springframework.web.util.UriComponentsBuilder; + +@Component +public class ChannelRouteBuilder extends ErrorHandlerRouteBuilder { + + private Logger logger = LoggerFactory.getLogger(this.getClass()); + + private static final String DEFAULT_COLLECTION_PAYMENT_SCHEME = "mpesa"; + + @Autowired + private AMSUtils amsUtils; + + @Autowired + TenantImplementationProperties tenantImplementationProperties; + + private String paymentTransferFlow; + private String specialPaymentTransferFlow; + private String transactionRequestFlow; + private String partyRegistration; + private String inboundTransactionReqFlow; + private String restAuthHost; + private String operationsUrl; + private Boolean operationsAuthEnabled; + private String transfersEndpoint; + private String transactionEndpoint; + private Boolean isNotificationSuccessServiceEnabled; + private Boolean isNotificationFailureServiceEnabled; + private ZeebeProcessStarter zeebeProcessStarter; + private ZeebeClient zeebeClient; + private List dfspIds; + private ObjectMapper objectMapper; + private ClientProperties clientProperties; + private RestTemplate restTemplate; + private String timer; + private String restAuthHeader; + String destinationDfspId; + + public ChannelRouteBuilder(@Value("#{'${dfspids}'.split(',')}") List dfspIds, + @Value("${bpmn.flows.payment-transfer}") String paymentTransferFlow, + @Value("${bpmn.flows.special-payment-transfer}") String specialPaymentTransferFlow, + @Value("${bpmn.flows.transaction-request}") String transactionRequestFlow, + @Value("${bpmn.flows.party-registration}") String partyRegistration, + @Value("${bpmn.flows.inboundTransactionReq-flow}") String inboundTransactionReqFlow, + @Value("${rest.authorization.host}") String restAuthHost, @Value("${operations.url}") String operationsUrl, + @Value("${operations.auth-enabled}") Boolean operationsAuthEnabled, + @Value("${operations.endpoint.transfers}") String transfersEndpoint, + @Value("${operations.endpoint.transactionReq}") String transactionEndpoint, + @Value("${mpesa.notification.success.enabled}") Boolean isNotificationSuccessServiceEnabled, + @Value("${mpesa.notification.failure.enabled}") Boolean isNotificationFailureServiceEnabled, @Value("${timer}") String timer, + @Value("${rest.authorization.header}") String restAuthHeader, @Value("${destination.dfspid}") String destinationDfspId, + ZeebeClient zeebeClient, ZeebeProcessStarter zeebeProcessStarter, @Autowired(required = false) AuthProcessor authProcessor, + @Autowired(required = false) AuthProperties authProperties, ObjectMapper objectMapper, ClientProperties clientProperties, + RestTemplate restTemplate) { + super(authProcessor, authProperties); + super.configure(); + this.paymentTransferFlow = paymentTransferFlow; + this.specialPaymentTransferFlow = specialPaymentTransferFlow; + this.transactionRequestFlow = transactionRequestFlow; + this.inboundTransactionReqFlow = inboundTransactionReqFlow; + this.partyRegistration = partyRegistration; + this.zeebeProcessStarter = zeebeProcessStarter; + this.zeebeClient = zeebeClient; + this.dfspIds = dfspIds; + this.objectMapper = objectMapper; + this.clientProperties = clientProperties; + this.restTemplate = restTemplate; + this.restAuthHost = restAuthHost; + this.operationsUrl = operationsUrl; + this.transfersEndpoint = transfersEndpoint; + this.transactionEndpoint = transactionEndpoint; + this.isNotificationSuccessServiceEnabled = isNotificationSuccessServiceEnabled; + this.isNotificationFailureServiceEnabled = isNotificationFailureServiceEnabled; + this.timer = timer; + this.restAuthHeader = restAuthHeader; + this.operationsAuthEnabled = operationsAuthEnabled; + this.destinationDfspId = destinationDfspId; + } + + @Override + public void configure() { + handleExceptions(); + indexRoutes(); + transferRoutes(); + collectionRoutes(); + transactionRoutes(); + partyRegistrationRoutes(); + jobRoutes(); + workflowRoutes(); + acknowledgementRoutes(); + inboundTransferC2bImplementationRoutes(); + } + + private void handleExceptions() { + onException(BeanValidationException.class).process(e -> { + JSONArray violations = new JSONArray(); + e.getProperty(Exchange.EXCEPTION_CAUGHT, BeanValidationException.class).getConstraintViolations().forEach(v -> { + violations.put(v.getPropertyPath() + " --- " + v.getMessage()); + }); + + JSONObject response = new JSONObject(); + response.put("violations", violations); + e.getIn().setBody(response.toString()); + e.removeProperties("*"); + }).setHeader(Exchange.HTTP_RESPONSE_CODE, constant(400)).stop(); + + onException(InvalidFormatException.class).process(e -> { + JSONArray violations = new JSONArray(); + violations.put(e.getProperty(Exchange.EXCEPTION_CAUGHT, InvalidFormatException.class).getMessage()); + + JSONObject response = new JSONObject(); + response.put("violations", violations); + e.getIn().setBody(response.toString()); + e.removeProperties("*"); + }).setHeader(Exchange.HTTP_RESPONSE_CODE, constant(400)).stop(); + } + + private void indexRoutes() { + from("direct:get-index").setHeader(Exchange.HTTP_RESPONSE_CODE, constant(200)).setBody(constant("")); + } + + private void transferRoutes() { + from("direct:get-transfer-transaction-id").id("transfer-details") + .log(LoggingLevel.INFO, "## CHANNEL -> inbound transferDetail request for ${header.transactionId}").process(e -> { + String tenantId = e.getIn().getHeader("Platform-TenantId", String.class); + if (tenantId == null || !dfspIds.contains(tenantId)) { + throw new RuntimeException("Requested tenant " + tenantId + " not configured in the connector!"); + } + Client client = clientProperties.getClient(tenantId); + HttpHeaders httpHeaders = new HttpHeaders(); + httpHeaders.add("Platform-TenantId", tenantId); + httpHeaders.add("Authorization", "Basic " + getEncoder() + .encodeToString((client.getClientId() + ":" + client.getClientSecret()).getBytes(StandardCharsets.UTF_8))); + + HttpEntity entity = new HttpEntity<>(null, httpHeaders); + ResponseEntity exchange = restTemplate.exchange(restAuthHost + "/oauth/token?grant_type=client_credentials", + HttpMethod.POST, entity, String.class); + String token = new JSONObject(exchange.getBody()).getString("access_token"); + + String transactionId = e.getIn().getHeader("transactionId", String.class); + + httpHeaders.remove("Authorization"); + httpHeaders.add("Authorization", "Bearer " + token); + entity = new HttpEntity<>(null, httpHeaders); + exchange = restTemplate.exchange(operationsUrl + "/transfers?page=0&size=20&transactionId=" + transactionId, + HttpMethod.GET, entity, String.class); + JSONArray contents = new JSONObject(exchange.getBody()).getJSONArray("content"); + + TransactionStatusResponseDTO response = new TransactionStatusResponseDTO(); + if (contents.length() != 1) { + response.setClientRefId("000000"); + response.setCompletedTimestamp(null); + response.setTransactionId(transactionId); + response.setTransferState(TransferState.RECEIVED); + response.setTransferId(null); + } else { + JSONObject transfer = contents.getJSONObject(0); + long workflowInstanceKey = transfer.getLong("workflowInstanceKey"); + String status = transfer.getString("status"); + response.setCompletedTimestamp(transfer.isNull("completedAt") ? null + : LocalDateTime.ofInstant(Instant.ofEpochMilli(transfer.getLong("completedAt")), ZoneId.systemDefault())); + response.setTransactionId(transactionId); + response.setTransferState("COMPLETED".equals(status) ? TransferState.COMMITTED : TransferState.RECEIVED); + + exchange = restTemplate.exchange(operationsUrl + "/transfer/" + workflowInstanceKey, HttpMethod.GET, entity, + String.class); + JSONArray variables = new JSONObject(exchange.getBody()).getJSONArray("variables"); + String transferCode = getVariableValue(variables.iterator(), "transferCode"); + response.setTransferId(transferCode == null ? null : transferCode.replace("\"", "")); + + String channelRequest = getVariableValue(variables.iterator(), "channelRequest"); + if (channelRequest != null) { + JSONObject channelRequestJson = new JSONObject( + channelRequest.substring(1, channelRequest.length() - 1).replace("\\\"", "\"")); + String clientRefId = channelRequestJson.optString("clientRefId", null); + response.setClientRefId(clientRefId == null ? "000000" : clientRefId); + } else { + response.setClientRefId("000000"); + } + } + + e.getIn().setBody(objectMapper.writeValueAsString(response)); + }); + + // fetch transfer details based on client correlation id + from("direct:get-txnState-correlationId").id("transfer-details-correlationId") + .log(LoggingLevel.INFO, "## CHANNEL -> request for txn with client correlation Id" + " ${header.X-CorrelationID}") + .process(e -> { + String tenantId = e.getIn().getHeader("Platform-TenantId", String.class); + if (tenantId == null || !dfspIds.contains(tenantId)) { + throw new RuntimeException("Requested tenant " + tenantId + " not configured in the connector!"); + } + Client client = clientProperties.getClient(tenantId); + String requestType = getRequestType(e.getIn().getHeader("requestType", String.class)); + HttpEntity entity = buildHeader(tenantId, null); + if (operationsAuthEnabled) { + UriComponentsBuilder builder = buildParams(client); + ResponseEntity exchange = callAuthApi(builder, entity); + JSONObject jsonObject = new JSONObject(exchange.getBody()); + String token = jsonObject.getString("access_token"); + entity = buildHeader(tenantId, token); + } else { + entity = buildHeader(tenantId, null); + } + String correlationId = e.getIn().getHeader(CLIENTCORRELATIONID, String.class); + ResponseEntity exchange = callOpsTxnApi(requestType, correlationId, entity); + JSONArray contents = new JSONObject(exchange.getBody()).getJSONArray("content"); + TransactionStatusResponseDTO response = new TransactionStatusResponseDTO(); + if (contents.length() != 1) { + response = setTxnNotFound(response, correlationId); + } else { + JSONObject transfer = contents.getJSONObject(0); + response = setTxnFound(response, transfer); + exchange = fetchApibyWorkflowKey(entity, transfer.getLong("workflowInstanceKey")); + JSONArray variables = new JSONObject(exchange.getBody()).getJSONArray("variables"); + String transferCode = getVariableValue(variables.iterator(), "transferCode"); + response.setTransferId(transferCode == null ? null : transferCode.replace("\"", "")); + response.setClientRefId(correlationId); + } + e.getIn().setBody(objectMapper.writeValueAsString(response)); + }); + + from("direct:post-transfer").id("inbound-transaction-request") + .log(LoggingLevel.INFO, "## CHANNEL -> PAYER inbound transfer request: ${body}").unmarshal() + .json(JsonLibrary.Jackson, TransactionChannelRequestDTO.class).to("bean-validator:request").process(exchange -> { + Map extraVariables = new HashMap<>(); + extraVariables.put(IS_RTP_REQUEST, false); + + // adding batchId zeebeVariable form header + String batchIdHeader = exchange.getIn().getHeader(BATCH_ID, String.class); + extraVariables.put(BATCH_ID, batchIdHeader); + + String tenantId = exchange.getIn().getHeader("Platform-TenantId", String.class); + String payeeDfspId = exchange.getIn().getHeader(PAYEE_DFSP_ID, String.class); + String registeringInstitutionId = exchange.getIn().getHeader("X-Registering-Institution-ID", String.class); + String clientCorrelationId = exchange.getIn().getHeader("X-CorrelationID", String.class); + logger.info("## CHANNEL Client Correlation Id: {}", clientCorrelationId); + if (tenantId == null || !dfspIds.contains(tenantId)) { + throw new RuntimeException("Requested tenant " + tenantId + " not configured in the connector!"); + } + extraVariables.put(TENANT_ID, tenantId); + extraVariables.put(REGISTERING_INSTITUTION_ID, registeringInstitutionId); + + TransactionChannelRequestDTO channelRequest = exchange.getIn().getBody(TransactionChannelRequestDTO.class); + TransactionType transactionType = new TransactionType(); + transactionType.setInitiator(PAYER); + transactionType.setInitiatorType(CONSUMER); + transactionType.setScenario(TRANSFER); + channelRequest.setTransactionType(transactionType); + channelRequest.getPayer().getPartyIdInfo().setFspId(tenantId); + if (payeeDfspId == null || payeeDfspId.isBlank()) { + channelRequest.getPayee().getPartyIdInfo().setFspId(destinationDfspId); + } else { + channelRequest.getPayee().getPartyIdInfo().setFspId(payeeDfspId); + } + String customDataString = String.valueOf(channelRequest.getCustomData()); + String currency = channelRequest.getAmount().getCurrency(); + + extraVariables.put("customData", customDataString); + extraVariables.put("currency", currency); + extraVariables.put("initiator", transactionType.getInitiator().name()); + extraVariables.put("initiatorType", transactionType.getInitiatorType().name()); + extraVariables.put("scenario", transactionType.getScenario().name()); + extraVariables.put("amount", + new FspMoneyData(channelRequest.getAmount().getAmountDecimal(), channelRequest.getAmount().getCurrency())); + extraVariables.put("clientCorrelationId", clientCorrelationId); + extraVariables.put("initiatorFspId", channelRequest.getPayer().getPartyIdInfo().getFspId()); + extraVariables.put("destinationFspId", channelRequest.getPayee().getPartyIdInfo().getFspId()); + String tenantSpecificBpmn; + String bpmn = getWorkflowForTenant(tenantId, "payment-transfer"); + if (channelRequest.getPayer().getPartyIdInfo().getPartyIdentifier().startsWith("6666")) { + tenantSpecificBpmn = bpmn.equals("default") ? specialPaymentTransferFlow.replace("{dfspid}", tenantId) + : bpmn.replace("{dfspid}", tenantId); + extraVariables.put("specialTermination", true); + } else { + tenantSpecificBpmn = bpmn.equals("default") ? paymentTransferFlow.replace("{dfspid}", tenantId) + : bpmn.replace("{dfspid}", tenantId); + extraVariables.put("specialTermination", false); + } + + String transactionId = zeebeProcessStarter.startZeebeWorkflow(tenantSpecificBpmn, + objectMapper.writeValueAsString(channelRequest), extraVariables); + JSONObject response = new JSONObject(); + response.put("transactionId", transactionId); + exchange.getIn().setBody(response.toString()); + }); + } + + public ResponseEntity fetchApibyWorkflowKey(HttpEntity entity, long workflowInstanceKey) { + return restTemplate.exchange(operationsUrl + "/transfer/" + workflowInstanceKey, HttpMethod.GET, entity, String.class); + } + + public ResponseEntity callOpsTxnApi(String requestType, String correlationId, HttpEntity entity) { + String url = String.format("%s%s%s%s%s", operationsUrl, requestType, Constants.CLIENT_CORRELATION_ID, Constants.EQUALS_SIGN, + correlationId); + return restTemplate.exchange(url, HttpMethod.GET, entity, String.class); + } + + public ResponseEntity callOpsTxnApiUsingWebClient(String requestType, String correlationId, HttpEntity entity) { + String url = String.format("%s%s%s%s%s", operationsUrl, requestType, Constants.CLIENT_CORRELATION_ID, Constants.EQUALS_SIGN, + correlationId); + + WebClient webClient = WebClient.create(); + + ResponseEntity responseEntity = webClient.method(HttpMethod.GET).uri(url) + .headers(headers -> headers.putAll(entity.getHeaders())).retrieve().toEntity(String.class).block(); + + return responseEntity; + } + + public ResponseEntity callAuthApi(UriComponentsBuilder builder, HttpEntity entity) { + return restTemplate.exchange(builder.toUriString(), HttpMethod.POST, entity, String.class); + } + + public String getRequestType(String requestType) { + requestType = requestType.isEmpty() ? "transfers" : requestType; + requestType = requestType.equalsIgnoreCase("transfers") ? transfersEndpoint : transactionEndpoint; + return requestType; + } + + private void collectionRoutes() { + from("direct:post-collection").id("inboundTransactionReqFlow-payment-request") + .log(LoggingLevel.INFO, "## CHANNEL -> MPESA transaction request").to("bean-validator:request") // todo + // revisit + // function + // is + // breaking + .process(exchange -> { + + amsUtils.postConstruct(); + + Map extraVariables = new HashMap<>(); + extraVariables.put("initiator", "PAYEE"); + extraVariables.put("initiatorType", "BUSINESS"); + extraVariables.put("scenario", "MPESA"); + + String tenantId = exchange.getIn().getHeader("Platform-TenantId", String.class); + String clientCorrelationId = exchange.getIn().getHeader("X-CorrelationID", String.class); + if (tenantId == null || !dfspIds.contains(tenantId)) { + throw new RuntimeException("Requested tenant " + tenantId + " not configured in the connector!"); + } + extraVariables.put(TENANT_ID, tenantId); + String paymentScheme = getCollectionPaymentScheme(exchange.getIn().getHeader(PAYMENT_SCHEME_HEADER, String.class)); + extraVariables.put(PAYMENT_SCHEME, paymentScheme); + String tenantSpecificBpmn; + + String channelRequestBodyString = exchange.getIn().getBody(String.class); + JSONObject body = new JSONObject(channelRequestBodyString); + JSONArray payer = body.getJSONArray("payer"); + + String finalAmsVal = getFinalAmsValue(payer, extraVariables); + + JSONObject amountObj = body.getJSONObject("amount"); + String currency = amountObj.getString("currency"); + Object customDataObj = amsUtils.getOrDefault(body, "customData", ""); + String customDataString = String.valueOf(customDataObj); + logger.info("Final Value for ams : " + finalAmsVal); + extraVariables.put(AMS, finalAmsVal); + + String bpmn = getWorkflowForTenant(tenantId, "outbound-transfer-request"); + if (bpmn.equals("default")) { + bpmn = inboundTransactionReqFlow; + } + tenantSpecificBpmn = bpmn.replace("{dfspid}", tenantId).replace("{ams}", finalAmsVal).replace("{ps}", paymentScheme); + + String amount = body.getJSONObject("amount").getString("amount"); + + extraVariables.put("customData", customDataString); + extraVariables.put("currency", currency); + extraVariables.put("amount", amount); + extraVariables.put("isNotificationsSuccessEnabled", isNotificationSuccessServiceEnabled); + extraVariables.put("isNotificationsFailureEnabled", isNotificationFailureServiceEnabled); + extraVariables.put("timer", timer); + extraVariables.put("clientCorrelationId", clientCorrelationId); + + String transactionId = zeebeProcessStarter.startInboundTransactionZeebeWorkflow(tenantSpecificBpmn, + channelRequestBodyString, extraVariables); + JSONObject response = new JSONObject(); + response.put("transactionId", transactionId); + exchange.getIn().setBody(response.toString()); + }); + } + + private String getFinalAmsValue(JSONArray payer, Map extraVariables) { + String primaryIdentifierVal = ""; + String secondaryIdentifierVal = ""; + String primaryIdentifierName = ""; + String secondaryIdentifierName = ""; + String finalAmsVal = "value"; + primaryIdentifierName = ((JSONObject) payer.get(0)).getString("key"); + secondaryIdentifierName = ((JSONObject) payer.get(1)).getString("key"); + primaryIdentifierVal = ((JSONObject) payer.get(0)).getString("value"); + secondaryIdentifierVal = ((JSONObject) payer.get(1)).getString("value"); + for (AMSProps.AMS amsIdentifier : amsUtils.postConstruct()) { + logger.debug("KEY VALUE PAIR : {} {}", amsIdentifier.getIdentifier(), amsIdentifier.getValue()); + String identifier = amsIdentifier.getIdentifier(); + if (identifier.equalsIgnoreCase(secondaryIdentifierName)) { + finalAmsVal = amsIdentifier.getValue(); + logger.debug("Assigned from secondary {}", finalAmsVal); + break; + } else if (identifier.equalsIgnoreCase(primaryIdentifierName)) { + finalAmsVal = amsIdentifier.getValue(); + // logic to keep correct primary/secondary identifier for line 345-346 + String temp = primaryIdentifierVal; + primaryIdentifierVal = secondaryIdentifierVal; + secondaryIdentifierVal = temp; + logger.debug("Assigned from primary {}", finalAmsVal); + break; + } else { + if (identifier.equalsIgnoreCase("default")) { + finalAmsVal = amsIdentifier.getDefaultValue(); + logger.debug("Assigned default from secondary {}", finalAmsVal); + } + } + } // end for loop + + extraVariables.put("accountId", secondaryIdentifierVal); + extraVariables.put("phoneNumber", primaryIdentifierVal); + return finalAmsVal; + } + + private void transactionRoutes() { + from("direct:post-transaction-request").id("inbound-payment-request") + .log(LoggingLevel.INFO, "## CHANNEL -> PAYEE inbound transaction request").unmarshal() + .json(JsonLibrary.Jackson, TransactionChannelRequestDTO.class).to("bean-validator:request")// todo + // revisit + // function + // is + // breaking + .process(exchange -> { + Map extraVariables = new HashMap<>(); + TransactionType transactionType = new TransactionType(); + transactionType.setInitiator(PAYEE); + transactionType.setInitiatorType(CONSUMER); + transactionType.setScenario(TRANSFER); + extraVariables.put("initiator", transactionType.getInitiator().name()); + extraVariables.put("initiatorType", transactionType.getInitiatorType().name()); + extraVariables.put("scenario", transactionType.getScenario().name()); + + extraVariables.put(IS_RTP_REQUEST, true); + // variables.put(AUTH_RETRIES_LEFT, 3); // TODO if auth enabled + extraVariables.put(IS_AUTHORISATION_REQUIRED, false); // TODO how to decide? + extraVariables.put(AUTH_TYPE, "NONE"); + + String tenantId = exchange.getIn().getHeader("Platform-TenantId", String.class); + if (tenantId == null || !dfspIds.contains(tenantId)) { + throw new RuntimeException("Requested tenant " + tenantId + " not configured in the connector!"); + } + String clientCorrelationId = exchange.getIn().getHeader("X-CorrelationID", String.class); + extraVariables.put("clientCorrelationId", clientCorrelationId); + String tenantSpecificBpmn = transactionRequestFlow.replace("{dfspid}", tenantId); + + TransactionChannelRequestDTO channelRequest = exchange.getIn().getBody(TransactionChannelRequestDTO.class); + channelRequest.setTransactionType(transactionType); + + String transactionId = zeebeProcessStarter.startZeebeWorkflow(tenantSpecificBpmn, + objectMapper.writeValueAsString(channelRequest), extraVariables); + JSONObject response = new JSONObject(); + response.put("transactionId", transactionId); + exchange.getIn().setBody(response.toString()); + }); + + from("direct:post-transaction-resolve").id("transaction-resolve").log(LoggingLevel.INFO, "## operator transaction resolve") + .process(e -> { + Map variables = new HashMap<>(); + JSONObject request = new JSONObject(e.getIn().getBody(String.class)); + request.keys().forEachRemaining(k -> { + variables.put(k, request.get(k)); + }); + + zeebeClient.newPublishMessageCommand().messageName(OPERATOR_MANUAL_RECOVERY) + .correlationKey(e.getIn().getHeader(TRANSACTION_ID, String.class)).timeToLive(Duration.ofMillis(30000)) + .variables(variables).send(); + }).setBody(constant((Object) null)); + } + + private void partyRegistrationRoutes() { + from("direct:post-party-registration").id("inbound-party-registration-request") + .log(LoggingLevel.INFO, "## CHANNEL -> PHEE inbound party registration request").unmarshal() + .json(JsonLibrary.Jackson, RegisterAliasRequestDTO.class).to("bean-validator:request").process(exchange -> { + String tenantId = exchange.getIn().getHeader("Platform-TenantId", String.class); + if (tenantId == null || !dfspIds.contains(tenantId)) { + throw new RuntimeException("Requested tenant " + tenantId + " not configured in the connector!"); + } + RegisterAliasRequestDTO channelRequest = exchange.getIn().getBody(RegisterAliasRequestDTO.class); + Map variables = new HashMap<>(); + variables.put(TENANT_ID, tenantId); + variables.put(PARTY_ID_TYPE, channelRequest.getIdType().name()); + variables.put(PARTY_ID, channelRequest.getIdValue()); + variables.put(ACCOUNT, channelRequest.getAccountId()); + String tenantSpecificBpmn = partyRegistration.replace("{dfspid}", tenantId); + + zeebeProcessStarter.startZeebeWorkflow(tenantSpecificBpmn, objectMapper.writeValueAsString(channelRequest), variables); + }).setBody(constant((Object) null)); + } + + private void jobRoutes() { + from("direct:post-job-resolve").id("job-resolve").log(LoggingLevel.INFO, "## operator job resolve").process(e -> { + JSONObject request = new JSONObject(e.getIn().getBody(String.class)); + JSONObject incident = request.getJSONObject("incident"); + Map newVariables = new HashMap<>(); + JSONObject requestedVariables = request.getJSONObject("variables"); + requestedVariables.keys().forEachRemaining(k -> { + newVariables.put(k, requestedVariables.get(k)); + }); + + zeebeClient.newSetVariablesCommand(incident.getLong("elementInstanceKey")).variables(newVariables).send(); + + zeebeClient.newUpdateRetriesCommand(incident.getLong("jobKey")).retries(incident.getInt("newRetries")).send(); + + zeebeClient.newResolveIncidentCommand(incident.getLong("key")).send(); + }).setBody(constant((Object) null)); + + } + + private void workflowRoutes() { + from("direct:post-workflow-resolve").id("workflow-resolve").log(LoggingLevel.INFO, "## operator workflow resolve").process(e -> { + JSONObject request = new JSONObject(e.getIn().getBody(String.class)); + JSONObject incident = request.getJSONObject("incident"); + Map newVariables = new HashMap<>(); + JSONObject requestedVariables = request.getJSONObject("variables"); + requestedVariables.keys().forEachRemaining(k -> { + newVariables.put(k, requestedVariables.get(k)); + }); + + zeebeClient.newSetVariablesCommand(incident.getLong("elementInstanceKey")).variables(newVariables).send(); + + zeebeClient.newResolveIncidentCommand(incident.getLong("key")).send(); + }).setBody(constant((Object) null)); + + from("direct:post-workflow-instanceKey-cancel").id("workflow-cancel") + .log(LoggingLevel.INFO, "## operator workflow cancel ${header.workflowInstanceKey}").process(e -> zeebeClient + .newCancelInstanceCommand(Long.parseLong(e.getIn().getHeader("workflowInstanceKey", String.class))).send()) + .setBody(constant((Object) null)); + } + + private void acknowledgementRoutes() { + String id = "invoke-ack-workers"; + from("direct:" + id).id(id).log(LoggingLevel.INFO, "## CHANNEL -> Ack transaction request").process(exchange -> { + // fetch transaction ids and batch id + Collection transactionIds = exchange.getProperty("successfulTxIds", ArrayList.class); + String batchId = (String) exchange.getProperty(BATCH_ID); + for (String transactionId : transactionIds) { + Map extraVariables = new HashMap<>(); + + String tenantId = exchange.getIn().getHeader("Platform-TenantId", String.class); + if (tenantId == null || !dfspIds.contains(tenantId)) { + throw new RuntimeException("Requested tenant " + tenantId + " not configured in the connector!"); + } + extraVariables.put(TENANT_ID, tenantId); + + String tenantSpecificBpmn = inboundTransactionReqFlow.replace("{dfspid}", tenantId); + + String instanceId = zeebeProcessStarter.startZeebeWorkflow(tenantSpecificBpmn, exchange.getIn().getBody(String.class), + extraVariables); + JSONObject response = new JSONObject(); + response.put("instanceId", instanceId); + response.put("transactionId", transactionId); + response.put("batchId", batchId); + exchange.getIn().setBody(response.toString()); + } + }); + } + + private void inboundTransferC2bImplementationRoutes() { + from("direct:post-validation-ams").id("validation-ams").log(LoggingLevel.INFO, "Validation Check").process(e -> { + String paybillRequestBodyString = e.getIn().getBody(String.class); + logger.debug("Payload : {}", paybillRequestBodyString); + JSONObject body = new JSONObject(paybillRequestBodyString); + String amsURL = e.getIn().getHeader("amsUrl").toString(); + String finalAmsVal = e.getIn().getHeader("amsName").toString(); + String accountHoldingInstitutionId = e.getIn().getHeader("accountHoldingInstitutionId").toString(); + logger.debug("Final Value for ams : " + finalAmsVal); + logger.debug("AMS URL : {}", amsURL); + logger.debug("accountHoldingInstitutionId: {}", accountHoldingInstitutionId); + e.getIn().setBody(body.toString()); + e.setProperty("amsURL", amsURL); + e.setProperty("finalAmsVal", finalAmsVal); + e.getIn().removeHeaders("*"); + e.getIn().setHeader("accountHoldingInstitutionId", accountHoldingInstitutionId); + logger.debug("Header:{}", e.getIn().getHeaders()); + }).log("${header.amsURL},${header.finalAmsVal}") + .toD("${header.amsURL}" + "/api/v1/paybill/validate/" + "${header.finalAmsVal}" + "?bridgeEndpoint=true") + .id("ams-validation-response").unmarshal().json(JsonLibrary.Jackson, ValidationResponseDTO.class) + .log(LoggingLevel.INFO, "## AMS Validation response DTO").setBody(e -> { + ValidationResponseDTO validationResponseDTO = e.getIn().getBody(ValidationResponseDTO.class); + try { + return objectMapper.writeValueAsString(validationResponseDTO); + } catch (JsonProcessingException ex) { + throw new RuntimeException(ex); + } + }); + + from("direct:post-gsma-transaction").id("gsma-transfer").unmarshal().json(JsonLibrary.Jackson, GsmaTransfer.class) + .log(LoggingLevel.INFO, "GSMA Transfer Body").process(e -> { + GsmaTransfer gsmaTranfer = e.getIn().getBody(GsmaTransfer.class); + logger.info("Gsma Transfer DTO : {}", String.valueOf(gsmaTranfer)); + String subtype = gsmaTranfer.getSubType(); + String type = gsmaTranfer.getType(); + String amsName = e.getIn().getHeader("amsName").toString(); + String accountHoldingInstitutionId = e.getIn().getHeader("accountHoldingInstitutionId").toString(); + String clientCorrelationId = e.getIn().getHeader("X-CorrelationID", String.class); + String callbackURL = e.getIn().getHeader("X-CallbackURL").toString(); + // inbound-transfer-mifos-lion + Map variables = amsUtils.setZeebeVariables(gsmaTranfer.getCustomData(), timer); + variables.put(TENANT_ID, accountHoldingInstitutionId); + variables.put(CHANNEL_REQUEST, objectMapper.writeValueAsString(gsmaTranfer)); + variables.put("clientCorrelationId", clientCorrelationId); + variables.put("X-CallbackURL", callbackURL); + String workflowName = new StringBuilder().append(subtype).append("_").append(type).append("_").append(amsName) + .append("-").append(accountHoldingInstitutionId).toString(); + logger.info("Workflow Name:{}", workflowName); + String transactionId = zeebeProcessStarter.startZeebeWorkflowC2B(workflowName, variables); + GsmaP2PResponseDto responseDto = new GsmaP2PResponseDto(); + responseDto.transactionId = transactionId; + + JSONObject response = new JSONObject(); + response.put("transactionId", transactionId); + e.getIn().setBody(response.toString()); + }); + } + + public String getVariableValue(Iterator iterator, String variableName) { + String value = stream(spliteratorUnknownSize(iterator, Spliterator.ORDERED), false).map(v -> (JSONObject) v) + .filter(v -> variableName.equals(v.getString("name"))).findFirst().map(v -> v.getString("value")).orElse(null); + logger.debug("Variable {} found, value: {}", variableName, value); + return value; + } + + public TransactionStatusResponseDTO setTxnFound(TransactionStatusResponseDTO response, JSONObject transfer) { + String status = transfer.has("status") ? transfer.getString("status") : transfer.getString("state"); + response.setCompletedTimestamp(transfer.isNull("completedAt") ? null + : LocalDateTime.ofInstant(Instant.ofEpochMilli(transfer.getLong("completedAt")), ZoneId.systemDefault())); + response.setTransactionId(transfer.getString("transactionId")); + response.setTransferState("COMPLETED".equals(status) ? TransferState.COMMITTED : TransferState.RECEIVED); + return response; + } + + public TransactionStatusResponseDTO setTxnNotFound(TransactionStatusResponseDTO response, String correlationId) { + logger.debug("Transaction not found for correlationId: {}", correlationId); + response.setClientRefId(correlationId); + response.setCompletedTimestamp(null); + response.setTransactionId(null); + response.setTransferState(TransferState.RECEIVED); + response.setTransferId(null); + return response; + } + + public UriComponentsBuilder buildParams(Client client) { + HttpsURLConnection.setDefaultHostnameVerifier((restAuthHost, session) -> true); + UriComponentsBuilder builder = UriComponentsBuilder.fromUriString(restAuthHost + "/oauth/token") + // Add query parameter + .queryParam("username", client.getClientId()).queryParam("password", client.getClientSecret()) + .queryParam("grant_type", "password"); + logger.debug("Builder : {}", builder.toUriString()); + return builder; + } + + public HttpEntity buildHeader(String tenantId, String token) { + HttpHeaders httpHeaders = new HttpHeaders(); + if (token == null) { + httpHeaders.add("Platform-TenantId", tenantId); + httpHeaders.add("Authorization", restAuthHeader); + logger.debug("Headers {}", httpHeaders.toSingleValueMap()); + } else { + httpHeaders.add("Platform-TenantId", tenantId); + httpHeaders.remove("Authorization"); + httpHeaders.add("Authorization", "Bearer " + token); + } + HttpEntity entity = new HttpEntity(null, httpHeaders); + return entity; + } + + public String getWorkflowForTenant(String tenantId, String useCase) { + + for (TenantImplementation tenant : tenantImplementationProperties.getTenants()) { + if (tenant.getId().equals(tenantId)) { + return tenant.getFlows().getOrDefault(useCase, "default"); + } + } + return "default"; + } + + private String getCollectionPaymentScheme(String paymentSchemeHeaderValue) { + if (paymentSchemeHeaderValue != null && !paymentSchemeHeaderValue.isBlank()) { + return paymentSchemeHeaderValue.toLowerCase(); + } + return DEFAULT_COLLECTION_PAYMENT_SCHEME; + } + + public TransactionStatusResponseDTO setTxnFound(TransactionStatusResponseDTO response, OpsTxnResponseDTO txnResponseDTO) { + String status = String.valueOf(txnResponseDTO.getStatus()); + + response.setCompletedTimestamp(txnResponseDTO.getCompletedAt() == null ? null + : txnResponseDTO.getCompletedAt().toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime()); + + response.setTransactionId(txnResponseDTO.getTransactionId()); + response.setTransferState(Constants.COMPLETED.equals(status) ? TransferState.COMMITTED : TransferState.RECEIVED); + return response; + } + +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/camel/routes/DmtOperationsRouteBuilder.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/camel/routes/DmtOperationsRouteBuilder.java new file mode 100644 index 000000000..ef33ec21d --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/camel/routes/DmtOperationsRouteBuilder.java @@ -0,0 +1,41 @@ +package org.mifos.connector.channel.camel.routes; + +import org.apache.camel.LoggingLevel; +import org.mifos.connector.channel.utils.CamelDslString; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class DmtOperationsRouteBuilder extends BaseErrorHandlerRoute { + + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + private final String basePath = "/channel/dmtops"; + private final CamelDslString path = new CamelDslString(basePath); + + @Override + void configureRoutes() { + // Add Sender info + // todo do request handling and trigger the zeebe message task [sender_info] with correlationId as + // [transactionId] + from(path.postPath("/senderinfo")).id("post-sender-info").log(LoggingLevel.INFO, "## CHANNEL -> Post sender info request: ${body}") + .setBody(constant("This API will trigger the add sender path with sender info: ${body}")); + + // Verify OTP + // todo do request handling and trigger the zeebe message task [otp] with correlationId as [transactionId] + from(path.postPath("/otp/verify")).id("verify-otp").log(LoggingLevel.INFO, "## CHANNEL -> Verify OTP request: ${body}") + .setBody(constant("This API will trigger the verify OTP path: ${body}")); + + // Resend OTP + // todo do request handling and trigger the zeebe message task [otp] with correlationId as [transactionId] + from(path.postPath("/otp/resend")).id("resend-otp").log(LoggingLevel.INFO, "## CHANNEL -> Resend OTP request: ${body}") + .setBody(constant("This API will trigger the resend OTP path: ${body}")); + + // Beneficiary lookup + // todo do request handling and trigger the zeebe message task [beneficiary_details] with correlationId as + // [transactionId] + from(path.postPath("/beneficiarydetails")).id("post-beneficiary-details") + .log(LoggingLevel.INFO, "## CHANNEL -> Post beneficiary details request: ${body}") + .setBody(constant("This API will trigger the beneficiary lookup path with beneficiary info: ${body}")); + + } + +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/camel/routes/GSMAChannelRouteBuilder.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/camel/routes/GSMAChannelRouteBuilder.java new file mode 100644 index 000000000..411799653 --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/camel/routes/GSMAChannelRouteBuilder.java @@ -0,0 +1,364 @@ +package org.mifos.connector.channel.camel.routes; + +import static org.mifos.connector.channel.camel.config.CamelProperties.BATCH_ID; +import static org.mifos.connector.channel.zeebe.ZeebeVariables.GSMA_CHANNEL_REQUEST; +import static org.mifos.connector.channel.zeebe.ZeebeVariables.IS_RTP_REQUEST; +import static org.mifos.connector.channel.zeebe.ZeebeVariables.NOTE; +import static org.mifos.connector.channel.zeebe.ZeebeVariables.PARTY_ID; +import static org.mifos.connector.channel.zeebe.ZeebeVariables.PARTY_ID_TYPE; +import static org.mifos.connector.channel.zeebe.ZeebeVariables.TENANT_ID; +import static org.mifos.connector.channel.zeebe.ZeebeVariables.TRANSACTION_TYPE; +import static org.mifos.connector.common.mojaloop.type.InitiatorType.CONSUMER; +import static org.mifos.connector.common.mojaloop.type.Scenario.TRANSFER; +import static org.mifos.connector.common.mojaloop.type.TransactionRole.PAYER; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.exc.InvalidFormatException; +import io.camunda.zeebe.client.ZeebeClient; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.apache.camel.Exchange; +import org.apache.camel.LoggingLevel; +import org.apache.camel.component.bean.validator.BeanValidationException; +import org.apache.camel.model.dataformat.JsonLibrary; +import org.json.JSONArray; +import org.json.JSONObject; +import org.mifos.connector.channel.properties.TenantImplementation; +import org.mifos.connector.channel.properties.TenantImplementationProperties; +import org.mifos.connector.channel.zeebe.ZeebeProcessStarter; +import org.mifos.connector.common.camel.ErrorHandlerRouteBuilder; +import org.mifos.connector.common.channel.dto.PhErrorDTO; +import org.mifos.connector.common.channel.dto.TransactionChannelRequestDTO; +import org.mifos.connector.common.exception.PaymentHubError; +import org.mifos.connector.common.gsma.dto.GSMATransaction; +import org.mifos.connector.common.gsma.dto.GsmaParty; +import org.mifos.connector.common.gsma.dto.RequestStateDTO; +import org.mifos.connector.common.mojaloop.dto.FspMoneyData; +import org.mifos.connector.common.mojaloop.dto.MoneyData; +import org.mifos.connector.common.mojaloop.dto.Party; +import org.mifos.connector.common.mojaloop.dto.PartyIdInfo; +import org.mifos.connector.common.mojaloop.dto.TransactionType; +import org.mifos.connector.common.mojaloop.type.IdentifierType; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +@Component +public class GSMAChannelRouteBuilder extends ErrorHandlerRouteBuilder { + + private Logger logger = LoggerFactory.getLogger(this.getClass()); + + private String baseTransaction; + private String intTransfer; + private String payeeProcess; + private String billPayment; + private String linkBasedPayment; + private String internationalRemittancePayee; + private String internationalRemittancePayer; + private ZeebeProcessStarter zeebeProcessStarter; + private ZeebeClient zeebeClient; + private List dfspIds; + private ObjectMapper objectMapper; + private String payeeDfspid; + + @Autowired + TenantImplementationProperties tenantImplementationProperties; + + public GSMAChannelRouteBuilder(@Value("#{'${dfspids}'.split(',')}") List dfspIds, + @Value("${bpmn.flows.gsma-base-transaction}") String baseTransaction, + @Value("${bpmn.flows.gsma-int-transfer}") String intTransfer, @Value("${bpmn.flows.gsma-payee-process}") String payeeProcess, + @Value("${bpmn.flows.gsma-bill-payment}") String billPayment, + @Value("${bpmn.flows.gsma-link-based-payment}") String linkBasedPayment, @Value("${destination.dfspid}") String payeeDfspid, + @Value("${bpmn.flows.international-remittance-payee}") String internationalRemittancePayee, + @Value("${bpmn.flows.international-remittance-payer}") String internationalRemittancePayer, ZeebeClient zeebeClient, + ZeebeProcessStarter zeebeProcessStarter, ObjectMapper objectMapper) { + super.configure(); + this.baseTransaction = baseTransaction; + this.intTransfer = intTransfer; + this.payeeProcess = payeeProcess; + this.billPayment = billPayment; + this.linkBasedPayment = linkBasedPayment; + this.internationalRemittancePayee = internationalRemittancePayee; + this.internationalRemittancePayer = internationalRemittancePayer; + this.zeebeProcessStarter = zeebeProcessStarter; + this.zeebeClient = zeebeClient; + this.dfspIds = dfspIds; + this.objectMapper = objectMapper; + this.payeeDfspid = payeeDfspid; + } + + @Override + public void configure() { + onException(BeanValidationException.class).process(e -> { + JSONArray violations = new JSONArray(); + e.getProperty(Exchange.EXCEPTION_CAUGHT, BeanValidationException.class).getConstraintViolations().forEach(v -> { + violations.put(v.getPropertyPath() + " --- " + v.getMessage()); + }); + + JSONObject response = new JSONObject(); + response.put("violations", violations); + e.getIn().setBody(response.toString()); + e.removeProperties("*"); + }).setHeader(Exchange.HTTP_RESPONSE_CODE, constant(400)).stop(); + + onException(InvalidFormatException.class).process(e -> { + JSONArray violations = new JSONArray(); + violations.put(e.getProperty(Exchange.EXCEPTION_CAUGHT, InvalidFormatException.class).getMessage()); + + JSONObject response = new JSONObject(); + response.put("violations", violations); + e.getIn().setBody(response.toString()); + e.removeProperties("*"); + }).setHeader(Exchange.HTTP_RESPONSE_CODE, constant(400)).stop(); + + from("direct:get-channel-gsma").setHeader(Exchange.HTTP_RESPONSE_CODE, constant(200)).setBody(constant("It Works!")); + + from("direct:post-gsma-transfer").id("gsma-payer-transfer").log(LoggingLevel.INFO, "## CHANNEL -> GSMA PAYER initiated transfer") + .unmarshal().json(JsonLibrary.Jackson, GSMATransaction.class).to("bean-validator:request").process(exchange -> { + GSMATransaction gsmaChannelRequest = exchange.getIn().getBody(GSMATransaction.class); // GSMA Object + + // validation of request + PhErrorDTO validationResponse = validateGsmaRequest(exchange); + if (validationResponse != null) { + // validation failed, means request has some validation faults + exchange.getIn().setBody(objectMapper.writeValueAsString(validationResponse)); + exchange.getIn().setHeader(Exchange.HTTP_RESPONSE_CODE, 400); + logger.info("Validation failed: {}", validationResponse); + return; + } + + TransactionChannelRequestDTO channelRequest = new TransactionChannelRequestDTO(); // Fineract Object + String clientCorrelationId = exchange.getIn().getHeader("X-CorrelationID", String.class); + String batchIdHeader = exchange.getIn().getHeader(BATCH_ID, String.class); + logger.info("Batch Id from route {}", batchIdHeader); + Party payer = partyMapper(gsmaChannelRequest.getDebitParty()); + Party payee = partyMapper(gsmaChannelRequest.getCreditParty()); + MoneyData amount = amountMapper(gsmaChannelRequest.getAmount(), gsmaChannelRequest.getCurrency()); + + channelRequest.setPayer(payer); + channelRequest.setPayee(payee); + channelRequest.setAmount(amount); + + TransactionType transactionType = new TransactionType(); + transactionType.setInitiator(PAYER); + transactionType.setInitiatorType(CONSUMER); + transactionType.setScenario(TRANSFER); + + Map extraVariables = new HashMap<>(); + extraVariables.put(IS_RTP_REQUEST, false); + extraVariables.put(TRANSACTION_TYPE, "transfer"); + extraVariables.put(BATCH_ID, batchIdHeader); + extraVariables.put("initiator", transactionType.getInitiator().name()); + extraVariables.put("initiatorType", transactionType.getInitiatorType().name()); + extraVariables.put("scenario", transactionType.getScenario().name()); + extraVariables.put("amount", + new FspMoneyData(channelRequest.getAmount().getAmountDecimal(), channelRequest.getAmount().getCurrency())); + extraVariables.put("processType", "api"); + extraVariables.put("payeeTenantId", payeeDfspid); + extraVariables.put("clientCorrelationId", clientCorrelationId); + + String tenantId = exchange.getIn().getHeader("Platform-TenantId", String.class); + extraVariables.put(TENANT_ID, tenantId); + channelRequest.setTransactionType(transactionType); + + PartyIdInfo requestedParty = (boolean) extraVariables.get(IS_RTP_REQUEST) ? channelRequest.getPayer().getPartyIdInfo() + : channelRequest.getPayee().getPartyIdInfo(); + extraVariables.put(PARTY_ID_TYPE, requestedParty.getPartyIdType()); + extraVariables.put(PARTY_ID, requestedParty.getPartyIdentifier()); + + extraVariables.put(GSMA_CHANNEL_REQUEST, objectMapper.writeValueAsString(gsmaChannelRequest)); + extraVariables.put(NOTE, gsmaChannelRequest.getDescriptionText()); + logger.info("Payee Tenant ID {}", extraVariables.get("payeeTenantId")); + String bpmn = getWorkflowForTenant(tenantId); + String tenantSpecificBpmn = bpmn.equals("default") ? baseTransaction.replace("{dfspid}", tenantId) + : bpmn.replace("{dfspid}", tenantId); + String transactionId = zeebeProcessStarter.startZeebeWorkflow(tenantSpecificBpmn, + objectMapper.writeValueAsString(channelRequest), extraVariables); + JSONObject response = new JSONObject(); + response.put("transactionId", transactionId); + exchange.getIn().setBody(response.toString()); + }); + + from("direct:post-gsma-payer-int-transfer").id("gsma-payer-inttransfer") + .log(LoggingLevel.INFO, "## CHANNEL -> GSMA PAYER initiated international transfer").unmarshal() + .json(JsonLibrary.Jackson, GSMATransaction.class).to("bean-validator:request").process(exchange -> { + GSMATransaction gsmaChannelRequest = exchange.getIn().getBody(GSMATransaction.class); // GSMA Object + TransactionChannelRequestDTO channelRequest = new TransactionChannelRequestDTO(); // Fineract Object + + Party payer = partyMapper(gsmaChannelRequest.getDebitParty()); + Party payee = partyMapper(gsmaChannelRequest.getCreditParty()); + MoneyData amount = amountMapper(gsmaChannelRequest.getAmount(), gsmaChannelRequest.getCurrency()); + + channelRequest.setPayer(payer); + channelRequest.setPayee(payee); + channelRequest.setAmount(amount); + + TransactionType transactionType = new TransactionType(); + transactionType.setInitiator(PAYER); + transactionType.setInitiatorType(CONSUMER); + transactionType.setScenario(TRANSFER); + + Map extraVariables = new HashMap<>(); + extraVariables.put(IS_RTP_REQUEST, false); + extraVariables.put(TRANSACTION_TYPE, "inttransfer"); + + String tenantId = exchange.getIn().getHeader("Platform-TenantId", String.class); + extraVariables.put(TENANT_ID, tenantId); + String bpmn = getWorkflowForTenant(tenantId); + String tenantSpecificBpmn = bpmn.equals("default") ? internationalRemittancePayer : bpmn.replace("{dfspid}", tenantId); + channelRequest.setTransactionType(transactionType); + + PartyIdInfo requestedParty = (boolean) extraVariables.get(IS_RTP_REQUEST) ? channelRequest.getPayer().getPartyIdInfo() + : channelRequest.getPayee().getPartyIdInfo(); + extraVariables.put(PARTY_ID_TYPE, requestedParty.getPartyIdType()); + extraVariables.put(PARTY_ID, requestedParty.getPartyIdentifier()); + + extraVariables.put(GSMA_CHANNEL_REQUEST, objectMapper.writeValueAsString(gsmaChannelRequest)); + + String transactionId = zeebeProcessStarter.startZeebeWorkflow(tenantSpecificBpmn, + objectMapper.writeValueAsString(channelRequest), extraVariables); + JSONObject response = new JSONObject(); + response.put("transactionId", transactionId); + exchange.getIn().setBody(response.toString()); + }); + + from("direct:post-gsma-deposit").id("gsma-payee-deposit").log(LoggingLevel.INFO, "## CHANNEL -> GSMA PAYEE deposit").unmarshal() + .json(JsonLibrary.Jackson, GSMATransaction.class).to("bean-validator:request").process(exchange -> { + GSMATransaction gsmaChannelRequest = exchange.getIn().getBody(GSMATransaction.class); // GSMA Object + TransactionChannelRequestDTO channelRequest = new TransactionChannelRequestDTO(); // Fineract Object + String clientCorrelationId = exchange.getIn().getHeader("X-CorrelationID", String.class); + Party payer = partyMapper(gsmaChannelRequest.getDebitParty()); + Party payee = partyMapper(gsmaChannelRequest.getCreditParty()); + MoneyData amount = amountMapper(gsmaChannelRequest.getAmount(), gsmaChannelRequest.getCurrency()); + + channelRequest.setPayer(payer); + channelRequest.setPayee(payee); + channelRequest.setAmount(amount); + + Map extraVariables = new HashMap<>(); + + String tenantId = exchange.getIn().getHeader("Platform-TenantId", String.class); + extraVariables.put(TENANT_ID, tenantId); + String bpmn = getWorkflowForTenant(tenantId); + String tenantSpecificBpmn = bpmn.equals("default") ? internationalRemittancePayee.replace("{dfspid}", tenantId) + : bpmn.replace("{dfspid}", tenantId); + + extraVariables.put(GSMA_CHANNEL_REQUEST, objectMapper.writeValueAsString(gsmaChannelRequest)); + extraVariables.put(NOTE, gsmaChannelRequest.getDescriptionText()); + + String transactionId = zeebeProcessStarter.startZeebeWorkflow(tenantSpecificBpmn, + objectMapper.writeValueAsString(channelRequest), extraVariables); + + RequestStateDTO gsmaResponse = new RequestStateDTO(); + gsmaResponse.setServerCorrelationId(transactionId); + gsmaResponse.setStatus("pending"); + gsmaResponse.setNotificationMethod("polling"); + gsmaResponse.setObjectReference(""); + gsmaResponse.setPollLimit(""); + extraVariables.put("clientCorrelationId", clientCorrelationId); + + exchange.getIn().setBody(objectMapper.writeValueAsString(gsmaResponse)); + exchange.getIn().setHeader(Exchange.HTTP_RESPONSE_CODE, constant(202)); + }); + + } + + // validates and return errorDTO if validation is failed or else null + private PhErrorDTO validateGsmaRequest(Exchange exchange) { + GSMATransaction gsmaChannelRequest = exchange.getIn().getBody(GSMATransaction.class); + + String defaultMessageInCaseOfMissingMandatoryField = gsmaMandatoryFieldValidation(gsmaChannelRequest); + if (defaultMessageInCaseOfMissingMandatoryField != null) { + return new PhErrorDTO.PhErrorDTOBuilder(PaymentHubError.MandatoryValueNotSupplied) + .developerMessage("Make sure all mandatory fields are provided, check the API spec for more info.") + .defaultUserMessage(defaultMessageInCaseOfMissingMandatoryField).build(); + } + + double amount; + try { + amount = Double.parseDouble(gsmaChannelRequest.getAmount()); + } catch (Exception e) { + return new PhErrorDTO.PhErrorDTOBuilder(PaymentHubError.FormatError) + .developerMessage("Amount field supports decimal values, with non negative value.") + .defaultUserMessage("Invalid amount format.").build(); + } + if (amount <= 0) { + return new PhErrorDTO.PhErrorDTOBuilder(PaymentHubError.NegativeValue) + .developerMessage("Amount field supports decimal values, with non negative value.") + .defaultUserMessage("Invalid amount format.").build(); + } + if (gsmaChannelRequest.getDebitParty()[0].getKey().equals(gsmaChannelRequest.getCreditParty()[0].getKey()) + && gsmaChannelRequest.getDebitParty()[0].getValue().equals(gsmaChannelRequest.getCreditParty()[0].getValue())) { + return new PhErrorDTO.PhErrorDTOBuilder(PaymentHubError.SamePartiesError) + .developerMessage("Credit and Debit MSISDNs can't be same") + .defaultUserMessage(PaymentHubError.SamePartiesError.getErrorDescription()).build(); + } + + return null; + } + + // check if mandatory field is non-empty or returns developer message + public String gsmaMandatoryFieldValidation(GSMATransaction gsmaChannelRequest) { + if (gsmaChannelRequest.getAmount().isEmpty()) { + return "Amount can't be empty"; + } + if (gsmaChannelRequest.getCreditParty().length == 0) { + return "Credit party can't pe empty"; + } + if (gsmaChannelRequest.getDebitParty().length == 0) { + return "Debit party can't be empty"; + } + if (gsmaChannelRequest.getCurrency().isEmpty()) { + return "Currency can't be empty"; + } + + return null; + } + + public Party partyMapper(GsmaParty[] gsmaParties) { + IdentifierType identifierType = IdentifierType.MSISDN; + + switch (gsmaParties[0].getKey()) { + case "accountid": + identifierType = IdentifierType.ACCOUNT_ID; + break; + case "identityalias": + identifierType = IdentifierType.ALIAS; + break; + case "iban": + identifierType = IdentifierType.IBAN; + break; + case "emailaddress": + identifierType = IdentifierType.EMAIL; + break; + } + + PartyIdInfo partyIdInfo = new PartyIdInfo(identifierType, gsmaParties[0].getValue()); + return new Party(partyIdInfo); + } + + // public Party partyMapper(GsmaParty[] gsmaParties, Kyc kyc) { + // return new Party(); // To be taken care of + // } + + public MoneyData amountMapper(String amount, String currency) { + MoneyData moneyData = new MoneyData(); + amount.trim(); + moneyData.setAmount(amount); + moneyData.setCurrency(currency); + + return moneyData; + } + + public String getWorkflowForTenant(String tenantId) { + for (TenantImplementation tenant : tenantImplementationProperties.getTenants()) { + if (tenant.getId().equals(tenantId)) { + return tenant.getFlows().getOrDefault("gsma-base-transaction", "default"); + } + } + return "default"; + } +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/examples/ErrorDetailsDto.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/examples/ErrorDetailsDto.java new file mode 100644 index 000000000..652451871 --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/examples/ErrorDetailsDto.java @@ -0,0 +1,19 @@ +package org.mifos.connector.channel.examples; + +import io.swagger.v3.oas.annotations.media.Schema; + +@Schema(description = "Error details") +public class ErrorDetailsDto { + + @Schema(description = "Error category", example = "Validation") + public String errorCategory; + + @Schema(description = "Error code", example = "error.msg.schema.payee.party.id.type.cannot.be.null.or.empty") + public String errorCode; + + @Schema(description = "Error description", example = "Payee party Id Type cannot be null or empty") + public String errorDescription; + + @Schema(description = "Error parameters", example = "null") + public Object errorParameters; +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/examples/InvalidRequestBodyResponseDto.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/examples/InvalidRequestBodyResponseDto.java new file mode 100644 index 000000000..bc8272824 --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/examples/InvalidRequestBodyResponseDto.java @@ -0,0 +1,29 @@ +package org.mifos.connector.channel.examples; + +import io.swagger.v3.oas.annotations.media.Schema; +import java.util.List; + +@Schema(description = "Example response for invalid request body") +public class InvalidRequestBodyResponseDto { + + @Schema(description = "Error category", example = "Validation") + public String errorCategory; + + @Schema(description = "Error code", example = "error.msg.schema.validation.errors") + public String errorCode; + + @Schema(description = "Error description", example = "The request is invalid") + public String errorDescription; + + @Schema(description = "Developer message", example = "The request is invalid") + public String developerMessage; + + @Schema(description = "User message", example = "The request is invalid") + public String defaultUserMessage; + + @Schema(description = "Error parameters", example = "null") + public Object errorParameters; + + @Schema(description = "List of errors") + public List errors; +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/examples/SuccessfulTransferResponseDto.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/examples/SuccessfulTransferResponseDto.java new file mode 100644 index 000000000..f512bb474 --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/examples/SuccessfulTransferResponseDto.java @@ -0,0 +1,10 @@ +package org.mifos.connector.channel.examples; + +import io.swagger.v3.oas.annotations.media.Schema; + +@Schema(description = "Example response for a successful transfer") +public class SuccessfulTransferResponseDto { + + @Schema(description = "Transaction ID", example = "c3ce2b92-85e1-42b1-a71f-08f2ee44d42b") + public String transactionId; +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/examples/SuccessfulTxnStateResponseDTO.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/examples/SuccessfulTxnStateResponseDTO.java new file mode 100644 index 000000000..32bd92259 --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/examples/SuccessfulTxnStateResponseDTO.java @@ -0,0 +1,12 @@ +package org.mifos.connector.channel.examples; + +import io.swagger.v3.oas.annotations.media.Schema; + +public class SuccessfulTxnStateResponseDTO { + + @Schema(description = "Transaction ID", example = "c3ce2b92-85e1-42b1-a71f-08f2ee44d42b") + public String transactionId; + + @Schema(description = "transferState", example = "RECEIVED") + public String transferState; +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/gsma_api/ChannelGSMAAPIController.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/gsma_api/ChannelGSMAAPIController.java new file mode 100644 index 000000000..c2314cab7 --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/gsma_api/ChannelGSMAAPIController.java @@ -0,0 +1,24 @@ +package org.mifos.connector.channel.gsma_api; + +import javax.servlet.http.HttpServletResponse; +import org.apache.camel.Exchange; +import org.apache.camel.ProducerTemplate; +import org.mifos.connector.channel.utils.Headers; +import org.mifos.connector.channel.utils.SpringWrapperUtil; +import org.springframework.beans.factory.annotation.Autowired; + +public class ChannelGSMAAPIController implements GSMAAPI { + + @Autowired + private ProducerTemplate producerTemplate; + + @Override + public String gsma(HttpServletResponse response) throws Exception { + Headers headers = new Headers.HeaderBuilder().build(); + Exchange exchange = SpringWrapperUtil.getDefaultWrappedExchange(producerTemplate.getCamelContext(), headers, null); + producerTemplate.send("direct:get-channel-gsma", exchange); + response.setStatus(exchange.getIn().getHeader(Exchange.HTTP_RESPONSE_CODE, Integer.class)); + + return exchange.getIn().getBody(String.class); + } +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/gsma_api/GSMAAPI.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/gsma_api/GSMAAPI.java new file mode 100644 index 000000000..3c771fd9e --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/gsma_api/GSMAAPI.java @@ -0,0 +1,10 @@ +package org.mifos.connector.channel.gsma_api; + +import javax.servlet.http.HttpServletResponse; +import org.springframework.web.bind.annotation.GetMapping; + +public interface GSMAAPI { + + @GetMapping("/channel/gsma") + String gsma(HttpServletResponse response) throws Exception; +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/gsma_api/GSMADepositAPI.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/gsma_api/GSMADepositAPI.java new file mode 100644 index 000000000..d3eac2020 --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/gsma_api/GSMADepositAPI.java @@ -0,0 +1,16 @@ +package org.mifos.connector.channel.gsma_api; + +import com.fasterxml.jackson.core.JsonProcessingException; +import org.mifos.connector.common.gsma.dto.GSMATransaction; +import org.mifos.connector.common.gsma.dto.RequestStateDTO; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestHeader; + +public interface GSMADepositAPI { + + @PostMapping("/channel/gsma/deposit") + RequestStateDTO gsmadeposit(@RequestHeader(value = "Platform-TenantId") String tenant, + @RequestHeader(value = "X-CorrelationID", required = false) String correlationId, @RequestBody GSMATransaction requestBody) + throws JsonProcessingException; +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/gsma_api/GSMADepositAPIController.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/gsma_api/GSMADepositAPIController.java new file mode 100644 index 000000000..6902242a4 --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/gsma_api/GSMADepositAPIController.java @@ -0,0 +1,40 @@ +package org.mifos.connector.channel.gsma_api; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import io.camunda.zeebe.client.api.command.ClientStatusException; +import io.grpc.Status; +import org.apache.camel.Exchange; +import org.apache.camel.ProducerTemplate; +import org.mifos.connector.channel.utils.Headers; +import org.mifos.connector.channel.utils.SpringWrapperUtil; +import org.mifos.connector.common.gsma.dto.GSMATransaction; +import org.mifos.connector.common.gsma.dto.RequestStateDTO; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.RestController; + +@RestController +public class GSMADepositAPIController implements GSMADepositAPI { + + @Autowired + private ProducerTemplate producerTemplate; + + @Autowired + ObjectMapper objectMapper; + + @Override + public RequestStateDTO gsmadeposit(String tenant, String correlationId, GSMATransaction requestBody) throws JsonProcessingException { + org.mifos.connector.channel.utils.Headers headers = new Headers.HeaderBuilder().addHeader("Platform-TenantId", tenant) + .addHeader("X-CorrelationID", correlationId).build(); + Exchange exchange = SpringWrapperUtil.getDefaultWrappedExchange(producerTemplate.getCamelContext(), headers, + objectMapper.writeValueAsString(requestBody)); + producerTemplate.send("direct:post-gsma-deposit", exchange); + Exception cause = exchange.getProperty(Exchange.EXCEPTION_CAUGHT, Exception.class); + if (cause instanceof ClientStatusException) { + throw new ClientStatusException(Status.FAILED_PRECONDITION, cause); + } + + String body = exchange.getIn().getBody(String.class); + return objectMapper.readValue(body, RequestStateDTO.class); + } +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/gsma_api/GSMATransferAPI.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/gsma_api/GSMATransferAPI.java new file mode 100644 index 000000000..1f2c4173c --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/gsma_api/GSMATransferAPI.java @@ -0,0 +1,20 @@ +package org.mifos.connector.channel.gsma_api; + +import static org.mifos.connector.channel.camel.config.CamelProperties.BATCH_ID_HEADER; + +import com.fasterxml.jackson.core.JsonProcessingException; +import org.mifos.connector.common.gsma.dto.GSMATransaction; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestHeader; + +public interface GSMATransferAPI { + + @PostMapping("/channel/gsma/transfer") + ResponseEntity gsmatransfer(@RequestHeader(value = "Platform-TenantId") String tenant, + @RequestHeader(value = "X-CorrelationID", required = false) String correlationId, + @RequestHeader(value = BATCH_ID_HEADER, required = false) String batchId, @RequestBody GSMATransaction requestBody) + throws JsonProcessingException; + +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/gsma_api/GSMATransferAPIController.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/gsma_api/GSMATransferAPIController.java new file mode 100644 index 000000000..d072326f8 --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/gsma_api/GSMATransferAPIController.java @@ -0,0 +1,57 @@ +package org.mifos.connector.channel.gsma_api; + +import static org.mifos.connector.channel.camel.config.CamelProperties.BATCH_ID; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import io.camunda.zeebe.client.api.command.ClientStatusException; +import io.grpc.Status; +import org.apache.camel.Exchange; +import org.apache.camel.ProducerTemplate; +import org.mifos.connector.channel.utils.Headers; +import org.mifos.connector.channel.utils.SpringWrapperUtil; +import org.mifos.connector.common.channel.dto.PhErrorDTO; +import org.mifos.connector.common.gsma.dto.GSMATransaction; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.RestController; + +@RestController +public class GSMATransferAPIController implements GSMATransferAPI { + + private Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Autowired + private ProducerTemplate producerTemplate; + + @Autowired + ObjectMapper objectMapper; + + @Override + public ResponseEntity gsmatransfer(String tenant, String correlationId, String batchId, GSMATransaction requestBody) + throws JsonProcessingException { + org.mifos.connector.channel.utils.Headers headers = new Headers.HeaderBuilder().addHeader("Platform-TenantId", tenant) + .addHeader("X-CorrelationID", correlationId).addHeader(BATCH_ID, batchId).build(); + Exchange exchange = SpringWrapperUtil.getDefaultWrappedExchange(producerTemplate.getCamelContext(), headers, + objectMapper.writeValueAsString(requestBody)); + logger.info("Batch id: " + batchId); + producerTemplate.send("direct:post-gsma-transfer", exchange); + Exception cause = exchange.getProperty(Exchange.EXCEPTION_CAUGHT, Exception.class); + if (cause instanceof ClientStatusException) { + throw new ClientStatusException(Status.FAILED_PRECONDITION, cause); + } + + String body = exchange.getIn().getBody(String.class); + try { + if (body.contains("error")) { + return new ResponseEntity<>(objectMapper.readValue(body, PhErrorDTO.class), HttpStatus.BAD_REQUEST); + } + return new ResponseEntity<>(objectMapper.readValue(body, GsmaP2PResponseDto.class), HttpStatus.OK); + } catch (Exception e) { + return new ResponseEntity<>(null, HttpStatus.INTERNAL_SERVER_ERROR); + } + } +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/gsma_api/GSMAinttransferAPI.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/gsma_api/GSMAinttransferAPI.java new file mode 100644 index 000000000..62f791a62 --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/gsma_api/GSMAinttransferAPI.java @@ -0,0 +1,14 @@ +package org.mifos.connector.channel.gsma_api; + +import com.fasterxml.jackson.core.JsonProcessingException; +import org.mifos.connector.common.gsma.dto.GSMATransaction; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestHeader; + +public interface GSMAinttransferAPI { + + @PostMapping("/channel/gsma/inttransfer") + GsmaP2PResponseDto gsmaintransfer(@RequestHeader(value = "Platform-TenantId") String tenant, @RequestBody GSMATransaction requestBody) + throws JsonProcessingException; +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/gsma_api/GSMAinttransferAPIController.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/gsma_api/GSMAinttransferAPIController.java new file mode 100644 index 000000000..b71a56bac --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/gsma_api/GSMAinttransferAPIController.java @@ -0,0 +1,30 @@ +package org.mifos.connector.channel.gsma_api; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.apache.camel.Exchange; +import org.apache.camel.ProducerTemplate; +import org.mifos.connector.channel.utils.Headers; +import org.mifos.connector.channel.utils.SpringWrapperUtil; +import org.mifos.connector.common.gsma.dto.GSMATransaction; +import org.springframework.beans.factory.annotation.Autowired; + +public class GSMAinttransferAPIController implements GSMAinttransferAPI { + + @Autowired + private ProducerTemplate producerTemplate; + + @Autowired + ObjectMapper objectMapper; + + @Override + public GsmaP2PResponseDto gsmaintransfer(String tenant, GSMATransaction requestBody) throws JsonProcessingException { + org.mifos.connector.channel.utils.Headers headers = new Headers.HeaderBuilder().addHeader("Platform-TenantId", tenant).build(); + Exchange exchange = SpringWrapperUtil.getDefaultWrappedExchange(producerTemplate.getCamelContext(), headers, + objectMapper.writeValueAsString(requestBody)); + producerTemplate.send("direct:post-gsma-payer-int-transfer", exchange); + + String body = exchange.getIn().getBody(String.class); + return objectMapper.readValue(body, GsmaP2PResponseDto.class); + } +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/gsma_api/GsmaP2PResponseDto.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/gsma_api/GsmaP2PResponseDto.java new file mode 100644 index 000000000..fc5415a25 --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/gsma_api/GsmaP2PResponseDto.java @@ -0,0 +1,6 @@ +package org.mifos.connector.channel.gsma_api; + +public class GsmaP2PResponseDto { + + public String transactionId; +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/interceptor/IdInterceptor.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/interceptor/IdInterceptor.java new file mode 100644 index 000000000..b59d55e6f --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/interceptor/IdInterceptor.java @@ -0,0 +1,155 @@ +package org.mifos.connector.channel.interceptor; + +import static org.mifos.connector.channel.camel.config.CamelProperties.CLIENTCORRELATIONID; + +import com.fasterxml.jackson.annotation.JsonAutoDetect; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; +import java.io.IOException; +import java.util.Arrays; +import java.util.List; +import java.util.Set; +import java.util.concurrent.TimeUnit; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import org.apache.commons.lang3.StringUtils; +import org.mifos.connector.channel.camel.routes.ChannelRouteBuilder; +import org.mifos.connector.common.channel.dto.PhErrorDTO; +import org.mifos.connector.common.exception.PaymentHubError; +import org.mifos.connector.common.exception.PaymentHubErrorCategory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Primary; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.stereotype.Component; +import org.springframework.web.servlet.HandlerInterceptor; + +@Component +@Primary +public class IdInterceptor implements HandlerInterceptor { + + @Autowired + ChannelRouteBuilder channelRouteBuilder; + + @Value("${redis.idempotency.enabled}") + Boolean redisIdempotencyEnabled; + + @Value("${redis.idempotency.apiList}.split(',')") + private Set apiList; + + @Value("${redis.idempotency.keyFormat}") + String keyFormat; + + @Value("${redis.cacheRetencyDuration}") + long cacheRetencyDuration; + + @Autowired + public RedisTemplate redisTemplate; + + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + IdInterceptor(Set apiList) { + this.apiList = apiList; + } + + @Override + public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { + + if (redisIdempotencyEnabled) { + if (apiList.contains(request.getRequestURI())) { + logger.debug("redis idempotency is enabled for this api,checking for idempotency"); + return checkIdempotency(request, response); + } else { + logger.debug("redis idempotency is disabled for this api,proceeding with request"); + } + return true; + } else { + logger.debug("redis idempotency is disabled,proceeding with request"); + } + return true; + } + + private boolean checkIdempotency(HttpServletRequest request, HttpServletResponse response) { + PhErrorDTO errorDTO = null; + String correlationId = request.getHeader(CLIENTCORRELATIONID); + if (correlationId.isBlank()) { + logger.debug("X-CorrelationID is missing,attaching error dto to response"); + errorDTO = new PhErrorDTO.PhErrorDTOBuilder(PaymentHubError.MandatoryValueNotSupplied) + .addErrorParameter(CLIENTCORRELATIONID, "X-CorrelationID") + .developerMessage("Pass the valid header value for " + CLIENTCORRELATIONID).build(); + createError(response, errorDTO); + return false; + } + String key = createRedisKey(request.getHeader("Platform-TenantId"), correlationId, request.getRequestURI(), keyFormat); + logger.debug("X-CorrelationID value is {}", correlationId); + if (Boolean.TRUE.equals(redisTemplate.hasKey(key))) { + logger.debug("X-CorrelationID exists already in redis,attaching error dto to response"); + errorDTO = new PhErrorDTO.PhErrorDTOBuilder(PaymentHubError.TransactionExistsError) + .addErrorParameter(CLIENTCORRELATIONID, correlationId) + .developerMessage("Pass the valid header value for " + CLIENTCORRELATIONID).build(); + createError(response, errorDTO); + response.setHeader(CLIENTCORRELATIONID, correlationId); + return false; + } else { + logger.debug("X-CorrelationID does not exist in redis,proceeding with request"); + redisTemplate.opsForValue().set(key, correlationId, cacheRetencyDuration, TimeUnit.DAYS); + return true; + } + + } + + private String createRedisKey(String tenant, String correlationId, String requestURI, String keyFormat) { + if (keyFormat.isBlank()) { + logger.info("redis key format is empty,using default key format as {tenant}{clientCorrelationId}"); + keyFormat = tenant + correlationId; + } else if (!keyFormat.isBlank()) { + List keyFormatList = Arrays.asList(keyFormat.split("_")); + String outputString = ""; + for (String keyFormatStr : keyFormatList) { + if (keyFormatStr.equals("tenant") && StringUtils.isNotBlank(tenant)) { + outputString = outputString + tenant + "_"; + } else if (keyFormatStr.equals("clientCorrelationId") && StringUtils.isNotBlank(correlationId)) { + outputString = outputString + correlationId + "_"; + } else if (keyFormatStr.equals("api") && StringUtils.isNotBlank(requestURI)) { + outputString = outputString + requestURI + "_"; + } + keyFormat = StringUtils.chop(outputString); + } + } else { + throw new RuntimeException(String.format("Invalid key format %s", keyFormat)); + } + + logger.debug("redis key is {}", keyFormat); + return keyFormat; + } + + public void createError(HttpServletResponse response, PhErrorDTO errorDTO) { + if (errorDTO.getErrorCategory().equals(PaymentHubErrorCategory.System.name())) { + response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); + } else { + response.setStatus(HttpServletResponse.SC_BAD_REQUEST); + } + try { + response.getWriter().write(getObjectMapper().writeValueAsString(errorDTO)); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + public ObjectMapper getObjectMapper() { + ObjectMapper objectMapper = new ObjectMapper(); + objectMapper.registerModule(new JavaTimeModule()); + objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false); + objectMapper.setVisibilityChecker(objectMapper.getSerializationConfig().getDefaultVisibilityChecker() + .withFieldVisibility(JsonAutoDetect.Visibility.ANY).withGetterVisibility(JsonAutoDetect.Visibility.NONE)); + return objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL) + .configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true) + .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + } + +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/interceptor/ValidatorInterceptor.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/interceptor/ValidatorInterceptor.java new file mode 100644 index 000000000..071bb3ab5 --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/interceptor/ValidatorInterceptor.java @@ -0,0 +1,71 @@ +package org.mifos.connector.channel.interceptor; + +import com.fasterxml.jackson.databind.ObjectMapper; +import java.lang.reflect.Method; +import java.util.Arrays; +import java.util.Set; +import java.util.stream.Collectors; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import lombok.extern.slf4j.Slf4j; +import org.mifos.connector.channel.service.ValidateHeaders; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.http.HttpStatus; +import org.springframework.stereotype.Component; +import org.springframework.web.method.HandlerMethod; +import org.springframework.web.servlet.HandlerInterceptor; + +@Slf4j +@Component +public class ValidatorInterceptor implements HandlerInterceptor { + + @Autowired + private ApplicationContext applicationContext; + + @Override + public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { + if (handler instanceof HandlerMethod) { + HandlerMethod handlerMethod = (HandlerMethod) handler; + Method method = handlerMethod.getMethod(); + if (method.isAnnotationPresent(ValidateHeaders.class)) { + ValidateHeaders validateHeaders = method.getAnnotation(ValidateHeaders.class); + Set headersSet = extractRequiredHeaders(validateHeaders); + + Object validatorInstance = getValidatorInstance(validateHeaders); + + Object methodResponse = invokeValidationMethod(validateHeaders, validatorInstance, headersSet, request); + + if (methodResponse != null) { + handleValidationFailure(response, methodResponse); + return false; + } + } + } + return true; + } + + private Set extractRequiredHeaders(ValidateHeaders validateHeaders) { + return Arrays.stream(validateHeaders.requiredHeaders()).map(String::toLowerCase).collect(Collectors.toSet()); + } + + private Object getValidatorInstance(ValidateHeaders validateHeaders) { + return applicationContext.getBean(validateHeaders.validatorClass()); + } + + private Object invokeValidationMethod(ValidateHeaders validateHeaders, Object validatorInstance, Set headersSet, + HttpServletRequest request) throws Exception { + Method validationMethod = validatorInstance.getClass().getDeclaredMethod(validateHeaders.validationFunction(), Set.class, + HttpServletRequest.class); + Object[] parameters = { headersSet, request }; + return validationMethod.invoke(validatorInstance, parameters); + } + + private void handleValidationFailure(HttpServletResponse response, Object methodResponse) throws Exception { + ObjectMapper objectMapper = new ObjectMapper(); + String jsonResponse = objectMapper.writeValueAsString(methodResponse); + response.setHeader("Content-Type", "application/json"); + response.setStatus(HttpStatus.BAD_REQUEST.value()); + response.getWriter().write(jsonResponse); + } +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/interceptor/config/RedisRouteConfig.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/interceptor/config/RedisRouteConfig.java new file mode 100644 index 000000000..d24a90ce9 --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/interceptor/config/RedisRouteConfig.java @@ -0,0 +1,28 @@ +package org.mifos.connector.channel.interceptor.config; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.redis.connection.jedis.JedisConnectionFactory; +import org.springframework.data.redis.core.RedisTemplate; + +@Configuration +public class RedisRouteConfig { + + private JedisConnectionFactory jedisConnectionFactory; + public RedisTemplate redisTemplate; + + @Value("${redis.host}") + private String redisHost; + @Value("${redis.port}") + private int redisPort; + @Value("${redis.password}") + private String redisPassword; + + public JedisConnectionFactory setupConnector() { + JedisConnectionFactory jedisConnectionFactory = new JedisConnectionFactory(); + jedisConnectionFactory.setHostName(redisHost); + jedisConnectionFactory.setPort(redisPort); + jedisConnectionFactory.setPassword(redisPassword); + return jedisConnectionFactory; + } +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/interceptor/config/SpringConfig.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/interceptor/config/SpringConfig.java new file mode 100644 index 000000000..464daf510 --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/interceptor/config/SpringConfig.java @@ -0,0 +1,18 @@ +package org.mifos.connector.channel.interceptor.config; + +import io.lettuce.core.ClientOptions; +import io.lettuce.core.protocol.ProtocolVersion; +import org.springframework.boot.autoconfigure.data.redis.LettuceClientConfigurationBuilderCustomizer; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.redis.connection.lettuce.LettuceClientConfiguration; + +@Configuration +public class SpringConfig implements LettuceClientConfigurationBuilderCustomizer { + + @Override + public void customize(LettuceClientConfiguration.LettuceClientConfigurationBuilder clientConfigurationBuilder) { + // manually specifying RESP2 + clientConfigurationBuilder.clientOptions(ClientOptions.builder().protocolVersion(ProtocolVersion.RESP2).build()); + } + +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/interceptor/config/WebMvc.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/interceptor/config/WebMvc.java new file mode 100644 index 000000000..0ce7cc55d --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/interceptor/config/WebMvc.java @@ -0,0 +1,3 @@ +package org.mifos.connector.channel.interceptor.config; + +public interface WebMvc {} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/interceptor/config/WebMvcConfig.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/interceptor/config/WebMvcConfig.java new file mode 100644 index 000000000..aa2bc13ed --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/interceptor/config/WebMvcConfig.java @@ -0,0 +1,26 @@ +package org.mifos.connector.channel.interceptor.config; + +import org.mifos.connector.channel.interceptor.ValidatorInterceptor; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Primary; +import org.springframework.stereotype.Component; +import org.springframework.web.servlet.HandlerInterceptor; +import org.springframework.web.servlet.config.annotation.InterceptorRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport; + +@Component +@Primary +public class WebMvcConfig extends WebMvcConfigurationSupport implements WebMvc { + + @Autowired + HandlerInterceptor idInterceptor; + @Autowired + ValidatorInterceptor validatorInterceptor; + + @Override + public void addInterceptors(InterceptorRegistry registry) { + registry.addInterceptor(idInterceptor); + registry.addInterceptor(validatorInterceptor).addPathPatterns("/channel/**"); + super.addInterceptors(registry); + } +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/model/Amount.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/model/Amount.java new file mode 100644 index 000000000..2623d8f97 --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/model/Amount.java @@ -0,0 +1,12 @@ +package org.mifos.connector.channel.model; + +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public class Amount { + + private String amount; + private String currency; +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/model/CollectionRequestDTO.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/model/CollectionRequestDTO.java new file mode 100644 index 000000000..31ef98f1b --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/model/CollectionRequestDTO.java @@ -0,0 +1,17 @@ +package org.mifos.connector.channel.model; + +import java.util.ArrayList; +import java.util.List; +import lombok.Getter; +import lombok.Setter; +import org.mifos.connector.common.gsma.dto.CustomData; + +@Getter +@Setter +public class CollectionRequestDTO { + + private ArrayList payer; + private Amount amount; + private TransactionType transactionType; + private List customData; +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/model/GlobalExceptionMapperDTO.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/model/GlobalExceptionMapperDTO.java new file mode 100644 index 000000000..bc08305a8 --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/model/GlobalExceptionMapperDTO.java @@ -0,0 +1,16 @@ +package org.mifos.connector.channel.model; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +public class GlobalExceptionMapperDTO { + + private String responseCode; + private String responseDescription; +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/model/OpsTxnResponseDTO.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/model/OpsTxnResponseDTO.java new file mode 100644 index 000000000..e47b36f9f --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/model/OpsTxnResponseDTO.java @@ -0,0 +1,80 @@ +package org.mifos.connector.channel.model; + +import java.math.BigDecimal; +import java.util.Date; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import lombok.ToString; +import org.mifos.connector.common.operations.type.TransferStatus; + +@NoArgsConstructor +@AllArgsConstructor +@Getter +@Setter +@ToString +public class OpsTxnResponseDTO { + + private Long id; + private Long workflowInstanceKey; + private String transactionId; + private Date startedAt; + private Date completedAt; + private TransferStatus status; + private String statusDetail; + private String payeeDfspId; + private String payeePartyId; + private String payeePartyIdType; + private BigDecimal payeeFee; + private String payeeFeeCurrency; + private String payeeQuoteCode; + private String payerDfspId; + private String payerPartyId; + private String payerPartyIdType; + private BigDecimal payerFee; + private String payerFeeCurrency; + private String payerQuoteCode; + private BigDecimal amount; + private String currency; + private String direction; + private String errorInformation; + private String batchId; + private String clientCorrelationId; + + public static OpsTxnResponseDTO createInstance(Long id, Long workflowInstanceKey, String transactionId, Date startedAt, + Date completedAt, TransferStatus status, String statusDetail, String payeeDfspId, String payeePartyId, String payeePartyIdType, + BigDecimal payeeFee, String payeeFeeCurrency, String payeeQuoteCode, String payerDfspId, String payerPartyId, + String payerPartyIdType, BigDecimal payerFee, String payerFeeCurrency, String payerQuoteCode, BigDecimal amount, + String currency, String direction, String errorInformation, String batchId, String clientCorrelationId) { + + OpsTxnResponseDTO response = new OpsTxnResponseDTO(); + response.id = id; + response.workflowInstanceKey = workflowInstanceKey; + response.transactionId = transactionId; + response.startedAt = startedAt; + response.completedAt = completedAt; + response.status = status; + response.statusDetail = statusDetail; + response.payeeDfspId = payeeDfspId; + response.payeePartyId = payeePartyId; + response.payeePartyIdType = payeePartyIdType; + response.payeeFee = payeeFee; + response.payeeFeeCurrency = payeeFeeCurrency; + response.payeeQuoteCode = payeeQuoteCode; + response.payerDfspId = payerDfspId; + response.payerPartyId = payerPartyId; + response.payerPartyIdType = payerPartyIdType; + response.payerFee = payerFee; + response.payerFeeCurrency = payerFeeCurrency; + response.payerQuoteCode = payerQuoteCode; + response.amount = amount; + response.currency = currency; + response.direction = direction; + response.errorInformation = errorInformation; + response.batchId = batchId; + response.clientCorrelationId = clientCorrelationId; + + return response; + } +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/model/Payer.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/model/Payer.java new file mode 100644 index 000000000..d6714c262 --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/model/Payer.java @@ -0,0 +1,12 @@ +package org.mifos.connector.channel.model; + +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public class Payer { + + private String key; + private String value; +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/model/TransactionType.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/model/TransactionType.java new file mode 100644 index 000000000..27bd8a9ae --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/model/TransactionType.java @@ -0,0 +1,14 @@ +package org.mifos.connector.channel.model; + +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public class TransactionType { + + private String scenario; + private String subScenario; + private String initiator; + private String initiatorType; +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/model/TxnStateResponseDTO.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/model/TxnStateResponseDTO.java new file mode 100644 index 000000000..6c3ec5ad1 --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/model/TxnStateResponseDTO.java @@ -0,0 +1,16 @@ +package org.mifos.connector.channel.model; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +public class TxnStateResponseDTO { + + private String transactionId; + private String transferState; +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/model/ValidationRequestDTO.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/model/ValidationRequestDTO.java new file mode 100644 index 000000000..63300cba9 --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/model/ValidationRequestDTO.java @@ -0,0 +1,23 @@ +package org.mifos.connector.channel.model; + +import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.List; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import org.mifos.connector.common.gsma.dto.CustomData; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +public class ValidationRequestDTO { + + @JsonProperty("primaryIdentifier") + private CustomData primaryIdentifier; + @JsonProperty("secondaryIdentifier") + private CustomData secondaryIdentifier; + @JsonProperty("customData") + private List customData; +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/model/ValidationResponseDTO.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/model/ValidationResponseDTO.java new file mode 100644 index 000000000..7f6e745b0 --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/model/ValidationResponseDTO.java @@ -0,0 +1,25 @@ +package org.mifos.connector.channel.model; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public class ValidationResponseDTO { + + @JsonProperty("transactionId") + public String transactionId; + @JsonProperty("accountHoldingInstitutionId") + public String accountHoldingInstitutionId; + @JsonProperty("amount") + public String amount; + @JsonProperty("currency") + public String currency; + @JsonProperty("msisdn") + public String msisdn; + @JsonProperty("reconciled") + public boolean reconciled; + @JsonProperty("amsName") + public String amsName; +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/properties/TenantImplementation.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/properties/TenantImplementation.java new file mode 100644 index 000000000..ea9cf81b8 --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/properties/TenantImplementation.java @@ -0,0 +1,26 @@ +package org.mifos.connector.channel.properties; + +import java.util.HashMap; + +public class TenantImplementation { + + String id; + HashMap flows; + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public HashMap getFlows() { + return flows; + } + + public void setFlows(HashMap flows) { + this.flows = flows; + } + +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/properties/TenantImplementationProperties.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/properties/TenantImplementationProperties.java new file mode 100644 index 000000000..46eeb24cc --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/properties/TenantImplementationProperties.java @@ -0,0 +1,21 @@ +package org.mifos.connector.channel.properties; + +import java.util.List; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +@Component +@ConfigurationProperties(prefix = "bpmns") +public class TenantImplementationProperties { + + List tenants; + + public List getTenants() { + return tenants; + } + + public void setTenants(List tenants) { + this.tenants = tenants; + } + +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/service/TxnStateService.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/service/TxnStateService.java new file mode 100644 index 000000000..fab4c27cf --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/service/TxnStateService.java @@ -0,0 +1,98 @@ +package org.mifos.connector.channel.service; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import java.util.List; +import org.json.JSONArray; +import org.json.JSONObject; +import org.mifos.connector.channel.camel.config.Client; +import org.mifos.connector.channel.camel.config.ClientProperties; +import org.mifos.connector.channel.camel.routes.ChannelRouteBuilder; +import org.mifos.connector.channel.model.OpsTxnResponseDTO; +import org.mifos.connector.channel.model.TxnStateResponseDTO; +import org.mifos.connector.channel.utils.Constants; +import org.mifos.connector.channel.utils.Headers; +import org.mifos.connector.common.channel.dto.TransactionStatusResponseDTO; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.HttpEntity; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Service; +import org.springframework.web.util.UriComponentsBuilder; + +@Service +public class TxnStateService { + + private Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Autowired + ChannelRouteBuilder routeBuilder; + @Autowired + private ClientProperties clientProperties; + @Value("#{'${dfspids}'.split(',')}") + private List dfspIds; + @Value("${operations.auth-enabled}") + private Boolean operationsAuthEnabled; + private ObjectMapper objectMapper = new ObjectMapper(); + + public TxnStateResponseDTO getTxnState(Headers headers, String correlationId, String requestType) throws JsonProcessingException { + String tenantId = (String) headers.get(Constants.PLATFORM_TENANT_ID); + validateTenantId(tenantId); + + Client client = clientProperties.getClient(tenantId); + requestType = routeBuilder.getRequestType(requestType); + HttpEntity entity = routeBuilder.buildHeader(tenantId, null); + + if (operationsAuthEnabled) { + performAuth(tenantId, client, entity); + } else { + entity = routeBuilder.buildHeader(tenantId, null); + } + + ResponseEntity responseEntity = routeBuilder.callOpsTxnApiUsingWebClient(requestType, correlationId, entity); + JsonNode contentNode = objectMapper.readTree(responseEntity.getBody()).get(Constants.CONTENT); + OpsTxnResponseDTO txnResponseDTO = objectMapper.treeToValue(contentNode.get(0), OpsTxnResponseDTO.class); + + TransactionStatusResponseDTO response = processContents(correlationId, txnResponseDTO, entity, responseEntity); + + TxnStateResponseDTO responseDTO = new TxnStateResponseDTO(); + responseDTO.setTransactionId(response.getTransactionId()); + responseDTO.setTransferState(String.valueOf(response.getTransferState())); + + return responseDTO; + } + + private void validateTenantId(String tenantId) { + if (tenantId == null || !dfspIds.contains(tenantId)) { + throw new RuntimeException("Requested tenant not configured in the connector!"); + } + } + + private void performAuth(String tenantId, Client client, HttpEntity entity) { + UriComponentsBuilder builder = routeBuilder.buildParams(client); + ResponseEntity responseEntity = routeBuilder.callAuthApi(builder, entity); + JSONObject jsonObject = new JSONObject(responseEntity.getBody()); + String token = jsonObject.getString(Constants.ACCESS_TOKEN); + entity = routeBuilder.buildHeader(tenantId, token); + } + + private TransactionStatusResponseDTO processContents(String correlationId, OpsTxnResponseDTO txnResponseDTO, HttpEntity entity, + ResponseEntity responseEntity) { + TransactionStatusResponseDTO response = new TransactionStatusResponseDTO(); + if (txnResponseDTO == null) { + response = routeBuilder.setTxnNotFound(response, correlationId); + } else { + response = routeBuilder.setTxnFound(response, txnResponseDTO); + + responseEntity = routeBuilder.fetchApibyWorkflowKey(entity, txnResponseDTO.getWorkflowInstanceKey()); + JSONArray variables = new JSONObject(responseEntity.getBody()).getJSONArray(Constants.VARIABLES); + String transferCode = routeBuilder.getVariableValue(variables.iterator(), Constants.TRANSFER_CODE); + response.setTransferId(transferCode == null ? null : transferCode.replace("\"", "")); + response.setClientRefId(correlationId); + } + return response; + } +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/service/ValidateHeaders.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/service/ValidateHeaders.java new file mode 100644 index 000000000..9bf1d5101 --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/service/ValidateHeaders.java @@ -0,0 +1,17 @@ +package org.mifos.connector.channel.service; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +public @interface ValidateHeaders { + + String[] requiredHeaders(); + + Class validatorClass(); + + String validationFunction(); +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/utils/AMSProps.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/utils/AMSProps.java new file mode 100644 index 000000000..2d75c285b --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/utils/AMSProps.java @@ -0,0 +1,50 @@ +package org.mifos.connector.channel.utils; + +import java.util.List; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +@Component +@ConfigurationProperties(prefix = "ams") +public class AMSProps { + + private List groups; + + public List getGroups() { + return groups; + } + + public void setGroups(List groups) { + this.groups = groups; + } + + public static class AMS { + + private String identifier; + private String value; + + public String getIdentifier() { + return identifier; + } + + public void setIdentifier(String identifier) { + this.identifier = identifier; + } + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } + + public String getDefaultValue() { + String value = null; + if (getIdentifier().equals("default")) { + value = getValue(); + } + return value; + } + } +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/utils/AMSUtils.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/utils/AMSUtils.java new file mode 100644 index 000000000..ee4782539 --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/utils/AMSUtils.java @@ -0,0 +1,85 @@ +package org.mifos.connector.channel.utils; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import javax.annotation.PostConstruct; +import org.json.JSONObject; +import org.mifos.connector.common.gsma.dto.CustomData; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component +public class AMSUtils { + + private Logger logger = LoggerFactory.getLogger(AMSUtils.class); + + @Autowired + private AMSProps amsProps; + + List ams; + + @Autowired + private ObjectMapper objectMapper; + + @PostConstruct + public List postConstruct() { + ams = amsProps.getGroups(); + return ams; + } + + public String getAMSName(JSONObject body) { + String primaryIdentifierName = body.getJSONObject("primaryIdentifier").getString("key"); + String secondaryIdentifierName = body.getJSONObject("secondaryIdentifier").getString("key"); + String primaryIdentifierVal = body.getJSONObject("primaryIdentifier").getString("value"); + String secondaryIdentifierVal = body.getJSONObject("primaryIdentifier").getString("value"); + String finalAmsVal = "value"; + for (AMSProps.AMS amsIdentifier : postConstruct()) { + logger.info("KEY VALUE PAIR : " + amsIdentifier.getIdentifier() + " " + amsIdentifier.getValue()); + String identifier = amsIdentifier.getIdentifier(); + if (identifier.equalsIgnoreCase(secondaryIdentifierName)) { + finalAmsVal = amsIdentifier.getValue(); + logger.info("Assigned from secondary" + finalAmsVal); + break; + } else if (identifier.equalsIgnoreCase(primaryIdentifierName)) { + finalAmsVal = amsIdentifier.getValue(); + String temp = primaryIdentifierVal; + primaryIdentifierVal = secondaryIdentifierVal; + secondaryIdentifierVal = temp; + logger.info("Assigned from primary" + finalAmsVal); + break; + } else { + if (identifier.equalsIgnoreCase("default")) { + finalAmsVal = amsIdentifier.getDefaultValue(); + logger.info("Assigned default from secondary" + finalAmsVal); + } + } + } // end for loop + logger.info("Identifier name and value {} : {} ", primaryIdentifierName, primaryIdentifierVal); + return finalAmsVal; + } + + public Map setZeebeVariables(List customData, String timer) throws JsonProcessingException { + Map variables = new HashMap<>(); + for (CustomData obj : customData) { + String key = obj.getKey(); + Object value = obj.getValue(); + variables.put(key, value); + } + // Also publishing custom data list + String customDataToString = objectMapper.writeValueAsString(customData); + if (!customData.isEmpty()) { + variables.put("customData", customDataToString); + } + variables.put("timer", timer); + return variables; + } + + public Object getOrDefault(JSONObject body, String value, Object defaultValue) { + return body.has(value) ? body.get(value) : defaultValue; + } +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/utils/CamelDslString.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/utils/CamelDslString.java new file mode 100644 index 000000000..5e8ff7122 --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/utils/CamelDslString.java @@ -0,0 +1,42 @@ +package org.mifos.connector.channel.utils; + +/** + * The static class for getting the camel specific REST DSL paths for different http request type. This class is + * specific to [BeneficiaryRouteBuilder] hence has a base path as [/channel/beneficiary] + * + * use case: where [basePath] = "/channel/beneficiary" Path.getPath("") >> "rest:GET:/channel/beneficiary" + * Path.getPath("{beneficiaryId}") >> "rest:GET:/channel/beneficiary/{beneficiaryId}" Path.postPath("") >> + * "rest:POST:/channel/beneficiary" Path.deletePath("{beneficiaryId}") >> + * "rest:DELETE:/channel/beneficiary/{beneficiaryId}" + */ +public class CamelDslString { + + private final String basePath; + + public CamelDslString(String basePath) { + this.basePath = basePath; + } + + public String getCamelPath(String path, String httpRequestType) { + if (path.isEmpty()) { + return String.format("rest:%s:%s", httpRequestType, basePath); + } + return String.format("rest:%s:%s/%s", httpRequestType, basePath, path); + } + + public String getPath(String path) { + return getCamelPath(path, "GET"); + } + + public String postPath(String path) { + return getCamelPath(path, "POST"); + } + + public String putPath(String path) { + return getCamelPath(path, "PUT"); + } + + public String deletePath(String path) { + return getCamelPath(path, "DELETE"); + } +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/utils/ChannelValidatorsEnum.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/utils/ChannelValidatorsEnum.java new file mode 100644 index 000000000..f38d01594 --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/utils/ChannelValidatorsEnum.java @@ -0,0 +1,89 @@ +package org.mifos.connector.channel.utils; + +import org.mifos.connector.common.exception.PaymentHubErrorCategory; +import org.mifos.connector.common.validation.ValidationCodeType; + +public enum ChannelValidatorsEnum implements ValidationCodeType { + + INVALID_PLATFORM_TENANT_ID_LENGTH("error.msg.schema.platform.tenant.id.length.is.invalid", + "Platform Tenant Id length is invalid"), INVALID_PLATFORM_TENANT_ID( + "error.msg.schema.platform.tenant.id.cannot.be.null.or.empty", "Platform Tenant Id cannot be null or empty"), + + INVALID_AMS_NAME("error.msg.schema.ams.name.cannot.be.null.or.empty", "Ams name cannot be null or empty"), INVALID_AMS_NAME_LENGTH( + "error.msg.schema.ams.name.length.is.invalid", "Ams name length is invalid"), + + INVALID_ACCOUNT_HOLDING_INSTITUTION_ID("error.msg.schema.account.holding.institution.id.cannot.be.null.or.empty", + "Account holding institution id cannot be null or empty"), INVALID_ACCOUNT_HOLDING_INSTITUTION_ID_LENGTH( + "error.msg.schema.account.holding.institution.id.length.is.invalid", + "Account holding institution id length is invalid"), + + INVALID_X_CALLBACK_URL("error.msg.schema.x.callback.url.cannot.be.null.or.empty", + "X callback url cannot be null or empty"), INVALID_X_CALLBACK_URL_LENGTH("error.msg.schema.x.callback.url.length.is.invalid", + "X callback url length is invalid"), + + INVALID_CLIENT_CORRELATION_ID_LENGTH("error.msg.schema.client.correlation.id.length.is.invalid", + "Client correlation id length is invalid"), + + TRANSFER_SCHEMA_VALIDATION_ERROR("error.msg.schema.validation.errors", "The request is invalid"), + + INVALID_PAYER("error.msg.schema.payer.cannot.be.null.or.empty", "Payer cannot be null or empty"), INVALID_PAYEE( + "error.msg.schema.payee.cannot.be.null.or.empty", "Payee cannot be null or empty"), + + INVALID_PAYER_PARTY_ID_INFO("error.msg.schema.payer.party.id.info.cannot.be.null.or.empty", + "Payer party Id Info cannot be null or empty"), INVALID_PAYEE_PARTY_ID_INFO( + "error.msg.schema.payee.party.id.info.cannot.be.null.or.empty", + "Payee party Id Info cannot be null or empty"), INVALID_PAYER_PARTY_IDENTIFIER( + "error.msg.schema.payer.party.identifier.cannot.be.null.or.empty", + "Payer party identifier cannot be null or empty"), INVALID_PAYEE_PARTY_IDENTIFIER( + "error.msg.schema.payee.party.identifier.cannot.be.null.or.empty", + "Payee party identifier cannot be null or empty"), INVALID_PAYER_PARTY_ID_TYPE( + "error.msg.schema.payer.party.id.type.cannot.be.null.or.empty", + "Payer party Id Type cannot be null or empty"), INVALID_PAYEE_PARTY_ID_TYPE( + "error.msg.schema.payee.party.id.type.cannot.be.null.or.empty", + "Payee party Id Type cannot be null or empty"), INVALID_PAYER_PARTY_ID_IDENTIFIER( + "error.msg.schema.payer.party.id.identifier.cannot.be.null.or.empty", + "Payer party id identifier cannot be null or empty"), INVALID_PAYEE_PARTY_ID_IDENTIFIER( + "error.msg.schema.payee.party.id.identifier.cannot.be.null.or.empty", + "Payee party id identifier cannot be null or empty"), + + INVALID_AMOUNT("error.msg.schema.amount.cannot.be.null.or.empty", "Amount cannot be null or empty"), INVALID_AMOUNT_AMOUNT( + "error.msg.schema.amount.amount.cannot.be.null.or.empty", + "Amount amount cannot be null or empty"), INVALID_NEGATIVE_AMOUNT("error.msg.schema.amount.cannot.be.negative", + "Amount cannot be negative"), INVALID_CURRENCY("error.msg.schema.currency.cannot.be.null.or.empty", + "Currency cannot be null or empty"), INVALID_CURRENCY_LENGTH("error.msg.schema.currency.length.is.invalid", + "Currency length is invalid"), + + INVALID_REQUEST_ORGANIZATION_TRANSACTION_REFERENCE( + "error.msg.schema.request.organization_transaction.reference.cannot.be.null.or.empty", + "Request organization transaction reference cannot be null or empty"), INVALID_SUB_TYPE( + "error.msg.schema.sub.type.cannot.be.null.or.empty", "Sub type cannot be null or empty"), INVALID_TYPE( + "error.msg.schema.type.cannot.be.null.or.empty", "Type cannot be null or empty"), INVALID_DESCRIPTION_TEXT( + "error.msg.schema.description.text.cannot.be.null.or.empty", + "Description text cannot be null or empty"), INVALID_REQUEST_DATE( + "error.msg.schema.request.date.cannot.be.null.or.empty", + "Request date cannot be null or empty"), + + HEADER_VALIDATION_ERROR("error.msg.header.validation.errors", "The headers are invalid"); + + private final String code; + private final String category; + private final String message; + + ChannelValidatorsEnum(String code, String message) { + this.code = code; + this.category = PaymentHubErrorCategory.Validation.toString(); + this.message = message; + } + + public String getCode() { + return this.code; + } + + public String getCategory() { + return this.category; + } + + public String getMessage() { + return message; + } +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/utils/ConnectorChannelEnum.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/utils/ConnectorChannelEnum.java new file mode 100644 index 000000000..29c1a6ce4 --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/utils/ConnectorChannelEnum.java @@ -0,0 +1,22 @@ +package org.mifos.connector.channel.utils; + +public enum ConnectorChannelEnum { + + PROCESS_DEFINITION_NOT_FOUND("01", "Process definition not found"), INTERNAL_SERVER_OCCURRED("01", "Internal Server Occurred"); + + private final String value; + private final String message; + + ConnectorChannelEnum(String value, String message) { + this.value = value; + this.message = message; + } + + public String getValue() { + return this.value; + } + + public String getMessage() { + return message; + } +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/utils/Constants.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/utils/Constants.java new file mode 100644 index 000000000..86b29390d --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/utils/Constants.java @@ -0,0 +1,14 @@ +package org.mifos.connector.channel.utils; + +public interface Constants { + + String PLATFORM_TENANT_ID = "Platform-TenantId"; + String ACCESS_TOKEN = "access_token"; + String CONTENT = "content"; + String WORKFLOW_INSTANCE_KEY = "workflowInstanceKey"; + String TRANSFER_CODE = "transferCode"; + String VARIABLES = "variables"; + String CLIENT_CORRELATION_ID = "clientCorrelationId"; + String EQUALS_SIGN = "="; + String COMPLETED = "COMPLETED"; +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/utils/HeaderConstants.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/utils/HeaderConstants.java new file mode 100644 index 000000000..3c6cb89d9 --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/utils/HeaderConstants.java @@ -0,0 +1,14 @@ +package org.mifos.connector.channel.utils; + +@SuppressWarnings("HideUtilityClassConstructor") +public class HeaderConstants { + + public static final String PLATFORM_TENANT_ID = "Platform-TenantId"; + public static final String AMS_NAME = "amsName"; + public static final String ACCOUNT_HOLDING_INSTITUTION_ID = "accountHoldingInstitutionId"; + public static final String X_Callback_URL = "X-CallbackURL"; + public static final String CLIENT_CORRELATION_ID = "X-CorrelationID"; + public static final String REGISTERING_INSTITUTION_ID = "X-Registering-Institution-ID"; + public static final String PAYEE_DFSP_ID = "X-PayeeDFSP-ID"; + public static final String BATCH_ID_HEADER = "X-BatchID"; +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/utils/Headers.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/utils/Headers.java new file mode 100644 index 000000000..6bf354056 --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/utils/Headers.java @@ -0,0 +1,45 @@ +package org.mifos.connector.channel.utils; + +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +public final class Headers { + + private Map headers; + + private Headers() {} + + private void setHeaders(Map headers) { + this.headers = headers; + } + + public Map getHeaders() { + return headers; + } + + public Set getHeadersKey() { + return this.headers.keySet(); + } + + public Object get(String key) { + return this.headers.get(key); + } + + public static class HeaderBuilder { + + private Map headers = new HashMap<>(); + + public HeaderBuilder addHeader(String key, Object value) { + headers.put(key, value); + return this; + } + + public Headers build() { + Headers headersClassInstance = new Headers(); + headersClassInstance.setHeaders(this.headers); + + return headersClassInstance; + } + } +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/utils/MpesaUtils.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/utils/MpesaUtils.java new file mode 100644 index 000000000..909586201 --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/utils/MpesaUtils.java @@ -0,0 +1,64 @@ +package org.mifos.connector.channel.utils; + +import com.google.common.base.Splitter; +import com.google.common.collect.Iterables; +import org.json.JSONArray; +import org.json.JSONObject; + +public final class MpesaUtils { + + private MpesaUtils() {} + + public static String mpesaChannelRequestToChannelRequestConvertor(String channelRequest) { + + JSONObject mpesaChannelRequestJson = new JSONObject(); + + JSONObject channelRequestJson = new JSONObject(channelRequest); + + JSONObject amountJson = channelRequestJson.getJSONObject("amount"); + JSONArray payerArray = channelRequestJson.getJSONArray("payer"); + + // setting amount json + mpesaChannelRequestJson.put("amount", amountJson); + + String payer; + String payee; + + // payer payee conversion + if (((JSONObject) payerArray.get(0)).getString("key").equals("MSISDN")) { + // case when 0th index is MSISDN + String msisdn = ((JSONObject) payerArray.get(0)).getString("value"); + String accountId = ((JSONObject) payerArray.get(1)).getString("value"); + + payer = ((JSONObject) payerArray.get(0)).getString("key") + " " + msisdn; + payee = ((JSONObject) payerArray.get(1)).getString("key") + " " + accountId; + } else { + // case when 0th index is ACCOUNTID + String msisdn = ((JSONObject) payerArray.get(1)).getString("value"); + String accountId = ((JSONObject) payerArray.get(0)).getString("value"); + + payer = ((JSONObject) payerArray.get(1)).getString("key") + " " + msisdn; + payee = ((JSONObject) payerArray.get(0)).getString("key") + " " + accountId; + } + + // setting payer and payee + // mpesaChannelRequestJson.put("payer", getPartyInfoJson(payer.split(" ")[0], payer.split(" ")[1])); + mpesaChannelRequestJson.put("payer", + getPartyInfoJson(Iterables.get(Splitter.on(' ').split(payer), 0), Iterables.get(Splitter.on(' ').split(payer), 1))); + mpesaChannelRequestJson.put("payee", + getPartyInfoJson(Iterables.get(Splitter.on(' ').split(payee), 0), Iterables.get(Splitter.on(' ').split(payee), 1))); + return mpesaChannelRequestJson.toString(); + } + + public static JSONObject getPartyInfoJson(String partyIdType, String partyIdentifier) { + JSONObject partyIdInfo = new JSONObject(); + partyIdInfo.put("partyIdType", partyIdType); + partyIdInfo.put("partyIdentifier", partyIdentifier); + + JSONObject party = new JSONObject(); + party.put("partyIdInfo", partyIdInfo); + + return party; + } + +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/utils/SpringWrapperUtil.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/utils/SpringWrapperUtil.java new file mode 100644 index 000000000..1b0cd5f28 --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/utils/SpringWrapperUtil.java @@ -0,0 +1,30 @@ +package org.mifos.connector.channel.utils; + +import org.apache.camel.CamelContext; +import org.apache.camel.Exchange; +import org.apache.camel.support.DefaultExchange; + +public final class SpringWrapperUtil { + + private SpringWrapperUtil() {} + + public static Exchange getDefaultWrappedExchange(CamelContext camelContext, Headers headers, String body) { + Exchange exchange = new DefaultExchange(camelContext); + + // Setting headers + for (String headerKey : headers.getHeadersKey()) { + exchange.getIn().setHeader(headerKey, headers.get(headerKey)); + } + + // Setting body if available + if (body != null) { + try { + exchange.getIn().setBody((String) body); + } catch (Exception e) { + exchange.getIn().setBody(body); + + } + } + return exchange; + } +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/validator/ChannelValidator.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/validator/ChannelValidator.java new file mode 100644 index 000000000..8affb8c04 --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/validator/ChannelValidator.java @@ -0,0 +1,188 @@ +package org.mifos.connector.channel.validator; + +import static org.mifos.connector.common.exception.PaymentHubError.ExtValidationError; + +import org.mifos.connector.channel.utils.ChannelValidatorsEnum; +import org.mifos.connector.common.channel.dto.PhErrorDTO; +import org.mifos.connector.common.channel.dto.TransactionChannelRequestDTO; +import org.mifos.connector.common.exception.PaymentHubErrorCategory; +import org.mifos.connector.common.exception.ValidationException; +import org.mifos.connector.common.gsma.dto.GsmaTransfer; +import org.mifos.connector.common.validation.ValidatorBuilder; + +@SuppressWarnings("HideUtilityClassConstructor") +public class ChannelValidator { + + private static final String resource = "ChannelValidator"; + private static final String payer = "payer"; + private static final String partyIdInfo = "partyIdInfo"; + private static final String partyIdType = "partyIdType"; + private static final String partyIdentifier = "partyIdentifier"; + private static final String partyIdIdentifier = "partyIdIdentifier"; + private static final String payee = "payee"; + private static final String amount = "amount"; + private static final String amount_value = "amount"; + private static final String currency = "currency"; + private static final int expectedCurrencyLength = 3; + private static final String requestingOrganisationTransactionReference = "requestingOrganisationTransactionReference"; + private static final String subType = "subType"; + private static final String type = "type"; + private static final String descriptionText = "descriptionText"; + private static final String requestDate = "requestDate"; + private static final String customData = "customData"; + private static final String key = "key"; + private static final String value = "value"; + + public static void validateTransfer(TransactionChannelRequestDTO request) throws ValidationException { + final ValidatorBuilder validatorBuilder = new ValidatorBuilder(); + + // validating payer + validatorBuilder.reset().resource(resource).parameter(payer).value(request.getPayer()) + .isNullWithFailureCode(ChannelValidatorsEnum.INVALID_PAYER); + + // validating payee + validatorBuilder.reset().resource(resource).parameter(payee).value(request.getPayee()) + .isNullWithFailureCode(ChannelValidatorsEnum.INVALID_PAYEE); + + if (request.getPayer() != null) { + // validating payer party id info + validatorBuilder.reset().resource(resource).parameter(partyIdInfo).value(request.getPayer().getPartyIdInfo()) + .isNullWithFailureCode(ChannelValidatorsEnum.INVALID_PAYER_PARTY_ID_INFO); + + if (request.getPayer().getPartyIdInfo() != null) { + // validating payer party id type + validatorBuilder.reset().resource(resource).parameter(partyIdType) + .value(request.getPayer().getPartyIdInfo().getPartyIdType()) + .isNullWithFailureCode(ChannelValidatorsEnum.INVALID_PAYER_PARTY_ID_TYPE); + + // validating payer party identifier + validatorBuilder.reset().resource(resource).parameter(partyIdentifier) + .value(request.getPayer().getPartyIdInfo().getPartyIdentifier()) + .isNullWithFailureCode(ChannelValidatorsEnum.INVALID_PAYER_PARTY_IDENTIFIER); + } + } + + if (request.getPayee() != null) { + // validating payee party id info + validatorBuilder.reset().resource(resource).parameter(partyIdInfo).value(request.getPayee().getPartyIdInfo()) + .isNullWithFailureCode(ChannelValidatorsEnum.INVALID_PAYEE_PARTY_ID_INFO); + + if (request.getPayee().getPartyIdInfo() != null) { + // validating payee party id type + validatorBuilder.reset().resource(resource).parameter(partyIdType) + .value(request.getPayee().getPartyIdInfo().getPartyIdType()) + .isNullWithFailureCode(ChannelValidatorsEnum.INVALID_PAYEE_PARTY_ID_TYPE); + + // validating payee party identifier + validatorBuilder.reset().resource(resource).parameter(partyIdentifier) + .value(request.getPayee().getPartyIdInfo().getPartyIdentifier()) + .isNullWithFailureCode(ChannelValidatorsEnum.INVALID_PAYEE_PARTY_IDENTIFIER); + } + } + + // validating amount + validatorBuilder.reset().resource(resource).parameter(amount).value(request.getAmount()) + .isNullWithFailureCode(ChannelValidatorsEnum.INVALID_AMOUNT); + + if (request.getAmount() != null) { + // validating the amount field inside the amount field. + validatorBuilder.reset().resource(resource).parameter(amount_value).value(request.getAmount().getAmount()) + .isNullWithFailureCode(ChannelValidatorsEnum.INVALID_AMOUNT_AMOUNT) + .validateBigDecimalFieldNotNegativeWithFailureCode(ChannelValidatorsEnum.INVALID_NEGATIVE_AMOUNT); + + // validating amount currency + validatorBuilder.reset().resource(resource).parameter(currency).value(request.getAmount().getCurrency()) + .isNullWithFailureCode(ChannelValidatorsEnum.INVALID_CURRENCY).validateFieldMaxLengthWithFailureCodeAndErrorParams( + expectedCurrencyLength, ChannelValidatorsEnum.INVALID_CURRENCY_LENGTH); + } + + if (validatorBuilder.hasError()) { + validatorBuilder.errorCategory(PaymentHubErrorCategory.Validation.toString()) + .errorCode(ChannelValidatorsEnum.TRANSFER_SCHEMA_VALIDATION_ERROR.getCode()) + .errorDescription(ChannelValidatorsEnum.TRANSFER_SCHEMA_VALIDATION_ERROR.getMessage()) + .developerMessage(ChannelValidatorsEnum.TRANSFER_SCHEMA_VALIDATION_ERROR.getMessage()) + .defaultUserMessage(ChannelValidatorsEnum.TRANSFER_SCHEMA_VALIDATION_ERROR.getMessage()); + + PhErrorDTO.PhErrorDTOBuilder phErrorDTOBuilder = new PhErrorDTO.PhErrorDTOBuilder(ExtValidationError.getErrorCode()); + phErrorDTOBuilder.fromValidatorBuilder(validatorBuilder); + + throw new ValidationException(phErrorDTOBuilder.build()); + } + } + + public static void validateTransaction(GsmaTransfer request) throws ValidationException { + final ValidatorBuilder validatorBuilder = new ValidatorBuilder(); + + // validate request organisation transaction reference + validatorBuilder.reset().resource(resource).parameter(requestingOrganisationTransactionReference) + .value(request.getRequestingOrganisationTransactionReference()) + .isNullWithFailureCode(ChannelValidatorsEnum.INVALID_REQUEST_ORGANIZATION_TRANSACTION_REFERENCE); + + // validate subtype + validatorBuilder.reset().resource(resource).parameter(subType).value(request.getSubType()) + .isNullWithFailureCode(ChannelValidatorsEnum.INVALID_SUB_TYPE); + + // validate type + validatorBuilder.reset().resource(resource).parameter(type).value(request.getType()) + .isNullWithFailureCode(ChannelValidatorsEnum.INVALID_TYPE); + + // validate amount + validatorBuilder.reset().resource(resource).parameter(amount).value(request.getAmount()) + .isNullWithFailureCode(ChannelValidatorsEnum.INVALID_AMOUNT) + .validateBigDecimalFieldNotNegativeWithFailureCode(ChannelValidatorsEnum.INVALID_NEGATIVE_AMOUNT); + + // validate currency + validatorBuilder.reset().resource(resource).parameter(currency).value(request.getCurrency()) + .isNullWithFailureCode(ChannelValidatorsEnum.INVALID_CURRENCY) + .validateFieldMaxLengthWithFailureCodeAndErrorParams(expectedCurrencyLength, ChannelValidatorsEnum.INVALID_CURRENCY_LENGTH); + + // validate description text + validatorBuilder.reset().resource(resource).parameter(descriptionText).value(request.getDescriptionText()) + .isNullWithFailureCode(ChannelValidatorsEnum.INVALID_DESCRIPTION_TEXT); + + // validate request date + validatorBuilder.reset().resource(resource).parameter(requestDate).value(request.getRequestDate()) + .isNullWithFailureCode(ChannelValidatorsEnum.INVALID_REQUEST_DATE); + + // validate payer + validatorBuilder.reset().resource(resource).parameter(payer).value(request.getPayer()) + .isNullWithFailureCode(ChannelValidatorsEnum.INVALID_PAYER); + + // validate payee + validatorBuilder.reset().resource(resource).parameter(payee).value(request.getPayee()) + .isNullWithFailureCode(ChannelValidatorsEnum.INVALID_PAYEE); + + if (request.getPayer() != null) { + // validate party id type + validatorBuilder.reset().resource(resource).parameter(partyIdType).value(request.getPayer().get(0).getPartyIdType()) + .isNullWithFailureCode(ChannelValidatorsEnum.INVALID_PAYER_PARTY_ID_TYPE); + + // validate party id identifier + validatorBuilder.reset().resource(resource).parameter(partyIdIdentifier).value(request.getPayer().get(0).getPartyIdIdentifier()) + .isNullWithFailureCode(ChannelValidatorsEnum.INVALID_PAYER_PARTY_ID_IDENTIFIER); + } + + if (request.getPayee() != null) { + // validate party id type + validatorBuilder.reset().resource(resource).parameter(partyIdType).value(request.getPayee().get(0).getPartyIdType()) + .isNullWithFailureCode(ChannelValidatorsEnum.INVALID_PAYER_PARTY_ID_TYPE); + + // validate party id identifier + validatorBuilder.reset().resource(resource).parameter(partyIdIdentifier).value(request.getPayee().get(0).getPartyIdIdentifier()) + .isNullWithFailureCode(ChannelValidatorsEnum.INVALID_PAYEE_PARTY_ID_IDENTIFIER); + } + + if (validatorBuilder.hasError()) { + validatorBuilder.errorCategory(PaymentHubErrorCategory.Validation.toString()) + .errorCode(ChannelValidatorsEnum.TRANSFER_SCHEMA_VALIDATION_ERROR.getCode()) + .errorDescription(ChannelValidatorsEnum.TRANSFER_SCHEMA_VALIDATION_ERROR.getMessage()) + .developerMessage(ChannelValidatorsEnum.TRANSFER_SCHEMA_VALIDATION_ERROR.getMessage()) + .defaultUserMessage(ChannelValidatorsEnum.TRANSFER_SCHEMA_VALIDATION_ERROR.getMessage()); + + PhErrorDTO.PhErrorDTOBuilder phErrorDTOBuilder = new PhErrorDTO.PhErrorDTOBuilder(ExtValidationError.getErrorCode()); + phErrorDTOBuilder.fromValidatorBuilder(validatorBuilder); + throw new ValidationException(phErrorDTOBuilder.build()); + } + } + +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/validator/HeaderValidator.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/validator/HeaderValidator.java new file mode 100644 index 000000000..00a984450 --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/validator/HeaderValidator.java @@ -0,0 +1,110 @@ +package org.mifos.connector.channel.validator; + +import static org.mifos.connector.common.exception.PaymentHubError.ExtValidationError; + +import java.util.Collections; +import java.util.Enumeration; +import java.util.List; +import java.util.Set; +import javax.servlet.http.HttpServletRequest; +import org.mifos.connector.channel.utils.ChannelValidatorsEnum; +import org.mifos.connector.channel.utils.HeaderConstants; +import org.mifos.connector.common.channel.dto.PhErrorDTO; +import org.mifos.connector.common.exception.PaymentHubErrorCategory; +import org.mifos.connector.common.validation.ValidatorBuilder; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +@Component +public class HeaderValidator { + + @Autowired + private UnsupportedParameterValidation unsupportedParameterValidator; + + @Value("#{'${default_headers}'.split(',')}") + private List defaultHeader; + + private static final String resource = "channelValidator"; + + public PhErrorDTO validateTransfer(Set requiredHeaders, HttpServletRequest request) { + final ValidatorBuilder validatorBuilder = new ValidatorBuilder(); + + List headers = getHeaderList(request); + + unsupportedParameterValidator.handleRequiredParameterValidation(headers, requiredHeaders, validatorBuilder); + + // Checks for Platform_TenantId + validatorBuilder.validateFieldIsNullAndMaxLengthWithFailureCode(resource, HeaderConstants.PLATFORM_TENANT_ID, + request.getHeader(HeaderConstants.PLATFORM_TENANT_ID), ChannelValidatorsEnum.INVALID_PLATFORM_TENANT_ID, 20, + ChannelValidatorsEnum.INVALID_PLATFORM_TENANT_ID_LENGTH); + + return handleValidationErrors(validatorBuilder); + } + + public PhErrorDTO validateTransactionRequest(Set requiredHeaders, HttpServletRequest request) { + final ValidatorBuilder validatorBuilder = new ValidatorBuilder(); + + List headers = getHeaderList(request); + + unsupportedParameterValidator.handleRequiredParameterValidation(headers, requiredHeaders, validatorBuilder); + + // Checks for Platform_TenantId + validatorBuilder.validateFieldIsNullAndMaxLengthWithFailureCode(resource, HeaderConstants.PLATFORM_TENANT_ID, + request.getHeader(HeaderConstants.PLATFORM_TENANT_ID), ChannelValidatorsEnum.INVALID_PLATFORM_TENANT_ID, 20, + ChannelValidatorsEnum.INVALID_PLATFORM_TENANT_ID_LENGTH); + + return handleValidationErrors(validatorBuilder); + } + + public PhErrorDTO validateGsmaTransaction(Set requiredHeaders, HttpServletRequest request) { + final ValidatorBuilder validatorBuilder = new ValidatorBuilder(); + + List headers = getHeaderList(request); + + unsupportedParameterValidator.handleRequiredParameterValidation(headers, requiredHeaders, validatorBuilder); + + // checks for ams name + validatorBuilder.validateFieldIsNullAndMaxLengthWithFailureCode(resource, HeaderConstants.AMS_NAME, + request.getHeader(HeaderConstants.AMS_NAME), ChannelValidatorsEnum.INVALID_AMS_NAME, 20, + ChannelValidatorsEnum.INVALID_AMS_NAME_LENGTH); + + // checks for account holding institution id + validatorBuilder.validateFieldIsNullAndMaxLengthWithFailureCode(resource, HeaderConstants.ACCOUNT_HOLDING_INSTITUTION_ID, + request.getHeader(HeaderConstants.ACCOUNT_HOLDING_INSTITUTION_ID), + ChannelValidatorsEnum.INVALID_ACCOUNT_HOLDING_INSTITUTION_ID, 20, + ChannelValidatorsEnum.INVALID_ACCOUNT_HOLDING_INSTITUTION_ID_LENGTH); + + // checks for x callback url + validatorBuilder.validateFieldIsNullAndMaxLengthWithFailureCode(resource, HeaderConstants.X_Callback_URL, + request.getHeader(HeaderConstants.X_Callback_URL), ChannelValidatorsEnum.INVALID_X_CALLBACK_URL, 1000, + ChannelValidatorsEnum.INVALID_X_CALLBACK_URL_LENGTH); + + // checks for x correlation id + validatorBuilder.validateFieldIgnoreNullAndMaxLengthWithFailureCode(resource, HeaderConstants.CLIENT_CORRELATION_ID, + request.getHeader(HeaderConstants.CLIENT_CORRELATION_ID), 100, ChannelValidatorsEnum.INVALID_CLIENT_CORRELATION_ID_LENGTH); + + return handleValidationErrors(validatorBuilder); + } + + private PhErrorDTO handleValidationErrors(ValidatorBuilder validatorBuilder) { + if (validatorBuilder.hasError()) { + validatorBuilder.errorCategory(PaymentHubErrorCategory.Validation.toString()) + .errorCode(ChannelValidatorsEnum.HEADER_VALIDATION_ERROR.getCode()) + .errorDescription(ChannelValidatorsEnum.HEADER_VALIDATION_ERROR.getMessage()) + .developerMessage(ChannelValidatorsEnum.HEADER_VALIDATION_ERROR.getMessage()) + .defaultUserMessage(ChannelValidatorsEnum.HEADER_VALIDATION_ERROR.getMessage()); + + PhErrorDTO.PhErrorDTOBuilder phErrorDTOBuilder = new PhErrorDTO.PhErrorDTOBuilder(ExtValidationError.getErrorCode()); + phErrorDTOBuilder.fromValidatorBuilder(validatorBuilder); + return phErrorDTOBuilder.build(); + } + return null; + } + + public List getHeaderList(HttpServletRequest request) { + Enumeration headers = request.getHeaderNames(); + return Collections.list(request.getHeaderNames()); + } + +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/validator/UnsupportedParameterValidation.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/validator/UnsupportedParameterValidation.java new file mode 100644 index 000000000..2e0b14203 --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/validator/UnsupportedParameterValidation.java @@ -0,0 +1,67 @@ +package org.mifos.connector.channel.validator; + +import java.util.List; +import java.util.Map; +import java.util.Set; +import org.mifos.connector.common.validation.ValidationCodeType; +import org.mifos.connector.common.validation.ValidatorBuilder; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +@Component +public class UnsupportedParameterValidation { + + @Value("#{'${default_headers}'.split(',')}") + private Set defaultHeader; + final StringBuilder validationErrorCode = new StringBuilder("error.msg.parameter.unsupported"); + + public void handleUnsupportedParameterValidation(Map additionalProperties, ValidatorBuilder validatorBuilder) { + + for (final String parameterName : additionalProperties.keySet()) { + final StringBuilder defaultEnglishMessage = new StringBuilder("The parameter ").append(parameterName) + .append(" is not supported."); + + ValidationCodeType validationCode = convertToStructuredErrorMessage(validationErrorCode.toString(), + defaultEnglishMessage.toString()); + validatorBuilder.failWithCode(validationCode); + } + + } + + public void handleRequiredParameterValidation(List fields, Set requiredFields, ValidatorBuilder validatorBuilder) { + + for (final String fieldName : fields) { + if (fieldName != "additionalProperties" && !requiredFields.contains(fieldName) && !defaultHeader.contains(fieldName)) { + + final StringBuilder defaultEnglishMessage = new StringBuilder("The parameter ").append(fieldName) + .append(" is not supported."); + + ValidationCodeType validationCode = convertToStructuredErrorMessage(validationErrorCode.toString(), + defaultEnglishMessage.toString()); + validatorBuilder.failWithCode(validationCode); + } + } + + } + + private ValidationCodeType convertToStructuredErrorMessage(String errorCode, String errorMessage) { + return new ValidationCodeType() { + + @Override + public String getCode() { + return errorCode; + } + + @Override + public String getCategory() { + return "Validation"; + } + + @Override + public String getMessage() { + return errorMessage; + } + }; + } + +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/zeebe/ZeebeClientConfiguration.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/zeebe/ZeebeClientConfiguration.java new file mode 100644 index 000000000..6ca787a3a --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/zeebe/ZeebeClientConfiguration.java @@ -0,0 +1,24 @@ +package org.mifos.connector.channel.zeebe; + +import io.camunda.zeebe.client.ZeebeClient; +import java.time.Duration; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class ZeebeClientConfiguration { + + @Value("${zeebe.broker.contactpoint}") + private String zeebeBrokerContactpoint; + + @Value("${zeebe.client.max-execution-threads}") + private int zeebeClientMaxThreads; + + @Bean + public ZeebeClient setup() { + return ZeebeClient.newClientBuilder().gatewayAddress(zeebeBrokerContactpoint).usePlaintext() + .defaultJobPollInterval(Duration.ofMillis(1)).defaultJobWorkerMaxJobsActive(2000) + .numJobWorkerExecutionThreads(zeebeClientMaxThreads).build(); + } +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/zeebe/ZeebeMessages.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/zeebe/ZeebeMessages.java new file mode 100644 index 000000000..dfaa035dc --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/zeebe/ZeebeMessages.java @@ -0,0 +1,9 @@ +package org.mifos.connector.channel.zeebe; + +public final class ZeebeMessages { + + private ZeebeMessages() {} + + public static final String OPERATOR_MANUAL_RECOVERY = "operator-manual-recovery"; + +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/zeebe/ZeebeProcessStarter.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/zeebe/ZeebeProcessStarter.java new file mode 100644 index 000000000..2d0c24aa2 --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/zeebe/ZeebeProcessStarter.java @@ -0,0 +1,131 @@ +package org.mifos.connector.channel.zeebe; + +import io.camunda.zeebe.client.ZeebeClient; +import io.camunda.zeebe.client.api.command.ClientStatusException; +import io.camunda.zeebe.client.api.response.ProcessInstanceEvent; +import java.time.Instant; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; +import org.mifos.connector.channel.utils.MpesaUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +/** + * Start a Zeebe workflow + */ +@Component +public class ZeebeProcessStarter { + + private static Logger logger = LoggerFactory.getLogger(ZeebeProcessStarter.class); + + @Autowired + private ZeebeClient zeebeClient; + + @Value("${transaction-id-length}") + private int transactionIdLength; + + public String startZeebeWorkflow(String workflowId, String request, Map extraVariables) { + String transactionId = generateTransactionId(); + + Map variables = new HashMap<>(); + variables.put(ZeebeVariables.TRANSACTION_ID, transactionId); + variables.put(ZeebeVariables.CHANNEL_REQUEST, request); + variables.put(ZeebeVariables.ORIGIN_DATE, Instant.now().toEpochMilli()); + if (extraVariables != null) { + variables.putAll(extraVariables); + } + + logger.info("starting workflow HERE:"); + // TODO if successful transfer response arrives in X timeout return it otherwise do callback + try { + ProcessInstanceEvent instance = zeebeClient.newCreateInstanceCommand().bpmnProcessId(workflowId).latestVersion() + .variables(variables).send().join(); + logger.info("zeebee workflow instance from process {} started with transactionId {}, instance key: {}", workflowId, + transactionId, instance.getProcessInstanceKey()); + } catch (ClientStatusException ex) { + logger.error("ClientStatusException occurred : {}", ex.getMessage()); + throw ex; + } + return transactionId; + } + + public String startInboundTransactionZeebeWorkflow(String workflowId, String request, Map extraVariables) { + String transactionId = customSizeTransactionId(); + + Map variables = new HashMap<>(); + variables.put(ZeebeVariables.TRANSACTION_ID, transactionId); + variables.put(ZeebeVariables.MPESA_CHANNEL_REQUEST, request); + variables.put(ZeebeVariables.CHANNEL_REQUEST, MpesaUtils.mpesaChannelRequestToChannelRequestConvertor(request)); + variables.put(ZeebeVariables.ORIGIN_DATE, Instant.now().toEpochMilli()); + if (extraVariables != null) { + variables.putAll(extraVariables); + } + + logger.info("starting workflow HERE:"); + // TODO if successful transfer response arrives in X timeout return it otherwise do callback + try { + ProcessInstanceEvent instance = zeebeClient.newCreateInstanceCommand().bpmnProcessId(workflowId).latestVersion() + .variables(variables).send().join(); + + logger.info("zeebee workflow instance from process {} started with transactionId {}, instance key: {}", workflowId, + transactionId, instance.getProcessInstanceKey()); + } catch (ClientStatusException ex) { + logger.error("ClientStatusException occurred : {}", ex.getMessage()); + throw ex; + } + return transactionId; + } + + // TODO generate proper cluster-safe transaction id + private String generateTransactionId() { + return UUID.randomUUID().toString(); + } + + private String randomCharOfSize(int size) { + String data = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; + char[] arr = data.toCharArray(); + StringBuilder s = new StringBuilder(); + for (int i = 0; i < size; i++) { + int index = (int) (Math.random() * data.length()); + s.append(arr[index]); + } + return s.toString(); + } + + public String customSizeTransactionId() { + String transactionId = generateTransactionId(); + if (transactionIdLength == -1 || transactionIdLength < 13) { + return transactionId; + } + String originalUUID = transactionId.replace("-", ""); + String uuid12digits = originalUUID.substring(0, 12); + String randomString = randomCharOfSize(transactionIdLength - 12); + return uuid12digits + randomString; + + } + + public String startZeebeWorkflowC2B(String workflowId, Map variables) { + + String transactionId = generateTransactionId(); + variables.put(ZeebeVariables.TRANSACTION_ID, transactionId); + variables.put(ZeebeVariables.ORIGIN_DATE, Instant.now().toEpochMilli()); + + logger.info("starting workflow HERE:"); + try { + ProcessInstanceEvent instance = zeebeClient.newCreateInstanceCommand().bpmnProcessId(workflowId).latestVersion() + .variables(variables).send().join(); + + logger.info("zeebee workflow instance from process {} started with transactionId {}, instance key: {}", workflowId, + transactionId, instance.getProcessInstanceKey()); + } catch (ClientStatusException ex) { + logger.error("ClientStatusException occurred : {}", ex.getMessage()); + throw ex; + } + + return transactionId; + } +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/zeebe/ZeebeVariables.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/zeebe/ZeebeVariables.java new file mode 100644 index 000000000..312534695 --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/zeebe/ZeebeVariables.java @@ -0,0 +1,32 @@ +package org.mifos.connector.channel.zeebe; + +public final class ZeebeVariables { + + private ZeebeVariables() {} + + public static final String ACCOUNT = "account"; + public static final String AUTH_RETRIES_LEFT = "authRetriesLeft"; + public static final String CHANNEL_REQUEST = "channelRequest"; + public static final String MPESA_CHANNEL_REQUEST = "mpesaChannelRequest"; + public static final String ERROR_INFORMATION = "errorInformation"; + public static final String ERROR_DESCRIPTION = "errorDescription"; + public static final String IS_AUTHORISATION_REQUIRED = "isAuthorisationRequired"; + public static final String IS_RTP_REQUEST = "isRtpRequest"; + public static final String OPERATOR_MANUAL_OVERRIDE = "operatorManualOverride"; // TODO validate in request? + public static final String ORIGIN_DATE = "originDate"; + public static final String PARTY_ID = "partyId"; + public static final String PARTY_ID_TYPE = "partyIdType"; + public static final String TENANT_ID = "tenantId"; + public static final String TRANSACTION_ID = "transactionId"; + public static final String TRANSACTION_TYPE = "transactionType"; + public static final String GSMA_AUTHORIZATION_CODE = "gsmaAuthorizationCode"; + public static final String GSMA_CHANNEL_REQUEST = "gsmaChannelRequest"; + public static final String SAMPLED_TX_IDS = "sampledTransactionIds"; + public static final String AMS = "ams"; + + public static final String NOTE = "note"; + public static final String TRANSFER_CREATE_FAILED = "transferCreateFailed"; + public static final String TRANSACTION_VALID = "isTxnValid"; + public static final String PAYMENT_SCHEME = "paymentScheme"; + +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/zeebe/ZeebeWorkers.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/zeebe/ZeebeWorkers.java new file mode 100644 index 000000000..fce50f695 --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/channel/zeebe/ZeebeWorkers.java @@ -0,0 +1,265 @@ +package org.mifos.connector.channel.zeebe; + +import static java.util.Comparator.naturalOrder; +import static org.mifos.connector.channel.camel.config.CamelProperties.BATCH_ID; +import static org.mifos.connector.channel.camel.config.CamelProperties.CLIENTCORRELATIONID; +import static org.mifos.connector.channel.camel.config.CamelProperties.PARTY_LOOKUP_FSP_ID; +import static org.mifos.connector.channel.zeebe.ZeebeVariables.CHANNEL_REQUEST; +import static org.mifos.connector.channel.zeebe.ZeebeVariables.ERROR_DESCRIPTION; +import static org.mifos.connector.channel.zeebe.ZeebeVariables.ERROR_INFORMATION; +import static org.mifos.connector.channel.zeebe.ZeebeVariables.SAMPLED_TX_IDS; +import static org.mifos.connector.channel.zeebe.ZeebeVariables.TRANSACTION_ID; +import static org.mifos.connector.channel.zeebe.ZeebeVariables.TRANSACTION_VALID; +import static org.mifos.connector.channel.zeebe.ZeebeVariables.TRANSFER_CREATE_FAILED; +import static org.mifos.connector.common.mojaloop.type.ErrorCode.fromCode; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.google.gson.Gson; +import io.camunda.zeebe.client.ZeebeClient; +import java.time.Duration; +import java.util.ArrayList; +import java.util.Map; +import java.util.UUID; +import java.util.stream.Collectors; +import javax.annotation.PostConstruct; +import org.apache.camel.CamelContext; +import org.apache.camel.Exchange; +import org.apache.camel.ProducerTemplate; +import org.apache.camel.support.DefaultExchange; +import org.json.JSONObject; +import org.mifos.connector.channel.utils.Headers; +import org.mifos.connector.channel.utils.SpringWrapperUtil; +import org.mifos.connector.common.channel.dto.TransactionChannelRequestDTO; +import org.mifos.connector.common.mojaloop.dto.MoneyData; +import org.mifos.connector.common.mojaloop.dto.Party; +import org.mifos.connector.common.mojaloop.dto.PartyIdInfo; +import org.mifos.connector.common.mojaloop.type.IdentifierType; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +@Component +public class ZeebeWorkers { + + private Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Autowired + private ZeebeClient zeebeClient; + + @Autowired + private ProducerTemplate producerTemplate; + + @Autowired + private CamelContext camelContext; + @Autowired + private ObjectMapper objectMapper; + + @Value("${zeebe.client.evenly-allocated-max-jobs}") + private int workerMaxJobs; + + public static final String TRANSFER_FAILED = "transferFailed"; + public static final String TRANSFER_STATE = "transferState"; + + public static final String MESSAGE = "message"; + + @PostConstruct + public void setupWorkers() { + workerSendErrorToChannel(); + workerSendSuccessToChannel(); + workerNotifyOperator(); + workerNotifyAmsFailure(); + workerSendUnknownToChannel(); + workerSendPayeeSuccessToChannel(); + workerSendPayeeFailureToChannel(); + workerInvokeAcknowledgementWorkflows(); + zeebeConsistencyWorker(); + validateTransactionalData(); + callTransferRoute(); + } + + private void workerSendErrorToChannel() { + zeebeClient.newWorker().jobType("send-error-to-channel").handler((client, job) -> { + logger.info("Job '{}' started from process '{}' with key {}", job.getType(), job.getBpmnProcessId(), job.getKey()); + + Object errorInfoVariable = job.getVariablesAsMap().get(ERROR_INFORMATION); + if (errorInfoVariable != null) { + JSONObject errorInformation = new JSONObject((String) errorInfoVariable).getJSONObject("errorInformation"); + int errorCode = Integer.parseInt(errorInformation.getString("errorCode")); + logger.error("Error occurred with code: {} type: {} message: {}", errorCode, fromCode(errorCode).name(), + errorInformation.getString("errorDescription")); + } + + Map existingVariables = job.getVariablesAsMap(); + + existingVariables.put(TRANSFER_CREATE_FAILED, "false"); + + client.newCompleteCommand(job.getKey()).variables(existingVariables).send(); + }).name("send-error-to-channel").maxJobsActive(workerMaxJobs).open(); + } + + private void callTransferRoute() { + zeebeClient.newWorker().jobType("call-transfer-API").handler((client, job) -> { + logger.info("Job '{}' started from process '{}' with key {}", job.getType(), job.getBpmnProcessId(), job.getKey()); + Map variables = job.getVariablesAsMap(); + String clientCorrelationId = UUID.randomUUID().toString(); + Headers headers = new Headers.HeaderBuilder().addHeader("Platform-TenantId", variables.get(PARTY_LOOKUP_FSP_ID).toString()) + .addHeader(CLIENTCORRELATIONID, clientCorrelationId).build(); + variables.put("clientCorrelationId", clientCorrelationId); + + PartyIdInfo payer = new PartyIdInfo(IdentifierType.valueOf(String.valueOf(variables.get("payerIdentifierType"))), + variables.get("payerIdentifier").toString()); + PartyIdInfo payee = new PartyIdInfo(IdentifierType.valueOf(String.valueOf(variables.get("payerIdentifierType"))), + variables.get("payeePartyId").toString()); + TransactionChannelRequestDTO channelRequestDTO = new TransactionChannelRequestDTO(); + Party payeeParty = new Party(); + payeeParty.setPartyIdInfo(payee); + Party payerParty = new Party(); + payerParty.setPartyIdInfo(payer); + channelRequestDTO.setPayee(payeeParty); + channelRequestDTO.setPayer(payerParty); + MoneyData amount = new MoneyData(); + amount.setAmount(variables.get("amount").toString()); + amount.setCurrency(variables.get("currency").toString()); + channelRequestDTO.setAmount(amount); + + Exchange exchange = SpringWrapperUtil.getDefaultWrappedExchange(producerTemplate.getCamelContext(), headers, + objectMapper.writeValueAsString(channelRequestDTO)); + producerTemplate.send("direct:post-transfer", exchange); + String responseBody = exchange.getIn().getBody(String.class); + client.newCompleteCommand(job.getKey()).variables(variables).send(); + }).name("call-transfer-API").maxJobsActive(workerMaxJobs).open(); + } + + private void workerSendSuccessToChannel() { + zeebeClient.newWorker().jobType("send-success-to-channel").handler((client, job) -> { + logger.info("Job '{}' started from process '{}' with key {}", job.getType(), job.getBpmnProcessId(), job.getKey()); + client.newCompleteCommand(job.getKey()).send(); + }).name("send-success-to-channel").maxJobsActive(workerMaxJobs).open(); + } + + private void workerNotifyOperator() { + zeebeClient.newWorker().jobType("notify-operator").handler((client, job) -> { + logger.info("Job '{}' started from process '{}' with key {}", job.getType(), job.getBpmnProcessId(), job.getKey()); + client.newCompleteCommand(job.getKey()).send(); + }).name("notify-operator").maxJobsActive(workerMaxJobs).open(); + } + + private void workerNotifyAmsFailure() { + zeebeClient.newWorker().jobType("notify-ams-failure").handler((client, job) -> { + logger.info("Job '{}' started from process '{}' with key {}", job.getType(), job.getBpmnProcessId(), job.getKey()); + client.newCompleteCommand(job.getKey()).send(); + }).name("notify-ams-failure").maxJobsActive(workerMaxJobs).open(); + } + + private void workerSendUnknownToChannel() { + zeebeClient.newWorker().jobType("send-unknown-to-channel").handler((client, job) -> { + logger.info("Job '{}' started from process '{}' with key {}", job.getType(), job.getBpmnProcessId(), job.getKey()); + + Map variables = job.getVariablesAsMap(); + logger.info("Transfer {} response did not arrive after {} retries, operator decision required! Variables:\n{}", + variables.get(TRANSACTION_ID), 3, // TODO externalize bpmn expression variables + variables.keySet().stream().sorted(naturalOrder()).map(k -> k + " -- " + variables.get(k)) + .collect(Collectors.joining("\n"))); + + client.newCompleteCommand(job.getKey()).send(); + }).name("send-unknown-to-channel").maxJobsActive(workerMaxJobs).open(); + } + + private void workerSendPayeeSuccessToChannel() { + zeebeClient.newWorker().jobType("send-payee-success-to-channel").handler((client, job) -> { + logger.info("Job '{}' started from process '{}' with key {}", job.getType(), job.getBpmnProcessId(), job.getKey()); + Map variables = job.getVariablesAsMap(); + + variables.put(ERROR_INFORMATION, "Custom Error: Failed to deposit!"); + variables.put(TRANSFER_FAILED, true); + + zeebeClient.newPublishMessageCommand().messageName("transferResponse").correlationKey(variables.get("transactionId").toString()) + .timeToLive(Duration.ofMillis(30000)).variables(variables).send().join(); + + client.newCompleteCommand(job.getKey()).send().join(); + }).name("send-payee-success-to-channel").maxJobsActive(workerMaxJobs).open(); + } + + private void workerSendPayeeFailureToChannel() { + zeebeClient.newWorker().jobType("send-payee-failure-to-channel").handler((client, job) -> { + logger.info("Job '{}' started from process '{}' with key {}", job.getType(), job.getBpmnProcessId(), job.getKey()); + Map variables = job.getVariablesAsMap(); + + variables.put(TRANSFER_STATE, "COMMITTED"); + variables.put(TRANSFER_FAILED, false); + + zeebeClient.newPublishMessageCommand().messageName("transferResponse").correlationKey(variables.get("transactionId").toString()) + .timeToLive(Duration.ofMillis(30000)).variables(variables).send().join(); + + client.newCompleteCommand(job.getKey()).send().join(); + }).name("send-payee-failure-to-channel").maxJobsActive(workerMaxJobs).open(); + } + + private void workerInvokeAcknowledgementWorkflows() { + zeebeClient.newWorker().jobType("invoke-ack-workers").handler((client, job) -> { + logger.info("Job '{}' started from process '{}' with key {}", job.getType(), job.getBpmnProcessId(), job.getKey()); + Map variables = job.getVariablesAsMap(); + + String successfulTxIdsStr = variables.get(SAMPLED_TX_IDS).toString(); + ArrayList successfulTxIds = new Gson().fromJson(successfulTxIdsStr, ArrayList.class); + + Exchange exchange = new DefaultExchange(camelContext); + exchange.setProperty("successfulTxIds", successfulTxIds); + exchange.setProperty("batchId", variables.get(BATCH_ID)); + producerTemplate.send("direct:invoke-ack-workers", exchange); + + client.newCompleteCommand(job.getKey()).send().join(); + }).name("send-payee-failure-to-channel").maxJobsActive(workerMaxJobs).open(); + } + + private void zeebeConsistencyWorker() { + zeebeClient.newWorker().jobType("zeebe-consistency-worker").handler((client, job) -> { + logger.info("Job '{}' started from process '{}' with key {}", job.getType(), job.getBpmnProcessId(), job.getKey()); + Map variables = job.getVariablesAsMap(); + variables.put(MESSAGE, "hello world"); + client.newCompleteCommand(job.getKey()).send().join(); + }).name("zeebe-consistency-worker").maxJobsActive(workerMaxJobs).open(); + } + + // validate transactional data + private void validateTransactionalData() { + zeebeClient.newWorker().jobType("validate-transactional-data").handler((client, job) -> { + logger.info("Job '{}' started from process '{}' with key {}", job.getType(), job.getBpmnProcessId(), job.getKey()); + Map variables = job.getVariablesAsMap(); + ObjectMapper mapper = new ObjectMapper(); + TransactionChannelRequestDTO channelRequestDTO = mapper.readValue(variables.get(CHANNEL_REQUEST).toString(), + TransactionChannelRequestDTO.class); + boolean valid = validateTxn(channelRequestDTO); + if (!valid) { + variables.put(TRANSACTION_VALID, false); + variables.put(ERROR_INFORMATION, "Custom Error: Transaction Invalid"); + variables.put(ERROR_DESCRIPTION, "Transaction data was wrong or incomplete"); + } else { + variables.put(TRANSACTION_VALID, true); + } + client.newCompleteCommand(job.getKey()).variables(variables).send().join(); + }).name("validate-transactional-data").maxJobsActive(workerMaxJobs).open(); + + } + + private boolean validateTxn(TransactionChannelRequestDTO channelRequestDTO) { + boolean valid = false; + String payerIdentifierType = channelRequestDTO.getPayer().getPartyIdInfo().getPartyIdType().toString(); + String payeeIdentifierType = channelRequestDTO.getPayee().getPartyIdInfo().getPartyIdType().toString(); + if (payerIdentifierType.equalsIgnoreCase("MSISDN") || payerIdentifierType.equalsIgnoreCase("ACCOUNTID")) { + String payerIdentity = channelRequestDTO.getPayer().getPartyIdInfo().getPartyIdentifier(); + valid = payerIdentity.matches("^[\\d*#+]+$"); + if (payeeIdentifierType.equalsIgnoreCase("MSISDN") || payeeIdentifierType.equalsIgnoreCase("ACCOUNTID")) { + String payeeIdentity = channelRequestDTO.getPayee().getPartyIdInfo().getPartyIdentifier(); + valid = payeeIdentity.matches("^[\\d*#+]+$"); + } + } + if (channelRequestDTO.getNote() != null && channelRequestDTO.getNote().contains("Duplicate Transaction")) { + valid = !channelRequestDTO.getNote().contains("Duplicate transaction"); + } + + return valid; + } +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/exceptionmapper/ExtendedGlobalExceptionMapper.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/exceptionmapper/ExtendedGlobalExceptionMapper.java new file mode 100644 index 000000000..a90e9e5a7 --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/exceptionmapper/ExtendedGlobalExceptionMapper.java @@ -0,0 +1,30 @@ +package org.mifos.connector.exceptionmapper; + +import static org.mifos.connector.channel.utils.ConnectorChannelEnum.INTERNAL_SERVER_OCCURRED; +import static org.mifos.connector.channel.utils.ConnectorChannelEnum.PROCESS_DEFINITION_NOT_FOUND; + +import io.camunda.zeebe.client.api.command.ClientStatusException; +import org.mifos.connector.channel.model.GlobalExceptionMapperDTO; +import org.mifos.connector.common.exception.mapper.GlobalExceptionMapper; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.RestControllerAdvice; + +@RestControllerAdvice +public class ExtendedGlobalExceptionMapper extends GlobalExceptionMapper { + + @ExceptionHandler(ClientStatusException.class) + public ResponseEntity handleClientStatusException(ClientStatusException ex) { + GlobalExceptionMapperDTO exceptionMapperDTO = new GlobalExceptionMapperDTO(PROCESS_DEFINITION_NOT_FOUND.getValue(), + PROCESS_DEFINITION_NOT_FOUND.getMessage()); + return ResponseEntity.status(HttpStatus.PRECONDITION_FAILED).body(exceptionMapperDTO); + } + + @ExceptionHandler(Exception.class) + public ResponseEntity handleException(Exception ex) { + GlobalExceptionMapperDTO exceptionMapperDTO = new GlobalExceptionMapperDTO(INTERNAL_SERVER_OCCURRED.getValue(), ex.getMessage()); + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(exceptionMapperDTO); + } + +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/RFC3339DateFormat.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/RFC3339DateFormat.java new file mode 100644 index 000000000..6331c9a37 --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/RFC3339DateFormat.java @@ -0,0 +1,22 @@ +package org.mifos.connector.gsmastub; + +import com.fasterxml.jackson.databind.util.ISO8601DateFormat; +import com.fasterxml.jackson.databind.util.ISO8601Utils; + +import java.text.FieldPosition; +import java.util.Date; + + +public class RFC3339DateFormat extends ISO8601DateFormat { + + private static final long serialVersionUID = 1L; + + // Same as ISO8601DateFormat but serializing milliseconds. + @Override + public StringBuffer format(Date date, StringBuffer toAppendTo, FieldPosition fieldPosition) { + String value = ISO8601Utils.format(date, true); + toAppendTo.append(value); + return toAppendTo; + } + +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/api/AccountsApi.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/api/AccountsApi.java new file mode 100644 index 000000000..eb267c06e --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/api/AccountsApi.java @@ -0,0 +1,1124 @@ +/** + * NOTE: This class is auto generated by the swagger code generator program (3.0.34). + * https://github.com/swagger-api/swagger-codegen + * Do not edit the class manually. + */ +package org.mifos.connector.gsmastub.api; + +import io.swagger.v3.oas.annotations.Hidden; +import org.mifos.connector.gsmastub.model.*; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.enums.ParameterIn; +import io.swagger.v3.oas.annotations.media.ArraySchema; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import org.springframework.http.ResponseEntity; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; +import org.threeten.bp.OffsetDateTime; + +import javax.validation.Valid; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Pattern; +import javax.validation.constraints.Size; +import java.util.List; + +@javax.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.SpringCodegen", date = "2022-09-27T11:46:46.417Z[GMT]") +@Validated +@Hidden +public interface AccountsApi extends BaseGsmaApi { + + @Operation(summary = "Update an Account Identity.", description = "This endpoint updates an account identity. identityStatus, kycVerificationStatus, kycVerificationEntity and kycLevel field updates are permitted.", tags={ "Accounts" }) + @ApiResponses(value = { + @ApiResponse(responseCode = "202", description = "Represents an Asynchronous response", content = @Content(mediaType = "application/json", schema = @Schema(implementation = RequestStateObject.class))), + + @ApiResponse(responseCode = "204", description = "An empty response is returned for a synchronous successful patch."), + + @ApiResponse(responseCode = "400", description = "Represents an Error Caused by the Violation of a Business Rule", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "401", description = "Represents an Error Caused by an Authorisation Failure", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "404", description = "Represents an Error Caused by a Failure to Identify the Target Resource", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "500", description = "Represents an Error Caused by a General Server-Side Issue", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "503", description = "Represents an Error Caused by System Unavailability", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))) }) + @RequestMapping(value = "/accounts/{accountId}/identities/{identityId}", + produces = { "application/json" }, + consumes = { "application/json" }, + method = RequestMethod.PATCH) + ResponseEntity accountIdentitiesAccountIdPATCH(@Pattern(regexp="^((accountcategory|bankaccountno|accountrank|identityalias|iban|accountid|msisdn|swiftbic|sortcode|organisationid|username|walletid|linkref|consumerno|serviceprovider|storeid|bankname|bankaccounttitle|emailaddress|mandatereference)@([^$\\n]+))(\\$(accountcategory|bankaccountno|accountrank|identityalias|iban|accountid|msisdn|swiftbic|sortcode|organisationid|username|walletid|linkref|consumerno|serviceprovider|storeid|bankname|bankaccounttitle|emailaddress|mandatereference)@([^$\\n]+)){0,2}$") @Parameter(in = ParameterIn.PATH, description = "Path variable to uniquely identify an account. Up to three account identifiers can be supplied. Identifiers are delimited by $ and values are delimited by @. Example: organisationid@1234$accountid@3333. Valid account identifiers are accountcategory, bankaccountno, accountrank, identityalias, iban, accountid, msisdn, swiftbic, sortcode, organisationid, username, walletid, linkref, consumerno, serviceprovider, storeid, bankname, bankaccounttitle, emailaddress, mandatereference.", required=true, schema=@Schema()) @PathVariable("accountId") String accountId, @Parameter(in = ParameterIn.PATH, description = "A unique id for the identity as assigned by the API Provider.", required=true, schema=@Schema()) @PathVariable("identityId") String identityId, @Parameter(in = ParameterIn.DEFAULT, description = "Represents the request body of a batch of generic Patch operation.", required=true, schema=@Schema()) @Valid @RequestBody List body, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to uniquely identify the request. Must be supplied as a UUID." ,schema=@Schema()) @RequestHeader(value="X-CorrelationID", required=false) String xCorrelationID, @Parameter(in = ParameterIn.HEADER, description = "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." ,schema=@Schema()) @RequestHeader(value="X-Callback-URL", required=false) String xCallbackURL, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." ,schema=@Schema()) @RequestHeader(value="X-Date", required=false) OffsetDateTime xDate, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's API key to the server." ,schema=@Schema()) @RequestHeader(value="X-API-Key", required=false) String xAPIKey, @Parameter(in = ParameterIn.HEADER, description = "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication." ,schema=@Schema()) @RequestHeader(value="X-User-Bearer", required=false) String xUserBearer, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's identifier to the server." ,schema=@Schema()) @RequestHeader(value="X-Client-Id", required=false) String xClientId, @Parameter(in = ParameterIn.HEADER, description = "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." ,schema=@Schema()) @RequestHeader(value="X-Content-Hash", required=false) String xContentHash, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-1", required=false) String xUserCredential1, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-2", required=false) String xUserCredential2, @Parameter(in = ParameterIn.HEADER, description = "String containing the channel that was used to originate the request. For example USSD, Web, App." ,schema=@Schema()) @RequestHeader(value="X-Channel", required=false) String xChannel, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." ,schema=@Schema(allowableValues={ "lei", "swiftbic", "organisationid" } +)) @RequestHeader(value="X-Account-Holding-Institution-Identifier-Type", required=false) String xAccountHoldingInstitutionIdentifierType, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." ,schema=@Schema()) @RequestHeader(value="X-Account-Holding-Institution-Identifier", required=false) String xAccountHoldingInstitutionIdentifier); + + + @Operation(summary = "Update an Account Identity", description = "This endpoint updates an account identity. identityStatus, kycVerificationStatus, kycVerificationEntity and kycLevel field updates are permitted.", tags={ "Accounts" }) + @ApiResponses(value = { + @ApiResponse(responseCode = "202", description = "Represents an Asynchronous response", content = @Content(mediaType = "application/json", schema = @Schema(implementation = RequestStateObject.class))), + + @ApiResponse(responseCode = "204", description = "An empty response is returned for a synchronous successful patch."), + + @ApiResponse(responseCode = "400", description = "Represents an Error Caused by the Violation of a Business Rule", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "401", description = "Represents an Error Caused by an Authorisation Failure", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "404", description = "Represents an Error Caused by a Failure to Identify the Target Resource", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "500", description = "Represents an Error Caused by a General Server-Side Issue", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "503", description = "Represents an Error Caused by System Unavailability", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))) }) + @RequestMapping(value = "/accounts/{identifierType}/{identifier}/identities/{identityId}", + produces = { "application/json" }, + consumes = { "application/json" }, + method = RequestMethod.PATCH) + ResponseEntity accountIdentitiesIdentifierTypeIdentifierPATCH(@Parameter(in = ParameterIn.PATH, description = "Path variable to specify the type of the identifier that is used to identify the account.", required=true, schema=@Schema(allowableValues={ "accountid", "msisdn", "walletid", "linkref", "consumerno", "serviceprovider", "storeid", "accountcategory", "bankaccountno", "accountrank", "identityalias", "iban", "swiftbic", "sortcode", "organisationid", "bankname", "bankaccounttitle", "username", "emailaddress", "mandatereference" } +)) @PathVariable("identifierType") String identifierType, @Size(min=1,max=256) @Parameter(in = ParameterIn.PATH, description = "Path variable that contains the account identifier.", required=true, schema=@Schema()) @PathVariable("identifier") String identifier, @Parameter(in = ParameterIn.PATH, description = "A unique id for the identity as assigned by the API Provider.", required=true, schema=@Schema()) @PathVariable("identityId") String identityId, @Parameter(in = ParameterIn.DEFAULT, description = "Represents the request body of a batch of generic Patch operation.", required=true, schema=@Schema()) @Valid @RequestBody List body, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to uniquely identify the request. Must be supplied as a UUID." ,schema=@Schema()) @RequestHeader(value="X-CorrelationID", required=false) String xCorrelationID, @Parameter(in = ParameterIn.HEADER, description = "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." ,schema=@Schema()) @RequestHeader(value="X-Callback-URL", required=false) String xCallbackURL, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." ,schema=@Schema()) @RequestHeader(value="X-Date", required=false) OffsetDateTime xDate, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's API key to the server." ,schema=@Schema()) @RequestHeader(value="X-API-Key", required=false) String xAPIKey, @Parameter(in = ParameterIn.HEADER, description = "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication." ,schema=@Schema()) @RequestHeader(value="X-User-Bearer", required=false) String xUserBearer, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's identifier to the server." ,schema=@Schema()) @RequestHeader(value="X-Client-Id", required=false) String xClientId, @Parameter(in = ParameterIn.HEADER, description = "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." ,schema=@Schema()) @RequestHeader(value="X-Content-Hash", required=false) String xContentHash, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-1", required=false) String xUserCredential1, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-2", required=false) String xUserCredential2, @Parameter(in = ParameterIn.HEADER, description = "String containing the channel that was used to originate the request. For example USSD, Web, App." ,schema=@Schema()) @RequestHeader(value="X-Channel", required=false) String xChannel, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." ,schema=@Schema(allowableValues={ "lei", "swiftbic", "organisationid" } +)) @RequestHeader(value="X-Account-Holding-Institution-Identifier-Type", required=false) String xAccountHoldingInstitutionIdentifierType, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." ,schema=@Schema()) @RequestHeader(value="X-Account-Holding-Institution-Identifier", required=false) String xAccountHoldingInstitutionIdentifier); + + + @Operation(summary = "View Account Name", description = "This endpoint returns the status of a given account.", tags={ "Accounts" }) + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Represents an Account Name response", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ResponseAccountName.class))), + + @ApiResponse(responseCode = "400", description = "Represents an Error Caused by the Violation of a Business Rule", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "401", description = "Represents an Error Caused by an Authorisation Failure", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "404", description = "Represents an Error Caused by a Failure to Identify the Target Resource", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "500", description = "Represents an Error Caused by a General Server-Side Issue", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "503", description = "Represents an Error Caused by System Unavailability", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))) }) + @RequestMapping(value = "/accounts/{accountId}/accountname", + produces = { "application/json" }, + method = RequestMethod.GET) + ResponseEntity accountsAccountIdAccountnameGET(@Pattern(regexp="^((accountcategory|bankaccountno|accountrank|identityalias|iban|accountid|msisdn|swiftbic|sortcode|organisationid|username|walletid|linkref|consumerno|serviceprovider|storeid|bankname|bankaccounttitle|emailaddress|mandatereference)@([^$\\n]+))(\\$(accountcategory|bankaccountno|accountrank|identityalias|iban|accountid|msisdn|swiftbic|sortcode|organisationid|username|walletid|linkref|consumerno|serviceprovider|storeid|bankname|bankaccounttitle|emailaddress|mandatereference)@([^$\\n]+)){0,2}$") @Parameter(in = ParameterIn.PATH, description = "Path variable to uniquely identify an account. Up to three account identifiers can be supplied. Identifiers are delimited by $ and values are delimited by @. Example: organisationid@1234$accountid@3333. Valid account identifiers are accountcategory, bankaccountno, accountrank, identityalias, iban, accountid, msisdn, swiftbic, sortcode, organisationid, username, walletid, linkref, consumerno, serviceprovider, storeid, bankname, bankaccounttitle, emailaddress, mandatereference.", required=true, schema=@Schema()) @PathVariable("accountId") String accountId, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." ,schema=@Schema()) @RequestHeader(value="X-Date", required=false) OffsetDateTime xDate, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's API key to the server." ,schema=@Schema()) @RequestHeader(value="X-API-Key", required=false) String xAPIKey, @Parameter(in = ParameterIn.HEADER, description = "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication." ,schema=@Schema()) @RequestHeader(value="X-User-Bearer", required=false) String xUserBearer, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's identifier to the server." ,schema=@Schema()) @RequestHeader(value="X-Client-Id", required=false) String xClientId, @Parameter(in = ParameterIn.HEADER, description = "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." ,schema=@Schema()) @RequestHeader(value="X-Content-Hash", required=false) String xContentHash, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-1", required=false) String xUserCredential1, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-2", required=false) String xUserCredential2, @Parameter(in = ParameterIn.HEADER, description = "String containing the channel that was used to originate the request. For example USSD, Web, App." ,schema=@Schema()) @RequestHeader(value="X-Channel", required=false) String xChannel, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." ,schema=@Schema(allowableValues={ "lei", "swiftbic", "organisationid" } +)) @RequestHeader(value="X-Account-Holding-Institution-Identifier-Type", required=false) String xAccountHoldingInstitutionIdentifierType, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." ,schema=@Schema()) @RequestHeader(value="X-Account-Holding-Institution-Identifier", required=false) String xAccountHoldingInstitutionIdentifier); + + + @Operation(summary = "View an Authorisation Code", description = "This endpoint returns a specific Authorisation Code linked to an account", tags={ "Authorisation Codes" }) + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Represents an Authorisation Code response", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ResponseAuthorisationCode.class))), + + @ApiResponse(responseCode = "400", description = "Represents an Error Caused by the Violation of a Business Rule", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "401", description = "Represents an Error Caused by an Authorisation Failure", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "404", description = "Represents an Error Caused by a Failure to Identify the Target Resource", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "500", description = "Represents an Error Caused by a General Server-Side Issue", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "503", description = "Represents an Error Caused by System Unavailability", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))) }) + @RequestMapping(value = "/accounts/{accountId}/authorisationcodes/{authorisationCode}", + produces = { "application/json" }, + method = RequestMethod.GET) + ResponseEntity accountsAccountIdAuthorisationCodeAuthorisationCodeGET(@Pattern(regexp="^((accountcategory|bankaccountno|accountrank|identityalias|iban|accountid|msisdn|swiftbic|sortcode|organisationid|username|walletid|linkref|consumerno|serviceprovider|storeid|bankname|bankaccounttitle|emailaddress|mandatereference)@([^$\\n]+))(\\$(accountcategory|bankaccountno|accountrank|identityalias|iban|accountid|msisdn|swiftbic|sortcode|organisationid|username|walletid|linkref|consumerno|serviceprovider|storeid|bankname|bankaccounttitle|emailaddress|mandatereference)@([^$\\n]+)){0,2}$") @Parameter(in = ParameterIn.PATH, description = "Path variable to uniquely identify an account. Up to three account identifiers can be supplied. Identifiers are delimited by $ and values are delimited by @. Example: organisationid@1234$accountid@3333. Valid account identifiers are accountcategory, bankaccountno, accountrank, identityalias, iban, accountid, msisdn, swiftbic, sortcode, organisationid, username, walletid, linkref, consumerno, serviceprovider, storeid, bankname, bankaccounttitle, emailaddress, mandatereference.", required=true, schema=@Schema()) @PathVariable("accountId") String accountId, @Size(min=1,max=256) @Parameter(in = ParameterIn.PATH, description = "Path variable to uniquely identify an authorisation code.", required=true, schema=@Schema()) @PathVariable("authorisationCode") String authorisationCode, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." ,schema=@Schema()) @RequestHeader(value="X-Date", required=false) OffsetDateTime xDate, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's API key to the server." ,schema=@Schema()) @RequestHeader(value="X-API-Key", required=false) String xAPIKey, @Parameter(in = ParameterIn.HEADER, description = "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication." ,schema=@Schema()) @RequestHeader(value="X-User-Bearer", required=false) String xUserBearer, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's identifier to the server." ,schema=@Schema()) @RequestHeader(value="X-Client-Id", required=false) String xClientId, @Parameter(in = ParameterIn.HEADER, description = "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." ,schema=@Schema()) @RequestHeader(value="X-Content-Hash", required=false) String xContentHash, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-1", required=false) String xUserCredential1, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-2", required=false) String xUserCredential2, @Parameter(in = ParameterIn.HEADER, description = "String containing the channel that was used to originate the request. For example USSD, Web, App." ,schema=@Schema()) @RequestHeader(value="X-Channel", required=false) String xChannel, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." ,schema=@Schema(allowableValues={ "lei", "swiftbic", "organisationid" } +)) @RequestHeader(value="X-Account-Holding-Institution-Identifier-Type", required=false) String xAccountHoldingInstitutionIdentifierType, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." ,schema=@Schema()) @RequestHeader(value="X-Account-Holding-Institution-Identifier", required=false) String xAccountHoldingInstitutionIdentifier); + + + @Operation(summary = "Update an Authorisation Code", description = "This endpoint updates a specific Authorisation Code linked to an account. The only permissable modification is to set codeState to cancelled.", tags={ "Authorisation Codes" }) + @ApiResponses(value = { + @ApiResponse(responseCode = "202", description = "Represents an Asynchronous response", content = @Content(mediaType = "application/json", schema = @Schema(implementation = RequestStateObject.class))), + + @ApiResponse(responseCode = "204", description = "An empty response is returned for a synchronous successful patch."), + + @ApiResponse(responseCode = "400", description = "Represents an Error Caused by the Violation of a Business Rule", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "401", description = "Represents an Error Caused by an Authorisation Failure", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "404", description = "Represents an Error Caused by a Failure to Identify the Target Resource", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "500", description = "Represents an Error Caused by a General Server-Side Issue", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "503", description = "Represents an Error Caused by System Unavailability", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))) }) + @RequestMapping(value = "/accounts/{accountId}/authorisationcodes/{authorisationCode}", + produces = { "application/json" }, + consumes = { "application/json" }, + method = RequestMethod.PATCH) + ResponseEntity accountsAccountIdAuthorisationCodesAuthorisationCodePATCH(@Pattern(regexp="^((accountcategory|bankaccountno|accountrank|identityalias|iban|accountid|msisdn|swiftbic|sortcode|organisationid|username|walletid|linkref|consumerno|serviceprovider|storeid|bankname|bankaccounttitle|emailaddress|mandatereference)@([^$\\n]+))(\\$(accountcategory|bankaccountno|accountrank|identityalias|iban|accountid|msisdn|swiftbic|sortcode|organisationid|username|walletid|linkref|consumerno|serviceprovider|storeid|bankname|bankaccounttitle|emailaddress|mandatereference)@([^$\\n]+)){0,2}$") @Parameter(in = ParameterIn.PATH, description = "Path variable to uniquely identify an account. Up to three account identifiers can be supplied. Identifiers are delimited by $ and values are delimited by @. Example: organisationid@1234$accountid@3333. Valid account identifiers are accountcategory, bankaccountno, accountrank, identityalias, iban, accountid, msisdn, swiftbic, sortcode, organisationid, username, walletid, linkref, consumerno, serviceprovider, storeid, bankname, bankaccounttitle, emailaddress, mandatereference.", required=true, schema=@Schema()) @PathVariable("accountId") String accountId, @Size(min=1,max=256) @Parameter(in = ParameterIn.PATH, description = "Path variable to uniquely identify an authorisation code.", required=true, schema=@Schema()) @PathVariable("authorisationCode") String authorisationCode, @Parameter(in = ParameterIn.DEFAULT, description = "Represents the request body of a batch of generic Patch operation.", required=true, schema=@Schema()) @Valid @RequestBody List body, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." ,schema=@Schema()) @RequestHeader(value="X-Date", required=false) OffsetDateTime xDate, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's API key to the server." ,schema=@Schema()) @RequestHeader(value="X-API-Key", required=false) String xAPIKey, @Parameter(in = ParameterIn.HEADER, description = "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication." ,schema=@Schema()) @RequestHeader(value="X-User-Bearer", required=false) String xUserBearer, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's identifier to the server." ,schema=@Schema()) @RequestHeader(value="X-Client-Id", required=false) String xClientId, @Parameter(in = ParameterIn.HEADER, description = "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." ,schema=@Schema()) @RequestHeader(value="X-Content-Hash", required=false) String xContentHash, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-1", required=false) String xUserCredential1, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-2", required=false) String xUserCredential2, @Parameter(in = ParameterIn.HEADER, description = "String containing the channel that was used to originate the request. For example USSD, Web, App." ,schema=@Schema()) @RequestHeader(value="X-Channel", required=false) String xChannel, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." ,schema=@Schema(allowableValues={ "lei", "swiftbic", "organisationid" } +)) @RequestHeader(value="X-Account-Holding-Institution-Identifier-Type", required=false) String xAccountHoldingInstitutionIdentifierType, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." ,schema=@Schema()) @RequestHeader(value="X-Account-Holding-Institution-Identifier", required=false) String xAccountHoldingInstitutionIdentifier, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to uniquely identify the request. Must be supplied as a UUID." ,schema=@Schema()) @RequestHeader(value="X-CorrelationID", required=false) String xCorrelationID, @Parameter(in = ParameterIn.HEADER, description = "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." ,schema=@Schema()) @RequestHeader(value="X-Callback-URL", required=false) String xCallbackURL); + + + @Operation(summary = "View Authorisation Codes for a given account", description = "This endpoint allows allows a mobile money payer or payee to view authorisation codes for a given account.", tags={ "Authorisation Codes" }) + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Represents an authorisation codes response", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ResponseAuthorisationCode.class))), + + @ApiResponse(responseCode = "400", description = "Represents an Error Caused by the Violation of a Business Rule", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "401", description = "Represents an Error Caused by an Authorisation Failure", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "404", description = "Represents an Error Caused by a Failure to Identify the Target Resource", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "500", description = "Represents an Error Caused by a General Server-Side Issue", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "503", description = "Represents an Error Caused by System Unavailability", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))) }) + @RequestMapping(value = "/accounts/{accountId}/authorisationcodes", + produces = { "application/json" }, + method = RequestMethod.GET) + ResponseEntity accountsAccountIdAuthorisationcodesGET(@Pattern(regexp="^((accountcategory|bankaccountno|accountrank|identityalias|iban|accountid|msisdn|swiftbic|sortcode|organisationid|username|walletid|linkref|consumerno|serviceprovider|storeid|bankname|bankaccounttitle|emailaddress|mandatereference)@([^$\\n]+))(\\$(accountcategory|bankaccountno|accountrank|identityalias|iban|accountid|msisdn|swiftbic|sortcode|organisationid|username|walletid|linkref|consumerno|serviceprovider|storeid|bankname|bankaccounttitle|emailaddress|mandatereference)@([^$\\n]+)){0,2}$") @Parameter(in = ParameterIn.PATH, description = "Path variable to uniquely identify an account. Up to three account identifiers can be supplied. Identifiers are delimited by $ and values are delimited by @. Example: organisationid@1234$accountid@3333. Valid account identifiers are accountcategory, bankaccountno, accountrank, identityalias, iban, accountid, msisdn, swiftbic, sortcode, organisationid, username, walletid, linkref, consumerno, serviceprovider, storeid, bankname, bankaccounttitle, emailaddress, mandatereference.", required=true, schema=@Schema()) @PathVariable("accountId") String accountId, @NotNull @Size(max=256) @Parameter(in = ParameterIn.QUERY, description = "Allows returned records to be filtered on state of the authorisation code." ,required=true,schema=@Schema()) @Valid @RequestParam(value = "codeState", required = true) String codeState, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." ,schema=@Schema()) @RequestHeader(value="X-Date", required=false) OffsetDateTime xDate, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's API key to the server." ,schema=@Schema()) @RequestHeader(value="X-API-Key", required=false) String xAPIKey, @Parameter(in = ParameterIn.HEADER, description = "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication." ,schema=@Schema()) @RequestHeader(value="X-User-Bearer", required=false) String xUserBearer, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's identifier to the server." ,schema=@Schema()) @RequestHeader(value="X-Client-Id", required=false) String xClientId, @Parameter(in = ParameterIn.HEADER, description = "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." ,schema=@Schema()) @RequestHeader(value="X-Content-Hash", required=false) String xContentHash, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-1", required=false) String xUserCredential1, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-2", required=false) String xUserCredential2, @Parameter(in = ParameterIn.HEADER, description = "String containing the channel that was used to originate the request. For example USSD, Web, App." ,schema=@Schema()) @RequestHeader(value="X-Channel", required=false) String xChannel, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." ,schema=@Schema(allowableValues={ "lei", "swiftbic", "organisationid" } +)) @RequestHeader(value="X-Account-Holding-Institution-Identifier-Type", required=false) String xAccountHoldingInstitutionIdentifierType, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." ,schema=@Schema()) @RequestHeader(value="X-Account-Holding-Institution-Identifier", required=false) String xAccountHoldingInstitutionIdentifier, @Parameter(in = ParameterIn.QUERY, description = "Supports pagination. If this is not supplied, then the server will apply a limit of 50 records returned for each request." ,schema=@Schema()) @Valid @RequestParam(value = "limit", required = false) Integer limit, @Parameter(in = ParameterIn.QUERY, description = "Supports pagination. This value will indicate the cursor position from where to retrieve the set of records. For example, a limit of 50 and offset of 10 will return records 11 to 60." ,schema=@Schema()) @Valid @RequestParam(value = "offset", required = false) Integer offset, @Parameter(in = ParameterIn.QUERY, description = "Indicates the minimum creation date for which records should be returned." ,schema=@Schema()) @Valid @RequestParam(value = "fromDateTime", required = false) OffsetDateTime fromDateTime, @Parameter(in = ParameterIn.QUERY, description = "Indicates the maximum creation date for which records should be returned." ,schema=@Schema()) @Valid @RequestParam(value = "toDateTime", required = false) OffsetDateTime toDateTime); + + + @Operation(summary = "Create an Authorisation Code", description = "this endpoint allows allows a mobile money payer or payee to generate a code which when presented to the other party, can be redeemed for an amount set by the payer or payee, depending upon the use case", tags={ "Authorisation Codes" }) + @ApiResponses(value = { + @ApiResponse(responseCode = "201", description = "Represents an Authorisation Code response", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ResponseAuthorisationCode.class))), + + @ApiResponse(responseCode = "202", description = "Represents an Asynchronous response", content = @Content(mediaType = "application/json", schema = @Schema(implementation = RequestStateObject.class))), + + @ApiResponse(responseCode = "400", description = "Represents an Error Caused by the Violation of a Business Rule", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "401", description = "Represents an Error Caused by an Authorisation Failure", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "404", description = "Represents an Error Caused by a Failure to Identify the Target Resource", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "500", description = "Represents an Error Caused by a General Server-Side Issue", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "503", description = "Represents an Error Caused by System Unavailability", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))) }) + @RequestMapping(value = "/accounts/{accountId}/authorisationcodes", + produces = { "application/json" }, + consumes = { "application/json" }, + method = RequestMethod.POST) + ResponseEntity accountsAccountIdAuthorisationcodesPOST(@Pattern(regexp="^((accountcategory|bankaccountno|accountrank|identityalias|iban|accountid|msisdn|swiftbic|sortcode|organisationid|username|walletid|linkref|consumerno|serviceprovider|storeid|bankname|bankaccounttitle|emailaddress|mandatereference)@([^$\\n]+))(\\$(accountcategory|bankaccountno|accountrank|identityalias|iban|accountid|msisdn|swiftbic|sortcode|organisationid|username|walletid|linkref|consumerno|serviceprovider|storeid|bankname|bankaccounttitle|emailaddress|mandatereference)@([^$\\n]+)){0,2}$") @Parameter(in = ParameterIn.PATH, description = "Path variable to uniquely identify an account. Up to three account identifiers can be supplied. Identifiers are delimited by $ and values are delimited by @. Example: organisationid@1234$accountid@3333. Valid account identifiers are accountcategory, bankaccountno, accountrank, identityalias, iban, accountid, msisdn, swiftbic, sortcode, organisationid, username, walletid, linkref, consumerno, serviceprovider, storeid, bankname, bankaccounttitle, emailaddress, mandatereference.", required=true, schema=@Schema()) @PathVariable("accountId") String accountId, @Parameter(in = ParameterIn.DEFAULT, description = "Represents the request body of an Authorisation Code.", required=true, schema=@Schema()) @Valid @RequestBody RequestAuthorisationCode body, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." ,schema=@Schema()) @RequestHeader(value="X-Date", required=false) OffsetDateTime xDate, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to uniquely identify the request. Must be supplied as a UUID." ,schema=@Schema()) @RequestHeader(value="X-CorrelationID", required=false) String xCorrelationID, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's API key to the server." ,schema=@Schema()) @RequestHeader(value="X-API-Key", required=false) String xAPIKey, @Parameter(in = ParameterIn.HEADER, description = "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication." ,schema=@Schema()) @RequestHeader(value="X-User-Bearer", required=false) String xUserBearer, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's identifier to the server." ,schema=@Schema()) @RequestHeader(value="X-Client-Id", required=false) String xClientId, @Parameter(in = ParameterIn.HEADER, description = "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." ,schema=@Schema()) @RequestHeader(value="X-Content-Hash", required=false) String xContentHash, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-1", required=false) String xUserCredential1, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-2", required=false) String xUserCredential2, @Parameter(in = ParameterIn.HEADER, description = "String containing the channel that was used to originate the request. For example USSD, Web, App." ,schema=@Schema()) @RequestHeader(value="X-Channel", required=false) String xChannel, @Parameter(in = ParameterIn.HEADER, description = "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." ,schema=@Schema()) @RequestHeader(value="X-Callback-URL", required=false) String xCallbackURL, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." ,schema=@Schema(allowableValues={ "lei", "swiftbic", "organisationid" } +)) @RequestHeader(value="X-Account-Holding-Institution-Identifier-Type", required=false) String xAccountHoldingInstitutionIdentifierType, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." ,schema=@Schema()) @RequestHeader(value="X-Account-Holding-Institution-Identifier", required=false) String xAccountHoldingInstitutionIdentifier); + + + @Operation(summary = "View Account Balance", description = "This endpoint returns the balance of an account", tags={ "Accounts" }) + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Represents an Account Balance response", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ResponseAccountBalance.class))), + + @ApiResponse(responseCode = "400", description = "Represents an Error Caused by the Violation of a Business Rule", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "401", description = "Represents an Error Caused by an Authorisation Failure", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "404", description = "Represents an Error Caused by a Failure to Identify the Target Resource", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "500", description = "Represents an Error Caused by a General Server-Side Issue", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "503", description = "Represents an Error Caused by System Unavailability", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))) }) + @RequestMapping(value = "/accounts/{accountId}/balance", + produces = { "application/json" }, + method = RequestMethod.GET) + ResponseEntity accountsAccountIdBalanceGET(@Pattern(regexp="^((accountcategory|bankaccountno|accountrank|identityalias|iban|accountid|msisdn|swiftbic|sortcode|organisationid|username|walletid|linkref|consumerno|serviceprovider|storeid|bankname|bankaccounttitle|emailaddress|mandatereference)@([^$\\n]+))(\\$(accountcategory|bankaccountno|accountrank|identityalias|iban|accountid|msisdn|swiftbic|sortcode|organisationid|username|walletid|linkref|consumerno|serviceprovider|storeid|bankname|bankaccounttitle|emailaddress|mandatereference)@([^$\\n]+)){0,2}$") @Parameter(in = ParameterIn.PATH, description = "Path variable to uniquely identify an account. Up to three account identifiers can be supplied. Identifiers are delimited by $ and values are delimited by @. Example: organisationid@1234$accountid@3333. Valid account identifiers are accountcategory, bankaccountno, accountrank, identityalias, iban, accountid, msisdn, swiftbic, sortcode, organisationid, username, walletid, linkref, consumerno, serviceprovider, storeid, bankname, bankaccounttitle, emailaddress, mandatereference.", required=true, schema=@Schema()) @PathVariable("accountId") String accountId, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." ,schema=@Schema()) @RequestHeader(value="X-Date", required=false) OffsetDateTime xDate, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's API key to the server." ,schema=@Schema()) @RequestHeader(value="X-API-Key", required=false) String xAPIKey, @Parameter(in = ParameterIn.HEADER, description = "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication." ,schema=@Schema()) @RequestHeader(value="X-User-Bearer", required=false) String xUserBearer, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's identifier to the server." ,schema=@Schema()) @RequestHeader(value="X-Client-Id", required=false) String xClientId, @Parameter(in = ParameterIn.HEADER, description = "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." ,schema=@Schema()) @RequestHeader(value="X-Content-Hash", required=false) String xContentHash, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-1", required=false) String xUserCredential1, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-2", required=false) String xUserCredential2, @Parameter(in = ParameterIn.HEADER, description = "String containing the channel that was used to originate the request. For example USSD, Web, App." ,schema=@Schema()) @RequestHeader(value="X-Channel", required=false) String xChannel, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." ,schema=@Schema(allowableValues={ "lei", "swiftbic", "organisationid" } +)) @RequestHeader(value="X-Account-Holding-Institution-Identifier-Type", required=false) String xAccountHoldingInstitutionIdentifierType, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." ,schema=@Schema()) @RequestHeader(value="X-Account-Holding-Institution-Identifier", required=false) String xAccountHoldingInstitutionIdentifier); + + + @Operation(summary = "View Bill Companies", description = "This Bill Companies API is used to return a list of Service Providers that accept Bill Payments for a given account.", tags={ "Bills" }) + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Represent a list of Bill Companies", content = @Content(mediaType = "application/json", array = @ArraySchema(schema = @Schema(implementation = ResponseBillCompanies.class)))), + + @ApiResponse(responseCode = "400", description = "Represents an Error Caused by the Violation of a Business Rule", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "401", description = "Represents an Error Caused by an Authorisation Failure", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "404", description = "Represents an Error Caused by a Failure to Identify the Target Resource", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "500", description = "Represents an Error Caused by a General Server-Side Issue", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "503", description = "Represents an Error Caused by System Unavailability", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))) }) + @RequestMapping(value = "/accounts/{accountId}/billcompanies", + produces = { "application/json" }, + method = RequestMethod.GET) + ResponseEntity> accountsAccountIdBillCompaniesGET(@Pattern(regexp="^((accountcategory|bankaccountno|accountrank|identityalias|iban|accountid|msisdn|swiftbic|sortcode|organisationid|username|walletid|linkref|consumerno|serviceprovider|storeid|bankname|bankaccounttitle|emailaddress|mandatereference)@([^$\\n]+))(\\$(accountcategory|bankaccountno|accountrank|identityalias|iban|accountid|msisdn|swiftbic|sortcode|organisationid|username|walletid|linkref|consumerno|serviceprovider|storeid|bankname|bankaccounttitle|emailaddress|mandatereference)@([^$\\n]+)){0,2}$") @Parameter(in = ParameterIn.PATH, description = "Path variable to uniquely identify an account. Up to three account identifiers can be supplied. Identifiers are delimited by $ and values are delimited by @. Example: organisationid@1234$accountid@3333. Valid account identifiers are accountcategory, bankaccountno, accountrank, identityalias, iban, accountid, msisdn, swiftbic, sortcode, organisationid, username, walletid, linkref, consumerno, serviceprovider, storeid, bankname, bankaccounttitle, emailaddress, mandatereference.", required=true, schema=@Schema()) @PathVariable("accountId") String accountId, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." ,schema=@Schema()) @RequestHeader(value="X-Date", required=false) OffsetDateTime xDate, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's API key to the server." ,schema=@Schema()) @RequestHeader(value="X-API-Key", required=false) String xAPIKey, @Parameter(in = ParameterIn.HEADER, description = "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication." ,schema=@Schema()) @RequestHeader(value="X-User-Bearer", required=false) String xUserBearer, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's identifier to the server." ,schema=@Schema()) @RequestHeader(value="X-Client-Id", required=false) String xClientId, @Parameter(in = ParameterIn.HEADER, description = "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." ,schema=@Schema()) @RequestHeader(value="X-Content-Hash", required=false) String xContentHash, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." ,schema=@Schema(allowableValues={ "lei", "swiftbic", "organisationid" } +)) @RequestHeader(value="X-Account-Holding-Institution-Identifier-Type", required=false) String xAccountHoldingInstitutionIdentifierType, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." ,schema=@Schema()) @RequestHeader(value="X-Account-Holding-Institution-Identifier", required=false) String xAccountHoldingInstitutionIdentifier, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-1", required=false) String xUserCredential1, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-2", required=false) String xUserCredential2, @Parameter(in = ParameterIn.HEADER, description = "String containing the channel that was used to originate the request. For example USSD, Web, App." ,schema=@Schema()) @RequestHeader(value="X-Channel", required=false) String xChannel, @Parameter(in = ParameterIn.QUERY, description = "Supports pagination. If this is not supplied, then the server will apply a limit of 50 records returned for each request." ,schema=@Schema()) @Valid @RequestParam(value = "limit", required = false) Integer limit, @Parameter(in = ParameterIn.QUERY, description = "Supports pagination. This value will indicate the cursor position from where to retrieve the set of records. For example, a limit of 50 and offset of 10 will return records 11 to 60." ,schema=@Schema()) @Valid @RequestParam(value = "offset", required = false) Integer offset); + + + @Operation(summary = "View Payments for a Bill without a Bill Reference", description = "This endpoint allows for bill payments for a specific account to be returned", tags={ "Bills" }) + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Represents a list of Bill Payments", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ResponseBillPayment2.class))), + + @ApiResponse(responseCode = "400", description = "Represents an Error Caused by the Violation of a Business Rule", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "401", description = "Represents an Error Caused by an Authorisation Failure", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "404", description = "Represents an Error Caused by a Failure to Identify the Target Resource", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "500", description = "Represents an Error Caused by a General Server-Side Issue", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "503", description = "Represents an Error Caused by System Unavailability", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))) }) + @RequestMapping(value = "/accounts/{accountId}/bills/payments", + produces = { "application/json" }, + method = RequestMethod.GET) + ResponseEntity accountsAccountIdBillsBillPaymentsGET(@Pattern(regexp="^((accountcategory|bankaccountno|accountrank|identityalias|iban|accountid|msisdn|swiftbic|sortcode|organisationid|username|walletid|linkref|consumerno|serviceprovider|storeid|bankname|bankaccounttitle|emailaddress|mandatereference)@([^$\\n]+))(\\$(accountcategory|bankaccountno|accountrank|identityalias|iban|accountid|msisdn|swiftbic|sortcode|organisationid|username|walletid|linkref|consumerno|serviceprovider|storeid|bankname|bankaccounttitle|emailaddress|mandatereference)@([^$\\n]+)){0,2}$") @Parameter(in = ParameterIn.PATH, description = "Path variable to uniquely identify an account. Up to three account identifiers can be supplied. Identifiers are delimited by $ and values are delimited by @. Example: organisationid@1234$accountid@3333. Valid account identifiers are accountcategory, bankaccountno, accountrank, identityalias, iban, accountid, msisdn, swiftbic, sortcode, organisationid, username, walletid, linkref, consumerno, serviceprovider, storeid, bankname, bankaccounttitle, emailaddress, mandatereference.", required=true, schema=@Schema()) @PathVariable("accountId") String accountId, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." ,schema=@Schema()) @RequestHeader(value="X-Date", required=false) OffsetDateTime xDate, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's API key to the server." ,schema=@Schema()) @RequestHeader(value="X-API-Key", required=false) String xAPIKey, @Parameter(in = ParameterIn.HEADER, description = "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication." ,schema=@Schema()) @RequestHeader(value="X-User-Bearer", required=false) String xUserBearer, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's identifier to the server." ,schema=@Schema()) @RequestHeader(value="X-Client-Id", required=false) String xClientId, @Parameter(in = ParameterIn.HEADER, description = "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." ,schema=@Schema()) @RequestHeader(value="X-Content-Hash", required=false) String xContentHash, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-1", required=false) String xUserCredential1, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-2", required=false) String xUserCredential2, @Parameter(in = ParameterIn.HEADER, description = "String containing the channel that was used to originate the request. For example USSD, Web, App." ,schema=@Schema()) @RequestHeader(value="X-Channel", required=false) String xChannel, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." ,schema=@Schema(allowableValues={ "lei", "swiftbic", "organisationid" } +)) @RequestHeader(value="X-Account-Holding-Institution-Identifier-Type", required=false) String xAccountHoldingInstitutionIdentifierType, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." ,schema=@Schema()) @RequestHeader(value="X-Account-Holding-Institution-Identifier", required=false) String xAccountHoldingInstitutionIdentifier, @Parameter(in = ParameterIn.QUERY, description = "Supports pagination. If this is not supplied, then the server will apply a limit of 50 records returned for each request." ,schema=@Schema()) @Valid @RequestParam(value = "limit", required = false) Integer limit, @Parameter(in = ParameterIn.QUERY, description = "Supports pagination. This value will indicate the cursor position from where to retrieve the set of records. For example, a limit of 50 and offset of 10 will return records 11 to 60." ,schema=@Schema()) @Valid @RequestParam(value = "offset", required = false) Integer offset, @Parameter(in = ParameterIn.QUERY, description = "Indicates the minimum creation date for which records should be returned." ,schema=@Schema()) @Valid @RequestParam(value = "fromDateTime", required = false) OffsetDateTime fromDateTime, @Parameter(in = ParameterIn.QUERY, description = "Indicates the maximum creation date for which records should be returned." ,schema=@Schema()) @Valid @RequestParam(value = "toDateTime", required = false) OffsetDateTime toDateTime); + + + @Operation(summary = "Create A Bill Payment without a Bill Reference", description = "Provided with a valid object representation, this endpoint allows for a new bill payment to be created for a specific account", tags={ "Bills" }) + @ApiResponses(value = { + @ApiResponse(responseCode = "201", description = "Represents a Bill Payment response", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ResponseBillPayment2.class))), + + @ApiResponse(responseCode = "202", description = "Represents an Asynchronous response", content = @Content(mediaType = "application/json", schema = @Schema(implementation = RequestStateObject.class))), + + @ApiResponse(responseCode = "400", description = "Represents an Error Caused by the Violation of a Business Rule", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "401", description = "Represents an Error Caused by an Authorisation Failure", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "404", description = "Represents an Error Caused by a Failure to Identify the Target Resource", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "500", description = "Represents an Error Caused by a General Server-Side Issue", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "503", description = "Represents an Error Caused by System Unavailability", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))) }) + @RequestMapping(value = "/accounts/{accountId}/bills/payments", + produces = { "application/json" }, + consumes = { "application/json" }, + method = RequestMethod.POST) + ResponseEntity accountsAccountIdBillsBillPaymentsPOST(@Pattern(regexp="^((accountcategory|bankaccountno|accountrank|identityalias|iban|accountid|msisdn|swiftbic|sortcode|organisationid|username|walletid|linkref|consumerno|serviceprovider|storeid|bankname|bankaccounttitle|emailaddress|mandatereference)@([^$\\n]+))(\\$(accountcategory|bankaccountno|accountrank|identityalias|iban|accountid|msisdn|swiftbic|sortcode|organisationid|username|walletid|linkref|consumerno|serviceprovider|storeid|bankname|bankaccounttitle|emailaddress|mandatereference)@([^$\\n]+)){0,2}$") @Parameter(in = ParameterIn.PATH, description = "Path variable to uniquely identify an account. Up to three account identifiers can be supplied. Identifiers are delimited by $ and values are delimited by @. Example: organisationid@1234$accountid@3333. Valid account identifiers are accountcategory, bankaccountno, accountrank, identityalias, iban, accountid, msisdn, swiftbic, sortcode, organisationid, username, walletid, linkref, consumerno, serviceprovider, storeid, bankname, bankaccounttitle, emailaddress, mandatereference.", required=true, schema=@Schema()) @PathVariable("accountId") String accountId, @Parameter(in = ParameterIn.DEFAULT, description = "Represents the request body of a bill payment.", required=true, schema=@Schema()) @Valid @RequestBody RequestBillPayment2 body, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." ,schema=@Schema()) @RequestHeader(value="X-Date", required=false) OffsetDateTime xDate, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to uniquely identify the request. Must be supplied as a UUID." ,schema=@Schema()) @RequestHeader(value="X-CorrelationID", required=false) String xCorrelationID, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's API key to the server." ,schema=@Schema()) @RequestHeader(value="X-API-Key", required=false) String xAPIKey, @Parameter(in = ParameterIn.HEADER, description = "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication." ,schema=@Schema()) @RequestHeader(value="X-User-Bearer", required=false) String xUserBearer, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's identifier to the server." ,schema=@Schema()) @RequestHeader(value="X-Client-Id", required=false) String xClientId, @Parameter(in = ParameterIn.HEADER, description = "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." ,schema=@Schema()) @RequestHeader(value="X-Content-Hash", required=false) String xContentHash, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-1", required=false) String xUserCredential1, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-2", required=false) String xUserCredential2, @Parameter(in = ParameterIn.HEADER, description = "String containing the channel that was used to originate the request. For example USSD, Web, App." ,schema=@Schema()) @RequestHeader(value="X-Channel", required=false) String xChannel, @Parameter(in = ParameterIn.HEADER, description = "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." ,schema=@Schema()) @RequestHeader(value="X-Callback-URL", required=false) String xCallbackURL, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." ,schema=@Schema(allowableValues={ "lei", "swiftbic", "organisationid" } +)) @RequestHeader(value="X-Account-Holding-Institution-Identifier-Type", required=false) String xAccountHoldingInstitutionIdentifierType, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." ,schema=@Schema()) @RequestHeader(value="X-Account-Holding-Institution-Identifier", required=false) String xAccountHoldingInstitutionIdentifier); + + + @Operation(summary = "View Payments for a Bill", description = "This endpoint allows for bill payments for a specific account to be returned", tags={ "Bills" }) + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Represents a list of Bill Payments", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ResponseBillPayment.class))), + + @ApiResponse(responseCode = "400", description = "Represents an Error Caused by the Violation of a Business Rule", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "401", description = "Represents an Error Caused by an Authorisation Failure", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "404", description = "Represents an Error Caused by a Failure to Identify the Target Resource", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "500", description = "Represents an Error Caused by a General Server-Side Issue", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "503", description = "Represents an Error Caused by System Unavailability", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))) }) + @RequestMapping(value = "/accounts/{accountId}/bills/{billReference}/payments", + produces = { "application/json" }, + method = RequestMethod.GET) + ResponseEntity accountsAccountIdBillsBillReferencePaymentsGET(@Pattern(regexp="^((accountcategory|bankaccountno|accountrank|identityalias|iban|accountid|msisdn|swiftbic|sortcode|organisationid|username|walletid|linkref|consumerno|serviceprovider|storeid|bankname|bankaccounttitle|emailaddress|mandatereference)@([^$\\n]+))(\\$(accountcategory|bankaccountno|accountrank|identityalias|iban|accountid|msisdn|swiftbic|sortcode|organisationid|username|walletid|linkref|consumerno|serviceprovider|storeid|bankname|bankaccounttitle|emailaddress|mandatereference)@([^$\\n]+)){0,2}$") @Parameter(in = ParameterIn.PATH, description = "Path variable to uniquely identify an account. Up to three account identifiers can be supplied. Identifiers are delimited by $ and values are delimited by @. Example: organisationid@1234$accountid@3333. Valid account identifiers are accountcategory, bankaccountno, accountrank, identityalias, iban, accountid, msisdn, swiftbic, sortcode, organisationid, username, walletid, linkref, consumerno, serviceprovider, storeid, bankname, bankaccounttitle, emailaddress, mandatereference.", required=true, schema=@Schema()) @PathVariable("accountId") String accountId, @Size(min=1,max=256) @Parameter(in = ParameterIn.PATH, description = "Path variable to uniquely identify a bill.", required=true, schema=@Schema()) @PathVariable("billReference") String billReference, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." ,schema=@Schema()) @RequestHeader(value="X-Date", required=false) OffsetDateTime xDate, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's API key to the server." ,schema=@Schema()) @RequestHeader(value="X-API-Key", required=false) String xAPIKey, @Parameter(in = ParameterIn.HEADER, description = "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication." ,schema=@Schema()) @RequestHeader(value="X-User-Bearer", required=false) String xUserBearer, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's identifier to the server." ,schema=@Schema()) @RequestHeader(value="X-Client-Id", required=false) String xClientId, @Parameter(in = ParameterIn.HEADER, description = "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." ,schema=@Schema()) @RequestHeader(value="X-Content-Hash", required=false) String xContentHash, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-1", required=false) String xUserCredential1, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-2", required=false) String xUserCredential2, @Parameter(in = ParameterIn.HEADER, description = "String containing the channel that was used to originate the request. For example USSD, Web, App." ,schema=@Schema()) @RequestHeader(value="X-Channel", required=false) String xChannel, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." ,schema=@Schema(allowableValues={ "lei", "swiftbic", "organisationid" } +)) @RequestHeader(value="X-Account-Holding-Institution-Identifier-Type", required=false) String xAccountHoldingInstitutionIdentifierType, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." ,schema=@Schema()) @RequestHeader(value="X-Account-Holding-Institution-Identifier", required=false) String xAccountHoldingInstitutionIdentifier, @Parameter(in = ParameterIn.QUERY, description = "Supports pagination. If this is not supplied, then the server will apply a limit of 50 records returned for each request." ,schema=@Schema()) @Valid @RequestParam(value = "limit", required = false) Integer limit, @Parameter(in = ParameterIn.QUERY, description = "Supports pagination. This value will indicate the cursor position from where to retrieve the set of records. For example, a limit of 50 and offset of 10 will return records 11 to 60." ,schema=@Schema()) @Valid @RequestParam(value = "offset", required = false) Integer offset, @Parameter(in = ParameterIn.QUERY, description = "Indicates the minimum creation date for which records should be returned." ,schema=@Schema()) @Valid @RequestParam(value = "fromDateTime", required = false) OffsetDateTime fromDateTime, @Parameter(in = ParameterIn.QUERY, description = "Indicates the maximum creation date for which records should be returned." ,schema=@Schema()) @Valid @RequestParam(value = "toDateTime", required = false) OffsetDateTime toDateTime); + + + @Operation(summary = "Create A Bill Payment", description = "Provided with a valid object representation, this endpoint allows for a new bill payment to be created for a specific account", tags={ "Bills" }) + @ApiResponses(value = { + @ApiResponse(responseCode = "201", description = "Represents a Bill Payment response", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ResponseBillPayment.class))), + + @ApiResponse(responseCode = "202", description = "Represents an Asynchronous response", content = @Content(mediaType = "application/json", schema = @Schema(implementation = RequestStateObject.class))), + + @ApiResponse(responseCode = "400", description = "Represents an Error Caused by the Violation of a Business Rule", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "401", description = "Represents an Error Caused by an Authorisation Failure", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "404", description = "Represents an Error Caused by a Failure to Identify the Target Resource", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "500", description = "Represents an Error Caused by a General Server-Side Issue", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "503", description = "Represents an Error Caused by System Unavailability", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))) }) + @RequestMapping(value = "/accounts/{accountId}/bills/{billReference}/payments", + produces = { "application/json" }, + consumes = { "application/json" }, + method = RequestMethod.POST) + ResponseEntity accountsAccountIdBillsBillReferencePaymentsPOST(@Pattern(regexp="^((accountcategory|bankaccountno|accountrank|identityalias|iban|accountid|msisdn|swiftbic|sortcode|organisationid|username|walletid|linkref|consumerno|serviceprovider|storeid|bankname|bankaccounttitle|emailaddress|mandatereference)@([^$\\n]+))(\\$(accountcategory|bankaccountno|accountrank|identityalias|iban|accountid|msisdn|swiftbic|sortcode|organisationid|username|walletid|linkref|consumerno|serviceprovider|storeid|bankname|bankaccounttitle|emailaddress|mandatereference)@([^$\\n]+)){0,2}$") @Parameter(in = ParameterIn.PATH, description = "Path variable to uniquely identify an account. Up to three account identifiers can be supplied. Identifiers are delimited by $ and values are delimited by @. Example: organisationid@1234$accountid@3333. Valid account identifiers are accountcategory, bankaccountno, accountrank, identityalias, iban, accountid, msisdn, swiftbic, sortcode, organisationid, username, walletid, linkref, consumerno, serviceprovider, storeid, bankname, bankaccounttitle, emailaddress, mandatereference.", required=true, schema=@Schema()) @PathVariable("accountId") String accountId, @Size(min=1,max=256) @Parameter(in = ParameterIn.PATH, description = "Path variable to uniquely identify a bill.", required=true, schema=@Schema()) @PathVariable("billReference") String billReference, @Parameter(in = ParameterIn.DEFAULT, description = "Represents the request body of a bill payment.", required=true, schema=@Schema()) @Valid @RequestBody RequestBillPayment body, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." ,schema=@Schema()) @RequestHeader(value="X-Date", required=false) OffsetDateTime xDate, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to uniquely identify the request. Must be supplied as a UUID." ,schema=@Schema()) @RequestHeader(value="X-CorrelationID", required=false) String xCorrelationID, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's API key to the server." ,schema=@Schema()) @RequestHeader(value="X-API-Key", required=false) String xAPIKey, @Parameter(in = ParameterIn.HEADER, description = "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication." ,schema=@Schema()) @RequestHeader(value="X-User-Bearer", required=false) String xUserBearer, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's identifier to the server." ,schema=@Schema()) @RequestHeader(value="X-Client-Id", required=false) String xClientId, @Parameter(in = ParameterIn.HEADER, description = "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." ,schema=@Schema()) @RequestHeader(value="X-Content-Hash", required=false) String xContentHash, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-1", required=false) String xUserCredential1, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-2", required=false) String xUserCredential2, @Parameter(in = ParameterIn.HEADER, description = "String containing the channel that was used to originate the request. For example USSD, Web, App." ,schema=@Schema()) @RequestHeader(value="X-Channel", required=false) String xChannel, @Parameter(in = ParameterIn.HEADER, description = "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." ,schema=@Schema()) @RequestHeader(value="X-Callback-URL", required=false) String xCallbackURL, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." ,schema=@Schema(allowableValues={ "lei", "swiftbic", "organisationid" } +)) @RequestHeader(value="X-Account-Holding-Institution-Identifier-Type", required=false) String xAccountHoldingInstitutionIdentifierType, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." ,schema=@Schema()) @RequestHeader(value="X-Account-Holding-Institution-Identifier", required=false) String xAccountHoldingInstitutionIdentifier); + + + @Operation(summary = "View Account Bills", description = "This endpoint returns bills linked to an account", tags={ "Bills" }) + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Represent a list of Bills", content = @Content(mediaType = "application/json", array = @ArraySchema(schema = @Schema(implementation = ResponseBills.class)))), + + @ApiResponse(responseCode = "400", description = "Represents an Error Caused by the Violation of a Business Rule", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "401", description = "Represents an Error Caused by an Authorisation Failure", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "404", description = "Represents an Error Caused by a Failure to Identify the Target Resource", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "500", description = "Represents an Error Caused by a General Server-Side Issue", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "503", description = "Represents an Error Caused by System Unavailability", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))) }) + @RequestMapping(value = "/accounts/{accountId}/bills", + produces = { "application/json" }, + method = RequestMethod.GET) + ResponseEntity> accountsAccountIdBillsGET(@Pattern(regexp="^((accountcategory|bankaccountno|accountrank|identityalias|iban|accountid|msisdn|swiftbic|sortcode|organisationid|username|walletid|linkref|consumerno|serviceprovider|storeid|bankname|bankaccounttitle|emailaddress|mandatereference)@([^$\\n]+))(\\$(accountcategory|bankaccountno|accountrank|identityalias|iban|accountid|msisdn|swiftbic|sortcode|organisationid|username|walletid|linkref|consumerno|serviceprovider|storeid|bankname|bankaccounttitle|emailaddress|mandatereference)@([^$\\n]+)){0,2}$") @Parameter(in = ParameterIn.PATH, description = "Path variable to uniquely identify an account. Up to three account identifiers can be supplied. Identifiers are delimited by $ and values are delimited by @. Example: organisationid@1234$accountid@3333. Valid account identifiers are accountcategory, bankaccountno, accountrank, identityalias, iban, accountid, msisdn, swiftbic, sortcode, organisationid, username, walletid, linkref, consumerno, serviceprovider, storeid, bankname, bankaccounttitle, emailaddress, mandatereference.", required=true, schema=@Schema()) @PathVariable("accountId") String accountId, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." ,schema=@Schema()) @RequestHeader(value="X-Date", required=false) OffsetDateTime xDate, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's API key to the server." ,schema=@Schema()) @RequestHeader(value="X-API-Key", required=false) String xAPIKey, @Parameter(in = ParameterIn.HEADER, description = "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication." ,schema=@Schema()) @RequestHeader(value="X-User-Bearer", required=false) String xUserBearer, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's identifier to the server." ,schema=@Schema()) @RequestHeader(value="X-Client-Id", required=false) String xClientId, @Parameter(in = ParameterIn.HEADER, description = "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." ,schema=@Schema()) @RequestHeader(value="X-Content-Hash", required=false) String xContentHash, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-1", required=false) String xUserCredential1, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-2", required=false) String xUserCredential2, @Parameter(in = ParameterIn.HEADER, description = "String containing the channel that was used to originate the request. For example USSD, Web, App." ,schema=@Schema()) @RequestHeader(value="X-Channel", required=false) String xChannel, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." ,schema=@Schema(allowableValues={ "lei", "swiftbic", "organisationid" } +)) @RequestHeader(value="X-Account-Holding-Institution-Identifier-Type", required=false) String xAccountHoldingInstitutionIdentifierType, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." ,schema=@Schema()) @RequestHeader(value="X-Account-Holding-Institution-Identifier", required=false) String xAccountHoldingInstitutionIdentifier, @Parameter(in = ParameterIn.QUERY, description = "Supports pagination. If this is not supplied, then the server will apply a limit of 50 records returned for each request." ,schema=@Schema()) @Valid @RequestParam(value = "limit", required = false) Integer limit, @Parameter(in = ParameterIn.QUERY, description = "Supports pagination. This value will indicate the cursor position from where to retrieve the set of records. For example, a limit of 50 and offset of 10 will return records 11 to 60." ,schema=@Schema()) @Valid @RequestParam(value = "offset", required = false) Integer offset, @Parameter(in = ParameterIn.QUERY, description = "Indicates the minimum creation date for which records should be returned." ,schema=@Schema()) @Valid @RequestParam(value = "fromDateTime", required = false) OffsetDateTime fromDateTime, @Parameter(in = ParameterIn.QUERY, description = "Indicates the maximum creation date for which records should be returned." ,schema=@Schema()) @Valid @RequestParam(value = "toDateTime", required = false) OffsetDateTime toDateTime); + + + @Operation(summary = "View A Debit Mandate", description = "This endpoint returns a specific debit mandate linked to an account", tags={ "Debit Mandates" }) + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Represents a Debit Mandate response", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ResponseDebitMandate.class))), + + @ApiResponse(responseCode = "400", description = "Represents an Error Caused by the Violation of a Business Rule", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "401", description = "Represents an Error Caused by an Authorisation Failure", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "404", description = "Represents an Error Caused by a Failure to Identify the Target Resource", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "500", description = "Represents an Error Caused by a General Server-Side Issue", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "503", description = "Represents an Error Caused by System Unavailability", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))) }) + @RequestMapping(value = "/accounts/{accountId}/debitmandates/{debitMandateReference}", + produces = { "application/json" }, + method = RequestMethod.GET) + ResponseEntity accountsAccountIdDebitmandatesDebitMandateReferenceGET(@Pattern(regexp="^((accountcategory|bankaccountno|accountrank|identityalias|iban|accountid|msisdn|swiftbic|sortcode|organisationid|username|walletid|linkref|consumerno|serviceprovider|storeid|bankname|bankaccounttitle|emailaddress|mandatereference)@([^$\\n]+))(\\$(accountcategory|bankaccountno|accountrank|identityalias|iban|accountid|msisdn|swiftbic|sortcode|organisationid|username|walletid|linkref|consumerno|serviceprovider|storeid|bankname|bankaccounttitle|emailaddress|mandatereference)@([^$\\n]+)){0,2}$") @Parameter(in = ParameterIn.PATH, description = "Path variable to uniquely identify an account. Up to three account identifiers can be supplied. Identifiers are delimited by $ and values are delimited by @. Example: organisationid@1234$accountid@3333. Valid account identifiers are accountcategory, bankaccountno, accountrank, identityalias, iban, accountid, msisdn, swiftbic, sortcode, organisationid, username, walletid, linkref, consumerno, serviceprovider, storeid, bankname, bankaccounttitle, emailaddress, mandatereference.", required=true, schema=@Schema()) @PathVariable("accountId") String accountId, @Size(min=1,max=256) @Parameter(in = ParameterIn.PATH, description = "Path variable to uniquely identify a Debit Mandate Reference.", required=true, schema=@Schema()) @PathVariable("debitMandateReference") String debitMandateReference, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." ,schema=@Schema()) @RequestHeader(value="X-Date", required=false) OffsetDateTime xDate, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's API key to the server." ,schema=@Schema()) @RequestHeader(value="X-API-Key", required=false) String xAPIKey, @Parameter(in = ParameterIn.HEADER, description = "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication." ,schema=@Schema()) @RequestHeader(value="X-User-Bearer", required=false) String xUserBearer, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's identifier to the server." ,schema=@Schema()) @RequestHeader(value="X-Client-Id", required=false) String xClientId, @Parameter(in = ParameterIn.HEADER, description = "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." ,schema=@Schema()) @RequestHeader(value="X-Content-Hash", required=false) String xContentHash, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-1", required=false) String xUserCredential1, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-2", required=false) String xUserCredential2, @Parameter(in = ParameterIn.HEADER, description = "String containing the channel that was used to originate the request. For example USSD, Web, App." ,schema=@Schema()) @RequestHeader(value="X-Channel", required=false) String xChannel, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." ,schema=@Schema(allowableValues={ "lei", "swiftbic", "organisationid" } +)) @RequestHeader(value="X-Account-Holding-Institution-Identifier-Type", required=false) String xAccountHoldingInstitutionIdentifierType, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." ,schema=@Schema()) @RequestHeader(value="X-Account-Holding-Institution-Identifier", required=false) String xAccountHoldingInstitutionIdentifier); + + + @Operation(summary = "Update A Debit Mandate", description = "This endpoint updates a specific debit mandate linked to an account. The following fields are modifiable] mandateStatus, startDate, endDate, frequencyType, numberOfPayments.", tags={ "Debit Mandates" }) + @ApiResponses(value = { + @ApiResponse(responseCode = "202", description = "Represents an Asynchronous response", content = @Content(mediaType = "application/json", schema = @Schema(implementation = RequestStateObject.class))), + + @ApiResponse(responseCode = "204", description = "An empty response is returned for a synchronous successful patch."), + + @ApiResponse(responseCode = "400", description = "Represents an Error Caused by the Violation of a Business Rule", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "401", description = "Represents an Error Caused by an Authorisation Failure", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "404", description = "Represents an Error Caused by a Failure to Identify the Target Resource", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "500", description = "Represents an Error Caused by a General Server-Side Issue", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "503", description = "Represents an Error Caused by System Unavailability", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))) }) + @RequestMapping(value = "/accounts/{accountId}/debitmandates/{debitMandateReference}", + produces = { "application/json" }, + consumes = { "application/json" }, + method = RequestMethod.PATCH) + ResponseEntity accountsAccountIdDebitmandatesDebitMandateReferencePATCH(@Pattern(regexp="^((accountcategory|bankaccountno|accountrank|identityalias|iban|accountid|msisdn|swiftbic|sortcode|organisationid|username|walletid|linkref|consumerno|serviceprovider|storeid|bankname|bankaccounttitle|emailaddress|mandatereference)@([^$\\n]+))(\\$(accountcategory|bankaccountno|accountrank|identityalias|iban|accountid|msisdn|swiftbic|sortcode|organisationid|username|walletid|linkref|consumerno|serviceprovider|storeid|bankname|bankaccounttitle|emailaddress|mandatereference)@([^$\\n]+)){0,2}$") @Parameter(in = ParameterIn.PATH, description = "Path variable to uniquely identify an account. Up to three account identifiers can be supplied. Identifiers are delimited by $ and values are delimited by @. Example: organisationid@1234$accountid@3333. Valid account identifiers are accountcategory, bankaccountno, accountrank, identityalias, iban, accountid, msisdn, swiftbic, sortcode, organisationid, username, walletid, linkref, consumerno, serviceprovider, storeid, bankname, bankaccounttitle, emailaddress, mandatereference.", required=true, schema=@Schema()) @PathVariable("accountId") String accountId, @Size(min=1,max=256) @Parameter(in = ParameterIn.PATH, description = "Path variable to uniquely identify a Debit Mandate Reference.", required=true, schema=@Schema()) @PathVariable("debitMandateReference") String debitMandateReference, @Parameter(in = ParameterIn.DEFAULT, description = "Represents the request body of a batch of generic Patch operation.", required=true, schema=@Schema()) @Valid @RequestBody List body, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." ,schema=@Schema()) @RequestHeader(value="X-Date", required=false) OffsetDateTime xDate, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's API key to the server." ,schema=@Schema()) @RequestHeader(value="X-API-Key", required=false) String xAPIKey, @Parameter(in = ParameterIn.HEADER, description = "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication." ,schema=@Schema()) @RequestHeader(value="X-User-Bearer", required=false) String xUserBearer, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's identifier to the server." ,schema=@Schema()) @RequestHeader(value="X-Client-Id", required=false) String xClientId, @Parameter(in = ParameterIn.HEADER, description = "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." ,schema=@Schema()) @RequestHeader(value="X-Content-Hash", required=false) String xContentHash, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-1", required=false) String xUserCredential1, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-2", required=false) String xUserCredential2, @Parameter(in = ParameterIn.HEADER, description = "String containing the channel that was used to originate the request. For example USSD, Web, App." ,schema=@Schema()) @RequestHeader(value="X-Channel", required=false) String xChannel, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." ,schema=@Schema(allowableValues={ "lei", "swiftbic", "organisationid" } +)) @RequestHeader(value="X-Account-Holding-Institution-Identifier-Type", required=false) String xAccountHoldingInstitutionIdentifierType, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." ,schema=@Schema()) @RequestHeader(value="X-Account-Holding-Institution-Identifier", required=false) String xAccountHoldingInstitutionIdentifier, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to uniquely identify the request. Must be supplied as a UUID." ,schema=@Schema()) @RequestHeader(value="X-CorrelationID", required=false) String xCorrelationID, @Parameter(in = ParameterIn.HEADER, description = "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." ,schema=@Schema()) @RequestHeader(value="X-Callback-URL", required=false) String xCallbackURL); + + + @Operation(summary = "Create A Debit Mandate", description = "Provided with a valid object representation, this endpoint allows for a new debit mandate to be created for a specific account.", tags={ "Debit Mandates" }) + @ApiResponses(value = { + @ApiResponse(responseCode = "201", description = "Represents a Debit Mandate response", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ResponseDebitMandate.class))), + + @ApiResponse(responseCode = "202", description = "Represents an Asynchronous response", content = @Content(mediaType = "application/json", schema = @Schema(implementation = RequestStateObject.class))), + + @ApiResponse(responseCode = "400", description = "Represents an Error Caused by the Violation of a Business Rule", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "401", description = "Represents an Error Caused by an Authorisation Failure", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "404", description = "Represents an Error Caused by a Failure to Identify the Target Resource", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "500", description = "Represents an Error Caused by a General Server-Side Issue", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "503", description = "Represents an Error Caused by System Unavailability", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))) }) + @RequestMapping(value = "/accounts/{accountId}/debitmandates", + produces = { "application/json" }, + consumes = { "application/json" }, + method = RequestMethod.POST) + ResponseEntity accountsAccountIdDebitmandatesPOST(@Pattern(regexp="^((accountcategory|bankaccountno|accountrank|identityalias|iban|accountid|msisdn|swiftbic|sortcode|organisationid|username|walletid|linkref|consumerno|serviceprovider|storeid|bankname|bankaccounttitle|emailaddress|mandatereference)@([^$\\n]+))(\\$(accountcategory|bankaccountno|accountrank|identityalias|iban|accountid|msisdn|swiftbic|sortcode|organisationid|username|walletid|linkref|consumerno|serviceprovider|storeid|bankname|bankaccounttitle|emailaddress|mandatereference)@([^$\\n]+)){0,2}$") @Parameter(in = ParameterIn.PATH, description = "Path variable to uniquely identify an account. Up to three account identifiers can be supplied. Identifiers are delimited by $ and values are delimited by @. Example: organisationid@1234$accountid@3333. Valid account identifiers are accountcategory, bankaccountno, accountrank, identityalias, iban, accountid, msisdn, swiftbic, sortcode, organisationid, username, walletid, linkref, consumerno, serviceprovider, storeid, bankname, bankaccounttitle, emailaddress, mandatereference.", required=true, schema=@Schema()) @PathVariable("accountId") String accountId, @Parameter(in = ParameterIn.DEFAULT, description = "Represents the request body of a debit mandate.", required=true, schema=@Schema()) @Valid @RequestBody RequestDebitMandate body, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." ,schema=@Schema()) @RequestHeader(value="X-Date", required=false) OffsetDateTime xDate, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to uniquely identify the request. Must be supplied as a UUID." ,schema=@Schema()) @RequestHeader(value="X-CorrelationID", required=false) String xCorrelationID, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's API key to the server." ,schema=@Schema()) @RequestHeader(value="X-API-Key", required=false) String xAPIKey, @Parameter(in = ParameterIn.HEADER, description = "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication." ,schema=@Schema()) @RequestHeader(value="X-User-Bearer", required=false) String xUserBearer, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's identifier to the server." ,schema=@Schema()) @RequestHeader(value="X-Client-Id", required=false) String xClientId, @Parameter(in = ParameterIn.HEADER, description = "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." ,schema=@Schema()) @RequestHeader(value="X-Content-Hash", required=false) String xContentHash, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-1", required=false) String xUserCredential1, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-2", required=false) String xUserCredential2, @Parameter(in = ParameterIn.HEADER, description = "String containing the channel that was used to originate the request. For example USSD, Web, App." ,schema=@Schema()) @RequestHeader(value="X-Channel", required=false) String xChannel, @Parameter(in = ParameterIn.HEADER, description = "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." ,schema=@Schema()) @RequestHeader(value="X-Callback-URL", required=false) String xCallbackURL, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." ,schema=@Schema(allowableValues={ "lei", "swiftbic", "organisationid" } +)) @RequestHeader(value="X-Account-Holding-Institution-Identifier-Type", required=false) String xAccountHoldingInstitutionIdentifierType, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." ,schema=@Schema()) @RequestHeader(value="X-Account-Holding-Institution-Identifier", required=false) String xAccountHoldingInstitutionIdentifier); + + + @Operation(summary = "View an Account", description = "This endpoint returns details for a given account. This API accepts multiple account identifiers", tags={ "Accounts" }) + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Represents an Account response", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ResponseAccount.class))), + + @ApiResponse(responseCode = "400", description = "Represents an Error Caused by the Violation of a Business Rule", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "401", description = "Represents an Error Caused by an Authorisation Failure", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "404", description = "Represents an Error Caused by a Failure to Identify the Target Resource", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "500", description = "Represents an Error Caused by a General Server-Side Issue", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "503", description = "Represents an Error Caused by System Unavailability", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))) }) + @RequestMapping(value = "/accounts/{accountId}", + produces = { "application/json" }, + method = RequestMethod.GET) + ResponseEntity accountsAccountIdGET(@Pattern(regexp="^((accountcategory|bankaccountno|accountrank|identityalias|iban|accountid|msisdn|swiftbic|sortcode|organisationid|username|walletid|linkref|consumerno|serviceprovider|storeid|bankname|bankaccounttitle|emailaddress|mandatereference)@([^$\\n]+))(\\$(accountcategory|bankaccountno|accountrank|identityalias|iban|accountid|msisdn|swiftbic|sortcode|organisationid|username|walletid|linkref|consumerno|serviceprovider|storeid|bankname|bankaccounttitle|emailaddress|mandatereference)@([^$\\n]+)){0,2}$") @Parameter(in = ParameterIn.PATH, description = "Path variable to uniquely identify an account. Up to three account identifiers can be supplied. Identifiers are delimited by $ and values are delimited by @. Example: organisationid@1234$accountid@3333. Valid account identifiers are accountcategory, bankaccountno, accountrank, identityalias, iban, accountid, msisdn, swiftbic, sortcode, organisationid, username, walletid, linkref, consumerno, serviceprovider, storeid, bankname, bankaccounttitle, emailaddress, mandatereference.", required=true, schema=@Schema()) @PathVariable("accountId") String accountId, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." ,schema=@Schema()) @RequestHeader(value="X-Date", required=false) OffsetDateTime xDate, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's API key to the server." ,schema=@Schema()) @RequestHeader(value="X-API-Key", required=false) String xAPIKey, @Parameter(in = ParameterIn.HEADER, description = "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication." ,schema=@Schema()) @RequestHeader(value="X-User-Bearer", required=false) String xUserBearer, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's identifier to the server." ,schema=@Schema()) @RequestHeader(value="X-Client-Id", required=false) String xClientId, @Parameter(in = ParameterIn.HEADER, description = "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." ,schema=@Schema()) @RequestHeader(value="X-Content-Hash", required=false) String xContentHash, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-1", required=false) String xUserCredential1, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-2", required=false) String xUserCredential2, @Parameter(in = ParameterIn.HEADER, description = "String containing the channel that was used to originate the request. For example USSD, Web, App." ,schema=@Schema()) @RequestHeader(value="X-Channel", required=false) String xChannel, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." ,schema=@Schema(allowableValues={ "lei", "swiftbic", "organisationid" } +)) @RequestHeader(value="X-Account-Holding-Institution-Identifier-Type", required=false) String xAccountHoldingInstitutionIdentifierType, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." ,schema=@Schema()) @RequestHeader(value="X-Account-Holding-Institution-Identifier", required=false) String xAccountHoldingInstitutionIdentifier); + + + @Operation(summary = "View A Link", description = "This endpoint returns a specific link", tags={ "Links" }) + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Represents a Link response\"", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ResponseLink.class))), + + @ApiResponse(responseCode = "400", description = "Represents an Error Caused by the Violation of a Business Rule", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "401", description = "Represents an Error Caused by an Authorisation Failure", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "404", description = "Represents an Error Caused by a Failure to Identify the Target Resource", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "500", description = "Represents an Error Caused by a General Server-Side Issue", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "503", description = "Represents an Error Caused by System Unavailability", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))) }) + @RequestMapping(value = "/accounts/{accountId}/links/{linkReference}", + produces = { "application/json" }, + method = RequestMethod.GET) + ResponseEntity accountsAccountIdLinksLinkReferenceGET(@Pattern(regexp="^((accountcategory|bankaccountno|accountrank|identityalias|iban|accountid|msisdn|swiftbic|sortcode|organisationid|username|walletid|linkref|consumerno|serviceprovider|storeid|bankname|bankaccounttitle|emailaddress|mandatereference)@([^$\\n]+))(\\$(accountcategory|bankaccountno|accountrank|identityalias|iban|accountid|msisdn|swiftbic|sortcode|organisationid|username|walletid|linkref|consumerno|serviceprovider|storeid|bankname|bankaccounttitle|emailaddress|mandatereference)@([^$\\n]+)){0,2}$") @Parameter(in = ParameterIn.PATH, description = "Path variable to uniquely identify an account. Up to three account identifiers can be supplied. Identifiers are delimited by $ and values are delimited by @. Example: organisationid@1234$accountid@3333. Valid account identifiers are accountcategory, bankaccountno, accountrank, identityalias, iban, accountid, msisdn, swiftbic, sortcode, organisationid, username, walletid, linkref, consumerno, serviceprovider, storeid, bankname, bankaccounttitle, emailaddress, mandatereference.", required=true, schema=@Schema()) @PathVariable("accountId") String accountId, @Size(min=1,max=256) @Parameter(in = ParameterIn.PATH, description = "Path variable to uniquely identify a link.", required=true, schema=@Schema()) @PathVariable("linkReference") String linkReference, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." ,schema=@Schema()) @RequestHeader(value="X-Date", required=false) OffsetDateTime xDate, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's API key to the server." ,schema=@Schema()) @RequestHeader(value="X-API-Key", required=false) String xAPIKey, @Parameter(in = ParameterIn.HEADER, description = "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication." ,schema=@Schema()) @RequestHeader(value="X-User-Bearer", required=false) String xUserBearer, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's identifier to the server." ,schema=@Schema()) @RequestHeader(value="X-Client-Id", required=false) String xClientId, @Parameter(in = ParameterIn.HEADER, description = "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." ,schema=@Schema()) @RequestHeader(value="X-Content-Hash", required=false) String xContentHash, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-1", required=false) String xUserCredential1, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-2", required=false) String xUserCredential2, @Parameter(in = ParameterIn.HEADER, description = "String containing the channel that was used to originate the request. For example USSD, Web, App." ,schema=@Schema()) @RequestHeader(value="X-Channel", required=false) String xChannel, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." ,schema=@Schema(allowableValues={ "lei", "swiftbic", "organisationid" } +)) @RequestHeader(value="X-Account-Holding-Institution-Identifier-Type", required=false) String xAccountHoldingInstitutionIdentifierType, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." ,schema=@Schema()) @RequestHeader(value="X-Account-Holding-Institution-Identifier", required=false) String xAccountHoldingInstitutionIdentifier); + + + @Operation(summary = "Update A Link", description = "This endpoint updates a specific link. mode and status fields are modifiable.", tags={ "Links" }) + @ApiResponses(value = { + @ApiResponse(responseCode = "202", description = "Represents an Asynchronous response", content = @Content(mediaType = "application/json", schema = @Schema(implementation = RequestStateObject.class))), + + @ApiResponse(responseCode = "204", description = "An empty response is returned for a synchronous successful patch."), + + @ApiResponse(responseCode = "400", description = "Represents an Error Caused by the Violation of a Business Rule", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "401", description = "Represents an Error Caused by an Authorisation Failure", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "404", description = "Represents an Error Caused by a Failure to Identify the Target Resource", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "500", description = "Represents an Error Caused by a General Server-Side Issue", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "503", description = "Represents an Error Caused by System Unavailability", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))) }) + @RequestMapping(value = "/accounts/{accountId}/links/{linkReference}", + produces = { "application/json" }, + consumes = { "application/json" }, + method = RequestMethod.PATCH) + ResponseEntity accountsAccountIdLinksLinkReferencePATCH(@Pattern(regexp="^((accountcategory|bankaccountno|accountrank|identityalias|iban|accountid|msisdn|swiftbic|sortcode|organisationid|username|walletid|linkref|consumerno|serviceprovider|storeid|bankname|bankaccounttitle|emailaddress|mandatereference)@([^$\\n]+))(\\$(accountcategory|bankaccountno|accountrank|identityalias|iban|accountid|msisdn|swiftbic|sortcode|organisationid|username|walletid|linkref|consumerno|serviceprovider|storeid|bankname|bankaccounttitle|emailaddress|mandatereference)@([^$\\n]+)){0,2}$") @Parameter(in = ParameterIn.PATH, description = "Path variable to uniquely identify an account. Up to three account identifiers can be supplied. Identifiers are delimited by $ and values are delimited by @. Example: organisationid@1234$accountid@3333. Valid account identifiers are accountcategory, bankaccountno, accountrank, identityalias, iban, accountid, msisdn, swiftbic, sortcode, organisationid, username, walletid, linkref, consumerno, serviceprovider, storeid, bankname, bankaccounttitle, emailaddress, mandatereference.", required=true, schema=@Schema()) @PathVariable("accountId") String accountId, @Size(min=1,max=256) @Parameter(in = ParameterIn.PATH, description = "Path variable to uniquely identify a link.", required=true, schema=@Schema()) @PathVariable("linkReference") String linkReference, @Parameter(in = ParameterIn.DEFAULT, description = "Represents the request body of a batch of generic Patch operation.", required=true, schema=@Schema()) @Valid @RequestBody List body, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." ,schema=@Schema()) @RequestHeader(value="X-Date", required=false) OffsetDateTime xDate, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's API key to the server." ,schema=@Schema()) @RequestHeader(value="X-API-Key", required=false) String xAPIKey, @Parameter(in = ParameterIn.HEADER, description = "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication." ,schema=@Schema()) @RequestHeader(value="X-User-Bearer", required=false) String xUserBearer, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's identifier to the server." ,schema=@Schema()) @RequestHeader(value="X-Client-Id", required=false) String xClientId, @Parameter(in = ParameterIn.HEADER, description = "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." ,schema=@Schema()) @RequestHeader(value="X-Content-Hash", required=false) String xContentHash, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-1", required=false) String xUserCredential1, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-2", required=false) String xUserCredential2, @Parameter(in = ParameterIn.HEADER, description = "String containing the channel that was used to originate the request. For example USSD, Web, App." ,schema=@Schema()) @RequestHeader(value="X-Channel", required=false) String xChannel, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." ,schema=@Schema(allowableValues={ "lei", "swiftbic", "organisationid" } +)) @RequestHeader(value="X-Account-Holding-Institution-Identifier-Type", required=false) String xAccountHoldingInstitutionIdentifierType, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." ,schema=@Schema()) @RequestHeader(value="X-Account-Holding-Institution-Identifier", required=false) String xAccountHoldingInstitutionIdentifier, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to uniquely identify the request. Must be supplied as a UUID." ,schema=@Schema()) @RequestHeader(value="X-CorrelationID", required=false) String xCorrelationID, @Parameter(in = ParameterIn.HEADER, description = "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." ,schema=@Schema()) @RequestHeader(value="X-Callback-URL", required=false) String xCallbackURL); + + + @Operation(summary = "Create A Link", description = "Provided with a valid object representation, this endpoint allows a new link to be created for a specific account", tags={ "Links" }) + @ApiResponses(value = { + @ApiResponse(responseCode = "201", description = "Represents a Link response", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ResponseLink.class))), + + @ApiResponse(responseCode = "202", description = "Represents an Asynchronous response", content = @Content(mediaType = "application/json", schema = @Schema(implementation = RequestStateObject.class))), + + @ApiResponse(responseCode = "400", description = "Represents an Error Caused by the Violation of a Business Rule", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "401", description = "Represents an Error Caused by an Authorisation Failure", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "404", description = "Represents an Error Caused by a Failure to Identify the Target Resource", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "500", description = "Represents an Error Caused by a General Server-Side Issue", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "503", description = "Represents an Error Caused by System Unavailability", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))) }) + @RequestMapping(value = "/accounts/{accountId}/links", + produces = { "application/json" }, + consumes = { "application/json" }, + method = RequestMethod.POST) + ResponseEntity accountsAccountIdLinksPOST(@Pattern(regexp="^((accountcategory|bankaccountno|accountrank|identityalias|iban|accountid|msisdn|swiftbic|sortcode|organisationid|username|walletid|linkref|consumerno|serviceprovider|storeid|bankname|bankaccounttitle|emailaddress|mandatereference)@([^$\\n]+))(\\$(accountcategory|bankaccountno|accountrank|identityalias|iban|accountid|msisdn|swiftbic|sortcode|organisationid|username|walletid|linkref|consumerno|serviceprovider|storeid|bankname|bankaccounttitle|emailaddress|mandatereference)@([^$\\n]+)){0,2}$") @Parameter(in = ParameterIn.PATH, description = "Path variable to uniquely identify an account. Up to three account identifiers can be supplied. Identifiers are delimited by $ and values are delimited by @. Example: organisationid@1234$accountid@3333. Valid account identifiers are accountcategory, bankaccountno, accountrank, identityalias, iban, accountid, msisdn, swiftbic, sortcode, organisationid, username, walletid, linkref, consumerno, serviceprovider, storeid, bankname, bankaccounttitle, emailaddress, mandatereference.", required=true, schema=@Schema()) @PathVariable("accountId") String accountId, @Parameter(in = ParameterIn.DEFAULT, description = "Represents the request body of a Link.", required=true, schema=@Schema()) @Valid @RequestBody RequestLink body, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." ,schema=@Schema()) @RequestHeader(value="X-Date", required=false) OffsetDateTime xDate, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to uniquely identify the request. Must be supplied as a UUID." ,schema=@Schema()) @RequestHeader(value="X-CorrelationID", required=false) String xCorrelationID, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's API key to the server." ,schema=@Schema()) @RequestHeader(value="X-API-Key", required=false) String xAPIKey, @Parameter(in = ParameterIn.HEADER, description = "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication." ,schema=@Schema()) @RequestHeader(value="X-User-Bearer", required=false) String xUserBearer, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's identifier to the server." ,schema=@Schema()) @RequestHeader(value="X-Client-Id", required=false) String xClientId, @Parameter(in = ParameterIn.HEADER, description = "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." ,schema=@Schema()) @RequestHeader(value="X-Content-Hash", required=false) String xContentHash, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-1", required=false) String xUserCredential1, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-2", required=false) String xUserCredential2, @Parameter(in = ParameterIn.HEADER, description = "String containing the channel that was used to originate the request. For example USSD, Web, App." ,schema=@Schema()) @RequestHeader(value="X-Channel", required=false) String xChannel, @Parameter(in = ParameterIn.HEADER, description = "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." ,schema=@Schema()) @RequestHeader(value="X-Callback-URL", required=false) String xCallbackURL, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." ,schema=@Schema(allowableValues={ "lei", "swiftbic", "organisationid" } +)) @RequestHeader(value="X-Account-Holding-Institution-Identifier-Type", required=false) String xAccountHoldingInstitutionIdentifierType, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." ,schema=@Schema()) @RequestHeader(value="X-Account-Holding-Institution-Identifier", required=false) String xAccountHoldingInstitutionIdentifier); + + + @Operation(summary = "Update an Account", description = "This endpoint updates an account. Currently, accountStatus and accountSubStatus fields can be updated.", tags={ "Accounts" }) + @ApiResponses(value = { + @ApiResponse(responseCode = "202", description = "Represents an Asynchronous response", content = @Content(mediaType = "application/json", schema = @Schema(implementation = RequestStateObject.class))), + + @ApiResponse(responseCode = "204", description = "An empty response is returned for a synchronous successful patch."), + + @ApiResponse(responseCode = "400", description = "Represents an Error Caused by the Violation of a Business Rule", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "401", description = "Represents an Error Caused by an Authorisation Failure", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "404", description = "Represents an Error Caused by a Failure to Identify the Target Resource", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "500", description = "Represents an Error Caused by a General Server-Side Issue", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "503", description = "Represents an Error Caused by System Unavailability", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))) }) + @RequestMapping(value = "/accounts/{accountId}", + produces = { "application/json" }, + consumes = { "application/json" }, + method = RequestMethod.PATCH) + ResponseEntity accountsAccountIdPATCH(@Pattern(regexp="^((accountcategory|bankaccountno|accountrank|identityalias|iban|accountid|msisdn|swiftbic|sortcode|organisationid|username|walletid|linkref|consumerno|serviceprovider|storeid|bankname|bankaccounttitle|emailaddress|mandatereference)@([^$\\n]+))(\\$(accountcategory|bankaccountno|accountrank|identityalias|iban|accountid|msisdn|swiftbic|sortcode|organisationid|username|walletid|linkref|consumerno|serviceprovider|storeid|bankname|bankaccounttitle|emailaddress|mandatereference)@([^$\\n]+)){0,2}$") @Parameter(in = ParameterIn.PATH, description = "Path variable to uniquely identify an account. Up to three account identifiers can be supplied. Identifiers are delimited by $ and values are delimited by @. Example: organisationid@1234$accountid@3333. Valid account identifiers are accountcategory, bankaccountno, accountrank, identityalias, iban, accountid, msisdn, swiftbic, sortcode, organisationid, username, walletid, linkref, consumerno, serviceprovider, storeid, bankname, bankaccounttitle, emailaddress, mandatereference.", required=true, schema=@Schema()) @PathVariable("accountId") String accountId, @Parameter(in = ParameterIn.DEFAULT, description = "Represents the request body of a batch of generic Patch operation.", required=true, schema=@Schema()) @Valid @RequestBody List body, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." ,schema=@Schema()) @RequestHeader(value="X-Date", required=false) OffsetDateTime xDate, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's API key to the server." ,schema=@Schema()) @RequestHeader(value="X-API-Key", required=false) String xAPIKey, @Parameter(in = ParameterIn.HEADER, description = "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication." ,schema=@Schema()) @RequestHeader(value="X-User-Bearer", required=false) String xUserBearer, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's identifier to the server." ,schema=@Schema()) @RequestHeader(value="X-Client-Id", required=false) String xClientId, @Parameter(in = ParameterIn.HEADER, description = "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." ,schema=@Schema()) @RequestHeader(value="X-Content-Hash", required=false) String xContentHash, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-1", required=false) String xUserCredential1, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-2", required=false) String xUserCredential2, @Parameter(in = ParameterIn.HEADER, description = "String containing the channel that was used to originate the request. For example USSD, Web, App." ,schema=@Schema()) @RequestHeader(value="X-Channel", required=false) String xChannel, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." ,schema=@Schema(allowableValues={ "lei", "swiftbic", "organisationid" } +)) @RequestHeader(value="X-Account-Holding-Institution-Identifier-Type", required=false) String xAccountHoldingInstitutionIdentifierType, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." ,schema=@Schema()) @RequestHeader(value="X-Account-Holding-Institution-Identifier", required=false) String xAccountHoldingInstitutionIdentifier, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to uniquely identify the request. Must be supplied as a UUID." ,schema=@Schema()) @RequestHeader(value="X-CorrelationID", required=false) String xCorrelationID, @Parameter(in = ParameterIn.HEADER, description = "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." ,schema=@Schema()) @RequestHeader(value="X-Callback-URL", required=false) String xCallbackURL); + + + @Operation(summary = "View Account Statements", description = "The Statement Entries API enables generic representations of transactions to be returned. Typically, the returned representations are used for the purposes of presenting a statement to the account holder. In order to return a statement, an account must be specified.", tags={ "Accounts" }) + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Represent a list of Statement Entries", content = @Content(mediaType = "application/json", array = @ArraySchema(schema = @Schema(implementation = ResponseStatementEntries.class)))), + + @ApiResponse(responseCode = "400", description = "Represents an Error Caused by the Violation of a Business Rule", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "401", description = "Represents an Error Caused by an Authorisation Failure", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "404", description = "Represents an Error Caused by a Failure to Identify the Target Resource", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "500", description = "Represents an Error Caused by a General Server-Side Issue", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "503", description = "Represents an Error Caused by System Unavailability", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))) }) + @RequestMapping(value = "/accounts/{accountId}/statemententries", + produces = { "application/json" }, + method = RequestMethod.GET) + ResponseEntity> accountsAccountIdStatemententriesGET(@Pattern(regexp="^((accountcategory|bankaccountno|accountrank|identityalias|iban|accountid|msisdn|swiftbic|sortcode|organisationid|username|walletid|linkref|consumerno|serviceprovider|storeid|bankname|bankaccounttitle|emailaddress|mandatereference)@([^$\\n]+))(\\$(accountcategory|bankaccountno|accountrank|identityalias|iban|accountid|msisdn|swiftbic|sortcode|organisationid|username|walletid|linkref|consumerno|serviceprovider|storeid|bankname|bankaccounttitle|emailaddress|mandatereference)@([^$\\n]+)){0,2}$") @Parameter(in = ParameterIn.PATH, description = "Path variable to uniquely identify an account. Up to three account identifiers can be supplied. Identifiers are delimited by $ and values are delimited by @. Example: organisationid@1234$accountid@3333. Valid account identifiers are accountcategory, bankaccountno, accountrank, identityalias, iban, accountid, msisdn, swiftbic, sortcode, organisationid, username, walletid, linkref, consumerno, serviceprovider, storeid, bankname, bankaccounttitle, emailaddress, mandatereference.", required=true, schema=@Schema()) @PathVariable("accountId") String accountId, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." ,schema=@Schema()) @RequestHeader(value="X-Date", required=false) OffsetDateTime xDate, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's API key to the server." ,schema=@Schema()) @RequestHeader(value="X-API-Key", required=false) String xAPIKey, @Parameter(in = ParameterIn.HEADER, description = "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication." ,schema=@Schema()) @RequestHeader(value="X-User-Bearer", required=false) String xUserBearer, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's identifier to the server." ,schema=@Schema()) @RequestHeader(value="X-Client-Id", required=false) String xClientId, @Parameter(in = ParameterIn.HEADER, description = "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." ,schema=@Schema()) @RequestHeader(value="X-Content-Hash", required=false) String xContentHash, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-1", required=false) String xUserCredential1, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-2", required=false) String xUserCredential2, @Parameter(in = ParameterIn.HEADER, description = "String containing the channel that was used to originate the request. For example USSD, Web, App." ,schema=@Schema()) @RequestHeader(value="X-Channel", required=false) String xChannel, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." ,schema=@Schema(allowableValues={ "lei", "swiftbic", "organisationid" } +)) @RequestHeader(value="X-Account-Holding-Institution-Identifier-Type", required=false) String xAccountHoldingInstitutionIdentifierType, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." ,schema=@Schema()) @RequestHeader(value="X-Account-Holding-Institution-Identifier", required=false) String xAccountHoldingInstitutionIdentifier, @Parameter(in = ParameterIn.QUERY, description = "Supports pagination. If this is not supplied, then the server will apply a limit of 50 records returned for each request." ,schema=@Schema()) @Valid @RequestParam(value = "limit", required = false) Integer limit, @Parameter(in = ParameterIn.QUERY, description = "Supports pagination. This value will indicate the cursor position from where to retrieve the set of records. For example, a limit of 50 and offset of 10 will return records 11 to 60." ,schema=@Schema()) @Valid @RequestParam(value = "offset", required = false) Integer offset, @Parameter(in = ParameterIn.QUERY, description = "Indicates the minimum creation date for which records should be returned." ,schema=@Schema()) @Valid @RequestParam(value = "fromDateTime", required = false) OffsetDateTime fromDateTime, @Parameter(in = ParameterIn.QUERY, description = "Indicates the maximum creation date for which records should be returned." ,schema=@Schema()) @Valid @RequestParam(value = "toDateTime", required = false) OffsetDateTime toDateTime, @Size(max=256) @Parameter(in = ParameterIn.QUERY, description = "Query variable to uniquely identify the transaction status." ,schema=@Schema()) @Valid @RequestParam(value = "transactionStatus", required = false) String transactionStatus, @Size(max=256) @Parameter(in = ParameterIn.QUERY, description = "Query parameter to to identify the display type of the statement entries to be returned." ,schema=@Schema()) @Valid @RequestParam(value = "displayType", required = false) String displayType); + + + @Operation(summary = "View Account Status", description = "This endpoint returns the current status of an account. This API accepts multiple identifiers", tags={ "Accounts" }) + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Represents an Account Status response", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ResponseAccountStatus.class))), + + @ApiResponse(responseCode = "400", description = "Represents an Error Caused by the Violation of a Business Rule", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "401", description = "Represents an Error Caused by an Authorisation Failure", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "404", description = "Represents an Error Caused by a Failure to Identify the Target Resource", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "500", description = "Represents an Error Caused by a General Server-Side Issue", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "503", description = "Represents an Error Caused by System Unavailability", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))) }) + @RequestMapping(value = "/accounts/{accountId}/status", + produces = { "application/json" }, + method = RequestMethod.GET) + ResponseEntity accountsAccountIdStatusGET(@Pattern(regexp="^((accountcategory|bankaccountno|accountrank|identityalias|iban|accountid|msisdn|swiftbic|sortcode|organisationid|username|walletid|linkref|consumerno|serviceprovider|storeid|bankname|bankaccounttitle|emailaddress|mandatereference)@([^$\\n]+))(\\$(accountcategory|bankaccountno|accountrank|identityalias|iban|accountid|msisdn|swiftbic|sortcode|organisationid|username|walletid|linkref|consumerno|serviceprovider|storeid|bankname|bankaccounttitle|emailaddress|mandatereference)@([^$\\n]+)){0,2}$") @Parameter(in = ParameterIn.PATH, description = "Path variable to uniquely identify an account. Up to three account identifiers can be supplied. Identifiers are delimited by $ and values are delimited by @. Example: organisationid@1234$accountid@3333. Valid account identifiers are accountcategory, bankaccountno, accountrank, identityalias, iban, accountid, msisdn, swiftbic, sortcode, organisationid, username, walletid, linkref, consumerno, serviceprovider, storeid, bankname, bankaccounttitle, emailaddress, mandatereference.", required=true, schema=@Schema()) @PathVariable("accountId") String accountId, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." ,schema=@Schema()) @RequestHeader(value="X-Date", required=false) OffsetDateTime xDate, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's API key to the server." ,schema=@Schema()) @RequestHeader(value="X-API-Key", required=false) String xAPIKey, @Parameter(in = ParameterIn.HEADER, description = "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication." ,schema=@Schema()) @RequestHeader(value="X-User-Bearer", required=false) String xUserBearer, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's identifier to the server." ,schema=@Schema()) @RequestHeader(value="X-Client-Id", required=false) String xClientId, @Parameter(in = ParameterIn.HEADER, description = "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." ,schema=@Schema()) @RequestHeader(value="X-Content-Hash", required=false) String xContentHash, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-1", required=false) String xUserCredential1, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-2", required=false) String xUserCredential2, @Parameter(in = ParameterIn.HEADER, description = "String containing the channel that was used to originate the request. For example USSD, Web, App." ,schema=@Schema()) @RequestHeader(value="X-Channel", required=false) String xChannel, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." ,schema=@Schema(allowableValues={ "lei", "swiftbic", "organisationid" } +)) @RequestHeader(value="X-Account-Holding-Institution-Identifier-Type", required=false) String xAccountHoldingInstitutionIdentifierType, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." ,schema=@Schema()) @RequestHeader(value="X-Account-Holding-Institution-Identifier", required=false) String xAccountHoldingInstitutionIdentifier); + + + @Operation(summary = "View Account Specific Transaction", description = "This endpoint returns transactions linked to a specific account", tags={ "Accounts" }) + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Represent a list of Transactions", content = @Content(mediaType = "application/json", array = @ArraySchema(schema = @Schema(implementation = ResponseTransaction.class)))), + + @ApiResponse(responseCode = "400", description = "Represents an Error Caused by the Violation of a Business Rule", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "401", description = "Represents an Error Caused by an Authorisation Failure", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "404", description = "Represents an Error Caused by a Failure to Identify the Target Resource", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "500", description = "Represents an Error Caused by a General Server-Side Issue", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "503", description = "Represents an Error Caused by System Unavailability", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))) }) + @RequestMapping(value = "/accounts/{accountId}/transactions", + produces = { "application/json" }, + method = RequestMethod.GET) + ResponseEntity> accountsAccountIdTransactionsGET(@Pattern(regexp="^((accountcategory|bankaccountno|accountrank|identityalias|iban|accountid|msisdn|swiftbic|sortcode|organisationid|username|walletid|linkref|consumerno|serviceprovider|storeid|bankname|bankaccounttitle|emailaddress|mandatereference)@([^$\\n]+))(\\$(accountcategory|bankaccountno|accountrank|identityalias|iban|accountid|msisdn|swiftbic|sortcode|organisationid|username|walletid|linkref|consumerno|serviceprovider|storeid|bankname|bankaccounttitle|emailaddress|mandatereference)@([^$\\n]+)){0,2}$") @Parameter(in = ParameterIn.PATH, description = "Path variable to uniquely identify an account. Up to three account identifiers can be supplied. Identifiers are delimited by $ and values are delimited by @. Example: organisationid@1234$accountid@3333. Valid account identifiers are accountcategory, bankaccountno, accountrank, identityalias, iban, accountid, msisdn, swiftbic, sortcode, organisationid, username, walletid, linkref, consumerno, serviceprovider, storeid, bankname, bankaccounttitle, emailaddress, mandatereference.", required=true, schema=@Schema()) @PathVariable("accountId") String accountId, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." ,schema=@Schema()) @RequestHeader(value="X-Date", required=false) OffsetDateTime xDate, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's API key to the server." ,schema=@Schema()) @RequestHeader(value="X-API-Key", required=false) String xAPIKey, @Parameter(in = ParameterIn.HEADER, description = "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication." ,schema=@Schema()) @RequestHeader(value="X-User-Bearer", required=false) String xUserBearer, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's identifier to the server." ,schema=@Schema()) @RequestHeader(value="X-Client-Id", required=false) String xClientId, @Parameter(in = ParameterIn.HEADER, description = "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." ,schema=@Schema()) @RequestHeader(value="X-Content-Hash", required=false) String xContentHash, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-1", required=false) String xUserCredential1, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-2", required=false) String xUserCredential2, @Parameter(in = ParameterIn.HEADER, description = "String containing the channel that was used to originate the request. For example USSD, Web, App." ,schema=@Schema()) @RequestHeader(value="X-Channel", required=false) String xChannel, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." ,schema=@Schema(allowableValues={ "lei", "swiftbic", "organisationid" } +)) @RequestHeader(value="X-Account-Holding-Institution-Identifier-Type", required=false) String xAccountHoldingInstitutionIdentifierType, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." ,schema=@Schema()) @RequestHeader(value="X-Account-Holding-Institution-Identifier", required=false) String xAccountHoldingInstitutionIdentifier, @Parameter(in = ParameterIn.QUERY, description = "Supports pagination. If this is not supplied, then the server will apply a limit of 50 records returned for each request." ,schema=@Schema()) @Valid @RequestParam(value = "limit", required = false) Integer limit, @Parameter(in = ParameterIn.QUERY, description = "Supports pagination. This value will indicate the cursor position from where to retrieve the set of records. For example, a limit of 50 and offset of 10 will return records 11 to 60." ,schema=@Schema()) @Valid @RequestParam(value = "offset", required = false) Integer offset, @Parameter(in = ParameterIn.QUERY, description = "Indicates the minimum creation date for which records should be returned." ,schema=@Schema()) @Valid @RequestParam(value = "fromDateTime", required = false) OffsetDateTime fromDateTime, @Parameter(in = ParameterIn.QUERY, description = "Indicates the maximum creation date for which records should be returned." ,schema=@Schema()) @Valid @RequestParam(value = "toDateTime", required = false) OffsetDateTime toDateTime, @Size(max=256) @Parameter(in = ParameterIn.QUERY, description = "Query variable to uniquely identify the transaction status." ,schema=@Schema()) @Valid @RequestParam(value = "transactionStatus", required = false) String transactionStatus, @Parameter(in = ParameterIn.QUERY, description = "Identifies the type of transaction." ,schema=@Schema(allowableValues={ "billpay", "deposit", "disbursement", "transfer", "merchantpay", "inttransfer", "adjustment", "reversal", "withdrawal" } +)) @Valid @RequestParam(value = "transactionType", required = false) String transactionType); + + + @Operation(summary = "View Account Balance", description = "This endpoint returns the balance of an account. As the account is not passed as a parameter, the account is assumed to be that of the calling client.", tags={ "Accounts" }) + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Represents an Account Balance response", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ResponseAccountBalance.class))), + + @ApiResponse(responseCode = "400", description = "Represents an Error Caused by the Violation of a Business Rule", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "401", description = "Represents an Error Caused by an Authorisation Failure", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "404", description = "Represents an Error Caused by a Failure to Identify the Target Resource", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "500", description = "Represents an Error Caused by a General Server-Side Issue", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "503", description = "Represents an Error Caused by System Unavailability", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))) }) + @RequestMapping(value = "/accounts/balance", + produces = { "application/json" }, + method = RequestMethod.GET) + ResponseEntity accountsBalanceGET(@Parameter(in = ParameterIn.HEADER, description = "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." ,schema=@Schema()) @RequestHeader(value="X-Date", required=false) OffsetDateTime xDate, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's API key to the server." ,schema=@Schema()) @RequestHeader(value="X-API-Key", required=false) String xAPIKey, @Parameter(in = ParameterIn.HEADER, description = "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication." ,schema=@Schema()) @RequestHeader(value="X-User-Bearer", required=false) String xUserBearer, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's identifier to the server." ,schema=@Schema()) @RequestHeader(value="X-Client-Id", required=false) String xClientId, @Parameter(in = ParameterIn.HEADER, description = "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." ,schema=@Schema()) @RequestHeader(value="X-Content-Hash", required=false) String xContentHash, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-1", required=false) String xUserCredential1, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-2", required=false) String xUserCredential2, @Parameter(in = ParameterIn.HEADER, description = "String containing the channel that was used to originate the request. For example USSD, Web, App." ,schema=@Schema()) @RequestHeader(value="X-Channel", required=false) String xChannel, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." ,schema=@Schema(allowableValues={ "lei", "swiftbic", "organisationid" } +)) @RequestHeader(value="X-Account-Holding-Institution-Identifier-Type", required=false) String xAccountHoldingInstitutionIdentifierType, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." ,schema=@Schema()) @RequestHeader(value="X-Account-Holding-Institution-Identifier", required=false) String xAccountHoldingInstitutionIdentifier); + + + @Operation(summary = "View Account Name", description = "This endpoint returns the name of an account holder.", tags={ "Accounts" }) + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Represents an Account Name response", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ResponseAccountName.class))), + + @ApiResponse(responseCode = "400", description = "Represents an Error Caused by the Violation of a Business Rule", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "401", description = "Represents an Error Caused by an Authorisation Failure", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "404", description = "Represents an Error Caused by a Failure to Identify the Target Resource", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "500", description = "Represents an Error Caused by a General Server-Side Issue", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "503", description = "Represents an Error Caused by System Unavailability", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))) }) + @RequestMapping(value = "/accounts/{identifierType}/{identifier}/accountname", + produces = { "application/json" }, + method = RequestMethod.GET) + ResponseEntity accountsIdentifierTypeIdentifierAccountnameGET(@Parameter(in = ParameterIn.PATH, description = "Path variable to specify the type of the identifier that is used to identify the account.", required=true, schema=@Schema(allowableValues={ "accountid", "msisdn", "walletid", "linkref", "consumerno", "serviceprovider", "storeid", "accountcategory", "bankaccountno", "accountrank", "identityalias", "iban", "swiftbic", "sortcode", "organisationid", "bankname", "bankaccounttitle", "username", "emailaddress", "mandatereference" } +)) @PathVariable("identifierType") String identifierType, @Size(min=1,max=256) @Parameter(in = ParameterIn.PATH, description = "Path variable that contains the account identifier.", required=true, schema=@Schema()) @PathVariable("identifier") String identifier, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." ,schema=@Schema()) @RequestHeader(value="X-Date", required=false) OffsetDateTime xDate, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's API key to the server." ,schema=@Schema()) @RequestHeader(value="X-API-Key", required=false) String xAPIKey, @Parameter(in = ParameterIn.HEADER, description = "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication." ,schema=@Schema()) @RequestHeader(value="X-User-Bearer", required=false) String xUserBearer, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's identifier to the server." ,schema=@Schema()) @RequestHeader(value="X-Client-Id", required=false) String xClientId, @Parameter(in = ParameterIn.HEADER, description = "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." ,schema=@Schema()) @RequestHeader(value="X-Content-Hash", required=false) String xContentHash, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-1", required=false) String xUserCredential1, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-2", required=false) String xUserCredential2, @Parameter(in = ParameterIn.HEADER, description = "String containing the channel that was used to originate the request. For example USSD, Web, App." ,schema=@Schema()) @RequestHeader(value="X-Channel", required=false) String xChannel, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." ,schema=@Schema(allowableValues={ "lei", "swiftbic", "organisationid" } +)) @RequestHeader(value="X-Account-Holding-Institution-Identifier-Type", required=false) String xAccountHoldingInstitutionIdentifierType, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." ,schema=@Schema()) @RequestHeader(value="X-Account-Holding-Institution-Identifier", required=false) String xAccountHoldingInstitutionIdentifier); + + + @Operation(summary = "View an Authorisation Code", description = "This endpoint returns a specific Authorisation Code linked to an account.", tags={ "Authorisation Codes" }) + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Represents an Authorisation Code response", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ResponseAuthorisationCode.class))), + + @ApiResponse(responseCode = "400", description = "Represents an Error Caused by the Violation of a Business Rule", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "401", description = "Represents an Error Caused by an Authorisation Failure", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "404", description = "Represents an Error Caused by a Failure to Identify the Target Resource", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "500", description = "Represents an Error Caused by a General Server-Side Issue", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "503", description = "Represents an Error Caused by System Unavailability", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))) }) + @RequestMapping(value = "/accounts/{identifierType}/{identifier}/authorisationcodes/{authorisationCode}", + produces = { "application/json" }, + method = RequestMethod.GET) + ResponseEntity accountsIdentifierTypeIdentifierAuthorisationCodesAuthorisationCodeGET(@Parameter(in = ParameterIn.PATH, description = "Path variable to specify the type of the identifier that is used to identify the account.", required=true, schema=@Schema(allowableValues={ "accountid", "msisdn", "walletid", "linkref", "consumerno", "serviceprovider", "storeid", "accountcategory", "bankaccountno", "accountrank", "identityalias", "iban", "swiftbic", "sortcode", "organisationid", "bankname", "bankaccounttitle", "username", "emailaddress", "mandatereference" } +)) @PathVariable("identifierType") String identifierType, @Size(min=1,max=256) @Parameter(in = ParameterIn.PATH, description = "Path variable that contains the account identifier.", required=true, schema=@Schema()) @PathVariable("identifier") String identifier, @Size(min=1,max=256) @Parameter(in = ParameterIn.PATH, description = "Path variable to uniquely identify an authorisation code.", required=true, schema=@Schema()) @PathVariable("authorisationCode") String authorisationCode, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." ,schema=@Schema()) @RequestHeader(value="X-Date", required=false) OffsetDateTime xDate, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's API key to the server." ,schema=@Schema()) @RequestHeader(value="X-API-Key", required=false) String xAPIKey, @Parameter(in = ParameterIn.HEADER, description = "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication." ,schema=@Schema()) @RequestHeader(value="X-User-Bearer", required=false) String xUserBearer, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's identifier to the server." ,schema=@Schema()) @RequestHeader(value="X-Client-Id", required=false) String xClientId, @Parameter(in = ParameterIn.HEADER, description = "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." ,schema=@Schema()) @RequestHeader(value="X-Content-Hash", required=false) String xContentHash, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-1", required=false) String xUserCredential1, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-2", required=false) String xUserCredential2, @Parameter(in = ParameterIn.HEADER, description = "String containing the channel that was used to originate the request. For example USSD, Web, App." ,schema=@Schema()) @RequestHeader(value="X-Channel", required=false) String xChannel, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." ,schema=@Schema(allowableValues={ "lei", "swiftbic", "organisationid" } +)) @RequestHeader(value="X-Account-Holding-Institution-Identifier-Type", required=false) String xAccountHoldingInstitutionIdentifierType, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." ,schema=@Schema()) @RequestHeader(value="X-Account-Holding-Institution-Identifier", required=false) String xAccountHoldingInstitutionIdentifier); + + + @Operation(summary = "Cancel an Authorisation Code", description = "This endpoint updates a specific Authorisation Code linked to an account. The only permissable modification is to set codeState to cancelled.", tags={ "Authorisation Codes" }) + @ApiResponses(value = { + @ApiResponse(responseCode = "202", description = "Represents an Asynchronous response", content = @Content(mediaType = "application/json", schema = @Schema(implementation = RequestStateObject.class))), + + @ApiResponse(responseCode = "204", description = "An empty response is returned for a synchronous successful patch."), + + @ApiResponse(responseCode = "400", description = "Represents an Error Caused by the Violation of a Business Rule", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "401", description = "Represents an Error Caused by an Authorisation Failure", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "404", description = "Represents an Error Caused by a Failure to Identify the Target Resource", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "500", description = "Represents an Error Caused by a General Server-Side Issue", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "503", description = "Represents an Error Caused by System Unavailability", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))) }) + @RequestMapping(value = "/accounts/{identifierType}/{identifier}/authorisationcodes/{authorisationCode}", + produces = { "application/json" }, + consumes = { "application/json" }, + method = RequestMethod.PATCH) + ResponseEntity accountsIdentifierTypeIdentifierAuthorisationCodesAuthorisationCodePATCH(@Parameter(in = ParameterIn.PATH, description = "Path variable to specify the type of the identifier that is used to identify the account.", required=true, schema=@Schema(allowableValues={ "accountid", "msisdn", "walletid", "linkref", "consumerno", "serviceprovider", "storeid", "accountcategory", "bankaccountno", "accountrank", "identityalias", "iban", "swiftbic", "sortcode", "organisationid", "bankname", "bankaccounttitle", "username", "emailaddress", "mandatereference" } +)) @PathVariable("identifierType") String identifierType, @Size(min=1,max=256) @Parameter(in = ParameterIn.PATH, description = "Path variable that contains the account identifier.", required=true, schema=@Schema()) @PathVariable("identifier") String identifier, @Size(min=1,max=256) @Parameter(in = ParameterIn.PATH, description = "Path variable to uniquely identify an authorisation code.", required=true, schema=@Schema()) @PathVariable("authorisationCode") String authorisationCode, @Parameter(in = ParameterIn.DEFAULT, description = "Represents the request body of a batch of generic Patch operation.", required=true, schema=@Schema()) @Valid @RequestBody List body, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." ,schema=@Schema()) @RequestHeader(value="X-Date", required=false) OffsetDateTime xDate, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's API key to the server." ,schema=@Schema()) @RequestHeader(value="X-API-Key", required=false) String xAPIKey, @Parameter(in = ParameterIn.HEADER, description = "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication." ,schema=@Schema()) @RequestHeader(value="X-User-Bearer", required=false) String xUserBearer, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's identifier to the server." ,schema=@Schema()) @RequestHeader(value="X-Client-Id", required=false) String xClientId, @Parameter(in = ParameterIn.HEADER, description = "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." ,schema=@Schema()) @RequestHeader(value="X-Content-Hash", required=false) String xContentHash, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-1", required=false) String xUserCredential1, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-2", required=false) String xUserCredential2, @Parameter(in = ParameterIn.HEADER, description = "String containing the channel that was used to originate the request. For example USSD, Web, App." ,schema=@Schema()) @RequestHeader(value="X-Channel", required=false) String xChannel, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." ,schema=@Schema(allowableValues={ "lei", "swiftbic", "organisationid" } +)) @RequestHeader(value="X-Account-Holding-Institution-Identifier-Type", required=false) String xAccountHoldingInstitutionIdentifierType, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." ,schema=@Schema()) @RequestHeader(value="X-Account-Holding-Institution-Identifier", required=false) String xAccountHoldingInstitutionIdentifier, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to uniquely identify the request. Must be supplied as a UUID." ,schema=@Schema()) @RequestHeader(value="X-CorrelationID", required=false) String xCorrelationID, @Parameter(in = ParameterIn.HEADER, description = "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." ,schema=@Schema()) @RequestHeader(value="X-Callback-URL", required=false) String xCallbackURL); + + + @Operation(summary = "View Authorisation Codes for a given account", description = "This endpoint allows allows a mobile money payer or payee to view authorisation codes for a given account.", tags={ "Authorisation Codes" }) + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Represents an authorisation codes response", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ResponseAuthorisationCode.class))), + + @ApiResponse(responseCode = "400", description = "Represents an Error Caused by the Violation of a Business Rule", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "401", description = "Represents an Error Caused by an Authorisation Failure", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "404", description = "Represents an Error Caused by a Failure to Identify the Target Resource", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "500", description = "Represents an Error Caused by a General Server-Side Issue", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "503", description = "Represents an Error Caused by System Unavailability", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))) }) + @RequestMapping(value = "/accounts/{identifierType}/{identifier}/authorisationcodes", + produces = { "application/json" }, + method = RequestMethod.GET) + ResponseEntity accountsIdentifierTypeIdentifierAuthorisationCodesGET(@Parameter(in = ParameterIn.PATH, description = "Path variable to specify the type of the identifier that is used to identify the account.", required=true, schema=@Schema(allowableValues={ "accountid", "msisdn", "walletid", "linkref", "consumerno", "serviceprovider", "storeid", "accountcategory", "bankaccountno", "accountrank", "identityalias", "iban", "swiftbic", "sortcode", "organisationid", "bankname", "bankaccounttitle", "username", "emailaddress", "mandatereference" } +)) @PathVariable("identifierType") String identifierType, @Size(min=1,max=256) @Parameter(in = ParameterIn.PATH, description = "Path variable that contains the account identifier.", required=true, schema=@Schema()) @PathVariable("identifier") String identifier, @NotNull @Size(max=256) @Parameter(in = ParameterIn.QUERY, description = "Allows returned records to be filtered on state of the authorisation code." ,required=true,schema=@Schema()) @Valid @RequestParam(value = "codeState", required = true) String codeState, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." ,schema=@Schema()) @RequestHeader(value="X-Date", required=false) OffsetDateTime xDate, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's API key to the server." ,schema=@Schema()) @RequestHeader(value="X-API-Key", required=false) String xAPIKey, @Parameter(in = ParameterIn.HEADER, description = "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication." ,schema=@Schema()) @RequestHeader(value="X-User-Bearer", required=false) String xUserBearer, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's identifier to the server." ,schema=@Schema()) @RequestHeader(value="X-Client-Id", required=false) String xClientId, @Parameter(in = ParameterIn.HEADER, description = "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." ,schema=@Schema()) @RequestHeader(value="X-Content-Hash", required=false) String xContentHash, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-1", required=false) String xUserCredential1, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-2", required=false) String xUserCredential2, @Parameter(in = ParameterIn.HEADER, description = "String containing the channel that was used to originate the request. For example USSD, Web, App." ,schema=@Schema()) @RequestHeader(value="X-Channel", required=false) String xChannel, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." ,schema=@Schema(allowableValues={ "lei", "swiftbic", "organisationid" } +)) @RequestHeader(value="X-Account-Holding-Institution-Identifier-Type", required=false) String xAccountHoldingInstitutionIdentifierType, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." ,schema=@Schema()) @RequestHeader(value="X-Account-Holding-Institution-Identifier", required=false) String xAccountHoldingInstitutionIdentifier, @Parameter(in = ParameterIn.QUERY, description = "Supports pagination. If this is not supplied, then the server will apply a limit of 50 records returned for each request." ,schema=@Schema()) @Valid @RequestParam(value = "limit", required = false) Integer limit, @Parameter(in = ParameterIn.QUERY, description = "Supports pagination. This value will indicate the cursor position from where to retrieve the set of records. For example, a limit of 50 and offset of 10 will return records 11 to 60." ,schema=@Schema()) @Valid @RequestParam(value = "offset", required = false) Integer offset, @Parameter(in = ParameterIn.QUERY, description = "Indicates the minimum creation date for which records should be returned." ,schema=@Schema()) @Valid @RequestParam(value = "fromDateTime", required = false) OffsetDateTime fromDateTime, @Parameter(in = ParameterIn.QUERY, description = "Indicates the maximum creation date for which records should be returned." ,schema=@Schema()) @Valid @RequestParam(value = "toDateTime", required = false) OffsetDateTime toDateTime); + + + @Operation(summary = "Create an Authorisation Code via an account identifier.", description = "This endpoint allows allows a mobile money payer or payee to generate a code which when presented to the other party, can be redeemed for an amount set by the payer or payee, depending upon the use case.", tags={ "Authorisation Codes" }) + @ApiResponses(value = { + @ApiResponse(responseCode = "201", description = "Represents an Authorisation Code response", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ResponseAuthorisationCode.class))), + + @ApiResponse(responseCode = "202", description = "Represents an Asynchronous response", content = @Content(mediaType = "application/json", schema = @Schema(implementation = RequestStateObject.class))), + + @ApiResponse(responseCode = "400", description = "Represents an Error Caused by the Violation of a Business Rule", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "401", description = "Represents an Error Caused by an Authorisation Failure", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "404", description = "Represents an Error Caused by a Failure to Identify the Target Resource", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "500", description = "Represents an Error Caused by a General Server-Side Issue", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "503", description = "Represents an Error Caused by System Unavailability", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))) }) + @RequestMapping(value = "/accounts/{identifierType}/{identifier}/authorisationcodes", + produces = { "application/json" }, + consumes = { "application/json" }, + method = RequestMethod.POST) + ResponseEntity accountsIdentifierTypeIdentifierAuthorisationCodesPOST(@Parameter(in = ParameterIn.PATH, description = "Path variable to specify the type of the identifier that is used to identify the account.", required=true, schema=@Schema(allowableValues={ "accountid", "msisdn", "walletid", "linkref", "consumerno", "serviceprovider", "storeid", "accountcategory", "bankaccountno", "accountrank", "identityalias", "iban", "swiftbic", "sortcode", "organisationid", "bankname", "bankaccounttitle", "username", "emailaddress", "mandatereference" } +)) @PathVariable("identifierType") String identifierType, @Size(min=1,max=256) @Parameter(in = ParameterIn.PATH, description = "Path variable that contains the account identifier.", required=true, schema=@Schema()) @PathVariable("identifier") String identifier, @Parameter(in = ParameterIn.DEFAULT, description = "Represents the request body of an Authorisation Code.", required=true, schema=@Schema()) @Valid @RequestBody RequestAuthorisationCode body, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." ,schema=@Schema()) @RequestHeader(value="X-Date", required=false) OffsetDateTime xDate, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to uniquely identify the request. Must be supplied as a UUID." ,schema=@Schema()) @RequestHeader(value="X-CorrelationID", required=false) String xCorrelationID, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's API key to the server." ,schema=@Schema()) @RequestHeader(value="X-API-Key", required=false) String xAPIKey, @Parameter(in = ParameterIn.HEADER, description = "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication." ,schema=@Schema()) @RequestHeader(value="X-User-Bearer", required=false) String xUserBearer, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's identifier to the server." ,schema=@Schema()) @RequestHeader(value="X-Client-Id", required=false) String xClientId, @Parameter(in = ParameterIn.HEADER, description = "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." ,schema=@Schema()) @RequestHeader(value="X-Content-Hash", required=false) String xContentHash, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-1", required=false) String xUserCredential1, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-2", required=false) String xUserCredential2, @Parameter(in = ParameterIn.HEADER, description = "String containing the channel that was used to originate the request. For example USSD, Web, App." ,schema=@Schema()) @RequestHeader(value="X-Channel", required=false) String xChannel, @Parameter(in = ParameterIn.HEADER, description = "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." ,schema=@Schema()) @RequestHeader(value="X-Callback-URL", required=false) String xCallbackURL, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." ,schema=@Schema(allowableValues={ "lei", "swiftbic", "organisationid" } +)) @RequestHeader(value="X-Account-Holding-Institution-Identifier-Type", required=false) String xAccountHoldingInstitutionIdentifierType, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." ,schema=@Schema()) @RequestHeader(value="X-Account-Holding-Institution-Identifier", required=false) String xAccountHoldingInstitutionIdentifier); + + + @Operation(summary = "View Account Balance", description = "This endpoint returns the balance of an account.", tags={ "Accounts" }) + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Represents an Account Balance response", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ResponseAccountBalance.class))), + + @ApiResponse(responseCode = "400", description = "Represents an Error Caused by the Violation of a Business Rule", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "401", description = "Represents an Error Caused by an Authorisation Failure", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "404", description = "Represents an Error Caused by a Failure to Identify the Target Resource", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "500", description = "Represents an Error Caused by a General Server-Side Issue", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "503", description = "Represents an Error Caused by System Unavailability", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))) }) + @RequestMapping(value = "/accounts/{identifierType}/{identifier}/balance", + produces = { "application/json" }, + method = RequestMethod.GET) + ResponseEntity accountsIdentifierTypeIdentifierBalanceGET(@Parameter(in = ParameterIn.PATH, description = "Path variable to specify the type of the identifier that is used to identify the account.", required=true, schema=@Schema(allowableValues={ "accountid", "msisdn", "walletid", "linkref", "consumerno", "serviceprovider", "storeid", "accountcategory", "bankaccountno", "accountrank", "identityalias", "iban", "swiftbic", "sortcode", "organisationid", "bankname", "bankaccounttitle", "username", "emailaddress", "mandatereference" } +)) @PathVariable("identifierType") String identifierType, @Size(min=1,max=256) @Parameter(in = ParameterIn.PATH, description = "Path variable that contains the account identifier.", required=true, schema=@Schema()) @PathVariable("identifier") String identifier, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." ,schema=@Schema()) @RequestHeader(value="X-Date", required=false) OffsetDateTime xDate, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's API key to the server." ,schema=@Schema()) @RequestHeader(value="X-API-Key", required=false) String xAPIKey, @Parameter(in = ParameterIn.HEADER, description = "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication." ,schema=@Schema()) @RequestHeader(value="X-User-Bearer", required=false) String xUserBearer, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's identifier to the server." ,schema=@Schema()) @RequestHeader(value="X-Client-Id", required=false) String xClientId, @Parameter(in = ParameterIn.HEADER, description = "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." ,schema=@Schema()) @RequestHeader(value="X-Content-Hash", required=false) String xContentHash, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-1", required=false) String xUserCredential1, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-2", required=false) String xUserCredential2, @Parameter(in = ParameterIn.HEADER, description = "String containing the channel that was used to originate the request. For example USSD, Web, App." ,schema=@Schema()) @RequestHeader(value="X-Channel", required=false) String xChannel, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." ,schema=@Schema(allowableValues={ "lei", "swiftbic", "organisationid" } +)) @RequestHeader(value="X-Account-Holding-Institution-Identifier-Type", required=false) String xAccountHoldingInstitutionIdentifierType, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." ,schema=@Schema()) @RequestHeader(value="X-Account-Holding-Institution-Identifier", required=false) String xAccountHoldingInstitutionIdentifier); + + + @Operation(summary = "View Bill Companies", description = "This Bill Companies API is used to return a list of Service Providers that accept Bill Payments for a given account.", tags={ "Bills" }) + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Represent a list of Bill Companies", content = @Content(mediaType = "application/json", array = @ArraySchema(schema = @Schema(implementation = ResponseBillCompanies.class)))), + + @ApiResponse(responseCode = "400", description = "Represents an Error Caused by the Violation of a Business Rule", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "401", description = "Represents an Error Caused by an Authorisation Failure", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "404", description = "Represents an Error Caused by a Failure to Identify the Target Resource", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "500", description = "Represents an Error Caused by a General Server-Side Issue", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "503", description = "Represents an Error Caused by System Unavailability", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))) }) + @RequestMapping(value = "/accounts/{identifierType}/{identifier}/billcompanies", + produces = { "application/json" }, + method = RequestMethod.GET) + ResponseEntity> accountsIdentifierTypeIdentifierBillCompaniesGET(@Parameter(in = ParameterIn.PATH, description = "Path variable to specify the type of the identifier that is used to identify the account.", required=true, schema=@Schema(allowableValues={ "accountid", "msisdn", "walletid", "linkref", "consumerno", "serviceprovider", "storeid", "accountcategory", "bankaccountno", "accountrank", "identityalias", "iban", "swiftbic", "sortcode", "organisationid", "bankname", "bankaccounttitle", "username", "emailaddress", "mandatereference" } +)) @PathVariable("identifierType") String identifierType, @Size(min=1,max=256) @Parameter(in = ParameterIn.PATH, description = "Path variable that contains the account identifier.", required=true, schema=@Schema()) @PathVariable("identifier") String identifier, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." ,schema=@Schema()) @RequestHeader(value="X-Date", required=false) OffsetDateTime xDate, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's API key to the server." ,schema=@Schema()) @RequestHeader(value="X-API-Key", required=false) String xAPIKey, @Parameter(in = ParameterIn.HEADER, description = "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication." ,schema=@Schema()) @RequestHeader(value="X-User-Bearer", required=false) String xUserBearer, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's identifier to the server." ,schema=@Schema()) @RequestHeader(value="X-Client-Id", required=false) String xClientId, @Parameter(in = ParameterIn.HEADER, description = "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." ,schema=@Schema()) @RequestHeader(value="X-Content-Hash", required=false) String xContentHash, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-1", required=false) String xUserCredential1, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-2", required=false) String xUserCredential2, @Parameter(in = ParameterIn.HEADER, description = "String containing the channel that was used to originate the request. For example USSD, Web, App." ,schema=@Schema()) @RequestHeader(value="X-Channel", required=false) String xChannel, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." ,schema=@Schema(allowableValues={ "lei", "swiftbic", "organisationid" } +)) @RequestHeader(value="X-Account-Holding-Institution-Identifier-Type", required=false) String xAccountHoldingInstitutionIdentifierType, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." ,schema=@Schema()) @RequestHeader(value="X-Account-Holding-Institution-Identifier", required=false) String xAccountHoldingInstitutionIdentifier, @Parameter(in = ParameterIn.QUERY, description = "Supports pagination. If this is not supplied, then the server will apply a limit of 50 records returned for each request." ,schema=@Schema()) @Valid @RequestParam(value = "limit", required = false) Integer limit, @Parameter(in = ParameterIn.QUERY, description = "Supports pagination. This value will indicate the cursor position from where to retrieve the set of records. For example, a limit of 50 and offset of 10 will return records 11 to 60." ,schema=@Schema()) @Valid @RequestParam(value = "offset", required = false) Integer offset); + + + @Operation(summary = "View Payments for a Bill without a Bill Reference", description = "This endpoint allows for bill payments for a specific account to be returned", tags={ "Bills" }) + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Represents a list of Bill Payments", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ResponseBillPayment2.class))), + + @ApiResponse(responseCode = "400", description = "Represents an Error Caused by the Violation of a Business Rule", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "401", description = "Represents an Error Caused by an Authorisation Failure", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "404", description = "Represents an Error Caused by a Failure to Identify the Target Resource", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "500", description = "Represents an Error Caused by a General Server-Side Issue", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "503", description = "Represents an Error Caused by System Unavailability", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))) }) + @RequestMapping(value = "/accounts/{identifierType}/{identifier}/bills/payments", + produces = { "application/json" }, + method = RequestMethod.GET) + ResponseEntity accountsIdentifierTypeIdentifierBillsBillPaymentsGET(@Parameter(in = ParameterIn.PATH, description = "Path variable to specify the type of the identifier that is used to identify the account.", required=true, schema=@Schema(allowableValues={ "accountid", "msisdn", "walletid", "linkref", "consumerno", "serviceprovider", "storeid", "accountcategory", "bankaccountno", "accountrank", "identityalias", "iban", "swiftbic", "sortcode", "organisationid", "bankname", "bankaccounttitle", "username", "emailaddress", "mandatereference" } +)) @PathVariable("identifierType") String identifierType, @Size(min=1,max=256) @Parameter(in = ParameterIn.PATH, description = "Path variable that contains the account identifier.", required=true, schema=@Schema()) @PathVariable("identifier") String identifier, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." ,schema=@Schema()) @RequestHeader(value="X-Date", required=false) OffsetDateTime xDate, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's API key to the server." ,schema=@Schema()) @RequestHeader(value="X-API-Key", required=false) String xAPIKey, @Parameter(in = ParameterIn.HEADER, description = "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication." ,schema=@Schema()) @RequestHeader(value="X-User-Bearer", required=false) String xUserBearer, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's identifier to the server." ,schema=@Schema()) @RequestHeader(value="X-Client-Id", required=false) String xClientId, @Parameter(in = ParameterIn.HEADER, description = "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." ,schema=@Schema()) @RequestHeader(value="X-Content-Hash", required=false) String xContentHash, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-1", required=false) String xUserCredential1, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-2", required=false) String xUserCredential2, @Parameter(in = ParameterIn.HEADER, description = "String containing the channel that was used to originate the request. For example USSD, Web, App." ,schema=@Schema()) @RequestHeader(value="X-Channel", required=false) String xChannel, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." ,schema=@Schema(allowableValues={ "lei", "swiftbic", "organisationid" } +)) @RequestHeader(value="X-Account-Holding-Institution-Identifier-Type", required=false) String xAccountHoldingInstitutionIdentifierType, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." ,schema=@Schema()) @RequestHeader(value="X-Account-Holding-Institution-Identifier", required=false) String xAccountHoldingInstitutionIdentifier, @Parameter(in = ParameterIn.QUERY, description = "Supports pagination. If this is not supplied, then the server will apply a limit of 50 records returned for each request." ,schema=@Schema()) @Valid @RequestParam(value = "limit", required = false) Integer limit, @Parameter(in = ParameterIn.QUERY, description = "Supports pagination. This value will indicate the cursor position from where to retrieve the set of records. For example, a limit of 50 and offset of 10 will return records 11 to 60." ,schema=@Schema()) @Valid @RequestParam(value = "offset", required = false) Integer offset, @Parameter(in = ParameterIn.QUERY, description = "Indicates the minimum creation date for which records should be returned." ,schema=@Schema()) @Valid @RequestParam(value = "fromDateTime", required = false) OffsetDateTime fromDateTime, @Parameter(in = ParameterIn.QUERY, description = "Indicates the maximum creation date for which records should be returned." ,schema=@Schema()) @Valid @RequestParam(value = "toDateTime", required = false) OffsetDateTime toDateTime); + + + @Operation(summary = "Create A Bill Payment without a Bill Reference", description = "Provided with a valid object representation, this endpoint allows for a new bill payment to be created for a specific account.", tags={ "Bills" }) + @ApiResponses(value = { + @ApiResponse(responseCode = "201", description = "Represents a Bill Payment response", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ResponseBillPayment2.class))), + + @ApiResponse(responseCode = "202", description = "Represents an Asynchronous response", content = @Content(mediaType = "application/json", schema = @Schema(implementation = RequestStateObject.class))), + + @ApiResponse(responseCode = "400", description = "Represents an Error Caused by the Violation of a Business Rule", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "401", description = "Represents an Error Caused by an Authorisation Failure", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "404", description = "Represents an Error Caused by a Failure to Identify the Target Resource", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "500", description = "Represents an Error Caused by a General Server-Side Issue", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "503", description = "Represents an Error Caused by System Unavailability", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))) }) + @RequestMapping(value = "/accounts/{identifierType}/{identifier}/bills/payments", + produces = { "application/json" }, + consumes = { "application/json" }, + method = RequestMethod.POST) + ResponseEntity accountsIdentifierTypeIdentifierBillsBillPaymentsPOST(@Parameter(in = ParameterIn.PATH, description = "Path variable to specify the type of the identifier that is used to identify the account.", required=true, schema=@Schema(allowableValues={ "accountid", "msisdn", "walletid", "linkref", "consumerno", "serviceprovider", "storeid", "accountcategory", "bankaccountno", "accountrank", "identityalias", "iban", "swiftbic", "sortcode", "organisationid", "bankname", "bankaccounttitle", "username", "emailaddress", "mandatereference" } +)) @PathVariable("identifierType") String identifierType, @Size(min=1,max=256) @Parameter(in = ParameterIn.PATH, description = "Path variable that contains the account identifier.", required=true, schema=@Schema()) @PathVariable("identifier") String identifier, @Parameter(in = ParameterIn.DEFAULT, description = "Represents the request body of a bill payment.", required=true, schema=@Schema()) @Valid @RequestBody RequestBillPayment2 body, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." ,schema=@Schema()) @RequestHeader(value="X-Date", required=false) OffsetDateTime xDate, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to uniquely identify the request. Must be supplied as a UUID." ,schema=@Schema()) @RequestHeader(value="X-CorrelationID", required=false) String xCorrelationID, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's API key to the server." ,schema=@Schema()) @RequestHeader(value="X-API-Key", required=false) String xAPIKey, @Parameter(in = ParameterIn.HEADER, description = "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication." ,schema=@Schema()) @RequestHeader(value="X-User-Bearer", required=false) String xUserBearer, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's identifier to the server." ,schema=@Schema()) @RequestHeader(value="X-Client-Id", required=false) String xClientId, @Parameter(in = ParameterIn.HEADER, description = "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." ,schema=@Schema()) @RequestHeader(value="X-Content-Hash", required=false) String xContentHash, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-1", required=false) String xUserCredential1, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-2", required=false) String xUserCredential2, @Parameter(in = ParameterIn.HEADER, description = "String containing the channel that was used to originate the request. For example USSD, Web, App." ,schema=@Schema()) @RequestHeader(value="X-Channel", required=false) String xChannel, @Parameter(in = ParameterIn.HEADER, description = "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." ,schema=@Schema()) @RequestHeader(value="X-Callback-URL", required=false) String xCallbackURL, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." ,schema=@Schema(allowableValues={ "lei", "swiftbic", "organisationid" } +)) @RequestHeader(value="X-Account-Holding-Institution-Identifier-Type", required=false) String xAccountHoldingInstitutionIdentifierType, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." ,schema=@Schema()) @RequestHeader(value="X-Account-Holding-Institution-Identifier", required=false) String xAccountHoldingInstitutionIdentifier); + + + @Operation(summary = "View Payments for a Bill", description = "This endpoint allows for bill payments for a specific account to be returned", tags={ "Bills" }) + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Represents a list of Bill Payments", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ResponseBillPayment.class))), + + @ApiResponse(responseCode = "400", description = "Represents an Error Caused by the Violation of a Business Rule", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "401", description = "Represents an Error Caused by an Authorisation Failure", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "404", description = "Represents an Error Caused by a Failure to Identify the Target Resource", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "500", description = "Represents an Error Caused by a General Server-Side Issue", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "503", description = "Represents an Error Caused by System Unavailability", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))) }) + @RequestMapping(value = "/accounts/{identifierType}/{identifier}/bills/{billReference}/payments", + produces = { "application/json" }, + method = RequestMethod.GET) + ResponseEntity accountsIdentifierTypeIdentifierBillsBillReferencePaymentsGET(@Parameter(in = ParameterIn.PATH, description = "Path variable to specify the type of the identifier that is used to identify the account.", required=true, schema=@Schema(allowableValues={ "accountid", "msisdn", "walletid", "linkref", "consumerno", "serviceprovider", "storeid", "accountcategory", "bankaccountno", "accountrank", "identityalias", "iban", "swiftbic", "sortcode", "organisationid", "bankname", "bankaccounttitle", "username", "emailaddress", "mandatereference" } +)) @PathVariable("identifierType") String identifierType, @Size(min=1,max=256) @Parameter(in = ParameterIn.PATH, description = "Path variable that contains the account identifier.", required=true, schema=@Schema()) @PathVariable("identifier") String identifier, @Size(min=1,max=256) @Parameter(in = ParameterIn.PATH, description = "Path variable to uniquely identify a bill.", required=true, schema=@Schema()) @PathVariable("billReference") String billReference, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." ,schema=@Schema()) @RequestHeader(value="X-Date", required=false) OffsetDateTime xDate, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's API key to the server." ,schema=@Schema()) @RequestHeader(value="X-API-Key", required=false) String xAPIKey, @Parameter(in = ParameterIn.HEADER, description = "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication." ,schema=@Schema()) @RequestHeader(value="X-User-Bearer", required=false) String xUserBearer, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's identifier to the server." ,schema=@Schema()) @RequestHeader(value="X-Client-Id", required=false) String xClientId, @Parameter(in = ParameterIn.HEADER, description = "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." ,schema=@Schema()) @RequestHeader(value="X-Content-Hash", required=false) String xContentHash, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-1", required=false) String xUserCredential1, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-2", required=false) String xUserCredential2, @Parameter(in = ParameterIn.HEADER, description = "String containing the channel that was used to originate the request. For example USSD, Web, App." ,schema=@Schema()) @RequestHeader(value="X-Channel", required=false) String xChannel, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." ,schema=@Schema(allowableValues={ "lei", "swiftbic", "organisationid" } +)) @RequestHeader(value="X-Account-Holding-Institution-Identifier-Type", required=false) String xAccountHoldingInstitutionIdentifierType, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." ,schema=@Schema()) @RequestHeader(value="X-Account-Holding-Institution-Identifier", required=false) String xAccountHoldingInstitutionIdentifier, @Parameter(in = ParameterIn.QUERY, description = "Supports pagination. If this is not supplied, then the server will apply a limit of 50 records returned for each request." ,schema=@Schema()) @Valid @RequestParam(value = "limit", required = false) Integer limit, @Parameter(in = ParameterIn.QUERY, description = "Supports pagination. This value will indicate the cursor position from where to retrieve the set of records. For example, a limit of 50 and offset of 10 will return records 11 to 60." ,schema=@Schema()) @Valid @RequestParam(value = "offset", required = false) Integer offset, @Parameter(in = ParameterIn.QUERY, description = "Indicates the minimum creation date for which records should be returned." ,schema=@Schema()) @Valid @RequestParam(value = "fromDateTime", required = false) OffsetDateTime fromDateTime, @Parameter(in = ParameterIn.QUERY, description = "Indicates the maximum creation date for which records should be returned." ,schema=@Schema()) @Valid @RequestParam(value = "toDateTime", required = false) OffsetDateTime toDateTime); + + + @Operation(summary = "Create A Bill Payment", description = "Provided with a valid object representation, this endpoint allows for a new bill payment to be created for a specific account.", tags={ "Bills" }) + @ApiResponses(value = { + @ApiResponse(responseCode = "201", description = "Represents a Bill Payment response", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ResponseBillPayment.class))), + + @ApiResponse(responseCode = "202", description = "Represents an Asynchronous response", content = @Content(mediaType = "application/json", schema = @Schema(implementation = RequestStateObject.class))), + + @ApiResponse(responseCode = "400", description = "Represents an Error Caused by the Violation of a Business Rule", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "401", description = "Represents an Error Caused by an Authorisation Failure", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "404", description = "Represents an Error Caused by a Failure to Identify the Target Resource", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "500", description = "Represents an Error Caused by a General Server-Side Issue", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "503", description = "Represents an Error Caused by System Unavailability", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))) }) + @RequestMapping(value = "/accounts/{identifierType}/{identifier}/bills/{billReference}/payments", + produces = { "application/json" }, + consumes = { "application/json" }, + method = RequestMethod.POST) + ResponseEntity accountsIdentifierTypeIdentifierBillsBillReferencePaymentsPOST(@Parameter(in = ParameterIn.PATH, description = "Path variable to specify the type of the identifier that is used to identify the account.", required=true, schema=@Schema(allowableValues={ "accountid", "msisdn", "walletid", "linkref", "consumerno", "serviceprovider", "storeid", "accountcategory", "bankaccountno", "accountrank", "identityalias", "iban", "swiftbic", "sortcode", "organisationid", "bankname", "bankaccounttitle", "username", "emailaddress", "mandatereference" } +)) @PathVariable("identifierType") String identifierType, @Size(min=1,max=256) @Parameter(in = ParameterIn.PATH, description = "Path variable that contains the account identifier.", required=true, schema=@Schema()) @PathVariable("identifier") String identifier, @Size(min=1,max=256) @Parameter(in = ParameterIn.PATH, description = "Path variable to uniquely identify a bill.", required=true, schema=@Schema()) @PathVariable("billReference") String billReference, @Parameter(in = ParameterIn.DEFAULT, description = "Represents the request body of a bill payment.", required=true, schema=@Schema()) @Valid @RequestBody RequestBillPayment body, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." ,schema=@Schema()) @RequestHeader(value="X-Date", required=false) OffsetDateTime xDate, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to uniquely identify the request. Must be supplied as a UUID." ,schema=@Schema()) @RequestHeader(value="X-CorrelationID", required=false) String xCorrelationID, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's API key to the server." ,schema=@Schema()) @RequestHeader(value="X-API-Key", required=false) String xAPIKey, @Parameter(in = ParameterIn.HEADER, description = "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication." ,schema=@Schema()) @RequestHeader(value="X-User-Bearer", required=false) String xUserBearer, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's identifier to the server." ,schema=@Schema()) @RequestHeader(value="X-Client-Id", required=false) String xClientId, @Parameter(in = ParameterIn.HEADER, description = "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." ,schema=@Schema()) @RequestHeader(value="X-Content-Hash", required=false) String xContentHash, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-1", required=false) String xUserCredential1, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-2", required=false) String xUserCredential2, @Parameter(in = ParameterIn.HEADER, description = "String containing the channel that was used to originate the request. For example USSD, Web, App." ,schema=@Schema()) @RequestHeader(value="X-Channel", required=false) String xChannel, @Parameter(in = ParameterIn.HEADER, description = "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." ,schema=@Schema()) @RequestHeader(value="X-Callback-URL", required=false) String xCallbackURL, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." ,schema=@Schema(allowableValues={ "lei", "swiftbic", "organisationid" } +)) @RequestHeader(value="X-Account-Holding-Institution-Identifier-Type", required=false) String xAccountHoldingInstitutionIdentifierType, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." ,schema=@Schema()) @RequestHeader(value="X-Account-Holding-Institution-Identifier", required=false) String xAccountHoldingInstitutionIdentifier); + + + @Operation(summary = "View Account Bills", description = "This endpoint returns bills linked to an account.", tags={ "Bills" }) + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Represent a list of Bills", content = @Content(mediaType = "application/json", array = @ArraySchema(schema = @Schema(implementation = ResponseBills.class)))), + + @ApiResponse(responseCode = "400", description = "Represents an Error Caused by the Violation of a Business Rule", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "401", description = "Represents an Error Caused by an Authorisation Failure", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "404", description = "Represents an Error Caused by a Failure to Identify the Target Resource", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "500", description = "Represents an Error Caused by a General Server-Side Issue", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "503", description = "Represents an Error Caused by System Unavailability", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))) }) + @RequestMapping(value = "/accounts/{identifierType}/{identifier}/bills", + produces = { "application/json" }, + method = RequestMethod.GET) + ResponseEntity> accountsIdentifierTypeIdentifierBillsGET(@Parameter(in = ParameterIn.PATH, description = "Path variable to specify the type of the identifier that is used to identify the account.", required=true, schema=@Schema(allowableValues={ "accountid", "msisdn", "walletid", "linkref", "consumerno", "serviceprovider", "storeid", "accountcategory", "bankaccountno", "accountrank", "identityalias", "iban", "swiftbic", "sortcode", "organisationid", "bankname", "bankaccounttitle", "username", "emailaddress", "mandatereference" } +)) @PathVariable("identifierType") String identifierType, @Size(min=1,max=256) @Parameter(in = ParameterIn.PATH, description = "Path variable that contains the account identifier.", required=true, schema=@Schema()) @PathVariable("identifier") String identifier, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." ,schema=@Schema()) @RequestHeader(value="X-Date", required=false) OffsetDateTime xDate, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's API key to the server." ,schema=@Schema()) @RequestHeader(value="X-API-Key", required=false) String xAPIKey, @Parameter(in = ParameterIn.HEADER, description = "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication." ,schema=@Schema()) @RequestHeader(value="X-User-Bearer", required=false) String xUserBearer, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's identifier to the server." ,schema=@Schema()) @RequestHeader(value="X-Client-Id", required=false) String xClientId, @Parameter(in = ParameterIn.HEADER, description = "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." ,schema=@Schema()) @RequestHeader(value="X-Content-Hash", required=false) String xContentHash, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-1", required=false) String xUserCredential1, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-2", required=false) String xUserCredential2, @Parameter(in = ParameterIn.HEADER, description = "String containing the channel that was used to originate the request. For example USSD, Web, App." ,schema=@Schema()) @RequestHeader(value="X-Channel", required=false) String xChannel, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." ,schema=@Schema(allowableValues={ "lei", "swiftbic", "organisationid" } +)) @RequestHeader(value="X-Account-Holding-Institution-Identifier-Type", required=false) String xAccountHoldingInstitutionIdentifierType, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." ,schema=@Schema()) @RequestHeader(value="X-Account-Holding-Institution-Identifier", required=false) String xAccountHoldingInstitutionIdentifier, @Parameter(in = ParameterIn.QUERY, description = "Supports pagination. If this is not supplied, then the server will apply a limit of 50 records returned for each request." ,schema=@Schema()) @Valid @RequestParam(value = "limit", required = false) Integer limit, @Parameter(in = ParameterIn.QUERY, description = "Supports pagination. This value will indicate the cursor position from where to retrieve the set of records. For example, a limit of 50 and offset of 10 will return records 11 to 60." ,schema=@Schema()) @Valid @RequestParam(value = "offset", required = false) Integer offset, @Parameter(in = ParameterIn.QUERY, description = "Indicates the minimum creation date for which records should be returned." ,schema=@Schema()) @Valid @RequestParam(value = "fromDateTime", required = false) OffsetDateTime fromDateTime, @Parameter(in = ParameterIn.QUERY, description = "Indicates the maximum creation date for which records should be returned." ,schema=@Schema()) @Valid @RequestParam(value = "toDateTime", required = false) OffsetDateTime toDateTime); + + + @Operation(summary = "View A Debit Mandate", description = "This endpoint returns a specific debit mandate linked to an account.", tags={ "Debit Mandates" }) + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Represents a Debit Mandate response", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ResponseDebitMandate.class))), + + @ApiResponse(responseCode = "400", description = "Represents an Error Caused by the Violation of a Business Rule", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "401", description = "Represents an Error Caused by an Authorisation Failure", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "404", description = "Represents an Error Caused by a Failure to Identify the Target Resource", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "500", description = "Represents an Error Caused by a General Server-Side Issue", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "503", description = "Represents an Error Caused by System Unavailability", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))) }) + @RequestMapping(value = "/accounts/{identifierType}/{identifier}/debitmandates/{debitMandateReference}", + produces = { "application/json" }, + method = RequestMethod.GET) + ResponseEntity accountsIdentifierTypeIdentifierDebitmandatesDebitMandateReferenceGET(@Parameter(in = ParameterIn.PATH, description = "Path variable to specify the type of the identifier that is used to identify the account.", required=true, schema=@Schema(allowableValues={ "accountid", "msisdn", "walletid", "linkref", "consumerno", "serviceprovider", "storeid", "accountcategory", "bankaccountno", "accountrank", "identityalias", "iban", "swiftbic", "sortcode", "organisationid", "bankname", "bankaccounttitle", "username", "emailaddress", "mandatereference" } +)) @PathVariable("identifierType") String identifierType, @Size(min=1,max=256) @Parameter(in = ParameterIn.PATH, description = "Path variable that contains the account identifier.", required=true, schema=@Schema()) @PathVariable("identifier") String identifier, @Size(min=1,max=256) @Parameter(in = ParameterIn.PATH, description = "Path variable to uniquely identify a Debit Mandate Reference.", required=true, schema=@Schema()) @PathVariable("debitMandateReference") String debitMandateReference, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." ,schema=@Schema()) @RequestHeader(value="X-Date", required=false) OffsetDateTime xDate, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's API key to the server." ,schema=@Schema()) @RequestHeader(value="X-API-Key", required=false) String xAPIKey, @Parameter(in = ParameterIn.HEADER, description = "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication." ,schema=@Schema()) @RequestHeader(value="X-User-Bearer", required=false) String xUserBearer, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's identifier to the server." ,schema=@Schema()) @RequestHeader(value="X-Client-Id", required=false) String xClientId, @Parameter(in = ParameterIn.HEADER, description = "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." ,schema=@Schema()) @RequestHeader(value="X-Content-Hash", required=false) String xContentHash, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-1", required=false) String xUserCredential1, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-2", required=false) String xUserCredential2, @Parameter(in = ParameterIn.HEADER, description = "String containing the channel that was used to originate the request. For example USSD, Web, App." ,schema=@Schema()) @RequestHeader(value="X-Channel", required=false) String xChannel, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." ,schema=@Schema(allowableValues={ "lei", "swiftbic", "organisationid" } +)) @RequestHeader(value="X-Account-Holding-Institution-Identifier-Type", required=false) String xAccountHoldingInstitutionIdentifierType, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." ,schema=@Schema()) @RequestHeader(value="X-Account-Holding-Institution-Identifier", required=false) String xAccountHoldingInstitutionIdentifier); + + + @Operation(summary = "Update A Debit Mandate", description = "This endpoint updates a specific debit mandate linked to an account. The following fields are modifiable] mandateStatus, startDate, endDate, frequencyType, numberOfPayments.", tags={ "Debit Mandates" }) + @ApiResponses(value = { + @ApiResponse(responseCode = "202", description = "Represents an Asynchronous response", content = @Content(mediaType = "application/json", schema = @Schema(implementation = RequestStateObject.class))), + + @ApiResponse(responseCode = "204", description = "An empty response is returned for a synchronous successful patch."), + + @ApiResponse(responseCode = "400", description = "Represents an Error Caused by the Violation of a Business Rule", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "401", description = "Represents an Error Caused by an Authorisation Failure", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "404", description = "Represents an Error Caused by a Failure to Identify the Target Resource", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "500", description = "Represents an Error Caused by a General Server-Side Issue", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "503", description = "Represents an Error Caused by System Unavailability", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))) }) + @RequestMapping(value = "/accounts/{identifierType}/{identifier}/debitmandates/{debitMandateReference}", + produces = { "application/json" }, + consumes = { "application/json" }, + method = RequestMethod.PATCH) + ResponseEntity accountsIdentifierTypeIdentifierDebitmandatesDebitMandateReferencePATCH(@Parameter(in = ParameterIn.PATH, description = "Path variable to specify the type of the identifier that is used to identify the account.", required=true, schema=@Schema(allowableValues={ "accountid", "msisdn", "walletid", "linkref", "consumerno", "serviceprovider", "storeid", "accountcategory", "bankaccountno", "accountrank", "identityalias", "iban", "swiftbic", "sortcode", "organisationid", "bankname", "bankaccounttitle", "username", "emailaddress", "mandatereference" } +)) @PathVariable("identifierType") String identifierType, @Size(min=1,max=256) @Parameter(in = ParameterIn.PATH, description = "Path variable that contains the account identifier.", required=true, schema=@Schema()) @PathVariable("identifier") String identifier, @Size(min=1,max=256) @Parameter(in = ParameterIn.PATH, description = "Path variable to uniquely identify a Debit Mandate Reference.", required=true, schema=@Schema()) @PathVariable("debitMandateReference") String debitMandateReference, @Parameter(in = ParameterIn.DEFAULT, description = "Represents the request body of a batch of generic Patch operation.", required=true, schema=@Schema()) @Valid @RequestBody List body, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." ,schema=@Schema()) @RequestHeader(value="X-Date", required=false) OffsetDateTime xDate, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's API key to the server." ,schema=@Schema()) @RequestHeader(value="X-API-Key", required=false) String xAPIKey, @Parameter(in = ParameterIn.HEADER, description = "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication." ,schema=@Schema()) @RequestHeader(value="X-User-Bearer", required=false) String xUserBearer, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's identifier to the server." ,schema=@Schema()) @RequestHeader(value="X-Client-Id", required=false) String xClientId, @Parameter(in = ParameterIn.HEADER, description = "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." ,schema=@Schema()) @RequestHeader(value="X-Content-Hash", required=false) String xContentHash, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-1", required=false) String xUserCredential1, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-2", required=false) String xUserCredential2, @Parameter(in = ParameterIn.HEADER, description = "String containing the channel that was used to originate the request. For example USSD, Web, App." ,schema=@Schema()) @RequestHeader(value="X-Channel", required=false) String xChannel, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." ,schema=@Schema(allowableValues={ "lei", "swiftbic", "organisationid" } +)) @RequestHeader(value="X-Account-Holding-Institution-Identifier-Type", required=false) String xAccountHoldingInstitutionIdentifierType, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." ,schema=@Schema()) @RequestHeader(value="X-Account-Holding-Institution-Identifier", required=false) String xAccountHoldingInstitutionIdentifier, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to uniquely identify the request. Must be supplied as a UUID." ,schema=@Schema()) @RequestHeader(value="X-CorrelationID", required=false) String xCorrelationID, @Parameter(in = ParameterIn.HEADER, description = "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." ,schema=@Schema()) @RequestHeader(value="X-Callback-URL", required=false) String xCallbackURL); + + + @Operation(summary = "Create A Debit Mandate", description = "Provided with a valid object representation, this endpoint allows for a new debit mandate to be created for a specific account.", tags={ "Debit Mandates" }) + @ApiResponses(value = { + @ApiResponse(responseCode = "201", description = "Represents a Debit Mandate response", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ResponseDebitMandate.class))), + + @ApiResponse(responseCode = "202", description = "Represents an Asynchronous response", content = @Content(mediaType = "application/json", schema = @Schema(implementation = RequestStateObject.class))), + + @ApiResponse(responseCode = "400", description = "Represents an Error Caused by the Violation of a Business Rule", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "401", description = "Represents an Error Caused by an Authorisation Failure", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "404", description = "Represents an Error Caused by a Failure to Identify the Target Resource", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "500", description = "Represents an Error Caused by a General Server-Side Issue", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "503", description = "Represents an Error Caused by System Unavailability", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))) }) + @RequestMapping(value = "/accounts/{identifierType}/{identifier}/debitmandates", + produces = { "application/json" }, + consumes = { "application/json" }, + method = RequestMethod.POST) + ResponseEntity accountsIdentifierTypeIdentifierDebitmandatesPOST(@Parameter(in = ParameterIn.PATH, description = "Path variable to specify the type of the identifier that is used to identify the account.", required=true, schema=@Schema(allowableValues={ "accountid", "msisdn", "walletid", "linkref", "consumerno", "serviceprovider", "storeid", "accountcategory", "bankaccountno", "accountrank", "identityalias", "iban", "swiftbic", "sortcode", "organisationid", "bankname", "bankaccounttitle", "username", "emailaddress", "mandatereference" } +)) @PathVariable("identifierType") String identifierType, @Size(min=1,max=256) @Parameter(in = ParameterIn.PATH, description = "Path variable that contains the account identifier.", required=true, schema=@Schema()) @PathVariable("identifier") String identifier, @Parameter(in = ParameterIn.DEFAULT, description = "Represents the request body of a debit mandate.", required=true, schema=@Schema()) @Valid @RequestBody RequestDebitMandate body, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." ,schema=@Schema()) @RequestHeader(value="X-Date", required=false) OffsetDateTime xDate, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to uniquely identify the request. Must be supplied as a UUID." ,schema=@Schema()) @RequestHeader(value="X-CorrelationID", required=false) String xCorrelationID, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's API key to the server." ,schema=@Schema()) @RequestHeader(value="X-API-Key", required=false) String xAPIKey, @Parameter(in = ParameterIn.HEADER, description = "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication." ,schema=@Schema()) @RequestHeader(value="X-User-Bearer", required=false) String xUserBearer, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's identifier to the server." ,schema=@Schema()) @RequestHeader(value="X-Client-Id", required=false) String xClientId, @Parameter(in = ParameterIn.HEADER, description = "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." ,schema=@Schema()) @RequestHeader(value="X-Content-Hash", required=false) String xContentHash, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-1", required=false) String xUserCredential1, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-2", required=false) String xUserCredential2, @Parameter(in = ParameterIn.HEADER, description = "String containing the channel that was used to originate the request. For example USSD, Web, App." ,schema=@Schema()) @RequestHeader(value="X-Channel", required=false) String xChannel, @Parameter(in = ParameterIn.HEADER, description = "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." ,schema=@Schema()) @RequestHeader(value="X-Callback-URL", required=false) String xCallbackURL, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." ,schema=@Schema(allowableValues={ "lei", "swiftbic", "organisationid" } +)) @RequestHeader(value="X-Account-Holding-Institution-Identifier-Type", required=false) String xAccountHoldingInstitutionIdentifierType, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." ,schema=@Schema()) @RequestHeader(value="X-Account-Holding-Institution-Identifier", required=false) String xAccountHoldingInstitutionIdentifier); + + + @Operation(summary = "View an Account", description = "This endpoint returns the details of an account.", tags={ "Accounts" }) + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Represents an Account response", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ResponseAccount.class))), + + @ApiResponse(responseCode = "400", description = "Represents an Error Caused by the Violation of a Business Rule", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "401", description = "Represents an Error Caused by an Authorisation Failure", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "404", description = "Represents an Error Caused by a Failure to Identify the Target Resource", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "500", description = "Represents an Error Caused by a General Server-Side Issue", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "503", description = "Represents an Error Caused by System Unavailability", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))) }) + @RequestMapping(value = "/accounts/{identifierType}/{identifier}", + produces = { "application/json" }, + method = RequestMethod.GET) + ResponseEntity accountsIdentifierTypeIdentifierGET(@Parameter(in = ParameterIn.PATH, description = "Path variable to specify the type of the identifier that is used to identify the account.", required=true, schema=@Schema(allowableValues={ "accountid", "msisdn", "walletid", "linkref", "consumerno", "serviceprovider", "storeid", "accountcategory", "bankaccountno", "accountrank", "identityalias", "iban", "swiftbic", "sortcode", "organisationid", "bankname", "bankaccounttitle", "username", "emailaddress", "mandatereference" } +)) @PathVariable("identifierType") String identifierType, @Size(min=1,max=256) @Parameter(in = ParameterIn.PATH, description = "Path variable that contains the account identifier.", required=true, schema=@Schema()) @PathVariable("identifier") String identifier, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." ,schema=@Schema()) @RequestHeader(value="X-Date", required=false) OffsetDateTime xDate, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's API key to the server." ,schema=@Schema()) @RequestHeader(value="X-API-Key", required=false) String xAPIKey, @Parameter(in = ParameterIn.HEADER, description = "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication." ,schema=@Schema()) @RequestHeader(value="X-User-Bearer", required=false) String xUserBearer, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's identifier to the server." ,schema=@Schema()) @RequestHeader(value="X-Client-Id", required=false) String xClientId, @Parameter(in = ParameterIn.HEADER, description = "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." ,schema=@Schema()) @RequestHeader(value="X-Content-Hash", required=false) String xContentHash, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-1", required=false) String xUserCredential1, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-2", required=false) String xUserCredential2, @Parameter(in = ParameterIn.HEADER, description = "String containing the channel that was used to originate the request. For example USSD, Web, App." ,schema=@Schema()) @RequestHeader(value="X-Channel", required=false) String xChannel, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." ,schema=@Schema(allowableValues={ "lei", "swiftbic", "organisationid" } +)) @RequestHeader(value="X-Account-Holding-Institution-Identifier-Type", required=false) String xAccountHoldingInstitutionIdentifierType, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." ,schema=@Schema()) @RequestHeader(value="X-Account-Holding-Institution-Identifier", required=false) String xAccountHoldingInstitutionIdentifier); + + + @Operation(summary = "View A Link", description = "This endpoint returns a specific link for a given account.", tags={ "Links" }) + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Represents a Link response", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ResponseLink.class))), + + @ApiResponse(responseCode = "400", description = "Represents an Error Caused by the Violation of a Business Rule", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "401", description = "Represents an Error Caused by an Authorisation Failure", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "404", description = "Represents an Error Caused by a Failure to Identify the Target Resource", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "500", description = "Represents an Error Caused by a General Server-Side Issue", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "503", description = "Represents an Error Caused by System Unavailability", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))) }) + @RequestMapping(value = "/accounts/{identifierType}/{identifier}/links/{linkReference}", + produces = { "application/json" }, + method = RequestMethod.GET) + ResponseEntity accountsIdentifierTypeIdentifierLinksLinkReferenceGET(@Parameter(in = ParameterIn.PATH, description = "Path variable to specify the type of the identifier that is used to identify the account.", required=true, schema=@Schema(allowableValues={ "accountid", "msisdn", "walletid", "linkref", "consumerno", "serviceprovider", "storeid", "accountcategory", "bankaccountno", "accountrank", "identityalias", "iban", "swiftbic", "sortcode", "organisationid", "bankname", "bankaccounttitle", "username", "emailaddress", "mandatereference" } +)) @PathVariable("identifierType") String identifierType, @Size(min=1,max=256) @Parameter(in = ParameterIn.PATH, description = "Path variable that contains the account identifier.", required=true, schema=@Schema()) @PathVariable("identifier") String identifier, @Size(min=1,max=256) @Parameter(in = ParameterIn.PATH, description = "Path variable to uniquely identify a link.", required=true, schema=@Schema()) @PathVariable("linkReference") String linkReference, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." ,schema=@Schema()) @RequestHeader(value="X-Date", required=false) OffsetDateTime xDate, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's API key to the server." ,schema=@Schema()) @RequestHeader(value="X-API-Key", required=false) String xAPIKey, @Parameter(in = ParameterIn.HEADER, description = "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication." ,schema=@Schema()) @RequestHeader(value="X-User-Bearer", required=false) String xUserBearer, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's identifier to the server." ,schema=@Schema()) @RequestHeader(value="X-Client-Id", required=false) String xClientId, @Parameter(in = ParameterIn.HEADER, description = "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." ,schema=@Schema()) @RequestHeader(value="X-Content-Hash", required=false) String xContentHash, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-1", required=false) String xUserCredential1, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-2", required=false) String xUserCredential2, @Parameter(in = ParameterIn.HEADER, description = "String containing the channel that was used to originate the request. For example USSD, Web, App." ,schema=@Schema()) @RequestHeader(value="X-Channel", required=false) String xChannel, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." ,schema=@Schema(allowableValues={ "lei", "swiftbic", "organisationid" } +)) @RequestHeader(value="X-Account-Holding-Institution-Identifier-Type", required=false) String xAccountHoldingInstitutionIdentifierType, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." ,schema=@Schema()) @RequestHeader(value="X-Account-Holding-Institution-Identifier", required=false) String xAccountHoldingInstitutionIdentifier); + + + @Operation(summary = "Update A Link", description = "This endpoint updates a specific link. mode and status fields are modifiable.", tags={ "Links" }) + @ApiResponses(value = { + @ApiResponse(responseCode = "202", description = "Represents an Asynchronous response", content = @Content(mediaType = "application/json", schema = @Schema(implementation = RequestStateObject.class))), + + @ApiResponse(responseCode = "204", description = "An empty response is returned for a synchronous successful patch."), + + @ApiResponse(responseCode = "400", description = "Represents an Error Caused by the Violation of a Business Rule", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "401", description = "Represents an Error Caused by an Authorisation Failure", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "404", description = "Represents an Error Caused by a Failure to Identify the Target Resource", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "500", description = "Represents an Error Caused by a General Server-Side Issue", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "503", description = "Represents an Error Caused by System Unavailability", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))) }) + @RequestMapping(value = "/accounts/{identifierType}/{identifier}/links/{linkReference}", + produces = { "application/json" }, + consumes = { "application/json" }, + method = RequestMethod.PATCH) + ResponseEntity accountsIdentifierTypeIdentifierLinksLinkReferencePATCH(@Parameter(in = ParameterIn.PATH, description = "Path variable to specify the type of the identifier that is used to identify the account.", required=true, schema=@Schema(allowableValues={ "accountid", "msisdn", "walletid", "linkref", "consumerno", "serviceprovider", "storeid", "accountcategory", "bankaccountno", "accountrank", "identityalias", "iban", "swiftbic", "sortcode", "organisationid", "bankname", "bankaccounttitle", "username", "emailaddress", "mandatereference" } +)) @PathVariable("identifierType") String identifierType, @Size(min=1,max=256) @Parameter(in = ParameterIn.PATH, description = "Path variable that contains the account identifier.", required=true, schema=@Schema()) @PathVariable("identifier") String identifier, @Size(min=1,max=256) @Parameter(in = ParameterIn.PATH, description = "Path variable to uniquely identify a link.", required=true, schema=@Schema()) @PathVariable("linkReference") String linkReference, @Parameter(in = ParameterIn.DEFAULT, description = "Represents the request body of a batch of generic Patch operation.", required=true, schema=@Schema()) @Valid @RequestBody List body, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." ,schema=@Schema()) @RequestHeader(value="X-Date", required=false) OffsetDateTime xDate, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's API key to the server." ,schema=@Schema()) @RequestHeader(value="X-API-Key", required=false) String xAPIKey, @Parameter(in = ParameterIn.HEADER, description = "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication." ,schema=@Schema()) @RequestHeader(value="X-User-Bearer", required=false) String xUserBearer, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's identifier to the server." ,schema=@Schema()) @RequestHeader(value="X-Client-Id", required=false) String xClientId, @Parameter(in = ParameterIn.HEADER, description = "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." ,schema=@Schema()) @RequestHeader(value="X-Content-Hash", required=false) String xContentHash, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-1", required=false) String xUserCredential1, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-2", required=false) String xUserCredential2, @Parameter(in = ParameterIn.HEADER, description = "String containing the channel that was used to originate the request. For example USSD, Web, App." ,schema=@Schema()) @RequestHeader(value="X-Channel", required=false) String xChannel, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." ,schema=@Schema(allowableValues={ "lei", "swiftbic", "organisationid" } +)) @RequestHeader(value="X-Account-Holding-Institution-Identifier-Type", required=false) String xAccountHoldingInstitutionIdentifierType, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." ,schema=@Schema()) @RequestHeader(value="X-Account-Holding-Institution-Identifier", required=false) String xAccountHoldingInstitutionIdentifier, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to uniquely identify the request. Must be supplied as a UUID." ,schema=@Schema()) @RequestHeader(value="X-CorrelationID", required=false) String xCorrelationID, @Parameter(in = ParameterIn.HEADER, description = "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." ,schema=@Schema()) @RequestHeader(value="X-Callback-URL", required=false) String xCallbackURL); + + + @Operation(summary = "Create A Link", description = "Provided with a valid object representation, this endpoint allows a new link to be created for a specific account.", tags={ "Links" }) + @ApiResponses(value = { + @ApiResponse(responseCode = "201", description = "Represents a Link response", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ResponseLink.class))), + + @ApiResponse(responseCode = "202", description = "Represents an Asynchronous response", content = @Content(mediaType = "application/json", schema = @Schema(implementation = RequestStateObject.class))), + + @ApiResponse(responseCode = "400", description = "Represents an Error Caused by the Violation of a Business Rule", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "401", description = "Represents an Error Caused by an Authorisation Failure", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "404", description = "Represents an Error Caused by a Failure to Identify the Target Resource", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "500", description = "Represents an Error Caused by a General Server-Side Issue", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "503", description = "Represents an Error Caused by System Unavailability", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))) }) + @RequestMapping(value = "/accounts/{identifierType}/{identifier}/links", + produces = { "application/json" }, + consumes = { "application/json" }, + method = RequestMethod.POST) + ResponseEntity accountsIdentifierTypeIdentifierLinksPOST(@Parameter(in = ParameterIn.PATH, description = "Path variable to specify the type of the identifier that is used to identify the account.", required=true, schema=@Schema(allowableValues={ "accountid", "msisdn", "walletid", "linkref", "consumerno", "serviceprovider", "storeid", "accountcategory", "bankaccountno", "accountrank", "identityalias", "iban", "swiftbic", "sortcode", "organisationid", "bankname", "bankaccounttitle", "username", "emailaddress", "mandatereference" } +)) @PathVariable("identifierType") String identifierType, @Size(min=1,max=256) @Parameter(in = ParameterIn.PATH, description = "Path variable that contains the account identifier.", required=true, schema=@Schema()) @PathVariable("identifier") String identifier, @Parameter(in = ParameterIn.DEFAULT, description = "Represents the request body of a Link.", required=true, schema=@Schema()) @Valid @RequestBody RequestLink body, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." ,schema=@Schema()) @RequestHeader(value="X-Date", required=false) OffsetDateTime xDate, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to uniquely identify the request. Must be supplied as a UUID." ,schema=@Schema()) @RequestHeader(value="X-CorrelationID", required=false) String xCorrelationID, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's API key to the server." ,schema=@Schema()) @RequestHeader(value="X-API-Key", required=false) String xAPIKey, @Parameter(in = ParameterIn.HEADER, description = "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication." ,schema=@Schema()) @RequestHeader(value="X-User-Bearer", required=false) String xUserBearer, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's identifier to the server." ,schema=@Schema()) @RequestHeader(value="X-Client-Id", required=false) String xClientId, @Parameter(in = ParameterIn.HEADER, description = "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." ,schema=@Schema()) @RequestHeader(value="X-Content-Hash", required=false) String xContentHash, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-1", required=false) String xUserCredential1, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-2", required=false) String xUserCredential2, @Parameter(in = ParameterIn.HEADER, description = "String containing the channel that was used to originate the request. For example USSD, Web, App." ,schema=@Schema()) @RequestHeader(value="X-Channel", required=false) String xChannel, @Parameter(in = ParameterIn.HEADER, description = "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." ,schema=@Schema()) @RequestHeader(value="X-Callback-URL", required=false) String xCallbackURL, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." ,schema=@Schema(allowableValues={ "lei", "swiftbic", "organisationid" } +)) @RequestHeader(value="X-Account-Holding-Institution-Identifier-Type", required=false) String xAccountHoldingInstitutionIdentifierType, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." ,schema=@Schema()) @RequestHeader(value="X-Account-Holding-Institution-Identifier", required=false) String xAccountHoldingInstitutionIdentifier); + + + @Operation(summary = "Update an Account", description = "This endpoint updates an account. Currently, accountStatus and accountSubStatus fields can be updated.", tags={ "Accounts" }) + @ApiResponses(value = { + @ApiResponse(responseCode = "202", description = "Represents an Asynchronous response", content = @Content(mediaType = "application/json", schema = @Schema(implementation = RequestStateObject.class))), + + @ApiResponse(responseCode = "204", description = "An empty response is returned for a synchronous successful patch."), + + @ApiResponse(responseCode = "400", description = "Represents an Error Caused by the Violation of a Business Rule", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "401", description = "Represents an Error Caused by an Authorisation Failure", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "404", description = "Represents an Error Caused by a Failure to Identify the Target Resource", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "500", description = "Represents an Error Caused by a General Server-Side Issue", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "503", description = "Represents an Error Caused by System Unavailability", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))) }) + @RequestMapping(value = "/accounts/{identifierType}/{identifier}", + produces = { "application/json" }, + consumes = { "application/json" }, + method = RequestMethod.PATCH) + ResponseEntity accountsIdentifierTypeIdentifierPATCH(@Parameter(in = ParameterIn.PATH, description = "Path variable to specify the type of the identifier that is used to identify the account.", required=true, schema=@Schema(allowableValues={ "accountid", "msisdn", "walletid", "linkref", "consumerno", "serviceprovider", "storeid", "accountcategory", "bankaccountno", "accountrank", "identityalias", "iban", "swiftbic", "sortcode", "organisationid", "bankname", "bankaccounttitle", "username", "emailaddress", "mandatereference" } +)) @PathVariable("identifierType") String identifierType, @Size(min=1,max=256) @Parameter(in = ParameterIn.PATH, description = "Path variable that contains the account identifier.", required=true, schema=@Schema()) @PathVariable("identifier") String identifier, @Parameter(in = ParameterIn.DEFAULT, description = "Represents the request body of a batch of generic Patch operation.", required=true, schema=@Schema()) @Valid @RequestBody List body, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." ,schema=@Schema()) @RequestHeader(value="X-Date", required=false) OffsetDateTime xDate, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's API key to the server." ,schema=@Schema()) @RequestHeader(value="X-API-Key", required=false) String xAPIKey, @Parameter(in = ParameterIn.HEADER, description = "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication." ,schema=@Schema()) @RequestHeader(value="X-User-Bearer", required=false) String xUserBearer, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's identifier to the server." ,schema=@Schema()) @RequestHeader(value="X-Client-Id", required=false) String xClientId, @Parameter(in = ParameterIn.HEADER, description = "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." ,schema=@Schema()) @RequestHeader(value="X-Content-Hash", required=false) String xContentHash, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-1", required=false) String xUserCredential1, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-2", required=false) String xUserCredential2, @Parameter(in = ParameterIn.HEADER, description = "String containing the channel that was used to originate the request. For example USSD, Web, App." ,schema=@Schema()) @RequestHeader(value="X-Channel", required=false) String xChannel, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." ,schema=@Schema(allowableValues={ "lei", "swiftbic", "organisationid" } +)) @RequestHeader(value="X-Account-Holding-Institution-Identifier-Type", required=false) String xAccountHoldingInstitutionIdentifierType, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." ,schema=@Schema()) @RequestHeader(value="X-Account-Holding-Institution-Identifier", required=false) String xAccountHoldingInstitutionIdentifier, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to uniquely identify the request. Must be supplied as a UUID." ,schema=@Schema()) @RequestHeader(value="X-CorrelationID", required=false) String xCorrelationID, @Parameter(in = ParameterIn.HEADER, description = "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." ,schema=@Schema()) @RequestHeader(value="X-Callback-URL", required=false) String xCallbackURL); + + + @Operation(summary = "View Account Statements", description = "The Statement Entries API enables generic representations of transactions to be returned. Typically, the returned representations are used for the purposes of presenting a statement to the account holder. In order to return a statement, an account must be specified.", tags={ "Accounts" }) + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Represent a list of Statement Entries", content = @Content(mediaType = "application/json", array = @ArraySchema(schema = @Schema(implementation = ResponseStatementEntries.class)))), + + @ApiResponse(responseCode = "400", description = "Represents an Error Caused by the Violation of a Business Rule", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "401", description = "Represents an Error Caused by an Authorisation Failure", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "404", description = "Represents an Error Caused by a Failure to Identify the Target Resource", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "500", description = "Represents an Error Caused by a General Server-Side Issue", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "503", description = "Represents an Error Caused by System Unavailability", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))) }) + @RequestMapping(value = "/accounts/{identifierType}/{identifier}/statemententries", + produces = { "application/json" }, + method = RequestMethod.GET) + ResponseEntity> accountsIdentifierTypeIdentifierStatemententriesGET(@Parameter(in = ParameterIn.PATH, description = "Path variable to specify the type of the identifier that is used to identify the account.", required=true, schema=@Schema(allowableValues={ "accountid", "msisdn", "walletid", "linkref", "consumerno", "serviceprovider", "storeid", "accountcategory", "bankaccountno", "accountrank", "identityalias", "iban", "swiftbic", "sortcode", "organisationid", "bankname", "bankaccounttitle", "username", "emailaddress", "mandatereference" } +)) @PathVariable("identifierType") String identifierType, @Size(min=1,max=256) @Parameter(in = ParameterIn.PATH, description = "Path variable that contains the account identifier.", required=true, schema=@Schema()) @PathVariable("identifier") String identifier, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." ,schema=@Schema()) @RequestHeader(value="X-Date", required=false) OffsetDateTime xDate, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's API key to the server." ,schema=@Schema()) @RequestHeader(value="X-API-Key", required=false) String xAPIKey, @Parameter(in = ParameterIn.HEADER, description = "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication." ,schema=@Schema()) @RequestHeader(value="X-User-Bearer", required=false) String xUserBearer, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's identifier to the server." ,schema=@Schema()) @RequestHeader(value="X-Client-Id", required=false) String xClientId, @Parameter(in = ParameterIn.HEADER, description = "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." ,schema=@Schema()) @RequestHeader(value="X-Content-Hash", required=false) String xContentHash, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-1", required=false) String xUserCredential1, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-2", required=false) String xUserCredential2, @Parameter(in = ParameterIn.HEADER, description = "String containing the channel that was used to originate the request. For example USSD, Web, App." ,schema=@Schema()) @RequestHeader(value="X-Channel", required=false) String xChannel, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." ,schema=@Schema(allowableValues={ "lei", "swiftbic", "organisationid" } +)) @RequestHeader(value="X-Account-Holding-Institution-Identifier-Type", required=false) String xAccountHoldingInstitutionIdentifierType, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." ,schema=@Schema()) @RequestHeader(value="X-Account-Holding-Institution-Identifier", required=false) String xAccountHoldingInstitutionIdentifier, @Parameter(in = ParameterIn.QUERY, description = "Supports pagination. If this is not supplied, then the server will apply a limit of 50 records returned for each request." ,schema=@Schema()) @Valid @RequestParam(value = "limit", required = false) Integer limit, @Parameter(in = ParameterIn.QUERY, description = "Supports pagination. This value will indicate the cursor position from where to retrieve the set of records. For example, a limit of 50 and offset of 10 will return records 11 to 60." ,schema=@Schema()) @Valid @RequestParam(value = "offset", required = false) Integer offset, @Parameter(in = ParameterIn.QUERY, description = "Indicates the minimum creation date for which records should be returned." ,schema=@Schema()) @Valid @RequestParam(value = "fromDateTime", required = false) OffsetDateTime fromDateTime, @Parameter(in = ParameterIn.QUERY, description = "Indicates the maximum creation date for which records should be returned." ,schema=@Schema()) @Valid @RequestParam(value = "toDateTime", required = false) OffsetDateTime toDateTime, @Size(max=256) @Parameter(in = ParameterIn.QUERY, description = "Query variable to uniquely identify the transaction status." ,schema=@Schema()) @Valid @RequestParam(value = "transactionStatus", required = false) String transactionStatus, @Size(max=256) @Parameter(in = ParameterIn.QUERY, description = "Query parameter to to identify the display type of the statement entries to be returned." ,schema=@Schema()) @Valid @RequestParam(value = "displayType", required = false) String displayType); + + + @Operation(summary = "View Account Status", description = "This endpoint returns the current status of an account.", tags={ "Accounts" }) + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Represents an Account Status response", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ResponseAccountStatus.class))), + + @ApiResponse(responseCode = "400", description = "Represents an Error Caused by the Violation of a Business Rule", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "401", description = "Represents an Error Caused by an Authorisation Failure", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "404", description = "Represents an Error Caused by a Failure to Identify the Target Resource", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "500", description = "Represents an Error Caused by a General Server-Side Issue", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "503", description = "Represents an Error Caused by System Unavailability", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))) }) + @RequestMapping(value = "/accounts/{identifierType}/{identifier}/status", + produces = { "application/json" }, + method = RequestMethod.GET) + ResponseEntity accountsIdentifierTypeIdentifierStatusGET(@Parameter(in = ParameterIn.PATH, description = "Path variable to specify the type of the identifier that is used to identify the account.", required=true, schema=@Schema(allowableValues={ "accountid", "msisdn", "walletid", "linkref", "consumerno", "serviceprovider", "storeid", "accountcategory", "bankaccountno", "accountrank", "identityalias", "iban", "swiftbic", "sortcode", "organisationid", "bankname", "bankaccounttitle", "username", "emailaddress", "mandatereference" } +)) @PathVariable("identifierType") String identifierType, @Size(min=1,max=256) @Parameter(in = ParameterIn.PATH, description = "Path variable that contains the account identifier.", required=true, schema=@Schema()) @PathVariable("identifier") String identifier, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." ,schema=@Schema()) @RequestHeader(value="X-Date", required=false) OffsetDateTime xDate, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's API key to the server." ,schema=@Schema()) @RequestHeader(value="X-API-Key", required=false) String xAPIKey, @Parameter(in = ParameterIn.HEADER, description = "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication." ,schema=@Schema()) @RequestHeader(value="X-User-Bearer", required=false) String xUserBearer, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's identifier to the server." ,schema=@Schema()) @RequestHeader(value="X-Client-Id", required=false) String xClientId, @Parameter(in = ParameterIn.HEADER, description = "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." ,schema=@Schema()) @RequestHeader(value="X-Content-Hash", required=false) String xContentHash, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-1", required=false) String xUserCredential1, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-2", required=false) String xUserCredential2, @Parameter(in = ParameterIn.HEADER, description = "String containing the channel that was used to originate the request. For example USSD, Web, App." ,schema=@Schema()) @RequestHeader(value="X-Channel", required=false) String xChannel, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." ,schema=@Schema(allowableValues={ "lei", "swiftbic", "organisationid" } +)) @RequestHeader(value="X-Account-Holding-Institution-Identifier-Type", required=false) String xAccountHoldingInstitutionIdentifierType, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." ,schema=@Schema()) @RequestHeader(value="X-Account-Holding-Institution-Identifier", required=false) String xAccountHoldingInstitutionIdentifier); + + + @Operation(summary = "View Account Specific Transaction", description = "This endpoint returns transactions linked to a specific account.", tags={ "Accounts" }) + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Represent a list of Transactions", content = @Content(mediaType = "application/json", array = @ArraySchema(schema = @Schema(implementation = ResponseTransaction.class)))), + + @ApiResponse(responseCode = "400", description = "Represents an Error Caused by the Violation of a Business Rule", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "401", description = "Represents an Error Caused by an Authorisation Failure", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "404", description = "Represents an Error Caused by a Failure to Identify the Target Resource", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "500", description = "Represents an Error Caused by a General Server-Side Issue", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "503", description = "Represents an Error Caused by System Unavailability", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))) }) + @RequestMapping(value = "/accounts/{identifierType}/{identifier}/transactions", + produces = { "application/json" }, + method = RequestMethod.GET) + ResponseEntity> accountsIdentifierTypeIdentifierTransactionsGET(@Parameter(in = ParameterIn.PATH, description = "Path variable to specify the type of the identifier that is used to identify the account.", required=true, schema=@Schema(allowableValues={ "accountid", "msisdn", "walletid", "linkref", "consumerno", "serviceprovider", "storeid", "accountcategory", "bankaccountno", "accountrank", "identityalias", "iban", "swiftbic", "sortcode", "organisationid", "bankname", "bankaccounttitle", "username", "emailaddress", "mandatereference" } +)) @PathVariable("identifierType") String identifierType, @Size(min=1,max=256) @Parameter(in = ParameterIn.PATH, description = "Path variable that contains the account identifier.", required=true, schema=@Schema()) @PathVariable("identifier") String identifier, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." ,schema=@Schema()) @RequestHeader(value="X-Date", required=false) OffsetDateTime xDate, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's API key to the server." ,schema=@Schema()) @RequestHeader(value="X-API-Key", required=false) String xAPIKey, @Parameter(in = ParameterIn.HEADER, description = "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication." ,schema=@Schema()) @RequestHeader(value="X-User-Bearer", required=false) String xUserBearer, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's identifier to the server." ,schema=@Schema()) @RequestHeader(value="X-Client-Id", required=false) String xClientId, @Parameter(in = ParameterIn.HEADER, description = "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." ,schema=@Schema()) @RequestHeader(value="X-Content-Hash", required=false) String xContentHash, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-1", required=false) String xUserCredential1, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-2", required=false) String xUserCredential2, @Parameter(in = ParameterIn.HEADER, description = "String containing the channel that was used to originate the request. For example USSD, Web, App." ,schema=@Schema()) @RequestHeader(value="X-Channel", required=false) String xChannel, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." ,schema=@Schema(allowableValues={ "lei", "swiftbic", "organisationid" } +)) @RequestHeader(value="X-Account-Holding-Institution-Identifier-Type", required=false) String xAccountHoldingInstitutionIdentifierType, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." ,schema=@Schema()) @RequestHeader(value="X-Account-Holding-Institution-Identifier", required=false) String xAccountHoldingInstitutionIdentifier, @Parameter(in = ParameterIn.QUERY, description = "Supports pagination. If this is not supplied, then the server will apply a limit of 50 records returned for each request." ,schema=@Schema()) @Valid @RequestParam(value = "limit", required = false) Integer limit, @Parameter(in = ParameterIn.QUERY, description = "Supports pagination. This value will indicate the cursor position from where to retrieve the set of records. For example, a limit of 50 and offset of 10 will return records 11 to 60." ,schema=@Schema()) @Valid @RequestParam(value = "offset", required = false) Integer offset, @Parameter(in = ParameterIn.QUERY, description = "Indicates the minimum creation date for which records should be returned." ,schema=@Schema()) @Valid @RequestParam(value = "fromDateTime", required = false) OffsetDateTime fromDateTime, @Parameter(in = ParameterIn.QUERY, description = "Indicates the maximum creation date for which records should be returned." ,schema=@Schema()) @Valid @RequestParam(value = "toDateTime", required = false) OffsetDateTime toDateTime, @Size(max=256) @Parameter(in = ParameterIn.QUERY, description = "Query variable to uniquely identify the transaction status." ,schema=@Schema()) @Valid @RequestParam(value = "transactionStatus", required = false) String transactionStatus, @Parameter(in = ParameterIn.QUERY, description = "Identifies the type of transaction." ,schema=@Schema(allowableValues={ "billpay", "deposit", "disbursement", "transfer", "merchantpay", "inttransfer", "adjustment", "reversal", "withdrawal" } +)) @Valid @RequestParam(value = "transactionType", required = false) String transactionType); + + + @Operation(summary = "Create an Account", description = "Provided with a valid object representation, this endpoint allows for a new account to be created", tags={ "Accounts" }) + @ApiResponses(value = { + @ApiResponse(responseCode = "201", description = "Represents an Account creation response", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ResponseAccount.class))), + + @ApiResponse(responseCode = "202", description = "Represents an Asynchronous response", content = @Content(mediaType = "application/json", schema = @Schema(implementation = RequestStateObject.class))), + + @ApiResponse(responseCode = "400", description = "Represents an Error Caused by the Violation of a Business Rule", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "401", description = "Represents an Error Caused by an Authorisation Failure", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "404", description = "Represents an Error Caused by a Failure to Identify the Target Resource", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "500", description = "Represents an Error Caused by a General Server-Side Issue", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "503", description = "Represents an Error Caused by System Unavailability", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))) }) + @RequestMapping(value = "/accounts/{identityType}", + produces = { "application/json" }, + consumes = { "application/json" }, + method = RequestMethod.POST) + ResponseEntity accountsPOST(@Parameter(in = ParameterIn.PATH, description = "Identifies the type of identity that is associated with the Account.", required=true, schema=@Schema(allowableValues={ "individual" } +)) @PathVariable("identityType") String identityType, @Parameter(in = ParameterIn.DEFAULT, description = "Represents the request body of an Account.", required=true, schema=@Schema()) @Valid @RequestBody RequestAccount body, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." ,schema=@Schema()) @RequestHeader(value="X-Date", required=false) OffsetDateTime xDate, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to uniquely identify the request. Must be supplied as a UUID." ,schema=@Schema()) @RequestHeader(value="X-CorrelationID", required=false) String xCorrelationID, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's API key to the server." ,schema=@Schema()) @RequestHeader(value="X-API-Key", required=false) String xAPIKey, @Parameter(in = ParameterIn.HEADER, description = "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication." ,schema=@Schema()) @RequestHeader(value="X-User-Bearer", required=false) String xUserBearer, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's identifier to the server." ,schema=@Schema()) @RequestHeader(value="X-Client-Id", required=false) String xClientId, @Parameter(in = ParameterIn.HEADER, description = "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." ,schema=@Schema()) @RequestHeader(value="X-Content-Hash", required=false) String xContentHash, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-1", required=false) String xUserCredential1, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-2", required=false) String xUserCredential2, @Parameter(in = ParameterIn.HEADER, description = "String containing the channel that was used to originate the request. For example USSD, Web, App." ,schema=@Schema()) @RequestHeader(value="X-Channel", required=false) String xChannel, @Parameter(in = ParameterIn.HEADER, description = "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." ,schema=@Schema()) @RequestHeader(value="X-Callback-URL", required=false) String xCallbackURL, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." ,schema=@Schema(allowableValues={ "lei", "swiftbic", "organisationid" } +)) @RequestHeader(value="X-Account-Holding-Institution-Identifier-Type", required=false) String xAccountHoldingInstitutionIdentifierType, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." ,schema=@Schema()) @RequestHeader(value="X-Account-Holding-Institution-Identifier", required=false) String xAccountHoldingInstitutionIdentifier); + +} + diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/api/AccountsApiController.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/api/AccountsApiController.java new file mode 100644 index 000000000..2971bbaa5 --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/api/AccountsApiController.java @@ -0,0 +1,824 @@ +package org.mifos.connector.gsmastub.api; + +import com.fasterxml.jackson.databind.ObjectMapper; +import io.swagger.v3.oas.annotations.Hidden; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.enums.ParameterIn; +import io.swagger.v3.oas.annotations.media.Schema; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; +import org.threeten.bp.OffsetDateTime; +import org.mifos.connector.gsmastub.model.*; +import springfox.documentation.annotations.*; + +import javax.servlet.http.HttpServletRequest; +import javax.validation.Valid; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Pattern; +import javax.validation.constraints.Size; +import java.io.IOException; +import java.util.List; + +@javax.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.SpringCodegen", date = "2022-09-27T11:46:46.417Z[GMT]") +@RestController +@Hidden +public class AccountsApiController implements AccountsApi { + + private static final Logger log = LoggerFactory.getLogger(AccountsApiController.class); + + private final ObjectMapper objectMapper; + + private final HttpServletRequest request; + + @GetMapping("/") + public String test() { + return "Hello"; + } + + @org.springframework.beans.factory.annotation.Autowired + public AccountsApiController(ObjectMapper objectMapper, HttpServletRequest request) { + this.objectMapper = objectMapper; + this.request = request; + } + + public ResponseEntity accountIdentitiesAccountIdPATCH(@Pattern(regexp = "^((accountcategory|bankaccountno|accountrank|identityalias|iban|accountid|msisdn|swiftbic|sortcode|organisationid|username|walletid|linkref|consumerno|serviceprovider|storeid|bankname|bankaccounttitle|emailaddress|mandatereference)@([^$\\n]+))(\\$(accountcategory|bankaccountno|accountrank|identityalias|iban|accountid|msisdn|swiftbic|sortcode|organisationid|username|walletid|linkref|consumerno|serviceprovider|storeid|bankname|bankaccounttitle|emailaddress|mandatereference)@([^$\\n]+)){0,2}$") @Parameter(in = ParameterIn.PATH, description = "Path variable to uniquely identify an account. Up to three account identifiers can be supplied. Identifiers are delimited by $ and values are delimited by @. Example: organisationid@1234$accountid@3333. Valid account identifiers are accountcategory, bankaccountno, accountrank, identityalias, iban, accountid, msisdn, swiftbic, sortcode, organisationid, username, walletid, linkref, consumerno, serviceprovider, storeid, bankname, bankaccounttitle, emailaddress, mandatereference.", required = true, schema = @Schema()) @PathVariable("accountId") String accountId, @Parameter(in = ParameterIn.PATH, description = "A unique id for the identity as assigned by the API Provider.", required = true, schema = @Schema()) @PathVariable("identityId") String identityId, @Parameter(in = ParameterIn.DEFAULT, description = "Represents the request body of a batch of generic Patch operation.", required = true, schema = @Schema()) @Valid @RequestBody List body, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to uniquely identify the request. Must be supplied as a UUID.", schema = @Schema()) @RequestHeader(value = "X-CorrelationID", required = false) String xCorrelationID, @Parameter(in = ParameterIn.HEADER, description = "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT.", schema = @Schema()) @RequestHeader(value = "X-Callback-URL", required = false) String xCallbackURL, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API.", schema = @Schema()) @RequestHeader(value = "X-Date", required = false) OffsetDateTime xDate, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's API key to the server.", schema = @Schema()) @RequestHeader(value = "X-API-Key", required = false) String xAPIKey, @Parameter(in = ParameterIn.HEADER, description = "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication.", schema = @Schema()) @RequestHeader(value = "X-User-Bearer", required = false) String xUserBearer, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's identifier to the server.", schema = @Schema()) @RequestHeader(value = "X-Client-Id", required = false) String xClientId, @Parameter(in = ParameterIn.HEADER, description = "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed.", schema = @Schema()) @RequestHeader(value = "X-Content-Hash", required = false) String xContentHash, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", schema = @Schema()) @RequestHeader(value = "X-User-Credential-1", required = false) String xUserCredential1, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", schema = @Schema()) @RequestHeader(value = "X-User-Credential-2", required = false) String xUserCredential2, @Parameter(in = ParameterIn.HEADER, description = "String containing the channel that was used to originate the request. For example USSD, Web, App.", schema = @Schema()) @RequestHeader(value = "X-Channel", required = false) String xChannel, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header.", schema = @Schema(allowableValues = {"lei", "swiftbic", "organisationid"} + )) @RequestHeader(value = "X-Account-Holding-Institution-Identifier-Type", required = false) String xAccountHoldingInstitutionIdentifierType, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header.", schema = @Schema()) @RequestHeader(value = "X-Account-Holding-Institution-Identifier", required = false) String xAccountHoldingInstitutionIdentifier) { + String accept = request.getHeader("Accept"); + if (accept != null && accept.contains("application/json")) { + try { + return new ResponseEntity(objectMapper.readValue("{\n \"pollLimit\" : 0.08008281904610115,\n \"pendingReason\" : \"pendingReason\",\n \"expiryTime\" : \"2000-01-23T04:56:07.000+00:00\",\n \"objectReference\" : \"objectReference\",\n \"notificationMethod\" : \"callback\",\n \"error\" : {\n \"errordescription\" : \"errordescription\",\n \"errorCategory\" : \"businessRule\",\n \"errorParameters\" : [ {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n } ],\n \"errorDateTime\" : \"2000-01-23T04:56:07.000+00:00\",\n \"errorCode\" : \"genericError\"\n },\n \"serverCorrelationId\" : \"serverCorrelationId\",\n \"status\" : \"pending\"\n}", RequestStateObject.class), HttpStatus.OK); + } catch (IOException e) { + log.error("Couldn't serialize response for content type application/json", e); + return new ResponseEntity(HttpStatus.INTERNAL_SERVER_ERROR); + } + } + + return new ResponseEntity(HttpStatus.OK); + } + + public ResponseEntity accountIdentitiesIdentifierTypeIdentifierPATCH(@Parameter(in = ParameterIn.PATH, description = "Path variable to specify the type of the identifier that is used to identify the account.", required = true, schema = @Schema(allowableValues = {"accountid", "msisdn", "walletid", "linkref", "consumerno", "serviceprovider", "storeid", "accountcategory", "bankaccountno", "accountrank", "identityalias", "iban", "swiftbic", "sortcode", "organisationid", "bankname", "bankaccounttitle", "username", "emailaddress", "mandatereference"} + )) @PathVariable("identifierType") String identifierType, @Size(min = 1, max = 256) @Parameter(in = ParameterIn.PATH, description = "Path variable that contains the account identifier.", required = true, schema = @Schema()) @PathVariable("identifier") String identifier, @Parameter(in = ParameterIn.PATH, description = "A unique id for the identity as assigned by the API Provider.", required = true, schema = @Schema()) @PathVariable("identityId") String identityId, @Parameter(in = ParameterIn.DEFAULT, description = "Represents the request body of a batch of generic Patch operation.", required = true, schema = @Schema()) @Valid @RequestBody List body, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to uniquely identify the request. Must be supplied as a UUID.", schema = @Schema()) @RequestHeader(value = "X-CorrelationID", required = false) String xCorrelationID, @Parameter(in = ParameterIn.HEADER, description = "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT.", schema = @Schema()) @RequestHeader(value = "X-Callback-URL", required = false) String xCallbackURL, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API.", schema = @Schema()) @RequestHeader(value = "X-Date", required = false) OffsetDateTime xDate, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's API key to the server.", schema = @Schema()) @RequestHeader(value = "X-API-Key", required = false) String xAPIKey, @Parameter(in = ParameterIn.HEADER, description = "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication.", schema = @Schema()) @RequestHeader(value = "X-User-Bearer", required = false) String xUserBearer, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's identifier to the server.", schema = @Schema()) @RequestHeader(value = "X-Client-Id", required = false) String xClientId, @Parameter(in = ParameterIn.HEADER, description = "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed.", schema = @Schema()) @RequestHeader(value = "X-Content-Hash", required = false) String xContentHash, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", schema = @Schema()) @RequestHeader(value = "X-User-Credential-1", required = false) String xUserCredential1, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", schema = @Schema()) @RequestHeader(value = "X-User-Credential-2", required = false) String xUserCredential2, @Parameter(in = ParameterIn.HEADER, description = "String containing the channel that was used to originate the request. For example USSD, Web, App.", schema = @Schema()) @RequestHeader(value = "X-Channel", required = false) String xChannel, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header.", schema = @Schema(allowableValues = {"lei", "swiftbic", "organisationid"} + )) @RequestHeader(value = "X-Account-Holding-Institution-Identifier-Type", required = false) String xAccountHoldingInstitutionIdentifierType, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header.", schema = @Schema()) @RequestHeader(value = "X-Account-Holding-Institution-Identifier", required = false) String xAccountHoldingInstitutionIdentifier) { + String accept = request.getHeader("Accept"); + if (accept != null && accept.contains("application/json")) { + try { + return new ResponseEntity(objectMapper.readValue("{\n \"pollLimit\" : 0.08008281904610115,\n \"pendingReason\" : \"pendingReason\",\n \"expiryTime\" : \"2000-01-23T04:56:07.000+00:00\",\n \"objectReference\" : \"objectReference\",\n \"notificationMethod\" : \"callback\",\n \"error\" : {\n \"errordescription\" : \"errordescription\",\n \"errorCategory\" : \"businessRule\",\n \"errorParameters\" : [ {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n } ],\n \"errorDateTime\" : \"2000-01-23T04:56:07.000+00:00\",\n \"errorCode\" : \"genericError\"\n },\n \"serverCorrelationId\" : \"serverCorrelationId\",\n \"status\" : \"pending\"\n}", RequestStateObject.class), HttpStatus.OK); + } catch (IOException e) { + log.error("Couldn't serialize response for content type application/json", e); + return new ResponseEntity(HttpStatus.INTERNAL_SERVER_ERROR); + } + } + + return new ResponseEntity(HttpStatus.OK); + } + + public ResponseEntity accountsAccountIdAccountnameGET(@Pattern(regexp = "^((accountcategory|bankaccountno|accountrank|identityalias|iban|accountid|msisdn|swiftbic|sortcode|organisationid|username|walletid|linkref|consumerno|serviceprovider|storeid|bankname|bankaccounttitle|emailaddress|mandatereference)@([^$\\n]+))(\\$(accountcategory|bankaccountno|accountrank|identityalias|iban|accountid|msisdn|swiftbic|sortcode|organisationid|username|walletid|linkref|consumerno|serviceprovider|storeid|bankname|bankaccounttitle|emailaddress|mandatereference)@([^$\\n]+)){0,2}$") @Parameter(in = ParameterIn.PATH, description = "Path variable to uniquely identify an account. Up to three account identifiers can be supplied. Identifiers are delimited by $ and values are delimited by @. Example: organisationid@1234$accountid@3333. Valid account identifiers are accountcategory, bankaccountno, accountrank, identityalias, iban, accountid, msisdn, swiftbic, sortcode, organisationid, username, walletid, linkref, consumerno, serviceprovider, storeid, bankname, bankaccounttitle, emailaddress, mandatereference.", required = true, schema = @Schema()) @PathVariable("accountId") String accountId, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API.", schema = @Schema()) @RequestHeader(value = "X-Date", required = false) OffsetDateTime xDate, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's API key to the server.", schema = @Schema()) @RequestHeader(value = "X-API-Key", required = false) String xAPIKey, @Parameter(in = ParameterIn.HEADER, description = "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication.", schema = @Schema()) @RequestHeader(value = "X-User-Bearer", required = false) String xUserBearer, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's identifier to the server.", schema = @Schema()) @RequestHeader(value = "X-Client-Id", required = false) String xClientId, @Parameter(in = ParameterIn.HEADER, description = "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed.", schema = @Schema()) @RequestHeader(value = "X-Content-Hash", required = false) String xContentHash, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", schema = @Schema()) @RequestHeader(value = "X-User-Credential-1", required = false) String xUserCredential1, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", schema = @Schema()) @RequestHeader(value = "X-User-Credential-2", required = false) String xUserCredential2, @Parameter(in = ParameterIn.HEADER, description = "String containing the channel that was used to originate the request. For example USSD, Web, App.", schema = @Schema()) @RequestHeader(value = "X-Channel", required = false) String xChannel, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header.", schema = @Schema(allowableValues = {"lei", "swiftbic", "organisationid"} + )) @RequestHeader(value = "X-Account-Holding-Institution-Identifier-Type", required = false) String xAccountHoldingInstitutionIdentifierType, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header.", schema = @Schema()) @RequestHeader(value = "X-Account-Holding-Institution-Identifier", required = false) String xAccountHoldingInstitutionIdentifier) { + String accept = request.getHeader("Accept"); + if (accept != null && accept.contains("application/json")) { + try { + return new ResponseEntity(objectMapper.readValue("{\n \"lei\" : \"5493000IBP32UQZ0KL24\",\n \"name\" : {\n \"firstName\" : \"firstName\",\n \"lastName\" : \"lastName\",\n \"nativeName\" : \"nativeName\",\n \"fullName\" : \"fullName\",\n \"middleName\" : \"middleName\",\n \"title\" : \"title\"\n }\n}", ResponseAccountName.class), HttpStatus.OK); + } catch (IOException e) { + log.error("Couldn't serialize response for content type application/json", e); + return new ResponseEntity(HttpStatus.INTERNAL_SERVER_ERROR); + } + } + + return new ResponseEntity(HttpStatus.OK); + } + + public ResponseEntity accountsAccountIdAuthorisationCodeAuthorisationCodeGET(@Pattern(regexp = "^((accountcategory|bankaccountno|accountrank|identityalias|iban|accountid|msisdn|swiftbic|sortcode|organisationid|username|walletid|linkref|consumerno|serviceprovider|storeid|bankname|bankaccounttitle|emailaddress|mandatereference)@([^$\\n]+))(\\$(accountcategory|bankaccountno|accountrank|identityalias|iban|accountid|msisdn|swiftbic|sortcode|organisationid|username|walletid|linkref|consumerno|serviceprovider|storeid|bankname|bankaccounttitle|emailaddress|mandatereference)@([^$\\n]+)){0,2}$") @Parameter(in = ParameterIn.PATH, description = "Path variable to uniquely identify an account. Up to three account identifiers can be supplied. Identifiers are delimited by $ and values are delimited by @. Example: organisationid@1234$accountid@3333. Valid account identifiers are accountcategory, bankaccountno, accountrank, identityalias, iban, accountid, msisdn, swiftbic, sortcode, organisationid, username, walletid, linkref, consumerno, serviceprovider, storeid, bankname, bankaccounttitle, emailaddress, mandatereference.", required = true, schema = @Schema()) @PathVariable("accountId") String accountId, @Size(min = 1, max = 256) @Parameter(in = ParameterIn.PATH, description = "Path variable to uniquely identify an authorisation code.", required = true, schema = @Schema()) @PathVariable("authorisationCode") String authorisationCode, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API.", schema = @Schema()) @RequestHeader(value = "X-Date", required = false) OffsetDateTime xDate, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's API key to the server.", schema = @Schema()) @RequestHeader(value = "X-API-Key", required = false) String xAPIKey, @Parameter(in = ParameterIn.HEADER, description = "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication.", schema = @Schema()) @RequestHeader(value = "X-User-Bearer", required = false) String xUserBearer, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's identifier to the server.", schema = @Schema()) @RequestHeader(value = "X-Client-Id", required = false) String xClientId, @Parameter(in = ParameterIn.HEADER, description = "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed.", schema = @Schema()) @RequestHeader(value = "X-Content-Hash", required = false) String xContentHash, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", schema = @Schema()) @RequestHeader(value = "X-User-Credential-1", required = false) String xUserCredential1, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", schema = @Schema()) @RequestHeader(value = "X-User-Credential-2", required = false) String xUserCredential2, @Parameter(in = ParameterIn.HEADER, description = "String containing the channel that was used to originate the request. For example USSD, Web, App.", schema = @Schema()) @RequestHeader(value = "X-Channel", required = false) String xChannel, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header.", schema = @Schema(allowableValues = {"lei", "swiftbic", "organisationid"} + )) @RequestHeader(value = "X-Account-Holding-Institution-Identifier-Type", required = false) String xAccountHoldingInstitutionIdentifierType, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header.", schema = @Schema()) @RequestHeader(value = "X-Account-Holding-Institution-Identifier", required = false) String xAccountHoldingInstitutionIdentifier) { + String accept = request.getHeader("Accept"); + if (accept != null && accept.contains("application/json")) { + try { + return new ResponseEntity(objectMapper.readValue("{\n \"amountType\" : \"exact\",\n \"amount\" : \"15.21\",\n \"metadata\" : [ {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n } ],\n \"requestingOrganisation\" : {\n \"requestingOrganisationIdentifierType\" : \"lei\",\n \"requestingOrganisationIdentifier\" : \"requestingOrganisationIdentifier\"\n },\n \"redemptionChannels\" : [ {\n \"channelType\" : \"channelType\"\n }, {\n \"channelType\" : \"channelType\"\n }, {\n \"channelType\" : \"channelType\"\n }, {\n \"channelType\" : \"channelType\"\n }, {\n \"channelType\" : \"channelType\"\n }, {\n \"channelType\" : \"channelType\"\n }, {\n \"channelType\" : \"channelType\"\n }, {\n \"channelType\" : \"channelType\"\n }, {\n \"channelType\" : \"channelType\"\n }, {\n \"channelType\" : \"channelType\"\n } ],\n \"customData\" : [ {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n } ],\n \"authorisationCode\" : \"authorisationCode\",\n \"creationDate\" : \"2000-01-23T04:56:07.000+00:00\",\n \"codeState\" : \"active\",\n \"codeLifetime\" : 600,\n \"redemptionTransactionTypes\" : [ {\n \"transactionType\" : \"billpay\",\n \"transactionSubtype\" : \"transactionSubtype\"\n }, {\n \"transactionType\" : \"billpay\",\n \"transactionSubtype\" : \"transactionSubtype\"\n }, {\n \"transactionType\" : \"billpay\",\n \"transactionSubtype\" : \"transactionSubtype\"\n }, {\n \"transactionType\" : \"billpay\",\n \"transactionSubtype\" : \"transactionSubtype\"\n }, {\n \"transactionType\" : \"billpay\",\n \"transactionSubtype\" : \"transactionSubtype\"\n }, {\n \"transactionType\" : \"billpay\",\n \"transactionSubtype\" : \"transactionSubtype\"\n }, {\n \"transactionType\" : \"billpay\",\n \"transactionSubtype\" : \"transactionSubtype\"\n }, {\n \"transactionType\" : \"billpay\",\n \"transactionSubtype\" : \"transactionSubtype\"\n }, {\n \"transactionType\" : \"billpay\",\n \"transactionSubtype\" : \"transactionSubtype\"\n }, {\n \"transactionType\" : \"billpay\",\n \"transactionSubtype\" : \"transactionSubtype\"\n } ],\n \"modificationDate\" : \"2000-01-23T04:56:07.000+00:00\",\n \"redemptionAccountIdentifiers\" : [ {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n } ],\n \"requestDate\" : \"2000-01-23T04:56:07.000+00:00\",\n \"currency\" : \"AED\",\n \"holdFundsIndicator\" : true\n}", ResponseAuthorisationCode.class), HttpStatus.OK); + } catch (IOException e) { + log.error("Couldn't serialize response for content type application/json", e); + return new ResponseEntity(HttpStatus.INTERNAL_SERVER_ERROR); + } + } + + return new ResponseEntity(HttpStatus.OK); + } + + public ResponseEntity accountsAccountIdAuthorisationCodesAuthorisationCodePATCH(@Pattern(regexp = "^((accountcategory|bankaccountno|accountrank|identityalias|iban|accountid|msisdn|swiftbic|sortcode|organisationid|username|walletid|linkref|consumerno|serviceprovider|storeid|bankname|bankaccounttitle|emailaddress|mandatereference)@([^$\\n]+))(\\$(accountcategory|bankaccountno|accountrank|identityalias|iban|accountid|msisdn|swiftbic|sortcode|organisationid|username|walletid|linkref|consumerno|serviceprovider|storeid|bankname|bankaccounttitle|emailaddress|mandatereference)@([^$\\n]+)){0,2}$") @Parameter(in = ParameterIn.PATH, description = "Path variable to uniquely identify an account. Up to three account identifiers can be supplied. Identifiers are delimited by $ and values are delimited by @. Example: organisationid@1234$accountid@3333. Valid account identifiers are accountcategory, bankaccountno, accountrank, identityalias, iban, accountid, msisdn, swiftbic, sortcode, organisationid, username, walletid, linkref, consumerno, serviceprovider, storeid, bankname, bankaccounttitle, emailaddress, mandatereference.", required = true, schema = @Schema()) @PathVariable("accountId") String accountId, @Size(min = 1, max = 256) @Parameter(in = ParameterIn.PATH, description = "Path variable to uniquely identify an authorisation code.", required = true, schema = @Schema()) @PathVariable("authorisationCode") String authorisationCode, @Parameter(in = ParameterIn.DEFAULT, description = "Represents the request body of a batch of generic Patch operation.", required = true, schema = @Schema()) @Valid @RequestBody List body, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API.", schema = @Schema()) @RequestHeader(value = "X-Date", required = false) OffsetDateTime xDate, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's API key to the server.", schema = @Schema()) @RequestHeader(value = "X-API-Key", required = false) String xAPIKey, @Parameter(in = ParameterIn.HEADER, description = "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication.", schema = @Schema()) @RequestHeader(value = "X-User-Bearer", required = false) String xUserBearer, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's identifier to the server.", schema = @Schema()) @RequestHeader(value = "X-Client-Id", required = false) String xClientId, @Parameter(in = ParameterIn.HEADER, description = "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed.", schema = @Schema()) @RequestHeader(value = "X-Content-Hash", required = false) String xContentHash, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", schema = @Schema()) @RequestHeader(value = "X-User-Credential-1", required = false) String xUserCredential1, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", schema = @Schema()) @RequestHeader(value = "X-User-Credential-2", required = false) String xUserCredential2, @Parameter(in = ParameterIn.HEADER, description = "String containing the channel that was used to originate the request. For example USSD, Web, App.", schema = @Schema()) @RequestHeader(value = "X-Channel", required = false) String xChannel, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header.", schema = @Schema(allowableValues = {"lei", "swiftbic", "organisationid"} + )) @RequestHeader(value = "X-Account-Holding-Institution-Identifier-Type", required = false) String xAccountHoldingInstitutionIdentifierType, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header.", schema = @Schema()) @RequestHeader(value = "X-Account-Holding-Institution-Identifier", required = false) String xAccountHoldingInstitutionIdentifier, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to uniquely identify the request. Must be supplied as a UUID.", schema = @Schema()) @RequestHeader(value = "X-CorrelationID", required = false) String xCorrelationID, @Parameter(in = ParameterIn.HEADER, description = "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT.", schema = @Schema()) @RequestHeader(value = "X-Callback-URL", required = false) String xCallbackURL) { + String accept = request.getHeader("Accept"); + if (accept != null && accept.contains("application/json")) { + try { + return new ResponseEntity(objectMapper.readValue("{\n \"pollLimit\" : 0.08008281904610115,\n \"pendingReason\" : \"pendingReason\",\n \"expiryTime\" : \"2000-01-23T04:56:07.000+00:00\",\n \"objectReference\" : \"objectReference\",\n \"notificationMethod\" : \"callback\",\n \"error\" : {\n \"errordescription\" : \"errordescription\",\n \"errorCategory\" : \"businessRule\",\n \"errorParameters\" : [ {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n } ],\n \"errorDateTime\" : \"2000-01-23T04:56:07.000+00:00\",\n \"errorCode\" : \"genericError\"\n },\n \"serverCorrelationId\" : \"serverCorrelationId\",\n \"status\" : \"pending\"\n}", RequestStateObject.class), HttpStatus.OK); + } catch (IOException e) { + log.error("Couldn't serialize response for content type application/json", e); + return new ResponseEntity(HttpStatus.INTERNAL_SERVER_ERROR); + } + } + + return new ResponseEntity(HttpStatus.OK); + } + + public ResponseEntity accountsAccountIdAuthorisationcodesGET(@Pattern(regexp = "^((accountcategory|bankaccountno|accountrank|identityalias|iban|accountid|msisdn|swiftbic|sortcode|organisationid|username|walletid|linkref|consumerno|serviceprovider|storeid|bankname|bankaccounttitle|emailaddress|mandatereference)@([^$\\n]+))(\\$(accountcategory|bankaccountno|accountrank|identityalias|iban|accountid|msisdn|swiftbic|sortcode|organisationid|username|walletid|linkref|consumerno|serviceprovider|storeid|bankname|bankaccounttitle|emailaddress|mandatereference)@([^$\\n]+)){0,2}$") @Parameter(in = ParameterIn.PATH, description = "Path variable to uniquely identify an account. Up to three account identifiers can be supplied. Identifiers are delimited by $ and values are delimited by @. Example: organisationid@1234$accountid@3333. Valid account identifiers are accountcategory, bankaccountno, accountrank, identityalias, iban, accountid, msisdn, swiftbic, sortcode, organisationid, username, walletid, linkref, consumerno, serviceprovider, storeid, bankname, bankaccounttitle, emailaddress, mandatereference.", required = true, schema = @Schema()) @PathVariable("accountId") String accountId, @NotNull @Size(max = 256) @Parameter(in = ParameterIn.QUERY, description = "Allows returned records to be filtered on state of the authorisation code.", required = true, schema = @Schema()) @Valid @RequestParam(value = "codeState", required = true) String codeState, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API.", schema = @Schema()) @RequestHeader(value = "X-Date", required = false) OffsetDateTime xDate, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's API key to the server.", schema = @Schema()) @RequestHeader(value = "X-API-Key", required = false) String xAPIKey, @Parameter(in = ParameterIn.HEADER, description = "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication.", schema = @Schema()) @RequestHeader(value = "X-User-Bearer", required = false) String xUserBearer, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's identifier to the server.", schema = @Schema()) @RequestHeader(value = "X-Client-Id", required = false) String xClientId, @Parameter(in = ParameterIn.HEADER, description = "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed.", schema = @Schema()) @RequestHeader(value = "X-Content-Hash", required = false) String xContentHash, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", schema = @Schema()) @RequestHeader(value = "X-User-Credential-1", required = false) String xUserCredential1, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", schema = @Schema()) @RequestHeader(value = "X-User-Credential-2", required = false) String xUserCredential2, @Parameter(in = ParameterIn.HEADER, description = "String containing the channel that was used to originate the request. For example USSD, Web, App.", schema = @Schema()) @RequestHeader(value = "X-Channel", required = false) String xChannel, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header.", schema = @Schema(allowableValues = {"lei", "swiftbic", "organisationid"} + )) @RequestHeader(value = "X-Account-Holding-Institution-Identifier-Type", required = false) String xAccountHoldingInstitutionIdentifierType, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header.", schema = @Schema()) @RequestHeader(value = "X-Account-Holding-Institution-Identifier", required = false) String xAccountHoldingInstitutionIdentifier, @Parameter(in = ParameterIn.QUERY, description = "Supports pagination. If this is not supplied, then the server will apply a limit of 50 records returned for each request.", schema = @Schema()) @Valid @RequestParam(value = "limit", required = false) Integer limit, @Parameter(in = ParameterIn.QUERY, description = "Supports pagination. This value will indicate the cursor position from where to retrieve the set of records. For example, a limit of 50 and offset of 10 will return records 11 to 60.", schema = @Schema()) @Valid @RequestParam(value = "offset", required = false) Integer offset, @Parameter(in = ParameterIn.QUERY, description = "Indicates the minimum creation date for which records should be returned.", schema = @Schema()) @Valid @RequestParam(value = "fromDateTime", required = false) OffsetDateTime fromDateTime, @Parameter(in = ParameterIn.QUERY, description = "Indicates the maximum creation date for which records should be returned.", schema = @Schema()) @Valid @RequestParam(value = "toDateTime", required = false) OffsetDateTime toDateTime) { + String accept = request.getHeader("Accept"); + if (accept != null && accept.contains("application/json")) { + try { + return new ResponseEntity(objectMapper.readValue("{\n \"amountType\" : \"exact\",\n \"amount\" : \"15.21\",\n \"metadata\" : [ {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n } ],\n \"requestingOrganisation\" : {\n \"requestingOrganisationIdentifierType\" : \"lei\",\n \"requestingOrganisationIdentifier\" : \"requestingOrganisationIdentifier\"\n },\n \"redemptionChannels\" : [ {\n \"channelType\" : \"channelType\"\n }, {\n \"channelType\" : \"channelType\"\n }, {\n \"channelType\" : \"channelType\"\n }, {\n \"channelType\" : \"channelType\"\n }, {\n \"channelType\" : \"channelType\"\n }, {\n \"channelType\" : \"channelType\"\n }, {\n \"channelType\" : \"channelType\"\n }, {\n \"channelType\" : \"channelType\"\n }, {\n \"channelType\" : \"channelType\"\n }, {\n \"channelType\" : \"channelType\"\n } ],\n \"customData\" : [ {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n } ],\n \"authorisationCode\" : \"authorisationCode\",\n \"creationDate\" : \"2000-01-23T04:56:07.000+00:00\",\n \"codeState\" : \"active\",\n \"codeLifetime\" : 600,\n \"redemptionTransactionTypes\" : [ {\n \"transactionType\" : \"billpay\",\n \"transactionSubtype\" : \"transactionSubtype\"\n }, {\n \"transactionType\" : \"billpay\",\n \"transactionSubtype\" : \"transactionSubtype\"\n }, {\n \"transactionType\" : \"billpay\",\n \"transactionSubtype\" : \"transactionSubtype\"\n }, {\n \"transactionType\" : \"billpay\",\n \"transactionSubtype\" : \"transactionSubtype\"\n }, {\n \"transactionType\" : \"billpay\",\n \"transactionSubtype\" : \"transactionSubtype\"\n }, {\n \"transactionType\" : \"billpay\",\n \"transactionSubtype\" : \"transactionSubtype\"\n }, {\n \"transactionType\" : \"billpay\",\n \"transactionSubtype\" : \"transactionSubtype\"\n }, {\n \"transactionType\" : \"billpay\",\n \"transactionSubtype\" : \"transactionSubtype\"\n }, {\n \"transactionType\" : \"billpay\",\n \"transactionSubtype\" : \"transactionSubtype\"\n }, {\n \"transactionType\" : \"billpay\",\n \"transactionSubtype\" : \"transactionSubtype\"\n } ],\n \"modificationDate\" : \"2000-01-23T04:56:07.000+00:00\",\n \"redemptionAccountIdentifiers\" : [ {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n } ],\n \"requestDate\" : \"2000-01-23T04:56:07.000+00:00\",\n \"currency\" : \"AED\",\n \"holdFundsIndicator\" : true\n}", ResponseAuthorisationCode.class), HttpStatus.OK); + } catch (IOException e) { + log.error("Couldn't serialize response for content type application/json", e); + return new ResponseEntity(HttpStatus.INTERNAL_SERVER_ERROR); + } + } + + return new ResponseEntity(HttpStatus.OK); + } + + public ResponseEntity accountsAccountIdAuthorisationcodesPOST(@Pattern(regexp = "^((accountcategory|bankaccountno|accountrank|identityalias|iban|accountid|msisdn|swiftbic|sortcode|organisationid|username|walletid|linkref|consumerno|serviceprovider|storeid|bankname|bankaccounttitle|emailaddress|mandatereference)@([^$\\n]+))(\\$(accountcategory|bankaccountno|accountrank|identityalias|iban|accountid|msisdn|swiftbic|sortcode|organisationid|username|walletid|linkref|consumerno|serviceprovider|storeid|bankname|bankaccounttitle|emailaddress|mandatereference)@([^$\\n]+)){0,2}$") @Parameter(in = ParameterIn.PATH, description = "Path variable to uniquely identify an account. Up to three account identifiers can be supplied. Identifiers are delimited by $ and values are delimited by @. Example: organisationid@1234$accountid@3333. Valid account identifiers are accountcategory, bankaccountno, accountrank, identityalias, iban, accountid, msisdn, swiftbic, sortcode, organisationid, username, walletid, linkref, consumerno, serviceprovider, storeid, bankname, bankaccounttitle, emailaddress, mandatereference.", required = true, schema = @Schema()) @PathVariable("accountId") String accountId, @Parameter(in = ParameterIn.DEFAULT, description = "Represents the request body of an Authorisation Code.", required = true, schema = @Schema()) @Valid @RequestBody RequestAuthorisationCode body, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API.", schema = @Schema()) @RequestHeader(value = "X-Date", required = false) OffsetDateTime xDate, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to uniquely identify the request. Must be supplied as a UUID.", schema = @Schema()) @RequestHeader(value = "X-CorrelationID", required = false) String xCorrelationID, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's API key to the server.", schema = @Schema()) @RequestHeader(value = "X-API-Key", required = false) String xAPIKey, @Parameter(in = ParameterIn.HEADER, description = "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication.", schema = @Schema()) @RequestHeader(value = "X-User-Bearer", required = false) String xUserBearer, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's identifier to the server.", schema = @Schema()) @RequestHeader(value = "X-Client-Id", required = false) String xClientId, @Parameter(in = ParameterIn.HEADER, description = "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed.", schema = @Schema()) @RequestHeader(value = "X-Content-Hash", required = false) String xContentHash, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", schema = @Schema()) @RequestHeader(value = "X-User-Credential-1", required = false) String xUserCredential1, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", schema = @Schema()) @RequestHeader(value = "X-User-Credential-2", required = false) String xUserCredential2, @Parameter(in = ParameterIn.HEADER, description = "String containing the channel that was used to originate the request. For example USSD, Web, App.", schema = @Schema()) @RequestHeader(value = "X-Channel", required = false) String xChannel, @Parameter(in = ParameterIn.HEADER, description = "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT.", schema = @Schema()) @RequestHeader(value = "X-Callback-URL", required = false) String xCallbackURL, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header.", schema = @Schema(allowableValues = {"lei", "swiftbic", "organisationid"} + )) @RequestHeader(value = "X-Account-Holding-Institution-Identifier-Type", required = false) String xAccountHoldingInstitutionIdentifierType, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header.", schema = @Schema()) @RequestHeader(value = "X-Account-Holding-Institution-Identifier", required = false) String xAccountHoldingInstitutionIdentifier) { + String accept = request.getHeader("Accept"); + if (accept != null && accept.contains("application/json")) { + try { + return new ResponseEntity(objectMapper.readValue("{\n \"amountType\" : \"exact\",\n \"amount\" : \"15.21\",\n \"metadata\" : [ {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n } ],\n \"requestingOrganisation\" : {\n \"requestingOrganisationIdentifierType\" : \"lei\",\n \"requestingOrganisationIdentifier\" : \"requestingOrganisationIdentifier\"\n },\n \"redemptionChannels\" : [ {\n \"channelType\" : \"channelType\"\n }, {\n \"channelType\" : \"channelType\"\n }, {\n \"channelType\" : \"channelType\"\n }, {\n \"channelType\" : \"channelType\"\n }, {\n \"channelType\" : \"channelType\"\n }, {\n \"channelType\" : \"channelType\"\n }, {\n \"channelType\" : \"channelType\"\n }, {\n \"channelType\" : \"channelType\"\n }, {\n \"channelType\" : \"channelType\"\n }, {\n \"channelType\" : \"channelType\"\n } ],\n \"customData\" : [ {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n } ],\n \"authorisationCode\" : \"authorisationCode\",\n \"creationDate\" : \"2000-01-23T04:56:07.000+00:00\",\n \"codeState\" : \"active\",\n \"codeLifetime\" : 600,\n \"redemptionTransactionTypes\" : [ {\n \"transactionType\" : \"billpay\",\n \"transactionSubtype\" : \"transactionSubtype\"\n }, {\n \"transactionType\" : \"billpay\",\n \"transactionSubtype\" : \"transactionSubtype\"\n }, {\n \"transactionType\" : \"billpay\",\n \"transactionSubtype\" : \"transactionSubtype\"\n }, {\n \"transactionType\" : \"billpay\",\n \"transactionSubtype\" : \"transactionSubtype\"\n }, {\n \"transactionType\" : \"billpay\",\n \"transactionSubtype\" : \"transactionSubtype\"\n }, {\n \"transactionType\" : \"billpay\",\n \"transactionSubtype\" : \"transactionSubtype\"\n }, {\n \"transactionType\" : \"billpay\",\n \"transactionSubtype\" : \"transactionSubtype\"\n }, {\n \"transactionType\" : \"billpay\",\n \"transactionSubtype\" : \"transactionSubtype\"\n }, {\n \"transactionType\" : \"billpay\",\n \"transactionSubtype\" : \"transactionSubtype\"\n }, {\n \"transactionType\" : \"billpay\",\n \"transactionSubtype\" : \"transactionSubtype\"\n } ],\n \"modificationDate\" : \"2000-01-23T04:56:07.000+00:00\",\n \"redemptionAccountIdentifiers\" : [ {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n } ],\n \"requestDate\" : \"2000-01-23T04:56:07.000+00:00\",\n \"currency\" : \"AED\",\n \"holdFundsIndicator\" : true\n}", ResponseAuthorisationCode.class), HttpStatus.OK); + } catch (IOException e) { + log.error("Couldn't serialize response for content type application/json", e); + return new ResponseEntity(HttpStatus.INTERNAL_SERVER_ERROR); + } + } + + return new ResponseEntity(HttpStatus.OK); + } + + public ResponseEntity accountsAccountIdBalanceGET(@Pattern(regexp = "^((accountcategory|bankaccountno|accountrank|identityalias|iban|accountid|msisdn|swiftbic|sortcode|organisationid|username|walletid|linkref|consumerno|serviceprovider|storeid|bankname|bankaccounttitle|emailaddress|mandatereference)@([^$\\n]+))(\\$(accountcategory|bankaccountno|accountrank|identityalias|iban|accountid|msisdn|swiftbic|sortcode|organisationid|username|walletid|linkref|consumerno|serviceprovider|storeid|bankname|bankaccounttitle|emailaddress|mandatereference)@([^$\\n]+)){0,2}$") @Parameter(in = ParameterIn.PATH, description = "Path variable to uniquely identify an account. Up to three account identifiers can be supplied. Identifiers are delimited by $ and values are delimited by @. Example: organisationid@1234$accountid@3333. Valid account identifiers are accountcategory, bankaccountno, accountrank, identityalias, iban, accountid, msisdn, swiftbic, sortcode, organisationid, username, walletid, linkref, consumerno, serviceprovider, storeid, bankname, bankaccounttitle, emailaddress, mandatereference.", required = true, schema = @Schema()) @PathVariable("accountId") String accountId, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API.", schema = @Schema()) @RequestHeader(value = "X-Date", required = false) OffsetDateTime xDate, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's API key to the server.", schema = @Schema()) @RequestHeader(value = "X-API-Key", required = false) String xAPIKey, @Parameter(in = ParameterIn.HEADER, description = "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication.", schema = @Schema()) @RequestHeader(value = "X-User-Bearer", required = false) String xUserBearer, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's identifier to the server.", schema = @Schema()) @RequestHeader(value = "X-Client-Id", required = false) String xClientId, @Parameter(in = ParameterIn.HEADER, description = "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed.", schema = @Schema()) @RequestHeader(value = "X-Content-Hash", required = false) String xContentHash, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", schema = @Schema()) @RequestHeader(value = "X-User-Credential-1", required = false) String xUserCredential1, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", schema = @Schema()) @RequestHeader(value = "X-User-Credential-2", required = false) String xUserCredential2, @Parameter(in = ParameterIn.HEADER, description = "String containing the channel that was used to originate the request. For example USSD, Web, App.", schema = @Schema()) @RequestHeader(value = "X-Channel", required = false) String xChannel, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header.", schema = @Schema(allowableValues = {"lei", "swiftbic", "organisationid"} + )) @RequestHeader(value = "X-Account-Holding-Institution-Identifier-Type", required = false) String xAccountHoldingInstitutionIdentifierType, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header.", schema = @Schema()) @RequestHeader(value = "X-Account-Holding-Institution-Identifier", required = false) String xAccountHoldingInstitutionIdentifier) { + String accept = request.getHeader("Accept"); + if (accept != null && accept.contains("application/json")) { + try { + return new ResponseEntity(objectMapper.readValue("{\n \"accountStatus\" : \"available\",\n \"currentBalance\" : \"15.21\",\n \"currency\" : \"AED\"\n}", ResponseAccountBalance.class), HttpStatus.OK); + } catch (IOException e) { + log.error("Couldn't serialize response for content type application/json", e); + return new ResponseEntity(HttpStatus.INTERNAL_SERVER_ERROR); + } + } + + return new ResponseEntity(HttpStatus.OK); + } + + public ResponseEntity> accountsAccountIdBillCompaniesGET(@Pattern(regexp = "^((accountcategory|bankaccountno|accountrank|identityalias|iban|accountid|msisdn|swiftbic|sortcode|organisationid|username|walletid|linkref|consumerno|serviceprovider|storeid|bankname|bankaccounttitle|emailaddress|mandatereference)@([^$\\n]+))(\\$(accountcategory|bankaccountno|accountrank|identityalias|iban|accountid|msisdn|swiftbic|sortcode|organisationid|username|walletid|linkref|consumerno|serviceprovider|storeid|bankname|bankaccounttitle|emailaddress|mandatereference)@([^$\\n]+)){0,2}$") @Parameter(in = ParameterIn.PATH, description = "Path variable to uniquely identify an account. Up to three account identifiers can be supplied. Identifiers are delimited by $ and values are delimited by @. Example: organisationid@1234$accountid@3333. Valid account identifiers are accountcategory, bankaccountno, accountrank, identityalias, iban, accountid, msisdn, swiftbic, sortcode, organisationid, username, walletid, linkref, consumerno, serviceprovider, storeid, bankname, bankaccounttitle, emailaddress, mandatereference.", required = true, schema = @Schema()) @PathVariable("accountId") String accountId, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API.", schema = @Schema()) @RequestHeader(value = "X-Date", required = false) OffsetDateTime xDate, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's API key to the server.", schema = @Schema()) @RequestHeader(value = "X-API-Key", required = false) String xAPIKey, @Parameter(in = ParameterIn.HEADER, description = "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication.", schema = @Schema()) @RequestHeader(value = "X-User-Bearer", required = false) String xUserBearer, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's identifier to the server.", schema = @Schema()) @RequestHeader(value = "X-Client-Id", required = false) String xClientId, @Parameter(in = ParameterIn.HEADER, description = "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed.", schema = @Schema()) @RequestHeader(value = "X-Content-Hash", required = false) String xContentHash, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header.", schema = @Schema(allowableValues = {"lei", "swiftbic", "organisationid"} + )) @RequestHeader(value = "X-Account-Holding-Institution-Identifier-Type", required = false) String xAccountHoldingInstitutionIdentifierType, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header.", schema = @Schema()) @RequestHeader(value = "X-Account-Holding-Institution-Identifier", required = false) String xAccountHoldingInstitutionIdentifier, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", schema = @Schema()) @RequestHeader(value = "X-User-Credential-1", required = false) String xUserCredential1, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", schema = @Schema()) @RequestHeader(value = "X-User-Credential-2", required = false) String xUserCredential2, @Parameter(in = ParameterIn.HEADER, description = "String containing the channel that was used to originate the request. For example USSD, Web, App.", schema = @Schema()) @RequestHeader(value = "X-Channel", required = false) String xChannel, @Parameter(in = ParameterIn.QUERY, description = "Supports pagination. If this is not supplied, then the server will apply a limit of 50 records returned for each request.", schema = @Schema()) @Valid @RequestParam(value = "limit", required = false) Integer limit, @Parameter(in = ParameterIn.QUERY, description = "Supports pagination. This value will indicate the cursor position from where to retrieve the set of records. For example, a limit of 50 and offset of 10 will return records 11 to 60.", schema = @Schema()) @Valid @RequestParam(value = "offset", required = false) Integer offset) { + String accept = request.getHeader("Accept"); + if (accept != null && accept.contains("application/json")) { + try { + return new ResponseEntity>(objectMapper.readValue("[ {\n \"supplementaryServiceProviderDetails\" : [ {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n } ],\n \"companyName\" : \"companyName\",\n \"serviceProvider\" : \"serviceProvider\",\n \"serviceProviderSubType\" : \"serviceProviderSubType\",\n \"serviceProviderType\" : \"serviceProviderType\"\n}, {\n \"supplementaryServiceProviderDetails\" : [ {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n } ],\n \"companyName\" : \"companyName\",\n \"serviceProvider\" : \"serviceProvider\",\n \"serviceProviderSubType\" : \"serviceProviderSubType\",\n \"serviceProviderType\" : \"serviceProviderType\"\n} ]", List.class), HttpStatus.OK); + } catch (IOException e) { + log.error("Couldn't serialize response for content type application/json", e); + return new ResponseEntity>(HttpStatus.INTERNAL_SERVER_ERROR); + } + } + + return new ResponseEntity>(HttpStatus.OK); + } + + public ResponseEntity accountsAccountIdBillsBillPaymentsGET(@Pattern(regexp = "^((accountcategory|bankaccountno|accountrank|identityalias|iban|accountid|msisdn|swiftbic|sortcode|organisationid|username|walletid|linkref|consumerno|serviceprovider|storeid|bankname|bankaccounttitle|emailaddress|mandatereference)@([^$\\n]+))(\\$(accountcategory|bankaccountno|accountrank|identityalias|iban|accountid|msisdn|swiftbic|sortcode|organisationid|username|walletid|linkref|consumerno|serviceprovider|storeid|bankname|bankaccounttitle|emailaddress|mandatereference)@([^$\\n]+)){0,2}$") @Parameter(in = ParameterIn.PATH, description = "Path variable to uniquely identify an account. Up to three account identifiers can be supplied. Identifiers are delimited by $ and values are delimited by @. Example: organisationid@1234$accountid@3333. Valid account identifiers are accountcategory, bankaccountno, accountrank, identityalias, iban, accountid, msisdn, swiftbic, sortcode, organisationid, username, walletid, linkref, consumerno, serviceprovider, storeid, bankname, bankaccounttitle, emailaddress, mandatereference.", required = true, schema = @Schema()) @PathVariable("accountId") String accountId, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API.", schema = @Schema()) @RequestHeader(value = "X-Date", required = false) OffsetDateTime xDate, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's API key to the server.", schema = @Schema()) @RequestHeader(value = "X-API-Key", required = false) String xAPIKey, @Parameter(in = ParameterIn.HEADER, description = "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication.", schema = @Schema()) @RequestHeader(value = "X-User-Bearer", required = false) String xUserBearer, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's identifier to the server.", schema = @Schema()) @RequestHeader(value = "X-Client-Id", required = false) String xClientId, @Parameter(in = ParameterIn.HEADER, description = "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed.", schema = @Schema()) @RequestHeader(value = "X-Content-Hash", required = false) String xContentHash, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", schema = @Schema()) @RequestHeader(value = "X-User-Credential-1", required = false) String xUserCredential1, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", schema = @Schema()) @RequestHeader(value = "X-User-Credential-2", required = false) String xUserCredential2, @Parameter(in = ParameterIn.HEADER, description = "String containing the channel that was used to originate the request. For example USSD, Web, App.", schema = @Schema()) @RequestHeader(value = "X-Channel", required = false) String xChannel, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header.", schema = @Schema(allowableValues = {"lei", "swiftbic", "organisationid"} + )) @RequestHeader(value = "X-Account-Holding-Institution-Identifier-Type", required = false) String xAccountHoldingInstitutionIdentifierType, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header.", schema = @Schema()) @RequestHeader(value = "X-Account-Holding-Institution-Identifier", required = false) String xAccountHoldingInstitutionIdentifier, @Parameter(in = ParameterIn.QUERY, description = "Supports pagination. If this is not supplied, then the server will apply a limit of 50 records returned for each request.", schema = @Schema()) @Valid @RequestParam(value = "limit", required = false) Integer limit, @Parameter(in = ParameterIn.QUERY, description = "Supports pagination. This value will indicate the cursor position from where to retrieve the set of records. For example, a limit of 50 and offset of 10 will return records 11 to 60.", schema = @Schema()) @Valid @RequestParam(value = "offset", required = false) Integer offset, @Parameter(in = ParameterIn.QUERY, description = "Indicates the minimum creation date for which records should be returned.", schema = @Schema()) @Valid @RequestParam(value = "fromDateTime", required = false) OffsetDateTime fromDateTime, @Parameter(in = ParameterIn.QUERY, description = "Indicates the maximum creation date for which records should be returned.", schema = @Schema()) @Valid @RequestParam(value = "toDateTime", required = false) OffsetDateTime toDateTime) { + String accept = request.getHeader("Accept"); + if (accept != null && accept.contains("application/json")) { + try { + return new ResponseEntity(objectMapper.readValue("{\n \"serviceProviderNotification\" : \"serviceProviderNotification\",\n \"metadata\" : [ {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n } ],\n \"requestingOrganisation\" : \"requestingOrganisation\",\n \"customData\" : [ {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n } ],\n \"creationDate\" : \"2000-01-23T04:56:07.000+00:00\",\n \"paymentType\" : \"partialpayment\",\n \"modificationDate\" : \"2000-01-23T04:56:07.000+00:00\",\n \"billPaymentStatus\" : \"billPaymentStatus\",\n \"amountPaid\" : \"15.21\",\n \"customerReference\" : \"customerReference\",\n \"requestDate\" : \"2000-01-23T04:56:07.000+00:00\",\n \"requestingOrganisationTransactionReference\" : \"requestingOrganisationTransactionReference\",\n \"currency\" : \"AED\",\n \"serviceProviderPaymentReference\" : \"serviceProviderPaymentReference\",\n \"serviceProviderComment\" : \"serviceProviderComment\"\n}", ResponseBillPayment2.class), HttpStatus.OK); + } catch (IOException e) { + log.error("Couldn't serialize response for content type application/json", e); + return new ResponseEntity(HttpStatus.INTERNAL_SERVER_ERROR); + } + } + + return new ResponseEntity(HttpStatus.OK); + } + + public ResponseEntity accountsAccountIdBillsBillPaymentsPOST(@Pattern(regexp = "^((accountcategory|bankaccountno|accountrank|identityalias|iban|accountid|msisdn|swiftbic|sortcode|organisationid|username|walletid|linkref|consumerno|serviceprovider|storeid|bankname|bankaccounttitle|emailaddress|mandatereference)@([^$\\n]+))(\\$(accountcategory|bankaccountno|accountrank|identityalias|iban|accountid|msisdn|swiftbic|sortcode|organisationid|username|walletid|linkref|consumerno|serviceprovider|storeid|bankname|bankaccounttitle|emailaddress|mandatereference)@([^$\\n]+)){0,2}$") @Parameter(in = ParameterIn.PATH, description = "Path variable to uniquely identify an account. Up to three account identifiers can be supplied. Identifiers are delimited by $ and values are delimited by @. Example: organisationid@1234$accountid@3333. Valid account identifiers are accountcategory, bankaccountno, accountrank, identityalias, iban, accountid, msisdn, swiftbic, sortcode, organisationid, username, walletid, linkref, consumerno, serviceprovider, storeid, bankname, bankaccounttitle, emailaddress, mandatereference.", required = true, schema = @Schema()) @PathVariable("accountId") String accountId, @Parameter(in = ParameterIn.DEFAULT, description = "Represents the request body of a bill payment.", required = true, schema = @Schema()) @Valid @RequestBody RequestBillPayment2 body, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API.", schema = @Schema()) @RequestHeader(value = "X-Date", required = false) OffsetDateTime xDate, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to uniquely identify the request. Must be supplied as a UUID.", schema = @Schema()) @RequestHeader(value = "X-CorrelationID", required = false) String xCorrelationID, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's API key to the server.", schema = @Schema()) @RequestHeader(value = "X-API-Key", required = false) String xAPIKey, @Parameter(in = ParameterIn.HEADER, description = "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication.", schema = @Schema()) @RequestHeader(value = "X-User-Bearer", required = false) String xUserBearer, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's identifier to the server.", schema = @Schema()) @RequestHeader(value = "X-Client-Id", required = false) String xClientId, @Parameter(in = ParameterIn.HEADER, description = "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed.", schema = @Schema()) @RequestHeader(value = "X-Content-Hash", required = false) String xContentHash, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", schema = @Schema()) @RequestHeader(value = "X-User-Credential-1", required = false) String xUserCredential1, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", schema = @Schema()) @RequestHeader(value = "X-User-Credential-2", required = false) String xUserCredential2, @Parameter(in = ParameterIn.HEADER, description = "String containing the channel that was used to originate the request. For example USSD, Web, App.", schema = @Schema()) @RequestHeader(value = "X-Channel", required = false) String xChannel, @Parameter(in = ParameterIn.HEADER, description = "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT.", schema = @Schema()) @RequestHeader(value = "X-Callback-URL", required = false) String xCallbackURL, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header.", schema = @Schema(allowableValues = {"lei", "swiftbic", "organisationid"} + )) @RequestHeader(value = "X-Account-Holding-Institution-Identifier-Type", required = false) String xAccountHoldingInstitutionIdentifierType, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header.", schema = @Schema()) @RequestHeader(value = "X-Account-Holding-Institution-Identifier", required = false) String xAccountHoldingInstitutionIdentifier) { + String accept = request.getHeader("Accept"); + if (accept != null && accept.contains("application/json")) { + try { + return new ResponseEntity(objectMapper.readValue("{\n \"serviceProviderNotification\" : \"serviceProviderNotification\",\n \"metadata\" : [ {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n } ],\n \"requestingOrganisation\" : \"requestingOrganisation\",\n \"customData\" : [ {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n } ],\n \"creationDate\" : \"2000-01-23T04:56:07.000+00:00\",\n \"paymentType\" : \"partialpayment\",\n \"modificationDate\" : \"2000-01-23T04:56:07.000+00:00\",\n \"billPaymentStatus\" : \"billPaymentStatus\",\n \"amountPaid\" : \"15.21\",\n \"customerReference\" : \"customerReference\",\n \"requestDate\" : \"2000-01-23T04:56:07.000+00:00\",\n \"requestingOrganisationTransactionReference\" : \"requestingOrganisationTransactionReference\",\n \"currency\" : \"AED\",\n \"serviceProviderPaymentReference\" : \"serviceProviderPaymentReference\",\n \"serviceProviderComment\" : \"serviceProviderComment\"\n}", ResponseBillPayment2.class), HttpStatus.OK); + } catch (IOException e) { + log.error("Couldn't serialize response for content type application/json", e); + return new ResponseEntity(HttpStatus.INTERNAL_SERVER_ERROR); + } + } + + return new ResponseEntity(HttpStatus.OK); + } + + public ResponseEntity accountsAccountIdBillsBillReferencePaymentsGET(@Pattern(regexp = "^((accountcategory|bankaccountno|accountrank|identityalias|iban|accountid|msisdn|swiftbic|sortcode|organisationid|username|walletid|linkref|consumerno|serviceprovider|storeid|bankname|bankaccounttitle|emailaddress|mandatereference)@([^$\\n]+))(\\$(accountcategory|bankaccountno|accountrank|identityalias|iban|accountid|msisdn|swiftbic|sortcode|organisationid|username|walletid|linkref|consumerno|serviceprovider|storeid|bankname|bankaccounttitle|emailaddress|mandatereference)@([^$\\n]+)){0,2}$") @Parameter(in = ParameterIn.PATH, description = "Path variable to uniquely identify an account. Up to three account identifiers can be supplied. Identifiers are delimited by $ and values are delimited by @. Example: organisationid@1234$accountid@3333. Valid account identifiers are accountcategory, bankaccountno, accountrank, identityalias, iban, accountid, msisdn, swiftbic, sortcode, organisationid, username, walletid, linkref, consumerno, serviceprovider, storeid, bankname, bankaccounttitle, emailaddress, mandatereference.", required = true, schema = @Schema()) @PathVariable("accountId") String accountId, @Size(min = 1, max = 256) @Parameter(in = ParameterIn.PATH, description = "Path variable to uniquely identify a bill.", required = true, schema = @Schema()) @PathVariable("billReference") String billReference, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API.", schema = @Schema()) @RequestHeader(value = "X-Date", required = false) OffsetDateTime xDate, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's API key to the server.", schema = @Schema()) @RequestHeader(value = "X-API-Key", required = false) String xAPIKey, @Parameter(in = ParameterIn.HEADER, description = "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication.", schema = @Schema()) @RequestHeader(value = "X-User-Bearer", required = false) String xUserBearer, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's identifier to the server.", schema = @Schema()) @RequestHeader(value = "X-Client-Id", required = false) String xClientId, @Parameter(in = ParameterIn.HEADER, description = "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed.", schema = @Schema()) @RequestHeader(value = "X-Content-Hash", required = false) String xContentHash, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", schema = @Schema()) @RequestHeader(value = "X-User-Credential-1", required = false) String xUserCredential1, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", schema = @Schema()) @RequestHeader(value = "X-User-Credential-2", required = false) String xUserCredential2, @Parameter(in = ParameterIn.HEADER, description = "String containing the channel that was used to originate the request. For example USSD, Web, App.", schema = @Schema()) @RequestHeader(value = "X-Channel", required = false) String xChannel, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header.", schema = @Schema(allowableValues = {"lei", "swiftbic", "organisationid"} + )) @RequestHeader(value = "X-Account-Holding-Institution-Identifier-Type", required = false) String xAccountHoldingInstitutionIdentifierType, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header.", schema = @Schema()) @RequestHeader(value = "X-Account-Holding-Institution-Identifier", required = false) String xAccountHoldingInstitutionIdentifier, @Parameter(in = ParameterIn.QUERY, description = "Supports pagination. If this is not supplied, then the server will apply a limit of 50 records returned for each request.", schema = @Schema()) @Valid @RequestParam(value = "limit", required = false) Integer limit, @Parameter(in = ParameterIn.QUERY, description = "Supports pagination. This value will indicate the cursor position from where to retrieve the set of records. For example, a limit of 50 and offset of 10 will return records 11 to 60.", schema = @Schema()) @Valid @RequestParam(value = "offset", required = false) Integer offset, @Parameter(in = ParameterIn.QUERY, description = "Indicates the minimum creation date for which records should be returned.", schema = @Schema()) @Valid @RequestParam(value = "fromDateTime", required = false) OffsetDateTime fromDateTime, @Parameter(in = ParameterIn.QUERY, description = "Indicates the maximum creation date for which records should be returned.", schema = @Schema()) @Valid @RequestParam(value = "toDateTime", required = false) OffsetDateTime toDateTime) { + String accept = request.getHeader("Accept"); + if (accept != null && accept.contains("application/json")) { + try { + return new ResponseEntity(objectMapper.readValue("{\n \"supplementaryBillReferenceDetails\" : [ {\n \"paymentReferenceType\" : \"paymentReferenceType\",\n \"paymentReferenceValue\" : \"paymentReferenceValue\"\n }, {\n \"paymentReferenceType\" : \"paymentReferenceType\",\n \"paymentReferenceValue\" : \"paymentReferenceValue\"\n }, {\n \"paymentReferenceType\" : \"paymentReferenceType\",\n \"paymentReferenceValue\" : \"paymentReferenceValue\"\n }, {\n \"paymentReferenceType\" : \"paymentReferenceType\",\n \"paymentReferenceValue\" : \"paymentReferenceValue\"\n }, {\n \"paymentReferenceType\" : \"paymentReferenceType\",\n \"paymentReferenceValue\" : \"paymentReferenceValue\"\n }, {\n \"paymentReferenceType\" : \"paymentReferenceType\",\n \"paymentReferenceValue\" : \"paymentReferenceValue\"\n }, {\n \"paymentReferenceType\" : \"paymentReferenceType\",\n \"paymentReferenceValue\" : \"paymentReferenceValue\"\n }, {\n \"paymentReferenceType\" : \"paymentReferenceType\",\n \"paymentReferenceValue\" : \"paymentReferenceValue\"\n }, {\n \"paymentReferenceType\" : \"paymentReferenceType\",\n \"paymentReferenceValue\" : \"paymentReferenceValue\"\n }, {\n \"paymentReferenceType\" : \"paymentReferenceType\",\n \"paymentReferenceValue\" : \"paymentReferenceValue\"\n } ],\n \"serviceProviderNotification\" : \"serviceProviderNotification\",\n \"metadata\" : [ {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n } ],\n \"requestingOrganisation\" : \"requestingOrganisation\",\n \"customData\" : [ {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n } ],\n \"creationDate\" : \"2000-01-23T04:56:07.000+00:00\",\n \"paymentType\" : \"partialpayment\",\n \"modificationDate\" : \"2000-01-23T04:56:07.000+00:00\",\n \"billPaymentStatus\" : \"billPaymentStatus\",\n \"amountPaid\" : \"15.21\",\n \"customerReference\" : \"customerReference\",\n \"requestDate\" : \"2000-01-23T04:56:07.000+00:00\",\n \"requestingOrganisationTransactionReference\" : \"requestingOrganisationTransactionReference\",\n \"currency\" : \"AED\",\n \"serviceProviderPaymentReference\" : \"serviceProviderPaymentReference\",\n \"serviceProviderComment\" : \"serviceProviderComment\"\n}", ResponseBillPayment.class), HttpStatus.OK); + } catch (IOException e) { + log.error("Couldn't serialize response for content type application/json", e); + return new ResponseEntity(HttpStatus.INTERNAL_SERVER_ERROR); + } + } + + return new ResponseEntity(HttpStatus.OK); + } + + public ResponseEntity accountsAccountIdBillsBillReferencePaymentsPOST(@Pattern(regexp = "^((accountcategory|bankaccountno|accountrank|identityalias|iban|accountid|msisdn|swiftbic|sortcode|organisationid|username|walletid|linkref|consumerno|serviceprovider|storeid|bankname|bankaccounttitle|emailaddress|mandatereference)@([^$\\n]+))(\\$(accountcategory|bankaccountno|accountrank|identityalias|iban|accountid|msisdn|swiftbic|sortcode|organisationid|username|walletid|linkref|consumerno|serviceprovider|storeid|bankname|bankaccounttitle|emailaddress|mandatereference)@([^$\\n]+)){0,2}$") @Parameter(in = ParameterIn.PATH, description = "Path variable to uniquely identify an account. Up to three account identifiers can be supplied. Identifiers are delimited by $ and values are delimited by @. Example: organisationid@1234$accountid@3333. Valid account identifiers are accountcategory, bankaccountno, accountrank, identityalias, iban, accountid, msisdn, swiftbic, sortcode, organisationid, username, walletid, linkref, consumerno, serviceprovider, storeid, bankname, bankaccounttitle, emailaddress, mandatereference.", required = true, schema = @Schema()) @PathVariable("accountId") String accountId, @Size(min = 1, max = 256) @Parameter(in = ParameterIn.PATH, description = "Path variable to uniquely identify a bill.", required = true, schema = @Schema()) @PathVariable("billReference") String billReference, @Parameter(in = ParameterIn.DEFAULT, description = "Represents the request body of a bill payment.", required = true, schema = @Schema()) @Valid @RequestBody RequestBillPayment body, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API.", schema = @Schema()) @RequestHeader(value = "X-Date", required = false) OffsetDateTime xDate, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to uniquely identify the request. Must be supplied as a UUID.", schema = @Schema()) @RequestHeader(value = "X-CorrelationID", required = false) String xCorrelationID, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's API key to the server.", schema = @Schema()) @RequestHeader(value = "X-API-Key", required = false) String xAPIKey, @Parameter(in = ParameterIn.HEADER, description = "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication.", schema = @Schema()) @RequestHeader(value = "X-User-Bearer", required = false) String xUserBearer, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's identifier to the server.", schema = @Schema()) @RequestHeader(value = "X-Client-Id", required = false) String xClientId, @Parameter(in = ParameterIn.HEADER, description = "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed.", schema = @Schema()) @RequestHeader(value = "X-Content-Hash", required = false) String xContentHash, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", schema = @Schema()) @RequestHeader(value = "X-User-Credential-1", required = false) String xUserCredential1, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", schema = @Schema()) @RequestHeader(value = "X-User-Credential-2", required = false) String xUserCredential2, @Parameter(in = ParameterIn.HEADER, description = "String containing the channel that was used to originate the request. For example USSD, Web, App.", schema = @Schema()) @RequestHeader(value = "X-Channel", required = false) String xChannel, @Parameter(in = ParameterIn.HEADER, description = "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT.", schema = @Schema()) @RequestHeader(value = "X-Callback-URL", required = false) String xCallbackURL, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header.", schema = @Schema(allowableValues = {"lei", "swiftbic", "organisationid"} + )) @RequestHeader(value = "X-Account-Holding-Institution-Identifier-Type", required = false) String xAccountHoldingInstitutionIdentifierType, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header.", schema = @Schema()) @RequestHeader(value = "X-Account-Holding-Institution-Identifier", required = false) String xAccountHoldingInstitutionIdentifier) { + String accept = request.getHeader("Accept"); + if (accept != null && accept.contains("application/json")) { + try { + return new ResponseEntity(objectMapper.readValue("{\n \"supplementaryBillReferenceDetails\" : [ {\n \"paymentReferenceType\" : \"paymentReferenceType\",\n \"paymentReferenceValue\" : \"paymentReferenceValue\"\n }, {\n \"paymentReferenceType\" : \"paymentReferenceType\",\n \"paymentReferenceValue\" : \"paymentReferenceValue\"\n }, {\n \"paymentReferenceType\" : \"paymentReferenceType\",\n \"paymentReferenceValue\" : \"paymentReferenceValue\"\n }, {\n \"paymentReferenceType\" : \"paymentReferenceType\",\n \"paymentReferenceValue\" : \"paymentReferenceValue\"\n }, {\n \"paymentReferenceType\" : \"paymentReferenceType\",\n \"paymentReferenceValue\" : \"paymentReferenceValue\"\n }, {\n \"paymentReferenceType\" : \"paymentReferenceType\",\n \"paymentReferenceValue\" : \"paymentReferenceValue\"\n }, {\n \"paymentReferenceType\" : \"paymentReferenceType\",\n \"paymentReferenceValue\" : \"paymentReferenceValue\"\n }, {\n \"paymentReferenceType\" : \"paymentReferenceType\",\n \"paymentReferenceValue\" : \"paymentReferenceValue\"\n }, {\n \"paymentReferenceType\" : \"paymentReferenceType\",\n \"paymentReferenceValue\" : \"paymentReferenceValue\"\n }, {\n \"paymentReferenceType\" : \"paymentReferenceType\",\n \"paymentReferenceValue\" : \"paymentReferenceValue\"\n } ],\n \"serviceProviderNotification\" : \"serviceProviderNotification\",\n \"metadata\" : [ {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n } ],\n \"requestingOrganisation\" : \"requestingOrganisation\",\n \"customData\" : [ {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n } ],\n \"creationDate\" : \"2000-01-23T04:56:07.000+00:00\",\n \"paymentType\" : \"partialpayment\",\n \"modificationDate\" : \"2000-01-23T04:56:07.000+00:00\",\n \"billPaymentStatus\" : \"billPaymentStatus\",\n \"amountPaid\" : \"15.21\",\n \"customerReference\" : \"customerReference\",\n \"requestDate\" : \"2000-01-23T04:56:07.000+00:00\",\n \"requestingOrganisationTransactionReference\" : \"requestingOrganisationTransactionReference\",\n \"currency\" : \"AED\",\n \"serviceProviderPaymentReference\" : \"serviceProviderPaymentReference\",\n \"serviceProviderComment\" : \"serviceProviderComment\"\n}", ResponseBillPayment.class), HttpStatus.OK); + } catch (IOException e) { + log.error("Couldn't serialize response for content type application/json", e); + return new ResponseEntity(HttpStatus.INTERNAL_SERVER_ERROR); + } + } + + return new ResponseEntity(HttpStatus.OK); + } + + public ResponseEntity> accountsAccountIdBillsGET(@Pattern(regexp = "^((accountcategory|bankaccountno|accountrank|identityalias|iban|accountid|msisdn|swiftbic|sortcode|organisationid|username|walletid|linkref|consumerno|serviceprovider|storeid|bankname|bankaccounttitle|emailaddress|mandatereference)@([^$\\n]+))(\\$(accountcategory|bankaccountno|accountrank|identityalias|iban|accountid|msisdn|swiftbic|sortcode|organisationid|username|walletid|linkref|consumerno|serviceprovider|storeid|bankname|bankaccounttitle|emailaddress|mandatereference)@([^$\\n]+)){0,2}$") @Parameter(in = ParameterIn.PATH, description = "Path variable to uniquely identify an account. Up to three account identifiers can be supplied. Identifiers are delimited by $ and values are delimited by @. Example: organisationid@1234$accountid@3333. Valid account identifiers are accountcategory, bankaccountno, accountrank, identityalias, iban, accountid, msisdn, swiftbic, sortcode, organisationid, username, walletid, linkref, consumerno, serviceprovider, storeid, bankname, bankaccounttitle, emailaddress, mandatereference.", required = true, schema = @Schema()) @PathVariable("accountId") String accountId, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API.", schema = @Schema()) @RequestHeader(value = "X-Date", required = false) OffsetDateTime xDate, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's API key to the server.", schema = @Schema()) @RequestHeader(value = "X-API-Key", required = false) String xAPIKey, @Parameter(in = ParameterIn.HEADER, description = "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication.", schema = @Schema()) @RequestHeader(value = "X-User-Bearer", required = false) String xUserBearer, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's identifier to the server.", schema = @Schema()) @RequestHeader(value = "X-Client-Id", required = false) String xClientId, @Parameter(in = ParameterIn.HEADER, description = "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed.", schema = @Schema()) @RequestHeader(value = "X-Content-Hash", required = false) String xContentHash, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", schema = @Schema()) @RequestHeader(value = "X-User-Credential-1", required = false) String xUserCredential1, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", schema = @Schema()) @RequestHeader(value = "X-User-Credential-2", required = false) String xUserCredential2, @Parameter(in = ParameterIn.HEADER, description = "String containing the channel that was used to originate the request. For example USSD, Web, App.", schema = @Schema()) @RequestHeader(value = "X-Channel", required = false) String xChannel, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header.", schema = @Schema(allowableValues = {"lei", "swiftbic", "organisationid"} + )) @RequestHeader(value = "X-Account-Holding-Institution-Identifier-Type", required = false) String xAccountHoldingInstitutionIdentifierType, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header.", schema = @Schema()) @RequestHeader(value = "X-Account-Holding-Institution-Identifier", required = false) String xAccountHoldingInstitutionIdentifier, @Parameter(in = ParameterIn.QUERY, description = "Supports pagination. If this is not supplied, then the server will apply a limit of 50 records returned for each request.", schema = @Schema()) @Valid @RequestParam(value = "limit", required = false) Integer limit, @Parameter(in = ParameterIn.QUERY, description = "Supports pagination. This value will indicate the cursor position from where to retrieve the set of records. For example, a limit of 50 and offset of 10 will return records 11 to 60.", schema = @Schema()) @Valid @RequestParam(value = "offset", required = false) Integer offset, @Parameter(in = ParameterIn.QUERY, description = "Indicates the minimum creation date for which records should be returned.", schema = @Schema()) @Valid @RequestParam(value = "fromDateTime", required = false) OffsetDateTime fromDateTime, @Parameter(in = ParameterIn.QUERY, description = "Indicates the maximum creation date for which records should be returned.", schema = @Schema()) @Valid @RequestParam(value = "toDateTime", required = false) OffsetDateTime toDateTime) { + String accept = request.getHeader("Accept"); + if (accept != null && accept.contains("application/json")) { + try { + return new ResponseEntity>(objectMapper.readValue("[ {\n \"amountDue\" : \"15.21\",\n \"billdescription\" : \"billdescription\",\n \"modificationDate\" : \"2000-01-23T04:56:07.000+00:00\",\n \"metadata\" : [ {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n } ],\n \"dueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"billStatus\" : \"unpaid\",\n \"currency\" : \"AED\",\n \"customData\" : [ {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n } ],\n \"creationDate\" : \"2000-01-23T04:56:07.000+00:00\",\n \"billReference\" : \"billReference\"\n}, {\n \"amountDue\" : \"15.21\",\n \"billdescription\" : \"billdescription\",\n \"modificationDate\" : \"2000-01-23T04:56:07.000+00:00\",\n \"metadata\" : [ {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n } ],\n \"dueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"billStatus\" : \"unpaid\",\n \"currency\" : \"AED\",\n \"customData\" : [ {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n } ],\n \"creationDate\" : \"2000-01-23T04:56:07.000+00:00\",\n \"billReference\" : \"billReference\"\n} ]", List.class), HttpStatus.OK); + } catch (IOException e) { + log.error("Couldn't serialize response for content type application/json", e); + return new ResponseEntity>(HttpStatus.INTERNAL_SERVER_ERROR); + } + } + + return new ResponseEntity>(HttpStatus.OK); + } + + public ResponseEntity accountsAccountIdDebitmandatesDebitMandateReferenceGET(@Pattern(regexp = "^((accountcategory|bankaccountno|accountrank|identityalias|iban|accountid|msisdn|swiftbic|sortcode|organisationid|username|walletid|linkref|consumerno|serviceprovider|storeid|bankname|bankaccounttitle|emailaddress|mandatereference)@([^$\\n]+))(\\$(accountcategory|bankaccountno|accountrank|identityalias|iban|accountid|msisdn|swiftbic|sortcode|organisationid|username|walletid|linkref|consumerno|serviceprovider|storeid|bankname|bankaccounttitle|emailaddress|mandatereference)@([^$\\n]+)){0,2}$") @Parameter(in = ParameterIn.PATH, description = "Path variable to uniquely identify an account. Up to three account identifiers can be supplied. Identifiers are delimited by $ and values are delimited by @. Example: organisationid@1234$accountid@3333. Valid account identifiers are accountcategory, bankaccountno, accountrank, identityalias, iban, accountid, msisdn, swiftbic, sortcode, organisationid, username, walletid, linkref, consumerno, serviceprovider, storeid, bankname, bankaccounttitle, emailaddress, mandatereference.", required = true, schema = @Schema()) @PathVariable("accountId") String accountId, @Size(min = 1, max = 256) @Parameter(in = ParameterIn.PATH, description = "Path variable to uniquely identify a Debit Mandate Reference.", required = true, schema = @Schema()) @PathVariable("debitMandateReference") String debitMandateReference, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API.", schema = @Schema()) @RequestHeader(value = "X-Date", required = false) OffsetDateTime xDate, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's API key to the server.", schema = @Schema()) @RequestHeader(value = "X-API-Key", required = false) String xAPIKey, @Parameter(in = ParameterIn.HEADER, description = "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication.", schema = @Schema()) @RequestHeader(value = "X-User-Bearer", required = false) String xUserBearer, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's identifier to the server.", schema = @Schema()) @RequestHeader(value = "X-Client-Id", required = false) String xClientId, @Parameter(in = ParameterIn.HEADER, description = "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed.", schema = @Schema()) @RequestHeader(value = "X-Content-Hash", required = false) String xContentHash, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", schema = @Schema()) @RequestHeader(value = "X-User-Credential-1", required = false) String xUserCredential1, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", schema = @Schema()) @RequestHeader(value = "X-User-Credential-2", required = false) String xUserCredential2, @Parameter(in = ParameterIn.HEADER, description = "String containing the channel that was used to originate the request. For example USSD, Web, App.", schema = @Schema()) @RequestHeader(value = "X-Channel", required = false) String xChannel, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header.", schema = @Schema(allowableValues = {"lei", "swiftbic", "organisationid"} + )) @RequestHeader(value = "X-Account-Holding-Institution-Identifier-Type", required = false) String xAccountHoldingInstitutionIdentifierType, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header.", schema = @Schema()) @RequestHeader(value = "X-Account-Holding-Institution-Identifier", required = false) String xAccountHoldingInstitutionIdentifier) { + String accept = request.getHeader("Accept"); + if (accept != null && accept.contains("application/json")) { + try { + return new ResponseEntity(objectMapper.readValue("{\n \"amountLimit\" : \"15.21\",\n \"numberOfPayments\" : 0.08008281904610115,\n \"endDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"requestingOrganisation\" : {\n \"requestingOrganisationIdentifierType\" : \"lei\",\n \"requestingOrganisationIdentifier\" : \"requestingOrganisationIdentifier\"\n },\n \"customData\" : [ {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n } ],\n \"dateModified\" : \"2000-01-23T04:56:07.000+00:00\",\n \"creationDate\" : \"2000-01-23T04:56:07.000+00:00\",\n \"payee\" : [ {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n } ],\n \"mandateReference\" : \"mandateReference\",\n \"modificationDate\" : \"2000-01-23T04:56:07.000+00:00\",\n \"dateCreated\" : \"2000-01-23T04:56:07.000+00:00\",\n \"mandateStatus\" : \"active\",\n \"frequencyType\" : \"weekly\",\n \"requestDate\" : \"2000-01-23T04:56:07.000+00:00\",\n \"currency\" : \"AED\",\n \"startDate\" : \"2018-11-20T00:00:00.000+00:00\"\n}", ResponseDebitMandate.class), HttpStatus.OK); + } catch (IOException e) { + log.error("Couldn't serialize response for content type application/json", e); + return new ResponseEntity(HttpStatus.INTERNAL_SERVER_ERROR); + } + } + + return new ResponseEntity(HttpStatus.OK); + } + + public ResponseEntity accountsAccountIdDebitmandatesDebitMandateReferencePATCH(@Pattern(regexp = "^((accountcategory|bankaccountno|accountrank|identityalias|iban|accountid|msisdn|swiftbic|sortcode|organisationid|username|walletid|linkref|consumerno|serviceprovider|storeid|bankname|bankaccounttitle|emailaddress|mandatereference)@([^$\\n]+))(\\$(accountcategory|bankaccountno|accountrank|identityalias|iban|accountid|msisdn|swiftbic|sortcode|organisationid|username|walletid|linkref|consumerno|serviceprovider|storeid|bankname|bankaccounttitle|emailaddress|mandatereference)@([^$\\n]+)){0,2}$") @Parameter(in = ParameterIn.PATH, description = "Path variable to uniquely identify an account. Up to three account identifiers can be supplied. Identifiers are delimited by $ and values are delimited by @. Example: organisationid@1234$accountid@3333. Valid account identifiers are accountcategory, bankaccountno, accountrank, identityalias, iban, accountid, msisdn, swiftbic, sortcode, organisationid, username, walletid, linkref, consumerno, serviceprovider, storeid, bankname, bankaccounttitle, emailaddress, mandatereference.", required = true, schema = @Schema()) @PathVariable("accountId") String accountId, @Size(min = 1, max = 256) @Parameter(in = ParameterIn.PATH, description = "Path variable to uniquely identify a Debit Mandate Reference.", required = true, schema = @Schema()) @PathVariable("debitMandateReference") String debitMandateReference, @Parameter(in = ParameterIn.DEFAULT, description = "Represents the request body of a batch of generic Patch operation.", required = true, schema = @Schema()) @Valid @RequestBody List body, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API.", schema = @Schema()) @RequestHeader(value = "X-Date", required = false) OffsetDateTime xDate, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's API key to the server.", schema = @Schema()) @RequestHeader(value = "X-API-Key", required = false) String xAPIKey, @Parameter(in = ParameterIn.HEADER, description = "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication.", schema = @Schema()) @RequestHeader(value = "X-User-Bearer", required = false) String xUserBearer, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's identifier to the server.", schema = @Schema()) @RequestHeader(value = "X-Client-Id", required = false) String xClientId, @Parameter(in = ParameterIn.HEADER, description = "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed.", schema = @Schema()) @RequestHeader(value = "X-Content-Hash", required = false) String xContentHash, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", schema = @Schema()) @RequestHeader(value = "X-User-Credential-1", required = false) String xUserCredential1, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", schema = @Schema()) @RequestHeader(value = "X-User-Credential-2", required = false) String xUserCredential2, @Parameter(in = ParameterIn.HEADER, description = "String containing the channel that was used to originate the request. For example USSD, Web, App.", schema = @Schema()) @RequestHeader(value = "X-Channel", required = false) String xChannel, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header.", schema = @Schema(allowableValues = {"lei", "swiftbic", "organisationid"} + )) @RequestHeader(value = "X-Account-Holding-Institution-Identifier-Type", required = false) String xAccountHoldingInstitutionIdentifierType, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header.", schema = @Schema()) @RequestHeader(value = "X-Account-Holding-Institution-Identifier", required = false) String xAccountHoldingInstitutionIdentifier, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to uniquely identify the request. Must be supplied as a UUID.", schema = @Schema()) @RequestHeader(value = "X-CorrelationID", required = false) String xCorrelationID, @Parameter(in = ParameterIn.HEADER, description = "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT.", schema = @Schema()) @RequestHeader(value = "X-Callback-URL", required = false) String xCallbackURL) { + String accept = request.getHeader("Accept"); + if (accept != null && accept.contains("application/json")) { + try { + return new ResponseEntity(objectMapper.readValue("{\n \"pollLimit\" : 0.08008281904610115,\n \"pendingReason\" : \"pendingReason\",\n \"expiryTime\" : \"2000-01-23T04:56:07.000+00:00\",\n \"objectReference\" : \"objectReference\",\n \"notificationMethod\" : \"callback\",\n \"error\" : {\n \"errordescription\" : \"errordescription\",\n \"errorCategory\" : \"businessRule\",\n \"errorParameters\" : [ {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n } ],\n \"errorDateTime\" : \"2000-01-23T04:56:07.000+00:00\",\n \"errorCode\" : \"genericError\"\n },\n \"serverCorrelationId\" : \"serverCorrelationId\",\n \"status\" : \"pending\"\n}", RequestStateObject.class), HttpStatus.OK); + } catch (IOException e) { + log.error("Couldn't serialize response for content type application/json", e); + return new ResponseEntity(HttpStatus.INTERNAL_SERVER_ERROR); + } + } + + return new ResponseEntity(HttpStatus.OK); + } + + public ResponseEntity accountsAccountIdDebitmandatesPOST(@Pattern(regexp = "^((accountcategory|bankaccountno|accountrank|identityalias|iban|accountid|msisdn|swiftbic|sortcode|organisationid|username|walletid|linkref|consumerno|serviceprovider|storeid|bankname|bankaccounttitle|emailaddress|mandatereference)@([^$\\n]+))(\\$(accountcategory|bankaccountno|accountrank|identityalias|iban|accountid|msisdn|swiftbic|sortcode|organisationid|username|walletid|linkref|consumerno|serviceprovider|storeid|bankname|bankaccounttitle|emailaddress|mandatereference)@([^$\\n]+)){0,2}$") @Parameter(in = ParameterIn.PATH, description = "Path variable to uniquely identify an account. Up to three account identifiers can be supplied. Identifiers are delimited by $ and values are delimited by @. Example: organisationid@1234$accountid@3333. Valid account identifiers are accountcategory, bankaccountno, accountrank, identityalias, iban, accountid, msisdn, swiftbic, sortcode, organisationid, username, walletid, linkref, consumerno, serviceprovider, storeid, bankname, bankaccounttitle, emailaddress, mandatereference.", required = true, schema = @Schema()) @PathVariable("accountId") String accountId, @Parameter(in = ParameterIn.DEFAULT, description = "Represents the request body of a debit mandate.", required = true, schema = @Schema()) @Valid @RequestBody RequestDebitMandate body, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API.", schema = @Schema()) @RequestHeader(value = "X-Date", required = false) OffsetDateTime xDate, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to uniquely identify the request. Must be supplied as a UUID.", schema = @Schema()) @RequestHeader(value = "X-CorrelationID", required = false) String xCorrelationID, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's API key to the server.", schema = @Schema()) @RequestHeader(value = "X-API-Key", required = false) String xAPIKey, @Parameter(in = ParameterIn.HEADER, description = "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication.", schema = @Schema()) @RequestHeader(value = "X-User-Bearer", required = false) String xUserBearer, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's identifier to the server.", schema = @Schema()) @RequestHeader(value = "X-Client-Id", required = false) String xClientId, @Parameter(in = ParameterIn.HEADER, description = "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed.", schema = @Schema()) @RequestHeader(value = "X-Content-Hash", required = false) String xContentHash, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", schema = @Schema()) @RequestHeader(value = "X-User-Credential-1", required = false) String xUserCredential1, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", schema = @Schema()) @RequestHeader(value = "X-User-Credential-2", required = false) String xUserCredential2, @Parameter(in = ParameterIn.HEADER, description = "String containing the channel that was used to originate the request. For example USSD, Web, App.", schema = @Schema()) @RequestHeader(value = "X-Channel", required = false) String xChannel, @Parameter(in = ParameterIn.HEADER, description = "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT.", schema = @Schema()) @RequestHeader(value = "X-Callback-URL", required = false) String xCallbackURL, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header.", schema = @Schema(allowableValues = {"lei", "swiftbic", "organisationid"} + )) @RequestHeader(value = "X-Account-Holding-Institution-Identifier-Type", required = false) String xAccountHoldingInstitutionIdentifierType, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header.", schema = @Schema()) @RequestHeader(value = "X-Account-Holding-Institution-Identifier", required = false) String xAccountHoldingInstitutionIdentifier) { + String accept = request.getHeader("Accept"); + if (accept != null && accept.contains("application/json")) { + try { + return new ResponseEntity(objectMapper.readValue("{\n \"amountLimit\" : \"15.21\",\n \"numberOfPayments\" : 0.08008281904610115,\n \"endDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"requestingOrganisation\" : {\n \"requestingOrganisationIdentifierType\" : \"lei\",\n \"requestingOrganisationIdentifier\" : \"requestingOrganisationIdentifier\"\n },\n \"customData\" : [ {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n } ],\n \"dateModified\" : \"2000-01-23T04:56:07.000+00:00\",\n \"creationDate\" : \"2000-01-23T04:56:07.000+00:00\",\n \"payee\" : [ {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n } ],\n \"mandateReference\" : \"mandateReference\",\n \"modificationDate\" : \"2000-01-23T04:56:07.000+00:00\",\n \"dateCreated\" : \"2000-01-23T04:56:07.000+00:00\",\n \"mandateStatus\" : \"active\",\n \"frequencyType\" : \"weekly\",\n \"requestDate\" : \"2000-01-23T04:56:07.000+00:00\",\n \"currency\" : \"AED\",\n \"startDate\" : \"2018-11-20T00:00:00.000+00:00\"\n}", ResponseDebitMandate.class), HttpStatus.OK); + } catch (IOException e) { + log.error("Couldn't serialize response for content type application/json", e); + return new ResponseEntity(HttpStatus.INTERNAL_SERVER_ERROR); + } + } + + return new ResponseEntity(HttpStatus.OK); + } + + public ResponseEntity accountsAccountIdGET(@Pattern(regexp = "^((accountcategory|bankaccountno|accountrank|identityalias|iban|accountid|msisdn|swiftbic|sortcode|organisationid|username|walletid|linkref|consumerno|serviceprovider|storeid|bankname|bankaccounttitle|emailaddress|mandatereference)@([^$\\n]+))(\\$(accountcategory|bankaccountno|accountrank|identityalias|iban|accountid|msisdn|swiftbic|sortcode|organisationid|username|walletid|linkref|consumerno|serviceprovider|storeid|bankname|bankaccounttitle|emailaddress|mandatereference)@([^$\\n]+)){0,2}$") @Parameter(in = ParameterIn.PATH, description = "Path variable to uniquely identify an account. Up to three account identifiers can be supplied. Identifiers are delimited by $ and values are delimited by @. Example: organisationid@1234$accountid@3333. Valid account identifiers are accountcategory, bankaccountno, accountrank, identityalias, iban, accountid, msisdn, swiftbic, sortcode, organisationid, username, walletid, linkref, consumerno, serviceprovider, storeid, bankname, bankaccounttitle, emailaddress, mandatereference.", required = true, schema = @Schema()) @PathVariable("accountId") String accountId, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API.", schema = @Schema()) @RequestHeader(value = "X-Date", required = false) OffsetDateTime xDate, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's API key to the server.", schema = @Schema()) @RequestHeader(value = "X-API-Key", required = false) String xAPIKey, @Parameter(in = ParameterIn.HEADER, description = "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication.", schema = @Schema()) @RequestHeader(value = "X-User-Bearer", required = false) String xUserBearer, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's identifier to the server.", schema = @Schema()) @RequestHeader(value = "X-Client-Id", required = false) String xClientId, @Parameter(in = ParameterIn.HEADER, description = "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed.", schema = @Schema()) @RequestHeader(value = "X-Content-Hash", required = false) String xContentHash, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", schema = @Schema()) @RequestHeader(value = "X-User-Credential-1", required = false) String xUserCredential1, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", schema = @Schema()) @RequestHeader(value = "X-User-Credential-2", required = false) String xUserCredential2, @Parameter(in = ParameterIn.HEADER, description = "String containing the channel that was used to originate the request. For example USSD, Web, App.", schema = @Schema()) @RequestHeader(value = "X-Channel", required = false) String xChannel, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header.", schema = @Schema(allowableValues = {"lei", "swiftbic", "organisationid"} + )) @RequestHeader(value = "X-Account-Holding-Institution-Identifier-Type", required = false) String xAccountHoldingInstitutionIdentifierType, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header.", schema = @Schema()) @RequestHeader(value = "X-Account-Holding-Institution-Identifier", required = false) String xAccountHoldingInstitutionIdentifier) { + String accept = request.getHeader("Accept"); + if (accept != null && accept.contains("application/json")) { + try { + return new ResponseEntity(objectMapper.readValue("{\n \"fees\" : [ {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n } ],\n \"commissionEarned\" : [ {\n \"commissionType\" : \"commissionType\"\n }, {\n \"commissionType\" : \"commissionType\"\n }, {\n \"commissionType\" : \"commissionType\"\n }, {\n \"commissionType\" : \"commissionType\"\n }, {\n \"commissionType\" : \"commissionType\"\n }, {\n \"commissionType\" : \"commissionType\"\n }, {\n \"commissionType\" : \"commissionType\"\n }, {\n \"commissionType\" : \"commissionType\"\n }, {\n \"commissionType\" : \"commissionType\"\n }, {\n \"commissionType\" : \"commissionType\"\n } ],\n \"accountType\" : \"accountType\",\n \"currentBalance\" : \"15.21\",\n \"creationDate\" : \"2000-01-23T04:56:07.000+00:00\",\n \"accountStatus\" : \"available\",\n \"registeringEntity\" : \"registeringEntity\",\n \"modificationDate\" : \"2000-01-23T04:56:07.000+00:00\",\n \"identity\" : [ {\n \"kycLevel\" : 1,\n \"identityType\" : \"individual\",\n \"identityId\" : \"identityId\",\n \"identityStatus\" : \"identityStatus\",\n \"accountRelationship\" : \"accountholder\",\n \"customData\" : [ {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n } ],\n \"identityKyc\" : {\n \"emailAddress\" : \"emailAddress\",\n \"occupation\" : \"occupation\",\n \"postalAddress\" : {\n \"city\" : \"city\",\n \"postalCode\" : \"postalCode\",\n \"addressLine1\" : \"addressLine1\",\n \"stateProvince\" : \"stateProvince\",\n \"addressLine2\" : \"addressLine2\",\n \"addressLine3\" : \"addressLine3\"\n },\n \"gender\" : \"m\",\n \"idDocument\" : [ {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n } ],\n \"employerName\" : \"employerName\",\n \"dateOfBirth\" : \"2000-11-20T00:00:00.000+00:00\",\n \"contactPhone\" : \"contactPhone\",\n \"subjectName\" : {\n \"firstName\" : \"firstName\",\n \"lastName\" : \"lastName\",\n \"nativeName\" : \"nativeName\",\n \"fullName\" : \"fullName\",\n \"middleName\" : \"middleName\",\n \"title\" : \"title\"\n }\n },\n \"kycVerificationStatus\" : \"verified\",\n \"kycVerificationEntity\" : \"kycVerificationEntity\"\n }, {\n \"kycLevel\" : 1,\n \"identityType\" : \"individual\",\n \"identityId\" : \"identityId\",\n \"identityStatus\" : \"identityStatus\",\n \"accountRelationship\" : \"accountholder\",\n \"customData\" : [ {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n } ],\n \"identityKyc\" : {\n \"emailAddress\" : \"emailAddress\",\n \"occupation\" : \"occupation\",\n \"postalAddress\" : {\n \"city\" : \"city\",\n \"postalCode\" : \"postalCode\",\n \"addressLine1\" : \"addressLine1\",\n \"stateProvince\" : \"stateProvince\",\n \"addressLine2\" : \"addressLine2\",\n \"addressLine3\" : \"addressLine3\"\n },\n \"gender\" : \"m\",\n \"idDocument\" : [ {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n } ],\n \"employerName\" : \"employerName\",\n \"dateOfBirth\" : \"2000-11-20T00:00:00.000+00:00\",\n \"contactPhone\" : \"contactPhone\",\n \"subjectName\" : {\n \"firstName\" : \"firstName\",\n \"lastName\" : \"lastName\",\n \"nativeName\" : \"nativeName\",\n \"fullName\" : \"fullName\",\n \"middleName\" : \"middleName\",\n \"title\" : \"title\"\n }\n },\n \"kycVerificationStatus\" : \"verified\",\n \"kycVerificationEntity\" : \"kycVerificationEntity\"\n }, {\n \"kycLevel\" : 1,\n \"identityType\" : \"individual\",\n \"identityId\" : \"identityId\",\n \"identityStatus\" : \"identityStatus\",\n \"accountRelationship\" : \"accountholder\",\n \"customData\" : [ {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n } ],\n \"identityKyc\" : {\n \"emailAddress\" : \"emailAddress\",\n \"occupation\" : \"occupation\",\n \"postalAddress\" : {\n \"city\" : \"city\",\n \"postalCode\" : \"postalCode\",\n \"addressLine1\" : \"addressLine1\",\n \"stateProvince\" : \"stateProvince\",\n \"addressLine2\" : \"addressLine2\",\n \"addressLine3\" : \"addressLine3\"\n },\n \"gender\" : \"m\",\n \"idDocument\" : [ {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n } ],\n \"employerName\" : \"employerName\",\n \"dateOfBirth\" : \"2000-11-20T00:00:00.000+00:00\",\n \"contactPhone\" : \"contactPhone\",\n \"subjectName\" : {\n \"firstName\" : \"firstName\",\n \"lastName\" : \"lastName\",\n \"nativeName\" : \"nativeName\",\n \"fullName\" : \"fullName\",\n \"middleName\" : \"middleName\",\n \"title\" : \"title\"\n }\n },\n \"kycVerificationStatus\" : \"verified\",\n \"kycVerificationEntity\" : \"kycVerificationEntity\"\n }, {\n \"kycLevel\" : 1,\n \"identityType\" : \"individual\",\n \"identityId\" : \"identityId\",\n \"identityStatus\" : \"identityStatus\",\n \"accountRelationship\" : \"accountholder\",\n \"customData\" : [ {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n } ],\n \"identityKyc\" : {\n \"emailAddress\" : \"emailAddress\",\n \"occupation\" : \"occupation\",\n \"postalAddress\" : {\n \"city\" : \"city\",\n \"postalCode\" : \"postalCode\",\n \"addressLine1\" : \"addressLine1\",\n \"stateProvince\" : \"stateProvince\",\n \"addressLine2\" : \"addressLine2\",\n \"addressLine3\" : \"addressLine3\"\n },\n \"gender\" : \"m\",\n \"idDocument\" : [ {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n } ],\n \"employerName\" : \"employerName\",\n \"dateOfBirth\" : \"2000-11-20T00:00:00.000+00:00\",\n \"contactPhone\" : \"contactPhone\",\n \"subjectName\" : {\n \"firstName\" : \"firstName\",\n \"lastName\" : \"lastName\",\n \"nativeName\" : \"nativeName\",\n \"fullName\" : \"fullName\",\n \"middleName\" : \"middleName\",\n \"title\" : \"title\"\n }\n },\n \"kycVerificationStatus\" : \"verified\",\n \"kycVerificationEntity\" : \"kycVerificationEntity\"\n }, {\n \"kycLevel\" : 1,\n \"identityType\" : \"individual\",\n \"identityId\" : \"identityId\",\n \"identityStatus\" : \"identityStatus\",\n \"accountRelationship\" : \"accountholder\",\n \"customData\" : [ {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n } ],\n \"identityKyc\" : {\n \"emailAddress\" : \"emailAddress\",\n \"occupation\" : \"occupation\",\n \"postalAddress\" : {\n \"city\" : \"city\",\n \"postalCode\" : \"postalCode\",\n \"addressLine1\" : \"addressLine1\",\n \"stateProvince\" : \"stateProvince\",\n \"addressLine2\" : \"addressLine2\",\n \"addressLine3\" : \"addressLine3\"\n },\n \"gender\" : \"m\",\n \"idDocument\" : [ {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n } ],\n \"employerName\" : \"employerName\",\n \"dateOfBirth\" : \"2000-11-20T00:00:00.000+00:00\",\n \"contactPhone\" : \"contactPhone\",\n \"subjectName\" : {\n \"firstName\" : \"firstName\",\n \"lastName\" : \"lastName\",\n \"nativeName\" : \"nativeName\",\n \"fullName\" : \"fullName\",\n \"middleName\" : \"middleName\",\n \"title\" : \"title\"\n }\n },\n \"kycVerificationStatus\" : \"verified\",\n \"kycVerificationEntity\" : \"kycVerificationEntity\"\n }, {\n \"kycLevel\" : 1,\n \"identityType\" : \"individual\",\n \"identityId\" : \"identityId\",\n \"identityStatus\" : \"identityStatus\",\n \"accountRelationship\" : \"accountholder\",\n \"customData\" : [ {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n } ],\n \"identityKyc\" : {\n \"emailAddress\" : \"emailAddress\",\n \"occupation\" : \"occupation\",\n \"postalAddress\" : {\n \"city\" : \"city\",\n \"postalCode\" : \"postalCode\",\n \"addressLine1\" : \"addressLine1\",\n \"stateProvince\" : \"stateProvince\",\n \"addressLine2\" : \"addressLine2\",\n \"addressLine3\" : \"addressLine3\"\n },\n \"gender\" : \"m\",\n \"idDocument\" : [ {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n } ],\n \"employerName\" : \"employerName\",\n \"dateOfBirth\" : \"2000-11-20T00:00:00.000+00:00\",\n \"contactPhone\" : \"contactPhone\",\n \"subjectName\" : {\n \"firstName\" : \"firstName\",\n \"lastName\" : \"lastName\",\n \"nativeName\" : \"nativeName\",\n \"fullName\" : \"fullName\",\n \"middleName\" : \"middleName\",\n \"title\" : \"title\"\n }\n },\n \"kycVerificationStatus\" : \"verified\",\n \"kycVerificationEntity\" : \"kycVerificationEntity\"\n }, {\n \"kycLevel\" : 1,\n \"identityType\" : \"individual\",\n \"identityId\" : \"identityId\",\n \"identityStatus\" : \"identityStatus\",\n \"accountRelationship\" : \"accountholder\",\n \"customData\" : [ {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n } ],\n \"identityKyc\" : {\n \"emailAddress\" : \"emailAddress\",\n \"occupation\" : \"occupation\",\n \"postalAddress\" : {\n \"city\" : \"city\",\n \"postalCode\" : \"postalCode\",\n \"addressLine1\" : \"addressLine1\",\n \"stateProvince\" : \"stateProvince\",\n \"addressLine2\" : \"addressLine2\",\n \"addressLine3\" : \"addressLine3\"\n },\n \"gender\" : \"m\",\n \"idDocument\" : [ {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n } ],\n \"employerName\" : \"employerName\",\n \"dateOfBirth\" : \"2000-11-20T00:00:00.000+00:00\",\n \"contactPhone\" : \"contactPhone\",\n \"subjectName\" : {\n \"firstName\" : \"firstName\",\n \"lastName\" : \"lastName\",\n \"nativeName\" : \"nativeName\",\n \"fullName\" : \"fullName\",\n \"middleName\" : \"middleName\",\n \"title\" : \"title\"\n }\n },\n \"kycVerificationStatus\" : \"verified\",\n \"kycVerificationEntity\" : \"kycVerificationEntity\"\n }, {\n \"kycLevel\" : 1,\n \"identityType\" : \"individual\",\n \"identityId\" : \"identityId\",\n \"identityStatus\" : \"identityStatus\",\n \"accountRelationship\" : \"accountholder\",\n \"customData\" : [ {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n } ],\n \"identityKyc\" : {\n \"emailAddress\" : \"emailAddress\",\n \"occupation\" : \"occupation\",\n \"postalAddress\" : {\n \"city\" : \"city\",\n \"postalCode\" : \"postalCode\",\n \"addressLine1\" : \"addressLine1\",\n \"stateProvince\" : \"stateProvince\",\n \"addressLine2\" : \"addressLine2\",\n \"addressLine3\" : \"addressLine3\"\n },\n \"gender\" : \"m\",\n \"idDocument\" : [ {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n } ],\n \"employerName\" : \"employerName\",\n \"dateOfBirth\" : \"2000-11-20T00:00:00.000+00:00\",\n \"contactPhone\" : \"contactPhone\",\n \"subjectName\" : {\n \"firstName\" : \"firstName\",\n \"lastName\" : \"lastName\",\n \"nativeName\" : \"nativeName\",\n \"fullName\" : \"fullName\",\n \"middleName\" : \"middleName\",\n \"title\" : \"title\"\n }\n },\n \"kycVerificationStatus\" : \"verified\",\n \"kycVerificationEntity\" : \"kycVerificationEntity\"\n }, {\n \"kycLevel\" : 1,\n \"identityType\" : \"individual\",\n \"identityId\" : \"identityId\",\n \"identityStatus\" : \"identityStatus\",\n \"accountRelationship\" : \"accountholder\",\n \"customData\" : [ {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n } ],\n \"identityKyc\" : {\n \"emailAddress\" : \"emailAddress\",\n \"occupation\" : \"occupation\",\n \"postalAddress\" : {\n \"city\" : \"city\",\n \"postalCode\" : \"postalCode\",\n \"addressLine1\" : \"addressLine1\",\n \"stateProvince\" : \"stateProvince\",\n \"addressLine2\" : \"addressLine2\",\n \"addressLine3\" : \"addressLine3\"\n },\n \"gender\" : \"m\",\n \"idDocument\" : [ {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n } ],\n \"employerName\" : \"employerName\",\n \"dateOfBirth\" : \"2000-11-20T00:00:00.000+00:00\",\n \"contactPhone\" : \"contactPhone\",\n \"subjectName\" : {\n \"firstName\" : \"firstName\",\n \"lastName\" : \"lastName\",\n \"nativeName\" : \"nativeName\",\n \"fullName\" : \"fullName\",\n \"middleName\" : \"middleName\",\n \"title\" : \"title\"\n }\n },\n \"kycVerificationStatus\" : \"verified\",\n \"kycVerificationEntity\" : \"kycVerificationEntity\"\n }, {\n \"kycLevel\" : 1,\n \"identityType\" : \"individual\",\n \"identityId\" : \"identityId\",\n \"identityStatus\" : \"identityStatus\",\n \"accountRelationship\" : \"accountholder\",\n \"customData\" : [ {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n } ],\n \"identityKyc\" : {\n \"emailAddress\" : \"emailAddress\",\n \"occupation\" : \"occupation\",\n \"postalAddress\" : {\n \"city\" : \"city\",\n \"postalCode\" : \"postalCode\",\n \"addressLine1\" : \"addressLine1\",\n \"stateProvince\" : \"stateProvince\",\n \"addressLine2\" : \"addressLine2\",\n \"addressLine3\" : \"addressLine3\"\n },\n \"gender\" : \"m\",\n \"idDocument\" : [ {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n } ],\n \"employerName\" : \"employerName\",\n \"dateOfBirth\" : \"2000-11-20T00:00:00.000+00:00\",\n \"contactPhone\" : \"contactPhone\",\n \"subjectName\" : {\n \"firstName\" : \"firstName\",\n \"lastName\" : \"lastName\",\n \"nativeName\" : \"nativeName\",\n \"fullName\" : \"fullName\",\n \"middleName\" : \"middleName\",\n \"title\" : \"title\"\n }\n },\n \"kycVerificationStatus\" : \"verified\",\n \"kycVerificationEntity\" : \"kycVerificationEntity\"\n } ],\n \"requestDate\" : \"2000-01-23T04:56:07.000+00:00\",\n \"accountSubStatus\" : \"accountSubStatus\",\n \"currency\" : \"AED\",\n \"accountIdentifiers\" : [ {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n } ]\n}", ResponseAccount.class), HttpStatus.OK); + } catch (IOException e) { + log.error("Couldn't serialize response for content type application/json", e); + return new ResponseEntity(HttpStatus.INTERNAL_SERVER_ERROR); + } + } + + return new ResponseEntity(HttpStatus.OK); + } + + public ResponseEntity accountsAccountIdLinksLinkReferenceGET(@Pattern(regexp = "^((accountcategory|bankaccountno|accountrank|identityalias|iban|accountid|msisdn|swiftbic|sortcode|organisationid|username|walletid|linkref|consumerno|serviceprovider|storeid|bankname|bankaccounttitle|emailaddress|mandatereference)@([^$\\n]+))(\\$(accountcategory|bankaccountno|accountrank|identityalias|iban|accountid|msisdn|swiftbic|sortcode|organisationid|username|walletid|linkref|consumerno|serviceprovider|storeid|bankname|bankaccounttitle|emailaddress|mandatereference)@([^$\\n]+)){0,2}$") @Parameter(in = ParameterIn.PATH, description = "Path variable to uniquely identify an account. Up to three account identifiers can be supplied. Identifiers are delimited by $ and values are delimited by @. Example: organisationid@1234$accountid@3333. Valid account identifiers are accountcategory, bankaccountno, accountrank, identityalias, iban, accountid, msisdn, swiftbic, sortcode, organisationid, username, walletid, linkref, consumerno, serviceprovider, storeid, bankname, bankaccounttitle, emailaddress, mandatereference.", required = true, schema = @Schema()) @PathVariable("accountId") String accountId, @Size(min = 1, max = 256) @Parameter(in = ParameterIn.PATH, description = "Path variable to uniquely identify a link.", required = true, schema = @Schema()) @PathVariable("linkReference") String linkReference, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API.", schema = @Schema()) @RequestHeader(value = "X-Date", required = false) OffsetDateTime xDate, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's API key to the server.", schema = @Schema()) @RequestHeader(value = "X-API-Key", required = false) String xAPIKey, @Parameter(in = ParameterIn.HEADER, description = "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication.", schema = @Schema()) @RequestHeader(value = "X-User-Bearer", required = false) String xUserBearer, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's identifier to the server.", schema = @Schema()) @RequestHeader(value = "X-Client-Id", required = false) String xClientId, @Parameter(in = ParameterIn.HEADER, description = "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed.", schema = @Schema()) @RequestHeader(value = "X-Content-Hash", required = false) String xContentHash, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", schema = @Schema()) @RequestHeader(value = "X-User-Credential-1", required = false) String xUserCredential1, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", schema = @Schema()) @RequestHeader(value = "X-User-Credential-2", required = false) String xUserCredential2, @Parameter(in = ParameterIn.HEADER, description = "String containing the channel that was used to originate the request. For example USSD, Web, App.", schema = @Schema()) @RequestHeader(value = "X-Channel", required = false) String xChannel, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header.", schema = @Schema(allowableValues = {"lei", "swiftbic", "organisationid"} + )) @RequestHeader(value = "X-Account-Holding-Institution-Identifier-Type", required = false) String xAccountHoldingInstitutionIdentifierType, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header.", schema = @Schema()) @RequestHeader(value = "X-Account-Holding-Institution-Identifier", required = false) String xAccountHoldingInstitutionIdentifier) { + String accept = request.getHeader("Accept"); + if (accept != null && accept.contains("application/json")) { + try { + return new ResponseEntity(objectMapper.readValue("{\n \"mode\" : \"push\",\n \"modificationDate\" : \"2000-01-23T04:56:07.000+00:00\",\n \"requestingOrganisation\" : {\n \"requestingOrganisationIdentifierType\" : \"lei\",\n \"requestingOrganisationIdentifier\" : \"requestingOrganisationIdentifier\"\n },\n \"requestDate\" : \"2000-01-23T04:56:07.000+00:00\",\n \"linkReference\" : \"linkReference\",\n \"customData\" : [ {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n } ],\n \"creationDate\" : \"2000-01-23T04:56:07.000+00:00\",\n \"sourceAccountIdentifiers\" : [ {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n } ],\n \"status\" : \"active\"\n}", ResponseLink.class), HttpStatus.OK); + } catch (IOException e) { + log.error("Couldn't serialize response for content type application/json", e); + return new ResponseEntity(HttpStatus.INTERNAL_SERVER_ERROR); + } + } + + return new ResponseEntity(HttpStatus.OK); + } + + public ResponseEntity accountsAccountIdLinksLinkReferencePATCH(@Pattern(regexp = "^((accountcategory|bankaccountno|accountrank|identityalias|iban|accountid|msisdn|swiftbic|sortcode|organisationid|username|walletid|linkref|consumerno|serviceprovider|storeid|bankname|bankaccounttitle|emailaddress|mandatereference)@([^$\\n]+))(\\$(accountcategory|bankaccountno|accountrank|identityalias|iban|accountid|msisdn|swiftbic|sortcode|organisationid|username|walletid|linkref|consumerno|serviceprovider|storeid|bankname|bankaccounttitle|emailaddress|mandatereference)@([^$\\n]+)){0,2}$") @Parameter(in = ParameterIn.PATH, description = "Path variable to uniquely identify an account. Up to three account identifiers can be supplied. Identifiers are delimited by $ and values are delimited by @. Example: organisationid@1234$accountid@3333. Valid account identifiers are accountcategory, bankaccountno, accountrank, identityalias, iban, accountid, msisdn, swiftbic, sortcode, organisationid, username, walletid, linkref, consumerno, serviceprovider, storeid, bankname, bankaccounttitle, emailaddress, mandatereference.", required = true, schema = @Schema()) @PathVariable("accountId") String accountId, @Size(min = 1, max = 256) @Parameter(in = ParameterIn.PATH, description = "Path variable to uniquely identify a link.", required = true, schema = @Schema()) @PathVariable("linkReference") String linkReference, @Parameter(in = ParameterIn.DEFAULT, description = "Represents the request body of a batch of generic Patch operation.", required = true, schema = @Schema()) @Valid @RequestBody List body, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API.", schema = @Schema()) @RequestHeader(value = "X-Date", required = false) OffsetDateTime xDate, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's API key to the server.", schema = @Schema()) @RequestHeader(value = "X-API-Key", required = false) String xAPIKey, @Parameter(in = ParameterIn.HEADER, description = "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication.", schema = @Schema()) @RequestHeader(value = "X-User-Bearer", required = false) String xUserBearer, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's identifier to the server.", schema = @Schema()) @RequestHeader(value = "X-Client-Id", required = false) String xClientId, @Parameter(in = ParameterIn.HEADER, description = "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed.", schema = @Schema()) @RequestHeader(value = "X-Content-Hash", required = false) String xContentHash, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", schema = @Schema()) @RequestHeader(value = "X-User-Credential-1", required = false) String xUserCredential1, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", schema = @Schema()) @RequestHeader(value = "X-User-Credential-2", required = false) String xUserCredential2, @Parameter(in = ParameterIn.HEADER, description = "String containing the channel that was used to originate the request. For example USSD, Web, App.", schema = @Schema()) @RequestHeader(value = "X-Channel", required = false) String xChannel, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header.", schema = @Schema(allowableValues = {"lei", "swiftbic", "organisationid"} + )) @RequestHeader(value = "X-Account-Holding-Institution-Identifier-Type", required = false) String xAccountHoldingInstitutionIdentifierType, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header.", schema = @Schema()) @RequestHeader(value = "X-Account-Holding-Institution-Identifier", required = false) String xAccountHoldingInstitutionIdentifier, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to uniquely identify the request. Must be supplied as a UUID.", schema = @Schema()) @RequestHeader(value = "X-CorrelationID", required = false) String xCorrelationID, @Parameter(in = ParameterIn.HEADER, description = "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT.", schema = @Schema()) @RequestHeader(value = "X-Callback-URL", required = false) String xCallbackURL) { + String accept = request.getHeader("Accept"); + if (accept != null && accept.contains("application/json")) { + try { + return new ResponseEntity(objectMapper.readValue("{\n \"pollLimit\" : 0.08008281904610115,\n \"pendingReason\" : \"pendingReason\",\n \"expiryTime\" : \"2000-01-23T04:56:07.000+00:00\",\n \"objectReference\" : \"objectReference\",\n \"notificationMethod\" : \"callback\",\n \"error\" : {\n \"errordescription\" : \"errordescription\",\n \"errorCategory\" : \"businessRule\",\n \"errorParameters\" : [ {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n } ],\n \"errorDateTime\" : \"2000-01-23T04:56:07.000+00:00\",\n \"errorCode\" : \"genericError\"\n },\n \"serverCorrelationId\" : \"serverCorrelationId\",\n \"status\" : \"pending\"\n}", RequestStateObject.class), HttpStatus.OK); + } catch (IOException e) { + log.error("Couldn't serialize response for content type application/json", e); + return new ResponseEntity(HttpStatus.INTERNAL_SERVER_ERROR); + } + } + + return new ResponseEntity(HttpStatus.OK); + } + + public ResponseEntity accountsAccountIdLinksPOST(@Pattern(regexp = "^((accountcategory|bankaccountno|accountrank|identityalias|iban|accountid|msisdn|swiftbic|sortcode|organisationid|username|walletid|linkref|consumerno|serviceprovider|storeid|bankname|bankaccounttitle|emailaddress|mandatereference)@([^$\\n]+))(\\$(accountcategory|bankaccountno|accountrank|identityalias|iban|accountid|msisdn|swiftbic|sortcode|organisationid|username|walletid|linkref|consumerno|serviceprovider|storeid|bankname|bankaccounttitle|emailaddress|mandatereference)@([^$\\n]+)){0,2}$") @Parameter(in = ParameterIn.PATH, description = "Path variable to uniquely identify an account. Up to three account identifiers can be supplied. Identifiers are delimited by $ and values are delimited by @. Example: organisationid@1234$accountid@3333. Valid account identifiers are accountcategory, bankaccountno, accountrank, identityalias, iban, accountid, msisdn, swiftbic, sortcode, organisationid, username, walletid, linkref, consumerno, serviceprovider, storeid, bankname, bankaccounttitle, emailaddress, mandatereference.", required = true, schema = @Schema()) @PathVariable("accountId") String accountId, @Parameter(in = ParameterIn.DEFAULT, description = "Represents the request body of a Link.", required = true, schema = @Schema()) @Valid @RequestBody RequestLink body, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API.", schema = @Schema()) @RequestHeader(value = "X-Date", required = false) OffsetDateTime xDate, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to uniquely identify the request. Must be supplied as a UUID.", schema = @Schema()) @RequestHeader(value = "X-CorrelationID", required = false) String xCorrelationID, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's API key to the server.", schema = @Schema()) @RequestHeader(value = "X-API-Key", required = false) String xAPIKey, @Parameter(in = ParameterIn.HEADER, description = "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication.", schema = @Schema()) @RequestHeader(value = "X-User-Bearer", required = false) String xUserBearer, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's identifier to the server.", schema = @Schema()) @RequestHeader(value = "X-Client-Id", required = false) String xClientId, @Parameter(in = ParameterIn.HEADER, description = "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed.", schema = @Schema()) @RequestHeader(value = "X-Content-Hash", required = false) String xContentHash, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", schema = @Schema()) @RequestHeader(value = "X-User-Credential-1", required = false) String xUserCredential1, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", schema = @Schema()) @RequestHeader(value = "X-User-Credential-2", required = false) String xUserCredential2, @Parameter(in = ParameterIn.HEADER, description = "String containing the channel that was used to originate the request. For example USSD, Web, App.", schema = @Schema()) @RequestHeader(value = "X-Channel", required = false) String xChannel, @Parameter(in = ParameterIn.HEADER, description = "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT.", schema = @Schema()) @RequestHeader(value = "X-Callback-URL", required = false) String xCallbackURL, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header.", schema = @Schema(allowableValues = {"lei", "swiftbic", "organisationid"} + )) @RequestHeader(value = "X-Account-Holding-Institution-Identifier-Type", required = false) String xAccountHoldingInstitutionIdentifierType, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header.", schema = @Schema()) @RequestHeader(value = "X-Account-Holding-Institution-Identifier", required = false) String xAccountHoldingInstitutionIdentifier) { + String accept = request.getHeader("Accept"); + if (accept != null && accept.contains("application/json")) { + try { + return new ResponseEntity(objectMapper.readValue("{\n \"mode\" : \"push\",\n \"modificationDate\" : \"2000-01-23T04:56:07.000+00:00\",\n \"requestingOrganisation\" : {\n \"requestingOrganisationIdentifierType\" : \"lei\",\n \"requestingOrganisationIdentifier\" : \"requestingOrganisationIdentifier\"\n },\n \"requestDate\" : \"2000-01-23T04:56:07.000+00:00\",\n \"linkReference\" : \"linkReference\",\n \"customData\" : [ {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n } ],\n \"creationDate\" : \"2000-01-23T04:56:07.000+00:00\",\n \"sourceAccountIdentifiers\" : [ {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n } ],\n \"status\" : \"active\"\n}", ResponseLink.class), HttpStatus.OK); + } catch (IOException e) { + log.error("Couldn't serialize response for content type application/json", e); + return new ResponseEntity(HttpStatus.INTERNAL_SERVER_ERROR); + } + } + + return new ResponseEntity(HttpStatus.OK); + } + + public ResponseEntity accountsAccountIdPATCH(@Pattern(regexp = "^((accountcategory|bankaccountno|accountrank|identityalias|iban|accountid|msisdn|swiftbic|sortcode|organisationid|username|walletid|linkref|consumerno|serviceprovider|storeid|bankname|bankaccounttitle|emailaddress|mandatereference)@([^$\\n]+))(\\$(accountcategory|bankaccountno|accountrank|identityalias|iban|accountid|msisdn|swiftbic|sortcode|organisationid|username|walletid|linkref|consumerno|serviceprovider|storeid|bankname|bankaccounttitle|emailaddress|mandatereference)@([^$\\n]+)){0,2}$") @Parameter(in = ParameterIn.PATH, description = "Path variable to uniquely identify an account. Up to three account identifiers can be supplied. Identifiers are delimited by $ and values are delimited by @. Example: organisationid@1234$accountid@3333. Valid account identifiers are accountcategory, bankaccountno, accountrank, identityalias, iban, accountid, msisdn, swiftbic, sortcode, organisationid, username, walletid, linkref, consumerno, serviceprovider, storeid, bankname, bankaccounttitle, emailaddress, mandatereference.", required = true, schema = @Schema()) @PathVariable("accountId") String accountId, @Parameter(in = ParameterIn.DEFAULT, description = "Represents the request body of a batch of generic Patch operation.", required = true, schema = @Schema()) @Valid @RequestBody List body, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API.", schema = @Schema()) @RequestHeader(value = "X-Date", required = false) OffsetDateTime xDate, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's API key to the server.", schema = @Schema()) @RequestHeader(value = "X-API-Key", required = false) String xAPIKey, @Parameter(in = ParameterIn.HEADER, description = "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication.", schema = @Schema()) @RequestHeader(value = "X-User-Bearer", required = false) String xUserBearer, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's identifier to the server.", schema = @Schema()) @RequestHeader(value = "X-Client-Id", required = false) String xClientId, @Parameter(in = ParameterIn.HEADER, description = "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed.", schema = @Schema()) @RequestHeader(value = "X-Content-Hash", required = false) String xContentHash, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", schema = @Schema()) @RequestHeader(value = "X-User-Credential-1", required = false) String xUserCredential1, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", schema = @Schema()) @RequestHeader(value = "X-User-Credential-2", required = false) String xUserCredential2, @Parameter(in = ParameterIn.HEADER, description = "String containing the channel that was used to originate the request. For example USSD, Web, App.", schema = @Schema()) @RequestHeader(value = "X-Channel", required = false) String xChannel, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header.", schema = @Schema(allowableValues = {"lei", "swiftbic", "organisationid"} + )) @RequestHeader(value = "X-Account-Holding-Institution-Identifier-Type", required = false) String xAccountHoldingInstitutionIdentifierType, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header.", schema = @Schema()) @RequestHeader(value = "X-Account-Holding-Institution-Identifier", required = false) String xAccountHoldingInstitutionIdentifier, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to uniquely identify the request. Must be supplied as a UUID.", schema = @Schema()) @RequestHeader(value = "X-CorrelationID", required = false) String xCorrelationID, @Parameter(in = ParameterIn.HEADER, description = "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT.", schema = @Schema()) @RequestHeader(value = "X-Callback-URL", required = false) String xCallbackURL) { + String accept = request.getHeader("Accept"); + if (accept != null && accept.contains("application/json")) { + try { + return new ResponseEntity(objectMapper.readValue("{\n \"pollLimit\" : 0.08008281904610115,\n \"pendingReason\" : \"pendingReason\",\n \"expiryTime\" : \"2000-01-23T04:56:07.000+00:00\",\n \"objectReference\" : \"objectReference\",\n \"notificationMethod\" : \"callback\",\n \"error\" : {\n \"errordescription\" : \"errordescription\",\n \"errorCategory\" : \"businessRule\",\n \"errorParameters\" : [ {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n } ],\n \"errorDateTime\" : \"2000-01-23T04:56:07.000+00:00\",\n \"errorCode\" : \"genericError\"\n },\n \"serverCorrelationId\" : \"serverCorrelationId\",\n \"status\" : \"pending\"\n}", RequestStateObject.class), HttpStatus.OK); + } catch (IOException e) { + log.error("Couldn't serialize response for content type application/json", e); + return new ResponseEntity(HttpStatus.INTERNAL_SERVER_ERROR); + } + } + + return new ResponseEntity(HttpStatus.OK); + } + + public ResponseEntity> accountsAccountIdStatemententriesGET(@Pattern(regexp = "^((accountcategory|bankaccountno|accountrank|identityalias|iban|accountid|msisdn|swiftbic|sortcode|organisationid|username|walletid|linkref|consumerno|serviceprovider|storeid|bankname|bankaccounttitle|emailaddress|mandatereference)@([^$\\n]+))(\\$(accountcategory|bankaccountno|accountrank|identityalias|iban|accountid|msisdn|swiftbic|sortcode|organisationid|username|walletid|linkref|consumerno|serviceprovider|storeid|bankname|bankaccounttitle|emailaddress|mandatereference)@([^$\\n]+)){0,2}$") @Parameter(in = ParameterIn.PATH, description = "Path variable to uniquely identify an account. Up to three account identifiers can be supplied. Identifiers are delimited by $ and values are delimited by @. Example: organisationid@1234$accountid@3333. Valid account identifiers are accountcategory, bankaccountno, accountrank, identityalias, iban, accountid, msisdn, swiftbic, sortcode, organisationid, username, walletid, linkref, consumerno, serviceprovider, storeid, bankname, bankaccounttitle, emailaddress, mandatereference.", required = true, schema = @Schema()) @PathVariable("accountId") String accountId, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API.", schema = @Schema()) @RequestHeader(value = "X-Date", required = false) OffsetDateTime xDate, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's API key to the server.", schema = @Schema()) @RequestHeader(value = "X-API-Key", required = false) String xAPIKey, @Parameter(in = ParameterIn.HEADER, description = "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication.", schema = @Schema()) @RequestHeader(value = "X-User-Bearer", required = false) String xUserBearer, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's identifier to the server.", schema = @Schema()) @RequestHeader(value = "X-Client-Id", required = false) String xClientId, @Parameter(in = ParameterIn.HEADER, description = "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed.", schema = @Schema()) @RequestHeader(value = "X-Content-Hash", required = false) String xContentHash, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", schema = @Schema()) @RequestHeader(value = "X-User-Credential-1", required = false) String xUserCredential1, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", schema = @Schema()) @RequestHeader(value = "X-User-Credential-2", required = false) String xUserCredential2, @Parameter(in = ParameterIn.HEADER, description = "String containing the channel that was used to originate the request. For example USSD, Web, App.", schema = @Schema()) @RequestHeader(value = "X-Channel", required = false) String xChannel, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header.", schema = @Schema(allowableValues = {"lei", "swiftbic", "organisationid"} + )) @RequestHeader(value = "X-Account-Holding-Institution-Identifier-Type", required = false) String xAccountHoldingInstitutionIdentifierType, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header.", schema = @Schema()) @RequestHeader(value = "X-Account-Holding-Institution-Identifier", required = false) String xAccountHoldingInstitutionIdentifier, @Parameter(in = ParameterIn.QUERY, description = "Supports pagination. If this is not supplied, then the server will apply a limit of 50 records returned for each request.", schema = @Schema()) @Valid @RequestParam(value = "limit", required = false) Integer limit, @Parameter(in = ParameterIn.QUERY, description = "Supports pagination. This value will indicate the cursor position from where to retrieve the set of records. For example, a limit of 50 and offset of 10 will return records 11 to 60.", schema = @Schema()) @Valid @RequestParam(value = "offset", required = false) Integer offset, @Parameter(in = ParameterIn.QUERY, description = "Indicates the minimum creation date for which records should be returned.", schema = @Schema()) @Valid @RequestParam(value = "fromDateTime", required = false) OffsetDateTime fromDateTime, @Parameter(in = ParameterIn.QUERY, description = "Indicates the maximum creation date for which records should be returned.", schema = @Schema()) @Valid @RequestParam(value = "toDateTime", required = false) OffsetDateTime toDateTime, @Size(max = 256) @Parameter(in = ParameterIn.QUERY, description = "Query variable to uniquely identify the transaction status.", schema = @Schema()) @Valid @RequestParam(value = "transactionStatus", required = false) String transactionStatus, @Size(max = 256) @Parameter(in = ParameterIn.QUERY, description = "Query parameter to to identify the display type of the statement entries to be returned.", schema = @Schema()) @Valid @RequestParam(value = "displayType", required = false) String displayType) { + String accept = request.getHeader("Accept"); + if (accept != null && accept.contains("application/json")) { + try { + return new ResponseEntity>(objectMapper.readValue("[ {\n \"debitParty\" : [ null, null, null, null, null, null, null, null, null, null ],\n \"amount\" : \"15.21\",\n \"transactionReference\" : \"transactionReference\",\n \"transactionStatus\" : \"transactionStatus\",\n \"customData\" : [ {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n } ],\n \"dateModified\" : \"2000-01-23T04:56:07.000+00:00\",\n \"descriptionText\" : \"descriptionText\",\n \"creationDate\" : \"2000-01-23T04:56:07.000+00:00\",\n \"displayType\" : \"displayType\",\n \"modificationDate\" : \"2000-01-23T04:56:07.000+00:00\",\n \"dateCreated\" : \"2000-01-23T04:56:07.000+00:00\",\n \"transactionReceipt\" : \"transactionReceipt\",\n \"requestDate\" : \"2000-01-23T04:56:07.000+00:00\",\n \"currency\" : \"AED\",\n \"creditParty\" : [ {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n } ]\n}, {\n \"debitParty\" : [ null, null, null, null, null, null, null, null, null, null ],\n \"amount\" : \"15.21\",\n \"transactionReference\" : \"transactionReference\",\n \"transactionStatus\" : \"transactionStatus\",\n \"customData\" : [ {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n } ],\n \"dateModified\" : \"2000-01-23T04:56:07.000+00:00\",\n \"descriptionText\" : \"descriptionText\",\n \"creationDate\" : \"2000-01-23T04:56:07.000+00:00\",\n \"displayType\" : \"displayType\",\n \"modificationDate\" : \"2000-01-23T04:56:07.000+00:00\",\n \"dateCreated\" : \"2000-01-23T04:56:07.000+00:00\",\n \"transactionReceipt\" : \"transactionReceipt\",\n \"requestDate\" : \"2000-01-23T04:56:07.000+00:00\",\n \"currency\" : \"AED\",\n \"creditParty\" : [ {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n } ]\n} ]", List.class), HttpStatus.OK); + } catch (IOException e) { + log.error("Couldn't serialize response for content type application/json", e); + return new ResponseEntity>(HttpStatus.INTERNAL_SERVER_ERROR); + } + } + + return new ResponseEntity>(HttpStatus.OK); + } + + public ResponseEntity accountsAccountIdStatusGET(@Pattern(regexp = "^((accountcategory|bankaccountno|accountrank|identityalias|iban|accountid|msisdn|swiftbic|sortcode|organisationid|username|walletid|linkref|consumerno|serviceprovider|storeid|bankname|bankaccounttitle|emailaddress|mandatereference)@([^$\\n]+))(\\$(accountcategory|bankaccountno|accountrank|identityalias|iban|accountid|msisdn|swiftbic|sortcode|organisationid|username|walletid|linkref|consumerno|serviceprovider|storeid|bankname|bankaccounttitle|emailaddress|mandatereference)@([^$\\n]+)){0,2}$") @Parameter(in = ParameterIn.PATH, description = "Path variable to uniquely identify an account. Up to three account identifiers can be supplied. Identifiers are delimited by $ and values are delimited by @. Example: organisationid@1234$accountid@3333. Valid account identifiers are accountcategory, bankaccountno, accountrank, identityalias, iban, accountid, msisdn, swiftbic, sortcode, organisationid, username, walletid, linkref, consumerno, serviceprovider, storeid, bankname, bankaccounttitle, emailaddress, mandatereference.", required = true, schema = @Schema()) @PathVariable("accountId") String accountId, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API.", schema = @Schema()) @RequestHeader(value = "X-Date", required = false) OffsetDateTime xDate, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's API key to the server.", schema = @Schema()) @RequestHeader(value = "X-API-Key", required = false) String xAPIKey, @Parameter(in = ParameterIn.HEADER, description = "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication.", schema = @Schema()) @RequestHeader(value = "X-User-Bearer", required = false) String xUserBearer, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's identifier to the server.", schema = @Schema()) @RequestHeader(value = "X-Client-Id", required = false) String xClientId, @Parameter(in = ParameterIn.HEADER, description = "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed.", schema = @Schema()) @RequestHeader(value = "X-Content-Hash", required = false) String xContentHash, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", schema = @Schema()) @RequestHeader(value = "X-User-Credential-1", required = false) String xUserCredential1, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", schema = @Schema()) @RequestHeader(value = "X-User-Credential-2", required = false) String xUserCredential2, @Parameter(in = ParameterIn.HEADER, description = "String containing the channel that was used to originate the request. For example USSD, Web, App.", schema = @Schema()) @RequestHeader(value = "X-Channel", required = false) String xChannel, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header.", schema = @Schema(allowableValues = {"lei", "swiftbic", "organisationid"} + )) @RequestHeader(value = "X-Account-Holding-Institution-Identifier-Type", required = false) String xAccountHoldingInstitutionIdentifierType, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header.", schema = @Schema()) @RequestHeader(value = "X-Account-Holding-Institution-Identifier", required = false) String xAccountHoldingInstitutionIdentifier) { + String accept = request.getHeader("Accept"); + if (accept != null && accept.contains("application/json")) { + try { + return new ResponseEntity(objectMapper.readValue("{\n \"accountStatus\" : \"available\",\n \"lei\" : \"5493000IBP32UQZ0KL24\",\n \"subStatus\" : \"subStatus\"\n}", ResponseAccountStatus.class), HttpStatus.OK); + } catch (IOException e) { + log.error("Couldn't serialize response for content type application/json", e); + return new ResponseEntity(HttpStatus.INTERNAL_SERVER_ERROR); + } + } + + return new ResponseEntity(HttpStatus.OK); + } + + public ResponseEntity> accountsAccountIdTransactionsGET(@Pattern(regexp = "^((accountcategory|bankaccountno|accountrank|identityalias|iban|accountid|msisdn|swiftbic|sortcode|organisationid|username|walletid|linkref|consumerno|serviceprovider|storeid|bankname|bankaccounttitle|emailaddress|mandatereference)@([^$\\n]+))(\\$(accountcategory|bankaccountno|accountrank|identityalias|iban|accountid|msisdn|swiftbic|sortcode|organisationid|username|walletid|linkref|consumerno|serviceprovider|storeid|bankname|bankaccounttitle|emailaddress|mandatereference)@([^$\\n]+)){0,2}$") @Parameter(in = ParameterIn.PATH, description = "Path variable to uniquely identify an account. Up to three account identifiers can be supplied. Identifiers are delimited by $ and values are delimited by @. Example: organisationid@1234$accountid@3333. Valid account identifiers are accountcategory, bankaccountno, accountrank, identityalias, iban, accountid, msisdn, swiftbic, sortcode, organisationid, username, walletid, linkref, consumerno, serviceprovider, storeid, bankname, bankaccounttitle, emailaddress, mandatereference.", required = true, schema = @Schema()) @PathVariable("accountId") String accountId, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API.", schema = @Schema()) @RequestHeader(value = "X-Date", required = false) OffsetDateTime xDate, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's API key to the server.", schema = @Schema()) @RequestHeader(value = "X-API-Key", required = false) String xAPIKey, @Parameter(in = ParameterIn.HEADER, description = "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication.", schema = @Schema()) @RequestHeader(value = "X-User-Bearer", required = false) String xUserBearer, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's identifier to the server.", schema = @Schema()) @RequestHeader(value = "X-Client-Id", required = false) String xClientId, @Parameter(in = ParameterIn.HEADER, description = "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed.", schema = @Schema()) @RequestHeader(value = "X-Content-Hash", required = false) String xContentHash, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", schema = @Schema()) @RequestHeader(value = "X-User-Credential-1", required = false) String xUserCredential1, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", schema = @Schema()) @RequestHeader(value = "X-User-Credential-2", required = false) String xUserCredential2, @Parameter(in = ParameterIn.HEADER, description = "String containing the channel that was used to originate the request. For example USSD, Web, App.", schema = @Schema()) @RequestHeader(value = "X-Channel", required = false) String xChannel, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header.", schema = @Schema(allowableValues = {"lei", "swiftbic", "organisationid"} + )) @RequestHeader(value = "X-Account-Holding-Institution-Identifier-Type", required = false) String xAccountHoldingInstitutionIdentifierType, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header.", schema = @Schema()) @RequestHeader(value = "X-Account-Holding-Institution-Identifier", required = false) String xAccountHoldingInstitutionIdentifier, @Parameter(in = ParameterIn.QUERY, description = "Supports pagination. If this is not supplied, then the server will apply a limit of 50 records returned for each request.", schema = @Schema()) @Valid @RequestParam(value = "limit", required = false) Integer limit, @Parameter(in = ParameterIn.QUERY, description = "Supports pagination. This value will indicate the cursor position from where to retrieve the set of records. For example, a limit of 50 and offset of 10 will return records 11 to 60.", schema = @Schema()) @Valid @RequestParam(value = "offset", required = false) Integer offset, @Parameter(in = ParameterIn.QUERY, description = "Indicates the minimum creation date for which records should be returned.", schema = @Schema()) @Valid @RequestParam(value = "fromDateTime", required = false) OffsetDateTime fromDateTime, @Parameter(in = ParameterIn.QUERY, description = "Indicates the maximum creation date for which records should be returned.", schema = @Schema()) @Valid @RequestParam(value = "toDateTime", required = false) OffsetDateTime toDateTime, @Size(max = 256) @Parameter(in = ParameterIn.QUERY, description = "Query variable to uniquely identify the transaction status.", schema = @Schema()) @Valid @RequestParam(value = "transactionStatus", required = false) String transactionStatus, @Parameter(in = ParameterIn.QUERY, description = "Identifies the type of transaction.", schema = @Schema(allowableValues = {"billpay", "deposit", "disbursement", "transfer", "merchantpay", "inttransfer", "adjustment", "reversal", "withdrawal"} + )) @Valid @RequestParam(value = "transactionType", required = false) String transactionType) { + String accept = request.getHeader("Accept"); + if (accept != null && accept.contains("application/json")) { + try { + return new ResponseEntity>(objectMapper.readValue("[ {\n \"recipientKyc\" : {\n \"emailAddress\" : \"emailAddress\",\n \"occupation\" : \"occupation\",\n \"postalAddress\" : {\n \"city\" : \"city\",\n \"postalCode\" : \"postalCode\",\n \"addressLine1\" : \"addressLine1\",\n \"stateProvince\" : \"stateProvince\",\n \"addressLine2\" : \"addressLine2\",\n \"addressLine3\" : \"addressLine3\"\n },\n \"gender\" : \"m\",\n \"idDocument\" : [ {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n } ],\n \"employerName\" : \"employerName\",\n \"dateOfBirth\" : \"2000-11-20T00:00:00.000+00:00\",\n \"contactPhone\" : \"contactPhone\",\n \"subjectName\" : {\n \"firstName\" : \"firstName\",\n \"lastName\" : \"lastName\",\n \"nativeName\" : \"nativeName\",\n \"fullName\" : \"fullName\",\n \"middleName\" : \"middleName\",\n \"title\" : \"title\"\n }\n },\n \"debitParty\" : [ null, null, null, null, null, null, null, null, null, null ],\n \"fees\" : [ {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n } ],\n \"metadata\" : [ {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n } ],\n \"customData\" : [ {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n } ],\n \"requestingLei\" : \"requestingLei\",\n \"descriptionText\" : \"descriptionText\",\n \"type\" : \"billpay\",\n \"dateCreated\" : \"2000-01-23T04:56:07.000+00:00\",\n \"transactionReceipt\" : \"transactionReceipt\",\n \"oneTimeCode\" : \"oneTimeCode\",\n \"requestDate\" : \"2000-01-23T04:56:07.000+00:00\",\n \"currency\" : \"AED\",\n \"originalTransactionReference\" : \"originalTransactionReference\",\n \"amount\" : \"15.21\",\n \"transactionReference\" : \"transactionReference\",\n \"transactionStatus\" : \"transactionStatus\",\n \"internationalTransferInformation\" : {\n \"quotationReference\" : \"quotationReference\",\n \"deliveryMethod\" : \"directtoaccount\",\n \"originCountry\" : \"AD\",\n \"relationshipSender\" : \"relationshipSender\",\n \"remittancePurpose\" : \"remittancePurpose\",\n \"senderBlockingReason\" : \"senderBlockingReason\",\n \"quoteId\" : \"quoteId\",\n \"recipientBlockingReason\" : \"recipientBlockingReason\"\n },\n \"requestingOrganisation\" : {\n \"requestingOrganisationIdentifierType\" : \"lei\",\n \"requestingOrganisationIdentifier\" : \"requestingOrganisationIdentifier\"\n },\n \"geoCode\" : \"37.423825,-122.082900\",\n \"dateModified\" : \"2000-01-23T04:56:07.000+00:00\",\n \"creationDate\" : \"2000-01-23T04:56:07.000+00:00\",\n \"modificationDate\" : \"2000-01-23T04:56:07.000+00:00\",\n \"receivingLei\" : \"receivingLei\",\n \"servicingIdentity\" : \"servicingIdentity\",\n \"requestingOrganisationTransactionReference\" : \"requestingOrganisationTransactionReference\",\n \"subType\" : \"subType\",\n \"creditParty\" : [ {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n } ]\n}, {\n \"recipientKyc\" : {\n \"emailAddress\" : \"emailAddress\",\n \"occupation\" : \"occupation\",\n \"postalAddress\" : {\n \"city\" : \"city\",\n \"postalCode\" : \"postalCode\",\n \"addressLine1\" : \"addressLine1\",\n \"stateProvince\" : \"stateProvince\",\n \"addressLine2\" : \"addressLine2\",\n \"addressLine3\" : \"addressLine3\"\n },\n \"gender\" : \"m\",\n \"idDocument\" : [ {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n } ],\n \"employerName\" : \"employerName\",\n \"dateOfBirth\" : \"2000-11-20T00:00:00.000+00:00\",\n \"contactPhone\" : \"contactPhone\",\n \"subjectName\" : {\n \"firstName\" : \"firstName\",\n \"lastName\" : \"lastName\",\n \"nativeName\" : \"nativeName\",\n \"fullName\" : \"fullName\",\n \"middleName\" : \"middleName\",\n \"title\" : \"title\"\n }\n },\n \"debitParty\" : [ null, null, null, null, null, null, null, null, null, null ],\n \"fees\" : [ {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n } ],\n \"metadata\" : [ {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n } ],\n \"customData\" : [ {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n } ],\n \"requestingLei\" : \"requestingLei\",\n \"descriptionText\" : \"descriptionText\",\n \"type\" : \"billpay\",\n \"dateCreated\" : \"2000-01-23T04:56:07.000+00:00\",\n \"transactionReceipt\" : \"transactionReceipt\",\n \"oneTimeCode\" : \"oneTimeCode\",\n \"requestDate\" : \"2000-01-23T04:56:07.000+00:00\",\n \"currency\" : \"AED\",\n \"originalTransactionReference\" : \"originalTransactionReference\",\n \"amount\" : \"15.21\",\n \"transactionReference\" : \"transactionReference\",\n \"transactionStatus\" : \"transactionStatus\",\n \"internationalTransferInformation\" : {\n \"quotationReference\" : \"quotationReference\",\n \"deliveryMethod\" : \"directtoaccount\",\n \"originCountry\" : \"AD\",\n \"relationshipSender\" : \"relationshipSender\",\n \"remittancePurpose\" : \"remittancePurpose\",\n \"senderBlockingReason\" : \"senderBlockingReason\",\n \"quoteId\" : \"quoteId\",\n \"recipientBlockingReason\" : \"recipientBlockingReason\"\n },\n \"requestingOrganisation\" : {\n \"requestingOrganisationIdentifierType\" : \"lei\",\n \"requestingOrganisationIdentifier\" : \"requestingOrganisationIdentifier\"\n },\n \"geoCode\" : \"37.423825,-122.082900\",\n \"dateModified\" : \"2000-01-23T04:56:07.000+00:00\",\n \"creationDate\" : \"2000-01-23T04:56:07.000+00:00\",\n \"modificationDate\" : \"2000-01-23T04:56:07.000+00:00\",\n \"receivingLei\" : \"receivingLei\",\n \"servicingIdentity\" : \"servicingIdentity\",\n \"requestingOrganisationTransactionReference\" : \"requestingOrganisationTransactionReference\",\n \"subType\" : \"subType\",\n \"creditParty\" : [ {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n } ]\n} ]", List.class), HttpStatus.OK); + } catch (IOException e) { + log.error("Couldn't serialize response for content type application/json", e); + return new ResponseEntity>(HttpStatus.INTERNAL_SERVER_ERROR); + } + } + + return new ResponseEntity>(HttpStatus.OK); + } + + public ResponseEntity accountsBalanceGET(@Parameter(in = ParameterIn.HEADER, description = "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API.", schema = @Schema()) @RequestHeader(value = "X-Date", required = false) OffsetDateTime xDate, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's API key to the server.", schema = @Schema()) @RequestHeader(value = "X-API-Key", required = false) String xAPIKey, @Parameter(in = ParameterIn.HEADER, description = "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication.", schema = @Schema()) @RequestHeader(value = "X-User-Bearer", required = false) String xUserBearer, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's identifier to the server.", schema = @Schema()) @RequestHeader(value = "X-Client-Id", required = false) String xClientId, @Parameter(in = ParameterIn.HEADER, description = "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed.", schema = @Schema()) @RequestHeader(value = "X-Content-Hash", required = false) String xContentHash, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", schema = @Schema()) @RequestHeader(value = "X-User-Credential-1", required = false) String xUserCredential1, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", schema = @Schema()) @RequestHeader(value = "X-User-Credential-2", required = false) String xUserCredential2, @Parameter(in = ParameterIn.HEADER, description = "String containing the channel that was used to originate the request. For example USSD, Web, App.", schema = @Schema()) @RequestHeader(value = "X-Channel", required = false) String xChannel, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header.", schema = @Schema(allowableValues = {"lei", "swiftbic", "organisationid"} + )) @RequestHeader(value = "X-Account-Holding-Institution-Identifier-Type", required = false) String xAccountHoldingInstitutionIdentifierType, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header.", schema = @Schema()) @RequestHeader(value = "X-Account-Holding-Institution-Identifier", required = false) String xAccountHoldingInstitutionIdentifier) { + String accept = request.getHeader("Accept"); + if (accept != null && accept.contains("application/json")) { + try { + return new ResponseEntity(objectMapper.readValue("{\n \"accountStatus\" : \"available\",\n \"currentBalance\" : \"15.21\",\n \"currency\" : \"AED\"\n}", ResponseAccountBalance.class), HttpStatus.OK); + } catch (IOException e) { + log.error("Couldn't serialize response for content type application/json", e); + return new ResponseEntity(HttpStatus.INTERNAL_SERVER_ERROR); + } + } + + return new ResponseEntity(HttpStatus.OK); + } + + public ResponseEntity accountsIdentifierTypeIdentifierAccountnameGET(@Parameter(in = ParameterIn.PATH, description = "Path variable to specify the type of the identifier that is used to identify the account.", required = true, schema = @Schema(allowableValues = {"accountid", "msisdn", "walletid", "linkref", "consumerno", "serviceprovider", "storeid", "accountcategory", "bankaccountno", "accountrank", "identityalias", "iban", "swiftbic", "sortcode", "organisationid", "bankname", "bankaccounttitle", "username", "emailaddress", "mandatereference"} + )) @PathVariable("identifierType") String identifierType, @Size(min = 1, max = 256) @Parameter(in = ParameterIn.PATH, description = "Path variable that contains the account identifier.", required = true, schema = @Schema()) @PathVariable("identifier") String identifier, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API.", schema = @Schema()) @RequestHeader(value = "X-Date", required = false) OffsetDateTime xDate, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's API key to the server.", schema = @Schema()) @RequestHeader(value = "X-API-Key", required = false) String xAPIKey, @Parameter(in = ParameterIn.HEADER, description = "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication.", schema = @Schema()) @RequestHeader(value = "X-User-Bearer", required = false) String xUserBearer, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's identifier to the server.", schema = @Schema()) @RequestHeader(value = "X-Client-Id", required = false) String xClientId, @Parameter(in = ParameterIn.HEADER, description = "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed.", schema = @Schema()) @RequestHeader(value = "X-Content-Hash", required = false) String xContentHash, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", schema = @Schema()) @RequestHeader(value = "X-User-Credential-1", required = false) String xUserCredential1, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", schema = @Schema()) @RequestHeader(value = "X-User-Credential-2", required = false) String xUserCredential2, @Parameter(in = ParameterIn.HEADER, description = "String containing the channel that was used to originate the request. For example USSD, Web, App.", schema = @Schema()) @RequestHeader(value = "X-Channel", required = false) String xChannel, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header.", schema = @Schema(allowableValues = {"lei", "swiftbic", "organisationid"} + )) @RequestHeader(value = "X-Account-Holding-Institution-Identifier-Type", required = false) String xAccountHoldingInstitutionIdentifierType, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header.", schema = @Schema()) @RequestHeader(value = "X-Account-Holding-Institution-Identifier", required = false) String xAccountHoldingInstitutionIdentifier) { + String accept = request.getHeader("Accept"); + if (accept != null && accept.contains("application/json")) { + try { + return new ResponseEntity(objectMapper.readValue("{\n \"lei\" : \"5493000IBP32UQZ0KL24\",\n \"name\" : {\n \"firstName\" : \"firstName\",\n \"lastName\" : \"lastName\",\n \"nativeName\" : \"nativeName\",\n \"fullName\" : \"fullName\",\n \"middleName\" : \"middleName\",\n \"title\" : \"title\"\n }\n}", ResponseAccountName.class), HttpStatus.OK); + } catch (IOException e) { + log.error("Couldn't serialize response for content type application/json", e); + return new ResponseEntity(HttpStatus.INTERNAL_SERVER_ERROR); + } + } + + return new ResponseEntity(HttpStatus.OK); + } + + public ResponseEntity accountsIdentifierTypeIdentifierAuthorisationCodesAuthorisationCodeGET(@Parameter(in = ParameterIn.PATH, description = "Path variable to specify the type of the identifier that is used to identify the account.", required = true, schema = @Schema(allowableValues = {"accountid", "msisdn", "walletid", "linkref", "consumerno", "serviceprovider", "storeid", "accountcategory", "bankaccountno", "accountrank", "identityalias", "iban", "swiftbic", "sortcode", "organisationid", "bankname", "bankaccounttitle", "username", "emailaddress", "mandatereference"} + )) @PathVariable("identifierType") String identifierType, @Size(min = 1, max = 256) @Parameter(in = ParameterIn.PATH, description = "Path variable that contains the account identifier.", required = true, schema = @Schema()) @PathVariable("identifier") String identifier, @Size(min = 1, max = 256) @Parameter(in = ParameterIn.PATH, description = "Path variable to uniquely identify an authorisation code.", required = true, schema = @Schema()) @PathVariable("authorisationCode") String authorisationCode, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API.", schema = @Schema()) @RequestHeader(value = "X-Date", required = false) OffsetDateTime xDate, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's API key to the server.", schema = @Schema()) @RequestHeader(value = "X-API-Key", required = false) String xAPIKey, @Parameter(in = ParameterIn.HEADER, description = "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication.", schema = @Schema()) @RequestHeader(value = "X-User-Bearer", required = false) String xUserBearer, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's identifier to the server.", schema = @Schema()) @RequestHeader(value = "X-Client-Id", required = false) String xClientId, @Parameter(in = ParameterIn.HEADER, description = "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed.", schema = @Schema()) @RequestHeader(value = "X-Content-Hash", required = false) String xContentHash, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", schema = @Schema()) @RequestHeader(value = "X-User-Credential-1", required = false) String xUserCredential1, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", schema = @Schema()) @RequestHeader(value = "X-User-Credential-2", required = false) String xUserCredential2, @Parameter(in = ParameterIn.HEADER, description = "String containing the channel that was used to originate the request. For example USSD, Web, App.", schema = @Schema()) @RequestHeader(value = "X-Channel", required = false) String xChannel, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header.", schema = @Schema(allowableValues = {"lei", "swiftbic", "organisationid"} + )) @RequestHeader(value = "X-Account-Holding-Institution-Identifier-Type", required = false) String xAccountHoldingInstitutionIdentifierType, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header.", schema = @Schema()) @RequestHeader(value = "X-Account-Holding-Institution-Identifier", required = false) String xAccountHoldingInstitutionIdentifier) { + String accept = request.getHeader("Accept"); + if (accept != null && accept.contains("application/json")) { + try { + return new ResponseEntity(objectMapper.readValue("{\n \"amountType\" : \"exact\",\n \"amount\" : \"15.21\",\n \"metadata\" : [ {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n } ],\n \"requestingOrganisation\" : {\n \"requestingOrganisationIdentifierType\" : \"lei\",\n \"requestingOrganisationIdentifier\" : \"requestingOrganisationIdentifier\"\n },\n \"redemptionChannels\" : [ {\n \"channelType\" : \"channelType\"\n }, {\n \"channelType\" : \"channelType\"\n }, {\n \"channelType\" : \"channelType\"\n }, {\n \"channelType\" : \"channelType\"\n }, {\n \"channelType\" : \"channelType\"\n }, {\n \"channelType\" : \"channelType\"\n }, {\n \"channelType\" : \"channelType\"\n }, {\n \"channelType\" : \"channelType\"\n }, {\n \"channelType\" : \"channelType\"\n }, {\n \"channelType\" : \"channelType\"\n } ],\n \"customData\" : [ {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n } ],\n \"authorisationCode\" : \"authorisationCode\",\n \"creationDate\" : \"2000-01-23T04:56:07.000+00:00\",\n \"codeState\" : \"active\",\n \"codeLifetime\" : 600,\n \"redemptionTransactionTypes\" : [ {\n \"transactionType\" : \"billpay\",\n \"transactionSubtype\" : \"transactionSubtype\"\n }, {\n \"transactionType\" : \"billpay\",\n \"transactionSubtype\" : \"transactionSubtype\"\n }, {\n \"transactionType\" : \"billpay\",\n \"transactionSubtype\" : \"transactionSubtype\"\n }, {\n \"transactionType\" : \"billpay\",\n \"transactionSubtype\" : \"transactionSubtype\"\n }, {\n \"transactionType\" : \"billpay\",\n \"transactionSubtype\" : \"transactionSubtype\"\n }, {\n \"transactionType\" : \"billpay\",\n \"transactionSubtype\" : \"transactionSubtype\"\n }, {\n \"transactionType\" : \"billpay\",\n \"transactionSubtype\" : \"transactionSubtype\"\n }, {\n \"transactionType\" : \"billpay\",\n \"transactionSubtype\" : \"transactionSubtype\"\n }, {\n \"transactionType\" : \"billpay\",\n \"transactionSubtype\" : \"transactionSubtype\"\n }, {\n \"transactionType\" : \"billpay\",\n \"transactionSubtype\" : \"transactionSubtype\"\n } ],\n \"modificationDate\" : \"2000-01-23T04:56:07.000+00:00\",\n \"redemptionAccountIdentifiers\" : [ {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n } ],\n \"requestDate\" : \"2000-01-23T04:56:07.000+00:00\",\n \"currency\" : \"AED\",\n \"holdFundsIndicator\" : true\n}", ResponseAuthorisationCode.class), HttpStatus.OK); + } catch (IOException e) { + log.error("Couldn't serialize response for content type application/json", e); + return new ResponseEntity(HttpStatus.INTERNAL_SERVER_ERROR); + } + } + + return new ResponseEntity(HttpStatus.OK); + } + + public ResponseEntity accountsIdentifierTypeIdentifierAuthorisationCodesAuthorisationCodePATCH(@Parameter(in = ParameterIn.PATH, description = "Path variable to specify the type of the identifier that is used to identify the account.", required = true, schema = @Schema(allowableValues = {"accountid", "msisdn", "walletid", "linkref", "consumerno", "serviceprovider", "storeid", "accountcategory", "bankaccountno", "accountrank", "identityalias", "iban", "swiftbic", "sortcode", "organisationid", "bankname", "bankaccounttitle", "username", "emailaddress", "mandatereference"} + )) @PathVariable("identifierType") String identifierType, @Size(min = 1, max = 256) @Parameter(in = ParameterIn.PATH, description = "Path variable that contains the account identifier.", required = true, schema = @Schema()) @PathVariable("identifier") String identifier, @Size(min = 1, max = 256) @Parameter(in = ParameterIn.PATH, description = "Path variable to uniquely identify an authorisation code.", required = true, schema = @Schema()) @PathVariable("authorisationCode") String authorisationCode, @Parameter(in = ParameterIn.DEFAULT, description = "Represents the request body of a batch of generic Patch operation.", required = true, schema = @Schema()) @Valid @RequestBody List body, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API.", schema = @Schema()) @RequestHeader(value = "X-Date", required = false) OffsetDateTime xDate, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's API key to the server.", schema = @Schema()) @RequestHeader(value = "X-API-Key", required = false) String xAPIKey, @Parameter(in = ParameterIn.HEADER, description = "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication.", schema = @Schema()) @RequestHeader(value = "X-User-Bearer", required = false) String xUserBearer, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's identifier to the server.", schema = @Schema()) @RequestHeader(value = "X-Client-Id", required = false) String xClientId, @Parameter(in = ParameterIn.HEADER, description = "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed.", schema = @Schema()) @RequestHeader(value = "X-Content-Hash", required = false) String xContentHash, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", schema = @Schema()) @RequestHeader(value = "X-User-Credential-1", required = false) String xUserCredential1, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", schema = @Schema()) @RequestHeader(value = "X-User-Credential-2", required = false) String xUserCredential2, @Parameter(in = ParameterIn.HEADER, description = "String containing the channel that was used to originate the request. For example USSD, Web, App.", schema = @Schema()) @RequestHeader(value = "X-Channel", required = false) String xChannel, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header.", schema = @Schema(allowableValues = {"lei", "swiftbic", "organisationid"} + )) @RequestHeader(value = "X-Account-Holding-Institution-Identifier-Type", required = false) String xAccountHoldingInstitutionIdentifierType, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header.", schema = @Schema()) @RequestHeader(value = "X-Account-Holding-Institution-Identifier", required = false) String xAccountHoldingInstitutionIdentifier, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to uniquely identify the request. Must be supplied as a UUID.", schema = @Schema()) @RequestHeader(value = "X-CorrelationID", required = false) String xCorrelationID, @Parameter(in = ParameterIn.HEADER, description = "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT.", schema = @Schema()) @RequestHeader(value = "X-Callback-URL", required = false) String xCallbackURL) { + String accept = request.getHeader("Accept"); + if (accept != null && accept.contains("application/json")) { + try { + return new ResponseEntity(objectMapper.readValue("{\n \"pollLimit\" : 0.08008281904610115,\n \"pendingReason\" : \"pendingReason\",\n \"expiryTime\" : \"2000-01-23T04:56:07.000+00:00\",\n \"objectReference\" : \"objectReference\",\n \"notificationMethod\" : \"callback\",\n \"error\" : {\n \"errordescription\" : \"errordescription\",\n \"errorCategory\" : \"businessRule\",\n \"errorParameters\" : [ {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n } ],\n \"errorDateTime\" : \"2000-01-23T04:56:07.000+00:00\",\n \"errorCode\" : \"genericError\"\n },\n \"serverCorrelationId\" : \"serverCorrelationId\",\n \"status\" : \"pending\"\n}", RequestStateObject.class), HttpStatus.OK); + } catch (IOException e) { + log.error("Couldn't serialize response for content type application/json", e); + return new ResponseEntity(HttpStatus.INTERNAL_SERVER_ERROR); + } + } + + return new ResponseEntity(HttpStatus.OK); + } + + public ResponseEntity accountsIdentifierTypeIdentifierAuthorisationCodesGET(@Parameter(in = ParameterIn.PATH, description = "Path variable to specify the type of the identifier that is used to identify the account.", required = true, schema = @Schema(allowableValues = {"accountid", "msisdn", "walletid", "linkref", "consumerno", "serviceprovider", "storeid", "accountcategory", "bankaccountno", "accountrank", "identityalias", "iban", "swiftbic", "sortcode", "organisationid", "bankname", "bankaccounttitle", "username", "emailaddress", "mandatereference"} + )) @PathVariable("identifierType") String identifierType, @Size(min = 1, max = 256) @Parameter(in = ParameterIn.PATH, description = "Path variable that contains the account identifier.", required = true, schema = @Schema()) @PathVariable("identifier") String identifier, @NotNull @Size(max = 256) @Parameter(in = ParameterIn.QUERY, description = "Allows returned records to be filtered on state of the authorisation code.", required = true, schema = @Schema()) @Valid @RequestParam(value = "codeState", required = true) String codeState, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API.", schema = @Schema()) @RequestHeader(value = "X-Date", required = false) OffsetDateTime xDate, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's API key to the server.", schema = @Schema()) @RequestHeader(value = "X-API-Key", required = false) String xAPIKey, @Parameter(in = ParameterIn.HEADER, description = "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication.", schema = @Schema()) @RequestHeader(value = "X-User-Bearer", required = false) String xUserBearer, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's identifier to the server.", schema = @Schema()) @RequestHeader(value = "X-Client-Id", required = false) String xClientId, @Parameter(in = ParameterIn.HEADER, description = "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed.", schema = @Schema()) @RequestHeader(value = "X-Content-Hash", required = false) String xContentHash, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", schema = @Schema()) @RequestHeader(value = "X-User-Credential-1", required = false) String xUserCredential1, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", schema = @Schema()) @RequestHeader(value = "X-User-Credential-2", required = false) String xUserCredential2, @Parameter(in = ParameterIn.HEADER, description = "String containing the channel that was used to originate the request. For example USSD, Web, App.", schema = @Schema()) @RequestHeader(value = "X-Channel", required = false) String xChannel, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header.", schema = @Schema(allowableValues = {"lei", "swiftbic", "organisationid"} + )) @RequestHeader(value = "X-Account-Holding-Institution-Identifier-Type", required = false) String xAccountHoldingInstitutionIdentifierType, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header.", schema = @Schema()) @RequestHeader(value = "X-Account-Holding-Institution-Identifier", required = false) String xAccountHoldingInstitutionIdentifier, @Parameter(in = ParameterIn.QUERY, description = "Supports pagination. If this is not supplied, then the server will apply a limit of 50 records returned for each request.", schema = @Schema()) @Valid @RequestParam(value = "limit", required = false) Integer limit, @Parameter(in = ParameterIn.QUERY, description = "Supports pagination. This value will indicate the cursor position from where to retrieve the set of records. For example, a limit of 50 and offset of 10 will return records 11 to 60.", schema = @Schema()) @Valid @RequestParam(value = "offset", required = false) Integer offset, @Parameter(in = ParameterIn.QUERY, description = "Indicates the minimum creation date for which records should be returned.", schema = @Schema()) @Valid @RequestParam(value = "fromDateTime", required = false) OffsetDateTime fromDateTime, @Parameter(in = ParameterIn.QUERY, description = "Indicates the maximum creation date for which records should be returned.", schema = @Schema()) @Valid @RequestParam(value = "toDateTime", required = false) OffsetDateTime toDateTime) { + String accept = request.getHeader("Accept"); + if (accept != null && accept.contains("application/json")) { + try { + return new ResponseEntity(objectMapper.readValue("{\n \"amountType\" : \"exact\",\n \"amount\" : \"15.21\",\n \"metadata\" : [ {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n } ],\n \"requestingOrganisation\" : {\n \"requestingOrganisationIdentifierType\" : \"lei\",\n \"requestingOrganisationIdentifier\" : \"requestingOrganisationIdentifier\"\n },\n \"redemptionChannels\" : [ {\n \"channelType\" : \"channelType\"\n }, {\n \"channelType\" : \"channelType\"\n }, {\n \"channelType\" : \"channelType\"\n }, {\n \"channelType\" : \"channelType\"\n }, {\n \"channelType\" : \"channelType\"\n }, {\n \"channelType\" : \"channelType\"\n }, {\n \"channelType\" : \"channelType\"\n }, {\n \"channelType\" : \"channelType\"\n }, {\n \"channelType\" : \"channelType\"\n }, {\n \"channelType\" : \"channelType\"\n } ],\n \"customData\" : [ {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n } ],\n \"authorisationCode\" : \"authorisationCode\",\n \"creationDate\" : \"2000-01-23T04:56:07.000+00:00\",\n \"codeState\" : \"active\",\n \"codeLifetime\" : 600,\n \"redemptionTransactionTypes\" : [ {\n \"transactionType\" : \"billpay\",\n \"transactionSubtype\" : \"transactionSubtype\"\n }, {\n \"transactionType\" : \"billpay\",\n \"transactionSubtype\" : \"transactionSubtype\"\n }, {\n \"transactionType\" : \"billpay\",\n \"transactionSubtype\" : \"transactionSubtype\"\n }, {\n \"transactionType\" : \"billpay\",\n \"transactionSubtype\" : \"transactionSubtype\"\n }, {\n \"transactionType\" : \"billpay\",\n \"transactionSubtype\" : \"transactionSubtype\"\n }, {\n \"transactionType\" : \"billpay\",\n \"transactionSubtype\" : \"transactionSubtype\"\n }, {\n \"transactionType\" : \"billpay\",\n \"transactionSubtype\" : \"transactionSubtype\"\n }, {\n \"transactionType\" : \"billpay\",\n \"transactionSubtype\" : \"transactionSubtype\"\n }, {\n \"transactionType\" : \"billpay\",\n \"transactionSubtype\" : \"transactionSubtype\"\n }, {\n \"transactionType\" : \"billpay\",\n \"transactionSubtype\" : \"transactionSubtype\"\n } ],\n \"modificationDate\" : \"2000-01-23T04:56:07.000+00:00\",\n \"redemptionAccountIdentifiers\" : [ {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n } ],\n \"requestDate\" : \"2000-01-23T04:56:07.000+00:00\",\n \"currency\" : \"AED\",\n \"holdFundsIndicator\" : true\n}", ResponseAuthorisationCode.class), HttpStatus.OK); + } catch (IOException e) { + log.error("Couldn't serialize response for content type application/json", e); + return new ResponseEntity(HttpStatus.INTERNAL_SERVER_ERROR); + } + } + + return new ResponseEntity(HttpStatus.OK); + } + + public ResponseEntity accountsIdentifierTypeIdentifierAuthorisationCodesPOST(@Parameter(in = ParameterIn.PATH, description = "Path variable to specify the type of the identifier that is used to identify the account.", required = true, schema = @Schema(allowableValues = {"accountid", "msisdn", "walletid", "linkref", "consumerno", "serviceprovider", "storeid", "accountcategory", "bankaccountno", "accountrank", "identityalias", "iban", "swiftbic", "sortcode", "organisationid", "bankname", "bankaccounttitle", "username", "emailaddress", "mandatereference"} + )) @PathVariable("identifierType") String identifierType, @Size(min = 1, max = 256) @Parameter(in = ParameterIn.PATH, description = "Path variable that contains the account identifier.", required = true, schema = @Schema()) @PathVariable("identifier") String identifier, @Parameter(in = ParameterIn.DEFAULT, description = "Represents the request body of an Authorisation Code.", required = true, schema = @Schema()) @Valid @RequestBody RequestAuthorisationCode body, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API.", schema = @Schema()) @RequestHeader(value = "X-Date", required = false) OffsetDateTime xDate, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to uniquely identify the request. Must be supplied as a UUID.", schema = @Schema()) @RequestHeader(value = "X-CorrelationID", required = false) String xCorrelationID, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's API key to the server.", schema = @Schema()) @RequestHeader(value = "X-API-Key", required = false) String xAPIKey, @Parameter(in = ParameterIn.HEADER, description = "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication.", schema = @Schema()) @RequestHeader(value = "X-User-Bearer", required = false) String xUserBearer, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's identifier to the server.", schema = @Schema()) @RequestHeader(value = "X-Client-Id", required = false) String xClientId, @Parameter(in = ParameterIn.HEADER, description = "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed.", schema = @Schema()) @RequestHeader(value = "X-Content-Hash", required = false) String xContentHash, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", schema = @Schema()) @RequestHeader(value = "X-User-Credential-1", required = false) String xUserCredential1, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", schema = @Schema()) @RequestHeader(value = "X-User-Credential-2", required = false) String xUserCredential2, @Parameter(in = ParameterIn.HEADER, description = "String containing the channel that was used to originate the request. For example USSD, Web, App.", schema = @Schema()) @RequestHeader(value = "X-Channel", required = false) String xChannel, @Parameter(in = ParameterIn.HEADER, description = "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT.", schema = @Schema()) @RequestHeader(value = "X-Callback-URL", required = false) String xCallbackURL, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header.", schema = @Schema(allowableValues = {"lei", "swiftbic", "organisationid"} + )) @RequestHeader(value = "X-Account-Holding-Institution-Identifier-Type", required = false) String xAccountHoldingInstitutionIdentifierType, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header.", schema = @Schema()) @RequestHeader(value = "X-Account-Holding-Institution-Identifier", required = false) String xAccountHoldingInstitutionIdentifier) { + String accept = request.getHeader("Accept"); + if (accept != null && accept.contains("application/json")) { + try { + return new ResponseEntity(objectMapper.readValue("{\n \"amountType\" : \"exact\",\n \"amount\" : \"15.21\",\n \"metadata\" : [ {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n } ],\n \"requestingOrganisation\" : {\n \"requestingOrganisationIdentifierType\" : \"lei\",\n \"requestingOrganisationIdentifier\" : \"requestingOrganisationIdentifier\"\n },\n \"redemptionChannels\" : [ {\n \"channelType\" : \"channelType\"\n }, {\n \"channelType\" : \"channelType\"\n }, {\n \"channelType\" : \"channelType\"\n }, {\n \"channelType\" : \"channelType\"\n }, {\n \"channelType\" : \"channelType\"\n }, {\n \"channelType\" : \"channelType\"\n }, {\n \"channelType\" : \"channelType\"\n }, {\n \"channelType\" : \"channelType\"\n }, {\n \"channelType\" : \"channelType\"\n }, {\n \"channelType\" : \"channelType\"\n } ],\n \"customData\" : [ {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n } ],\n \"authorisationCode\" : \"authorisationCode\",\n \"creationDate\" : \"2000-01-23T04:56:07.000+00:00\",\n \"codeState\" : \"active\",\n \"codeLifetime\" : 600,\n \"redemptionTransactionTypes\" : [ {\n \"transactionType\" : \"billpay\",\n \"transactionSubtype\" : \"transactionSubtype\"\n }, {\n \"transactionType\" : \"billpay\",\n \"transactionSubtype\" : \"transactionSubtype\"\n }, {\n \"transactionType\" : \"billpay\",\n \"transactionSubtype\" : \"transactionSubtype\"\n }, {\n \"transactionType\" : \"billpay\",\n \"transactionSubtype\" : \"transactionSubtype\"\n }, {\n \"transactionType\" : \"billpay\",\n \"transactionSubtype\" : \"transactionSubtype\"\n }, {\n \"transactionType\" : \"billpay\",\n \"transactionSubtype\" : \"transactionSubtype\"\n }, {\n \"transactionType\" : \"billpay\",\n \"transactionSubtype\" : \"transactionSubtype\"\n }, {\n \"transactionType\" : \"billpay\",\n \"transactionSubtype\" : \"transactionSubtype\"\n }, {\n \"transactionType\" : \"billpay\",\n \"transactionSubtype\" : \"transactionSubtype\"\n }, {\n \"transactionType\" : \"billpay\",\n \"transactionSubtype\" : \"transactionSubtype\"\n } ],\n \"modificationDate\" : \"2000-01-23T04:56:07.000+00:00\",\n \"redemptionAccountIdentifiers\" : [ {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n } ],\n \"requestDate\" : \"2000-01-23T04:56:07.000+00:00\",\n \"currency\" : \"AED\",\n \"holdFundsIndicator\" : true\n}", ResponseAuthorisationCode.class), HttpStatus.OK); + } catch (IOException e) { + log.error("Couldn't serialize response for content type application/json", e); + return new ResponseEntity(HttpStatus.INTERNAL_SERVER_ERROR); + } + } + + return new ResponseEntity(HttpStatus.OK); + } + + public ResponseEntity accountsIdentifierTypeIdentifierBalanceGET(@Parameter(in = ParameterIn.PATH, description = "Path variable to specify the type of the identifier that is used to identify the account.", required = true, schema = @Schema(allowableValues = {"accountid", "msisdn", "walletid", "linkref", "consumerno", "serviceprovider", "storeid", "accountcategory", "bankaccountno", "accountrank", "identityalias", "iban", "swiftbic", "sortcode", "organisationid", "bankname", "bankaccounttitle", "username", "emailaddress", "mandatereference"} + )) @PathVariable("identifierType") String identifierType, @Size(min = 1, max = 256) @Parameter(in = ParameterIn.PATH, description = "Path variable that contains the account identifier.", required = true, schema = @Schema()) @PathVariable("identifier") String identifier, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API.", schema = @Schema()) @RequestHeader(value = "X-Date", required = false) OffsetDateTime xDate, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's API key to the server.", schema = @Schema()) @RequestHeader(value = "X-API-Key", required = false) String xAPIKey, @Parameter(in = ParameterIn.HEADER, description = "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication.", schema = @Schema()) @RequestHeader(value = "X-User-Bearer", required = false) String xUserBearer, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's identifier to the server.", schema = @Schema()) @RequestHeader(value = "X-Client-Id", required = false) String xClientId, @Parameter(in = ParameterIn.HEADER, description = "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed.", schema = @Schema()) @RequestHeader(value = "X-Content-Hash", required = false) String xContentHash, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", schema = @Schema()) @RequestHeader(value = "X-User-Credential-1", required = false) String xUserCredential1, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", schema = @Schema()) @RequestHeader(value = "X-User-Credential-2", required = false) String xUserCredential2, @Parameter(in = ParameterIn.HEADER, description = "String containing the channel that was used to originate the request. For example USSD, Web, App.", schema = @Schema()) @RequestHeader(value = "X-Channel", required = false) String xChannel, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header.", schema = @Schema(allowableValues = {"lei", "swiftbic", "organisationid"} + )) @RequestHeader(value = "X-Account-Holding-Institution-Identifier-Type", required = false) String xAccountHoldingInstitutionIdentifierType, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header.", schema = @Schema()) @RequestHeader(value = "X-Account-Holding-Institution-Identifier", required = false) String xAccountHoldingInstitutionIdentifier) { + String accept = request.getHeader("Accept"); + if (accept != null && accept.contains("application/json")) { + try { + return new ResponseEntity(objectMapper.readValue("{\n \"accountStatus\" : \"available\",\n \"currentBalance\" : \"15.21\",\n \"currency\" : \"AED\"\n}", ResponseAccountBalance.class), HttpStatus.OK); + } catch (IOException e) { + log.error("Couldn't serialize response for content type application/json", e); + return new ResponseEntity(HttpStatus.INTERNAL_SERVER_ERROR); + } + } + + return new ResponseEntity(HttpStatus.OK); + } + + public ResponseEntity> accountsIdentifierTypeIdentifierBillCompaniesGET(@Parameter(in = ParameterIn.PATH, description = "Path variable to specify the type of the identifier that is used to identify the account.", required = true, schema = @Schema(allowableValues = {"accountid", "msisdn", "walletid", "linkref", "consumerno", "serviceprovider", "storeid", "accountcategory", "bankaccountno", "accountrank", "identityalias", "iban", "swiftbic", "sortcode", "organisationid", "bankname", "bankaccounttitle", "username", "emailaddress", "mandatereference"} + )) @PathVariable("identifierType") String identifierType, @Size(min = 1, max = 256) @Parameter(in = ParameterIn.PATH, description = "Path variable that contains the account identifier.", required = true, schema = @Schema()) @PathVariable("identifier") String identifier, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API.", schema = @Schema()) @RequestHeader(value = "X-Date", required = false) OffsetDateTime xDate, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's API key to the server.", schema = @Schema()) @RequestHeader(value = "X-API-Key", required = false) String xAPIKey, @Parameter(in = ParameterIn.HEADER, description = "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication.", schema = @Schema()) @RequestHeader(value = "X-User-Bearer", required = false) String xUserBearer, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's identifier to the server.", schema = @Schema()) @RequestHeader(value = "X-Client-Id", required = false) String xClientId, @Parameter(in = ParameterIn.HEADER, description = "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed.", schema = @Schema()) @RequestHeader(value = "X-Content-Hash", required = false) String xContentHash, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", schema = @Schema()) @RequestHeader(value = "X-User-Credential-1", required = false) String xUserCredential1, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", schema = @Schema()) @RequestHeader(value = "X-User-Credential-2", required = false) String xUserCredential2, @Parameter(in = ParameterIn.HEADER, description = "String containing the channel that was used to originate the request. For example USSD, Web, App.", schema = @Schema()) @RequestHeader(value = "X-Channel", required = false) String xChannel, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header.", schema = @Schema(allowableValues = {"lei", "swiftbic", "organisationid"} + )) @RequestHeader(value = "X-Account-Holding-Institution-Identifier-Type", required = false) String xAccountHoldingInstitutionIdentifierType, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header.", schema = @Schema()) @RequestHeader(value = "X-Account-Holding-Institution-Identifier", required = false) String xAccountHoldingInstitutionIdentifier, @Parameter(in = ParameterIn.QUERY, description = "Supports pagination. If this is not supplied, then the server will apply a limit of 50 records returned for each request.", schema = @Schema()) @Valid @RequestParam(value = "limit", required = false) Integer limit, @Parameter(in = ParameterIn.QUERY, description = "Supports pagination. This value will indicate the cursor position from where to retrieve the set of records. For example, a limit of 50 and offset of 10 will return records 11 to 60.", schema = @Schema()) @Valid @RequestParam(value = "offset", required = false) Integer offset) { + String accept = request.getHeader("Accept"); + if (accept != null && accept.contains("application/json")) { + try { + return new ResponseEntity>(objectMapper.readValue("[ {\n \"supplementaryServiceProviderDetails\" : [ {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n } ],\n \"companyName\" : \"companyName\",\n \"serviceProvider\" : \"serviceProvider\",\n \"serviceProviderSubType\" : \"serviceProviderSubType\",\n \"serviceProviderType\" : \"serviceProviderType\"\n}, {\n \"supplementaryServiceProviderDetails\" : [ {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n } ],\n \"companyName\" : \"companyName\",\n \"serviceProvider\" : \"serviceProvider\",\n \"serviceProviderSubType\" : \"serviceProviderSubType\",\n \"serviceProviderType\" : \"serviceProviderType\"\n} ]", List.class), HttpStatus.OK); + } catch (IOException e) { + log.error("Couldn't serialize response for content type application/json", e); + return new ResponseEntity>(HttpStatus.INTERNAL_SERVER_ERROR); + } + } + + return new ResponseEntity>(HttpStatus.OK); + } + + public ResponseEntity accountsIdentifierTypeIdentifierBillsBillPaymentsGET(@Parameter(in = ParameterIn.PATH, description = "Path variable to specify the type of the identifier that is used to identify the account.", required = true, schema = @Schema(allowableValues = {"accountid", "msisdn", "walletid", "linkref", "consumerno", "serviceprovider", "storeid", "accountcategory", "bankaccountno", "accountrank", "identityalias", "iban", "swiftbic", "sortcode", "organisationid", "bankname", "bankaccounttitle", "username", "emailaddress", "mandatereference"} + )) @PathVariable("identifierType") String identifierType, @Size(min = 1, max = 256) @Parameter(in = ParameterIn.PATH, description = "Path variable that contains the account identifier.", required = true, schema = @Schema()) @PathVariable("identifier") String identifier, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API.", schema = @Schema()) @RequestHeader(value = "X-Date", required = false) OffsetDateTime xDate, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's API key to the server.", schema = @Schema()) @RequestHeader(value = "X-API-Key", required = false) String xAPIKey, @Parameter(in = ParameterIn.HEADER, description = "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication.", schema = @Schema()) @RequestHeader(value = "X-User-Bearer", required = false) String xUserBearer, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's identifier to the server.", schema = @Schema()) @RequestHeader(value = "X-Client-Id", required = false) String xClientId, @Parameter(in = ParameterIn.HEADER, description = "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed.", schema = @Schema()) @RequestHeader(value = "X-Content-Hash", required = false) String xContentHash, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", schema = @Schema()) @RequestHeader(value = "X-User-Credential-1", required = false) String xUserCredential1, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", schema = @Schema()) @RequestHeader(value = "X-User-Credential-2", required = false) String xUserCredential2, @Parameter(in = ParameterIn.HEADER, description = "String containing the channel that was used to originate the request. For example USSD, Web, App.", schema = @Schema()) @RequestHeader(value = "X-Channel", required = false) String xChannel, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header.", schema = @Schema(allowableValues = {"lei", "swiftbic", "organisationid"} + )) @RequestHeader(value = "X-Account-Holding-Institution-Identifier-Type", required = false) String xAccountHoldingInstitutionIdentifierType, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header.", schema = @Schema()) @RequestHeader(value = "X-Account-Holding-Institution-Identifier", required = false) String xAccountHoldingInstitutionIdentifier, @Parameter(in = ParameterIn.QUERY, description = "Supports pagination. If this is not supplied, then the server will apply a limit of 50 records returned for each request.", schema = @Schema()) @Valid @RequestParam(value = "limit", required = false) Integer limit, @Parameter(in = ParameterIn.QUERY, description = "Supports pagination. This value will indicate the cursor position from where to retrieve the set of records. For example, a limit of 50 and offset of 10 will return records 11 to 60.", schema = @Schema()) @Valid @RequestParam(value = "offset", required = false) Integer offset, @Parameter(in = ParameterIn.QUERY, description = "Indicates the minimum creation date for which records should be returned.", schema = @Schema()) @Valid @RequestParam(value = "fromDateTime", required = false) OffsetDateTime fromDateTime, @Parameter(in = ParameterIn.QUERY, description = "Indicates the maximum creation date for which records should be returned.", schema = @Schema()) @Valid @RequestParam(value = "toDateTime", required = false) OffsetDateTime toDateTime) { + String accept = request.getHeader("Accept"); + if (accept != null && accept.contains("application/json")) { + try { + return new ResponseEntity(objectMapper.readValue("{\n \"serviceProviderNotification\" : \"serviceProviderNotification\",\n \"metadata\" : [ {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n } ],\n \"requestingOrganisation\" : \"requestingOrganisation\",\n \"customData\" : [ {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n } ],\n \"creationDate\" : \"2000-01-23T04:56:07.000+00:00\",\n \"paymentType\" : \"partialpayment\",\n \"modificationDate\" : \"2000-01-23T04:56:07.000+00:00\",\n \"billPaymentStatus\" : \"billPaymentStatus\",\n \"amountPaid\" : \"15.21\",\n \"customerReference\" : \"customerReference\",\n \"requestDate\" : \"2000-01-23T04:56:07.000+00:00\",\n \"requestingOrganisationTransactionReference\" : \"requestingOrganisationTransactionReference\",\n \"currency\" : \"AED\",\n \"serviceProviderPaymentReference\" : \"serviceProviderPaymentReference\",\n \"serviceProviderComment\" : \"serviceProviderComment\"\n}", ResponseBillPayment2.class), HttpStatus.OK); + } catch (IOException e) { + log.error("Couldn't serialize response for content type application/json", e); + return new ResponseEntity(HttpStatus.INTERNAL_SERVER_ERROR); + } + } + + return new ResponseEntity(HttpStatus.OK); + } + + public ResponseEntity accountsIdentifierTypeIdentifierBillsBillPaymentsPOST(@Parameter(in = ParameterIn.PATH, description = "Path variable to specify the type of the identifier that is used to identify the account.", required = true, schema = @Schema(allowableValues = {"accountid", "msisdn", "walletid", "linkref", "consumerno", "serviceprovider", "storeid", "accountcategory", "bankaccountno", "accountrank", "identityalias", "iban", "swiftbic", "sortcode", "organisationid", "bankname", "bankaccounttitle", "username", "emailaddress", "mandatereference"} + )) @PathVariable("identifierType") String identifierType, @Size(min = 1, max = 256) @Parameter(in = ParameterIn.PATH, description = "Path variable that contains the account identifier.", required = true, schema = @Schema()) @PathVariable("identifier") String identifier, @Parameter(in = ParameterIn.DEFAULT, description = "Represents the request body of a bill payment.", required = true, schema = @Schema()) @Valid @RequestBody RequestBillPayment2 body, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API.", schema = @Schema()) @RequestHeader(value = "X-Date", required = false) OffsetDateTime xDate, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to uniquely identify the request. Must be supplied as a UUID.", schema = @Schema()) @RequestHeader(value = "X-CorrelationID", required = false) String xCorrelationID, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's API key to the server.", schema = @Schema()) @RequestHeader(value = "X-API-Key", required = false) String xAPIKey, @Parameter(in = ParameterIn.HEADER, description = "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication.", schema = @Schema()) @RequestHeader(value = "X-User-Bearer", required = false) String xUserBearer, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's identifier to the server.", schema = @Schema()) @RequestHeader(value = "X-Client-Id", required = false) String xClientId, @Parameter(in = ParameterIn.HEADER, description = "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed.", schema = @Schema()) @RequestHeader(value = "X-Content-Hash", required = false) String xContentHash, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", schema = @Schema()) @RequestHeader(value = "X-User-Credential-1", required = false) String xUserCredential1, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", schema = @Schema()) @RequestHeader(value = "X-User-Credential-2", required = false) String xUserCredential2, @Parameter(in = ParameterIn.HEADER, description = "String containing the channel that was used to originate the request. For example USSD, Web, App.", schema = @Schema()) @RequestHeader(value = "X-Channel", required = false) String xChannel, @Parameter(in = ParameterIn.HEADER, description = "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT.", schema = @Schema()) @RequestHeader(value = "X-Callback-URL", required = false) String xCallbackURL, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header.", schema = @Schema(allowableValues = {"lei", "swiftbic", "organisationid"} + )) @RequestHeader(value = "X-Account-Holding-Institution-Identifier-Type", required = false) String xAccountHoldingInstitutionIdentifierType, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header.", schema = @Schema()) @RequestHeader(value = "X-Account-Holding-Institution-Identifier", required = false) String xAccountHoldingInstitutionIdentifier) { + String accept = request.getHeader("Accept"); + if (accept != null && accept.contains("application/json")) { + try { + return new ResponseEntity(objectMapper.readValue("{\n \"serviceProviderNotification\" : \"serviceProviderNotification\",\n \"metadata\" : [ {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n } ],\n \"requestingOrganisation\" : \"requestingOrganisation\",\n \"customData\" : [ {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n } ],\n \"creationDate\" : \"2000-01-23T04:56:07.000+00:00\",\n \"paymentType\" : \"partialpayment\",\n \"modificationDate\" : \"2000-01-23T04:56:07.000+00:00\",\n \"billPaymentStatus\" : \"billPaymentStatus\",\n \"amountPaid\" : \"15.21\",\n \"customerReference\" : \"customerReference\",\n \"requestDate\" : \"2000-01-23T04:56:07.000+00:00\",\n \"requestingOrganisationTransactionReference\" : \"requestingOrganisationTransactionReference\",\n \"currency\" : \"AED\",\n \"serviceProviderPaymentReference\" : \"serviceProviderPaymentReference\",\n \"serviceProviderComment\" : \"serviceProviderComment\"\n}", ResponseBillPayment2.class), HttpStatus.OK); + } catch (IOException e) { + log.error("Couldn't serialize response for content type application/json", e); + return new ResponseEntity(HttpStatus.INTERNAL_SERVER_ERROR); + } + } + + return new ResponseEntity(HttpStatus.OK); + } + + public ResponseEntity accountsIdentifierTypeIdentifierBillsBillReferencePaymentsGET(@Parameter(in = ParameterIn.PATH, description = "Path variable to specify the type of the identifier that is used to identify the account.", required = true, schema = @Schema(allowableValues = {"accountid", "msisdn", "walletid", "linkref", "consumerno", "serviceprovider", "storeid", "accountcategory", "bankaccountno", "accountrank", "identityalias", "iban", "swiftbic", "sortcode", "organisationid", "bankname", "bankaccounttitle", "username", "emailaddress", "mandatereference"} + )) @PathVariable("identifierType") String identifierType, @Size(min = 1, max = 256) @Parameter(in = ParameterIn.PATH, description = "Path variable that contains the account identifier.", required = true, schema = @Schema()) @PathVariable("identifier") String identifier, @Size(min = 1, max = 256) @Parameter(in = ParameterIn.PATH, description = "Path variable to uniquely identify a bill.", required = true, schema = @Schema()) @PathVariable("billReference") String billReference, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API.", schema = @Schema()) @RequestHeader(value = "X-Date", required = false) OffsetDateTime xDate, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's API key to the server.", schema = @Schema()) @RequestHeader(value = "X-API-Key", required = false) String xAPIKey, @Parameter(in = ParameterIn.HEADER, description = "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication.", schema = @Schema()) @RequestHeader(value = "X-User-Bearer", required = false) String xUserBearer, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's identifier to the server.", schema = @Schema()) @RequestHeader(value = "X-Client-Id", required = false) String xClientId, @Parameter(in = ParameterIn.HEADER, description = "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed.", schema = @Schema()) @RequestHeader(value = "X-Content-Hash", required = false) String xContentHash, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", schema = @Schema()) @RequestHeader(value = "X-User-Credential-1", required = false) String xUserCredential1, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", schema = @Schema()) @RequestHeader(value = "X-User-Credential-2", required = false) String xUserCredential2, @Parameter(in = ParameterIn.HEADER, description = "String containing the channel that was used to originate the request. For example USSD, Web, App.", schema = @Schema()) @RequestHeader(value = "X-Channel", required = false) String xChannel, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header.", schema = @Schema(allowableValues = {"lei", "swiftbic", "organisationid"} + )) @RequestHeader(value = "X-Account-Holding-Institution-Identifier-Type", required = false) String xAccountHoldingInstitutionIdentifierType, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header.", schema = @Schema()) @RequestHeader(value = "X-Account-Holding-Institution-Identifier", required = false) String xAccountHoldingInstitutionIdentifier, @Parameter(in = ParameterIn.QUERY, description = "Supports pagination. If this is not supplied, then the server will apply a limit of 50 records returned for each request.", schema = @Schema()) @Valid @RequestParam(value = "limit", required = false) Integer limit, @Parameter(in = ParameterIn.QUERY, description = "Supports pagination. This value will indicate the cursor position from where to retrieve the set of records. For example, a limit of 50 and offset of 10 will return records 11 to 60.", schema = @Schema()) @Valid @RequestParam(value = "offset", required = false) Integer offset, @Parameter(in = ParameterIn.QUERY, description = "Indicates the minimum creation date for which records should be returned.", schema = @Schema()) @Valid @RequestParam(value = "fromDateTime", required = false) OffsetDateTime fromDateTime, @Parameter(in = ParameterIn.QUERY, description = "Indicates the maximum creation date for which records should be returned.", schema = @Schema()) @Valid @RequestParam(value = "toDateTime", required = false) OffsetDateTime toDateTime) { + String accept = request.getHeader("Accept"); + if (accept != null && accept.contains("application/json")) { + try { + return new ResponseEntity(objectMapper.readValue("{\n \"supplementaryBillReferenceDetails\" : [ {\n \"paymentReferenceType\" : \"paymentReferenceType\",\n \"paymentReferenceValue\" : \"paymentReferenceValue\"\n }, {\n \"paymentReferenceType\" : \"paymentReferenceType\",\n \"paymentReferenceValue\" : \"paymentReferenceValue\"\n }, {\n \"paymentReferenceType\" : \"paymentReferenceType\",\n \"paymentReferenceValue\" : \"paymentReferenceValue\"\n }, {\n \"paymentReferenceType\" : \"paymentReferenceType\",\n \"paymentReferenceValue\" : \"paymentReferenceValue\"\n }, {\n \"paymentReferenceType\" : \"paymentReferenceType\",\n \"paymentReferenceValue\" : \"paymentReferenceValue\"\n }, {\n \"paymentReferenceType\" : \"paymentReferenceType\",\n \"paymentReferenceValue\" : \"paymentReferenceValue\"\n }, {\n \"paymentReferenceType\" : \"paymentReferenceType\",\n \"paymentReferenceValue\" : \"paymentReferenceValue\"\n }, {\n \"paymentReferenceType\" : \"paymentReferenceType\",\n \"paymentReferenceValue\" : \"paymentReferenceValue\"\n }, {\n \"paymentReferenceType\" : \"paymentReferenceType\",\n \"paymentReferenceValue\" : \"paymentReferenceValue\"\n }, {\n \"paymentReferenceType\" : \"paymentReferenceType\",\n \"paymentReferenceValue\" : \"paymentReferenceValue\"\n } ],\n \"serviceProviderNotification\" : \"serviceProviderNotification\",\n \"metadata\" : [ {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n } ],\n \"requestingOrganisation\" : \"requestingOrganisation\",\n \"customData\" : [ {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n } ],\n \"creationDate\" : \"2000-01-23T04:56:07.000+00:00\",\n \"paymentType\" : \"partialpayment\",\n \"modificationDate\" : \"2000-01-23T04:56:07.000+00:00\",\n \"billPaymentStatus\" : \"billPaymentStatus\",\n \"amountPaid\" : \"15.21\",\n \"customerReference\" : \"customerReference\",\n \"requestDate\" : \"2000-01-23T04:56:07.000+00:00\",\n \"requestingOrganisationTransactionReference\" : \"requestingOrganisationTransactionReference\",\n \"currency\" : \"AED\",\n \"serviceProviderPaymentReference\" : \"serviceProviderPaymentReference\",\n \"serviceProviderComment\" : \"serviceProviderComment\"\n}", ResponseBillPayment.class), HttpStatus.OK); + } catch (IOException e) { + log.error("Couldn't serialize response for content type application/json", e); + return new ResponseEntity(HttpStatus.INTERNAL_SERVER_ERROR); + } + } + + return new ResponseEntity(HttpStatus.OK); + } + + public ResponseEntity accountsIdentifierTypeIdentifierBillsBillReferencePaymentsPOST(@Parameter(in = ParameterIn.PATH, description = "Path variable to specify the type of the identifier that is used to identify the account.", required = true, schema = @Schema(allowableValues = {"accountid", "msisdn", "walletid", "linkref", "consumerno", "serviceprovider", "storeid", "accountcategory", "bankaccountno", "accountrank", "identityalias", "iban", "swiftbic", "sortcode", "organisationid", "bankname", "bankaccounttitle", "username", "emailaddress", "mandatereference"} + )) @PathVariable("identifierType") String identifierType, @Size(min = 1, max = 256) @Parameter(in = ParameterIn.PATH, description = "Path variable that contains the account identifier.", required = true, schema = @Schema()) @PathVariable("identifier") String identifier, @Size(min = 1, max = 256) @Parameter(in = ParameterIn.PATH, description = "Path variable to uniquely identify a bill.", required = true, schema = @Schema()) @PathVariable("billReference") String billReference, @Parameter(in = ParameterIn.DEFAULT, description = "Represents the request body of a bill payment.", required = true, schema = @Schema()) @Valid @RequestBody RequestBillPayment body, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API.", schema = @Schema()) @RequestHeader(value = "X-Date", required = false) OffsetDateTime xDate, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to uniquely identify the request. Must be supplied as a UUID.", schema = @Schema()) @RequestHeader(value = "X-CorrelationID", required = false) String xCorrelationID, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's API key to the server.", schema = @Schema()) @RequestHeader(value = "X-API-Key", required = false) String xAPIKey, @Parameter(in = ParameterIn.HEADER, description = "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication.", schema = @Schema()) @RequestHeader(value = "X-User-Bearer", required = false) String xUserBearer, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's identifier to the server.", schema = @Schema()) @RequestHeader(value = "X-Client-Id", required = false) String xClientId, @Parameter(in = ParameterIn.HEADER, description = "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed.", schema = @Schema()) @RequestHeader(value = "X-Content-Hash", required = false) String xContentHash, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", schema = @Schema()) @RequestHeader(value = "X-User-Credential-1", required = false) String xUserCredential1, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", schema = @Schema()) @RequestHeader(value = "X-User-Credential-2", required = false) String xUserCredential2, @Parameter(in = ParameterIn.HEADER, description = "String containing the channel that was used to originate the request. For example USSD, Web, App.", schema = @Schema()) @RequestHeader(value = "X-Channel", required = false) String xChannel, @Parameter(in = ParameterIn.HEADER, description = "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT.", schema = @Schema()) @RequestHeader(value = "X-Callback-URL", required = false) String xCallbackURL, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header.", schema = @Schema(allowableValues = {"lei", "swiftbic", "organisationid"} + )) @RequestHeader(value = "X-Account-Holding-Institution-Identifier-Type", required = false) String xAccountHoldingInstitutionIdentifierType, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header.", schema = @Schema()) @RequestHeader(value = "X-Account-Holding-Institution-Identifier", required = false) String xAccountHoldingInstitutionIdentifier) { + String accept = request.getHeader("Accept"); + if (accept != null && accept.contains("application/json")) { + try { + return new ResponseEntity(objectMapper.readValue("{\n \"supplementaryBillReferenceDetails\" : [ {\n \"paymentReferenceType\" : \"paymentReferenceType\",\n \"paymentReferenceValue\" : \"paymentReferenceValue\"\n }, {\n \"paymentReferenceType\" : \"paymentReferenceType\",\n \"paymentReferenceValue\" : \"paymentReferenceValue\"\n }, {\n \"paymentReferenceType\" : \"paymentReferenceType\",\n \"paymentReferenceValue\" : \"paymentReferenceValue\"\n }, {\n \"paymentReferenceType\" : \"paymentReferenceType\",\n \"paymentReferenceValue\" : \"paymentReferenceValue\"\n }, {\n \"paymentReferenceType\" : \"paymentReferenceType\",\n \"paymentReferenceValue\" : \"paymentReferenceValue\"\n }, {\n \"paymentReferenceType\" : \"paymentReferenceType\",\n \"paymentReferenceValue\" : \"paymentReferenceValue\"\n }, {\n \"paymentReferenceType\" : \"paymentReferenceType\",\n \"paymentReferenceValue\" : \"paymentReferenceValue\"\n }, {\n \"paymentReferenceType\" : \"paymentReferenceType\",\n \"paymentReferenceValue\" : \"paymentReferenceValue\"\n }, {\n \"paymentReferenceType\" : \"paymentReferenceType\",\n \"paymentReferenceValue\" : \"paymentReferenceValue\"\n }, {\n \"paymentReferenceType\" : \"paymentReferenceType\",\n \"paymentReferenceValue\" : \"paymentReferenceValue\"\n } ],\n \"serviceProviderNotification\" : \"serviceProviderNotification\",\n \"metadata\" : [ {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n } ],\n \"requestingOrganisation\" : \"requestingOrganisation\",\n \"customData\" : [ {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n } ],\n \"creationDate\" : \"2000-01-23T04:56:07.000+00:00\",\n \"paymentType\" : \"partialpayment\",\n \"modificationDate\" : \"2000-01-23T04:56:07.000+00:00\",\n \"billPaymentStatus\" : \"billPaymentStatus\",\n \"amountPaid\" : \"15.21\",\n \"customerReference\" : \"customerReference\",\n \"requestDate\" : \"2000-01-23T04:56:07.000+00:00\",\n \"requestingOrganisationTransactionReference\" : \"requestingOrganisationTransactionReference\",\n \"currency\" : \"AED\",\n \"serviceProviderPaymentReference\" : \"serviceProviderPaymentReference\",\n \"serviceProviderComment\" : \"serviceProviderComment\"\n}", ResponseBillPayment.class), HttpStatus.OK); + } catch (IOException e) { + log.error("Couldn't serialize response for content type application/json", e); + return new ResponseEntity(HttpStatus.INTERNAL_SERVER_ERROR); + } + } + + return new ResponseEntity(HttpStatus.OK); + } + + public ResponseEntity> accountsIdentifierTypeIdentifierBillsGET(@Parameter(in = ParameterIn.PATH, description = "Path variable to specify the type of the identifier that is used to identify the account.", required = true, schema = @Schema(allowableValues = {"accountid", "msisdn", "walletid", "linkref", "consumerno", "serviceprovider", "storeid", "accountcategory", "bankaccountno", "accountrank", "identityalias", "iban", "swiftbic", "sortcode", "organisationid", "bankname", "bankaccounttitle", "username", "emailaddress", "mandatereference"} + )) @PathVariable("identifierType") String identifierType, @Size(min = 1, max = 256) @Parameter(in = ParameterIn.PATH, description = "Path variable that contains the account identifier.", required = true, schema = @Schema()) @PathVariable("identifier") String identifier, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API.", schema = @Schema()) @RequestHeader(value = "X-Date", required = false) OffsetDateTime xDate, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's API key to the server.", schema = @Schema()) @RequestHeader(value = "X-API-Key", required = false) String xAPIKey, @Parameter(in = ParameterIn.HEADER, description = "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication.", schema = @Schema()) @RequestHeader(value = "X-User-Bearer", required = false) String xUserBearer, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's identifier to the server.", schema = @Schema()) @RequestHeader(value = "X-Client-Id", required = false) String xClientId, @Parameter(in = ParameterIn.HEADER, description = "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed.", schema = @Schema()) @RequestHeader(value = "X-Content-Hash", required = false) String xContentHash, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", schema = @Schema()) @RequestHeader(value = "X-User-Credential-1", required = false) String xUserCredential1, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", schema = @Schema()) @RequestHeader(value = "X-User-Credential-2", required = false) String xUserCredential2, @Parameter(in = ParameterIn.HEADER, description = "String containing the channel that was used to originate the request. For example USSD, Web, App.", schema = @Schema()) @RequestHeader(value = "X-Channel", required = false) String xChannel, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header.", schema = @Schema(allowableValues = {"lei", "swiftbic", "organisationid"} + )) @RequestHeader(value = "X-Account-Holding-Institution-Identifier-Type", required = false) String xAccountHoldingInstitutionIdentifierType, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header.", schema = @Schema()) @RequestHeader(value = "X-Account-Holding-Institution-Identifier", required = false) String xAccountHoldingInstitutionIdentifier, @Parameter(in = ParameterIn.QUERY, description = "Supports pagination. If this is not supplied, then the server will apply a limit of 50 records returned for each request.", schema = @Schema()) @Valid @RequestParam(value = "limit", required = false) Integer limit, @Parameter(in = ParameterIn.QUERY, description = "Supports pagination. This value will indicate the cursor position from where to retrieve the set of records. For example, a limit of 50 and offset of 10 will return records 11 to 60.", schema = @Schema()) @Valid @RequestParam(value = "offset", required = false) Integer offset, @Parameter(in = ParameterIn.QUERY, description = "Indicates the minimum creation date for which records should be returned.", schema = @Schema()) @Valid @RequestParam(value = "fromDateTime", required = false) OffsetDateTime fromDateTime, @Parameter(in = ParameterIn.QUERY, description = "Indicates the maximum creation date for which records should be returned.", schema = @Schema()) @Valid @RequestParam(value = "toDateTime", required = false) OffsetDateTime toDateTime) { + String accept = request.getHeader("Accept"); + if (accept != null && accept.contains("application/json")) { + try { + return new ResponseEntity>(objectMapper.readValue("[ {\n \"amountDue\" : \"15.21\",\n \"billdescription\" : \"billdescription\",\n \"modificationDate\" : \"2000-01-23T04:56:07.000+00:00\",\n \"metadata\" : [ {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n } ],\n \"dueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"billStatus\" : \"unpaid\",\n \"currency\" : \"AED\",\n \"customData\" : [ {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n } ],\n \"creationDate\" : \"2000-01-23T04:56:07.000+00:00\",\n \"billReference\" : \"billReference\"\n}, {\n \"amountDue\" : \"15.21\",\n \"billdescription\" : \"billdescription\",\n \"modificationDate\" : \"2000-01-23T04:56:07.000+00:00\",\n \"metadata\" : [ {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n } ],\n \"dueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"billStatus\" : \"unpaid\",\n \"currency\" : \"AED\",\n \"customData\" : [ {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n } ],\n \"creationDate\" : \"2000-01-23T04:56:07.000+00:00\",\n \"billReference\" : \"billReference\"\n} ]", List.class), HttpStatus.OK); + } catch (IOException e) { + log.error("Couldn't serialize response for content type application/json", e); + return new ResponseEntity>(HttpStatus.INTERNAL_SERVER_ERROR); + } + } + + return new ResponseEntity>(HttpStatus.OK); + } + + public ResponseEntity accountsIdentifierTypeIdentifierDebitmandatesDebitMandateReferenceGET(@Parameter(in = ParameterIn.PATH, description = "Path variable to specify the type of the identifier that is used to identify the account.", required = true, schema = @Schema(allowableValues = {"accountid", "msisdn", "walletid", "linkref", "consumerno", "serviceprovider", "storeid", "accountcategory", "bankaccountno", "accountrank", "identityalias", "iban", "swiftbic", "sortcode", "organisationid", "bankname", "bankaccounttitle", "username", "emailaddress", "mandatereference"} + )) @PathVariable("identifierType") String identifierType, @Size(min = 1, max = 256) @Parameter(in = ParameterIn.PATH, description = "Path variable that contains the account identifier.", required = true, schema = @Schema()) @PathVariable("identifier") String identifier, @Size(min = 1, max = 256) @Parameter(in = ParameterIn.PATH, description = "Path variable to uniquely identify a Debit Mandate Reference.", required = true, schema = @Schema()) @PathVariable("debitMandateReference") String debitMandateReference, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API.", schema = @Schema()) @RequestHeader(value = "X-Date", required = false) OffsetDateTime xDate, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's API key to the server.", schema = @Schema()) @RequestHeader(value = "X-API-Key", required = false) String xAPIKey, @Parameter(in = ParameterIn.HEADER, description = "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication.", schema = @Schema()) @RequestHeader(value = "X-User-Bearer", required = false) String xUserBearer, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's identifier to the server.", schema = @Schema()) @RequestHeader(value = "X-Client-Id", required = false) String xClientId, @Parameter(in = ParameterIn.HEADER, description = "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed.", schema = @Schema()) @RequestHeader(value = "X-Content-Hash", required = false) String xContentHash, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", schema = @Schema()) @RequestHeader(value = "X-User-Credential-1", required = false) String xUserCredential1, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", schema = @Schema()) @RequestHeader(value = "X-User-Credential-2", required = false) String xUserCredential2, @Parameter(in = ParameterIn.HEADER, description = "String containing the channel that was used to originate the request. For example USSD, Web, App.", schema = @Schema()) @RequestHeader(value = "X-Channel", required = false) String xChannel, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header.", schema = @Schema(allowableValues = {"lei", "swiftbic", "organisationid"} + )) @RequestHeader(value = "X-Account-Holding-Institution-Identifier-Type", required = false) String xAccountHoldingInstitutionIdentifierType, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header.", schema = @Schema()) @RequestHeader(value = "X-Account-Holding-Institution-Identifier", required = false) String xAccountHoldingInstitutionIdentifier) { + String accept = request.getHeader("Accept"); + if (accept != null && accept.contains("application/json")) { + try { + return new ResponseEntity(objectMapper.readValue("{\n \"amountLimit\" : \"15.21\",\n \"numberOfPayments\" : 0.08008281904610115,\n \"endDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"requestingOrganisation\" : {\n \"requestingOrganisationIdentifierType\" : \"lei\",\n \"requestingOrganisationIdentifier\" : \"requestingOrganisationIdentifier\"\n },\n \"customData\" : [ {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n } ],\n \"dateModified\" : \"2000-01-23T04:56:07.000+00:00\",\n \"creationDate\" : \"2000-01-23T04:56:07.000+00:00\",\n \"payee\" : [ {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n } ],\n \"mandateReference\" : \"mandateReference\",\n \"modificationDate\" : \"2000-01-23T04:56:07.000+00:00\",\n \"dateCreated\" : \"2000-01-23T04:56:07.000+00:00\",\n \"mandateStatus\" : \"active\",\n \"frequencyType\" : \"weekly\",\n \"requestDate\" : \"2000-01-23T04:56:07.000+00:00\",\n \"currency\" : \"AED\",\n \"startDate\" : \"2018-11-20T00:00:00.000+00:00\"\n}", ResponseDebitMandate.class), HttpStatus.OK); + } catch (IOException e) { + log.error("Couldn't serialize response for content type application/json", e); + return new ResponseEntity(HttpStatus.INTERNAL_SERVER_ERROR); + } + } + + return new ResponseEntity(HttpStatus.OK); + } + + public ResponseEntity accountsIdentifierTypeIdentifierDebitmandatesDebitMandateReferencePATCH(@Parameter(in = ParameterIn.PATH, description = "Path variable to specify the type of the identifier that is used to identify the account.", required = true, schema = @Schema(allowableValues = {"accountid", "msisdn", "walletid", "linkref", "consumerno", "serviceprovider", "storeid", "accountcategory", "bankaccountno", "accountrank", "identityalias", "iban", "swiftbic", "sortcode", "organisationid", "bankname", "bankaccounttitle", "username", "emailaddress", "mandatereference"} + )) @PathVariable("identifierType") String identifierType, @Size(min = 1, max = 256) @Parameter(in = ParameterIn.PATH, description = "Path variable that contains the account identifier.", required = true, schema = @Schema()) @PathVariable("identifier") String identifier, @Size(min = 1, max = 256) @Parameter(in = ParameterIn.PATH, description = "Path variable to uniquely identify a Debit Mandate Reference.", required = true, schema = @Schema()) @PathVariable("debitMandateReference") String debitMandateReference, @Parameter(in = ParameterIn.DEFAULT, description = "Represents the request body of a batch of generic Patch operation.", required = true, schema = @Schema()) @Valid @RequestBody List body, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API.", schema = @Schema()) @RequestHeader(value = "X-Date", required = false) OffsetDateTime xDate, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's API key to the server.", schema = @Schema()) @RequestHeader(value = "X-API-Key", required = false) String xAPIKey, @Parameter(in = ParameterIn.HEADER, description = "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication.", schema = @Schema()) @RequestHeader(value = "X-User-Bearer", required = false) String xUserBearer, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's identifier to the server.", schema = @Schema()) @RequestHeader(value = "X-Client-Id", required = false) String xClientId, @Parameter(in = ParameterIn.HEADER, description = "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed.", schema = @Schema()) @RequestHeader(value = "X-Content-Hash", required = false) String xContentHash, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", schema = @Schema()) @RequestHeader(value = "X-User-Credential-1", required = false) String xUserCredential1, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", schema = @Schema()) @RequestHeader(value = "X-User-Credential-2", required = false) String xUserCredential2, @Parameter(in = ParameterIn.HEADER, description = "String containing the channel that was used to originate the request. For example USSD, Web, App.", schema = @Schema()) @RequestHeader(value = "X-Channel", required = false) String xChannel, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header.", schema = @Schema(allowableValues = {"lei", "swiftbic", "organisationid"} + )) @RequestHeader(value = "X-Account-Holding-Institution-Identifier-Type", required = false) String xAccountHoldingInstitutionIdentifierType, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header.", schema = @Schema()) @RequestHeader(value = "X-Account-Holding-Institution-Identifier", required = false) String xAccountHoldingInstitutionIdentifier, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to uniquely identify the request. Must be supplied as a UUID.", schema = @Schema()) @RequestHeader(value = "X-CorrelationID", required = false) String xCorrelationID, @Parameter(in = ParameterIn.HEADER, description = "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT.", schema = @Schema()) @RequestHeader(value = "X-Callback-URL", required = false) String xCallbackURL) { + String accept = request.getHeader("Accept"); + if (accept != null && accept.contains("application/json")) { + try { + return new ResponseEntity(objectMapper.readValue("{\n \"pollLimit\" : 0.08008281904610115,\n \"pendingReason\" : \"pendingReason\",\n \"expiryTime\" : \"2000-01-23T04:56:07.000+00:00\",\n \"objectReference\" : \"objectReference\",\n \"notificationMethod\" : \"callback\",\n \"error\" : {\n \"errordescription\" : \"errordescription\",\n \"errorCategory\" : \"businessRule\",\n \"errorParameters\" : [ {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n } ],\n \"errorDateTime\" : \"2000-01-23T04:56:07.000+00:00\",\n \"errorCode\" : \"genericError\"\n },\n \"serverCorrelationId\" : \"serverCorrelationId\",\n \"status\" : \"pending\"\n}", RequestStateObject.class), HttpStatus.OK); + } catch (IOException e) { + log.error("Couldn't serialize response for content type application/json", e); + return new ResponseEntity(HttpStatus.INTERNAL_SERVER_ERROR); + } + } + + return new ResponseEntity(HttpStatus.OK); + } + + public ResponseEntity accountsIdentifierTypeIdentifierDebitmandatesPOST(@Parameter(in = ParameterIn.PATH, description = "Path variable to specify the type of the identifier that is used to identify the account.", required = true, schema = @Schema(allowableValues = {"accountid", "msisdn", "walletid", "linkref", "consumerno", "serviceprovider", "storeid", "accountcategory", "bankaccountno", "accountrank", "identityalias", "iban", "swiftbic", "sortcode", "organisationid", "bankname", "bankaccounttitle", "username", "emailaddress", "mandatereference"} + )) @PathVariable("identifierType") String identifierType, @Size(min = 1, max = 256) @Parameter(in = ParameterIn.PATH, description = "Path variable that contains the account identifier.", required = true, schema = @Schema()) @PathVariable("identifier") String identifier, @Parameter(in = ParameterIn.DEFAULT, description = "Represents the request body of a debit mandate.", required = true, schema = @Schema()) @Valid @RequestBody RequestDebitMandate body, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API.", schema = @Schema()) @RequestHeader(value = "X-Date", required = false) OffsetDateTime xDate, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to uniquely identify the request. Must be supplied as a UUID.", schema = @Schema()) @RequestHeader(value = "X-CorrelationID", required = false) String xCorrelationID, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's API key to the server.", schema = @Schema()) @RequestHeader(value = "X-API-Key", required = false) String xAPIKey, @Parameter(in = ParameterIn.HEADER, description = "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication.", schema = @Schema()) @RequestHeader(value = "X-User-Bearer", required = false) String xUserBearer, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's identifier to the server.", schema = @Schema()) @RequestHeader(value = "X-Client-Id", required = false) String xClientId, @Parameter(in = ParameterIn.HEADER, description = "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed.", schema = @Schema()) @RequestHeader(value = "X-Content-Hash", required = false) String xContentHash, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", schema = @Schema()) @RequestHeader(value = "X-User-Credential-1", required = false) String xUserCredential1, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", schema = @Schema()) @RequestHeader(value = "X-User-Credential-2", required = false) String xUserCredential2, @Parameter(in = ParameterIn.HEADER, description = "String containing the channel that was used to originate the request. For example USSD, Web, App.", schema = @Schema()) @RequestHeader(value = "X-Channel", required = false) String xChannel, @Parameter(in = ParameterIn.HEADER, description = "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT.", schema = @Schema()) @RequestHeader(value = "X-Callback-URL", required = false) String xCallbackURL, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header.", schema = @Schema(allowableValues = {"lei", "swiftbic", "organisationid"} + )) @RequestHeader(value = "X-Account-Holding-Institution-Identifier-Type", required = false) String xAccountHoldingInstitutionIdentifierType, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header.", schema = @Schema()) @RequestHeader(value = "X-Account-Holding-Institution-Identifier", required = false) String xAccountHoldingInstitutionIdentifier) { + String accept = request.getHeader("Accept"); + if (accept != null && accept.contains("application/json")) { + try { + return new ResponseEntity(objectMapper.readValue("{\n \"amountLimit\" : \"15.21\",\n \"numberOfPayments\" : 0.08008281904610115,\n \"endDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"requestingOrganisation\" : {\n \"requestingOrganisationIdentifierType\" : \"lei\",\n \"requestingOrganisationIdentifier\" : \"requestingOrganisationIdentifier\"\n },\n \"customData\" : [ {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n } ],\n \"dateModified\" : \"2000-01-23T04:56:07.000+00:00\",\n \"creationDate\" : \"2000-01-23T04:56:07.000+00:00\",\n \"payee\" : [ {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n } ],\n \"mandateReference\" : \"mandateReference\",\n \"modificationDate\" : \"2000-01-23T04:56:07.000+00:00\",\n \"dateCreated\" : \"2000-01-23T04:56:07.000+00:00\",\n \"mandateStatus\" : \"active\",\n \"frequencyType\" : \"weekly\",\n \"requestDate\" : \"2000-01-23T04:56:07.000+00:00\",\n \"currency\" : \"AED\",\n \"startDate\" : \"2018-11-20T00:00:00.000+00:00\"\n}", ResponseDebitMandate.class), HttpStatus.OK); + } catch (IOException e) { + log.error("Couldn't serialize response for content type application/json", e); + return new ResponseEntity(HttpStatus.INTERNAL_SERVER_ERROR); + } + } + + return new ResponseEntity(HttpStatus.OK); + } + + public ResponseEntity accountsIdentifierTypeIdentifierGET(@Parameter(in = ParameterIn.PATH, description = "Path variable to specify the type of the identifier that is used to identify the account.", required = true, schema = @Schema(allowableValues = {"accountid", "msisdn", "walletid", "linkref", "consumerno", "serviceprovider", "storeid", "accountcategory", "bankaccountno", "accountrank", "identityalias", "iban", "swiftbic", "sortcode", "organisationid", "bankname", "bankaccounttitle", "username", "emailaddress", "mandatereference"} + )) @PathVariable("identifierType") String identifierType, @Size(min = 1, max = 256) @Parameter(in = ParameterIn.PATH, description = "Path variable that contains the account identifier.", required = true, schema = @Schema()) @PathVariable("identifier") String identifier, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API.", schema = @Schema()) @RequestHeader(value = "X-Date", required = false) OffsetDateTime xDate, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's API key to the server.", schema = @Schema()) @RequestHeader(value = "X-API-Key", required = false) String xAPIKey, @Parameter(in = ParameterIn.HEADER, description = "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication.", schema = @Schema()) @RequestHeader(value = "X-User-Bearer", required = false) String xUserBearer, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's identifier to the server.", schema = @Schema()) @RequestHeader(value = "X-Client-Id", required = false) String xClientId, @Parameter(in = ParameterIn.HEADER, description = "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed.", schema = @Schema()) @RequestHeader(value = "X-Content-Hash", required = false) String xContentHash, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", schema = @Schema()) @RequestHeader(value = "X-User-Credential-1", required = false) String xUserCredential1, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", schema = @Schema()) @RequestHeader(value = "X-User-Credential-2", required = false) String xUserCredential2, @Parameter(in = ParameterIn.HEADER, description = "String containing the channel that was used to originate the request. For example USSD, Web, App.", schema = @Schema()) @RequestHeader(value = "X-Channel", required = false) String xChannel, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header.", schema = @Schema(allowableValues = {"lei", "swiftbic", "organisationid"} + )) @RequestHeader(value = "X-Account-Holding-Institution-Identifier-Type", required = false) String xAccountHoldingInstitutionIdentifierType, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header.", schema = @Schema()) @RequestHeader(value = "X-Account-Holding-Institution-Identifier", required = false) String xAccountHoldingInstitutionIdentifier) { + String accept = request.getHeader("Accept"); + if (accept != null && accept.contains("application/json")) { + try { + return new ResponseEntity(objectMapper.readValue("{\n \"fees\" : [ {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n } ],\n \"commissionEarned\" : [ {\n \"commissionType\" : \"commissionType\"\n }, {\n \"commissionType\" : \"commissionType\"\n }, {\n \"commissionType\" : \"commissionType\"\n }, {\n \"commissionType\" : \"commissionType\"\n }, {\n \"commissionType\" : \"commissionType\"\n }, {\n \"commissionType\" : \"commissionType\"\n }, {\n \"commissionType\" : \"commissionType\"\n }, {\n \"commissionType\" : \"commissionType\"\n }, {\n \"commissionType\" : \"commissionType\"\n }, {\n \"commissionType\" : \"commissionType\"\n } ],\n \"accountType\" : \"accountType\",\n \"currentBalance\" : \"15.21\",\n \"creationDate\" : \"2000-01-23T04:56:07.000+00:00\",\n \"accountStatus\" : \"available\",\n \"registeringEntity\" : \"registeringEntity\",\n \"modificationDate\" : \"2000-01-23T04:56:07.000+00:00\",\n \"identity\" : [ {\n \"kycLevel\" : 1,\n \"identityType\" : \"individual\",\n \"identityId\" : \"identityId\",\n \"identityStatus\" : \"identityStatus\",\n \"accountRelationship\" : \"accountholder\",\n \"customData\" : [ {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n } ],\n \"identityKyc\" : {\n \"emailAddress\" : \"emailAddress\",\n \"occupation\" : \"occupation\",\n \"postalAddress\" : {\n \"city\" : \"city\",\n \"postalCode\" : \"postalCode\",\n \"addressLine1\" : \"addressLine1\",\n \"stateProvince\" : \"stateProvince\",\n \"addressLine2\" : \"addressLine2\",\n \"addressLine3\" : \"addressLine3\"\n },\n \"gender\" : \"m\",\n \"idDocument\" : [ {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n } ],\n \"employerName\" : \"employerName\",\n \"dateOfBirth\" : \"2000-11-20T00:00:00.000+00:00\",\n \"contactPhone\" : \"contactPhone\",\n \"subjectName\" : {\n \"firstName\" : \"firstName\",\n \"lastName\" : \"lastName\",\n \"nativeName\" : \"nativeName\",\n \"fullName\" : \"fullName\",\n \"middleName\" : \"middleName\",\n \"title\" : \"title\"\n }\n },\n \"kycVerificationStatus\" : \"verified\",\n \"kycVerificationEntity\" : \"kycVerificationEntity\"\n }, {\n \"kycLevel\" : 1,\n \"identityType\" : \"individual\",\n \"identityId\" : \"identityId\",\n \"identityStatus\" : \"identityStatus\",\n \"accountRelationship\" : \"accountholder\",\n \"customData\" : [ {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n } ],\n \"identityKyc\" : {\n \"emailAddress\" : \"emailAddress\",\n \"occupation\" : \"occupation\",\n \"postalAddress\" : {\n \"city\" : \"city\",\n \"postalCode\" : \"postalCode\",\n \"addressLine1\" : \"addressLine1\",\n \"stateProvince\" : \"stateProvince\",\n \"addressLine2\" : \"addressLine2\",\n \"addressLine3\" : \"addressLine3\"\n },\n \"gender\" : \"m\",\n \"idDocument\" : [ {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n } ],\n \"employerName\" : \"employerName\",\n \"dateOfBirth\" : \"2000-11-20T00:00:00.000+00:00\",\n \"contactPhone\" : \"contactPhone\",\n \"subjectName\" : {\n \"firstName\" : \"firstName\",\n \"lastName\" : \"lastName\",\n \"nativeName\" : \"nativeName\",\n \"fullName\" : \"fullName\",\n \"middleName\" : \"middleName\",\n \"title\" : \"title\"\n }\n },\n \"kycVerificationStatus\" : \"verified\",\n \"kycVerificationEntity\" : \"kycVerificationEntity\"\n }, {\n \"kycLevel\" : 1,\n \"identityType\" : \"individual\",\n \"identityId\" : \"identityId\",\n \"identityStatus\" : \"identityStatus\",\n \"accountRelationship\" : \"accountholder\",\n \"customData\" : [ {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n } ],\n \"identityKyc\" : {\n \"emailAddress\" : \"emailAddress\",\n \"occupation\" : \"occupation\",\n \"postalAddress\" : {\n \"city\" : \"city\",\n \"postalCode\" : \"postalCode\",\n \"addressLine1\" : \"addressLine1\",\n \"stateProvince\" : \"stateProvince\",\n \"addressLine2\" : \"addressLine2\",\n \"addressLine3\" : \"addressLine3\"\n },\n \"gender\" : \"m\",\n \"idDocument\" : [ {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n } ],\n \"employerName\" : \"employerName\",\n \"dateOfBirth\" : \"2000-11-20T00:00:00.000+00:00\",\n \"contactPhone\" : \"contactPhone\",\n \"subjectName\" : {\n \"firstName\" : \"firstName\",\n \"lastName\" : \"lastName\",\n \"nativeName\" : \"nativeName\",\n \"fullName\" : \"fullName\",\n \"middleName\" : \"middleName\",\n \"title\" : \"title\"\n }\n },\n \"kycVerificationStatus\" : \"verified\",\n \"kycVerificationEntity\" : \"kycVerificationEntity\"\n }, {\n \"kycLevel\" : 1,\n \"identityType\" : \"individual\",\n \"identityId\" : \"identityId\",\n \"identityStatus\" : \"identityStatus\",\n \"accountRelationship\" : \"accountholder\",\n \"customData\" : [ {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n } ],\n \"identityKyc\" : {\n \"emailAddress\" : \"emailAddress\",\n \"occupation\" : \"occupation\",\n \"postalAddress\" : {\n \"city\" : \"city\",\n \"postalCode\" : \"postalCode\",\n \"addressLine1\" : \"addressLine1\",\n \"stateProvince\" : \"stateProvince\",\n \"addressLine2\" : \"addressLine2\",\n \"addressLine3\" : \"addressLine3\"\n },\n \"gender\" : \"m\",\n \"idDocument\" : [ {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n } ],\n \"employerName\" : \"employerName\",\n \"dateOfBirth\" : \"2000-11-20T00:00:00.000+00:00\",\n \"contactPhone\" : \"contactPhone\",\n \"subjectName\" : {\n \"firstName\" : \"firstName\",\n \"lastName\" : \"lastName\",\n \"nativeName\" : \"nativeName\",\n \"fullName\" : \"fullName\",\n \"middleName\" : \"middleName\",\n \"title\" : \"title\"\n }\n },\n \"kycVerificationStatus\" : \"verified\",\n \"kycVerificationEntity\" : \"kycVerificationEntity\"\n }, {\n \"kycLevel\" : 1,\n \"identityType\" : \"individual\",\n \"identityId\" : \"identityId\",\n \"identityStatus\" : \"identityStatus\",\n \"accountRelationship\" : \"accountholder\",\n \"customData\" : [ {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n } ],\n \"identityKyc\" : {\n \"emailAddress\" : \"emailAddress\",\n \"occupation\" : \"occupation\",\n \"postalAddress\" : {\n \"city\" : \"city\",\n \"postalCode\" : \"postalCode\",\n \"addressLine1\" : \"addressLine1\",\n \"stateProvince\" : \"stateProvince\",\n \"addressLine2\" : \"addressLine2\",\n \"addressLine3\" : \"addressLine3\"\n },\n \"gender\" : \"m\",\n \"idDocument\" : [ {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n } ],\n \"employerName\" : \"employerName\",\n \"dateOfBirth\" : \"2000-11-20T00:00:00.000+00:00\",\n \"contactPhone\" : \"contactPhone\",\n \"subjectName\" : {\n \"firstName\" : \"firstName\",\n \"lastName\" : \"lastName\",\n \"nativeName\" : \"nativeName\",\n \"fullName\" : \"fullName\",\n \"middleName\" : \"middleName\",\n \"title\" : \"title\"\n }\n },\n \"kycVerificationStatus\" : \"verified\",\n \"kycVerificationEntity\" : \"kycVerificationEntity\"\n }, {\n \"kycLevel\" : 1,\n \"identityType\" : \"individual\",\n \"identityId\" : \"identityId\",\n \"identityStatus\" : \"identityStatus\",\n \"accountRelationship\" : \"accountholder\",\n \"customData\" : [ {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n } ],\n \"identityKyc\" : {\n \"emailAddress\" : \"emailAddress\",\n \"occupation\" : \"occupation\",\n \"postalAddress\" : {\n \"city\" : \"city\",\n \"postalCode\" : \"postalCode\",\n \"addressLine1\" : \"addressLine1\",\n \"stateProvince\" : \"stateProvince\",\n \"addressLine2\" : \"addressLine2\",\n \"addressLine3\" : \"addressLine3\"\n },\n \"gender\" : \"m\",\n \"idDocument\" : [ {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n } ],\n \"employerName\" : \"employerName\",\n \"dateOfBirth\" : \"2000-11-20T00:00:00.000+00:00\",\n \"contactPhone\" : \"contactPhone\",\n \"subjectName\" : {\n \"firstName\" : \"firstName\",\n \"lastName\" : \"lastName\",\n \"nativeName\" : \"nativeName\",\n \"fullName\" : \"fullName\",\n \"middleName\" : \"middleName\",\n \"title\" : \"title\"\n }\n },\n \"kycVerificationStatus\" : \"verified\",\n \"kycVerificationEntity\" : \"kycVerificationEntity\"\n }, {\n \"kycLevel\" : 1,\n \"identityType\" : \"individual\",\n \"identityId\" : \"identityId\",\n \"identityStatus\" : \"identityStatus\",\n \"accountRelationship\" : \"accountholder\",\n \"customData\" : [ {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n } ],\n \"identityKyc\" : {\n \"emailAddress\" : \"emailAddress\",\n \"occupation\" : \"occupation\",\n \"postalAddress\" : {\n \"city\" : \"city\",\n \"postalCode\" : \"postalCode\",\n \"addressLine1\" : \"addressLine1\",\n \"stateProvince\" : \"stateProvince\",\n \"addressLine2\" : \"addressLine2\",\n \"addressLine3\" : \"addressLine3\"\n },\n \"gender\" : \"m\",\n \"idDocument\" : [ {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n } ],\n \"employerName\" : \"employerName\",\n \"dateOfBirth\" : \"2000-11-20T00:00:00.000+00:00\",\n \"contactPhone\" : \"contactPhone\",\n \"subjectName\" : {\n \"firstName\" : \"firstName\",\n \"lastName\" : \"lastName\",\n \"nativeName\" : \"nativeName\",\n \"fullName\" : \"fullName\",\n \"middleName\" : \"middleName\",\n \"title\" : \"title\"\n }\n },\n \"kycVerificationStatus\" : \"verified\",\n \"kycVerificationEntity\" : \"kycVerificationEntity\"\n }, {\n \"kycLevel\" : 1,\n \"identityType\" : \"individual\",\n \"identityId\" : \"identityId\",\n \"identityStatus\" : \"identityStatus\",\n \"accountRelationship\" : \"accountholder\",\n \"customData\" : [ {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n } ],\n \"identityKyc\" : {\n \"emailAddress\" : \"emailAddress\",\n \"occupation\" : \"occupation\",\n \"postalAddress\" : {\n \"city\" : \"city\",\n \"postalCode\" : \"postalCode\",\n \"addressLine1\" : \"addressLine1\",\n \"stateProvince\" : \"stateProvince\",\n \"addressLine2\" : \"addressLine2\",\n \"addressLine3\" : \"addressLine3\"\n },\n \"gender\" : \"m\",\n \"idDocument\" : [ {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n } ],\n \"employerName\" : \"employerName\",\n \"dateOfBirth\" : \"2000-11-20T00:00:00.000+00:00\",\n \"contactPhone\" : \"contactPhone\",\n \"subjectName\" : {\n \"firstName\" : \"firstName\",\n \"lastName\" : \"lastName\",\n \"nativeName\" : \"nativeName\",\n \"fullName\" : \"fullName\",\n \"middleName\" : \"middleName\",\n \"title\" : \"title\"\n }\n },\n \"kycVerificationStatus\" : \"verified\",\n \"kycVerificationEntity\" : \"kycVerificationEntity\"\n }, {\n \"kycLevel\" : 1,\n \"identityType\" : \"individual\",\n \"identityId\" : \"identityId\",\n \"identityStatus\" : \"identityStatus\",\n \"accountRelationship\" : \"accountholder\",\n \"customData\" : [ {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n } ],\n \"identityKyc\" : {\n \"emailAddress\" : \"emailAddress\",\n \"occupation\" : \"occupation\",\n \"postalAddress\" : {\n \"city\" : \"city\",\n \"postalCode\" : \"postalCode\",\n \"addressLine1\" : \"addressLine1\",\n \"stateProvince\" : \"stateProvince\",\n \"addressLine2\" : \"addressLine2\",\n \"addressLine3\" : \"addressLine3\"\n },\n \"gender\" : \"m\",\n \"idDocument\" : [ {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n } ],\n \"employerName\" : \"employerName\",\n \"dateOfBirth\" : \"2000-11-20T00:00:00.000+00:00\",\n \"contactPhone\" : \"contactPhone\",\n \"subjectName\" : {\n \"firstName\" : \"firstName\",\n \"lastName\" : \"lastName\",\n \"nativeName\" : \"nativeName\",\n \"fullName\" : \"fullName\",\n \"middleName\" : \"middleName\",\n \"title\" : \"title\"\n }\n },\n \"kycVerificationStatus\" : \"verified\",\n \"kycVerificationEntity\" : \"kycVerificationEntity\"\n }, {\n \"kycLevel\" : 1,\n \"identityType\" : \"individual\",\n \"identityId\" : \"identityId\",\n \"identityStatus\" : \"identityStatus\",\n \"accountRelationship\" : \"accountholder\",\n \"customData\" : [ {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n } ],\n \"identityKyc\" : {\n \"emailAddress\" : \"emailAddress\",\n \"occupation\" : \"occupation\",\n \"postalAddress\" : {\n \"city\" : \"city\",\n \"postalCode\" : \"postalCode\",\n \"addressLine1\" : \"addressLine1\",\n \"stateProvince\" : \"stateProvince\",\n \"addressLine2\" : \"addressLine2\",\n \"addressLine3\" : \"addressLine3\"\n },\n \"gender\" : \"m\",\n \"idDocument\" : [ {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n } ],\n \"employerName\" : \"employerName\",\n \"dateOfBirth\" : \"2000-11-20T00:00:00.000+00:00\",\n \"contactPhone\" : \"contactPhone\",\n \"subjectName\" : {\n \"firstName\" : \"firstName\",\n \"lastName\" : \"lastName\",\n \"nativeName\" : \"nativeName\",\n \"fullName\" : \"fullName\",\n \"middleName\" : \"middleName\",\n \"title\" : \"title\"\n }\n },\n \"kycVerificationStatus\" : \"verified\",\n \"kycVerificationEntity\" : \"kycVerificationEntity\"\n } ],\n \"requestDate\" : \"2000-01-23T04:56:07.000+00:00\",\n \"accountSubStatus\" : \"accountSubStatus\",\n \"currency\" : \"AED\",\n \"accountIdentifiers\" : [ {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n } ]\n}", ResponseAccount.class), HttpStatus.OK); + } catch (IOException e) { + log.error("Couldn't serialize response for content type application/json", e); + return new ResponseEntity(HttpStatus.INTERNAL_SERVER_ERROR); + } + } + + return new ResponseEntity(HttpStatus.OK); + } + + public ResponseEntity accountsIdentifierTypeIdentifierLinksLinkReferenceGET(@Parameter(in = ParameterIn.PATH, description = "Path variable to specify the type of the identifier that is used to identify the account.", required = true, schema = @Schema(allowableValues = {"accountid", "msisdn", "walletid", "linkref", "consumerno", "serviceprovider", "storeid", "accountcategory", "bankaccountno", "accountrank", "identityalias", "iban", "swiftbic", "sortcode", "organisationid", "bankname", "bankaccounttitle", "username", "emailaddress", "mandatereference"} + )) @PathVariable("identifierType") String identifierType, @Size(min = 1, max = 256) @Parameter(in = ParameterIn.PATH, description = "Path variable that contains the account identifier.", required = true, schema = @Schema()) @PathVariable("identifier") String identifier, @Size(min = 1, max = 256) @Parameter(in = ParameterIn.PATH, description = "Path variable to uniquely identify a link.", required = true, schema = @Schema()) @PathVariable("linkReference") String linkReference, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API.", schema = @Schema()) @RequestHeader(value = "X-Date", required = false) OffsetDateTime xDate, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's API key to the server.", schema = @Schema()) @RequestHeader(value = "X-API-Key", required = false) String xAPIKey, @Parameter(in = ParameterIn.HEADER, description = "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication.", schema = @Schema()) @RequestHeader(value = "X-User-Bearer", required = false) String xUserBearer, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's identifier to the server.", schema = @Schema()) @RequestHeader(value = "X-Client-Id", required = false) String xClientId, @Parameter(in = ParameterIn.HEADER, description = "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed.", schema = @Schema()) @RequestHeader(value = "X-Content-Hash", required = false) String xContentHash, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", schema = @Schema()) @RequestHeader(value = "X-User-Credential-1", required = false) String xUserCredential1, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", schema = @Schema()) @RequestHeader(value = "X-User-Credential-2", required = false) String xUserCredential2, @Parameter(in = ParameterIn.HEADER, description = "String containing the channel that was used to originate the request. For example USSD, Web, App.", schema = @Schema()) @RequestHeader(value = "X-Channel", required = false) String xChannel, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header.", schema = @Schema(allowableValues = {"lei", "swiftbic", "organisationid"} + )) @RequestHeader(value = "X-Account-Holding-Institution-Identifier-Type", required = false) String xAccountHoldingInstitutionIdentifierType, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header.", schema = @Schema()) @RequestHeader(value = "X-Account-Holding-Institution-Identifier", required = false) String xAccountHoldingInstitutionIdentifier) { + String accept = request.getHeader("Accept"); + if (accept != null && accept.contains("application/json")) { + try { + return new ResponseEntity(objectMapper.readValue("{\n \"mode\" : \"push\",\n \"modificationDate\" : \"2000-01-23T04:56:07.000+00:00\",\n \"requestingOrganisation\" : {\n \"requestingOrganisationIdentifierType\" : \"lei\",\n \"requestingOrganisationIdentifier\" : \"requestingOrganisationIdentifier\"\n },\n \"requestDate\" : \"2000-01-23T04:56:07.000+00:00\",\n \"linkReference\" : \"linkReference\",\n \"customData\" : [ {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n } ],\n \"creationDate\" : \"2000-01-23T04:56:07.000+00:00\",\n \"sourceAccountIdentifiers\" : [ {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n } ],\n \"status\" : \"active\"\n}", ResponseLink.class), HttpStatus.OK); + } catch (IOException e) { + log.error("Couldn't serialize response for content type application/json", e); + return new ResponseEntity(HttpStatus.INTERNAL_SERVER_ERROR); + } + } + + return new ResponseEntity(HttpStatus.OK); + } + + public ResponseEntity accountsIdentifierTypeIdentifierLinksLinkReferencePATCH(@Parameter(in = ParameterIn.PATH, description = "Path variable to specify the type of the identifier that is used to identify the account.", required = true, schema = @Schema(allowableValues = {"accountid", "msisdn", "walletid", "linkref", "consumerno", "serviceprovider", "storeid", "accountcategory", "bankaccountno", "accountrank", "identityalias", "iban", "swiftbic", "sortcode", "organisationid", "bankname", "bankaccounttitle", "username", "emailaddress", "mandatereference"} + )) @PathVariable("identifierType") String identifierType, @Size(min = 1, max = 256) @Parameter(in = ParameterIn.PATH, description = "Path variable that contains the account identifier.", required = true, schema = @Schema()) @PathVariable("identifier") String identifier, @Size(min = 1, max = 256) @Parameter(in = ParameterIn.PATH, description = "Path variable to uniquely identify a link.", required = true, schema = @Schema()) @PathVariable("linkReference") String linkReference, @Parameter(in = ParameterIn.DEFAULT, description = "Represents the request body of a batch of generic Patch operation.", required = true, schema = @Schema()) @Valid @RequestBody List body, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API.", schema = @Schema()) @RequestHeader(value = "X-Date", required = false) OffsetDateTime xDate, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's API key to the server.", schema = @Schema()) @RequestHeader(value = "X-API-Key", required = false) String xAPIKey, @Parameter(in = ParameterIn.HEADER, description = "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication.", schema = @Schema()) @RequestHeader(value = "X-User-Bearer", required = false) String xUserBearer, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's identifier to the server.", schema = @Schema()) @RequestHeader(value = "X-Client-Id", required = false) String xClientId, @Parameter(in = ParameterIn.HEADER, description = "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed.", schema = @Schema()) @RequestHeader(value = "X-Content-Hash", required = false) String xContentHash, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", schema = @Schema()) @RequestHeader(value = "X-User-Credential-1", required = false) String xUserCredential1, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", schema = @Schema()) @RequestHeader(value = "X-User-Credential-2", required = false) String xUserCredential2, @Parameter(in = ParameterIn.HEADER, description = "String containing the channel that was used to originate the request. For example USSD, Web, App.", schema = @Schema()) @RequestHeader(value = "X-Channel", required = false) String xChannel, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header.", schema = @Schema(allowableValues = {"lei", "swiftbic", "organisationid"} + )) @RequestHeader(value = "X-Account-Holding-Institution-Identifier-Type", required = false) String xAccountHoldingInstitutionIdentifierType, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header.", schema = @Schema()) @RequestHeader(value = "X-Account-Holding-Institution-Identifier", required = false) String xAccountHoldingInstitutionIdentifier, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to uniquely identify the request. Must be supplied as a UUID.", schema = @Schema()) @RequestHeader(value = "X-CorrelationID", required = false) String xCorrelationID, @Parameter(in = ParameterIn.HEADER, description = "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT.", schema = @Schema()) @RequestHeader(value = "X-Callback-URL", required = false) String xCallbackURL) { + String accept = request.getHeader("Accept"); + if (accept != null && accept.contains("application/json")) { + try { + return new ResponseEntity(objectMapper.readValue("{\n \"pollLimit\" : 0.08008281904610115,\n \"pendingReason\" : \"pendingReason\",\n \"expiryTime\" : \"2000-01-23T04:56:07.000+00:00\",\n \"objectReference\" : \"objectReference\",\n \"notificationMethod\" : \"callback\",\n \"error\" : {\n \"errordescription\" : \"errordescription\",\n \"errorCategory\" : \"businessRule\",\n \"errorParameters\" : [ {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n } ],\n \"errorDateTime\" : \"2000-01-23T04:56:07.000+00:00\",\n \"errorCode\" : \"genericError\"\n },\n \"serverCorrelationId\" : \"serverCorrelationId\",\n \"status\" : \"pending\"\n}", RequestStateObject.class), HttpStatus.OK); + } catch (IOException e) { + log.error("Couldn't serialize response for content type application/json", e); + return new ResponseEntity(HttpStatus.INTERNAL_SERVER_ERROR); + } + } + + return new ResponseEntity(HttpStatus.OK); + } + + public ResponseEntity accountsIdentifierTypeIdentifierLinksPOST(@Parameter(in = ParameterIn.PATH, description = "Path variable to specify the type of the identifier that is used to identify the account.", required = true, schema = @Schema(allowableValues = {"accountid", "msisdn", "walletid", "linkref", "consumerno", "serviceprovider", "storeid", "accountcategory", "bankaccountno", "accountrank", "identityalias", "iban", "swiftbic", "sortcode", "organisationid", "bankname", "bankaccounttitle", "username", "emailaddress", "mandatereference"} + )) @PathVariable("identifierType") String identifierType, @Size(min = 1, max = 256) @Parameter(in = ParameterIn.PATH, description = "Path variable that contains the account identifier.", required = true, schema = @Schema()) @PathVariable("identifier") String identifier, @Parameter(in = ParameterIn.DEFAULT, description = "Represents the request body of a Link.", required = true, schema = @Schema()) @Valid @RequestBody RequestLink body, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API.", schema = @Schema()) @RequestHeader(value = "X-Date", required = false) OffsetDateTime xDate, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to uniquely identify the request. Must be supplied as a UUID.", schema = @Schema()) @RequestHeader(value = "X-CorrelationID", required = false) String xCorrelationID, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's API key to the server.", schema = @Schema()) @RequestHeader(value = "X-API-Key", required = false) String xAPIKey, @Parameter(in = ParameterIn.HEADER, description = "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication.", schema = @Schema()) @RequestHeader(value = "X-User-Bearer", required = false) String xUserBearer, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's identifier to the server.", schema = @Schema()) @RequestHeader(value = "X-Client-Id", required = false) String xClientId, @Parameter(in = ParameterIn.HEADER, description = "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed.", schema = @Schema()) @RequestHeader(value = "X-Content-Hash", required = false) String xContentHash, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", schema = @Schema()) @RequestHeader(value = "X-User-Credential-1", required = false) String xUserCredential1, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", schema = @Schema()) @RequestHeader(value = "X-User-Credential-2", required = false) String xUserCredential2, @Parameter(in = ParameterIn.HEADER, description = "String containing the channel that was used to originate the request. For example USSD, Web, App.", schema = @Schema()) @RequestHeader(value = "X-Channel", required = false) String xChannel, @Parameter(in = ParameterIn.HEADER, description = "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT.", schema = @Schema()) @RequestHeader(value = "X-Callback-URL", required = false) String xCallbackURL, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header.", schema = @Schema(allowableValues = {"lei", "swiftbic", "organisationid"} + )) @RequestHeader(value = "X-Account-Holding-Institution-Identifier-Type", required = false) String xAccountHoldingInstitutionIdentifierType, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header.", schema = @Schema()) @RequestHeader(value = "X-Account-Holding-Institution-Identifier", required = false) String xAccountHoldingInstitutionIdentifier) { + String accept = request.getHeader("Accept"); + if (accept != null && accept.contains("application/json")) { + try { + return new ResponseEntity(objectMapper.readValue("{\n \"mode\" : \"push\",\n \"modificationDate\" : \"2000-01-23T04:56:07.000+00:00\",\n \"requestingOrganisation\" : {\n \"requestingOrganisationIdentifierType\" : \"lei\",\n \"requestingOrganisationIdentifier\" : \"requestingOrganisationIdentifier\"\n },\n \"requestDate\" : \"2000-01-23T04:56:07.000+00:00\",\n \"linkReference\" : \"linkReference\",\n \"customData\" : [ {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n } ],\n \"creationDate\" : \"2000-01-23T04:56:07.000+00:00\",\n \"sourceAccountIdentifiers\" : [ {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n } ],\n \"status\" : \"active\"\n}", ResponseLink.class), HttpStatus.OK); + } catch (IOException e) { + log.error("Couldn't serialize response for content type application/json", e); + return new ResponseEntity(HttpStatus.INTERNAL_SERVER_ERROR); + } + } + + return new ResponseEntity(HttpStatus.OK); + } + + public ResponseEntity accountsIdentifierTypeIdentifierPATCH(@Parameter(in = ParameterIn.PATH, description = "Path variable to specify the type of the identifier that is used to identify the account.", required = true, schema = @Schema(allowableValues = {"accountid", "msisdn", "walletid", "linkref", "consumerno", "serviceprovider", "storeid", "accountcategory", "bankaccountno", "accountrank", "identityalias", "iban", "swiftbic", "sortcode", "organisationid", "bankname", "bankaccounttitle", "username", "emailaddress", "mandatereference"} + )) @PathVariable("identifierType") String identifierType, @Size(min = 1, max = 256) @Parameter(in = ParameterIn.PATH, description = "Path variable that contains the account identifier.", required = true, schema = @Schema()) @PathVariable("identifier") String identifier, @Parameter(in = ParameterIn.DEFAULT, description = "Represents the request body of a batch of generic Patch operation.", required = true, schema = @Schema()) @Valid @RequestBody List body, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API.", schema = @Schema()) @RequestHeader(value = "X-Date", required = false) OffsetDateTime xDate, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's API key to the server.", schema = @Schema()) @RequestHeader(value = "X-API-Key", required = false) String xAPIKey, @Parameter(in = ParameterIn.HEADER, description = "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication.", schema = @Schema()) @RequestHeader(value = "X-User-Bearer", required = false) String xUserBearer, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's identifier to the server.", schema = @Schema()) @RequestHeader(value = "X-Client-Id", required = false) String xClientId, @Parameter(in = ParameterIn.HEADER, description = "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed.", schema = @Schema()) @RequestHeader(value = "X-Content-Hash", required = false) String xContentHash, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", schema = @Schema()) @RequestHeader(value = "X-User-Credential-1", required = false) String xUserCredential1, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", schema = @Schema()) @RequestHeader(value = "X-User-Credential-2", required = false) String xUserCredential2, @Parameter(in = ParameterIn.HEADER, description = "String containing the channel that was used to originate the request. For example USSD, Web, App.", schema = @Schema()) @RequestHeader(value = "X-Channel", required = false) String xChannel, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header.", schema = @Schema(allowableValues = {"lei", "swiftbic", "organisationid"} + )) @RequestHeader(value = "X-Account-Holding-Institution-Identifier-Type", required = false) String xAccountHoldingInstitutionIdentifierType, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header.", schema = @Schema()) @RequestHeader(value = "X-Account-Holding-Institution-Identifier", required = false) String xAccountHoldingInstitutionIdentifier, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to uniquely identify the request. Must be supplied as a UUID.", schema = @Schema()) @RequestHeader(value = "X-CorrelationID", required = false) String xCorrelationID, @Parameter(in = ParameterIn.HEADER, description = "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT.", schema = @Schema()) @RequestHeader(value = "X-Callback-URL", required = false) String xCallbackURL) { + String accept = request.getHeader("Accept"); + if (accept != null && accept.contains("application/json")) { + try { + return new ResponseEntity(objectMapper.readValue("{\n \"pollLimit\" : 0.08008281904610115,\n \"pendingReason\" : \"pendingReason\",\n \"expiryTime\" : \"2000-01-23T04:56:07.000+00:00\",\n \"objectReference\" : \"objectReference\",\n \"notificationMethod\" : \"callback\",\n \"error\" : {\n \"errordescription\" : \"errordescription\",\n \"errorCategory\" : \"businessRule\",\n \"errorParameters\" : [ {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n } ],\n \"errorDateTime\" : \"2000-01-23T04:56:07.000+00:00\",\n \"errorCode\" : \"genericError\"\n },\n \"serverCorrelationId\" : \"serverCorrelationId\",\n \"status\" : \"pending\"\n}", RequestStateObject.class), HttpStatus.OK); + } catch (IOException e) { + log.error("Couldn't serialize response for content type application/json", e); + return new ResponseEntity(HttpStatus.INTERNAL_SERVER_ERROR); + } + } + + return new ResponseEntity(HttpStatus.OK); + } + + public ResponseEntity> accountsIdentifierTypeIdentifierStatemententriesGET(@Parameter(in = ParameterIn.PATH, description = "Path variable to specify the type of the identifier that is used to identify the account.", required = true, schema = @Schema(allowableValues = {"accountid", "msisdn", "walletid", "linkref", "consumerno", "serviceprovider", "storeid", "accountcategory", "bankaccountno", "accountrank", "identityalias", "iban", "swiftbic", "sortcode", "organisationid", "bankname", "bankaccounttitle", "username", "emailaddress", "mandatereference"} + )) @PathVariable("identifierType") String identifierType, @Size(min = 1, max = 256) @Parameter(in = ParameterIn.PATH, description = "Path variable that contains the account identifier.", required = true, schema = @Schema()) @PathVariable("identifier") String identifier, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API.", schema = @Schema()) @RequestHeader(value = "X-Date", required = false) OffsetDateTime xDate, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's API key to the server.", schema = @Schema()) @RequestHeader(value = "X-API-Key", required = false) String xAPIKey, @Parameter(in = ParameterIn.HEADER, description = "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication.", schema = @Schema()) @RequestHeader(value = "X-User-Bearer", required = false) String xUserBearer, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's identifier to the server.", schema = @Schema()) @RequestHeader(value = "X-Client-Id", required = false) String xClientId, @Parameter(in = ParameterIn.HEADER, description = "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed.", schema = @Schema()) @RequestHeader(value = "X-Content-Hash", required = false) String xContentHash, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", schema = @Schema()) @RequestHeader(value = "X-User-Credential-1", required = false) String xUserCredential1, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", schema = @Schema()) @RequestHeader(value = "X-User-Credential-2", required = false) String xUserCredential2, @Parameter(in = ParameterIn.HEADER, description = "String containing the channel that was used to originate the request. For example USSD, Web, App.", schema = @Schema()) @RequestHeader(value = "X-Channel", required = false) String xChannel, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header.", schema = @Schema(allowableValues = {"lei", "swiftbic", "organisationid"} + )) @RequestHeader(value = "X-Account-Holding-Institution-Identifier-Type", required = false) String xAccountHoldingInstitutionIdentifierType, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header.", schema = @Schema()) @RequestHeader(value = "X-Account-Holding-Institution-Identifier", required = false) String xAccountHoldingInstitutionIdentifier, @Parameter(in = ParameterIn.QUERY, description = "Supports pagination. If this is not supplied, then the server will apply a limit of 50 records returned for each request.", schema = @Schema()) @Valid @RequestParam(value = "limit", required = false) Integer limit, @Parameter(in = ParameterIn.QUERY, description = "Supports pagination. This value will indicate the cursor position from where to retrieve the set of records. For example, a limit of 50 and offset of 10 will return records 11 to 60.", schema = @Schema()) @Valid @RequestParam(value = "offset", required = false) Integer offset, @Parameter(in = ParameterIn.QUERY, description = "Indicates the minimum creation date for which records should be returned.", schema = @Schema()) @Valid @RequestParam(value = "fromDateTime", required = false) OffsetDateTime fromDateTime, @Parameter(in = ParameterIn.QUERY, description = "Indicates the maximum creation date for which records should be returned.", schema = @Schema()) @Valid @RequestParam(value = "toDateTime", required = false) OffsetDateTime toDateTime, @Size(max = 256) @Parameter(in = ParameterIn.QUERY, description = "Query variable to uniquely identify the transaction status.", schema = @Schema()) @Valid @RequestParam(value = "transactionStatus", required = false) String transactionStatus, @Size(max = 256) @Parameter(in = ParameterIn.QUERY, description = "Query parameter to to identify the display type of the statement entries to be returned.", schema = @Schema()) @Valid @RequestParam(value = "displayType", required = false) String displayType) { + String accept = request.getHeader("Accept"); + if (accept != null && accept.contains("application/json")) { + try { + return new ResponseEntity>(objectMapper.readValue("[ {\n \"debitParty\" : [ null, null, null, null, null, null, null, null, null, null ],\n \"amount\" : \"15.21\",\n \"transactionReference\" : \"transactionReference\",\n \"transactionStatus\" : \"transactionStatus\",\n \"customData\" : [ {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n } ],\n \"dateModified\" : \"2000-01-23T04:56:07.000+00:00\",\n \"descriptionText\" : \"descriptionText\",\n \"creationDate\" : \"2000-01-23T04:56:07.000+00:00\",\n \"displayType\" : \"displayType\",\n \"modificationDate\" : \"2000-01-23T04:56:07.000+00:00\",\n \"dateCreated\" : \"2000-01-23T04:56:07.000+00:00\",\n \"transactionReceipt\" : \"transactionReceipt\",\n \"requestDate\" : \"2000-01-23T04:56:07.000+00:00\",\n \"currency\" : \"AED\",\n \"creditParty\" : [ {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n } ]\n}, {\n \"debitParty\" : [ null, null, null, null, null, null, null, null, null, null ],\n \"amount\" : \"15.21\",\n \"transactionReference\" : \"transactionReference\",\n \"transactionStatus\" : \"transactionStatus\",\n \"customData\" : [ {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n } ],\n \"dateModified\" : \"2000-01-23T04:56:07.000+00:00\",\n \"descriptionText\" : \"descriptionText\",\n \"creationDate\" : \"2000-01-23T04:56:07.000+00:00\",\n \"displayType\" : \"displayType\",\n \"modificationDate\" : \"2000-01-23T04:56:07.000+00:00\",\n \"dateCreated\" : \"2000-01-23T04:56:07.000+00:00\",\n \"transactionReceipt\" : \"transactionReceipt\",\n \"requestDate\" : \"2000-01-23T04:56:07.000+00:00\",\n \"currency\" : \"AED\",\n \"creditParty\" : [ {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n } ]\n} ]", List.class), HttpStatus.OK); + } catch (IOException e) { + log.error("Couldn't serialize response for content type application/json", e); + return new ResponseEntity>(HttpStatus.INTERNAL_SERVER_ERROR); + } + } + + return new ResponseEntity>(HttpStatus.OK); + } + + public ResponseEntity accountsIdentifierTypeIdentifierStatusGET(@Parameter(in = ParameterIn.PATH, description = "Path variable to specify the type of the identifier that is used to identify the account.", required = true, schema = @Schema(allowableValues = {"accountid", "msisdn", "walletid", "linkref", "consumerno", "serviceprovider", "storeid", "accountcategory", "bankaccountno", "accountrank", "identityalias", "iban", "swiftbic", "sortcode", "organisationid", "bankname", "bankaccounttitle", "username", "emailaddress", "mandatereference"} + )) @PathVariable("identifierType") String identifierType, @Size(min = 1, max = 256) @Parameter(in = ParameterIn.PATH, description = "Path variable that contains the account identifier.", required = true, schema = @Schema()) @PathVariable("identifier") String identifier, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API.", schema = @Schema()) @RequestHeader(value = "X-Date", required = false) OffsetDateTime xDate, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's API key to the server.", schema = @Schema()) @RequestHeader(value = "X-API-Key", required = false) String xAPIKey, @Parameter(in = ParameterIn.HEADER, description = "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication.", schema = @Schema()) @RequestHeader(value = "X-User-Bearer", required = false) String xUserBearer, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's identifier to the server.", schema = @Schema()) @RequestHeader(value = "X-Client-Id", required = false) String xClientId, @Parameter(in = ParameterIn.HEADER, description = "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed.", schema = @Schema()) @RequestHeader(value = "X-Content-Hash", required = false) String xContentHash, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", schema = @Schema()) @RequestHeader(value = "X-User-Credential-1", required = false) String xUserCredential1, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", schema = @Schema()) @RequestHeader(value = "X-User-Credential-2", required = false) String xUserCredential2, @Parameter(in = ParameterIn.HEADER, description = "String containing the channel that was used to originate the request. For example USSD, Web, App.", schema = @Schema()) @RequestHeader(value = "X-Channel", required = false) String xChannel, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header.", schema = @Schema(allowableValues = {"lei", "swiftbic", "organisationid"} + )) @RequestHeader(value = "X-Account-Holding-Institution-Identifier-Type", required = false) String xAccountHoldingInstitutionIdentifierType, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header.", schema = @Schema()) @RequestHeader(value = "X-Account-Holding-Institution-Identifier", required = false) String xAccountHoldingInstitutionIdentifier) { + String accept = request.getHeader("Accept"); + if (accept != null && accept.contains("application/json")) { + try { + return new ResponseEntity(objectMapper.readValue("{\n \"accountStatus\" : \"available\",\n \"lei\" : \"5493000IBP32UQZ0KL24\",\n \"subStatus\" : \"subStatus\"\n}", ResponseAccountStatus.class), HttpStatus.OK); + } catch (IOException e) { + log.error("Couldn't serialize response for content type application/json", e); + return new ResponseEntity(HttpStatus.INTERNAL_SERVER_ERROR); + } + } + + return new ResponseEntity(HttpStatus.OK); + } + + public ResponseEntity> accountsIdentifierTypeIdentifierTransactionsGET(@Parameter(in = ParameterIn.PATH, description = "Path variable to specify the type of the identifier that is used to identify the account.", required = true, schema = @Schema(allowableValues = {"accountid", "msisdn", "walletid", "linkref", "consumerno", "serviceprovider", "storeid", "accountcategory", "bankaccountno", "accountrank", "identityalias", "iban", "swiftbic", "sortcode", "organisationid", "bankname", "bankaccounttitle", "username", "emailaddress", "mandatereference"} + )) @PathVariable("identifierType") String identifierType, @Size(min = 1, max = 256) @Parameter(in = ParameterIn.PATH, description = "Path variable that contains the account identifier.", required = true, schema = @Schema()) @PathVariable("identifier") String identifier, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API.", schema = @Schema()) @RequestHeader(value = "X-Date", required = false) OffsetDateTime xDate, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's API key to the server.", schema = @Schema()) @RequestHeader(value = "X-API-Key", required = false) String xAPIKey, @Parameter(in = ParameterIn.HEADER, description = "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication.", schema = @Schema()) @RequestHeader(value = "X-User-Bearer", required = false) String xUserBearer, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's identifier to the server.", schema = @Schema()) @RequestHeader(value = "X-Client-Id", required = false) String xClientId, @Parameter(in = ParameterIn.HEADER, description = "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed.", schema = @Schema()) @RequestHeader(value = "X-Content-Hash", required = false) String xContentHash, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", schema = @Schema()) @RequestHeader(value = "X-User-Credential-1", required = false) String xUserCredential1, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", schema = @Schema()) @RequestHeader(value = "X-User-Credential-2", required = false) String xUserCredential2, @Parameter(in = ParameterIn.HEADER, description = "String containing the channel that was used to originate the request. For example USSD, Web, App.", schema = @Schema()) @RequestHeader(value = "X-Channel", required = false) String xChannel, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header.", schema = @Schema(allowableValues = {"lei", "swiftbic", "organisationid"} + )) @RequestHeader(value = "X-Account-Holding-Institution-Identifier-Type", required = false) String xAccountHoldingInstitutionIdentifierType, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header.", schema = @Schema()) @RequestHeader(value = "X-Account-Holding-Institution-Identifier", required = false) String xAccountHoldingInstitutionIdentifier, @Parameter(in = ParameterIn.QUERY, description = "Supports pagination. If this is not supplied, then the server will apply a limit of 50 records returned for each request.", schema = @Schema()) @Valid @RequestParam(value = "limit", required = false) Integer limit, @Parameter(in = ParameterIn.QUERY, description = "Supports pagination. This value will indicate the cursor position from where to retrieve the set of records. For example, a limit of 50 and offset of 10 will return records 11 to 60.", schema = @Schema()) @Valid @RequestParam(value = "offset", required = false) Integer offset, @Parameter(in = ParameterIn.QUERY, description = "Indicates the minimum creation date for which records should be returned.", schema = @Schema()) @Valid @RequestParam(value = "fromDateTime", required = false) OffsetDateTime fromDateTime, @Parameter(in = ParameterIn.QUERY, description = "Indicates the maximum creation date for which records should be returned.", schema = @Schema()) @Valid @RequestParam(value = "toDateTime", required = false) OffsetDateTime toDateTime, @Size(max = 256) @Parameter(in = ParameterIn.QUERY, description = "Query variable to uniquely identify the transaction status.", schema = @Schema()) @Valid @RequestParam(value = "transactionStatus", required = false) String transactionStatus, @Parameter(in = ParameterIn.QUERY, description = "Identifies the type of transaction.", schema = @Schema(allowableValues = {"billpay", "deposit", "disbursement", "transfer", "merchantpay", "inttransfer", "adjustment", "reversal", "withdrawal"} + )) @Valid @RequestParam(value = "transactionType", required = false) String transactionType) { + String accept = request.getHeader("Accept"); + if (accept != null && accept.contains("application/json")) { + try { + return new ResponseEntity>(objectMapper.readValue("[ {\n \"recipientKyc\" : {\n \"emailAddress\" : \"emailAddress\",\n \"occupation\" : \"occupation\",\n \"postalAddress\" : {\n \"city\" : \"city\",\n \"postalCode\" : \"postalCode\",\n \"addressLine1\" : \"addressLine1\",\n \"stateProvince\" : \"stateProvince\",\n \"addressLine2\" : \"addressLine2\",\n \"addressLine3\" : \"addressLine3\"\n },\n \"gender\" : \"m\",\n \"idDocument\" : [ {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n } ],\n \"employerName\" : \"employerName\",\n \"dateOfBirth\" : \"2000-11-20T00:00:00.000+00:00\",\n \"contactPhone\" : \"contactPhone\",\n \"subjectName\" : {\n \"firstName\" : \"firstName\",\n \"lastName\" : \"lastName\",\n \"nativeName\" : \"nativeName\",\n \"fullName\" : \"fullName\",\n \"middleName\" : \"middleName\",\n \"title\" : \"title\"\n }\n },\n \"debitParty\" : [ null, null, null, null, null, null, null, null, null, null ],\n \"fees\" : [ {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n } ],\n \"metadata\" : [ {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n } ],\n \"customData\" : [ {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n } ],\n \"requestingLei\" : \"requestingLei\",\n \"descriptionText\" : \"descriptionText\",\n \"type\" : \"billpay\",\n \"dateCreated\" : \"2000-01-23T04:56:07.000+00:00\",\n \"transactionReceipt\" : \"transactionReceipt\",\n \"oneTimeCode\" : \"oneTimeCode\",\n \"requestDate\" : \"2000-01-23T04:56:07.000+00:00\",\n \"currency\" : \"AED\",\n \"originalTransactionReference\" : \"originalTransactionReference\",\n \"amount\" : \"15.21\",\n \"transactionReference\" : \"transactionReference\",\n \"transactionStatus\" : \"transactionStatus\",\n \"internationalTransferInformation\" : {\n \"quotationReference\" : \"quotationReference\",\n \"deliveryMethod\" : \"directtoaccount\",\n \"originCountry\" : \"AD\",\n \"relationshipSender\" : \"relationshipSender\",\n \"remittancePurpose\" : \"remittancePurpose\",\n \"senderBlockingReason\" : \"senderBlockingReason\",\n \"quoteId\" : \"quoteId\",\n \"recipientBlockingReason\" : \"recipientBlockingReason\"\n },\n \"requestingOrganisation\" : {\n \"requestingOrganisationIdentifierType\" : \"lei\",\n \"requestingOrganisationIdentifier\" : \"requestingOrganisationIdentifier\"\n },\n \"geoCode\" : \"37.423825,-122.082900\",\n \"dateModified\" : \"2000-01-23T04:56:07.000+00:00\",\n \"creationDate\" : \"2000-01-23T04:56:07.000+00:00\",\n \"modificationDate\" : \"2000-01-23T04:56:07.000+00:00\",\n \"receivingLei\" : \"receivingLei\",\n \"servicingIdentity\" : \"servicingIdentity\",\n \"requestingOrganisationTransactionReference\" : \"requestingOrganisationTransactionReference\",\n \"subType\" : \"subType\",\n \"creditParty\" : [ {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n } ]\n}, {\n \"recipientKyc\" : {\n \"emailAddress\" : \"emailAddress\",\n \"occupation\" : \"occupation\",\n \"postalAddress\" : {\n \"city\" : \"city\",\n \"postalCode\" : \"postalCode\",\n \"addressLine1\" : \"addressLine1\",\n \"stateProvince\" : \"stateProvince\",\n \"addressLine2\" : \"addressLine2\",\n \"addressLine3\" : \"addressLine3\"\n },\n \"gender\" : \"m\",\n \"idDocument\" : [ {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n } ],\n \"employerName\" : \"employerName\",\n \"dateOfBirth\" : \"2000-11-20T00:00:00.000+00:00\",\n \"contactPhone\" : \"contactPhone\",\n \"subjectName\" : {\n \"firstName\" : \"firstName\",\n \"lastName\" : \"lastName\",\n \"nativeName\" : \"nativeName\",\n \"fullName\" : \"fullName\",\n \"middleName\" : \"middleName\",\n \"title\" : \"title\"\n }\n },\n \"debitParty\" : [ null, null, null, null, null, null, null, null, null, null ],\n \"fees\" : [ {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n } ],\n \"metadata\" : [ {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n } ],\n \"customData\" : [ {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n } ],\n \"requestingLei\" : \"requestingLei\",\n \"descriptionText\" : \"descriptionText\",\n \"type\" : \"billpay\",\n \"dateCreated\" : \"2000-01-23T04:56:07.000+00:00\",\n \"transactionReceipt\" : \"transactionReceipt\",\n \"oneTimeCode\" : \"oneTimeCode\",\n \"requestDate\" : \"2000-01-23T04:56:07.000+00:00\",\n \"currency\" : \"AED\",\n \"originalTransactionReference\" : \"originalTransactionReference\",\n \"amount\" : \"15.21\",\n \"transactionReference\" : \"transactionReference\",\n \"transactionStatus\" : \"transactionStatus\",\n \"internationalTransferInformation\" : {\n \"quotationReference\" : \"quotationReference\",\n \"deliveryMethod\" : \"directtoaccount\",\n \"originCountry\" : \"AD\",\n \"relationshipSender\" : \"relationshipSender\",\n \"remittancePurpose\" : \"remittancePurpose\",\n \"senderBlockingReason\" : \"senderBlockingReason\",\n \"quoteId\" : \"quoteId\",\n \"recipientBlockingReason\" : \"recipientBlockingReason\"\n },\n \"requestingOrganisation\" : {\n \"requestingOrganisationIdentifierType\" : \"lei\",\n \"requestingOrganisationIdentifier\" : \"requestingOrganisationIdentifier\"\n },\n \"geoCode\" : \"37.423825,-122.082900\",\n \"dateModified\" : \"2000-01-23T04:56:07.000+00:00\",\n \"creationDate\" : \"2000-01-23T04:56:07.000+00:00\",\n \"modificationDate\" : \"2000-01-23T04:56:07.000+00:00\",\n \"receivingLei\" : \"receivingLei\",\n \"servicingIdentity\" : \"servicingIdentity\",\n \"requestingOrganisationTransactionReference\" : \"requestingOrganisationTransactionReference\",\n \"subType\" : \"subType\",\n \"creditParty\" : [ {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n } ]\n} ]", List.class), HttpStatus.OK); + } catch (IOException e) { + log.error("Couldn't serialize response for content type application/json", e); + return new ResponseEntity>(HttpStatus.INTERNAL_SERVER_ERROR); + } + } + + return new ResponseEntity>(HttpStatus.OK); + } + + public ResponseEntity accountsPOST(@Parameter(in = ParameterIn.PATH, description = "Identifies the type of identity that is associated with the Account.", required = true, schema = @Schema(allowableValues = {"individual"} + )) @PathVariable("identityType") String identityType, @Parameter(in = ParameterIn.DEFAULT, description = "Represents the request body of an Account.", required = true, schema = @Schema()) @Valid @RequestBody RequestAccount body, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API.", schema = @Schema()) @RequestHeader(value = "X-Date", required = false) OffsetDateTime xDate, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to uniquely identify the request. Must be supplied as a UUID.", schema = @Schema()) @RequestHeader(value = "X-CorrelationID", required = false) String xCorrelationID, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's API key to the server.", schema = @Schema()) @RequestHeader(value = "X-API-Key", required = false) String xAPIKey, @Parameter(in = ParameterIn.HEADER, description = "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication.", schema = @Schema()) @RequestHeader(value = "X-User-Bearer", required = false) String xUserBearer, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's identifier to the server.", schema = @Schema()) @RequestHeader(value = "X-Client-Id", required = false) String xClientId, @Parameter(in = ParameterIn.HEADER, description = "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed.", schema = @Schema()) @RequestHeader(value = "X-Content-Hash", required = false) String xContentHash, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", schema = @Schema()) @RequestHeader(value = "X-User-Credential-1", required = false) String xUserCredential1, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", schema = @Schema()) @RequestHeader(value = "X-User-Credential-2", required = false) String xUserCredential2, @Parameter(in = ParameterIn.HEADER, description = "String containing the channel that was used to originate the request. For example USSD, Web, App.", schema = @Schema()) @RequestHeader(value = "X-Channel", required = false) String xChannel, @Parameter(in = ParameterIn.HEADER, description = "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT.", schema = @Schema()) @RequestHeader(value = "X-Callback-URL", required = false) String xCallbackURL, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header.", schema = @Schema(allowableValues = {"lei", "swiftbic", "organisationid"} + )) @RequestHeader(value = "X-Account-Holding-Institution-Identifier-Type", required = false) String xAccountHoldingInstitutionIdentifierType, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header.", schema = @Schema()) @RequestHeader(value = "X-Account-Holding-Institution-Identifier", required = false) String xAccountHoldingInstitutionIdentifier) { + String accept = request.getHeader("Accept"); + if (accept != null && accept.contains("application/json")) { + try { + return new ResponseEntity(objectMapper.readValue("{\n \"fees\" : [ {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n } ],\n \"commissionEarned\" : [ {\n \"commissionType\" : \"commissionType\"\n }, {\n \"commissionType\" : \"commissionType\"\n }, {\n \"commissionType\" : \"commissionType\"\n }, {\n \"commissionType\" : \"commissionType\"\n }, {\n \"commissionType\" : \"commissionType\"\n }, {\n \"commissionType\" : \"commissionType\"\n }, {\n \"commissionType\" : \"commissionType\"\n }, {\n \"commissionType\" : \"commissionType\"\n }, {\n \"commissionType\" : \"commissionType\"\n }, {\n \"commissionType\" : \"commissionType\"\n } ],\n \"accountType\" : \"accountType\",\n \"currentBalance\" : \"15.21\",\n \"creationDate\" : \"2000-01-23T04:56:07.000+00:00\",\n \"accountStatus\" : \"available\",\n \"registeringEntity\" : \"registeringEntity\",\n \"modificationDate\" : \"2000-01-23T04:56:07.000+00:00\",\n \"identity\" : [ {\n \"kycLevel\" : 1,\n \"identityType\" : \"individual\",\n \"identityId\" : \"identityId\",\n \"identityStatus\" : \"identityStatus\",\n \"accountRelationship\" : \"accountholder\",\n \"customData\" : [ {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n } ],\n \"identityKyc\" : {\n \"emailAddress\" : \"emailAddress\",\n \"occupation\" : \"occupation\",\n \"postalAddress\" : {\n \"city\" : \"city\",\n \"postalCode\" : \"postalCode\",\n \"addressLine1\" : \"addressLine1\",\n \"stateProvince\" : \"stateProvince\",\n \"addressLine2\" : \"addressLine2\",\n \"addressLine3\" : \"addressLine3\"\n },\n \"gender\" : \"m\",\n \"idDocument\" : [ {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n } ],\n \"employerName\" : \"employerName\",\n \"dateOfBirth\" : \"2000-11-20T00:00:00.000+00:00\",\n \"contactPhone\" : \"contactPhone\",\n \"subjectName\" : {\n \"firstName\" : \"firstName\",\n \"lastName\" : \"lastName\",\n \"nativeName\" : \"nativeName\",\n \"fullName\" : \"fullName\",\n \"middleName\" : \"middleName\",\n \"title\" : \"title\"\n }\n },\n \"kycVerificationStatus\" : \"verified\",\n \"kycVerificationEntity\" : \"kycVerificationEntity\"\n }, {\n \"kycLevel\" : 1,\n \"identityType\" : \"individual\",\n \"identityId\" : \"identityId\",\n \"identityStatus\" : \"identityStatus\",\n \"accountRelationship\" : \"accountholder\",\n \"customData\" : [ {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n } ],\n \"identityKyc\" : {\n \"emailAddress\" : \"emailAddress\",\n \"occupation\" : \"occupation\",\n \"postalAddress\" : {\n \"city\" : \"city\",\n \"postalCode\" : \"postalCode\",\n \"addressLine1\" : \"addressLine1\",\n \"stateProvince\" : \"stateProvince\",\n \"addressLine2\" : \"addressLine2\",\n \"addressLine3\" : \"addressLine3\"\n },\n \"gender\" : \"m\",\n \"idDocument\" : [ {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n } ],\n \"employerName\" : \"employerName\",\n \"dateOfBirth\" : \"2000-11-20T00:00:00.000+00:00\",\n \"contactPhone\" : \"contactPhone\",\n \"subjectName\" : {\n \"firstName\" : \"firstName\",\n \"lastName\" : \"lastName\",\n \"nativeName\" : \"nativeName\",\n \"fullName\" : \"fullName\",\n \"middleName\" : \"middleName\",\n \"title\" : \"title\"\n }\n },\n \"kycVerificationStatus\" : \"verified\",\n \"kycVerificationEntity\" : \"kycVerificationEntity\"\n }, {\n \"kycLevel\" : 1,\n \"identityType\" : \"individual\",\n \"identityId\" : \"identityId\",\n \"identityStatus\" : \"identityStatus\",\n \"accountRelationship\" : \"accountholder\",\n \"customData\" : [ {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n } ],\n \"identityKyc\" : {\n \"emailAddress\" : \"emailAddress\",\n \"occupation\" : \"occupation\",\n \"postalAddress\" : {\n \"city\" : \"city\",\n \"postalCode\" : \"postalCode\",\n \"addressLine1\" : \"addressLine1\",\n \"stateProvince\" : \"stateProvince\",\n \"addressLine2\" : \"addressLine2\",\n \"addressLine3\" : \"addressLine3\"\n },\n \"gender\" : \"m\",\n \"idDocument\" : [ {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n } ],\n \"employerName\" : \"employerName\",\n \"dateOfBirth\" : \"2000-11-20T00:00:00.000+00:00\",\n \"contactPhone\" : \"contactPhone\",\n \"subjectName\" : {\n \"firstName\" : \"firstName\",\n \"lastName\" : \"lastName\",\n \"nativeName\" : \"nativeName\",\n \"fullName\" : \"fullName\",\n \"middleName\" : \"middleName\",\n \"title\" : \"title\"\n }\n },\n \"kycVerificationStatus\" : \"verified\",\n \"kycVerificationEntity\" : \"kycVerificationEntity\"\n }, {\n \"kycLevel\" : 1,\n \"identityType\" : \"individual\",\n \"identityId\" : \"identityId\",\n \"identityStatus\" : \"identityStatus\",\n \"accountRelationship\" : \"accountholder\",\n \"customData\" : [ {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n } ],\n \"identityKyc\" : {\n \"emailAddress\" : \"emailAddress\",\n \"occupation\" : \"occupation\",\n \"postalAddress\" : {\n \"city\" : \"city\",\n \"postalCode\" : \"postalCode\",\n \"addressLine1\" : \"addressLine1\",\n \"stateProvince\" : \"stateProvince\",\n \"addressLine2\" : \"addressLine2\",\n \"addressLine3\" : \"addressLine3\"\n },\n \"gender\" : \"m\",\n \"idDocument\" : [ {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n } ],\n \"employerName\" : \"employerName\",\n \"dateOfBirth\" : \"2000-11-20T00:00:00.000+00:00\",\n \"contactPhone\" : \"contactPhone\",\n \"subjectName\" : {\n \"firstName\" : \"firstName\",\n \"lastName\" : \"lastName\",\n \"nativeName\" : \"nativeName\",\n \"fullName\" : \"fullName\",\n \"middleName\" : \"middleName\",\n \"title\" : \"title\"\n }\n },\n \"kycVerificationStatus\" : \"verified\",\n \"kycVerificationEntity\" : \"kycVerificationEntity\"\n }, {\n \"kycLevel\" : 1,\n \"identityType\" : \"individual\",\n \"identityId\" : \"identityId\",\n \"identityStatus\" : \"identityStatus\",\n \"accountRelationship\" : \"accountholder\",\n \"customData\" : [ {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n } ],\n \"identityKyc\" : {\n \"emailAddress\" : \"emailAddress\",\n \"occupation\" : \"occupation\",\n \"postalAddress\" : {\n \"city\" : \"city\",\n \"postalCode\" : \"postalCode\",\n \"addressLine1\" : \"addressLine1\",\n \"stateProvince\" : \"stateProvince\",\n \"addressLine2\" : \"addressLine2\",\n \"addressLine3\" : \"addressLine3\"\n },\n \"gender\" : \"m\",\n \"idDocument\" : [ {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n } ],\n \"employerName\" : \"employerName\",\n \"dateOfBirth\" : \"2000-11-20T00:00:00.000+00:00\",\n \"contactPhone\" : \"contactPhone\",\n \"subjectName\" : {\n \"firstName\" : \"firstName\",\n \"lastName\" : \"lastName\",\n \"nativeName\" : \"nativeName\",\n \"fullName\" : \"fullName\",\n \"middleName\" : \"middleName\",\n \"title\" : \"title\"\n }\n },\n \"kycVerificationStatus\" : \"verified\",\n \"kycVerificationEntity\" : \"kycVerificationEntity\"\n }, {\n \"kycLevel\" : 1,\n \"identityType\" : \"individual\",\n \"identityId\" : \"identityId\",\n \"identityStatus\" : \"identityStatus\",\n \"accountRelationship\" : \"accountholder\",\n \"customData\" : [ {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n } ],\n \"identityKyc\" : {\n \"emailAddress\" : \"emailAddress\",\n \"occupation\" : \"occupation\",\n \"postalAddress\" : {\n \"city\" : \"city\",\n \"postalCode\" : \"postalCode\",\n \"addressLine1\" : \"addressLine1\",\n \"stateProvince\" : \"stateProvince\",\n \"addressLine2\" : \"addressLine2\",\n \"addressLine3\" : \"addressLine3\"\n },\n \"gender\" : \"m\",\n \"idDocument\" : [ {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n } ],\n \"employerName\" : \"employerName\",\n \"dateOfBirth\" : \"2000-11-20T00:00:00.000+00:00\",\n \"contactPhone\" : \"contactPhone\",\n \"subjectName\" : {\n \"firstName\" : \"firstName\",\n \"lastName\" : \"lastName\",\n \"nativeName\" : \"nativeName\",\n \"fullName\" : \"fullName\",\n \"middleName\" : \"middleName\",\n \"title\" : \"title\"\n }\n },\n \"kycVerificationStatus\" : \"verified\",\n \"kycVerificationEntity\" : \"kycVerificationEntity\"\n }, {\n \"kycLevel\" : 1,\n \"identityType\" : \"individual\",\n \"identityId\" : \"identityId\",\n \"identityStatus\" : \"identityStatus\",\n \"accountRelationship\" : \"accountholder\",\n \"customData\" : [ {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n } ],\n \"identityKyc\" : {\n \"emailAddress\" : \"emailAddress\",\n \"occupation\" : \"occupation\",\n \"postalAddress\" : {\n \"city\" : \"city\",\n \"postalCode\" : \"postalCode\",\n \"addressLine1\" : \"addressLine1\",\n \"stateProvince\" : \"stateProvince\",\n \"addressLine2\" : \"addressLine2\",\n \"addressLine3\" : \"addressLine3\"\n },\n \"gender\" : \"m\",\n \"idDocument\" : [ {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n } ],\n \"employerName\" : \"employerName\",\n \"dateOfBirth\" : \"2000-11-20T00:00:00.000+00:00\",\n \"contactPhone\" : \"contactPhone\",\n \"subjectName\" : {\n \"firstName\" : \"firstName\",\n \"lastName\" : \"lastName\",\n \"nativeName\" : \"nativeName\",\n \"fullName\" : \"fullName\",\n \"middleName\" : \"middleName\",\n \"title\" : \"title\"\n }\n },\n \"kycVerificationStatus\" : \"verified\",\n \"kycVerificationEntity\" : \"kycVerificationEntity\"\n }, {\n \"kycLevel\" : 1,\n \"identityType\" : \"individual\",\n \"identityId\" : \"identityId\",\n \"identityStatus\" : \"identityStatus\",\n \"accountRelationship\" : \"accountholder\",\n \"customData\" : [ {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n } ],\n \"identityKyc\" : {\n \"emailAddress\" : \"emailAddress\",\n \"occupation\" : \"occupation\",\n \"postalAddress\" : {\n \"city\" : \"city\",\n \"postalCode\" : \"postalCode\",\n \"addressLine1\" : \"addressLine1\",\n \"stateProvince\" : \"stateProvince\",\n \"addressLine2\" : \"addressLine2\",\n \"addressLine3\" : \"addressLine3\"\n },\n \"gender\" : \"m\",\n \"idDocument\" : [ {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n } ],\n \"employerName\" : \"employerName\",\n \"dateOfBirth\" : \"2000-11-20T00:00:00.000+00:00\",\n \"contactPhone\" : \"contactPhone\",\n \"subjectName\" : {\n \"firstName\" : \"firstName\",\n \"lastName\" : \"lastName\",\n \"nativeName\" : \"nativeName\",\n \"fullName\" : \"fullName\",\n \"middleName\" : \"middleName\",\n \"title\" : \"title\"\n }\n },\n \"kycVerificationStatus\" : \"verified\",\n \"kycVerificationEntity\" : \"kycVerificationEntity\"\n }, {\n \"kycLevel\" : 1,\n \"identityType\" : \"individual\",\n \"identityId\" : \"identityId\",\n \"identityStatus\" : \"identityStatus\",\n \"accountRelationship\" : \"accountholder\",\n \"customData\" : [ {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n } ],\n \"identityKyc\" : {\n \"emailAddress\" : \"emailAddress\",\n \"occupation\" : \"occupation\",\n \"postalAddress\" : {\n \"city\" : \"city\",\n \"postalCode\" : \"postalCode\",\n \"addressLine1\" : \"addressLine1\",\n \"stateProvince\" : \"stateProvince\",\n \"addressLine2\" : \"addressLine2\",\n \"addressLine3\" : \"addressLine3\"\n },\n \"gender\" : \"m\",\n \"idDocument\" : [ {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n } ],\n \"employerName\" : \"employerName\",\n \"dateOfBirth\" : \"2000-11-20T00:00:00.000+00:00\",\n \"contactPhone\" : \"contactPhone\",\n \"subjectName\" : {\n \"firstName\" : \"firstName\",\n \"lastName\" : \"lastName\",\n \"nativeName\" : \"nativeName\",\n \"fullName\" : \"fullName\",\n \"middleName\" : \"middleName\",\n \"title\" : \"title\"\n }\n },\n \"kycVerificationStatus\" : \"verified\",\n \"kycVerificationEntity\" : \"kycVerificationEntity\"\n }, {\n \"kycLevel\" : 1,\n \"identityType\" : \"individual\",\n \"identityId\" : \"identityId\",\n \"identityStatus\" : \"identityStatus\",\n \"accountRelationship\" : \"accountholder\",\n \"customData\" : [ {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n } ],\n \"identityKyc\" : {\n \"emailAddress\" : \"emailAddress\",\n \"occupation\" : \"occupation\",\n \"postalAddress\" : {\n \"city\" : \"city\",\n \"postalCode\" : \"postalCode\",\n \"addressLine1\" : \"addressLine1\",\n \"stateProvince\" : \"stateProvince\",\n \"addressLine2\" : \"addressLine2\",\n \"addressLine3\" : \"addressLine3\"\n },\n \"gender\" : \"m\",\n \"idDocument\" : [ {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n } ],\n \"employerName\" : \"employerName\",\n \"dateOfBirth\" : \"2000-11-20T00:00:00.000+00:00\",\n \"contactPhone\" : \"contactPhone\",\n \"subjectName\" : {\n \"firstName\" : \"firstName\",\n \"lastName\" : \"lastName\",\n \"nativeName\" : \"nativeName\",\n \"fullName\" : \"fullName\",\n \"middleName\" : \"middleName\",\n \"title\" : \"title\"\n }\n },\n \"kycVerificationStatus\" : \"verified\",\n \"kycVerificationEntity\" : \"kycVerificationEntity\"\n } ],\n \"requestDate\" : \"2000-01-23T04:56:07.000+00:00\",\n \"accountSubStatus\" : \"accountSubStatus\",\n \"currency\" : \"AED\",\n \"accountIdentifiers\" : [ {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n } ]\n}", ResponseAccount.class), HttpStatus.OK); + } catch (IOException e) { + log.error("Couldn't serialize response for content type application/json", e); + return new ResponseEntity(HttpStatus.INTERNAL_SERVER_ERROR); + } + } + + return new ResponseEntity(HttpStatus.OK); + } + +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/api/ApiException.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/api/ApiException.java new file mode 100644 index 000000000..7cb0a6639 --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/api/ApiException.java @@ -0,0 +1,10 @@ +package org.mifos.connector.gsmastub.api; + +@javax.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.SpringCodegen", date = "2022-09-27T11:46:46.417Z[GMT]") +public class ApiException extends Exception { + private int code; + public ApiException (int code, String msg) { + super(msg); + this.code = code; + } +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/api/ApiOriginFilter.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/api/ApiOriginFilter.java new file mode 100644 index 000000000..d0ed4b5ba --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/api/ApiOriginFilter.java @@ -0,0 +1,36 @@ +package org.mifos.connector.gsmastub.api; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; +import org.springframework.web.filter.GenericFilterBean; + +import javax.servlet.*; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.Optional; + +import static org.mifos.connector.channel.camel.config.CamelProperties.PLATFORM_TENANT_ID; + +@javax.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.SpringCodegen", date = "2022-09-27T11:46:46.417Z[GMT]") + +public class ApiOriginFilter extends GenericFilterBean { + private Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Override + public void doFilter(ServletRequest request, ServletResponse response, + FilterChain chain) throws IOException, ServletException { + HttpServletRequest req = (HttpServletRequest) request; + String tenant = req.getHeader(PLATFORM_TENANT_ID); + logger.debug("Tenant Name is : {}", tenant); + logger.info("Client IP Address: {}",req.getRemoteHost()); + HttpServletResponse res = (HttpServletResponse) response; + res.addHeader("Access-Control-Allow-Origin", "*"); + res.addHeader("Access-Control-Allow-Methods", "GET, POST, DELETE, PUT"); + res.addHeader("Access-Control-Allow-Headers", "Content-Type"); + chain.doFilter(request, response); + } + + +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/api/ApiResponseMessage.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/api/ApiResponseMessage.java new file mode 100644 index 000000000..58e9e904b --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/api/ApiResponseMessage.java @@ -0,0 +1,69 @@ +package org.mifos.connector.gsmastub.api; + +import javax.xml.bind.annotation.XmlTransient; + +@javax.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.SpringCodegen", date = "2022-09-27T11:46:46.417Z[GMT]") +@javax.xml.bind.annotation.XmlRootElement +public class ApiResponseMessage { + public static final int ERROR = 1; + public static final int WARNING = 2; + public static final int INFO = 3; + public static final int OK = 4; + public static final int TOO_BUSY = 5; + + int code; + String type; + String message; + + public ApiResponseMessage(){} + + public ApiResponseMessage(int code, String message){ + this.code = code; + switch(code){ + case ERROR: + setType("error"); + break; + case WARNING: + setType("warning"); + break; + case INFO: + setType("info"); + break; + case OK: + setType("ok"); + break; + case TOO_BUSY: + setType("too busy"); + break; + default: + setType("unknown"); + break; + } + this.message = message; + } + + @XmlTransient + public int getCode() { + return code; + } + + public void setCode(int code) { + this.code = code; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/api/BaseGsmaApi.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/api/BaseGsmaApi.java new file mode 100644 index 000000000..b8a2e21af --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/api/BaseGsmaApi.java @@ -0,0 +1,7 @@ +package org.mifos.connector.gsmastub.api; + +import org.springframework.web.bind.annotation.RequestMapping; + +@RequestMapping("gsma/") +public interface BaseGsmaApi { +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/api/BatchtransactionsApi.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/api/BatchtransactionsApi.java new file mode 100644 index 000000000..f5caaf736 --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/api/BatchtransactionsApi.java @@ -0,0 +1,134 @@ +/** + * NOTE: This class is auto generated by the swagger code generator program (3.0.34). + * https://github.com/swagger-api/swagger-codegen + * Do not edit the class manually. + */ +package org.mifos.connector.gsmastub.api; + +import org.mifos.connector.gsmastub.model.*; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.enums.ParameterIn; +import io.swagger.v3.oas.annotations.media.ArraySchema; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import org.springframework.http.ResponseEntity; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; +import org.threeten.bp.OffsetDateTime; + +import javax.validation.Valid; +import javax.validation.constraints.Size; +import java.util.List; + +@javax.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.SpringCodegen", date = "2022-09-27T11:46:46.417Z[GMT]") +@Validated +public interface BatchtransactionsApi extends BaseGsmaApi { + + @Operation(summary = "View Batch Completions", description = "This endpoint returns completed transactions for a specific batch", tags={ "Transactions" }) + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Represent a list of Batch Completions", content = @Content(mediaType = "application/json", array = @ArraySchema(schema = @Schema(implementation = ResponseBatchTransactionCompletion.class)))), + + @ApiResponse(responseCode = "400", description = "Represents an Error Caused by the Violation of a Business Rule", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "401", description = "Represents an Error Caused by an Authorisation Failure", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "404", description = "Represents an Error Caused by a Failure to Identify the Target Resource", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "500", description = "Represents an Error Caused by a General Server-Side Issue", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "503", description = "Represents an Error Caused by System Unavailability", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))) }) + @RequestMapping(value = "/batchtransactions/{batchId}/completions", + produces = { "application/json" }, + method = RequestMethod.GET) + ResponseEntity> batchtransactionsBatchIdCompletionsGET(@Size(min=1,max=256) @Parameter(in = ParameterIn.PATH, description = "Path variable to uniquely identify the transaction batch.", required=true, schema=@Schema()) @PathVariable("batchId") String batchId, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." ,schema=@Schema()) @RequestHeader(value="X-Date", required=false) OffsetDateTime xDate, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's API key to the server." ,schema=@Schema()) @RequestHeader(value="X-API-Key", required=false) String xAPIKey, @Parameter(in = ParameterIn.HEADER, description = "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication." ,schema=@Schema()) @RequestHeader(value="X-User-Bearer", required=false) String xUserBearer, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's identifier to the server." ,schema=@Schema()) @RequestHeader(value="X-Client-Id", required=false) String xClientId, @Parameter(in = ParameterIn.HEADER, description = "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." ,schema=@Schema()) @RequestHeader(value="X-Content-Hash", required=false) String xContentHash, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-1", required=false) String xUserCredential1, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-2", required=false) String xUserCredential2, @Parameter(in = ParameterIn.HEADER, description = "String containing the channel that was used to originate the request. For example USSD, Web, App." ,schema=@Schema()) @RequestHeader(value="X-Channel", required=false) String xChannel, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." ,schema=@Schema(allowableValues={ "lei", "swiftbic", "organisationid" } +)) @RequestHeader(value="X-Account-Holding-Institution-Identifier-Type", required=false) String xAccountHoldingInstitutionIdentifierType, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." ,schema=@Schema()) @RequestHeader(value="X-Account-Holding-Institution-Identifier", required=false) String xAccountHoldingInstitutionIdentifier, @Parameter(in = ParameterIn.QUERY, description = "Supports pagination. If this is not supplied, then the server will apply a limit of 50 records returned for each request." ,schema=@Schema()) @Valid @RequestParam(value = "limit", required = false) Integer limit, @Parameter(in = ParameterIn.QUERY, description = "Supports pagination. This value will indicate the cursor position from where to retrieve the set of records. For example, a limit of 50 and offset of 10 will return records 11 to 60." ,schema=@Schema()) @Valid @RequestParam(value = "offset", required = false) Integer offset, @Parameter(in = ParameterIn.QUERY, description = "Indicates the minimum creation date for which records should be returned." ,schema=@Schema()) @Valid @RequestParam(value = "fromDateTime", required = false) OffsetDateTime fromDateTime, @Parameter(in = ParameterIn.QUERY, description = "Indicates the maximum creation date for which records should be returned." ,schema=@Schema()) @Valid @RequestParam(value = "toDateTime", required = false) OffsetDateTime toDateTime); + + + @Operation(summary = "View A Transaction Batch", description = "This endpoint returns the current status of a batch transaction", tags={ "Transactions" }) + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Represents a Batch Transaction response", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ResponseBatchTransaction.class))), + + @ApiResponse(responseCode = "400", description = "Represents an Error Caused by the Violation of a Business Rule", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "401", description = "Represents an Error Caused by an Authorisation Failure", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "404", description = "Represents an Error Caused by a Failure to Identify the Target Resource", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "500", description = "Represents an Error Caused by a General Server-Side Issue", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "503", description = "Represents an Error Caused by System Unavailability", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))) }) + @RequestMapping(value = "/batchtransactions/{batchId}", + produces = { "application/json" }, + method = RequestMethod.GET) + ResponseEntity batchtransactionsBatchIdGET(@Size(min=1,max=256) @Parameter(in = ParameterIn.PATH, description = "Path variable to uniquely identify the transaction batch.", required=true, schema=@Schema()) @PathVariable("batchId") String batchId, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." ,schema=@Schema()) @RequestHeader(value="X-Date", required=false) OffsetDateTime xDate, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's API key to the server." ,schema=@Schema()) @RequestHeader(value="X-API-Key", required=false) String xAPIKey, @Parameter(in = ParameterIn.HEADER, description = "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication." ,schema=@Schema()) @RequestHeader(value="X-User-Bearer", required=false) String xUserBearer, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's identifier to the server." ,schema=@Schema()) @RequestHeader(value="X-Client-Id", required=false) String xClientId, @Parameter(in = ParameterIn.HEADER, description = "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." ,schema=@Schema()) @RequestHeader(value="X-Content-Hash", required=false) String xContentHash, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-1", required=false) String xUserCredential1, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-2", required=false) String xUserCredential2, @Parameter(in = ParameterIn.HEADER, description = "String containing the channel that was used to originate the request. For example USSD, Web, App." ,schema=@Schema()) @RequestHeader(value="X-Channel", required=false) String xChannel, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." ,schema=@Schema(allowableValues={ "lei", "swiftbic", "organisationid" } +)) @RequestHeader(value="X-Account-Holding-Institution-Identifier-Type", required=false) String xAccountHoldingInstitutionIdentifierType, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." ,schema=@Schema()) @RequestHeader(value="X-Account-Holding-Institution-Identifier", required=false) String xAccountHoldingInstitutionIdentifier); + + + @Operation(summary = "Update A Transaction Batch", description = "This endpoint updates a specific transaction batch. Only the batchStatus field can be modified.", tags={ "Transactions" }) + @ApiResponses(value = { + @ApiResponse(responseCode = "202", description = "Represents an Asynchronous response", content = @Content(mediaType = "application/json", schema = @Schema(implementation = RequestStateObject.class))), + + @ApiResponse(responseCode = "204", description = "An empty response is returned for a synchronous successful patch."), + + @ApiResponse(responseCode = "400", description = "Represents an Error Caused by the Violation of a Business Rule", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "401", description = "Represents an Error Caused by an Authorisation Failure", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "404", description = "Represents an Error Caused by a Failure to Identify the Target Resource", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "500", description = "Represents an Error Caused by a General Server-Side Issue", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "503", description = "Represents an Error Caused by System Unavailability", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))) }) + @RequestMapping(value = "/batchtransactions/{batchId}", + produces = { "application/json" }, + consumes = { "application/json" }, + method = RequestMethod.PATCH) + ResponseEntity batchtransactionsBatchIdPATCH(@Size(min=1,max=256) @Parameter(in = ParameterIn.PATH, description = "Path variable to uniquely identify the transaction batch.", required=true, schema=@Schema()) @PathVariable("batchId") String batchId, @Parameter(in = ParameterIn.DEFAULT, description = "Represents the request body of a batch of generic Patch operation.", required=true, schema=@Schema()) @Valid @RequestBody List body, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." ,schema=@Schema()) @RequestHeader(value="X-Date", required=false) OffsetDateTime xDate, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's API key to the server." ,schema=@Schema()) @RequestHeader(value="X-API-Key", required=false) String xAPIKey, @Parameter(in = ParameterIn.HEADER, description = "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication." ,schema=@Schema()) @RequestHeader(value="X-User-Bearer", required=false) String xUserBearer, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's identifier to the server." ,schema=@Schema()) @RequestHeader(value="X-Client-Id", required=false) String xClientId, @Parameter(in = ParameterIn.HEADER, description = "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." ,schema=@Schema()) @RequestHeader(value="X-Content-Hash", required=false) String xContentHash, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-1", required=false) String xUserCredential1, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-2", required=false) String xUserCredential2, @Parameter(in = ParameterIn.HEADER, description = "String containing the channel that was used to originate the request. For example USSD, Web, App." ,schema=@Schema()) @RequestHeader(value="X-Channel", required=false) String xChannel, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." ,schema=@Schema(allowableValues={ "lei", "swiftbic", "organisationid" } +)) @RequestHeader(value="X-Account-Holding-Institution-Identifier-Type", required=false) String xAccountHoldingInstitutionIdentifierType, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." ,schema=@Schema()) @RequestHeader(value="X-Account-Holding-Institution-Identifier", required=false) String xAccountHoldingInstitutionIdentifier, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to uniquely identify the request. Must be supplied as a UUID." ,schema=@Schema()) @RequestHeader(value="X-CorrelationID", required=false) String xCorrelationID, @Parameter(in = ParameterIn.HEADER, description = "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." ,schema=@Schema()) @RequestHeader(value="X-Callback-URL", required=false) String xCallbackURL); + + + @Operation(summary = "View Batch Rejections", description = "This endpoint returns rejected transactions for a specific batch\"", tags={ "Transactions" }) + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Represents a Batch Transaction Rejection response", content = @Content(mediaType = "application/json", array = @ArraySchema(schema = @Schema(implementation = ResponseBatchTransactionRejection.class)))), + + @ApiResponse(responseCode = "400", description = "Represents an Error Caused by the Violation of a Business Rule", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "401", description = "Represents an Error Caused by an Authorisation Failure", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "404", description = "Represents an Error Caused by a Failure to Identify the Target Resource", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "500", description = "Represents an Error Caused by a General Server-Side Issue", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "503", description = "Represents an Error Caused by System Unavailability", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))) }) + @RequestMapping(value = "/batchtransactions/{batchId}/rejections", + produces = { "application/json" }, + method = RequestMethod.GET) + ResponseEntity> batchtransactionsBatchIdRejectionsGET(@Size(min=1,max=256) @Parameter(in = ParameterIn.PATH, description = "Path variable to uniquely identify the transaction batch.", required=true, schema=@Schema()) @PathVariable("batchId") String batchId, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." ,schema=@Schema()) @RequestHeader(value="X-Date", required=false) OffsetDateTime xDate, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's API key to the server." ,schema=@Schema()) @RequestHeader(value="X-API-Key", required=false) String xAPIKey, @Parameter(in = ParameterIn.HEADER, description = "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication." ,schema=@Schema()) @RequestHeader(value="X-User-Bearer", required=false) String xUserBearer, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's identifier to the server." ,schema=@Schema()) @RequestHeader(value="X-Client-Id", required=false) String xClientId, @Parameter(in = ParameterIn.HEADER, description = "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." ,schema=@Schema()) @RequestHeader(value="X-Content-Hash", required=false) String xContentHash, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-1", required=false) String xUserCredential1, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-2", required=false) String xUserCredential2, @Parameter(in = ParameterIn.HEADER, description = "String containing the channel that was used to originate the request. For example USSD, Web, App." ,schema=@Schema()) @RequestHeader(value="X-Channel", required=false) String xChannel, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." ,schema=@Schema(allowableValues={ "lei", "swiftbic", "organisationid" } +)) @RequestHeader(value="X-Account-Holding-Institution-Identifier-Type", required=false) String xAccountHoldingInstitutionIdentifierType, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." ,schema=@Schema()) @RequestHeader(value="X-Account-Holding-Institution-Identifier", required=false) String xAccountHoldingInstitutionIdentifier, @Parameter(in = ParameterIn.QUERY, description = "Supports pagination. If this is not supplied, then the server will apply a limit of 50 records returned for each request." ,schema=@Schema()) @Valid @RequestParam(value = "limit", required = false) Integer limit, @Parameter(in = ParameterIn.QUERY, description = "Supports pagination. This value will indicate the cursor position from where to retrieve the set of records. For example, a limit of 50 and offset of 10 will return records 11 to 60." ,schema=@Schema()) @Valid @RequestParam(value = "offset", required = false) Integer offset, @Parameter(in = ParameterIn.QUERY, description = "Indicates the minimum creation date for which records should be returned." ,schema=@Schema()) @Valid @RequestParam(value = "fromDateTime", required = false) OffsetDateTime fromDateTime, @Parameter(in = ParameterIn.QUERY, description = "Indicates the maximum creation date for which records should be returned." ,schema=@Schema()) @Valid @RequestParam(value = "toDateTime", required = false) OffsetDateTime toDateTime); + + + @Operation(summary = "Create A Transaction Batch", description = "Provided with a valid object representation, this endpoint allows for a new transaction batch to be created", tags={ "Transactions" }) + @ApiResponses(value = { + @ApiResponse(responseCode = "202", description = "Represents an Asynchronous response", content = @Content(mediaType = "application/json", schema = @Schema(implementation = RequestStateObject.class))), + + @ApiResponse(responseCode = "400", description = "Represents an Error Caused by the Violation of a Business Rule", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "401", description = "Represents an Error Caused by an Authorisation Failure", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "404", description = "Represents an Error Caused by a Failure to Identify the Target Resource", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "500", description = "Represents an Error Caused by a General Server-Side Issue", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "503", description = "Represents an Error Caused by System Unavailability", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))) }) + @RequestMapping(value = "/batchtransactions", + produces = { "application/json" }, + consumes = { "application/json" }, + method = RequestMethod.POST) + ResponseEntity batchtransactionsPOST(@Parameter(in = ParameterIn.DEFAULT, description = "Represents the request body of a batch of transactions.", required=true, schema=@Schema()) @Valid @RequestBody RequestBatchTransaction body, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." ,schema=@Schema()) @RequestHeader(value="X-Date", required=false) OffsetDateTime xDate, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to uniquely identify the request. Must be supplied as a UUID." ,schema=@Schema()) @RequestHeader(value="X-CorrelationID", required=false) String xCorrelationID, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's API key to the server." ,schema=@Schema()) @RequestHeader(value="X-API-Key", required=false) String xAPIKey, @Parameter(in = ParameterIn.HEADER, description = "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication." ,schema=@Schema()) @RequestHeader(value="X-User-Bearer", required=false) String xUserBearer, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's identifier to the server." ,schema=@Schema()) @RequestHeader(value="X-Client-Id", required=false) String xClientId, @Parameter(in = ParameterIn.HEADER, description = "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." ,schema=@Schema()) @RequestHeader(value="X-Content-Hash", required=false) String xContentHash, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-1", required=false) String xUserCredential1, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-2", required=false) String xUserCredential2, @Parameter(in = ParameterIn.HEADER, description = "String containing the channel that was used to originate the request. For example USSD, Web, App." ,schema=@Schema()) @RequestHeader(value="X-Channel", required=false) String xChannel, @Parameter(in = ParameterIn.HEADER, description = "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." ,schema=@Schema()) @RequestHeader(value="X-Callback-URL", required=false) String xCallbackURL, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." ,schema=@Schema(allowableValues={ "lei", "swiftbic", "organisationid" } +)) @RequestHeader(value="X-Account-Holding-Institution-Identifier-Type", required=false) String xAccountHoldingInstitutionIdentifierType, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." ,schema=@Schema()) @RequestHeader(value="X-Account-Holding-Institution-Identifier", required=false) String xAccountHoldingInstitutionIdentifier); + +} + diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/api/BatchtransactionsApiController.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/api/BatchtransactionsApiController.java new file mode 100644 index 000000000..c5dc4db7f --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/api/BatchtransactionsApiController.java @@ -0,0 +1,114 @@ +package org.mifos.connector.gsmastub.api; + +import com.fasterxml.jackson.databind.ObjectMapper; +import io.swagger.v3.oas.annotations.Hidden; +import io.swagger.v3.oas.annotations.Parameter; +import org.mifos.connector.gsmastub.model.*; +import io.swagger.v3.oas.annotations.enums.ParameterIn; +import io.swagger.v3.oas.annotations.media.Schema; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; +import org.threeten.bp.OffsetDateTime; + +import javax.servlet.http.HttpServletRequest; +import javax.validation.Valid; +import javax.validation.constraints.Size; +import java.io.IOException; +import java.util.List; + +@javax.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.SpringCodegen", date = "2022-09-27T11:46:46.417Z[GMT]") +@RestController +@Hidden +public class BatchtransactionsApiController implements BatchtransactionsApi { + + private static final Logger log = LoggerFactory.getLogger(BatchtransactionsApiController.class); + + private final ObjectMapper objectMapper; + + private final HttpServletRequest request; + + @org.springframework.beans.factory.annotation.Autowired + public BatchtransactionsApiController(ObjectMapper objectMapper, HttpServletRequest request) { + this.objectMapper = objectMapper; + this.request = request; + } + + public ResponseEntity> batchtransactionsBatchIdCompletionsGET(@Size(min=1,max=256) @Parameter(in = ParameterIn.PATH, description = "Path variable to uniquely identify the transaction batch.", required=true, schema=@Schema()) @PathVariable("batchId") String batchId, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." ,schema=@Schema()) @RequestHeader(value="X-Date", required=false) OffsetDateTime xDate, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's API key to the server." ,schema=@Schema()) @RequestHeader(value="X-API-Key", required=false) String xAPIKey, @Parameter(in = ParameterIn.HEADER, description = "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication." ,schema=@Schema()) @RequestHeader(value="X-User-Bearer", required=false) String xUserBearer, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's identifier to the server." ,schema=@Schema()) @RequestHeader(value="X-Client-Id", required=false) String xClientId, @Parameter(in = ParameterIn.HEADER, description = "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." ,schema=@Schema()) @RequestHeader(value="X-Content-Hash", required=false) String xContentHash, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-1", required=false) String xUserCredential1, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-2", required=false) String xUserCredential2, @Parameter(in = ParameterIn.HEADER, description = "String containing the channel that was used to originate the request. For example USSD, Web, App." ,schema=@Schema()) @RequestHeader(value="X-Channel", required=false) String xChannel, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." ,schema=@Schema(allowableValues={ "lei", "swiftbic", "organisationid" } +)) @RequestHeader(value="X-Account-Holding-Institution-Identifier-Type", required=false) String xAccountHoldingInstitutionIdentifierType, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." ,schema=@Schema()) @RequestHeader(value="X-Account-Holding-Institution-Identifier", required=false) String xAccountHoldingInstitutionIdentifier, @Parameter(in = ParameterIn.QUERY, description = "Supports pagination. If this is not supplied, then the server will apply a limit of 50 records returned for each request." ,schema=@Schema()) @Valid @RequestParam(value = "limit", required = false) Integer limit, @Parameter(in = ParameterIn.QUERY, description = "Supports pagination. This value will indicate the cursor position from where to retrieve the set of records. For example, a limit of 50 and offset of 10 will return records 11 to 60." ,schema=@Schema()) @Valid @RequestParam(value = "offset", required = false) Integer offset, @Parameter(in = ParameterIn.QUERY, description = "Indicates the minimum creation date for which records should be returned." ,schema=@Schema()) @Valid @RequestParam(value = "fromDateTime", required = false) OffsetDateTime fromDateTime, @Parameter(in = ParameterIn.QUERY, description = "Indicates the maximum creation date for which records should be returned." ,schema=@Schema()) @Valid @RequestParam(value = "toDateTime", required = false) OffsetDateTime toDateTime) { + String accept = request.getHeader("Accept"); + if (accept != null && accept.contains("application/json")) { + try { + return new ResponseEntity>(objectMapper.readValue("[ {\n \"debitParty\" : [ null, null, null, null, null, null, null, null, null, null ],\n \"transactionReference\" : \"transactionReference\",\n \"link\" : \"link\",\n \"requestingOrganisationTransactionReference\" : \"requestingOrganisationTransactionReference\",\n \"completionDate\" : \"2000-01-23T04:56:07.000+00:00\",\n \"customData\" : [ {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n } ],\n \"creditParty\" : [ {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n } ],\n \"completedDate\" : \"2000-01-23T04:56:07.000+00:00\"\n}, {\n \"debitParty\" : [ null, null, null, null, null, null, null, null, null, null ],\n \"transactionReference\" : \"transactionReference\",\n \"link\" : \"link\",\n \"requestingOrganisationTransactionReference\" : \"requestingOrganisationTransactionReference\",\n \"completionDate\" : \"2000-01-23T04:56:07.000+00:00\",\n \"customData\" : [ {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n } ],\n \"creditParty\" : [ {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n } ],\n \"completedDate\" : \"2000-01-23T04:56:07.000+00:00\"\n} ]", List.class), HttpStatus.OK); + } catch (IOException e) { + log.error("Couldn't serialize response for content type application/json", e); + return new ResponseEntity>(HttpStatus.INTERNAL_SERVER_ERROR); + } + } + + return new ResponseEntity>(HttpStatus.OK); + } + + public ResponseEntity batchtransactionsBatchIdGET(@Size(min=1,max=256) @Parameter(in = ParameterIn.PATH, description = "Path variable to uniquely identify the transaction batch.", required=true, schema=@Schema()) @PathVariable("batchId") String batchId,@Parameter(in = ParameterIn.HEADER, description = "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." ,schema=@Schema()) @RequestHeader(value="X-Date", required=false) OffsetDateTime xDate,@Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's API key to the server." ,schema=@Schema()) @RequestHeader(value="X-API-Key", required=false) String xAPIKey,@Parameter(in = ParameterIn.HEADER, description = "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication." ,schema=@Schema()) @RequestHeader(value="X-User-Bearer", required=false) String xUserBearer,@Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's identifier to the server." ,schema=@Schema()) @RequestHeader(value="X-Client-Id", required=false) String xClientId,@Parameter(in = ParameterIn.HEADER, description = "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." ,schema=@Schema()) @RequestHeader(value="X-Content-Hash", required=false) String xContentHash,@Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-1", required=false) String xUserCredential1,@Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-2", required=false) String xUserCredential2,@Parameter(in = ParameterIn.HEADER, description = "String containing the channel that was used to originate the request. For example USSD, Web, App." ,schema=@Schema()) @RequestHeader(value="X-Channel", required=false) String xChannel,@Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." ,schema=@Schema(allowableValues={ "lei", "swiftbic", "organisationid" } +)) @RequestHeader(value="X-Account-Holding-Institution-Identifier-Type", required=false) String xAccountHoldingInstitutionIdentifierType,@Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." ,schema=@Schema()) @RequestHeader(value="X-Account-Holding-Institution-Identifier", required=false) String xAccountHoldingInstitutionIdentifier) { + String accept = request.getHeader("Accept"); + if (accept != null && accept.contains("application/json")) { + try { + return new ResponseEntity(objectMapper.readValue("{\n \"approvalDate\" : \"2000-01-23T04:56:07.000+00:00\",\n \"batchdescription\" : \"batchdescription\",\n \"requestingOrganisation\" : {\n \"requestingOrganisationIdentifierType\" : \"lei\",\n \"requestingOrganisationIdentifier\" : \"requestingOrganisationIdentifier\"\n },\n \"rejectionCount\" : 0.6027456183070403,\n \"customData\" : [ {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n } ],\n \"batchId\" : \"batchId\",\n \"completedCount\" : 0.08008281904610115,\n \"creationDate\" : \"2000-01-23T04:56:07.000+00:00\",\n \"scheduledStartDate\" : \"2000-01-23T04:56:07.000+00:00\",\n \"completedDate\" : \"2000-01-23T04:56:07.000+00:00\",\n \"modificationDate\" : \"2000-01-23T04:56:07.000+00:00\",\n \"processingFlag\" : true,\n \"requestDate\" : \"2000-01-23T04:56:07.000+00:00\",\n \"completionDate\" : \"2000-01-23T04:56:07.000+00:00\",\n \"batchTitle\" : \"batchTitle\",\n \"parsingSuccessCount\" : 0.14658129805029452,\n \"batchStatus\" : \"created\"\n}", ResponseBatchTransaction.class), HttpStatus.OK); + } catch (IOException e) { + log.error("Couldn't serialize response for content type application/json", e); + return new ResponseEntity(HttpStatus.INTERNAL_SERVER_ERROR); + } + } + + return new ResponseEntity(HttpStatus.OK); + } + + public ResponseEntity batchtransactionsBatchIdPATCH(@Size(min=1,max=256) @Parameter(in = ParameterIn.PATH, description = "Path variable to uniquely identify the transaction batch.", required=true, schema=@Schema()) @PathVariable("batchId") String batchId,@Parameter(in = ParameterIn.DEFAULT, description = "Represents the request body of a batch of generic Patch operation.", required=true, schema=@Schema()) @Valid @RequestBody List body,@Parameter(in = ParameterIn.HEADER, description = "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." ,schema=@Schema()) @RequestHeader(value="X-Date", required=false) OffsetDateTime xDate,@Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's API key to the server." ,schema=@Schema()) @RequestHeader(value="X-API-Key", required=false) String xAPIKey,@Parameter(in = ParameterIn.HEADER, description = "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication." ,schema=@Schema()) @RequestHeader(value="X-User-Bearer", required=false) String xUserBearer,@Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's identifier to the server." ,schema=@Schema()) @RequestHeader(value="X-Client-Id", required=false) String xClientId,@Parameter(in = ParameterIn.HEADER, description = "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." ,schema=@Schema()) @RequestHeader(value="X-Content-Hash", required=false) String xContentHash,@Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-1", required=false) String xUserCredential1,@Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-2", required=false) String xUserCredential2,@Parameter(in = ParameterIn.HEADER, description = "String containing the channel that was used to originate the request. For example USSD, Web, App." ,schema=@Schema()) @RequestHeader(value="X-Channel", required=false) String xChannel,@Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." ,schema=@Schema(allowableValues={ "lei", "swiftbic", "organisationid" } +)) @RequestHeader(value="X-Account-Holding-Institution-Identifier-Type", required=false) String xAccountHoldingInstitutionIdentifierType,@Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." ,schema=@Schema()) @RequestHeader(value="X-Account-Holding-Institution-Identifier", required=false) String xAccountHoldingInstitutionIdentifier,@Parameter(in = ParameterIn.HEADER, description = "Header parameter to uniquely identify the request. Must be supplied as a UUID." ,schema=@Schema()) @RequestHeader(value="X-CorrelationID", required=false) String xCorrelationID,@Parameter(in = ParameterIn.HEADER, description = "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." ,schema=@Schema()) @RequestHeader(value="X-Callback-URL", required=false) String xCallbackURL) { + String accept = request.getHeader("Accept"); + if (accept != null && accept.contains("application/json")) { + try { + return new ResponseEntity(objectMapper.readValue("{\n \"pollLimit\" : 0.08008281904610115,\n \"pendingReason\" : \"pendingReason\",\n \"expiryTime\" : \"2000-01-23T04:56:07.000+00:00\",\n \"objectReference\" : \"objectReference\",\n \"notificationMethod\" : \"callback\",\n \"error\" : {\n \"errordescription\" : \"errordescription\",\n \"errorCategory\" : \"businessRule\",\n \"errorParameters\" : [ {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n } ],\n \"errorDateTime\" : \"2000-01-23T04:56:07.000+00:00\",\n \"errorCode\" : \"genericError\"\n },\n \"serverCorrelationId\" : \"serverCorrelationId\",\n \"status\" : \"pending\"\n}", RequestStateObject.class), HttpStatus.OK); + } catch (IOException e) { + log.error("Couldn't serialize response for content type application/json", e); + return new ResponseEntity(HttpStatus.INTERNAL_SERVER_ERROR); + } + } + + return new ResponseEntity(HttpStatus.OK); + } + + public ResponseEntity> batchtransactionsBatchIdRejectionsGET(@Size(min=1,max=256) @Parameter(in = ParameterIn.PATH, description = "Path variable to uniquely identify the transaction batch.", required=true, schema=@Schema()) @PathVariable("batchId") String batchId,@Parameter(in = ParameterIn.HEADER, description = "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." ,schema=@Schema()) @RequestHeader(value="X-Date", required=false) OffsetDateTime xDate,@Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's API key to the server." ,schema=@Schema()) @RequestHeader(value="X-API-Key", required=false) String xAPIKey,@Parameter(in = ParameterIn.HEADER, description = "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication." ,schema=@Schema()) @RequestHeader(value="X-User-Bearer", required=false) String xUserBearer,@Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's identifier to the server." ,schema=@Schema()) @RequestHeader(value="X-Client-Id", required=false) String xClientId,@Parameter(in = ParameterIn.HEADER, description = "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." ,schema=@Schema()) @RequestHeader(value="X-Content-Hash", required=false) String xContentHash,@Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-1", required=false) String xUserCredential1,@Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-2", required=false) String xUserCredential2,@Parameter(in = ParameterIn.HEADER, description = "String containing the channel that was used to originate the request. For example USSD, Web, App." ,schema=@Schema()) @RequestHeader(value="X-Channel", required=false) String xChannel,@Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." ,schema=@Schema(allowableValues={ "lei", "swiftbic", "organisationid" } +)) @RequestHeader(value="X-Account-Holding-Institution-Identifier-Type", required=false) String xAccountHoldingInstitutionIdentifierType,@Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." ,schema=@Schema()) @RequestHeader(value="X-Account-Holding-Institution-Identifier", required=false) String xAccountHoldingInstitutionIdentifier,@Parameter(in = ParameterIn.QUERY, description = "Supports pagination. If this is not supplied, then the server will apply a limit of 50 records returned for each request." ,schema=@Schema()) @Valid @RequestParam(value = "limit", required = false) Integer limit,@Parameter(in = ParameterIn.QUERY, description = "Supports pagination. This value will indicate the cursor position from where to retrieve the set of records. For example, a limit of 50 and offset of 10 will return records 11 to 60." ,schema=@Schema()) @Valid @RequestParam(value = "offset", required = false) Integer offset,@Parameter(in = ParameterIn.QUERY, description = "Indicates the minimum creation date for which records should be returned." ,schema=@Schema()) @Valid @RequestParam(value = "fromDateTime", required = false) OffsetDateTime fromDateTime,@Parameter(in = ParameterIn.QUERY, description = "Indicates the maximum creation date for which records should be returned." ,schema=@Schema()) @Valid @RequestParam(value = "toDateTime", required = false) OffsetDateTime toDateTime) { + String accept = request.getHeader("Accept"); + if (accept != null && accept.contains("application/json")) { + try { + return new ResponseEntity>(objectMapper.readValue("[ {\n \"debitParty\" : [ null, null, null, null, null, null, null, null, null, null ],\n \"dateRejected\" : \"2000-01-23T04:56:07.000+00:00\",\n \"transactionReference\" : \"transactionReference\",\n \"rejectionDate\" : \"2000-01-23T04:56:07.000+00:00\",\n \"requestingOrganisationTransactionReference\" : \"requestingOrganisationTransactionReference\",\n \"customData\" : [ {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n } ],\n \"rejectionReason\" : \"rejectionReason\",\n \"creditParty\" : [ {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n } ]\n}, {\n \"debitParty\" : [ null, null, null, null, null, null, null, null, null, null ],\n \"dateRejected\" : \"2000-01-23T04:56:07.000+00:00\",\n \"transactionReference\" : \"transactionReference\",\n \"rejectionDate\" : \"2000-01-23T04:56:07.000+00:00\",\n \"requestingOrganisationTransactionReference\" : \"requestingOrganisationTransactionReference\",\n \"customData\" : [ {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n } ],\n \"rejectionReason\" : \"rejectionReason\",\n \"creditParty\" : [ {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n } ]\n} ]", List.class), HttpStatus.OK); + } catch (IOException e) { + log.error("Couldn't serialize response for content type application/json", e); + return new ResponseEntity>(HttpStatus.INTERNAL_SERVER_ERROR); + } + } + + return new ResponseEntity>(HttpStatus.OK); + } + + public ResponseEntity batchtransactionsPOST(@Parameter(in = ParameterIn.DEFAULT, description = "Represents the request body of a batch of transactions.", required=true, schema=@Schema()) @Valid @RequestBody RequestBatchTransaction body,@Parameter(in = ParameterIn.HEADER, description = "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." ,schema=@Schema()) @RequestHeader(value="X-Date", required=false) OffsetDateTime xDate,@Parameter(in = ParameterIn.HEADER, description = "Header parameter to uniquely identify the request. Must be supplied as a UUID." ,schema=@Schema()) @RequestHeader(value="X-CorrelationID", required=false) String xCorrelationID,@Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's API key to the server." ,schema=@Schema()) @RequestHeader(value="X-API-Key", required=false) String xAPIKey,@Parameter(in = ParameterIn.HEADER, description = "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication." ,schema=@Schema()) @RequestHeader(value="X-User-Bearer", required=false) String xUserBearer,@Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's identifier to the server." ,schema=@Schema()) @RequestHeader(value="X-Client-Id", required=false) String xClientId,@Parameter(in = ParameterIn.HEADER, description = "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." ,schema=@Schema()) @RequestHeader(value="X-Content-Hash", required=false) String xContentHash,@Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-1", required=false) String xUserCredential1,@Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-2", required=false) String xUserCredential2,@Parameter(in = ParameterIn.HEADER, description = "String containing the channel that was used to originate the request. For example USSD, Web, App." ,schema=@Schema()) @RequestHeader(value="X-Channel", required=false) String xChannel,@Parameter(in = ParameterIn.HEADER, description = "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." ,schema=@Schema()) @RequestHeader(value="X-Callback-URL", required=false) String xCallbackURL,@Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." ,schema=@Schema(allowableValues={ "lei", "swiftbic", "organisationid" } +)) @RequestHeader(value="X-Account-Holding-Institution-Identifier-Type", required=false) String xAccountHoldingInstitutionIdentifierType,@Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." ,schema=@Schema()) @RequestHeader(value="X-Account-Holding-Institution-Identifier", required=false) String xAccountHoldingInstitutionIdentifier) { + String accept = request.getHeader("Accept"); + if (accept != null && accept.contains("application/json")) { + try { + return new ResponseEntity(objectMapper.readValue("{\n \"pollLimit\" : 0.08008281904610115,\n \"pendingReason\" : \"pendingReason\",\n \"expiryTime\" : \"2000-01-23T04:56:07.000+00:00\",\n \"objectReference\" : \"objectReference\",\n \"notificationMethod\" : \"callback\",\n \"error\" : {\n \"errordescription\" : \"errordescription\",\n \"errorCategory\" : \"businessRule\",\n \"errorParameters\" : [ {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n } ],\n \"errorDateTime\" : \"2000-01-23T04:56:07.000+00:00\",\n \"errorCode\" : \"genericError\"\n },\n \"serverCorrelationId\" : \"serverCorrelationId\",\n \"status\" : \"pending\"\n}", RequestStateObject.class), HttpStatus.OK); + } catch (IOException e) { + log.error("Couldn't serialize response for content type application/json", e); + return new ResponseEntity(HttpStatus.INTERNAL_SERVER_ERROR); + } + } + + return new ResponseEntity(HttpStatus.OK); + } + +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/api/BillcompaniesApi.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/api/BillcompaniesApi.java new file mode 100644 index 000000000..e30f429eb --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/api/BillcompaniesApi.java @@ -0,0 +1,71 @@ +/** + * NOTE: This class is auto generated by the swagger code generator program (3.0.34). + * https://github.com/swagger-api/swagger-codegen + * Do not edit the class manually. + */ +package org.mifos.connector.gsmastub.api; + +import org.mifos.connector.gsmastub.model.ErrorObject; +import org.mifos.connector.gsmastub.model.ResponseBillCompanies; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.enums.ParameterIn; +import io.swagger.v3.oas.annotations.media.ArraySchema; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import org.springframework.http.ResponseEntity; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; +import org.threeten.bp.OffsetDateTime; + +import javax.validation.Valid; +import javax.validation.constraints.Size; +import java.util.List; + +@javax.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.SpringCodegen", date = "2022-09-27T11:46:46.417Z[GMT]") +@Validated +public interface BillcompaniesApi extends BaseGsmaApi { + + @Operation(summary = "View Bill Companies", description = "The Bill Companies API is used to return a list of Service Providers that accept Bill Payments.", tags={ "Bills" }) + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Represent a list of Bill Companies", content = @Content(mediaType = "application/json", array = @ArraySchema(schema = @Schema(implementation = ResponseBillCompanies.class)))), + + @ApiResponse(responseCode = "400", description = "Represents an Error Caused by the Violation of a Business Rule", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "401", description = "Represents an Error Caused by an Authorisation Failure", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "404", description = "Represents an Error Caused by a Failure to Identify the Target Resource", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "500", description = "Represents an Error Caused by a General Server-Side Issue", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "503", description = "Represents an Error Caused by System Unavailability", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))) }) + @RequestMapping(value = "/billcompanies", + produces = { "application/json" }, + method = RequestMethod.GET) + ResponseEntity> billCompaniesGET(@Parameter(in = ParameterIn.HEADER, description = "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." ,schema=@Schema()) @RequestHeader(value="X-Date", required=false) OffsetDateTime xDate, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's API key to the server." ,schema=@Schema()) @RequestHeader(value="X-API-Key", required=false) String xAPIKey, @Parameter(in = ParameterIn.HEADER, description = "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication." ,schema=@Schema()) @RequestHeader(value="X-User-Bearer", required=false) String xUserBearer, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's identifier to the server." ,schema=@Schema()) @RequestHeader(value="X-Client-Id", required=false) String xClientId, @Parameter(in = ParameterIn.HEADER, description = "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." ,schema=@Schema()) @RequestHeader(value="X-Content-Hash", required=false) String xContentHash, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-1", required=false) String xUserCredential1, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-2", required=false) String xUserCredential2, @Parameter(in = ParameterIn.HEADER, description = "String containing the channel that was used to originate the request. For example USSD, Web, App." ,schema=@Schema()) @RequestHeader(value="X-Channel", required=false) String xChannel, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." ,schema=@Schema(allowableValues={ "lei", "swiftbic", "organisationid" } +)) @RequestHeader(value="X-Account-Holding-Institution-Identifier-Type", required=false) String xAccountHoldingInstitutionIdentifierType, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." ,schema=@Schema()) @RequestHeader(value="X-Account-Holding-Institution-Identifier", required=false) String xAccountHoldingInstitutionIdentifier, @Parameter(in = ParameterIn.QUERY, description = "Supports pagination. If this is not supplied, then the server will apply a limit of 50 records returned for each request." ,schema=@Schema()) @Valid @RequestParam(value = "limit", required = false) Integer limit, @Parameter(in = ParameterIn.QUERY, description = "Supports pagination. This value will indicate the cursor position from where to retrieve the set of records. For example, a limit of 50 and offset of 10 will return records 11 to 60." ,schema=@Schema()) @Valid @RequestParam(value = "offset", required = false) Integer offset); + + + @Operation(summary = "View a Specific Bill Company", description = "This Bill Companies API is used to return a information for a specific Service Providers that accepts Bill Payments.", tags={ "Bills" }) + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Returns a specific Bill Payment Service Provider", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ResponseBillCompanies.class))), + + @ApiResponse(responseCode = "400", description = "Represents an Error Caused by the Violation of a Business Rule", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "401", description = "Represents an Error Caused by an Authorisation Failure", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "404", description = "Represents an Error Caused by a Failure to Identify the Target Resource", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "500", description = "Represents an Error Caused by a General Server-Side Issue", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "503", description = "Represents an Error Caused by System Unavailability", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))) }) + @RequestMapping(value = "/billcompanies/{serviceProvider}", + produces = { "application/json" }, + method = RequestMethod.GET) + ResponseEntity billCompaniesServiceProviderGET(@Size(min=1,max=256) @Parameter(in = ParameterIn.PATH, description = "The identifier for the Bill Payment Service Provider.", required=true, schema=@Schema()) @PathVariable("serviceProvider") String serviceProvider, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." ,schema=@Schema()) @RequestHeader(value="X-Date", required=false) OffsetDateTime xDate, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's API key to the server." ,schema=@Schema()) @RequestHeader(value="X-API-Key", required=false) String xAPIKey, @Parameter(in = ParameterIn.HEADER, description = "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication." ,schema=@Schema()) @RequestHeader(value="X-User-Bearer", required=false) String xUserBearer, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's identifier to the server." ,schema=@Schema()) @RequestHeader(value="X-Client-Id", required=false) String xClientId, @Parameter(in = ParameterIn.HEADER, description = "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." ,schema=@Schema()) @RequestHeader(value="X-Content-Hash", required=false) String xContentHash, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-1", required=false) String xUserCredential1, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-2", required=false) String xUserCredential2, @Parameter(in = ParameterIn.HEADER, description = "String containing the channel that was used to originate the request. For example USSD, Web, App." ,schema=@Schema()) @RequestHeader(value="X-Channel", required=false) String xChannel, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." ,schema=@Schema(allowableValues={ "lei", "swiftbic", "organisationid" } +)) @RequestHeader(value="X-Account-Holding-Institution-Identifier-Type", required=false) String xAccountHoldingInstitutionIdentifierType, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." ,schema=@Schema()) @RequestHeader(value="X-Account-Holding-Institution-Identifier", required=false) String xAccountHoldingInstitutionIdentifier); + +} + diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/api/BillcompaniesApiController.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/api/BillcompaniesApiController.java new file mode 100644 index 000000000..edc0ef2fb --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/api/BillcompaniesApiController.java @@ -0,0 +1,72 @@ +package org.mifos.connector.gsmastub.api; + +import com.fasterxml.jackson.databind.ObjectMapper; +import io.swagger.v3.oas.annotations.Hidden; +import io.swagger.v3.oas.annotations.Parameter; +import org.mifos.connector.gsmastub.model.ResponseBillCompanies; +import io.swagger.v3.oas.annotations.enums.ParameterIn; +import io.swagger.v3.oas.annotations.media.Schema; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestHeader; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; +import org.threeten.bp.OffsetDateTime; + +import javax.servlet.http.HttpServletRequest; +import javax.validation.Valid; +import javax.validation.constraints.Size; +import java.io.IOException; +import java.util.List; + +@javax.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.SpringCodegen", date = "2022-09-27T11:46:46.417Z[GMT]") +@RestController +@Hidden +public class BillcompaniesApiController implements BillcompaniesApi { + + private static final Logger log = LoggerFactory.getLogger(BillcompaniesApiController.class); + + private final ObjectMapper objectMapper; + + private final HttpServletRequest request; + + @org.springframework.beans.factory.annotation.Autowired + public BillcompaniesApiController(ObjectMapper objectMapper, HttpServletRequest request) { + this.objectMapper = objectMapper; + this.request = request; + } + + public ResponseEntity> billCompaniesGET(@Parameter(in = ParameterIn.HEADER, description = "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." ,schema=@Schema()) @RequestHeader(value="X-Date", required=false) OffsetDateTime xDate,@Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's API key to the server." ,schema=@Schema()) @RequestHeader(value="X-API-Key", required=false) String xAPIKey,@Parameter(in = ParameterIn.HEADER, description = "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication." ,schema=@Schema()) @RequestHeader(value="X-User-Bearer", required=false) String xUserBearer,@Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's identifier to the server." ,schema=@Schema()) @RequestHeader(value="X-Client-Id", required=false) String xClientId,@Parameter(in = ParameterIn.HEADER, description = "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." ,schema=@Schema()) @RequestHeader(value="X-Content-Hash", required=false) String xContentHash,@Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-1", required=false) String xUserCredential1,@Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-2", required=false) String xUserCredential2,@Parameter(in = ParameterIn.HEADER, description = "String containing the channel that was used to originate the request. For example USSD, Web, App." ,schema=@Schema()) @RequestHeader(value="X-Channel", required=false) String xChannel,@Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." ,schema=@Schema(allowableValues={ "lei", "swiftbic", "organisationid" } +)) @RequestHeader(value="X-Account-Holding-Institution-Identifier-Type", required=false) String xAccountHoldingInstitutionIdentifierType,@Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." ,schema=@Schema()) @RequestHeader(value="X-Account-Holding-Institution-Identifier", required=false) String xAccountHoldingInstitutionIdentifier,@Parameter(in = ParameterIn.QUERY, description = "Supports pagination. If this is not supplied, then the server will apply a limit of 50 records returned for each request." ,schema=@Schema()) @Valid @RequestParam(value = "limit", required = false) Integer limit,@Parameter(in = ParameterIn.QUERY, description = "Supports pagination. This value will indicate the cursor position from where to retrieve the set of records. For example, a limit of 50 and offset of 10 will return records 11 to 60." ,schema=@Schema()) @Valid @RequestParam(value = "offset", required = false) Integer offset) { + String accept = request.getHeader("Accept"); + if (accept != null && accept.contains("application/json")) { + try { + return new ResponseEntity>(objectMapper.readValue("[ {\n \"supplementaryServiceProviderDetails\" : [ {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n } ],\n \"companyName\" : \"companyName\",\n \"serviceProvider\" : \"serviceProvider\",\n \"serviceProviderSubType\" : \"serviceProviderSubType\",\n \"serviceProviderType\" : \"serviceProviderType\"\n}, {\n \"supplementaryServiceProviderDetails\" : [ {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n } ],\n \"companyName\" : \"companyName\",\n \"serviceProvider\" : \"serviceProvider\",\n \"serviceProviderSubType\" : \"serviceProviderSubType\",\n \"serviceProviderType\" : \"serviceProviderType\"\n} ]", List.class), HttpStatus.OK); + } catch (IOException e) { + log.error("Couldn't serialize response for content type application/json", e); + return new ResponseEntity>(HttpStatus.INTERNAL_SERVER_ERROR); + } + } + + return new ResponseEntity>(HttpStatus.OK); + } + + public ResponseEntity billCompaniesServiceProviderGET(@Size(min=1,max=256) @Parameter(in = ParameterIn.PATH, description = "The identifier for the Bill Payment Service Provider.", required=true, schema=@Schema()) @PathVariable("serviceProvider") String serviceProvider, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." ,schema=@Schema()) @RequestHeader(value="X-Date", required=false) OffsetDateTime xDate, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's API key to the server." ,schema=@Schema()) @RequestHeader(value="X-API-Key", required=false) String xAPIKey, @Parameter(in = ParameterIn.HEADER, description = "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication." ,schema=@Schema()) @RequestHeader(value="X-User-Bearer", required=false) String xUserBearer, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's identifier to the server." ,schema=@Schema()) @RequestHeader(value="X-Client-Id", required=false) String xClientId, @Parameter(in = ParameterIn.HEADER, description = "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." ,schema=@Schema()) @RequestHeader(value="X-Content-Hash", required=false) String xContentHash, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-1", required=false) String xUserCredential1, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-2", required=false) String xUserCredential2, @Parameter(in = ParameterIn.HEADER, description = "String containing the channel that was used to originate the request. For example USSD, Web, App." ,schema=@Schema()) @RequestHeader(value="X-Channel", required=false) String xChannel, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." ,schema=@Schema(allowableValues={ "lei", "swiftbic", "organisationid" } +)) @RequestHeader(value="X-Account-Holding-Institution-Identifier-Type", required=false) String xAccountHoldingInstitutionIdentifierType, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." ,schema=@Schema()) @RequestHeader(value="X-Account-Holding-Institution-Identifier", required=false) String xAccountHoldingInstitutionIdentifier) { + String accept = request.getHeader("Accept"); + if (accept != null && accept.contains("application/json")) { + try { + return new ResponseEntity(objectMapper.readValue("{\n \"supplementaryServiceProviderDetails\" : [ {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n } ],\n \"companyName\" : \"companyName\",\n \"serviceProvider\" : \"serviceProvider\",\n \"serviceProviderSubType\" : \"serviceProviderSubType\",\n \"serviceProviderType\" : \"serviceProviderType\"\n}", ResponseBillCompanies.class), HttpStatus.OK); + } catch (IOException e) { + log.error("Couldn't serialize response for content type application/json", e); + return new ResponseEntity(HttpStatus.INTERNAL_SERVER_ERROR); + } + } + + return new ResponseEntity(HttpStatus.OK); + } + +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/api/BillsApi.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/api/BillsApi.java new file mode 100644 index 000000000..8f1b9e309 --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/api/BillsApi.java @@ -0,0 +1,74 @@ +/** + * NOTE: This class is auto generated by the swagger code generator program (3.0.34). + * https://github.com/swagger-api/swagger-codegen + * Do not edit the class manually. + */ +package org.mifos.connector.gsmastub.api; + +import org.mifos.connector.gsmastub.model.ErrorObject; +import org.mifos.connector.gsmastub.model.RequestBillPayment; +import org.mifos.connector.gsmastub.model.RequestStateObject; +import org.mifos.connector.gsmastub.model.ResponseBillPayment; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.enums.ParameterIn; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import org.springframework.http.ResponseEntity; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; +import org.threeten.bp.OffsetDateTime; + +import javax.validation.Valid; +import javax.validation.constraints.Size; + +@javax.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.SpringCodegen", date = "2022-09-27T11:46:46.417Z[GMT]") +@Validated +public interface BillsApi extends BaseGsmaApi { + + @Operation(summary = "View Payments for a Bill", description = "This endpoint allows for bill payments for a given bill reference to be returned", tags={ "Bills" }) + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Represents a list of Bill Payments", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ResponseBillPayment.class))), + + @ApiResponse(responseCode = "400", description = "Represents an Error Caused by the Violation of a Business Rule", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "401", description = "Represents an Error Caused by an Authorisation Failure", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "404", description = "Represents an Error Caused by a Failure to Identify the Target Resource", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "500", description = "Represents an Error Caused by a General Server-Side Issue", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "503", description = "Represents an Error Caused by System Unavailability", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))) }) + @RequestMapping(value = "/bills/{billReference}/payments", + produces = { "application/json" }, + method = RequestMethod.GET) + ResponseEntity abillsBillReferencePaymentsGET(@Size(min=1,max=256) @Parameter(in = ParameterIn.PATH, description = "Path variable to uniquely identify a bill.", required=true, schema=@Schema()) @PathVariable("billReference") String billReference, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." ,schema=@Schema()) @RequestHeader(value="X-Date", required=false) OffsetDateTime xDate, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's API key to the server." ,schema=@Schema()) @RequestHeader(value="X-API-Key", required=false) String xAPIKey, @Parameter(in = ParameterIn.HEADER, description = "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication." ,schema=@Schema()) @RequestHeader(value="X-User-Bearer", required=false) String xUserBearer, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's identifier to the server." ,schema=@Schema()) @RequestHeader(value="X-Client-Id", required=false) String xClientId, @Parameter(in = ParameterIn.HEADER, description = "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." ,schema=@Schema()) @RequestHeader(value="X-Content-Hash", required=false) String xContentHash, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-1", required=false) String xUserCredential1, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-2", required=false) String xUserCredential2, @Parameter(in = ParameterIn.HEADER, description = "String containing the channel that was used to originate the request. For example USSD, Web, App." ,schema=@Schema()) @RequestHeader(value="X-Channel", required=false) String xChannel, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." ,schema=@Schema(allowableValues={ "lei", "swiftbic", "organisationid" } +)) @RequestHeader(value="X-Account-Holding-Institution-Identifier-Type", required=false) String xAccountHoldingInstitutionIdentifierType, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." ,schema=@Schema()) @RequestHeader(value="X-Account-Holding-Institution-Identifier", required=false) String xAccountHoldingInstitutionIdentifier, @Parameter(in = ParameterIn.QUERY, description = "Supports pagination. If this is not supplied, then the server will apply a limit of 50 records returned for each request." ,schema=@Schema()) @Valid @RequestParam(value = "limit", required = false) Integer limit, @Parameter(in = ParameterIn.QUERY, description = "Supports pagination. This value will indicate the cursor position from where to retrieve the set of records. For example, a limit of 50 and offset of 10 will return records 11 to 60." ,schema=@Schema()) @Valid @RequestParam(value = "offset", required = false) Integer offset, @Parameter(in = ParameterIn.QUERY, description = "Indicates the minimum creation date for which records should be returned." ,schema=@Schema()) @Valid @RequestParam(value = "fromDateTime", required = false) OffsetDateTime fromDateTime, @Parameter(in = ParameterIn.QUERY, description = "Indicates the maximum creation date for which records should be returned." ,schema=@Schema()) @Valid @RequestParam(value = "toDateTime", required = false) OffsetDateTime toDateTime); + + + @Operation(summary = "Create A Bill Payment", description = "Provided with a valid object representation, this endpoint allows for a new bill payment to be created.", tags={ "Bills" }) + @ApiResponses(value = { + @ApiResponse(responseCode = "201", description = "Represents a Bill Payment response", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ResponseBillPayment.class))), + + @ApiResponse(responseCode = "202", description = "Represents an Asynchronous response", content = @Content(mediaType = "application/json", schema = @Schema(implementation = RequestStateObject.class))), + + @ApiResponse(responseCode = "400", description = "Represents an Error Caused by the Violation of a Business Rule", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "401", description = "Represents an Error Caused by an Authorisation Failure", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "404", description = "Represents an Error Caused by a Failure to Identify the Target Resource", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "500", description = "Represents an Error Caused by a General Server-Side Issue", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "503", description = "Represents an Error Caused by System Unavailability", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))) }) + @RequestMapping(value = "/bills/{billReference}/payments", + produces = { "application/json" }, + consumes = { "application/json" }, + method = RequestMethod.POST) + ResponseEntity billsBillReferencePaymentsPOST(@Size(min=1,max=256) @Parameter(in = ParameterIn.PATH, description = "Path variable to uniquely identify a bill.", required=true, schema=@Schema()) @PathVariable("billReference") String billReference, @Parameter(in = ParameterIn.DEFAULT, description = "Represents the request body of a bill payment.", required=true, schema=@Schema()) @Valid @RequestBody RequestBillPayment body, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." ,schema=@Schema()) @RequestHeader(value="X-Date", required=false) OffsetDateTime xDate, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to uniquely identify the request. Must be supplied as a UUID." ,schema=@Schema()) @RequestHeader(value="X-CorrelationID", required=false) String xCorrelationID, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's API key to the server." ,schema=@Schema()) @RequestHeader(value="X-API-Key", required=false) String xAPIKey, @Parameter(in = ParameterIn.HEADER, description = "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication." ,schema=@Schema()) @RequestHeader(value="X-User-Bearer", required=false) String xUserBearer, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's identifier to the server." ,schema=@Schema()) @RequestHeader(value="X-Client-Id", required=false) String xClientId, @Parameter(in = ParameterIn.HEADER, description = "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." ,schema=@Schema()) @RequestHeader(value="X-Content-Hash", required=false) String xContentHash, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-1", required=false) String xUserCredential1, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-2", required=false) String xUserCredential2, @Parameter(in = ParameterIn.HEADER, description = "String containing the channel that was used to originate the request. For example USSD, Web, App." ,schema=@Schema()) @RequestHeader(value="X-Channel", required=false) String xChannel, @Parameter(in = ParameterIn.HEADER, description = "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." ,schema=@Schema()) @RequestHeader(value="X-Callback-URL", required=false) String xCallbackURL, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." ,schema=@Schema(allowableValues={ "lei", "swiftbic", "organisationid" } +)) @RequestHeader(value="X-Account-Holding-Institution-Identifier-Type", required=false) String xAccountHoldingInstitutionIdentifierType, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." ,schema=@Schema()) @RequestHeader(value="X-Account-Holding-Institution-Identifier", required=false) String xAccountHoldingInstitutionIdentifier); + +} + diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/api/BillsApiController.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/api/BillsApiController.java new file mode 100644 index 000000000..57002b0c0 --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/api/BillsApiController.java @@ -0,0 +1,69 @@ +package org.mifos.connector.gsmastub.api; + +import com.fasterxml.jackson.databind.ObjectMapper; +import io.swagger.v3.oas.annotations.Hidden; +import io.swagger.v3.oas.annotations.Parameter; +import org.mifos.connector.gsmastub.model.RequestBillPayment; +import org.mifos.connector.gsmastub.model.ResponseBillPayment; +import io.swagger.v3.oas.annotations.enums.ParameterIn; +import io.swagger.v3.oas.annotations.media.Schema; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; +import org.threeten.bp.OffsetDateTime; + +import javax.servlet.http.HttpServletRequest; +import javax.validation.Valid; +import javax.validation.constraints.Size; +import java.io.IOException; + +@javax.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.SpringCodegen", date = "2022-09-27T11:46:46.417Z[GMT]") +@RestController +@Hidden +public class BillsApiController implements BillsApi { + + private static final Logger log = LoggerFactory.getLogger(BillsApiController.class); + + private final ObjectMapper objectMapper; + + private final HttpServletRequest request; + + @org.springframework.beans.factory.annotation.Autowired + public BillsApiController(ObjectMapper objectMapper, HttpServletRequest request) { + this.objectMapper = objectMapper; + this.request = request; + } + + public ResponseEntity abillsBillReferencePaymentsGET(@Size(min=1,max=256) @Parameter(in = ParameterIn.PATH, description = "Path variable to uniquely identify a bill.", required=true, schema=@Schema()) @PathVariable("billReference") String billReference, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." ,schema=@Schema()) @RequestHeader(value="X-Date", required=false) OffsetDateTime xDate, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's API key to the server." ,schema=@Schema()) @RequestHeader(value="X-API-Key", required=false) String xAPIKey, @Parameter(in = ParameterIn.HEADER, description = "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication." ,schema=@Schema()) @RequestHeader(value="X-User-Bearer", required=false) String xUserBearer, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's identifier to the server." ,schema=@Schema()) @RequestHeader(value="X-Client-Id", required=false) String xClientId, @Parameter(in = ParameterIn.HEADER, description = "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." ,schema=@Schema()) @RequestHeader(value="X-Content-Hash", required=false) String xContentHash, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-1", required=false) String xUserCredential1, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-2", required=false) String xUserCredential2, @Parameter(in = ParameterIn.HEADER, description = "String containing the channel that was used to originate the request. For example USSD, Web, App." ,schema=@Schema()) @RequestHeader(value="X-Channel", required=false) String xChannel, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." ,schema=@Schema(allowableValues={ "lei", "swiftbic", "organisationid" } +)) @RequestHeader(value="X-Account-Holding-Institution-Identifier-Type", required=false) String xAccountHoldingInstitutionIdentifierType, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." ,schema=@Schema()) @RequestHeader(value="X-Account-Holding-Institution-Identifier", required=false) String xAccountHoldingInstitutionIdentifier, @Parameter(in = ParameterIn.QUERY, description = "Supports pagination. If this is not supplied, then the server will apply a limit of 50 records returned for each request." ,schema=@Schema()) @Valid @RequestParam(value = "limit", required = false) Integer limit, @Parameter(in = ParameterIn.QUERY, description = "Supports pagination. This value will indicate the cursor position from where to retrieve the set of records. For example, a limit of 50 and offset of 10 will return records 11 to 60." ,schema=@Schema()) @Valid @RequestParam(value = "offset", required = false) Integer offset, @Parameter(in = ParameterIn.QUERY, description = "Indicates the minimum creation date for which records should be returned." ,schema=@Schema()) @Valid @RequestParam(value = "fromDateTime", required = false) OffsetDateTime fromDateTime, @Parameter(in = ParameterIn.QUERY, description = "Indicates the maximum creation date for which records should be returned." ,schema=@Schema()) @Valid @RequestParam(value = "toDateTime", required = false) OffsetDateTime toDateTime) { + String accept = request.getHeader("Accept"); + if (accept != null && accept.contains("application/json")) { + try { + return new ResponseEntity(objectMapper.readValue("{\n \"supplementaryBillReferenceDetails\" : [ {\n \"paymentReferenceType\" : \"paymentReferenceType\",\n \"paymentReferenceValue\" : \"paymentReferenceValue\"\n }, {\n \"paymentReferenceType\" : \"paymentReferenceType\",\n \"paymentReferenceValue\" : \"paymentReferenceValue\"\n }, {\n \"paymentReferenceType\" : \"paymentReferenceType\",\n \"paymentReferenceValue\" : \"paymentReferenceValue\"\n }, {\n \"paymentReferenceType\" : \"paymentReferenceType\",\n \"paymentReferenceValue\" : \"paymentReferenceValue\"\n }, {\n \"paymentReferenceType\" : \"paymentReferenceType\",\n \"paymentReferenceValue\" : \"paymentReferenceValue\"\n }, {\n \"paymentReferenceType\" : \"paymentReferenceType\",\n \"paymentReferenceValue\" : \"paymentReferenceValue\"\n }, {\n \"paymentReferenceType\" : \"paymentReferenceType\",\n \"paymentReferenceValue\" : \"paymentReferenceValue\"\n }, {\n \"paymentReferenceType\" : \"paymentReferenceType\",\n \"paymentReferenceValue\" : \"paymentReferenceValue\"\n }, {\n \"paymentReferenceType\" : \"paymentReferenceType\",\n \"paymentReferenceValue\" : \"paymentReferenceValue\"\n }, {\n \"paymentReferenceType\" : \"paymentReferenceType\",\n \"paymentReferenceValue\" : \"paymentReferenceValue\"\n } ],\n \"serviceProviderNotification\" : \"serviceProviderNotification\",\n \"metadata\" : [ {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n } ],\n \"requestingOrganisation\" : \"requestingOrganisation\",\n \"customData\" : [ {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n } ],\n \"creationDate\" : \"2000-01-23T04:56:07.000+00:00\",\n \"paymentType\" : \"partialpayment\",\n \"modificationDate\" : \"2000-01-23T04:56:07.000+00:00\",\n \"billPaymentStatus\" : \"billPaymentStatus\",\n \"amountPaid\" : \"15.21\",\n \"customerReference\" : \"customerReference\",\n \"requestDate\" : \"2000-01-23T04:56:07.000+00:00\",\n \"requestingOrganisationTransactionReference\" : \"requestingOrganisationTransactionReference\",\n \"currency\" : \"AED\",\n \"serviceProviderPaymentReference\" : \"serviceProviderPaymentReference\",\n \"serviceProviderComment\" : \"serviceProviderComment\"\n}", ResponseBillPayment.class), HttpStatus.OK); + } catch (IOException e) { + log.error("Couldn't serialize response for content type application/json", e); + return new ResponseEntity(HttpStatus.INTERNAL_SERVER_ERROR); + } + } + + return new ResponseEntity(HttpStatus.OK); + } + + public ResponseEntity billsBillReferencePaymentsPOST(@Size(min=1,max=256) @Parameter(in = ParameterIn.PATH, description = "Path variable to uniquely identify a bill.", required=true, schema=@Schema()) @PathVariable("billReference") String billReference,@Parameter(in = ParameterIn.DEFAULT, description = "Represents the request body of a bill payment.", required=true, schema=@Schema()) @Valid @RequestBody RequestBillPayment body,@Parameter(in = ParameterIn.HEADER, description = "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." ,schema=@Schema()) @RequestHeader(value="X-Date", required=false) OffsetDateTime xDate,@Parameter(in = ParameterIn.HEADER, description = "Header parameter to uniquely identify the request. Must be supplied as a UUID." ,schema=@Schema()) @RequestHeader(value="X-CorrelationID", required=false) String xCorrelationID,@Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's API key to the server." ,schema=@Schema()) @RequestHeader(value="X-API-Key", required=false) String xAPIKey,@Parameter(in = ParameterIn.HEADER, description = "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication." ,schema=@Schema()) @RequestHeader(value="X-User-Bearer", required=false) String xUserBearer,@Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's identifier to the server." ,schema=@Schema()) @RequestHeader(value="X-Client-Id", required=false) String xClientId,@Parameter(in = ParameterIn.HEADER, description = "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." ,schema=@Schema()) @RequestHeader(value="X-Content-Hash", required=false) String xContentHash,@Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-1", required=false) String xUserCredential1,@Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-2", required=false) String xUserCredential2,@Parameter(in = ParameterIn.HEADER, description = "String containing the channel that was used to originate the request. For example USSD, Web, App." ,schema=@Schema()) @RequestHeader(value="X-Channel", required=false) String xChannel,@Parameter(in = ParameterIn.HEADER, description = "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." ,schema=@Schema()) @RequestHeader(value="X-Callback-URL", required=false) String xCallbackURL,@Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." ,schema=@Schema(allowableValues={ "lei", "swiftbic", "organisationid" } +)) @RequestHeader(value="X-Account-Holding-Institution-Identifier-Type", required=false) String xAccountHoldingInstitutionIdentifierType,@Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." ,schema=@Schema()) @RequestHeader(value="X-Account-Holding-Institution-Identifier", required=false) String xAccountHoldingInstitutionIdentifier) { + String accept = request.getHeader("Accept"); + if (accept != null && accept.contains("application/json")) { + try { + return new ResponseEntity(objectMapper.readValue("{\n \"supplementaryBillReferenceDetails\" : [ {\n \"paymentReferenceType\" : \"paymentReferenceType\",\n \"paymentReferenceValue\" : \"paymentReferenceValue\"\n }, {\n \"paymentReferenceType\" : \"paymentReferenceType\",\n \"paymentReferenceValue\" : \"paymentReferenceValue\"\n }, {\n \"paymentReferenceType\" : \"paymentReferenceType\",\n \"paymentReferenceValue\" : \"paymentReferenceValue\"\n }, {\n \"paymentReferenceType\" : \"paymentReferenceType\",\n \"paymentReferenceValue\" : \"paymentReferenceValue\"\n }, {\n \"paymentReferenceType\" : \"paymentReferenceType\",\n \"paymentReferenceValue\" : \"paymentReferenceValue\"\n }, {\n \"paymentReferenceType\" : \"paymentReferenceType\",\n \"paymentReferenceValue\" : \"paymentReferenceValue\"\n }, {\n \"paymentReferenceType\" : \"paymentReferenceType\",\n \"paymentReferenceValue\" : \"paymentReferenceValue\"\n }, {\n \"paymentReferenceType\" : \"paymentReferenceType\",\n \"paymentReferenceValue\" : \"paymentReferenceValue\"\n }, {\n \"paymentReferenceType\" : \"paymentReferenceType\",\n \"paymentReferenceValue\" : \"paymentReferenceValue\"\n }, {\n \"paymentReferenceType\" : \"paymentReferenceType\",\n \"paymentReferenceValue\" : \"paymentReferenceValue\"\n } ],\n \"serviceProviderNotification\" : \"serviceProviderNotification\",\n \"metadata\" : [ {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n } ],\n \"requestingOrganisation\" : \"requestingOrganisation\",\n \"customData\" : [ {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n } ],\n \"creationDate\" : \"2000-01-23T04:56:07.000+00:00\",\n \"paymentType\" : \"partialpayment\",\n \"modificationDate\" : \"2000-01-23T04:56:07.000+00:00\",\n \"billPaymentStatus\" : \"billPaymentStatus\",\n \"amountPaid\" : \"15.21\",\n \"customerReference\" : \"customerReference\",\n \"requestDate\" : \"2000-01-23T04:56:07.000+00:00\",\n \"requestingOrganisationTransactionReference\" : \"requestingOrganisationTransactionReference\",\n \"currency\" : \"AED\",\n \"serviceProviderPaymentReference\" : \"serviceProviderPaymentReference\",\n \"serviceProviderComment\" : \"serviceProviderComment\"\n}", ResponseBillPayment.class), HttpStatus.OK); + } catch (IOException e) { + log.error("Couldn't serialize response for content type application/json", e); + return new ResponseEntity(HttpStatus.INTERNAL_SERVER_ERROR); + } + } + + return new ResponseEntity(HttpStatus.OK); + } + +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/api/HeartbeatApi.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/api/HeartbeatApi.java new file mode 100644 index 000000000..bee8c0e58 --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/api/HeartbeatApi.java @@ -0,0 +1,47 @@ +/** + * NOTE: This class is auto generated by the swagger code generator program (3.0.34). + * https://github.com/swagger-api/swagger-codegen + * Do not edit the class manually. + */ +package org.mifos.connector.gsmastub.api; + +import org.mifos.connector.gsmastub.model.ErrorObject; +import org.mifos.connector.gsmastub.model.ResponseHeartbeat; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.enums.ParameterIn; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import org.springframework.http.ResponseEntity; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.RequestHeader; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.threeten.bp.OffsetDateTime; + +@javax.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.SpringCodegen", date = "2022-09-27T11:46:46.417Z[GMT]") +@Validated +public interface HeartbeatApi extends BaseGsmaApi { + + @Operation(summary = "Check API availability", description = "This endpoint returns the current status of the API", tags={ "Supporting" }) + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Represents a Heartbeat response", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ResponseHeartbeat.class))), + + @ApiResponse(responseCode = "400", description = "Represents an Error Caused by the Violation of a Business Rule", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "401", description = "Represents an Error Caused by an Authorisation Failure", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "404", description = "Represents an Error Caused by a Failure to Identify the Target Resource", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "500", description = "Represents an Error Caused by a General Server-Side Issue", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "503", description = "Represents an Error Caused by System Unavailability", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))) }) + @RequestMapping(value = "/heartbeat", + produces = { "application/json" }, + method = RequestMethod.GET) + ResponseEntity heartbeatGET(@Parameter(in = ParameterIn.HEADER, description = "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." ,schema=@Schema()) @RequestHeader(value="X-Date", required=false) OffsetDateTime xDate, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's API key to the server." ,schema=@Schema()) @RequestHeader(value="X-API-Key", required=false) String xAPIKey, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's identifier to the server." ,schema=@Schema()) @RequestHeader(value="X-Client-Id", required=false) String xClientId); + +} + diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/api/HeartbeatApiController.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/api/HeartbeatApiController.java new file mode 100644 index 000000000..ec23bb3b9 --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/api/HeartbeatApiController.java @@ -0,0 +1,55 @@ +package org.mifos.connector.gsmastub.api; + +import com.fasterxml.jackson.databind.ObjectMapper; +import io.swagger.v3.oas.annotations.Hidden; +import io.swagger.v3.oas.annotations.Parameter; +import org.mifos.connector.gsmastub.model.ResponseHeartbeat; +import io.swagger.v3.oas.annotations.enums.ParameterIn; +import io.swagger.v3.oas.annotations.media.Schema; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.RequestHeader; +import org.springframework.web.bind.annotation.RestController; +import org.threeten.bp.OffsetDateTime; + +import javax.servlet.http.HttpServletRequest; +import java.io.IOException; + +@javax.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.SpringCodegen", date = "2022-09-27T11:46:46.417Z[GMT]") +@RestController +@Hidden +public class HeartbeatApiController implements HeartbeatApi { + + private static final Logger log = LoggerFactory.getLogger(HeartbeatApiController.class); + + private final ObjectMapper objectMapper; + + private final HttpServletRequest request; + + @org.springframework.beans.factory.annotation.Autowired + public HeartbeatApiController(ObjectMapper objectMapper, HttpServletRequest request) { + this.objectMapper = objectMapper; + this.request = request; + } + + public ResponseEntity heartbeatGET(@Parameter(in = ParameterIn.HEADER, description = "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." ,schema=@Schema()) @RequestHeader(value="X-Date", required=false) OffsetDateTime xDate, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's API key to the server." ,schema=@Schema()) @RequestHeader(value="X-API-Key", required=false) String xAPIKey, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's identifier to the server." ,schema=@Schema()) @RequestHeader(value="X-Client-Id", required=false) String xClientId) { + String accept = request.getHeader("Accept"); + if (accept != null && accept.contains("application/json")) { + try { + return new ResponseEntity( + objectMapper.readValue( + "{\n \"plannedRestorationTime\" : \"2000-01-23T04:56:07.000+00:00\",\n " + + " \"delay\" : 0.8008281904610115,\n \"serviceStatus\" : \"available\"\n}", ResponseHeartbeat.class), + HttpStatus.OK); + } catch (IOException e) { + log.error("Couldn't serialize response for content type application/json", e); + return new ResponseEntity(HttpStatus.INTERNAL_SERVER_ERROR); + } + } + + return new ResponseEntity(HttpStatus.OK); + } + +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/api/NotFoundException.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/api/NotFoundException.java new file mode 100644 index 000000000..6a3ff24fa --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/api/NotFoundException.java @@ -0,0 +1,10 @@ +package org.mifos.connector.gsmastub.api; + +@javax.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.SpringCodegen", date = "2022-09-27T11:46:46.417Z[GMT]") +public class NotFoundException extends ApiException { + private int code; + public NotFoundException (int code, String msg) { + super(code, msg); + this.code = code; + } +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/api/QuotationsApi.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/api/QuotationsApi.java new file mode 100644 index 000000000..8f76d2fc0 --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/api/QuotationsApi.java @@ -0,0 +1,74 @@ +/** + * NOTE: This class is auto generated by the swagger code generator program (3.0.34). + * https://github.com/swagger-api/swagger-codegen + * Do not edit the class manually. + */ +package org.mifos.connector.gsmastub.api; + +import org.mifos.connector.gsmastub.model.ErrorObject; +import org.mifos.connector.gsmastub.model.RequestQuotation; +import org.mifos.connector.gsmastub.model.RequestStateObject; +import org.mifos.connector.gsmastub.model.ResponseQuotation; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.enums.ParameterIn; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import org.springframework.http.ResponseEntity; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; +import org.threeten.bp.OffsetDateTime; + +import javax.validation.Valid; +import javax.validation.constraints.Size; + +@javax.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.SpringCodegen", date = "2022-09-27T11:46:46.417Z[GMT]") +@Validated +public interface QuotationsApi extends BaseGsmaApi { + + @Operation(summary = "Create A New Quotation", description = "Provided with a valid object representation, this endpoint allows for a new quotation to be created.", tags={ "Quotations" }) + @ApiResponses(value = { + @ApiResponse(responseCode = "201", description = "Represents a Quotation response", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ResponseQuotation.class))), + + @ApiResponse(responseCode = "202", description = "Represents an Asynchronous response", content = @Content(mediaType = "application/json", schema = @Schema(implementation = RequestStateObject.class))), + + @ApiResponse(responseCode = "400", description = "Represents an Error Caused by the Violation of a Business Rule", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "401", description = "Represents an Error Caused by an Authorisation Failure", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "404", description = "Represents an Error Caused by a Failure to Identify the Target Resource", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "500", description = "Represents an Error Caused by a General Server-Side Issue", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "503", description = "Represents an Error Caused by System Unavailability", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))) }) + @RequestMapping(value = "/quotations", + produces = { "application/json" }, + consumes = { "application/json" }, + method = RequestMethod.POST) + ResponseEntity quotationsPOST(@Parameter(in = ParameterIn.DEFAULT, description = "Represents the request body of a Quotation.", required=true, schema=@Schema()) @Valid @RequestBody RequestQuotation body, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." ,schema=@Schema()) @RequestHeader(value="X-Date", required=false) OffsetDateTime xDate, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to uniquely identify the request. Must be supplied as a UUID." ,schema=@Schema()) @RequestHeader(value="X-CorrelationID", required=false) String xCorrelationID, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's API key to the server." ,schema=@Schema()) @RequestHeader(value="X-API-Key", required=false) String xAPIKey, @Parameter(in = ParameterIn.HEADER, description = "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication." ,schema=@Schema()) @RequestHeader(value="X-User-Bearer", required=false) String xUserBearer, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's identifier to the server." ,schema=@Schema()) @RequestHeader(value="X-Client-Id", required=false) String xClientId, @Parameter(in = ParameterIn.HEADER, description = "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." ,schema=@Schema()) @RequestHeader(value="X-Content-Hash", required=false) String xContentHash, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-1", required=false) String xUserCredential1, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-2", required=false) String xUserCredential2, @Parameter(in = ParameterIn.HEADER, description = "String containing the channel that was used to originate the request. For example USSD, Web, App." ,schema=@Schema()) @RequestHeader(value="X-Channel", required=false) String xChannel, @Parameter(in = ParameterIn.HEADER, description = "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." ,schema=@Schema()) @RequestHeader(value="X-Callback-URL", required=false) String xCallbackURL, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." ,schema=@Schema(allowableValues={ "lei", "swiftbic", "organisationid" } +)) @RequestHeader(value="X-Account-Holding-Institution-Identifier-Type", required=false) String xAccountHoldingInstitutionIdentifierType, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." ,schema=@Schema()) @RequestHeader(value="X-Account-Holding-Institution-Identifier", required=false) String xAccountHoldingInstitutionIdentifier); + + + @Operation(summary = "View A Quotation", description = "This endpoint returns a specific quotation", tags={ "Quotations" }) + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Represents a Quotation response", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ResponseQuotation.class))), + + @ApiResponse(responseCode = "400", description = "Represents an Error Caused by the Violation of a Business Rule", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "401", description = "Represents an Error Caused by an Authorisation Failure", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "404", description = "Represents an Error Caused by a Failure to Identify the Target Resource", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "500", description = "Represents an Error Caused by a General Server-Side Issue", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "503", description = "Represents an Error Caused by System Unavailability", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))) }) + @RequestMapping(value = "/quotations/{quotationReference}", + produces = { "application/json" }, + method = RequestMethod.GET) + ResponseEntity quotationsQuotationReferenceGET(@Size(min=1,max=256) @Parameter(in = ParameterIn.PATH, description = "Path variable to uniquely identify the quotation.", required=true, schema=@Schema()) @PathVariable("quotationReference") String quotationReference, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." ,schema=@Schema()) @RequestHeader(value="X-Date", required=false) OffsetDateTime xDate, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's API key to the server." ,schema=@Schema()) @RequestHeader(value="X-API-Key", required=false) String xAPIKey, @Parameter(in = ParameterIn.HEADER, description = "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication." ,schema=@Schema()) @RequestHeader(value="X-User-Bearer", required=false) String xUserBearer, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's identifier to the server." ,schema=@Schema()) @RequestHeader(value="X-Client-Id", required=false) String xClientId, @Parameter(in = ParameterIn.HEADER, description = "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." ,schema=@Schema()) @RequestHeader(value="X-Content-Hash", required=false) String xContentHash, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-1", required=false) String xUserCredential1, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-2", required=false) String xUserCredential2, @Parameter(in = ParameterIn.HEADER, description = "String containing the channel that was used to originate the request. For example USSD, Web, App." ,schema=@Schema()) @RequestHeader(value="X-Channel", required=false) String xChannel, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." ,schema=@Schema(allowableValues={ "lei", "swiftbic", "organisationid" } +)) @RequestHeader(value="X-Account-Holding-Institution-Identifier-Type", required=false) String xAccountHoldingInstitutionIdentifierType, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." ,schema=@Schema()) @RequestHeader(value="X-Account-Holding-Institution-Identifier", required=false) String xAccountHoldingInstitutionIdentifier); + +} + diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/api/QuotationsApiController.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/api/QuotationsApiController.java new file mode 100644 index 000000000..b20286349 --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/api/QuotationsApiController.java @@ -0,0 +1,72 @@ +package org.mifos.connector.gsmastub.api; + +import com.fasterxml.jackson.databind.ObjectMapper; +import io.swagger.v3.oas.annotations.Hidden; +import io.swagger.v3.oas.annotations.Parameter; +import org.mifos.connector.gsmastub.model.RequestQuotation; +import org.mifos.connector.gsmastub.model.ResponseQuotation; +import io.swagger.v3.oas.annotations.enums.ParameterIn; +import io.swagger.v3.oas.annotations.media.Schema; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestHeader; +import org.springframework.web.bind.annotation.RestController; +import org.threeten.bp.OffsetDateTime; + +import javax.servlet.http.HttpServletRequest; +import javax.validation.Valid; +import javax.validation.constraints.Size; +import java.io.IOException; + +@javax.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.SpringCodegen", date = "2022-09-27T11:46:46.417Z[GMT]") +@RestController +@Hidden +public class QuotationsApiController implements QuotationsApi { + + private static final Logger log = LoggerFactory.getLogger(QuotationsApiController.class); + + private final ObjectMapper objectMapper; + + private final HttpServletRequest request; + + @org.springframework.beans.factory.annotation.Autowired + public QuotationsApiController(ObjectMapper objectMapper, HttpServletRequest request) { + this.objectMapper = objectMapper; + this.request = request; + } + + public ResponseEntity quotationsPOST(@Parameter(in = ParameterIn.DEFAULT, description = "Represents the request body of a Quotation.", required=true, schema=@Schema()) @Valid @RequestBody RequestQuotation body, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." ,schema=@Schema()) @RequestHeader(value="X-Date", required=false) OffsetDateTime xDate, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to uniquely identify the request. Must be supplied as a UUID." ,schema=@Schema()) @RequestHeader(value="X-CorrelationID", required=false) String xCorrelationID, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's API key to the server." ,schema=@Schema()) @RequestHeader(value="X-API-Key", required=false) String xAPIKey, @Parameter(in = ParameterIn.HEADER, description = "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication." ,schema=@Schema()) @RequestHeader(value="X-User-Bearer", required=false) String xUserBearer, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's identifier to the server." ,schema=@Schema()) @RequestHeader(value="X-Client-Id", required=false) String xClientId, @Parameter(in = ParameterIn.HEADER, description = "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." ,schema=@Schema()) @RequestHeader(value="X-Content-Hash", required=false) String xContentHash, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-1", required=false) String xUserCredential1, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-2", required=false) String xUserCredential2, @Parameter(in = ParameterIn.HEADER, description = "String containing the channel that was used to originate the request. For example USSD, Web, App." ,schema=@Schema()) @RequestHeader(value="X-Channel", required=false) String xChannel, @Parameter(in = ParameterIn.HEADER, description = "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." ,schema=@Schema()) @RequestHeader(value="X-Callback-URL", required=false) String xCallbackURL, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." ,schema=@Schema(allowableValues={ "lei", "swiftbic", "organisationid" } +)) @RequestHeader(value="X-Account-Holding-Institution-Identifier-Type", required=false) String xAccountHoldingInstitutionIdentifierType, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." ,schema=@Schema()) @RequestHeader(value="X-Account-Holding-Institution-Identifier", required=false) String xAccountHoldingInstitutionIdentifier) { + String accept = request.getHeader("Accept"); + if (accept != null && accept.contains("application/json")) { + try { + return new ResponseEntity(objectMapper.readValue("{\n \"recipientKyc\" : {\n \"emailAddress\" : \"emailAddress\",\n \"occupation\" : \"occupation\",\n \"postalAddress\" : {\n \"city\" : \"city\",\n \"postalCode\" : \"postalCode\",\n \"addressLine1\" : \"addressLine1\",\n \"stateProvince\" : \"stateProvince\",\n \"addressLine2\" : \"addressLine2\",\n \"addressLine3\" : \"addressLine3\"\n },\n \"gender\" : \"m\",\n \"idDocument\" : [ {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n } ],\n \"employerName\" : \"employerName\",\n \"dateOfBirth\" : \"2000-11-20T00:00:00.000+00:00\",\n \"contactPhone\" : \"contactPhone\",\n \"subjectName\" : {\n \"firstName\" : \"firstName\",\n \"lastName\" : \"lastName\",\n \"nativeName\" : \"nativeName\",\n \"fullName\" : \"fullName\",\n \"middleName\" : \"middleName\",\n \"title\" : \"title\"\n }\n },\n \"debitParty\" : [ null, null, null, null, null, null, null, null, null, null ],\n \"metadata\" : [ {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n } ],\n \"customData\" : [ {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n } ],\n \"type\" : \"billpay\",\n \"requestAmount\" : \"15.21\",\n \"quotes\" : [ {\n \"fees\" : [ {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n } ],\n \"fxRate\" : \"1.3436\",\n \"quoteExpiryTime\" : \"2000-01-23T04:56:07.000+00:00\",\n \"receivingServiceProvider\" : \"receivingServiceProvider\",\n \"quoteId\" : \"quoteId\"\n }, {\n \"fees\" : [ {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n } ],\n \"fxRate\" : \"1.3436\",\n \"quoteExpiryTime\" : \"2000-01-23T04:56:07.000+00:00\",\n \"receivingServiceProvider\" : \"receivingServiceProvider\",\n \"quoteId\" : \"quoteId\"\n }, {\n \"fees\" : [ {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n } ],\n \"fxRate\" : \"1.3436\",\n \"quoteExpiryTime\" : \"2000-01-23T04:56:07.000+00:00\",\n \"receivingServiceProvider\" : \"receivingServiceProvider\",\n \"quoteId\" : \"quoteId\"\n }, {\n \"fees\" : [ {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n } ],\n \"fxRate\" : \"1.3436\",\n \"quoteExpiryTime\" : \"2000-01-23T04:56:07.000+00:00\",\n \"receivingServiceProvider\" : \"receivingServiceProvider\",\n \"quoteId\" : \"quoteId\"\n }, {\n \"fees\" : [ {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n } ],\n \"fxRate\" : \"1.3436\",\n \"quoteExpiryTime\" : \"2000-01-23T04:56:07.000+00:00\",\n \"receivingServiceProvider\" : \"receivingServiceProvider\",\n \"quoteId\" : \"quoteId\"\n }, {\n \"fees\" : [ {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n } ],\n \"fxRate\" : \"1.3436\",\n \"quoteExpiryTime\" : \"2000-01-23T04:56:07.000+00:00\",\n \"receivingServiceProvider\" : \"receivingServiceProvider\",\n \"quoteId\" : \"quoteId\"\n }, {\n \"fees\" : [ {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n } ],\n \"fxRate\" : \"1.3436\",\n \"quoteExpiryTime\" : \"2000-01-23T04:56:07.000+00:00\",\n \"receivingServiceProvider\" : \"receivingServiceProvider\",\n \"quoteId\" : \"quoteId\"\n }, {\n \"fees\" : [ {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n } ],\n \"fxRate\" : \"1.3436\",\n \"quoteExpiryTime\" : \"2000-01-23T04:56:07.000+00:00\",\n \"receivingServiceProvider\" : \"receivingServiceProvider\",\n \"quoteId\" : \"quoteId\"\n }, {\n \"fees\" : [ {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n } ],\n \"fxRate\" : \"1.3436\",\n \"quoteExpiryTime\" : \"2000-01-23T04:56:07.000+00:00\",\n \"receivingServiceProvider\" : \"receivingServiceProvider\",\n \"quoteId\" : \"quoteId\"\n }, {\n \"fees\" : [ {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n } ],\n \"fxRate\" : \"1.3436\",\n \"quoteExpiryTime\" : \"2000-01-23T04:56:07.000+00:00\",\n \"receivingServiceProvider\" : \"receivingServiceProvider\",\n \"quoteId\" : \"quoteId\"\n } ],\n \"recipientBlockingReason\" : \"recipientBlockingReason\",\n \"dateCreated\" : \"2000-01-23T04:56:07.000+00:00\",\n \"quotationStatus\" : \"pending\",\n \"requestDate\" : \"2000-01-23T04:56:07.000+00:00\",\n \"availableDeliveryMethod\" : \"directtoaccount\",\n \"senderBlockingReason\" : \"senderBlockingReason\",\n \"requestCurrency\" : \"AED\",\n \"quotationReference\" : \"quotationReference\",\n \"requestingOrganisation\" : {\n \"requestingOrganisationIdentifierType\" : \"lei\",\n \"requestingOrganisationIdentifier\" : \"requestingOrganisationIdentifier\"\n },\n \"dateModified\" : \"2000-01-23T04:56:07.000+00:00\",\n \"creationDate\" : \"2000-01-23T04:56:07.000+00:00\",\n \"modificationDate\" : \"2000-01-23T04:56:07.000+00:00\",\n \"originCountry\" : \"AD\",\n \"subType\" : \"subType\",\n \"creditParty\" : [ {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n } ]\n}", ResponseQuotation.class), HttpStatus.OK); + } catch (IOException e) { + log.error("Couldn't serialize response for content type application/json", e); + return new ResponseEntity(HttpStatus.INTERNAL_SERVER_ERROR); + } + } + + return new ResponseEntity(HttpStatus.OK); + } + + public ResponseEntity quotationsQuotationReferenceGET(@Size(min=1,max=256) @Parameter(in = ParameterIn.PATH, description = "Path variable to uniquely identify the quotation.", required=true, schema=@Schema()) @PathVariable("quotationReference") String quotationReference,@Parameter(in = ParameterIn.HEADER, description = "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." ,schema=@Schema()) @RequestHeader(value="X-Date", required=false) OffsetDateTime xDate,@Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's API key to the server." ,schema=@Schema()) @RequestHeader(value="X-API-Key", required=false) String xAPIKey,@Parameter(in = ParameterIn.HEADER, description = "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication." ,schema=@Schema()) @RequestHeader(value="X-User-Bearer", required=false) String xUserBearer,@Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's identifier to the server." ,schema=@Schema()) @RequestHeader(value="X-Client-Id", required=false) String xClientId,@Parameter(in = ParameterIn.HEADER, description = "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." ,schema=@Schema()) @RequestHeader(value="X-Content-Hash", required=false) String xContentHash,@Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-1", required=false) String xUserCredential1,@Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-2", required=false) String xUserCredential2,@Parameter(in = ParameterIn.HEADER, description = "String containing the channel that was used to originate the request. For example USSD, Web, App." ,schema=@Schema()) @RequestHeader(value="X-Channel", required=false) String xChannel,@Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." ,schema=@Schema(allowableValues={ "lei", "swiftbic", "organisationid" } +)) @RequestHeader(value="X-Account-Holding-Institution-Identifier-Type", required=false) String xAccountHoldingInstitutionIdentifierType,@Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." ,schema=@Schema()) @RequestHeader(value="X-Account-Holding-Institution-Identifier", required=false) String xAccountHoldingInstitutionIdentifier) { + String accept = request.getHeader("Accept"); + if (accept != null && accept.contains("application/json")) { + try { + return new ResponseEntity(objectMapper.readValue("{\n \"recipientKyc\" : {\n \"emailAddress\" : \"emailAddress\",\n \"occupation\" : \"occupation\",\n \"postalAddress\" : {\n \"city\" : \"city\",\n \"postalCode\" : \"postalCode\",\n \"addressLine1\" : \"addressLine1\",\n \"stateProvince\" : \"stateProvince\",\n \"addressLine2\" : \"addressLine2\",\n \"addressLine3\" : \"addressLine3\"\n },\n \"gender\" : \"m\",\n \"idDocument\" : [ {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n } ],\n \"employerName\" : \"employerName\",\n \"dateOfBirth\" : \"2000-11-20T00:00:00.000+00:00\",\n \"contactPhone\" : \"contactPhone\",\n \"subjectName\" : {\n \"firstName\" : \"firstName\",\n \"lastName\" : \"lastName\",\n \"nativeName\" : \"nativeName\",\n \"fullName\" : \"fullName\",\n \"middleName\" : \"middleName\",\n \"title\" : \"title\"\n }\n },\n \"debitParty\" : [ null, null, null, null, null, null, null, null, null, null ],\n \"metadata\" : [ {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n } ],\n \"customData\" : [ {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n } ],\n \"type\" : \"billpay\",\n \"requestAmount\" : \"15.21\",\n \"quotes\" : [ {\n \"fees\" : [ {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n } ],\n \"fxRate\" : \"1.3436\",\n \"quoteExpiryTime\" : \"2000-01-23T04:56:07.000+00:00\",\n \"receivingServiceProvider\" : \"receivingServiceProvider\",\n \"quoteId\" : \"quoteId\"\n }, {\n \"fees\" : [ {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n } ],\n \"fxRate\" : \"1.3436\",\n \"quoteExpiryTime\" : \"2000-01-23T04:56:07.000+00:00\",\n \"receivingServiceProvider\" : \"receivingServiceProvider\",\n \"quoteId\" : \"quoteId\"\n }, {\n \"fees\" : [ {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n } ],\n \"fxRate\" : \"1.3436\",\n \"quoteExpiryTime\" : \"2000-01-23T04:56:07.000+00:00\",\n \"receivingServiceProvider\" : \"receivingServiceProvider\",\n \"quoteId\" : \"quoteId\"\n }, {\n \"fees\" : [ {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n } ],\n \"fxRate\" : \"1.3436\",\n \"quoteExpiryTime\" : \"2000-01-23T04:56:07.000+00:00\",\n \"receivingServiceProvider\" : \"receivingServiceProvider\",\n \"quoteId\" : \"quoteId\"\n }, {\n \"fees\" : [ {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n } ],\n \"fxRate\" : \"1.3436\",\n \"quoteExpiryTime\" : \"2000-01-23T04:56:07.000+00:00\",\n \"receivingServiceProvider\" : \"receivingServiceProvider\",\n \"quoteId\" : \"quoteId\"\n }, {\n \"fees\" : [ {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n } ],\n \"fxRate\" : \"1.3436\",\n \"quoteExpiryTime\" : \"2000-01-23T04:56:07.000+00:00\",\n \"receivingServiceProvider\" : \"receivingServiceProvider\",\n \"quoteId\" : \"quoteId\"\n }, {\n \"fees\" : [ {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n } ],\n \"fxRate\" : \"1.3436\",\n \"quoteExpiryTime\" : \"2000-01-23T04:56:07.000+00:00\",\n \"receivingServiceProvider\" : \"receivingServiceProvider\",\n \"quoteId\" : \"quoteId\"\n }, {\n \"fees\" : [ {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n } ],\n \"fxRate\" : \"1.3436\",\n \"quoteExpiryTime\" : \"2000-01-23T04:56:07.000+00:00\",\n \"receivingServiceProvider\" : \"receivingServiceProvider\",\n \"quoteId\" : \"quoteId\"\n }, {\n \"fees\" : [ {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n } ],\n \"fxRate\" : \"1.3436\",\n \"quoteExpiryTime\" : \"2000-01-23T04:56:07.000+00:00\",\n \"receivingServiceProvider\" : \"receivingServiceProvider\",\n \"quoteId\" : \"quoteId\"\n }, {\n \"fees\" : [ {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n } ],\n \"fxRate\" : \"1.3436\",\n \"quoteExpiryTime\" : \"2000-01-23T04:56:07.000+00:00\",\n \"receivingServiceProvider\" : \"receivingServiceProvider\",\n \"quoteId\" : \"quoteId\"\n } ],\n \"recipientBlockingReason\" : \"recipientBlockingReason\",\n \"dateCreated\" : \"2000-01-23T04:56:07.000+00:00\",\n \"quotationStatus\" : \"pending\",\n \"requestDate\" : \"2000-01-23T04:56:07.000+00:00\",\n \"availableDeliveryMethod\" : \"directtoaccount\",\n \"senderBlockingReason\" : \"senderBlockingReason\",\n \"requestCurrency\" : \"AED\",\n \"quotationReference\" : \"quotationReference\",\n \"requestingOrganisation\" : {\n \"requestingOrganisationIdentifierType\" : \"lei\",\n \"requestingOrganisationIdentifier\" : \"requestingOrganisationIdentifier\"\n },\n \"dateModified\" : \"2000-01-23T04:56:07.000+00:00\",\n \"creationDate\" : \"2000-01-23T04:56:07.000+00:00\",\n \"modificationDate\" : \"2000-01-23T04:56:07.000+00:00\",\n \"originCountry\" : \"AD\",\n \"subType\" : \"subType\",\n \"creditParty\" : [ {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n } ]\n}", ResponseQuotation.class), HttpStatus.OK); + } catch (IOException e) { + log.error("Couldn't serialize response for content type application/json", e); + return new ResponseEntity(HttpStatus.INTERNAL_SERVER_ERROR); + } + } + + return new ResponseEntity(HttpStatus.OK); + } + +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/api/RequeststatesApi.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/api/RequeststatesApi.java new file mode 100644 index 000000000..c585c08f0 --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/api/RequeststatesApi.java @@ -0,0 +1,70 @@ +/** + * NOTE: This class is auto generated by the swagger code generator program (3.0.34). + * https://github.com/swagger-api/swagger-codegen + * Do not edit the class manually. + */ +package org.mifos.connector.gsmastub.api; + +import org.mifos.connector.gsmastub.model.ErrorObject; +import org.mifos.connector.gsmastub.model.RequestGenericPatch; +import org.mifos.connector.gsmastub.model.RequestStateObject; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.enums.ParameterIn; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import org.springframework.http.ResponseEntity; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; +import org.threeten.bp.OffsetDateTime; + +import javax.validation.Valid; +import javax.validation.constraints.Pattern; +import java.util.List; + +@javax.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.SpringCodegen", date = "2022-09-27T11:46:46.417Z[GMT]") +@Validated +public interface RequeststatesApi extends BaseGsmaApi { + + @Operation(summary = "View A Request State", description = "This endpoint returns a specific request state", tags={ "Supporting" }) + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Represents an Asynchronous response", content = @Content(mediaType = "application/json", schema = @Schema(implementation = RequestStateObject.class))), + + @ApiResponse(responseCode = "400", description = "Represents an Error Caused by the Violation of a Business Rule", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "401", description = "Represents an Error Caused by an Authorisation Failure", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "404", description = "Represents an Error Caused by a Failure to Identify the Target Resource", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "500", description = "Represents an Error Caused by a General Server-Side Issue", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "503", description = "Represents an Error Caused by System Unavailability", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))) }) + @RequestMapping(value = "/requeststates/{serverCorrelationId}", + produces = { "application/json" }, + method = RequestMethod.GET) + ResponseEntity requeststatesServerCorrelationIdGET(@Pattern(regexp="^[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{12}$") @Parameter(in = ParameterIn.PATH, description = "Path variable to uniquely identify a request state. Must be supplied as a UUID.", required=true, schema=@Schema()) @PathVariable("serverCorrelationId") String serverCorrelationId, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." ,schema=@Schema()) @RequestHeader(value="X-Date", required=false) OffsetDateTime xDate, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's API key to the server." ,schema=@Schema()) @RequestHeader(value="X-API-Key", required=false) String xAPIKey, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's identifier to the server." ,schema=@Schema()) @RequestHeader(value="X-Client-Id", required=false) String xClientId, @Parameter(in = ParameterIn.HEADER, description = "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." ,schema=@Schema()) @RequestHeader(value="X-Content-Hash", required=false) String xContentHash, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-1", required=false) String xUserCredential1, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-2", required=false) String xUserCredential2, @Parameter(in = ParameterIn.HEADER, description = "String containing the channel that was used to originate the request. For example USSD, Web, App." ,schema=@Schema()) @RequestHeader(value="X-Channel", required=false) String xChannel); + + + @Operation(summary = "Update A Request State", description = "This endpoint updates a specific request state. This operation is to be deprecated. Please refer to Callback definitions for the revised approach to implementing asynchronous callbacks.", tags={ "Supporting" }) + @ApiResponses(value = { + @ApiResponse(responseCode = "204", description = "An empty response is returned for a synchronous successful patch."), + + @ApiResponse(responseCode = "400", description = "Represents an Error Caused by the Violation of a Business Rule", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "401", description = "Represents an Error Caused by an Authorisation Failure", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "404", description = "Represents an Error Caused by a Failure to Identify the Target Resource", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "500", description = "Represents an Error Caused by a General Server-Side Issue", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "503", description = "Represents an Error Caused by System Unavailability", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))) }) + @RequestMapping(value = "/requeststates/{serverCorrelationId}", + produces = { "application/json" }, + consumes = { "application/json" }, + method = RequestMethod.PATCH) + ResponseEntity requeststatesServerCorrelationIdPATCH(@Pattern(regexp="^[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{12}$") @Parameter(in = ParameterIn.PATH, description = "Path variable to uniquely identify a request state. Must be supplied as a UUID.", required=true, schema=@Schema()) @PathVariable("serverCorrelationId") String serverCorrelationId, @Parameter(in = ParameterIn.DEFAULT, description = "Represents the request body of a batch of generic Patch operation.", required=true, schema=@Schema()) @Valid @RequestBody List body, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." ,schema=@Schema()) @RequestHeader(value="X-Date", required=false) OffsetDateTime xDate, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to uniquely identify the request. Must be supplied as a UUID." ,schema=@Schema()) @RequestHeader(value="X-CorrelationID", required=false) String xCorrelationID, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's API key to the server." ,schema=@Schema()) @RequestHeader(value="X-API-Key", required=false) String xAPIKey, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's identifier to the server." ,schema=@Schema()) @RequestHeader(value="X-Client-Id", required=false) String xClientId, @Parameter(in = ParameterIn.HEADER, description = "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." ,schema=@Schema()) @RequestHeader(value="X-Content-Hash", required=false) String xContentHash, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-1", required=false) String xUserCredential1, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-2", required=false) String xUserCredential2, @Parameter(in = ParameterIn.HEADER, description = "String containing the channel that was used to originate the request. For example USSD, Web, App." ,schema=@Schema()) @RequestHeader(value="X-Channel", required=false) String xChannel); + +} + diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/api/RequeststatesApiController.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/api/RequeststatesApiController.java new file mode 100644 index 000000000..48794c05e --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/api/RequeststatesApiController.java @@ -0,0 +1,62 @@ +package org.mifos.connector.gsmastub.api; + +import com.fasterxml.jackson.databind.ObjectMapper; +import io.swagger.v3.oas.annotations.Hidden; +import io.swagger.v3.oas.annotations.Parameter; +import org.mifos.connector.gsmastub.model.RequestGenericPatch; +import org.mifos.connector.gsmastub.model.RequestStateObject; +import io.swagger.v3.oas.annotations.enums.ParameterIn; +import io.swagger.v3.oas.annotations.media.Schema; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestHeader; +import org.springframework.web.bind.annotation.RestController; +import org.threeten.bp.OffsetDateTime; + +import javax.servlet.http.HttpServletRequest; +import javax.validation.Valid; +import javax.validation.constraints.Pattern; +import java.io.IOException; +import java.util.List; + +@javax.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.SpringCodegen", date = "2022-09-27T11:46:46.417Z[GMT]") +@RestController +@Hidden +public class RequeststatesApiController implements RequeststatesApi { + + private static final Logger log = LoggerFactory.getLogger(RequeststatesApiController.class); + + private final ObjectMapper objectMapper; + + private final HttpServletRequest request; + + @org.springframework.beans.factory.annotation.Autowired + public RequeststatesApiController(ObjectMapper objectMapper, HttpServletRequest request) { + this.objectMapper = objectMapper; + this.request = request; + } + + public ResponseEntity requeststatesServerCorrelationIdGET(@Pattern(regexp="^[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{12}$") @Parameter(in = ParameterIn.PATH, description = "Path variable to uniquely identify a request state. Must be supplied as a UUID.", required=true, schema=@Schema()) @PathVariable("serverCorrelationId") String serverCorrelationId, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." ,schema=@Schema()) @RequestHeader(value="X-Date", required=false) OffsetDateTime xDate, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's API key to the server." ,schema=@Schema()) @RequestHeader(value="X-API-Key", required=false) String xAPIKey, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's identifier to the server." ,schema=@Schema()) @RequestHeader(value="X-Client-Id", required=false) String xClientId, @Parameter(in = ParameterIn.HEADER, description = "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." ,schema=@Schema()) @RequestHeader(value="X-Content-Hash", required=false) String xContentHash, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-1", required=false) String xUserCredential1, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-2", required=false) String xUserCredential2, @Parameter(in = ParameterIn.HEADER, description = "String containing the channel that was used to originate the request. For example USSD, Web, App." ,schema=@Schema()) @RequestHeader(value="X-Channel", required=false) String xChannel) { + String accept = request.getHeader("Accept"); + if (accept != null && accept.contains("application/json")) { + try { + return new ResponseEntity(objectMapper.readValue("{\n \"pollLimit\" : 0.08008281904610115,\n \"pendingReason\" : \"pendingReason\",\n \"expiryTime\" : \"2000-01-23T04:56:07.000+00:00\",\n \"objectReference\" : \"objectReference\",\n \"notificationMethod\" : \"callback\",\n \"error\" : {\n \"errordescription\" : \"errordescription\",\n \"errorCategory\" : \"businessRule\",\n \"errorParameters\" : [ {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n } ],\n \"errorDateTime\" : \"2000-01-23T04:56:07.000+00:00\",\n \"errorCode\" : \"genericError\"\n },\n \"serverCorrelationId\" : \"serverCorrelationId\",\n \"status\" : \"pending\"\n}", RequestStateObject.class), HttpStatus.OK); + } catch (IOException e) { + log.error("Couldn't serialize response for content type application/json", e); + return new ResponseEntity(HttpStatus.INTERNAL_SERVER_ERROR); + } + } + + return new ResponseEntity(HttpStatus.OK); + } + + public ResponseEntity requeststatesServerCorrelationIdPATCH(@Pattern(regexp="^[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{12}$") @Parameter(in = ParameterIn.PATH, description = "Path variable to uniquely identify a request state. Must be supplied as a UUID.", required=true, schema=@Schema()) @PathVariable("serverCorrelationId") String serverCorrelationId,@Parameter(in = ParameterIn.DEFAULT, description = "Represents the request body of a batch of generic Patch operation.", required=true, schema=@Schema()) @Valid @RequestBody List body,@Parameter(in = ParameterIn.HEADER, description = "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." ,schema=@Schema()) @RequestHeader(value="X-Date", required=false) OffsetDateTime xDate,@Parameter(in = ParameterIn.HEADER, description = "Header parameter to uniquely identify the request. Must be supplied as a UUID." ,schema=@Schema()) @RequestHeader(value="X-CorrelationID", required=false) String xCorrelationID,@Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's API key to the server." ,schema=@Schema()) @RequestHeader(value="X-API-Key", required=false) String xAPIKey,@Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's identifier to the server." ,schema=@Schema()) @RequestHeader(value="X-Client-Id", required=false) String xClientId,@Parameter(in = ParameterIn.HEADER, description = "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." ,schema=@Schema()) @RequestHeader(value="X-Content-Hash", required=false) String xContentHash,@Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-1", required=false) String xUserCredential1,@Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-2", required=false) String xUserCredential2,@Parameter(in = ParameterIn.HEADER, description = "String containing the channel that was used to originate the request. For example USSD, Web, App." ,schema=@Schema()) @RequestHeader(value="X-Channel", required=false) String xChannel) { + String accept = request.getHeader("Accept"); + return new ResponseEntity(HttpStatus.OK); + } + +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/api/ResponsesApi.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/api/ResponsesApi.java new file mode 100644 index 000000000..ffa83a61b --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/api/ResponsesApi.java @@ -0,0 +1,50 @@ +/** + * NOTE: This class is auto generated by the swagger code generator program (3.0.34). + * https://github.com/swagger-api/swagger-codegen + * Do not edit the class manually. + */ +package org.mifos.connector.gsmastub.api; + +import org.mifos.connector.gsmastub.model.ErrorObject; +import org.mifos.connector.gsmastub.model.ResponseResponse; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.enums.ParameterIn; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import org.springframework.http.ResponseEntity; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestHeader; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.threeten.bp.OffsetDateTime; + +import javax.validation.constraints.Pattern; + +@javax.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.SpringCodegen", date = "2022-09-27T11:46:46.417Z[GMT]") +@Validated +public interface ResponsesApi extends BaseGsmaApi { + + @Operation(summary = "View A Response", description = "This endpoint returns a specific response.", tags={ "Supporting" }) + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Represents an Response object response", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ResponseResponse.class))), + + @ApiResponse(responseCode = "400", description = "Represents an Error Caused by the Violation of a Business Rule", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "401", description = "Represents an Error Caused by an Authorisation Failure", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "404", description = "Represents an Error Caused by a Failure to Identify the Target Resource", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "500", description = "Represents an Error Caused by a General Server-Side Issue", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "503", description = "Represents an Error Caused by System Unavailability", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))) }) + @RequestMapping(value = "/responses/{clientCorrelationId}", + produces = { "application/json" }, + method = RequestMethod.GET) + ResponseEntity responsesClientCorrelationIdGET(@Pattern(regexp="^[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{12}$") @Parameter(in = ParameterIn.PATH, description = "Path variable to uniquely identify a response object. Must be supplied as a UUID.", required=true, schema=@Schema()) @PathVariable("clientCorrelationId") String clientCorrelationId, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." ,schema=@Schema()) @RequestHeader(value="X-Date", required=false) OffsetDateTime xDate, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's API key to the server." ,schema=@Schema()) @RequestHeader(value="X-API-Key", required=false) String xAPIKey, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's identifier to the server." ,schema=@Schema()) @RequestHeader(value="X-Client-Id", required=false) String xClientId, @Parameter(in = ParameterIn.HEADER, description = "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." ,schema=@Schema()) @RequestHeader(value="X-Content-Hash", required=false) String xContentHash, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-1", required=false) String xUserCredential1, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-2", required=false) String xUserCredential2, @Parameter(in = ParameterIn.HEADER, description = "String containing the channel that was used to originate the request. For example USSD, Web, App." ,schema=@Schema()) @RequestHeader(value="X-Channel", required=false) String xChannel); + +} + diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/api/ResponsesApiController.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/api/ResponsesApiController.java new file mode 100644 index 000000000..6df0a0fdd --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/api/ResponsesApiController.java @@ -0,0 +1,53 @@ +package org.mifos.connector.gsmastub.api; + +import com.fasterxml.jackson.databind.ObjectMapper; +import io.swagger.v3.oas.annotations.Hidden; +import io.swagger.v3.oas.annotations.Parameter; +import org.mifos.connector.gsmastub.model.ResponseResponse; +import io.swagger.v3.oas.annotations.enums.ParameterIn; +import io.swagger.v3.oas.annotations.media.Schema; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestHeader; +import org.springframework.web.bind.annotation.RestController; +import org.threeten.bp.OffsetDateTime; + +import javax.servlet.http.HttpServletRequest; +import javax.validation.constraints.Pattern; +import java.io.IOException; + +@javax.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.SpringCodegen", date = "2022-09-27T11:46:46.417Z[GMT]") +@RestController +@Hidden +public class ResponsesApiController implements ResponsesApi { + + private static final Logger log = LoggerFactory.getLogger(ResponsesApiController.class); + + private final ObjectMapper objectMapper; + + private final HttpServletRequest request; + + @org.springframework.beans.factory.annotation.Autowired + public ResponsesApiController(ObjectMapper objectMapper, HttpServletRequest request) { + this.objectMapper = objectMapper; + this.request = request; + } + + public ResponseEntity responsesClientCorrelationIdGET(@Pattern(regexp="^[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{12}$") @Parameter(in = ParameterIn.PATH, description = "Path variable to uniquely identify a response object. Must be supplied as a UUID.", required=true, schema=@Schema()) @PathVariable("clientCorrelationId") String clientCorrelationId, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." ,schema=@Schema()) @RequestHeader(value="X-Date", required=false) OffsetDateTime xDate, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's API key to the server." ,schema=@Schema()) @RequestHeader(value="X-API-Key", required=false) String xAPIKey, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's identifier to the server." ,schema=@Schema()) @RequestHeader(value="X-Client-Id", required=false) String xClientId, @Parameter(in = ParameterIn.HEADER, description = "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." ,schema=@Schema()) @RequestHeader(value="X-Content-Hash", required=false) String xContentHash, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-1", required=false) String xUserCredential1, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-2", required=false) String xUserCredential2, @Parameter(in = ParameterIn.HEADER, description = "String containing the channel that was used to originate the request. For example USSD, Web, App." ,schema=@Schema()) @RequestHeader(value="X-Channel", required=false) String xChannel) { + String accept = request.getHeader("Accept"); + if (accept != null && accept.contains("application/json")) { + try { + return new ResponseEntity(objectMapper.readValue("{\n \"link\" : \"link\"\n}", ResponseResponse.class), HttpStatus.OK); + } catch (IOException e) { + log.error("Couldn't serialize response for content type application/json", e); + return new ResponseEntity(HttpStatus.INTERNAL_SERVER_ERROR); + } + } + + return new ResponseEntity(HttpStatus.OK); + } + +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/api/StatemententriesApi.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/api/StatemententriesApi.java new file mode 100644 index 000000000..062bf86f9 --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/api/StatemententriesApi.java @@ -0,0 +1,51 @@ +/** + * NOTE: This class is auto generated by the swagger code generator program (3.0.34). + * https://github.com/swagger-api/swagger-codegen + * Do not edit the class manually. + */ +package org.mifos.connector.gsmastub.api; + +import org.mifos.connector.gsmastub.model.ErrorObject; +import org.mifos.connector.gsmastub.model.ResponseStatementEntries; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.enums.ParameterIn; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import org.springframework.http.ResponseEntity; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestHeader; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.threeten.bp.OffsetDateTime; + +import javax.validation.constraints.Size; + +@javax.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.SpringCodegen", date = "2022-09-27T11:46:46.417Z[GMT]") +@Validated +public interface StatemententriesApi extends BaseGsmaApi { + + @Operation(summary = "View Specific Statement", description = "The Statement Entries API enables generic representations of transactions to be returned. Typically, the returned representations are used for the purposes of presenting a statement to the account holder. In order to return a statement, a transaction reference must be specified.", tags={ "Accounts" }) + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Represent a list of Statement Entries", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ResponseStatementEntries.class))), + + @ApiResponse(responseCode = "400", description = "Represents an Error Caused by the Violation of a Business Rule", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "401", description = "Represents an Error Caused by an Authorisation Failure", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "404", description = "Represents an Error Caused by a Failure to Identify the Target Resource", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "500", description = "Represents an Error Caused by a General Server-Side Issue", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "503", description = "Represents an Error Caused by System Unavailability", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))) }) + @RequestMapping(value = "/statemententries/{transactionReference}", + produces = { "application/json" }, + method = RequestMethod.GET) + ResponseEntity statemententriesTransactionReferenceGET(@Size(min=1,max=256) @Parameter(in = ParameterIn.PATH, description = "Path variable to uniquely identify the transaction.", required=true, schema=@Schema()) @PathVariable("transactionReference") String transactionReference, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." ,schema=@Schema()) @RequestHeader(value="X-Date", required=false) OffsetDateTime xDate, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's API key to the server." ,schema=@Schema()) @RequestHeader(value="X-API-Key", required=false) String xAPIKey, @Parameter(in = ParameterIn.HEADER, description = "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication." ,schema=@Schema()) @RequestHeader(value="X-User-Bearer", required=false) String xUserBearer, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's identifier to the server." ,schema=@Schema()) @RequestHeader(value="X-Client-Id", required=false) String xClientId, @Parameter(in = ParameterIn.HEADER, description = "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." ,schema=@Schema()) @RequestHeader(value="X-Content-Hash", required=false) String xContentHash, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-1", required=false) String xUserCredential1, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-2", required=false) String xUserCredential2, @Parameter(in = ParameterIn.HEADER, description = "String containing the channel that was used to originate the request. For example USSD, Web, App." ,schema=@Schema()) @RequestHeader(value="X-Channel", required=false) String xChannel, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." ,schema=@Schema(allowableValues={ "lei", "swiftbic", "organisationid" } +)) @RequestHeader(value="X-Account-Holding-Institution-Identifier-Type", required=false) String xAccountHoldingInstitutionIdentifierType, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." ,schema=@Schema()) @RequestHeader(value="X-Account-Holding-Institution-Identifier", required=false) String xAccountHoldingInstitutionIdentifier); + +} + diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/api/StatemententriesApiController.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/api/StatemententriesApiController.java new file mode 100644 index 000000000..ae20b357b --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/api/StatemententriesApiController.java @@ -0,0 +1,54 @@ +package org.mifos.connector.gsmastub.api; + +import com.fasterxml.jackson.databind.ObjectMapper; +import io.swagger.v3.oas.annotations.Hidden; +import io.swagger.v3.oas.annotations.Parameter; +import org.mifos.connector.gsmastub.model.ResponseStatementEntries; +import io.swagger.v3.oas.annotations.enums.ParameterIn; +import io.swagger.v3.oas.annotations.media.Schema; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestHeader; +import org.springframework.web.bind.annotation.RestController; +import org.threeten.bp.OffsetDateTime; + +import javax.servlet.http.HttpServletRequest; +import javax.validation.constraints.Size; +import java.io.IOException; + +@javax.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.SpringCodegen", date = "2022-09-27T11:46:46.417Z[GMT]") +@RestController +@Hidden +public class StatemententriesApiController implements StatemententriesApi { + + private static final Logger log = LoggerFactory.getLogger(StatemententriesApiController.class); + + private final ObjectMapper objectMapper; + + private final HttpServletRequest request; + + @org.springframework.beans.factory.annotation.Autowired + public StatemententriesApiController(ObjectMapper objectMapper, HttpServletRequest request) { + this.objectMapper = objectMapper; + this.request = request; + } + + public ResponseEntity statemententriesTransactionReferenceGET(@Size(min=1,max=256) @Parameter(in = ParameterIn.PATH, description = "Path variable to uniquely identify the transaction.", required=true, schema=@Schema()) @PathVariable("transactionReference") String transactionReference, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." ,schema=@Schema()) @RequestHeader(value="X-Date", required=false) OffsetDateTime xDate, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's API key to the server." ,schema=@Schema()) @RequestHeader(value="X-API-Key", required=false) String xAPIKey, @Parameter(in = ParameterIn.HEADER, description = "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication." ,schema=@Schema()) @RequestHeader(value="X-User-Bearer", required=false) String xUserBearer, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's identifier to the server." ,schema=@Schema()) @RequestHeader(value="X-Client-Id", required=false) String xClientId, @Parameter(in = ParameterIn.HEADER, description = "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." ,schema=@Schema()) @RequestHeader(value="X-Content-Hash", required=false) String xContentHash, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-1", required=false) String xUserCredential1, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-2", required=false) String xUserCredential2, @Parameter(in = ParameterIn.HEADER, description = "String containing the channel that was used to originate the request. For example USSD, Web, App." ,schema=@Schema()) @RequestHeader(value="X-Channel", required=false) String xChannel, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." ,schema=@Schema(allowableValues={ "lei", "swiftbic", "organisationid" } +)) @RequestHeader(value="X-Account-Holding-Institution-Identifier-Type", required=false) String xAccountHoldingInstitutionIdentifierType, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." ,schema=@Schema()) @RequestHeader(value="X-Account-Holding-Institution-Identifier", required=false) String xAccountHoldingInstitutionIdentifier) { + String accept = request.getHeader("Accept"); + if (accept != null && accept.contains("application/json")) { + try { + return new ResponseEntity(objectMapper.readValue("{\n \"debitParty\" : [ null, null, null, null, null, null, null, null, null, null ],\n \"amount\" : \"15.21\",\n \"transactionReference\" : \"transactionReference\",\n \"transactionStatus\" : \"transactionStatus\",\n \"customData\" : [ {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n } ],\n \"dateModified\" : \"2000-01-23T04:56:07.000+00:00\",\n \"descriptionText\" : \"descriptionText\",\n \"creationDate\" : \"2000-01-23T04:56:07.000+00:00\",\n \"displayType\" : \"displayType\",\n \"modificationDate\" : \"2000-01-23T04:56:07.000+00:00\",\n \"dateCreated\" : \"2000-01-23T04:56:07.000+00:00\",\n \"transactionReceipt\" : \"transactionReceipt\",\n \"requestDate\" : \"2000-01-23T04:56:07.000+00:00\",\n \"currency\" : \"AED\",\n \"creditParty\" : [ {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n } ]\n}", ResponseStatementEntries.class), HttpStatus.OK); + } catch (IOException e) { + log.error("Couldn't serialize response for content type application/json", e); + return new ResponseEntity(HttpStatus.INTERNAL_SERVER_ERROR); + } + } + + return new ResponseEntity(HttpStatus.OK); + } + +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/api/TransactionsApi.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/api/TransactionsApi.java new file mode 100644 index 000000000..3a9acf0ea --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/api/TransactionsApi.java @@ -0,0 +1,142 @@ +/** + * NOTE: This class is auto generated by the swagger code generator program (3.0.34). + * https://github.com/swagger-api/swagger-codegen + * Do not edit the class manually. + */ +package org.mifos.connector.gsmastub.api; + +import org.mifos.connector.gsmastub.model.*; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.enums.ParameterIn; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import org.springframework.http.ResponseEntity; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; +import org.threeten.bp.OffsetDateTime; + +import javax.validation.Valid; +import javax.validation.constraints.Size; +import java.util.List; + +@javax.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.SpringCodegen", date = "2022-09-27T11:46:46.417Z[GMT]") +@Validated +public interface TransactionsApi extends BaseGsmaApi { + + @Operation(summary = "Create a Transaction", description = "Provided with a valid object representation, this endpoint allows for a new transaction to be created", tags={ "Transactions" }) + @ApiResponses(value = { + @ApiResponse(responseCode = "201", description = "Represents a Transaction response", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ResponseTransaction.class))), + + @ApiResponse(responseCode = "202", description = "Represents an Asynchronous response", content = @Content(mediaType = "application/json", schema = @Schema(implementation = RequestStateObject.class))), + + @ApiResponse(responseCode = "400", description = "Represents an Error Caused by the Violation of a Business Rule", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "401", description = "Represents an Error Caused by an Authorisation Failure", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "404", description = "Represents an Error Caused by a Failure to Identify the Target Resource", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "500", description = "Represents an Error Caused by a General Server-Side Issue", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "503", description = "Represents an Error Caused by System Unavailability", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))) }) + @RequestMapping(value = "/transactions", + produces = { "application/json" }, + consumes = { "application/json" }, + method = RequestMethod.POST) + ResponseEntity transactionsPOST(@Parameter(in = ParameterIn.DEFAULT, description = "Represents the request body of a transaction.", required=true, schema=@Schema()) @Valid @RequestBody RequestTransaction body, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." ,schema=@Schema()) @RequestHeader(value="X-Date", required=false) OffsetDateTime xDate, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to uniquely identify the request. Must be supplied as a UUID." ,schema=@Schema()) @RequestHeader(value="X-CorrelationID", required=false) String xCorrelationID, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's API key to the server." ,schema=@Schema()) @RequestHeader(value="X-API-Key", required=false) String xAPIKey, @Parameter(in = ParameterIn.HEADER, description = "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication." ,schema=@Schema()) @RequestHeader(value="X-User-Bearer", required=false) String xUserBearer, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's identifier to the server." ,schema=@Schema()) @RequestHeader(value="X-Client-Id", required=false) String xClientId, @Parameter(in = ParameterIn.HEADER, description = "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." ,schema=@Schema()) @RequestHeader(value="X-Content-Hash", required=false) String xContentHash, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-1", required=false) String xUserCredential1, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-2", required=false) String xUserCredential2, @Parameter(in = ParameterIn.HEADER, description = "String containing the channel that was used to originate the request. For example USSD, Web, App." ,schema=@Schema()) @RequestHeader(value="X-Channel", required=false) String xChannel, @Parameter(in = ParameterIn.HEADER, description = "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." ,schema=@Schema()) @RequestHeader(value="X-Callback-URL", required=false) String xCallbackURL, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." ,schema=@Schema(allowableValues={ "lei", "swiftbic", "organisationid" } +)) @RequestHeader(value="X-Account-Holding-Institution-Identifier-Type", required=false) String xAccountHoldingInstitutionIdentifierType, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." ,schema=@Schema()) @RequestHeader(value="X-Account-Holding-Institution-Identifier", required=false) String xAccountHoldingInstitutionIdentifier); + + + @Operation(summary = "View A Transaction", description = "This endpoint returns the details of a transaction", tags={ "Transactions" }) + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Represents a Transaction response", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ResponseTransaction.class))), + + @ApiResponse(responseCode = "400", description = "Represents an Error Caused by the Violation of a Business Rule", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "401", description = "Represents an Error Caused by an Authorisation Failure", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "404", description = "Represents an Error Caused by a Failure to Identify the Target Resource", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "500", description = "Represents an Error Caused by a General Server-Side Issue", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "503", description = "Represents an Error Caused by System Unavailability", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))) }) + @RequestMapping(value = "/transactions/{transactionReference}", + produces = { "application/json" }, + method = RequestMethod.GET) + ResponseEntity transactionsTransactionReferenceGET(@Size(min=1,max=256) @Parameter(in = ParameterIn.PATH, description = "Path variable to uniquely identify the transaction.", required=true, schema=@Schema()) @PathVariable("transactionReference") String transactionReference, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." ,schema=@Schema()) @RequestHeader(value="X-Date", required=false) OffsetDateTime xDate, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's API key to the server." ,schema=@Schema()) @RequestHeader(value="X-API-Key", required=false) String xAPIKey, @Parameter(in = ParameterIn.HEADER, description = "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication." ,schema=@Schema()) @RequestHeader(value="X-User-Bearer", required=false) String xUserBearer, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's identifier to the server." ,schema=@Schema()) @RequestHeader(value="X-Client-Id", required=false) String xClientId, @Parameter(in = ParameterIn.HEADER, description = "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." ,schema=@Schema()) @RequestHeader(value="X-Content-Hash", required=false) String xContentHash, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-1", required=false) String xUserCredential1, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-2", required=false) String xUserCredential2, @Parameter(in = ParameterIn.HEADER, description = "String containing the channel that was used to originate the request. For example USSD, Web, App." ,schema=@Schema()) @RequestHeader(value="X-Channel", required=false) String xChannel, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." ,schema=@Schema(allowableValues={ "lei", "swiftbic", "organisationid" } +)) @RequestHeader(value="X-Account-Holding-Institution-Identifier-Type", required=false) String xAccountHoldingInstitutionIdentifierType, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." ,schema=@Schema()) @RequestHeader(value="X-Account-Holding-Institution-Identifier", required=false) String xAccountHoldingInstitutionIdentifier); + + + @Operation(summary = "Update A Transaction", description = "This endpoint allows the transactionStatus of a transaction to be updated.", tags={ "Transactions" }) + @ApiResponses(value = { + @ApiResponse(responseCode = "202", description = "Represents an Asynchronous response", content = @Content(mediaType = "application/json", schema = @Schema(implementation = RequestStateObject.class))), + + @ApiResponse(responseCode = "204", description = "An empty response is returned for a synchronous successful patch."), + + @ApiResponse(responseCode = "400", description = "Represents an Error Caused by the Violation of a Business Rule", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "401", description = "Represents an Error Caused by an Authorisation Failure", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "404", description = "Represents an Error Caused by a Failure to Identify the Target Resource", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "500", description = "Represents an Error Caused by a General Server-Side Issue", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "503", description = "Represents an Error Caused by System Unavailability", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))) }) + @RequestMapping(value = "/transactions/{transactionReference}", + produces = { "application/json" }, + consumes = { "application/json" }, + method = RequestMethod.PATCH) + ResponseEntity transactionsTransactionReferencePATCH(@Size(min=1,max=256) @Parameter(in = ParameterIn.PATH, description = "Path variable to uniquely identify the transaction.", required=true, schema=@Schema()) @PathVariable("transactionReference") String transactionReference, @Parameter(in = ParameterIn.DEFAULT, description = "Represents the request body of a batch of generic Patch operation.", required=true, schema=@Schema()) @Valid @RequestBody List body, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." ,schema=@Schema()) @RequestHeader(value="X-Date", required=false) OffsetDateTime xDate, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's API key to the server." ,schema=@Schema()) @RequestHeader(value="X-API-Key", required=false) String xAPIKey, @Parameter(in = ParameterIn.HEADER, description = "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication." ,schema=@Schema()) @RequestHeader(value="X-User-Bearer", required=false) String xUserBearer, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's identifier to the server." ,schema=@Schema()) @RequestHeader(value="X-Client-Id", required=false) String xClientId, @Parameter(in = ParameterIn.HEADER, description = "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." ,schema=@Schema()) @RequestHeader(value="X-Content-Hash", required=false) String xContentHash, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-1", required=false) String xUserCredential1, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-2", required=false) String xUserCredential2, @Parameter(in = ParameterIn.HEADER, description = "String containing the channel that was used to originate the request. For example USSD, Web, App." ,schema=@Schema()) @RequestHeader(value="X-Channel", required=false) String xChannel, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." ,schema=@Schema(allowableValues={ "lei", "swiftbic", "organisationid" } +)) @RequestHeader(value="X-Account-Holding-Institution-Identifier-Type", required=false) String xAccountHoldingInstitutionIdentifierType, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." ,schema=@Schema()) @RequestHeader(value="X-Account-Holding-Institution-Identifier", required=false) String xAccountHoldingInstitutionIdentifier, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to uniquely identify the request. Must be supplied as a UUID." ,schema=@Schema()) @RequestHeader(value="X-CorrelationID", required=false) String xCorrelationID, @Parameter(in = ParameterIn.HEADER, description = "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." ,schema=@Schema()) @RequestHeader(value="X-Callback-URL", required=false) String xCallbackURL); + + + @Operation(summary = "Create A Reversal", description = "Provided with a valid object representation, this endpoint allows for a new reversal to be created", tags={ "Transactions" }) + @ApiResponses(value = { + @ApiResponse(responseCode = "201", description = "Represents a Transaction Reversal response", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ResponseReversal.class))), + + @ApiResponse(responseCode = "202", description = "Represents an Asynchronous response", content = @Content(mediaType = "application/json", schema = @Schema(implementation = RequestStateObject.class))), + + @ApiResponse(responseCode = "400", description = "Represents an Error Caused by the Violation of a Business Rule", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "401", description = "Represents an Error Caused by an Authorisation Failure", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "404", description = "Represents an Error Caused by a Failure to Identify the Target Resource", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "500", description = "Represents an Error Caused by a General Server-Side Issue", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "503", description = "Represents an Error Caused by System Unavailability", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))) }) + @RequestMapping(value = "/transactions/{transactionReference}/reversals", + produces = { "application/json" }, + consumes = { "application/json" }, + method = RequestMethod.POST) + ResponseEntity transactionsTransactionReferenceReversalsPOST(@Size(min=1,max=256) @Parameter(in = ParameterIn.PATH, description = "Path variable to uniquely identify the transaction.", required=true, schema=@Schema()) @PathVariable("transactionReference") String transactionReference, @Parameter(in = ParameterIn.DEFAULT, description = "Represents the request body of a transaction reversal.", required=true, schema=@Schema()) @Valid @RequestBody RequestReversal body, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." ,schema=@Schema()) @RequestHeader(value="X-Date", required=false) OffsetDateTime xDate, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to uniquely identify the request. Must be supplied as a UUID." ,schema=@Schema()) @RequestHeader(value="X-CorrelationID", required=false) String xCorrelationID, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's API key to the server." ,schema=@Schema()) @RequestHeader(value="X-API-Key", required=false) String xAPIKey, @Parameter(in = ParameterIn.HEADER, description = "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication." ,schema=@Schema()) @RequestHeader(value="X-User-Bearer", required=false) String xUserBearer, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's identifier to the server." ,schema=@Schema()) @RequestHeader(value="X-Client-Id", required=false) String xClientId, @Parameter(in = ParameterIn.HEADER, description = "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." ,schema=@Schema()) @RequestHeader(value="X-Content-Hash", required=false) String xContentHash, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-1", required=false) String xUserCredential1, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-2", required=false) String xUserCredential2, @Parameter(in = ParameterIn.HEADER, description = "String containing the channel that was used to originate the request. For example USSD, Web, App." ,schema=@Schema()) @RequestHeader(value="X-Channel", required=false) String xChannel, @Parameter(in = ParameterIn.HEADER, description = "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." ,schema=@Schema()) @RequestHeader(value="X-Callback-URL", required=false) String xCallbackURL, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." ,schema=@Schema(allowableValues={ "lei", "swiftbic", "organisationid" } +)) @RequestHeader(value="X-Account-Holding-Institution-Identifier-Type", required=false) String xAccountHoldingInstitutionIdentifierType, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." ,schema=@Schema()) @RequestHeader(value="X-Account-Holding-Institution-Identifier", required=false) String xAccountHoldingInstitutionIdentifier); + + + @Operation(summary = "Create a Transaction", description = "Provided with a valid object representation, this endpoint allows for a new transaction to be created for a given transaction type passed via the URL.", tags={ "Transactions" }) + @ApiResponses(value = { + @ApiResponse(responseCode = "201", description = "Represents a Transaction response", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ResponseTransactionType.class))), + + @ApiResponse(responseCode = "202", description = "Represents an Asynchronous response", content = @Content(mediaType = "application/json", schema = @Schema(implementation = RequestStateObject.class))), + + @ApiResponse(responseCode = "400", description = "Represents an Error Caused by the Violation of a Business Rule", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "401", description = "Represents an Error Caused by an Authorisation Failure", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "404", description = "Represents an Error Caused by a Failure to Identify the Target Resource", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "500", description = "Represents an Error Caused by a General Server-Side Issue", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))), + + @ApiResponse(responseCode = "503", description = "Represents an Error Caused by System Unavailability", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorObject.class))) }) + @RequestMapping(value = "/transactions/type/{transactionType}", + produces = { "application/json" }, + consumes = { "application/json" }, + method = RequestMethod.POST) + ResponseEntity transactionstypetransactionTypePUT(@Parameter(in = ParameterIn.PATH, description = "Identifies the type of transaction that is to be created.", required=true, schema=@Schema(allowableValues={ "billpay", "deposit", "disbursement", "transfer", "merchantpay", "inttransfer", "adjustment", "reversal", "withdrawal" } +)) @PathVariable("transactionType") String transactionType, @Parameter(in = ParameterIn.DEFAULT, description = "Represents the request body of a transaction without Type.", required=true, schema=@Schema()) @Valid @RequestBody RequestTransactionType body, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." ,schema=@Schema()) @RequestHeader(value="X-Date", required=false) OffsetDateTime xDate, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to uniquely identify the request. Must be supplied as a UUID." ,schema=@Schema()) @RequestHeader(value="X-CorrelationID", required=false) String xCorrelationID, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's API key to the server." ,schema=@Schema()) @RequestHeader(value="X-API-Key", required=false) String xAPIKey, @Parameter(in = ParameterIn.HEADER, description = "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication." ,schema=@Schema()) @RequestHeader(value="X-User-Bearer", required=false) String xUserBearer, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's identifier to the server." ,schema=@Schema()) @RequestHeader(value="X-Client-Id", required=false) String xClientId, @Parameter(in = ParameterIn.HEADER, description = "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." ,schema=@Schema()) @RequestHeader(value="X-Content-Hash", required=false) String xContentHash, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-1", required=false) String xUserCredential1, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-2", required=false) String xUserCredential2, @Parameter(in = ParameterIn.HEADER, description = "String containing the channel that was used to originate the request. For example USSD, Web, App." ,schema=@Schema()) @RequestHeader(value="X-Channel", required=false) String xChannel, @Parameter(in = ParameterIn.HEADER, description = "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." ,schema=@Schema()) @RequestHeader(value="X-Callback-URL", required=false) String xCallbackURL, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." ,schema=@Schema(allowableValues={ "lei", "swiftbic", "organisationid" } +)) @RequestHeader(value="X-Account-Holding-Institution-Identifier-Type", required=false) String xAccountHoldingInstitutionIdentifierType, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." ,schema=@Schema()) @RequestHeader(value="X-Account-Holding-Institution-Identifier", required=false) String xAccountHoldingInstitutionIdentifier); + +} + diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/api/TransactionsApiController.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/api/TransactionsApiController.java new file mode 100644 index 000000000..370853c01 --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/api/TransactionsApiController.java @@ -0,0 +1,118 @@ +package org.mifos.connector.gsmastub.api; + +import com.fasterxml.jackson.databind.ObjectMapper; +import io.swagger.v3.oas.annotations.Hidden; +import io.swagger.v3.oas.annotations.Parameter; +import org.mifos.connector.gsmastub.model.*; +import io.swagger.v3.oas.annotations.enums.ParameterIn; +import io.swagger.v3.oas.annotations.media.Schema; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestHeader; +import org.springframework.web.bind.annotation.RestController; +import org.threeten.bp.OffsetDateTime; + +import javax.servlet.http.HttpServletRequest; +import javax.validation.Valid; +import javax.validation.constraints.Size; +import java.io.IOException; +import java.util.List; + +@javax.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.SpringCodegen", date = "2022-09-27T11:46:46.417Z[GMT]") +@RestController +@Hidden +public class TransactionsApiController implements TransactionsApi { + + private static final Logger log = LoggerFactory.getLogger(TransactionsApiController.class); + + private final ObjectMapper objectMapper; + + private final HttpServletRequest request; + + @org.springframework.beans.factory.annotation.Autowired + public TransactionsApiController(ObjectMapper objectMapper, HttpServletRequest request) { + this.objectMapper = objectMapper; + this.request = request; + } + + public ResponseEntity transactionsPOST(@Parameter(in = ParameterIn.DEFAULT, description = "Represents the request body of a transaction.", required=true, schema=@Schema()) @Valid @RequestBody RequestTransaction body, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." ,schema=@Schema()) @RequestHeader(value="X-Date", required=false) OffsetDateTime xDate, @Parameter(in = ParameterIn.HEADER, description = "Header parameter to uniquely identify the request. Must be supplied as a UUID." ,schema=@Schema()) @RequestHeader(value="X-CorrelationID", required=false) String xCorrelationID, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's API key to the server." ,schema=@Schema()) @RequestHeader(value="X-API-Key", required=false) String xAPIKey, @Parameter(in = ParameterIn.HEADER, description = "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication." ,schema=@Schema()) @RequestHeader(value="X-User-Bearer", required=false) String xUserBearer, @Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's identifier to the server." ,schema=@Schema()) @RequestHeader(value="X-Client-Id", required=false) String xClientId, @Parameter(in = ParameterIn.HEADER, description = "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." ,schema=@Schema()) @RequestHeader(value="X-Content-Hash", required=false) String xContentHash, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-1", required=false) String xUserCredential1, @Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-2", required=false) String xUserCredential2, @Parameter(in = ParameterIn.HEADER, description = "String containing the channel that was used to originate the request. For example USSD, Web, App." ,schema=@Schema()) @RequestHeader(value="X-Channel", required=false) String xChannel, @Parameter(in = ParameterIn.HEADER, description = "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." ,schema=@Schema()) @RequestHeader(value="X-Callback-URL", required=false) String xCallbackURL, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." ,schema=@Schema(allowableValues={ "lei", "swiftbic", "organisationid" } +)) @RequestHeader(value="X-Account-Holding-Institution-Identifier-Type", required=false) String xAccountHoldingInstitutionIdentifierType, @Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." ,schema=@Schema()) @RequestHeader(value="X-Account-Holding-Institution-Identifier", required=false) String xAccountHoldingInstitutionIdentifier) { + String accept = request.getHeader("Accept"); + if (accept != null && accept.contains("application/json")) { + try { + return new ResponseEntity(objectMapper.readValue("{\n \"recipientKyc\" : {\n \"emailAddress\" : \"emailAddress\",\n \"occupation\" : \"occupation\",\n \"postalAddress\" : {\n \"city\" : \"city\",\n \"postalCode\" : \"postalCode\",\n \"addressLine1\" : \"addressLine1\",\n \"stateProvince\" : \"stateProvince\",\n \"addressLine2\" : \"addressLine2\",\n \"addressLine3\" : \"addressLine3\"\n },\n \"gender\" : \"m\",\n \"idDocument\" : [ {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n } ],\n \"employerName\" : \"employerName\",\n \"dateOfBirth\" : \"2000-11-20T00:00:00.000+00:00\",\n \"contactPhone\" : \"contactPhone\",\n \"subjectName\" : {\n \"firstName\" : \"firstName\",\n \"lastName\" : \"lastName\",\n \"nativeName\" : \"nativeName\",\n \"fullName\" : \"fullName\",\n \"middleName\" : \"middleName\",\n \"title\" : \"title\"\n }\n },\n \"debitParty\" : [ null, null, null, null, null, null, null, null, null, null ],\n \"fees\" : [ {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n } ],\n \"metadata\" : [ {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n } ],\n \"customData\" : [ {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n } ],\n \"requestingLei\" : \"requestingLei\",\n \"descriptionText\" : \"descriptionText\",\n \"type\" : \"billpay\",\n \"dateCreated\" : \"2000-01-23T04:56:07.000+00:00\",\n \"transactionReceipt\" : \"transactionReceipt\",\n \"oneTimeCode\" : \"oneTimeCode\",\n \"requestDate\" : \"2000-01-23T04:56:07.000+00:00\",\n \"currency\" : \"AED\",\n \"originalTransactionReference\" : \"originalTransactionReference\",\n \"amount\" : \"15.21\",\n \"transactionReference\" : \"transactionReference\",\n \"transactionStatus\" : \"transactionStatus\",\n \"internationalTransferInformation\" : {\n \"quotationReference\" : \"quotationReference\",\n \"deliveryMethod\" : \"directtoaccount\",\n \"originCountry\" : \"AD\",\n \"relationshipSender\" : \"relationshipSender\",\n \"remittancePurpose\" : \"remittancePurpose\",\n \"senderBlockingReason\" : \"senderBlockingReason\",\n \"quoteId\" : \"quoteId\",\n \"recipientBlockingReason\" : \"recipientBlockingReason\"\n },\n \"requestingOrganisation\" : {\n \"requestingOrganisationIdentifierType\" : \"lei\",\n \"requestingOrganisationIdentifier\" : \"requestingOrganisationIdentifier\"\n },\n \"geoCode\" : \"37.423825,-122.082900\",\n \"dateModified\" : \"2000-01-23T04:56:07.000+00:00\",\n \"creationDate\" : \"2000-01-23T04:56:07.000+00:00\",\n \"modificationDate\" : \"2000-01-23T04:56:07.000+00:00\",\n \"receivingLei\" : \"receivingLei\",\n \"servicingIdentity\" : \"servicingIdentity\",\n \"requestingOrganisationTransactionReference\" : \"requestingOrganisationTransactionReference\",\n \"subType\" : \"subType\",\n \"creditParty\" : [ {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n } ]\n}", ResponseTransaction.class), HttpStatus.OK); + } catch (IOException e) { + log.error("Couldn't serialize response for content type application/json", e); + return new ResponseEntity(HttpStatus.INTERNAL_SERVER_ERROR); + } + } + + return new ResponseEntity(HttpStatus.OK); + } + + public ResponseEntity transactionsTransactionReferenceGET(@Size(min=1,max=256) @Parameter(in = ParameterIn.PATH, description = "Path variable to uniquely identify the transaction.", required=true, schema=@Schema()) @PathVariable("transactionReference") String transactionReference,@Parameter(in = ParameterIn.HEADER, description = "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." ,schema=@Schema()) @RequestHeader(value="X-Date", required=false) OffsetDateTime xDate,@Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's API key to the server." ,schema=@Schema()) @RequestHeader(value="X-API-Key", required=false) String xAPIKey,@Parameter(in = ParameterIn.HEADER, description = "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication." ,schema=@Schema()) @RequestHeader(value="X-User-Bearer", required=false) String xUserBearer,@Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's identifier to the server." ,schema=@Schema()) @RequestHeader(value="X-Client-Id", required=false) String xClientId,@Parameter(in = ParameterIn.HEADER, description = "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." ,schema=@Schema()) @RequestHeader(value="X-Content-Hash", required=false) String xContentHash,@Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-1", required=false) String xUserCredential1,@Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-2", required=false) String xUserCredential2,@Parameter(in = ParameterIn.HEADER, description = "String containing the channel that was used to originate the request. For example USSD, Web, App." ,schema=@Schema()) @RequestHeader(value="X-Channel", required=false) String xChannel,@Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." ,schema=@Schema(allowableValues={ "lei", "swiftbic", "organisationid" } +)) @RequestHeader(value="X-Account-Holding-Institution-Identifier-Type", required=false) String xAccountHoldingInstitutionIdentifierType,@Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." ,schema=@Schema()) @RequestHeader(value="X-Account-Holding-Institution-Identifier", required=false) String xAccountHoldingInstitutionIdentifier) { + String accept = request.getHeader("Accept"); + if (accept != null && accept.contains("application/json")) { + try { + return new ResponseEntity(objectMapper.readValue("{\n \"recipientKyc\" : {\n \"emailAddress\" : \"emailAddress\",\n \"occupation\" : \"occupation\",\n \"postalAddress\" : {\n \"city\" : \"city\",\n \"postalCode\" : \"postalCode\",\n \"addressLine1\" : \"addressLine1\",\n \"stateProvince\" : \"stateProvince\",\n \"addressLine2\" : \"addressLine2\",\n \"addressLine3\" : \"addressLine3\"\n },\n \"gender\" : \"m\",\n \"idDocument\" : [ {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n }, {\n \"expiryDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"idType\" : \"passport\",\n \"issuerPlace\" : \"issuerPlace\",\n \"otherIddescription\" : \"otherIddescription\",\n \"idNumber\" : \"idNumber\",\n \"issueDate\" : \"2018-11-20T00:00:00.000+00:00\",\n \"issuer\" : \"issuer\"\n } ],\n \"employerName\" : \"employerName\",\n \"dateOfBirth\" : \"2000-11-20T00:00:00.000+00:00\",\n \"contactPhone\" : \"contactPhone\",\n \"subjectName\" : {\n \"firstName\" : \"firstName\",\n \"lastName\" : \"lastName\",\n \"nativeName\" : \"nativeName\",\n \"fullName\" : \"fullName\",\n \"middleName\" : \"middleName\",\n \"title\" : \"title\"\n }\n },\n \"debitParty\" : [ null, null, null, null, null, null, null, null, null, null ],\n \"fees\" : [ {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n } ],\n \"metadata\" : [ {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n } ],\n \"customData\" : [ {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n } ],\n \"requestingLei\" : \"requestingLei\",\n \"descriptionText\" : \"descriptionText\",\n \"type\" : \"billpay\",\n \"dateCreated\" : \"2000-01-23T04:56:07.000+00:00\",\n \"transactionReceipt\" : \"transactionReceipt\",\n \"oneTimeCode\" : \"oneTimeCode\",\n \"requestDate\" : \"2000-01-23T04:56:07.000+00:00\",\n \"currency\" : \"AED\",\n \"originalTransactionReference\" : \"originalTransactionReference\",\n \"amount\" : \"15.21\",\n \"transactionReference\" : \"transactionReference\",\n \"transactionStatus\" : \"transactionStatus\",\n \"internationalTransferInformation\" : {\n \"quotationReference\" : \"quotationReference\",\n \"deliveryMethod\" : \"directtoaccount\",\n \"originCountry\" : \"AD\",\n \"relationshipSender\" : \"relationshipSender\",\n \"remittancePurpose\" : \"remittancePurpose\",\n \"senderBlockingReason\" : \"senderBlockingReason\",\n \"quoteId\" : \"quoteId\",\n \"recipientBlockingReason\" : \"recipientBlockingReason\"\n },\n \"requestingOrganisation\" : {\n \"requestingOrganisationIdentifierType\" : \"lei\",\n \"requestingOrganisationIdentifier\" : \"requestingOrganisationIdentifier\"\n },\n \"geoCode\" : \"37.423825,-122.082900\",\n \"dateModified\" : \"2000-01-23T04:56:07.000+00:00\",\n \"creationDate\" : \"2000-01-23T04:56:07.000+00:00\",\n \"modificationDate\" : \"2000-01-23T04:56:07.000+00:00\",\n \"receivingLei\" : \"receivingLei\",\n \"servicingIdentity\" : \"servicingIdentity\",\n \"requestingOrganisationTransactionReference\" : \"requestingOrganisationTransactionReference\",\n \"subType\" : \"subType\",\n \"creditParty\" : [ {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n } ]\n}", ResponseTransaction.class), HttpStatus.OK); + } catch (IOException e) { + log.error("Couldn't serialize response for content type application/json", e); + return new ResponseEntity(HttpStatus.INTERNAL_SERVER_ERROR); + } + } + + return new ResponseEntity(HttpStatus.OK); + } + + public ResponseEntity transactionsTransactionReferencePATCH(@Size(min=1,max=256) @Parameter(in = ParameterIn.PATH, description = "Path variable to uniquely identify the transaction.", required=true, schema=@Schema()) @PathVariable("transactionReference") String transactionReference,@Parameter(in = ParameterIn.DEFAULT, description = "Represents the request body of a batch of generic Patch operation.", required=true, schema=@Schema()) @Valid @RequestBody List body,@Parameter(in = ParameterIn.HEADER, description = "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." ,schema=@Schema()) @RequestHeader(value="X-Date", required=false) OffsetDateTime xDate,@Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's API key to the server." ,schema=@Schema()) @RequestHeader(value="X-API-Key", required=false) String xAPIKey,@Parameter(in = ParameterIn.HEADER, description = "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication." ,schema=@Schema()) @RequestHeader(value="X-User-Bearer", required=false) String xUserBearer,@Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's identifier to the server." ,schema=@Schema()) @RequestHeader(value="X-Client-Id", required=false) String xClientId,@Parameter(in = ParameterIn.HEADER, description = "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." ,schema=@Schema()) @RequestHeader(value="X-Content-Hash", required=false) String xContentHash,@Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-1", required=false) String xUserCredential1,@Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-2", required=false) String xUserCredential2,@Parameter(in = ParameterIn.HEADER, description = "String containing the channel that was used to originate the request. For example USSD, Web, App." ,schema=@Schema()) @RequestHeader(value="X-Channel", required=false) String xChannel,@Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." ,schema=@Schema(allowableValues={ "lei", "swiftbic", "organisationid" } +)) @RequestHeader(value="X-Account-Holding-Institution-Identifier-Type", required=false) String xAccountHoldingInstitutionIdentifierType,@Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." ,schema=@Schema()) @RequestHeader(value="X-Account-Holding-Institution-Identifier", required=false) String xAccountHoldingInstitutionIdentifier,@Parameter(in = ParameterIn.HEADER, description = "Header parameter to uniquely identify the request. Must be supplied as a UUID." ,schema=@Schema()) @RequestHeader(value="X-CorrelationID", required=false) String xCorrelationID,@Parameter(in = ParameterIn.HEADER, description = "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." ,schema=@Schema()) @RequestHeader(value="X-Callback-URL", required=false) String xCallbackURL) { + String accept = request.getHeader("Accept"); + if (accept != null && accept.contains("application/json")) { + try { + return new ResponseEntity(objectMapper.readValue("{\n \"pollLimit\" : 0.08008281904610115,\n \"pendingReason\" : \"pendingReason\",\n \"expiryTime\" : \"2000-01-23T04:56:07.000+00:00\",\n \"objectReference\" : \"objectReference\",\n \"notificationMethod\" : \"callback\",\n \"error\" : {\n \"errordescription\" : \"errordescription\",\n \"errorCategory\" : \"businessRule\",\n \"errorParameters\" : [ {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n } ],\n \"errorDateTime\" : \"2000-01-23T04:56:07.000+00:00\",\n \"errorCode\" : \"genericError\"\n },\n \"serverCorrelationId\" : \"serverCorrelationId\",\n \"status\" : \"pending\"\n}", RequestStateObject.class), HttpStatus.OK); + } catch (IOException e) { + log.error("Couldn't serialize response for content type application/json", e); + return new ResponseEntity(HttpStatus.INTERNAL_SERVER_ERROR); + } + } + + return new ResponseEntity(HttpStatus.OK); + } + + public ResponseEntity transactionsTransactionReferenceReversalsPOST(@Size(min=1,max=256) @Parameter(in = ParameterIn.PATH, description = "Path variable to uniquely identify the transaction.", required=true, schema=@Schema()) @PathVariable("transactionReference") String transactionReference,@Parameter(in = ParameterIn.DEFAULT, description = "Represents the request body of a transaction reversal.", required=true, schema=@Schema()) @Valid @RequestBody RequestReversal body,@Parameter(in = ParameterIn.HEADER, description = "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." ,schema=@Schema()) @RequestHeader(value="X-Date", required=false) OffsetDateTime xDate,@Parameter(in = ParameterIn.HEADER, description = "Header parameter to uniquely identify the request. Must be supplied as a UUID." ,schema=@Schema()) @RequestHeader(value="X-CorrelationID", required=false) String xCorrelationID,@Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's API key to the server." ,schema=@Schema()) @RequestHeader(value="X-API-Key", required=false) String xAPIKey,@Parameter(in = ParameterIn.HEADER, description = "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication." ,schema=@Schema()) @RequestHeader(value="X-User-Bearer", required=false) String xUserBearer,@Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's identifier to the server." ,schema=@Schema()) @RequestHeader(value="X-Client-Id", required=false) String xClientId,@Parameter(in = ParameterIn.HEADER, description = "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." ,schema=@Schema()) @RequestHeader(value="X-Content-Hash", required=false) String xContentHash,@Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-1", required=false) String xUserCredential1,@Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-2", required=false) String xUserCredential2,@Parameter(in = ParameterIn.HEADER, description = "String containing the channel that was used to originate the request. For example USSD, Web, App." ,schema=@Schema()) @RequestHeader(value="X-Channel", required=false) String xChannel,@Parameter(in = ParameterIn.HEADER, description = "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." ,schema=@Schema()) @RequestHeader(value="X-Callback-URL", required=false) String xCallbackURL,@Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." ,schema=@Schema(allowableValues={ "lei", "swiftbic", "organisationid" } +)) @RequestHeader(value="X-Account-Holding-Institution-Identifier-Type", required=false) String xAccountHoldingInstitutionIdentifierType,@Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." ,schema=@Schema()) @RequestHeader(value="X-Account-Holding-Institution-Identifier", required=false) String xAccountHoldingInstitutionIdentifier) { + String accept = request.getHeader("Accept"); + if (accept != null && accept.contains("application/json")) { + try { + return new ResponseEntity(objectMapper.readValue("{\n \"fees\" : [ {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n }, {\n \"feeType\" : \"feeType\"\n } ],\n \"metadata\" : [ {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n } ],\n \"customData\" : [ {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n }, {\n \"value\" : \"value\",\n \"key\" : \"key\"\n } ],\n \"requestingLei\" : \"requestingLei\",\n \"descriptionText\" : \"descriptionText\",\n \"type\" : \"reversal\",\n \"dateCreated\" : \"2000-01-23T04:56:07.000+00:00\",\n \"transactionReceipt\" : \"transactionReceipt\",\n \"requestDate\" : \"2000-01-23T04:56:07.000+00:00\",\n \"currency\" : \"AED\",\n \"originalTransactionReference\" : \"originalTransactionReference\",\n \"amount\" : \"15.21\",\n \"transactionReference\" : \"transactionReference\",\n \"transactionStatus\" : \"transactionStatus\",\n \"requestingOrganisation\" : {\n \"requestingOrganisationIdentifierType\" : \"lei\",\n \"requestingOrganisationIdentifier\" : \"requestingOrganisationIdentifier\"\n },\n \"geoCode\" : \"37.423825,-122.082900\",\n \"dateModified\" : \"2000-01-23T04:56:07.000+00:00\",\n \"creationDate\" : \"2000-01-23T04:56:07.000+00:00\",\n \"modificationDate\" : \"2000-01-23T04:56:07.000+00:00\",\n \"receivingLei\" : \"receivingLei\",\n \"servicingIdentity\" : \"servicingIdentity\",\n \"requestingOrganisationTransactionReference\" : \"requestingOrganisationTransactionReference\",\n \"subType\" : \"subType\",\n \"creditParty\" : [ {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n }, {\n \"value\" : \"+33555123456\",\n \"key\" : \"msisdn\"\n } ]\n}", ResponseReversal.class), HttpStatus.OK); + } catch (IOException e) { + log.error("Couldn't serialize response for content type application/json", e); + return new ResponseEntity(HttpStatus.INTERNAL_SERVER_ERROR); + } + } + + return new ResponseEntity(HttpStatus.OK); + } + + public ResponseEntity transactionstypetransactionTypePUT(@Parameter(in = ParameterIn.PATH, description = "Identifies the type of transaction that is to be created.", required=true, schema=@Schema(allowableValues={ "billpay", "deposit", "disbursement", "transfer", "merchantpay", "inttransfer", "adjustment", "reversal", "withdrawal" } +)) @PathVariable("transactionType") String transactionType,@Parameter(in = ParameterIn.DEFAULT, description = "Represents the request body of a transaction without Type.", required=true, schema=@Schema()) @Valid @RequestBody RequestTransactionType body,@Parameter(in = ParameterIn.HEADER, description = "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." ,schema=@Schema()) @RequestHeader(value="X-Date", required=false) OffsetDateTime xDate,@Parameter(in = ParameterIn.HEADER, description = "Header parameter to uniquely identify the request. Must be supplied as a UUID." ,schema=@Schema()) @RequestHeader(value="X-CorrelationID", required=false) String xCorrelationID,@Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's API key to the server." ,schema=@Schema()) @RequestHeader(value="X-API-Key", required=false) String xAPIKey,@Parameter(in = ParameterIn.HEADER, description = "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication." ,schema=@Schema()) @RequestHeader(value="X-User-Bearer", required=false) String xUserBearer,@Parameter(in = ParameterIn.HEADER, description = "Used to pass pre-shared client's identifier to the server." ,schema=@Schema()) @RequestHeader(value="X-Client-Id", required=false) String xClientId,@Parameter(in = ParameterIn.HEADER, description = "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." ,schema=@Schema()) @RequestHeader(value="X-Content-Hash", required=false) String xContentHash,@Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-1", required=false) String xUserCredential1,@Parameter(in = ParameterIn.HEADER, description = "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." ,schema=@Schema()) @RequestHeader(value="X-User-Credential-2", required=false) String xUserCredential2,@Parameter(in = ParameterIn.HEADER, description = "String containing the channel that was used to originate the request. For example USSD, Web, App." ,schema=@Schema()) @RequestHeader(value="X-Channel", required=false) String xChannel,@Parameter(in = ParameterIn.HEADER, description = "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." ,schema=@Schema()) @RequestHeader(value="X-Callback-URL", required=false) String xCallbackURL,@Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." ,schema=@Schema(allowableValues={ "lei", "swiftbic", "organisationid" } +)) @RequestHeader(value="X-Account-Holding-Institution-Identifier-Type", required=false) String xAccountHoldingInstitutionIdentifierType,@Parameter(in = ParameterIn.HEADER, description = "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." ,schema=@Schema()) @RequestHeader(value="X-Account-Holding-Institution-Identifier", required=false) String xAccountHoldingInstitutionIdentifier) { + String accept = request.getHeader("Accept"); + if (accept != null && accept.contains("application/json")) { + try { + return new ResponseEntity(objectMapper.readValue("{}", ResponseTransactionType.class), HttpStatus.OK); + } catch (IOException e) { + log.error("Couldn't serialize response for content type application/json", e); + return new ResponseEntity(HttpStatus.INTERNAL_SERVER_ERROR); + } + } + + return new ResponseEntity(HttpStatus.OK); + } + +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/configuration/CustomInstantDeserializer.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/configuration/CustomInstantDeserializer.java new file mode 100644 index 000000000..fdb9556f4 --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/configuration/CustomInstantDeserializer.java @@ -0,0 +1,244 @@ +package org.mifos.connector.gsmastub.configuration; + +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.JsonTokenId; +import com.fasterxml.jackson.databind.*; +import com.fasterxml.jackson.datatype.threetenbp.DecimalUtils; +import com.fasterxml.jackson.datatype.threetenbp.deser.ThreeTenDateTimeDeserializerBase; +import com.fasterxml.jackson.datatype.threetenbp.function.BiFunction; +import com.fasterxml.jackson.datatype.threetenbp.function.Function; +import org.threeten.bp.*; +import org.threeten.bp.format.DateTimeFormatter; +import org.threeten.bp.temporal.Temporal; +import org.threeten.bp.temporal.TemporalAccessor; + +import java.io.IOException; +import java.math.BigDecimal; + +/** + * Deserializer for ThreeTen temporal {@link Instant}s, {@link OffsetDateTime}, and {@link ZonedDateTime}s. + * Adapted from the jackson threetenbp InstantDeserializer to add support for deserializing rfc822 format. + * + * @author Nick Williams + */ +public class CustomInstantDeserializer + extends ThreeTenDateTimeDeserializerBase { + private static final long serialVersionUID = 1L; + + public static class LocalDateSerializer extends JsonSerializer { + @Override + public void serialize(LocalDate arg0, JsonGenerator arg1, SerializerProvider arg2) throws IOException { + arg1.writeString(arg0.toString()); + } + } + + public static class LocalDateDeserializer extends JsonDeserializer { + @Override + public LocalDate deserialize(JsonParser arg0, DeserializationContext arg1) throws IOException { + try { + return LocalDate.parse(arg0.getText(), DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSXXX")); + } catch (Exception e) { + return LocalDate.parse(arg0.getText(), DateTimeFormatter.ofPattern("yyyy-MM-dd")); + } + } + } + + public static final CustomInstantDeserializer INSTANT = new CustomInstantDeserializer( + Instant.class, DateTimeFormatter.ISO_INSTANT, + new Function() { + @Override + public Instant apply(TemporalAccessor temporalAccessor) { + return Instant.from(temporalAccessor); + } + }, + new Function() { + @Override + public Instant apply(FromIntegerArguments a) { + return Instant.ofEpochMilli(a.value); + } + }, + new Function() { + @Override + public Instant apply(FromDecimalArguments a) { + return Instant.ofEpochSecond(a.integer, a.fraction); + } + }, + null + ); + + public static final CustomInstantDeserializer OFFSET_DATE_TIME = new CustomInstantDeserializer( + OffsetDateTime.class, DateTimeFormatter.ISO_OFFSET_DATE_TIME, + new Function() { + @Override + public OffsetDateTime apply(TemporalAccessor temporalAccessor) { + return OffsetDateTime.from(temporalAccessor); + } + }, + new Function() { + @Override + public OffsetDateTime apply(FromIntegerArguments a) { + return OffsetDateTime.ofInstant(Instant.ofEpochMilli(a.value), a.zoneId); + } + }, + new Function() { + @Override + public OffsetDateTime apply(FromDecimalArguments a) { + return OffsetDateTime.ofInstant(Instant.ofEpochSecond(a.integer, a.fraction), a.zoneId); + } + }, + new BiFunction() { + @Override + public OffsetDateTime apply(OffsetDateTime d, ZoneId z) { + return d.withOffsetSameInstant(z.getRules().getOffset(d.toLocalDateTime())); + } + } + ); + + public static final CustomInstantDeserializer ZONED_DATE_TIME = new CustomInstantDeserializer( + ZonedDateTime.class, DateTimeFormatter.ISO_ZONED_DATE_TIME, + new Function() { + @Override + public ZonedDateTime apply(TemporalAccessor temporalAccessor) { + return ZonedDateTime.from(temporalAccessor); + } + }, + new Function() { + @Override + public ZonedDateTime apply(FromIntegerArguments a) { + return ZonedDateTime.ofInstant(Instant.ofEpochMilli(a.value), a.zoneId); + } + }, + new Function() { + @Override + public ZonedDateTime apply(FromDecimalArguments a) { + return ZonedDateTime.ofInstant(Instant.ofEpochSecond(a.integer, a.fraction), a.zoneId); + } + }, + new BiFunction() { + @Override + public ZonedDateTime apply(ZonedDateTime zonedDateTime, ZoneId zoneId) { + return zonedDateTime.withZoneSameInstant(zoneId); + } + } + ); + + protected final Function fromMilliseconds; + + protected final Function fromNanoseconds; + + protected final Function parsedToValue; + + protected final BiFunction adjust; + + protected CustomInstantDeserializer(Class supportedType, + DateTimeFormatter parser, + Function parsedToValue, + Function fromMilliseconds, + Function fromNanoseconds, + BiFunction adjust) { + super(supportedType, parser); + this.parsedToValue = parsedToValue; + this.fromMilliseconds = fromMilliseconds; + this.fromNanoseconds = fromNanoseconds; + this.adjust = adjust == null ? new BiFunction() { + @Override + public T apply(T t, ZoneId zoneId) { + return t; + } + } : adjust; + } + + @SuppressWarnings("unchecked") + protected CustomInstantDeserializer(CustomInstantDeserializer base, DateTimeFormatter f) { + super((Class) base.handledType(), f); + parsedToValue = base.parsedToValue; + fromMilliseconds = base.fromMilliseconds; + fromNanoseconds = base.fromNanoseconds; + adjust = base.adjust; + } + + @Override + protected JsonDeserializer withDateFormat(DateTimeFormatter dtf) { + if (dtf == _formatter) { + return this; + } + return new CustomInstantDeserializer(this, dtf); + } + + @Override + public T deserialize(JsonParser parser, DeserializationContext context) throws IOException { + //NOTE: Timestamps contain no timezone info, and are always in configured TZ. Only + //string values have to be adjusted to the configured TZ. + switch (parser.getCurrentTokenId()) { + case JsonTokenId.ID_NUMBER_FLOAT: { + BigDecimal value = parser.getDecimalValue(); + long seconds = value.longValue(); + int nanoseconds = DecimalUtils.extractNanosecondDecimal(value, seconds); + return fromNanoseconds.apply(new FromDecimalArguments( + seconds, nanoseconds, getZone(context))); + } + + case JsonTokenId.ID_NUMBER_INT: { + long timestamp = parser.getLongValue(); + if (context.isEnabled(DeserializationFeature.READ_DATE_TIMESTAMPS_AS_NANOSECONDS)) { + return this.fromNanoseconds.apply(new FromDecimalArguments( + timestamp, 0, this.getZone(context) + )); + } + return this.fromMilliseconds.apply(new FromIntegerArguments( + timestamp, this.getZone(context) + )); + } + + case JsonTokenId.ID_STRING: { + String string = parser.getText().trim(); + if (string.length() == 0) { + return null; + } + if (string.endsWith("+0000")) { + string = string.substring(0, string.length() - 5) + "Z"; + } + T value; + try { + TemporalAccessor acc = _formatter.parse(string); + value = parsedToValue.apply(acc); + if (context.isEnabled(DeserializationFeature.ADJUST_DATES_TO_CONTEXT_TIME_ZONE)) { + return adjust.apply(value, this.getZone(context)); + } + } catch (DateTimeException e) { + throw _peelDTE(e); + } + return value; + } + } + throw context.mappingException("Expected type float, integer, or string."); + } + + private ZoneId getZone(DeserializationContext context) { + // Instants are always in UTC, so don't waste compute cycles + return (_valueClass == Instant.class) ? null : DateTimeUtils.toZoneId(context.getTimeZone()); + } + + private static class FromIntegerArguments { + public final long value; + public final ZoneId zoneId; + + private FromIntegerArguments(long value, ZoneId zoneId) { + this.value = value; + this.zoneId = zoneId; + } + } + + private static class FromDecimalArguments { + public final long integer; + public final int fraction; + public final ZoneId zoneId; + + private FromDecimalArguments(long integer, int fraction, ZoneId zoneId) { + this.integer = integer; + this.fraction = fraction; + this.zoneId = zoneId; + } + } +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/configuration/JacksonConfiguration.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/configuration/JacksonConfiguration.java new file mode 100644 index 000000000..61195a0db --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/configuration/JacksonConfiguration.java @@ -0,0 +1,23 @@ +package org.mifos.connector.gsmastub.configuration; + +import com.fasterxml.jackson.datatype.threetenbp.ThreeTenModule; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.threeten.bp.Instant; +import org.threeten.bp.OffsetDateTime; +import org.threeten.bp.ZonedDateTime; + +@Configuration +public class JacksonConfiguration { + + @Bean + @ConditionalOnMissingBean(ThreeTenModule.class) + ThreeTenModule threeTenModule() { + ThreeTenModule module = new ThreeTenModule(); + module.addDeserializer(Instant.class, CustomInstantDeserializer.INSTANT); + module.addDeserializer(OffsetDateTime.class, CustomInstantDeserializer.OFFSET_DATE_TIME); + module.addDeserializer(ZonedDateTime.class, CustomInstantDeserializer.ZONED_DATE_TIME); + return module; + } +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/configuration/LocalDateConverter.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/configuration/LocalDateConverter.java new file mode 100644 index 000000000..38fd714ed --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/configuration/LocalDateConverter.java @@ -0,0 +1,21 @@ +package org.mifos.connector.gsmastub.configuration; + +import org.springframework.core.convert.converter.Converter; +import org.threeten.bp.LocalDate; +import org.threeten.bp.format.DateTimeFormatter; + +public class LocalDateConverter implements Converter { + private final DateTimeFormatter formatter; + + public LocalDateConverter(String dateFormat) { + this.formatter = DateTimeFormatter.ofPattern(dateFormat); + } + + @Override + public LocalDate convert(String source) { + if(source == null || source.isEmpty()) { + return null; + } + return LocalDate.parse(source, this.formatter); + } +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/configuration/LocalDateTimeConverter.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/configuration/LocalDateTimeConverter.java new file mode 100644 index 000000000..3d736f5d4 --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/configuration/LocalDateTimeConverter.java @@ -0,0 +1,21 @@ +package org.mifos.connector.gsmastub.configuration; + +import org.springframework.core.convert.converter.Converter; +import org.threeten.bp.LocalDateTime; +import org.threeten.bp.format.DateTimeFormatter; + +public class LocalDateTimeConverter implements Converter { + private final DateTimeFormatter formatter; + + public LocalDateTimeConverter(String dateFormat) { + this.formatter = DateTimeFormatter.ofPattern(dateFormat); + } + + @Override + public LocalDateTime convert(String source) { + if(source == null || source.isEmpty()) { + return null; + } + return LocalDateTime.parse(source, this.formatter); + } +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/AccountIdentifiersArray.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/AccountIdentifiersArray.java new file mode 100644 index 000000000..b70f9a0d1 --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/AccountIdentifiersArray.java @@ -0,0 +1,51 @@ +package org.mifos.connector.gsmastub.model; + +import org.springframework.validation.annotation.Validated; +import java.util.ArrayList; +import java.util.Objects; + +/** + * A collection of key/value pairs that enable the account to be identified. Keys include MSISDN and Wallet Identifier. + */ +@Validated +@javax.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.SpringCodegen", date = "2022-09-27T11:46:46.417Z[GMT]") + + +public class AccountIdentifiersArray extends ArrayList { + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + return true; + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode()); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class AccountIdentifiersArray {\n"); + sb.append(" ").append(toIndentedString(super.toString())).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/AccountRelationship.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/AccountRelationship.java new file mode 100644 index 000000000..59fc0d9b8 --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/AccountRelationship.java @@ -0,0 +1,33 @@ +package org.mifos.connector.gsmastub.model; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonValue; + +/** + * Describes the relationship that the identity holds with the account. + */ +public enum AccountRelationship { + ACCOUNTHOLDER("accountholder"); + + private String value; + + AccountRelationship(String value) { + this.value = value; + } + + @Override + @JsonValue + public String toString() { + return String.valueOf(value); + } + + @JsonCreator + public static AccountRelationship fromValue(String text) { + for (AccountRelationship b : AccountRelationship.values()) { + if (String.valueOf(b.value).equals(text)) { + return b; + } + } + return null; + } +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/AccountStatus.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/AccountStatus.java new file mode 100644 index 000000000..2fd9b9e09 --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/AccountStatus.java @@ -0,0 +1,35 @@ +package org.mifos.connector.gsmastub.model; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonValue; + +/** + * Indicates a harmonised representation of the account status. This will be shown as available, unavailable or unregistered. + */ +public enum AccountStatus { + AVAILABLE("available"), + UNAVAILABLE("unavailable"), + UNREGISTERED("unregistered"); + + private String value; + + AccountStatus(String value) { + this.value = value; + } + + @Override + @JsonValue + public String toString() { + return String.valueOf(value); + } + + @JsonCreator + public static AccountStatus fromValue(String text) { + for (AccountStatus b : AccountStatus.values()) { + if (String.valueOf(b.value).equals(text)) { + return b; + } + } + return null; + } +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/AmountType.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/AmountType.java new file mode 100644 index 000000000..92e8af981 --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/AmountType.java @@ -0,0 +1,34 @@ +package org.mifos.connector.gsmastub.model; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonValue; + +/** + * The amount for the authorisation can be an exact amount or can be a maximum amount. + */ +public enum AmountType { + EXACT("exact"), + MAXIMUM("maximum"); + + private String value; + + AmountType(String value) { + this.value = value; + } + + @Override + @JsonValue + public String toString() { + return String.valueOf(value); + } + + @JsonCreator + public static AmountType fromValue(String text) { + for (AmountType b : AmountType.values()) { + if (String.valueOf(b.value).equals(text)) { + return b; + } + } + return null; + } +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/BatchStatus.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/BatchStatus.java new file mode 100644 index 000000000..84e535787 --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/BatchStatus.java @@ -0,0 +1,35 @@ +package org.mifos.connector.gsmastub.model; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonValue; + +/** + * Gets or Sets batchStatus + */ +public enum BatchStatus { + CREATED("created"), + APPROVED("approved"), + COMPLETED("completed"); + + private String value; + + BatchStatus(String value) { + this.value = value; + } + + @Override + @JsonValue + public String toString() { + return String.valueOf(value); + } + + @JsonCreator + public static BatchStatus fromValue(String text) { + for (BatchStatus b : BatchStatus.values()) { + if (String.valueOf(b.value).equals(text)) { + return b; + } + } + return null; + } +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/BillStatus.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/BillStatus.java new file mode 100644 index 000000000..822014123 --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/BillStatus.java @@ -0,0 +1,35 @@ +package org.mifos.connector.gsmastub.model; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonValue; + +/** + * Gets or Sets billStatus + */ +public enum BillStatus { + UNPAID("unpaid"), + PAID("paid"), + PARTIALPAID("partialpaid"); + + private String value; + + BillStatus(String value) { + this.value = value; + } + + @Override + @JsonValue + public String toString() { + return String.valueOf(value); + } + + @JsonCreator + public static BillStatus fromValue(String text) { + for (BillStatus b : BillStatus.values()) { + if (String.valueOf(b.value).equals(text)) { + return b; + } + } + return null; + } +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/CodeState.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/CodeState.java new file mode 100644 index 000000000..a1bf2f851 --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/CodeState.java @@ -0,0 +1,35 @@ +package org.mifos.connector.gsmastub.model; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonValue; + +/** + * Indicates the state of the Authorisation Code. + */ +public enum CodeState { + ACTIVE("active"), + EXPIRED("expired"), + CANCELLED("cancelled"); + + private String value; + + CodeState(String value) { + this.value = value; + } + + @Override + @JsonValue + public String toString() { + return String.valueOf(value); + } + + @JsonCreator + public static CodeState fromValue(String text) { + for (CodeState b : CodeState.values()) { + if (String.valueOf(b.value).equals(text)) { + return b; + } + } + return null; + } +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/CommissionEarned.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/CommissionEarned.java new file mode 100644 index 000000000..c1bd4a99a --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/CommissionEarned.java @@ -0,0 +1,133 @@ +package org.mifos.connector.gsmastub.model; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import org.springframework.validation.annotation.Validated; + +import javax.validation.Valid; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Pattern; +import javax.validation.constraints.Size; +import java.util.Objects; + +/** + * CommissionEarned + */ +@Validated +@javax.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.SpringCodegen", date = "2022-09-27T11:46:46.417Z[GMT]") + + +public class CommissionEarned { + @JsonProperty("commissionType") + private String commissionType = null; + + @JsonProperty("commissionAmount") + private String commissionAmount = null; + + @JsonProperty("commissionCurrency") + private Currency commissionCurrency = null; + + public CommissionEarned commissionType(String commissionType) { + this.commissionType = commissionType; + return this; + } + + /** + * Defines the type of commission. + * @return commissionType + **/ + @Schema(required = true, description = "Defines the type of commission.") + @NotNull + + @Size(min=1,max=256) public String getCommissionType() { + return commissionType; + } + + public void setCommissionType(String commissionType) { + this.commissionType = commissionType; + } + + public CommissionEarned commissionAmount(String commissionAmount) { + this.commissionAmount = commissionAmount; + return this; + } + + /** + * Get commissionAmount + * @return commissionAmount + **/ + @Schema(example = "15.21", required = true, description = "") + @NotNull + + @Pattern(regexp="^([0]|([1-9][0-9]{0,17}))([.][0-9]{0,3}[0-9])?$") @Size(min=1,max=23) public String getCommissionAmount() { + return commissionAmount; + } + + public void setCommissionAmount(String commissionAmount) { + this.commissionAmount = commissionAmount; + } + + public CommissionEarned commissionCurrency(Currency commissionCurrency) { + this.commissionCurrency = commissionCurrency; + return this; + } + + /** + * Get commissionCurrency + * @return commissionCurrency + **/ + @Schema(required = true, description = "") + @NotNull + + @Valid + public Currency getCommissionCurrency() { + return commissionCurrency; + } + + public void setCommissionCurrency(Currency commissionCurrency) { + this.commissionCurrency = commissionCurrency; + } + + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + CommissionEarned commissionEarned = (CommissionEarned) o; + return Objects.equals(this.commissionType, commissionEarned.commissionType) && + Objects.equals(this.commissionAmount, commissionEarned.commissionAmount) && + Objects.equals(this.commissionCurrency, commissionEarned.commissionCurrency); + } + + @Override + public int hashCode() { + return Objects.hash(commissionType, commissionAmount, commissionCurrency); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class CommissionEarned {\n"); + + sb.append(" commissionType: ").append(toIndentedString(commissionType)).append("\n"); + sb.append(" commissionAmount: ").append(toIndentedString(commissionAmount)).append("\n"); + sb.append(" commissionCurrency: ").append(toIndentedString(commissionCurrency)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/CommissionEarnedArray.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/CommissionEarnedArray.java new file mode 100644 index 000000000..d2134c39b --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/CommissionEarnedArray.java @@ -0,0 +1,54 @@ +package org.mifos.connector.gsmastub.model; + +import io.swagger.v3.oas.annotations.media.Schema; +import org.springframework.validation.annotation.Validated; + +import java.util.ArrayList; +import java.util.Objects; + +/** + * Returns all commission earned by the registering entity for the creation of the account. + */ +@Schema(description = "Returns all commission earned by the registering entity for the creation of the account.") +@Validated +@javax.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.SpringCodegen", date = "2022-09-27T11:46:46.417Z[GMT]") + + +public class CommissionEarnedArray extends ArrayList { + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + return true; + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode()); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class CommissionEarnedArray {\n"); + sb.append(" ").append(toIndentedString(super.toString())).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/CreditPartyArray.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/CreditPartyArray.java new file mode 100644 index 000000000..499b43d7c --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/CreditPartyArray.java @@ -0,0 +1,54 @@ +package org.mifos.connector.gsmastub.model; + +import io.swagger.v3.oas.annotations.media.Schema; +import org.springframework.validation.annotation.Validated; + +import java.util.ArrayList; +import java.util.Objects; + +/** + * A collection of key/value pairs that enable the party to be identified. Keys include MSISDN and Wallet Identifier. + */ +@Schema(description = "A collection of key/value pairs that enable the party to be identified. Keys include MSISDN and Wallet Identifier.") +@Validated +@javax.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.SpringCodegen", date = "2022-09-27T11:46:46.417Z[GMT]") + + +public class CreditPartyArray extends ArrayList { + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + return true; + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode()); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class CreditPartyArray {\n"); + sb.append(" ").append(toIndentedString(super.toString())).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/Currency.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/Currency.java new file mode 100644 index 000000000..a6b2b0878 --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/Currency.java @@ -0,0 +1,210 @@ +package org.mifos.connector.gsmastub.model; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonValue; + +/** + * Gets or Sets currency + */ +public enum Currency { + AED("AED"), + AFN("AFN"), + ALL("ALL"), + AMD("AMD"), + ANG("ANG"), + AOA("AOA"), + ARS("ARS"), + AUD("AUD"), + AWG("AWG"), + AZN("AZN"), + BAM("BAM"), + BBD("BBD"), + BDT("BDT"), + BGN("BGN"), + BHD("BHD"), + BIF("BIF"), + BMD("BMD"), + BND("BND"), + BOB("BOB"), + BOV("BOV"), + BRL("BRL"), + BSD("BSD"), + BTN("BTN"), + BWP("BWP"), + BYN("BYN"), + BZD("BZD"), + CAD("CAD"), + CDF("CDF"), + CHE("CHE"), + CHF("CHF"), + CHW("CHW"), + CLF("CLF"), + CLP("CLP"), + CNY("CNY"), + COP("COP"), + COU("COU"), + CRC("CRC"), + CUC("CUC"), + CUP("CUP"), + CVE("CVE"), + CZK("CZK"), + DJF("DJF"), + DKK("DKK"), + DOP("DOP"), + DZD("DZD"), + EGP("EGP"), + ERN("ERN"), + ETB("ETB"), + EUR("EUR"), + FJD("FJD"), + FKP("FKP"), + GBP("GBP"), + GEL("GEL"), + GHS("GHS"), + GIP("GIP"), + GMD("GMD"), + GNF("GNF"), + GTQ("GTQ"), + GYD("GYD"), + HKD("HKD"), + HNL("HNL"), + HRK("HRK"), + HTG("HTG"), + HUF("HUF"), + IDR("IDR"), + ILS("ILS"), + INR("INR"), + IQD("IQD"), + IRR("IRR"), + ISK("ISK"), + JMD("JMD"), + JOD("JOD"), + JPY("JPY"), + KES("KES"), + KGS("KGS"), + KHR("KHR"), + KMF("KMF"), + KPW("KPW"), + KRW("KRW"), + KWD("KWD"), + KYD("KYD"), + KZT("KZT"), + LAK("LAK"), + LBP("LBP"), + LKR("LKR"), + LRD("LRD"), + LSL("LSL"), + LYD("LYD"), + MAD("MAD"), + MDL("MDL"), + MGA("MGA"), + MKD("MKD"), + MMK("MMK"), + MNT("MNT"), + MOP("MOP"), + MRO("MRO"), + MUR("MUR"), + MVR("MVR"), + MWK("MWK"), + MXN("MXN"), + MXV("MXV"), + MYR("MYR"), + MZN("MZN"), + NAD("NAD"), + NGN("NGN"), + NIO("NIO"), + NOK("NOK"), + NPR("NPR"), + NZD("NZD"), + OMR("OMR"), + PAB("PAB"), + PEN("PEN"), + PGK("PGK"), + PHP("PHP"), + PKR("PKR"), + PLN("PLN"), + PYG("PYG"), + QAR("QAR"), + RON("RON"), + RSD("RSD"), + RUB("RUB"), + RWF("RWF"), + SAR("SAR"), + SBD("SBD"), + SCR("SCR"), + SDG("SDG"), + SEK("SEK"), + SGD("SGD"), + SHP("SHP"), + SLL("SLL"), + SOS("SOS"), + SRD("SRD"), + SSP("SSP"), + STD("STD"), + SVC("SVC"), + SYP("SYP"), + SZL("SZL"), + THB("THB"), + TJS("TJS"), + TMT("TMT"), + TND("TND"), + TOP("TOP"), + TRY("TRY"), + TTD("TTD"), + TWD("TWD"), + TZS("TZS"), + UAH("UAH"), + UGX("UGX"), + USD("USD"), + USN("USN"), + UYI("UYI"), + UYU("UYU"), + UZS("UZS"), + VEF("VEF"), + VND("VND"), + VUV("VUV"), + WST("WST"), + XAF("XAF"), + XAG("XAG"), + XAU("XAU"), + XBA("XBA"), + XBB("XBB"), + XBC("XBC"), + XBD("XBD"), + XCD("XCD"), + XDR("XDR"), + XOF("XOF"), + XPD("XPD"), + XPF("XPF"), + XPT("XPT"), + XSU("XSU"), + XTS("XTS"), + XUA("XUA"), + XXX("XXX"), + YER("YER"), + ZAR("ZAR"), + ZMW("ZMW"), + ZWL("ZWL"); + + private String value; + + Currency(String value) { + this.value = value; + } + + @Override + @JsonValue + public String toString() { + return String.valueOf(value); + } + + @JsonCreator + public static Currency fromValue(String text) { + for (Currency b : Currency.values()) { + if (String.valueOf(b.value).equals(text)) { + return b; + } + } + return null; + } +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/CustomData.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/CustomData.java new file mode 100644 index 000000000..7b7ce0642 --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/CustomData.java @@ -0,0 +1,105 @@ +package org.mifos.connector.gsmastub.model; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import org.springframework.validation.annotation.Validated; + +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; +import java.util.Objects; + +/** + * CustomData + */ +@Validated +@javax.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.SpringCodegen", date = "2022-09-27T11:46:46.417Z[GMT]") + + +public class CustomData { + @JsonProperty("key") + private String key = null; + + @JsonProperty("value") + private String value = null; + + public CustomData key(String key) { + this.key = key; + return this; + } + + /** + * Identifies the type of additional field. + * @return key + **/ + @Schema(required = true, description = "Identifies the type of additional field.") + @NotNull + + @Size(min=1,max=256) public String getKey() { + return key; + } + + public void setKey(String key) { + this.key = key; + } + + public CustomData value(String value) { + this.value = value; + return this; + } + + /** + * Identifies the value of the additional field. + * @return value + **/ + @Schema(required = true, description = "Identifies the value of the additional field.") + @NotNull + + @Size(min=1,max=256) public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } + + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + CustomData customData = (CustomData) o; + return Objects.equals(this.key, customData.key) && + Objects.equals(this.value, customData.value); + } + + @Override + public int hashCode() { + return Objects.hash(key, value); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class CustomData {\n"); + + sb.append(" key: ").append(toIndentedString(key)).append("\n"); + sb.append(" value: ").append(toIndentedString(value)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/CustomDataArray.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/CustomDataArray.java new file mode 100644 index 000000000..8b7622c3c --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/CustomDataArray.java @@ -0,0 +1,54 @@ +package org.mifos.connector.gsmastub.model; + +import io.swagger.v3.oas.annotations.media.Schema; +import org.springframework.validation.annotation.Validated; + +import java.util.ArrayList; +import java.util.Objects; + +/** + * A collection of key/value pairs. These can be used to populate provider specific fields. + */ +@Schema(description = "A collection of key/value pairs. These can be used to populate provider specific fields.") +@Validated +@javax.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.SpringCodegen", date = "2022-09-27T11:46:46.417Z[GMT]") + + +public class CustomDataArray extends ArrayList { + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + return true; + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode()); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class CustomDataArray {\n"); + sb.append(" ").append(toIndentedString(super.toString())).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/DebitPartyArray.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/DebitPartyArray.java new file mode 100644 index 000000000..069575c58 --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/DebitPartyArray.java @@ -0,0 +1,54 @@ +package org.mifos.connector.gsmastub.model; + +import io.swagger.v3.oas.annotations.media.Schema; +import org.springframework.validation.annotation.Validated; + +import java.util.ArrayList; +import java.util.Objects; + +/** + * A collection of key/value pairs that enable the party to be identified. Keys include MSISDN and Wallet Identifier. + */ +@Schema(description = "A collection of key/value pairs that enable the party to be identified. Keys include MSISDN and Wallet Identifier.") +@Validated +@javax.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.SpringCodegen", date = "2022-09-27T11:46:46.417Z[GMT]") + + +public class DebitPartyArray extends ArrayList { + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + return true; + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode()); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class DebitPartyArray {\n"); + sb.append(" ").append(toIndentedString(super.toString())).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/DeliveryMethod.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/DeliveryMethod.java new file mode 100644 index 000000000..9d344e740 --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/DeliveryMethod.java @@ -0,0 +1,35 @@ +package org.mifos.connector.gsmastub.model; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonValue; + +/** + * Gets or Sets deliveryMethod + */ +public enum DeliveryMethod { + DIRECTTOACCOUNT("directtoaccount"), + AGENT("agent"), + PERSONALDELIVERY("personaldelivery"); + + private String value; + + DeliveryMethod(String value) { + this.value = value; + } + + @Override + @JsonValue + public String toString() { + return String.valueOf(value); + } + + @JsonCreator + public static DeliveryMethod fromValue(String text) { + for (DeliveryMethod b : DeliveryMethod.values()) { + if (String.valueOf(b.value).equals(text)) { + return b; + } + } + return null; + } +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/ErrorObject.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/ErrorObject.java new file mode 100644 index 000000000..1744ab64a --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/ErrorObject.java @@ -0,0 +1,323 @@ +package org.mifos.connector.gsmastub.model; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonValue; +import io.swagger.v3.oas.annotations.media.Schema; +import org.springframework.validation.annotation.Validated; +import org.threeten.bp.OffsetDateTime; + +import javax.validation.Valid; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; +import java.util.Objects; + +/** + * ErrorObject + */ +@Validated +@javax.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.SpringCodegen", date = "2022-09-27T11:46:46.417Z[GMT]") + + +public class ErrorObject { + /** + * The category grouping for the error. + */ + public enum ErrorCategoryEnum { + BUSINESSRULE("businessRule"), + + VALIDATION("validation"), + + AUTHORISATION("authorisation"), + + IDENTIFICATION("identification"), + + INTERNAL("internal"), + + SERVICEUNAVAILABLE("serviceUnavailable"); + + private String value; + + ErrorCategoryEnum(String value) { + this.value = value; + } + + @Override + @JsonValue + public String toString() { + return String.valueOf(value); + } + + @JsonCreator + public static ErrorCategoryEnum fromValue(String text) { + for (ErrorCategoryEnum b : ErrorCategoryEnum.values()) { + if (String.valueOf(b.value).equals(text)) { + return b; + } + } + return null; + } + } + @JsonProperty("errorCategory") + private ErrorCategoryEnum errorCategory = null; + + /** + * The harmonised error code identifying the reason for error. + */ + public enum ErrorCodeEnum { + GENERICERROR("genericError"), + + DAILYVOLUMELIMITEXCEEDED("dailyVolumeLimitExceeded"), + + DAILYVALUELIMITEXCEEDED("dailyValueLimitExceeded"), + + WEEKLYVOLUMELIMITEXCEEDED("weeklyVolumeLimitExceeded"), + + WEEKLYVALUELIMITEXCEEDED("weeklyValueLimitExceeded"), + + MONTHLYVOLUMELIMITEXCEEDED("monthlyVolumeLimitExceeded"), + + MONTHLYVALUELIMITEXCEEDED("monthlyValueLimitExceeded"), + + ACCOUNTMAXTOTALVOLUMEEXCEEDED("accountMaxTotalVolumeExceeded"), + + ACCOUNTMAXTOTALVALUEEXCEEDED("accountMaxTotalValueExceeded"), + + LESSTHANTRANSACTIONMINVALUE("lessThanTransactionMinValue"), + + GREATERTHANTRANSACTIONMAXVALUE("greaterThanTransactionMaxValue"), + + MAXBALANCEEXCEEDED("maxBalanceExceeded"), + + SAMEPARTIESERROR("samePartiesError"), + + DUPLICATEREQUEST("duplicateRequest"), + + INSUFFICIENTFUNDS("insufficientFunds"), + + INCORRECTSTATE("incorrectState"), + + UNDERPAYMENTNOTALLOWED("underPaymentNotAllowed"), + + OVERPAYMENTNOTALLOWED("overPaymentNotAllowed"), + + RATELIMITERROR("rateLimitError"), + + TRANSACTIONTYPEERROR("transactionTypeError"), + + NOMANDATEAUTHORITY("noMandateAuthority"), + + LINKVIOLATION("linkViolation"), + + COUNTRYOFORIGINNOTPERMITTED("countryofOriginNotPermitted"), + + NATIONALITYNOTPERMITTED("nationalityNotPermitted"), + + IDDOCUMENTNOTSUPPORTED("idDocumentNotSupported"), + + ISSUINGCOUNTRYNOTSUPPORTED("issuingCountryNotSupported"), + + QUOTEHASEXPIRED("quoteHasExpired"), + + IDENTIFIERERROR("identifierError"), + + LENGTHERROR("lengthError"), + + FORMATERROR("formatError"), + + NEGATIVEVALUE("negativeValue"), + + CURRENCYNOTSUPPORTED("currencyNotSupported"), + + MANDATORYVALUENOTSUPPLIED("mandatoryValueNotSupplied"), + + INVALIDOFFSET("invalidOffset"), + + CLIENTAUTHORISATIONERROR("clientAuthorisationError"), + + REQUESTDECLINED("requestDeclined"), + + SERVICINGPARTYAUTHORISATIONERROR("servicingPartyAuthorisationError"), + + REQUESTINGPARTYAUTHORISATIONERROR("requestingPartyAuthorisationError"); + + private String value; + + ErrorCodeEnum(String value) { + this.value = value; + } + + @Override + @JsonValue + public String toString() { + return String.valueOf(value); + } + + @JsonCreator + public static ErrorCodeEnum fromValue(String text) { + for (ErrorCodeEnum b : ErrorCodeEnum.values()) { + if (String.valueOf(b.value).equals(text)) { + return b; + } + } + return null; + } + } + @JsonProperty("errorCode") + private ErrorCodeEnum errorCode = null; + + @JsonProperty("errordescription") + private String errordescription = null; + + @JsonProperty("errorDateTime") + private OffsetDateTime errorDateTime = null; + + @JsonProperty("errorParameters") + private MetadataArray errorParameters = null; + + public ErrorObject errorCategory(ErrorCategoryEnum errorCategory) { + this.errorCategory = errorCategory; + return this; + } + + /** + * The category grouping for the error. + * @return errorCategory + **/ + @Schema(required = true, description = "The category grouping for the error.") + @NotNull + + public ErrorCategoryEnum getErrorCategory() { + return errorCategory; + } + + public void setErrorCategory(ErrorCategoryEnum errorCategory) { + this.errorCategory = errorCategory; + } + + public ErrorObject errorCode(ErrorCodeEnum errorCode) { + this.errorCode = errorCode; + return this; + } + + /** + * The harmonised error code identifying the reason for error. + * @return errorCode + **/ + @Schema(required = true, description = "The harmonised error code identifying the reason for error.") + @NotNull + + public ErrorCodeEnum getErrorCode() { + return errorCode; + } + + public void setErrorCode(ErrorCodeEnum errorCode) { + this.errorCode = errorCode; + } + + public ErrorObject errordescription(String errordescription) { + this.errordescription = errordescription; + return this; + } + + /** + * A textual description of the error. + * @return errordescription + **/ + @Schema(description = "A textual description of the error.") + + @Size(max=256) public String getErrordescription() { + return errordescription; + } + + public void setErrordescription(String errordescription) { + this.errordescription = errordescription; + } + + public ErrorObject errorDateTime(OffsetDateTime errorDateTime) { + this.errorDateTime = errorDateTime; + return this; + } + + /** + * The timestamp indicating when the error occurred. + * @return errorDateTime + **/ + @Schema(description = "The timestamp indicating when the error occurred.") + + @Valid + public OffsetDateTime getErrorDateTime() { + return errorDateTime; + } + + public void setErrorDateTime(OffsetDateTime errorDateTime) { + this.errorDateTime = errorDateTime; + } + + public ErrorObject errorParameters(MetadataArray errorParameters) { + this.errorParameters = errorParameters; + return this; + } + + /** + * Get errorParameters + * @return errorParameters + **/ + @Schema(description = "") + + @Valid + public MetadataArray getErrorParameters() { + return errorParameters; + } + + public void setErrorParameters(MetadataArray errorParameters) { + this.errorParameters = errorParameters; + } + + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + ErrorObject errorObject = (ErrorObject) o; + return Objects.equals(this.errorCategory, errorObject.errorCategory) && + Objects.equals(this.errorCode, errorObject.errorCode) && + Objects.equals(this.errordescription, errorObject.errordescription) && + Objects.equals(this.errorDateTime, errorObject.errorDateTime) && + Objects.equals(this.errorParameters, errorObject.errorParameters); + } + + @Override + public int hashCode() { + return Objects.hash(errorCategory, errorCode, errordescription, errorDateTime, errorParameters); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class ErrorObject {\n"); + + sb.append(" errorCategory: ").append(toIndentedString(errorCategory)).append("\n"); + sb.append(" errorCode: ").append(toIndentedString(errorCode)).append("\n"); + sb.append(" errordescription: ").append(toIndentedString(errordescription)).append("\n"); + sb.append(" errorDateTime: ").append(toIndentedString(errorDateTime)).append("\n"); + sb.append(" errorParameters: ").append(toIndentedString(errorParameters)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/Fees.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/Fees.java new file mode 100644 index 000000000..5263822a6 --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/Fees.java @@ -0,0 +1,133 @@ +package org.mifos.connector.gsmastub.model; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import org.springframework.validation.annotation.Validated; + +import javax.validation.Valid; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Pattern; +import javax.validation.constraints.Size; +import java.util.Objects; + +/** + * Fees + */ +@Validated +@javax.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.SpringCodegen", date = "2022-09-27T11:46:46.417Z[GMT]") + + +public class Fees { + @JsonProperty("feeType") + private String feeType = null; + + @JsonProperty("feeAmount") + private String feeAmount = null; + + @JsonProperty("feeCurrency") + private Currency feeCurrency = null; + + public Fees feeType(String feeType) { + this.feeType = feeType; + return this; + } + + /** + * Defines the type of fee. + * @return feeType + **/ + @Schema(required = true, description = "Defines the type of fee.") + @NotNull + + @Size(min=1,max=256) public String getFeeType() { + return feeType; + } + + public void setFeeType(String feeType) { + this.feeType = feeType; + } + + public Fees feeAmount(String feeAmount) { + this.feeAmount = feeAmount; + return this; + } + + /** + * Get feeAmount + * @return feeAmount + **/ + @Schema(example = "15.21", required = true, description = "") + @NotNull + + @Pattern(regexp="^([0]|([1-9][0-9]{0,17}))([.][0-9]{0,3}[0-9])?$") @Size(min=1,max=23) public String getFeeAmount() { + return feeAmount; + } + + public void setFeeAmount(String feeAmount) { + this.feeAmount = feeAmount; + } + + public Fees feeCurrency(Currency feeCurrency) { + this.feeCurrency = feeCurrency; + return this; + } + + /** + * Get feeCurrency + * @return feeCurrency + **/ + @Schema(required = true, description = "") + @NotNull + + @Valid + public Currency getFeeCurrency() { + return feeCurrency; + } + + public void setFeeCurrency(Currency feeCurrency) { + this.feeCurrency = feeCurrency; + } + + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Fees fees = (Fees) o; + return Objects.equals(this.feeType, fees.feeType) && + Objects.equals(this.feeAmount, fees.feeAmount) && + Objects.equals(this.feeCurrency, fees.feeCurrency); + } + + @Override + public int hashCode() { + return Objects.hash(feeType, feeAmount, feeCurrency); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class Fees {\n"); + + sb.append(" feeType: ").append(toIndentedString(feeType)).append("\n"); + sb.append(" feeAmount: ").append(toIndentedString(feeAmount)).append("\n"); + sb.append(" feeCurrency: ").append(toIndentedString(feeCurrency)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/FeesArray.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/FeesArray.java new file mode 100644 index 000000000..f023d3ff3 --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/FeesArray.java @@ -0,0 +1,54 @@ +package org.mifos.connector.gsmastub.model; + +import io.swagger.v3.oas.annotations.media.Schema; +import org.springframework.validation.annotation.Validated; + +import java.util.ArrayList; +import java.util.Objects; + +/** + * Returns all fees that are applicable to the object. + */ +@Schema(description = "Returns all fees that are applicable to the object.") +@Validated +@javax.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.SpringCodegen", date = "2022-09-27T11:46:46.417Z[GMT]") + + +public class FeesArray extends ArrayList { + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + return true; + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode()); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class FeesArray {\n"); + sb.append(" ").append(toIndentedString(super.toString())).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/FrequencyType.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/FrequencyType.java new file mode 100644 index 000000000..4698d8e9a --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/FrequencyType.java @@ -0,0 +1,50 @@ +package org.mifos.connector.gsmastub.model; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonValue; + +/** + * Gets or Sets frequencyType + */ +public enum FrequencyType { + WEEKLY("weekly"), + FORTNIGHT("fortnight"), + MONTHSPECIFICDATE("monthspecificdate"), + TWOMONTHS("twomonths"), + THREEMONTHS("threemonths"), + FOURMONTHS("fourmonths"), + SIXMONTHS("sixmonths"), + YEARLY("yearly"), + LASTDAYMONTH("lastdaymonth"), + LASTDAYMONTHWORKING("lastdaymonthworking"), + LASTMONDAY("lastmonday"), + LASTTUESDAY("lasttuesday"), + LASTWEDNESDAY("lastwednesday"), + LASTTHURSDAY("lastthursday"), + LASTFRIDAY("lastfriday"), + LASTSATURDAY("lastsaturday"), + LASTSUNDAY("lastsunday"), + SPECIFICDAYMONTHLY("specificdaymonthly"); + + private String value; + + FrequencyType(String value) { + this.value = value; + } + + @Override + @JsonValue + public String toString() { + return String.valueOf(value); + } + + @JsonCreator + public static FrequencyType fromValue(String text) { + for (FrequencyType b : FrequencyType.values()) { + if (String.valueOf(b.value).equals(text)) { + return b; + } + } + return null; + } +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/Gender.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/Gender.java new file mode 100644 index 000000000..b61c87ebc --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/Gender.java @@ -0,0 +1,35 @@ +package org.mifos.connector.gsmastub.model; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonValue; + +/** + * Gender of the KYC subject. + */ +public enum Gender { + M("m"), + F("f"), + U("u"); + + private String value; + + Gender(String value) { + this.value = value; + } + + @Override + @JsonValue + public String toString() { + return String.valueOf(value); + } + + @JsonCreator + public static Gender fromValue(String text) { + for (Gender b : Gender.values()) { + if (String.valueOf(b.value).equals(text)) { + return b; + } + } + return null; + } +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/GenericUpdateSuccess.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/GenericUpdateSuccess.java new file mode 100644 index 000000000..94f9312ee --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/GenericUpdateSuccess.java @@ -0,0 +1,109 @@ +package org.mifos.connector.gsmastub.model; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonValue; +import io.swagger.v3.oas.annotations.media.Schema; +import org.springframework.validation.annotation.Validated; + +import javax.validation.constraints.NotNull; +import java.util.Objects; + +/** + * GenericUpdateSuccess + */ +@Validated +@javax.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.SpringCodegen", date = "2022-09-27T11:46:46.417Z[GMT]") + + +public class GenericUpdateSuccess { + /** + * The success message provided in a callback to communicate the success of an update operation. + */ + public enum ResultEnum { + SUCCESS("success"); + + private String value; + + ResultEnum(String value) { + this.value = value; + } + + @Override + @JsonValue + public String toString() { + return String.valueOf(value); + } + + @JsonCreator + public static ResultEnum fromValue(String text) { + for (ResultEnum b : ResultEnum.values()) { + if (String.valueOf(b.value).equals(text)) { + return b; + } + } + return null; + } + } + @JsonProperty("result") + private ResultEnum result = null; + + public GenericUpdateSuccess result(ResultEnum result) { + this.result = result; + return this; + } + + /** + * The success message provided in a callback to communicate the success of an update operation. + * @return result + **/ + @Schema(required = true, description = "The success message provided in a callback to communicate the success of an update operation.") + @NotNull + + public ResultEnum getResult() { + return result; + } + + public void setResult(ResultEnum result) { + this.result = result; + } + + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + GenericUpdateSuccess genericUpdateSuccess = (GenericUpdateSuccess) o; + return Objects.equals(this.result, genericUpdateSuccess.result); + } + + @Override + public int hashCode() { + return Objects.hash(result); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class GenericUpdateSuccess {\n"); + + sb.append(" result: ").append(toIndentedString(result)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/IdDocument.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/IdDocument.java new file mode 100644 index 000000000..a166b994b --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/IdDocument.java @@ -0,0 +1,315 @@ +package org.mifos.connector.gsmastub.model; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonValue; +import io.swagger.v3.oas.annotations.media.Schema; +import org.springframework.validation.annotation.Validated; +import org.threeten.bp.LocalDate; + +import javax.validation.Valid; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; +import java.util.Objects; + +/** + * IdDocument + */ +@Validated +@javax.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.SpringCodegen", date = "2022-09-27T11:46:46.417Z[GMT]") + + +public class IdDocument { + /** + * Indicates the type of identification for the KYC subject, e.g. passport, driving licence etc. + */ + public enum IdTypeEnum { + PASSPORT("passport"), + + NATIONALREGISTRATION("nationalregistration"), + + OTHERID("otherId"), + + DRIVINGLICENCE("drivinglicence"), + + SOCIALSECURITY("socialsecurity"), + + ALIENREGISTRATION("alienregistration"), + + NATIONALIDCARD("nationalidcard"), + + EMPLOYER("employer"), + + TAXID("taxid"), + + SENIORCITIZENSCARD("seniorcitizenscard"), + + MARRIAGECERTIFICATE("marriagecertificate"), + + BIRTHCERTIFICATE("birthcertificate"), + + HEALTHCARD("healthcard"), + + VOTERSID("votersid"), + + VILLAGEELDERLETTER("villageelderLetter"), + + PANCARD("pancard"), + + OFFICIALLETTER("officialletter"); + + private String value; + + IdTypeEnum(String value) { + this.value = value; + } + + @Override + @JsonValue + public String toString() { + return String.valueOf(value); + } + + @JsonCreator + public static IdTypeEnum fromValue(String text) { + for (IdTypeEnum b : IdTypeEnum.values()) { + if (String.valueOf(b.value).equals(text)) { + return b; + } + } + return null; + } + } + @JsonProperty("idType") + private IdTypeEnum idType = null; + + @JsonProperty("idNumber") + private String idNumber = null; + + @JsonProperty("issueDate") + private LocalDate issueDate = null; + + @JsonProperty("expiryDate") + private LocalDate expiryDate = null; + + @JsonProperty("issuer") + private String issuer = null; + + @JsonProperty("issuerPlace") + private String issuerPlace = null; + + @JsonProperty("issuerCountry") + private Nationality issuerCountry = null; + + @JsonProperty("otherIddescription") + private String otherIddescription = null; + + public IdDocument idType(IdTypeEnum idType) { + this.idType = idType; + return this; + } + + /** + * Indicates the type of identification for the KYC subject, e.g. passport, driving licence etc. + * @return idType + **/ + @Schema(required = true, description = "Indicates the type of identification for the KYC subject, e.g. passport, driving licence etc.") + @NotNull + + public IdTypeEnum getIdType() { + return idType; + } + + public void setIdType(IdTypeEnum idType) { + this.idType = idType; + } + + public IdDocument idNumber(String idNumber) { + this.idNumber = idNumber; + return this; + } + + /** + * Reference pertaining to the type of identification for the KYC subject. + * @return idNumber + **/ + @Schema(description = "Reference pertaining to the type of identification for the KYC subject.") + + @Size(max=256) public String getIdNumber() { + return idNumber; + } + + public void setIdNumber(String idNumber) { + this.idNumber = idNumber; + } + + public IdDocument issueDate(LocalDate issueDate) { + this.issueDate = issueDate; + return this; + } + + /** + * Date of issue for the identification document. + * @return issueDate + **/ + @Schema(example = "Tue Nov 20 00:00:00 GMT 2018", description = "Date of issue for the identification document.") + + @Valid + public LocalDate getIssueDate() { + return issueDate; + } + + public void setIssueDate(LocalDate issueDate) { + this.issueDate = issueDate; + } + + public IdDocument expiryDate(LocalDate expiryDate) { + this.expiryDate = expiryDate; + return this; + } + + /** + * Date of expiry for the identification document. + * @return expiryDate + **/ + @Schema(example = "Tue Nov 20 00:00:00 GMT 2018", description = "Date of expiry for the identification document.") + + @Valid + public LocalDate getExpiryDate() { + return expiryDate; + } + + public void setExpiryDate(LocalDate expiryDate) { + this.expiryDate = expiryDate; + } + + public IdDocument issuer(String issuer) { + this.issuer = issuer; + return this; + } + + /** + * Indicates the organisation/government entity that issued the ID document. + * @return issuer + **/ + @Schema(description = "Indicates the organisation/government entity that issued the ID document.") + + @Size(max=256) public String getIssuer() { + return issuer; + } + + public void setIssuer(String issuer) { + this.issuer = issuer; + } + + public IdDocument issuerPlace(String issuerPlace) { + this.issuerPlace = issuerPlace; + return this; + } + + /** + * Place of issue for the identification type. + * @return issuerPlace + **/ + @Schema(description = "Place of issue for the identification type.") + + @Size(max=256) public String getIssuerPlace() { + return issuerPlace; + } + + public void setIssuerPlace(String issuerPlace) { + this.issuerPlace = issuerPlace; + } + + public IdDocument issuerCountry(Nationality issuerCountry) { + this.issuerCountry = issuerCountry; + return this; + } + + /** + * Get issuerCountry + * @return issuerCountry + **/ + @Schema(description = "") + + @Valid + public Nationality getIssuerCountry() { + return issuerCountry; + } + + public void setIssuerCountry(Nationality issuerCountry) { + this.issuerCountry = issuerCountry; + } + + public IdDocument otherIddescription(String otherIddescription) { + this.otherIddescription = otherIddescription; + return this; + } + + /** + * Where an ID Type of otherid is specified, a description of the type of identification can be provided in this field. + * @return otherIddescription + **/ + @Schema(description = "Where an ID Type of otherid is specified, a description of the type of identification can be provided in this field.") + + @Size(max=256) public String getOtherIddescription() { + return otherIddescription; + } + + public void setOtherIddescription(String otherIddescription) { + this.otherIddescription = otherIddescription; + } + + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + IdDocument idDocument = (IdDocument) o; + return Objects.equals(this.idType, idDocument.idType) && + Objects.equals(this.idNumber, idDocument.idNumber) && + Objects.equals(this.issueDate, idDocument.issueDate) && + Objects.equals(this.expiryDate, idDocument.expiryDate) && + Objects.equals(this.issuer, idDocument.issuer) && + Objects.equals(this.issuerPlace, idDocument.issuerPlace) && + Objects.equals(this.issuerCountry, idDocument.issuerCountry) && + Objects.equals(this.otherIddescription, idDocument.otherIddescription); + } + + @Override + public int hashCode() { + return Objects.hash(idType, idNumber, issueDate, expiryDate, issuer, issuerPlace, issuerCountry, otherIddescription); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class IdDocument {\n"); + + sb.append(" idType: ").append(toIndentedString(idType)).append("\n"); + sb.append(" idNumber: ").append(toIndentedString(idNumber)).append("\n"); + sb.append(" issueDate: ").append(toIndentedString(issueDate)).append("\n"); + sb.append(" expiryDate: ").append(toIndentedString(expiryDate)).append("\n"); + sb.append(" issuer: ").append(toIndentedString(issuer)).append("\n"); + sb.append(" issuerPlace: ").append(toIndentedString(issuerPlace)).append("\n"); + sb.append(" issuerCountry: ").append(toIndentedString(issuerCountry)).append("\n"); + sb.append(" otherIddescription: ").append(toIndentedString(otherIddescription)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/IdDocumentArray.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/IdDocumentArray.java new file mode 100644 index 000000000..52bf8afd6 --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/IdDocumentArray.java @@ -0,0 +1,54 @@ +package org.mifos.connector.gsmastub.model; + +import io.swagger.v3.oas.annotations.media.Schema; +import org.springframework.validation.annotation.Validated; + +import java.util.ArrayList; +import java.util.Objects; + +/** + * An array of properties containing the forms of identification that are associated with the subject. + */ +@Schema(description = "An array of properties containing the forms of identification that are associated with the subject.") +@Validated +@javax.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.SpringCodegen", date = "2022-09-27T11:46:46.417Z[GMT]") + + +public class IdDocumentArray extends ArrayList { + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + return true; + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode()); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class IdDocumentArray {\n"); + sb.append(" ").append(toIndentedString(super.toString())).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/IdentityRequest.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/IdentityRequest.java new file mode 100644 index 000000000..c671854d1 --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/IdentityRequest.java @@ -0,0 +1,206 @@ +package org.mifos.connector.gsmastub.model; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import org.springframework.validation.annotation.Validated; + +import javax.validation.Valid; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; +import java.util.Objects; + +/** + * IdentityRequest + */ +@Validated +@javax.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.SpringCodegen", date = "2022-09-27T11:46:46.417Z[GMT]") + + +public class IdentityRequest { + @JsonProperty("identityKyc") + private Kyc identityKyc = null; + + @JsonProperty("accountRelationship") + private AccountRelationship accountRelationship = null; + + @JsonProperty("kycVerificationStatus") + private KycVerificationStatus kycVerificationStatus = null; + + @JsonProperty("kycVerificationEntity") + private String kycVerificationEntity = null; + + @JsonProperty("kycLevel") + private Integer kycLevel = null; + + @JsonProperty("customData") + private CustomDataArray customData = null; + + public IdentityRequest identityKyc(Kyc identityKyc) { + this.identityKyc = identityKyc; + return this; + } + + /** + * Get identityKyc + * @return identityKyc + **/ + @Schema(required = true, description = "") + @NotNull + + @Valid + public Kyc getIdentityKyc() { + return identityKyc; + } + + public void setIdentityKyc(Kyc identityKyc) { + this.identityKyc = identityKyc; + } + + public IdentityRequest accountRelationship(AccountRelationship accountRelationship) { + this.accountRelationship = accountRelationship; + return this; + } + + /** + * Get accountRelationship + * @return accountRelationship + **/ + @Schema(required = true, description = "") + @NotNull + + @Valid + public AccountRelationship getAccountRelationship() { + return accountRelationship; + } + + public void setAccountRelationship(AccountRelationship accountRelationship) { + this.accountRelationship = accountRelationship; + } + + public IdentityRequest kycVerificationStatus(KycVerificationStatus kycVerificationStatus) { + this.kycVerificationStatus = kycVerificationStatus; + return this; + } + + /** + * Get kycVerificationStatus + * @return kycVerificationStatus + **/ + @Schema(description = "") + + @Valid + public KycVerificationStatus getKycVerificationStatus() { + return kycVerificationStatus; + } + + public void setKycVerificationStatus(KycVerificationStatus kycVerificationStatus) { + this.kycVerificationStatus = kycVerificationStatus; + } + + public IdentityRequest kycVerificationEntity(String kycVerificationEntity) { + this.kycVerificationEntity = kycVerificationEntity; + return this; + } + + /** + * Indicates the entity (e.g. mobile money agent) that has verified the KYC of the identity. + * @return kycVerificationEntity + **/ + @Schema(description = "Indicates the entity (e.g. mobile money agent) that has verified the KYC of the identity.") + + @Size(max=256) public String getKycVerificationEntity() { + return kycVerificationEntity; + } + + public void setKycVerificationEntity(String kycVerificationEntity) { + this.kycVerificationEntity = kycVerificationEntity; + } + + public IdentityRequest kycLevel(Integer kycLevel) { + this.kycLevel = kycLevel; + return this; + } + + /** + * Indicates the KYC level that the identity is associated with. + * @return kycLevel + **/ + @Schema(example = "1", description = "Indicates the KYC level that the identity is associated with.") + + public Integer getKycLevel() { + return kycLevel; + } + + public void setKycLevel(Integer kycLevel) { + this.kycLevel = kycLevel; + } + + public IdentityRequest customData(CustomDataArray customData) { + this.customData = customData; + return this; + } + + /** + * Get customData + * @return customData + **/ + @Schema(description = "") + + @Valid + public CustomDataArray getCustomData() { + return customData; + } + + public void setCustomData(CustomDataArray customData) { + this.customData = customData; + } + + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + IdentityRequest identityRequest = (IdentityRequest) o; + return Objects.equals(this.identityKyc, identityRequest.identityKyc) && + Objects.equals(this.accountRelationship, identityRequest.accountRelationship) && + Objects.equals(this.kycVerificationStatus, identityRequest.kycVerificationStatus) && + Objects.equals(this.kycVerificationEntity, identityRequest.kycVerificationEntity) && + Objects.equals(this.kycLevel, identityRequest.kycLevel) && + Objects.equals(this.customData, identityRequest.customData); + } + + @Override + public int hashCode() { + return Objects.hash(identityKyc, accountRelationship, kycVerificationStatus, kycVerificationEntity, kycLevel, customData); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class IdentityRequest {\n"); + + sb.append(" identityKyc: ").append(toIndentedString(identityKyc)).append("\n"); + sb.append(" accountRelationship: ").append(toIndentedString(accountRelationship)).append("\n"); + sb.append(" kycVerificationStatus: ").append(toIndentedString(kycVerificationStatus)).append("\n"); + sb.append(" kycVerificationEntity: ").append(toIndentedString(kycVerificationEntity)).append("\n"); + sb.append(" kycLevel: ").append(toIndentedString(kycLevel)).append("\n"); + sb.append(" customData: ").append(toIndentedString(customData)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/IdentityRequestArray.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/IdentityRequestArray.java new file mode 100644 index 000000000..bca4176b7 --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/IdentityRequestArray.java @@ -0,0 +1,54 @@ +package org.mifos.connector.gsmastub.model; + +import io.swagger.v3.oas.annotations.media.Schema; +import org.springframework.validation.annotation.Validated; + +import java.util.ArrayList; +import java.util.Objects; + +/** + * An array containing the details of each identity associated with an account. + */ +@Schema(description = "An array containing the details of each identity associated with an account.") +@Validated +@javax.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.SpringCodegen", date = "2022-09-27T11:46:46.417Z[GMT]") + + +public class IdentityRequestArray extends ArrayList { + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + return true; + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode()); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class IdentityRequestArray {\n"); + sb.append(" ").append(toIndentedString(super.toString())).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/IdentityResponse.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/IdentityResponse.java new file mode 100644 index 000000000..fcbc7009b --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/IdentityResponse.java @@ -0,0 +1,281 @@ +package org.mifos.connector.gsmastub.model; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import org.springframework.validation.annotation.Validated; + +import javax.validation.Valid; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; +import java.util.Objects; + +/** + * IdentityResponse + */ +@Validated +@javax.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.SpringCodegen", date = "2022-09-27T11:46:46.417Z[GMT]") + + +public class IdentityResponse { + @JsonProperty("identityId") + private String identityId = null; + + @JsonProperty("identityType") + private IdentityType identityType = null; + + @JsonProperty("identityStatus") + private String identityStatus = null; + + @JsonProperty("identityKyc") + private Kyc identityKyc = null; + + @JsonProperty("accountRelationship") + private AccountRelationship accountRelationship = null; + + @JsonProperty("kycVerificationStatus") + private KycVerificationStatus kycVerificationStatus = null; + + @JsonProperty("kycVerificationEntity") + private String kycVerificationEntity = null; + + @JsonProperty("kycLevel") + private Integer kycLevel = null; + + @JsonProperty("customData") + private CustomDataArray customData = null; + + public IdentityResponse identityId(String identityId) { + this.identityId = identityId; + return this; + } + + /** + * A unique id for the identity as assigned by the API Provider. + * @return identityId + **/ + @Schema(required = true, description = "A unique id for the identity as assigned by the API Provider.") + @NotNull + + @Size(min=1,max=256) public String getIdentityId() { + return identityId; + } + + public void setIdentityId(String identityId) { + this.identityId = identityId; + } + + public IdentityResponse identityType(IdentityType identityType) { + this.identityType = identityType; + return this; + } + + /** + * Get identityType + * @return identityType + **/ + @Schema(required = true, description = "") + @NotNull + + @Valid + public IdentityType getIdentityType() { + return identityType; + } + + public void setIdentityType(IdentityType identityType) { + this.identityType = identityType; + } + + public IdentityResponse identityStatus(String identityStatus) { + this.identityStatus = identityStatus; + return this; + } + + /** + * A unique id for the identity as assigned by the API Provider. + * @return identityStatus + **/ + @Schema(description = "A unique id for the identity as assigned by the API Provider.") + + @Size(max=256) public String getIdentityStatus() { + return identityStatus; + } + + public void setIdentityStatus(String identityStatus) { + this.identityStatus = identityStatus; + } + + public IdentityResponse identityKyc(Kyc identityKyc) { + this.identityKyc = identityKyc; + return this; + } + + /** + * Get identityKyc + * @return identityKyc + **/ + @Schema(required = true, description = "") + @NotNull + + @Valid + public Kyc getIdentityKyc() { + return identityKyc; + } + + public void setIdentityKyc(Kyc identityKyc) { + this.identityKyc = identityKyc; + } + + public IdentityResponse accountRelationship(AccountRelationship accountRelationship) { + this.accountRelationship = accountRelationship; + return this; + } + + /** + * Get accountRelationship + * @return accountRelationship + **/ + @Schema(required = true, description = "") + @NotNull + + @Valid + public AccountRelationship getAccountRelationship() { + return accountRelationship; + } + + public void setAccountRelationship(AccountRelationship accountRelationship) { + this.accountRelationship = accountRelationship; + } + + public IdentityResponse kycVerificationStatus(KycVerificationStatus kycVerificationStatus) { + this.kycVerificationStatus = kycVerificationStatus; + return this; + } + + /** + * Get kycVerificationStatus + * @return kycVerificationStatus + **/ + @Schema(description = "") + + @Valid + public KycVerificationStatus getKycVerificationStatus() { + return kycVerificationStatus; + } + + public void setKycVerificationStatus(KycVerificationStatus kycVerificationStatus) { + this.kycVerificationStatus = kycVerificationStatus; + } + + public IdentityResponse kycVerificationEntity(String kycVerificationEntity) { + this.kycVerificationEntity = kycVerificationEntity; + return this; + } + + /** + * Indicates the entity (e.g. mobile money agent) that has verified the KYC of the identity. + * @return kycVerificationEntity + **/ + @Schema(description = "Indicates the entity (e.g. mobile money agent) that has verified the KYC of the identity.") + + @Size(max=256) public String getKycVerificationEntity() { + return kycVerificationEntity; + } + + public void setKycVerificationEntity(String kycVerificationEntity) { + this.kycVerificationEntity = kycVerificationEntity; + } + + public IdentityResponse kycLevel(Integer kycLevel) { + this.kycLevel = kycLevel; + return this; + } + + /** + * Indicates the KYC level that the identity is associated with. + * @return kycLevel + **/ + @Schema(example = "1", description = "Indicates the KYC level that the identity is associated with.") + + public Integer getKycLevel() { + return kycLevel; + } + + public void setKycLevel(Integer kycLevel) { + this.kycLevel = kycLevel; + } + + public IdentityResponse customData(CustomDataArray customData) { + this.customData = customData; + return this; + } + + /** + * Get customData + * @return customData + **/ + @Schema(description = "") + + @Valid + public CustomDataArray getCustomData() { + return customData; + } + + public void setCustomData(CustomDataArray customData) { + this.customData = customData; + } + + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + IdentityResponse identityResponse = (IdentityResponse) o; + return Objects.equals(this.identityId, identityResponse.identityId) && + Objects.equals(this.identityType, identityResponse.identityType) && + Objects.equals(this.identityStatus, identityResponse.identityStatus) && + Objects.equals(this.identityKyc, identityResponse.identityKyc) && + Objects.equals(this.accountRelationship, identityResponse.accountRelationship) && + Objects.equals(this.kycVerificationStatus, identityResponse.kycVerificationStatus) && + Objects.equals(this.kycVerificationEntity, identityResponse.kycVerificationEntity) && + Objects.equals(this.kycLevel, identityResponse.kycLevel) && + Objects.equals(this.customData, identityResponse.customData); + } + + @Override + public int hashCode() { + return Objects.hash(identityId, identityType, identityStatus, identityKyc, accountRelationship, kycVerificationStatus, kycVerificationEntity, kycLevel, customData); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class IdentityResponse {\n"); + + sb.append(" identityId: ").append(toIndentedString(identityId)).append("\n"); + sb.append(" identityType: ").append(toIndentedString(identityType)).append("\n"); + sb.append(" identityStatus: ").append(toIndentedString(identityStatus)).append("\n"); + sb.append(" identityKyc: ").append(toIndentedString(identityKyc)).append("\n"); + sb.append(" accountRelationship: ").append(toIndentedString(accountRelationship)).append("\n"); + sb.append(" kycVerificationStatus: ").append(toIndentedString(kycVerificationStatus)).append("\n"); + sb.append(" kycVerificationEntity: ").append(toIndentedString(kycVerificationEntity)).append("\n"); + sb.append(" kycLevel: ").append(toIndentedString(kycLevel)).append("\n"); + sb.append(" customData: ").append(toIndentedString(customData)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/IdentityResponseArray.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/IdentityResponseArray.java new file mode 100644 index 000000000..c8e4c50a3 --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/IdentityResponseArray.java @@ -0,0 +1,54 @@ +package org.mifos.connector.gsmastub.model; + +import io.swagger.v3.oas.annotations.media.Schema; +import org.springframework.validation.annotation.Validated; + +import java.util.ArrayList; +import java.util.Objects; + +/** + * An array containing the details of each identity associated with an account. + */ +@Schema(description = "An array containing the details of each identity associated with an account.") +@Validated +@javax.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.SpringCodegen", date = "2022-09-27T11:46:46.417Z[GMT]") + + +public class IdentityResponseArray extends ArrayList { + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + return true; + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode()); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class IdentityResponseArray {\n"); + sb.append(" ").append(toIndentedString(super.toString())).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/IdentityType.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/IdentityType.java new file mode 100644 index 000000000..d6bc8cec0 --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/IdentityType.java @@ -0,0 +1,33 @@ +package org.mifos.connector.gsmastub.model; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonValue; + +/** + * Indicates the type of the identity. Currently, only ‘individual’ is supported. + */ +public enum IdentityType { + INDIVIDUAL("individual"); + + private String value; + + IdentityType(String value) { + this.value = value; + } + + @Override + @JsonValue + public String toString() { + return String.valueOf(value); + } + + @JsonCreator + public static IdentityType fromValue(String text) { + for (IdentityType b : IdentityType.values()) { + if (String.valueOf(b.value).equals(text)) { + return b; + } + } + return null; + } +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/InternationalTransferInformation.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/InternationalTransferInformation.java new file mode 100644 index 000000000..860c390a1 --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/InternationalTransferInformation.java @@ -0,0 +1,254 @@ +package org.mifos.connector.gsmastub.model; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import org.springframework.validation.annotation.Validated; + +import javax.validation.Valid; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; +import java.util.Objects; + +/** + * A collection of properties detailing information specifically used for international transfers. + */ +@Schema(description = "A collection of properties detailing information specifically used for international transfers.") +@Validated +@javax.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.SpringCodegen", date = "2022-09-27T11:46:46.417Z[GMT]") + + +public class InternationalTransferInformation { + @JsonProperty("quotationReference") + private String quotationReference = null; + + @JsonProperty("quoteId") + private String quoteId = null; + + @JsonProperty("originCountry") + private Nationality originCountry = null; + + @JsonProperty("deliveryMethod") + private DeliveryMethod deliveryMethod = null; + + @JsonProperty("receivingCountry") + private Nationality receivingCountry = null; + + @JsonProperty("relationshipSender") + private String relationshipSender = null; + + @JsonProperty("remittancePurpose") + private String remittancePurpose = null; + + @JsonProperty("sendingServiceProviderCountry") + private Nationality sendingServiceProviderCountry = null; + + public InternationalTransferInformation quotationReference(String quotationReference) { + this.quotationReference = quotationReference; + return this; + } + + /** + * Reference for the quotation that was provided to the sender. + * @return quotationReference + **/ + @Schema(description = "Reference for the quotation that was provided to the sender.") + + @Size(min=1,max=256) public String getQuotationReference() { + return quotationReference; + } + + public void setQuotationReference(String quotationReference) { + this.quotationReference = quotationReference; + } + + public InternationalTransferInformation quoteId(String quoteId) { + this.quoteId = quoteId; + return this; + } + + /** + * The specific quote associated with the quotation. + * @return quoteId + **/ + @Schema(description = "The specific quote associated with the quotation.") + + @Size(min=1,max=256) public String getQuoteId() { + return quoteId; + } + + public void setQuoteId(String quoteId) { + this.quoteId = quoteId; + } + + public InternationalTransferInformation originCountry(Nationality originCountry) { + this.originCountry = originCountry; + return this; + } + + /** + * Get originCountry + * @return originCountry + **/ + @Schema(required = true, description = "") + @NotNull + + @Valid + public Nationality getOriginCountry() { + return originCountry; + } + + public void setOriginCountry(Nationality originCountry) { + this.originCountry = originCountry; + } + + public InternationalTransferInformation deliveryMethod(DeliveryMethod deliveryMethod) { + this.deliveryMethod = deliveryMethod; + return this; + } + + /** + * Get deliveryMethod + * @return deliveryMethod + **/ + @Schema(description = "") + + @Valid + public DeliveryMethod getDeliveryMethod() { + return deliveryMethod; + } + + public void setDeliveryMethod(DeliveryMethod deliveryMethod) { + this.deliveryMethod = deliveryMethod; + } + + public InternationalTransferInformation receivingCountry(Nationality receivingCountry) { + this.receivingCountry = receivingCountry; + return this; + } + + /** + * Get receivingCountry + * @return receivingCountry + **/ + @Schema(description = "") + + @Valid + public Nationality getReceivingCountry() { + return receivingCountry; + } + + public void setReceivingCountry(Nationality receivingCountry) { + this.receivingCountry = receivingCountry; + } + + public InternationalTransferInformation relationshipSender(String relationshipSender) { + this.relationshipSender = relationshipSender; + return this; + } + + /** + * Indicates the relationship (if any) between the sender and the receiver. + * @return relationshipSender + **/ + @Schema(description = "Indicates the relationship (if any) between the sender and the receiver.") + + @Size(max=256) public String getRelationshipSender() { + return relationshipSender; + } + + public void setRelationshipSender(String relationshipSender) { + this.relationshipSender = relationshipSender; + } + + public InternationalTransferInformation remittancePurpose(String remittancePurpose) { + this.remittancePurpose = remittancePurpose; + return this; + } + + /** + * Field providing a description of the reason for the international remittance. + * @return remittancePurpose + **/ + @Schema(description = "Field providing a description of the reason for the international remittance.") + + @Size(max=256) public String getRemittancePurpose() { + return remittancePurpose; + } + + public void setRemittancePurpose(String remittancePurpose) { + this.remittancePurpose = remittancePurpose; + } + + public InternationalTransferInformation sendingServiceProviderCountry(Nationality sendingServiceProviderCountry) { + this.sendingServiceProviderCountry = sendingServiceProviderCountry; + return this; + } + + /** + * Get sendingServiceProviderCountry + * @return sendingServiceProviderCountry + **/ + @Schema(description = "") + + @Valid + public Nationality getSendingServiceProviderCountry() { + return sendingServiceProviderCountry; + } + + public void setSendingServiceProviderCountry(Nationality sendingServiceProviderCountry) { + this.sendingServiceProviderCountry = sendingServiceProviderCountry; + } + + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + InternationalTransferInformation internationalTransferInformation = (InternationalTransferInformation) o; + return Objects.equals(this.quotationReference, internationalTransferInformation.quotationReference) && + Objects.equals(this.quoteId, internationalTransferInformation.quoteId) && + Objects.equals(this.originCountry, internationalTransferInformation.originCountry) && + Objects.equals(this.deliveryMethod, internationalTransferInformation.deliveryMethod) && + Objects.equals(this.receivingCountry, internationalTransferInformation.receivingCountry) && + Objects.equals(this.relationshipSender, internationalTransferInformation.relationshipSender) && + Objects.equals(this.remittancePurpose, internationalTransferInformation.remittancePurpose) && + Objects.equals(this.sendingServiceProviderCountry, internationalTransferInformation.sendingServiceProviderCountry); + } + + @Override + public int hashCode() { + return Objects.hash(quotationReference, quoteId, originCountry, deliveryMethod, receivingCountry, relationshipSender, remittancePurpose, sendingServiceProviderCountry); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class InternationalTransferInformation {\n"); + + sb.append(" quotationReference: ").append(toIndentedString(quotationReference)).append("\n"); + sb.append(" quoteId: ").append(toIndentedString(quoteId)).append("\n"); + sb.append(" originCountry: ").append(toIndentedString(originCountry)).append("\n"); + sb.append(" deliveryMethod: ").append(toIndentedString(deliveryMethod)).append("\n"); + sb.append(" receivingCountry: ").append(toIndentedString(receivingCountry)).append("\n"); + sb.append(" relationshipSender: ").append(toIndentedString(relationshipSender)).append("\n"); + sb.append(" remittancePurpose: ").append(toIndentedString(remittancePurpose)).append("\n"); + sb.append(" sendingServiceProviderCountry: ").append(toIndentedString(sendingServiceProviderCountry)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/InternationalTransferInformationResponse.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/InternationalTransferInformationResponse.java new file mode 100644 index 000000000..bc669981f --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/InternationalTransferInformationResponse.java @@ -0,0 +1,301 @@ +package org.mifos.connector.gsmastub.model; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import org.springframework.validation.annotation.Validated; + +import javax.validation.Valid; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; +import java.util.Objects; + +/** + * InternationalTransferInformationResponse + */ +@Validated +@javax.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.SpringCodegen", date = "2022-09-27T11:46:46.417Z[GMT]") + + +public class InternationalTransferInformationResponse { + @JsonProperty("originCountry") + private Nationality originCountry = null; + + @JsonProperty("quotationReference") + private String quotationReference = null; + + @JsonProperty("quoteId") + private String quoteId = null; + + @JsonProperty("deliveryMethod") + private DeliveryMethod deliveryMethod = null; + + @JsonProperty("receivingCountry") + private Nationality receivingCountry = null; + + @JsonProperty("relationshipSender") + private String relationshipSender = null; + + @JsonProperty("remittancePurpose") + private String remittancePurpose = null; + + @JsonProperty("recipientBlockingReason") + private String recipientBlockingReason = null; + + @JsonProperty("senderBlockingReason") + private String senderBlockingReason = null; + + @JsonProperty("sendingServiceProviderCountry") + private Nationality sendingServiceProviderCountry = null; + + public InternationalTransferInformationResponse originCountry(Nationality originCountry) { + this.originCountry = originCountry; + return this; + } + + /** + * Get originCountry + * @return originCountry + **/ + @Schema(required = true, description = "") + @NotNull + + @Valid + public Nationality getOriginCountry() { + return originCountry; + } + + public void setOriginCountry(Nationality originCountry) { + this.originCountry = originCountry; + } + + public InternationalTransferInformationResponse quotationReference(String quotationReference) { + this.quotationReference = quotationReference; + return this; + } + + /** + * Reference for the quotation that was provided to the sender. + * @return quotationReference + **/ + @Schema(description = "Reference for the quotation that was provided to the sender.") + + @Size(min=1,max=256) public String getQuotationReference() { + return quotationReference; + } + + public void setQuotationReference(String quotationReference) { + this.quotationReference = quotationReference; + } + + public InternationalTransferInformationResponse quoteId(String quoteId) { + this.quoteId = quoteId; + return this; + } + + /** + * The specific quote associated with the quotation. + * @return quoteId + **/ + @Schema(description = "The specific quote associated with the quotation.") + + @Size(min=1,max=256) public String getQuoteId() { + return quoteId; + } + + public void setQuoteId(String quoteId) { + this.quoteId = quoteId; + } + + public InternationalTransferInformationResponse deliveryMethod(DeliveryMethod deliveryMethod) { + this.deliveryMethod = deliveryMethod; + return this; + } + + /** + * Get deliveryMethod + * @return deliveryMethod + **/ + @Schema(description = "") + + @Valid + public DeliveryMethod getDeliveryMethod() { + return deliveryMethod; + } + + public void setDeliveryMethod(DeliveryMethod deliveryMethod) { + this.deliveryMethod = deliveryMethod; + } + + public InternationalTransferInformationResponse receivingCountry(Nationality receivingCountry) { + this.receivingCountry = receivingCountry; + return this; + } + + /** + * Get receivingCountry + * @return receivingCountry + **/ + @Schema(description = "") + + @Valid + public Nationality getReceivingCountry() { + return receivingCountry; + } + + public void setReceivingCountry(Nationality receivingCountry) { + this.receivingCountry = receivingCountry; + } + + public InternationalTransferInformationResponse relationshipSender(String relationshipSender) { + this.relationshipSender = relationshipSender; + return this; + } + + /** + * Indicates the relationship (if any) between the sender and the receiver. + * @return relationshipSender + **/ + @Schema(description = "Indicates the relationship (if any) between the sender and the receiver.") + + @Size(max=256) public String getRelationshipSender() { + return relationshipSender; + } + + public void setRelationshipSender(String relationshipSender) { + this.relationshipSender = relationshipSender; + } + + public InternationalTransferInformationResponse remittancePurpose(String remittancePurpose) { + this.remittancePurpose = remittancePurpose; + return this; + } + + /** + * Field providing a description of the reason for the international remittance. + * @return remittancePurpose + **/ + @Schema(description = "Field providing a description of the reason for the international remittance.") + + @Size(max=256) public String getRemittancePurpose() { + return remittancePurpose; + } + + public void setRemittancePurpose(String remittancePurpose) { + this.remittancePurpose = remittancePurpose; + } + + public InternationalTransferInformationResponse recipientBlockingReason(String recipientBlockingReason) { + this.recipientBlockingReason = recipientBlockingReason; + return this; + } + + /** + * The reason for blocking the quotation, based on AML checks on the recipient. + * @return recipientBlockingReason + **/ + @Schema(description = "The reason for blocking the quotation, based on AML checks on the recipient.") + + @Size(max=256) public String getRecipientBlockingReason() { + return recipientBlockingReason; + } + + public void setRecipientBlockingReason(String recipientBlockingReason) { + this.recipientBlockingReason = recipientBlockingReason; + } + + public InternationalTransferInformationResponse senderBlockingReason(String senderBlockingReason) { + this.senderBlockingReason = senderBlockingReason; + return this; + } + + /** + * The reason for blocking the quotation, based on AML checks on the sender. + * @return senderBlockingReason + **/ + @Schema(description = "The reason for blocking the quotation, based on AML checks on the sender.") + + @Size(max=256) public String getSenderBlockingReason() { + return senderBlockingReason; + } + + public void setSenderBlockingReason(String senderBlockingReason) { + this.senderBlockingReason = senderBlockingReason; + } + + public InternationalTransferInformationResponse sendingServiceProviderCountry(Nationality sendingServiceProviderCountry) { + this.sendingServiceProviderCountry = sendingServiceProviderCountry; + return this; + } + + /** + * Get sendingServiceProviderCountry + * @return sendingServiceProviderCountry + **/ + @Schema(description = "") + + @Valid + public Nationality getSendingServiceProviderCountry() { + return sendingServiceProviderCountry; + } + + public void setSendingServiceProviderCountry(Nationality sendingServiceProviderCountry) { + this.sendingServiceProviderCountry = sendingServiceProviderCountry; + } + + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + InternationalTransferInformationResponse internationalTransferInformationResponse = (InternationalTransferInformationResponse) o; + return Objects.equals(this.originCountry, internationalTransferInformationResponse.originCountry) && + Objects.equals(this.quotationReference, internationalTransferInformationResponse.quotationReference) && + Objects.equals(this.quoteId, internationalTransferInformationResponse.quoteId) && + Objects.equals(this.deliveryMethod, internationalTransferInformationResponse.deliveryMethod) && + Objects.equals(this.receivingCountry, internationalTransferInformationResponse.receivingCountry) && + Objects.equals(this.relationshipSender, internationalTransferInformationResponse.relationshipSender) && + Objects.equals(this.remittancePurpose, internationalTransferInformationResponse.remittancePurpose) && + Objects.equals(this.recipientBlockingReason, internationalTransferInformationResponse.recipientBlockingReason) && + Objects.equals(this.senderBlockingReason, internationalTransferInformationResponse.senderBlockingReason) && + Objects.equals(this.sendingServiceProviderCountry, internationalTransferInformationResponse.sendingServiceProviderCountry); + } + + @Override + public int hashCode() { + return Objects.hash(originCountry, quotationReference, quoteId, deliveryMethod, receivingCountry, relationshipSender, remittancePurpose, recipientBlockingReason, senderBlockingReason, sendingServiceProviderCountry); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class InternationalTransferInformationResponse {\n"); + + sb.append(" originCountry: ").append(toIndentedString(originCountry)).append("\n"); + sb.append(" quotationReference: ").append(toIndentedString(quotationReference)).append("\n"); + sb.append(" quoteId: ").append(toIndentedString(quoteId)).append("\n"); + sb.append(" deliveryMethod: ").append(toIndentedString(deliveryMethod)).append("\n"); + sb.append(" receivingCountry: ").append(toIndentedString(receivingCountry)).append("\n"); + sb.append(" relationshipSender: ").append(toIndentedString(relationshipSender)).append("\n"); + sb.append(" remittancePurpose: ").append(toIndentedString(remittancePurpose)).append("\n"); + sb.append(" recipientBlockingReason: ").append(toIndentedString(recipientBlockingReason)).append("\n"); + sb.append(" senderBlockingReason: ").append(toIndentedString(senderBlockingReason)).append("\n"); + sb.append(" sendingServiceProviderCountry: ").append(toIndentedString(sendingServiceProviderCountry)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/Kyc.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/Kyc.java new file mode 100644 index 000000000..cd30ce388 --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/Kyc.java @@ -0,0 +1,327 @@ +package org.mifos.connector.gsmastub.model; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import org.springframework.validation.annotation.Validated; +import org.threeten.bp.LocalDate; + +import javax.validation.Valid; +import javax.validation.constraints.Size; +import java.util.Objects; + +/** + * Kyc + */ +@Validated +@javax.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.SpringCodegen", date = "2022-09-27T11:46:46.417Z[GMT]") + + +public class Kyc { + @JsonProperty("birthCountry") + private Nationality birthCountry = null; + + @JsonProperty("contactPhone") + private String contactPhone = null; + + @JsonProperty("dateOfBirth") + private LocalDate dateOfBirth = null; + + @JsonProperty("emailAddress") + private String emailAddress = null; + + @JsonProperty("employerName") + private String employerName = null; + + @JsonProperty("gender") + private Gender gender = null; + + @JsonProperty("idDocument") + private IdDocumentArray idDocument = null; + + @JsonProperty("nationality") + private Nationality nationality = null; + + @JsonProperty("occupation") + private String occupation = null; + + @JsonProperty("postalAddress") + private PostalAddress postalAddress = null; + + @JsonProperty("subjectName") + private SubjectName subjectName = null; + + public Kyc birthCountry(Nationality birthCountry) { + this.birthCountry = birthCountry; + return this; + } + + /** + * Get birthCountry + * @return birthCountry + **/ + @Schema(description = "") + + @Valid + public Nationality getBirthCountry() { + return birthCountry; + } + + public void setBirthCountry(Nationality birthCountry) { + this.birthCountry = birthCountry; + } + + public Kyc contactPhone(String contactPhone) { + this.contactPhone = contactPhone; + return this; + } + + /** + * Contact phone number (mobile or landline) of the KYC subject. + * @return contactPhone + **/ + @Schema(description = "Contact phone number (mobile or landline) of the KYC subject.") + + @Size(max=256) public String getContactPhone() { + return contactPhone; + } + + public void setContactPhone(String contactPhone) { + this.contactPhone = contactPhone; + } + + public Kyc dateOfBirth(LocalDate dateOfBirth) { + this.dateOfBirth = dateOfBirth; + return this; + } + + /** + * Birth date of the KYC subject. + * @return dateOfBirth + **/ + @Schema(example = "Mon Nov 20 00:00:00 GMT 2000", description = "Birth date of the KYC subject.") + + @Valid + public LocalDate getDateOfBirth() { + return dateOfBirth; + } + + public void setDateOfBirth(LocalDate dateOfBirth) { + this.dateOfBirth = dateOfBirth; + } + + public Kyc emailAddress(String emailAddress) { + this.emailAddress = emailAddress; + return this; + } + + /** + * Email address of the KYC subject. + * @return emailAddress + **/ + @Schema(description = "Email address of the KYC subject.") + + @Size(max=256) public String getEmailAddress() { + return emailAddress; + } + + public void setEmailAddress(String emailAddress) { + this.emailAddress = emailAddress; + } + + public Kyc employerName(String employerName) { + this.employerName = employerName; + return this; + } + + /** + * Employer name of the KYC subject. + * @return employerName + **/ + @Schema(description = "Employer name of the KYC subject.") + + @Size(max=256) public String getEmployerName() { + return employerName; + } + + public void setEmployerName(String employerName) { + this.employerName = employerName; + } + + public Kyc gender(Gender gender) { + this.gender = gender; + return this; + } + + /** + * Get gender + * @return gender + **/ + @Schema(description = "") + + @Valid + public Gender getGender() { + return gender; + } + + public void setGender(Gender gender) { + this.gender = gender; + } + + public Kyc idDocument(IdDocumentArray idDocument) { + this.idDocument = idDocument; + return this; + } + + /** + * Get idDocument + * @return idDocument + **/ + @Schema(description = "") + + @Valid + public IdDocumentArray getIdDocument() { + return idDocument; + } + + public void setIdDocument(IdDocumentArray idDocument) { + this.idDocument = idDocument; + } + + public Kyc nationality(Nationality nationality) { + this.nationality = nationality; + return this; + } + + /** + * Get nationality + * @return nationality + **/ + @Schema(description = "") + + @Valid + public Nationality getNationality() { + return nationality; + } + + public void setNationality(Nationality nationality) { + this.nationality = nationality; + } + + public Kyc occupation(String occupation) { + this.occupation = occupation; + return this; + } + + /** + * Occupation of the KYC subject. + * @return occupation + **/ + @Schema(description = "Occupation of the KYC subject.") + + @Size(max=256) public String getOccupation() { + return occupation; + } + + public void setOccupation(String occupation) { + this.occupation = occupation; + } + + public Kyc postalAddress(PostalAddress postalAddress) { + this.postalAddress = postalAddress; + return this; + } + + /** + * Get postalAddress + * @return postalAddress + **/ + @Schema(description = "") + + @Valid + public PostalAddress getPostalAddress() { + return postalAddress; + } + + public void setPostalAddress(PostalAddress postalAddress) { + this.postalAddress = postalAddress; + } + + public Kyc subjectName(SubjectName subjectName) { + this.subjectName = subjectName; + return this; + } + + /** + * Get subjectName + * @return subjectName + **/ + @Schema(description = "") + + @Valid + public SubjectName getSubjectName() { + return subjectName; + } + + public void setSubjectName(SubjectName subjectName) { + this.subjectName = subjectName; + } + + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Kyc kyc = (Kyc) o; + return Objects.equals(this.birthCountry, kyc.birthCountry) && + Objects.equals(this.contactPhone, kyc.contactPhone) && + Objects.equals(this.dateOfBirth, kyc.dateOfBirth) && + Objects.equals(this.emailAddress, kyc.emailAddress) && + Objects.equals(this.employerName, kyc.employerName) && + Objects.equals(this.gender, kyc.gender) && + Objects.equals(this.idDocument, kyc.idDocument) && + Objects.equals(this.nationality, kyc.nationality) && + Objects.equals(this.occupation, kyc.occupation) && + Objects.equals(this.postalAddress, kyc.postalAddress) && + Objects.equals(this.subjectName, kyc.subjectName); + } + + @Override + public int hashCode() { + return Objects.hash(birthCountry, contactPhone, dateOfBirth, emailAddress, employerName, gender, idDocument, nationality, occupation, postalAddress, subjectName); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class Kyc {\n"); + + sb.append(" birthCountry: ").append(toIndentedString(birthCountry)).append("\n"); + sb.append(" contactPhone: ").append(toIndentedString(contactPhone)).append("\n"); + sb.append(" dateOfBirth: ").append(toIndentedString(dateOfBirth)).append("\n"); + sb.append(" emailAddress: ").append(toIndentedString(emailAddress)).append("\n"); + sb.append(" employerName: ").append(toIndentedString(employerName)).append("\n"); + sb.append(" gender: ").append(toIndentedString(gender)).append("\n"); + sb.append(" idDocument: ").append(toIndentedString(idDocument)).append("\n"); + sb.append(" nationality: ").append(toIndentedString(nationality)).append("\n"); + sb.append(" occupation: ").append(toIndentedString(occupation)).append("\n"); + sb.append(" postalAddress: ").append(toIndentedString(postalAddress)).append("\n"); + sb.append(" subjectName: ").append(toIndentedString(subjectName)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/KycVerificationStatus.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/KycVerificationStatus.java new file mode 100644 index 000000000..5275161ee --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/KycVerificationStatus.java @@ -0,0 +1,35 @@ +package org.mifos.connector.gsmastub.model; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonValue; + +/** + * Indicates the status of the identity’s KYC verification. + */ +public enum KycVerificationStatus { + VERIFIED("verified"), + UNVERIFIED("unverified"), + REJECTED("rejected"); + + private String value; + + KycVerificationStatus(String value) { + this.value = value; + } + + @Override + @JsonValue + public String toString() { + return String.valueOf(value); + } + + @JsonCreator + public static KycVerificationStatus fromValue(String text) { + for (KycVerificationStatus b : KycVerificationStatus.values()) { + if (String.valueOf(b.value).equals(text)) { + return b; + } + } + return null; + } +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/MandateStatus.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/MandateStatus.java new file mode 100644 index 000000000..21c9a5f29 --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/MandateStatus.java @@ -0,0 +1,34 @@ +package org.mifos.connector.gsmastub.model; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonValue; + +/** + * Gets or Sets mandateStatus + */ +public enum MandateStatus { + ACTIVE("active"), + INACTIVE("inactive"); + + private String value; + + MandateStatus(String value) { + this.value = value; + } + + @Override + @JsonValue + public String toString() { + return String.valueOf(value); + } + + @JsonCreator + public static MandateStatus fromValue(String text) { + for (MandateStatus b : MandateStatus.values()) { + if (String.valueOf(b.value).equals(text)) { + return b; + } + } + return null; + } +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/Metadata.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/Metadata.java new file mode 100644 index 000000000..a07e550d3 --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/Metadata.java @@ -0,0 +1,105 @@ +package org.mifos.connector.gsmastub.model; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import org.springframework.validation.annotation.Validated; + +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; +import java.util.Objects; + +/** + * Metadata + */ +@Validated +@javax.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.SpringCodegen", date = "2022-09-27T11:46:46.417Z[GMT]") + + +public class Metadata { + @JsonProperty("key") + private String key = null; + + @JsonProperty("value") + private String value = null; + + public Metadata key(String key) { + this.key = key; + return this; + } + + /** + * Identifies the type of additional field. + * @return key + **/ + @Schema(required = true, description = "Identifies the type of additional field.") + @NotNull + + @Size(min=1,max=256) public String getKey() { + return key; + } + + public void setKey(String key) { + this.key = key; + } + + public Metadata value(String value) { + this.value = value; + return this; + } + + /** + * Identifies the value of the additional field. + * @return value + **/ + @Schema(required = true, description = "Identifies the value of the additional field.") + @NotNull + + @Size(min=1,max=256) public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } + + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Metadata metadata = (Metadata) o; + return Objects.equals(this.key, metadata.key) && + Objects.equals(this.value, metadata.value); + } + + @Override + public int hashCode() { + return Objects.hash(key, value); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class Metadata {\n"); + + sb.append(" key: ").append(toIndentedString(key)).append("\n"); + sb.append(" value: ").append(toIndentedString(value)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/MetadataArray.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/MetadataArray.java new file mode 100644 index 000000000..9ccb81f71 --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/MetadataArray.java @@ -0,0 +1,54 @@ +package org.mifos.connector.gsmastub.model; + +import io.swagger.v3.oas.annotations.media.Schema; +import org.springframework.validation.annotation.Validated; + +import java.util.ArrayList; +import java.util.Objects; + +/** + * A collection of key/value pairs. These can be used to populate additional properties that describe administrative information regarding the resource. + */ +@Schema(description = "A collection of key/value pairs. These can be used to populate additional properties that describe administrative information regarding the resource.") +@Validated +@javax.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.SpringCodegen", date = "2022-09-27T11:46:46.417Z[GMT]") + + +public class MetadataArray extends ArrayList { + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + return true; + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode()); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class MetadataArray {\n"); + sb.append(" ").append(toIndentedString(super.toString())).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/Mode.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/Mode.java new file mode 100644 index 000000000..60b8a8aa6 --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/Mode.java @@ -0,0 +1,35 @@ +package org.mifos.connector.gsmastub.model; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonValue; + +/** + * Gets or Sets mode + */ +public enum Mode { + PUSH("push"), + PULL("pull"), + BOTH("both"); + + private String value; + + Mode(String value) { + this.value = value; + } + + @Override + @JsonValue + public String toString() { + return String.valueOf(value); + } + + @JsonCreator + public static Mode fromValue(String text) { + for (Mode b : Mode.values()) { + if (String.valueOf(b.value).equals(text)) { + return b; + } + } + return null; + } +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/Nationality.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/Nationality.java new file mode 100644 index 000000000..fac9ff117 --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/Nationality.java @@ -0,0 +1,281 @@ +package org.mifos.connector.gsmastub.model; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonValue; + +/** + * Gets or Sets nationality + */ +public enum Nationality { + AD("AD"), + AE("AE"), + AF("AF"), + AG("AG"), + AI("AI"), + AL("AL"), + AM("AM"), + AO("AO"), + AQ("AQ"), + AR("AR"), + AS("AS"), + AT("AT"), + AU("AU"), + AW("AW"), + AX("AX"), + AZ("AZ"), + BA("BA"), + BB("BB"), + BD("BD"), + BE("BE"), + BF("BF"), + BG("BG"), + BH("BH"), + BI("BI"), + BJ("BJ"), + BL("BL"), + BM("BM"), + BN("BN"), + BO("BO"), + BQ("BQ"), + BR("BR"), + BS("BS"), + BT("BT"), + BV("BV"), + BW("BW"), + BY("BY"), + BZ("BZ"), + CA("CA"), + CC("CC"), + CD("CD"), + CF("CF"), + CG("CG"), + CH("CH"), + CI("CI"), + CK("CK"), + CL("CL"), + CM("CM"), + CN("CN"), + CO("CO"), + CR("CR"), + CU("CU"), + CV("CV"), + CW("CW"), + CX("CX"), + CY("CY"), + CZ("CZ"), + DE("DE"), + DJ("DJ"), + DK("DK"), + DM("DM"), + DO("DO"), + DZ("DZ"), + EC("EC"), + EE("EE"), + EG("EG"), + EH("EH"), + ER("ER"), + ES("ES"), + ET("ET"), + FI("FI"), + FJ("FJ"), + FK("FK"), + FM("FM"), + FO("FO"), + FR("FR"), + GA("GA"), + GB("GB"), + GD("GD"), + GE("GE"), + GF("GF"), + GG("GG"), + GH("GH"), + GI("GI"), + GL("GL"), + GM("GM"), + GN("GN"), + GP("GP"), + GQ("GQ"), + GR("GR"), + GS("GS"), + GT("GT"), + GU("GU"), + GW("GW"), + GY("GY"), + HK("HK"), + HM("HM"), + HN("HN"), + HR("HR"), + HT("HT"), + HU("HU"), + ID("ID"), + IE("IE"), + IL("IL"), + IM("IM"), + IN("IN"), + IO("IO"), + IQ("IQ"), + IR("IR"), + IS("IS"), + IT("IT"), + JE("JE"), + JM("JM"), + JO("JO"), + JP("JP"), + KE("KE"), + KG("KG"), + KH("KH"), + KI("KI"), + KM("KM"), + KN("KN"), + KP("KP"), + KR("KR"), + KW("KW"), + KY("KY"), + KZ("KZ"), + LA("LA"), + LB("LB"), + LC("LC"), + LI("LI"), + LK("LK"), + LR("LR"), + LS("LS"), + LT("LT"), + LU("LU"), + LV("LV"), + LY("LY"), + MA("MA"), + MC("MC"), + MD("MD"), + ME("ME"), + MF("MF"), + MG("MG"), + MH("MH"), + MK("MK"), + ML("ML"), + MM("MM"), + MN("MN"), + MO("MO"), + MP("MP"), + MQ("MQ"), + MR("MR"), + MS("MS"), + MT("MT"), + MU("MU"), + MV("MV"), + MW("MW"), + MX("MX"), + MY("MY"), + MZ("MZ"), + NA("NA"), + NC("NC"), + NE("NE"), + NF("NF"), + NG("NG"), + NI("NI"), + NL("NL"), + NO("NO"), + NP("NP"), + NR("NR"), + NU("NU"), + NZ("NZ"), + OM("OM"), + PA("PA"), + PE("PE"), + PF("PF"), + PG("PG"), + PH("PH"), + PK("PK"), + PL("PL"), + PM("PM"), + PN("PN"), + PR("PR"), + PS("PS"), + PT("PT"), + PW("PW"), + PY("PY"), + QA("QA"), + RE("RE"), + RO("RO"), + RS("RS"), + RU("RU"), + RW("RW"), + SA("SA"), + SB("SB"), + SC("SC"), + SD("SD"), + SE("SE"), + SG("SG"), + SH("SH"), + SI("SI"), + SJ("SJ"), + SK("SK"), + SL("SL"), + SM("SM"), + SN("SN"), + SO("SO"), + SR("SR"), + SS("SS"), + ST("ST"), + SV("SV"), + SX("SX"), + SY("SY"), + SZ("SZ"), + TC("TC"), + TD("TD"), + TF("TF"), + TG("TG"), + TH("TH"), + TJ("TJ"), + TK("TK"), + TL("TL"), + TM("TM"), + TN("TN"), + TO("TO"), + TR("TR"), + TT("TT"), + TV("TV"), + TW("TW"), + TZ("TZ"), + UA("UA"), + UG("UG"), + UM("UM"), + US("US"), + UY("UY"), + UZ("UZ"), + VA("VA"), + VC("VC"), + VE("VE"), + VG("VG"), + VI("VI"), + VN("VN"), + VU("VU"), + WF("WF"), + WS("WS"), + YE("YE"), + YT("YT"), + ZA("ZA"), + ZM("ZM"), + ZW("ZW"); + + private String value; + + Nationality(String value) { + this.value = value; + } + + @Override + @JsonValue + public String toString() { + return String.valueOf(value); + } + + @JsonCreator + public static Nationality fromValue(String text) { + for (Nationality b : Nationality.values()) { + if (String.valueOf(b.value).equals(text)) { + return b; + } + } + return null; + } +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/Party.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/Party.java new file mode 100644 index 000000000..27dfe4545 --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/Party.java @@ -0,0 +1,105 @@ +package org.mifos.connector.gsmastub.model; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import org.springframework.validation.annotation.Validated; + +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; +import java.util.Objects; + +/** + * Party + */ +@Validated +@javax.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.SpringCodegen", date = "2022-09-27T11:46:46.417Z[GMT]") + + +public class Party { + @JsonProperty("key") + private String key = null; + + @JsonProperty("value") + private String value = null; + + public Party key(String key) { + this.key = key; + return this; + } + + /** + * Provides the account identifier type. + * @return key + **/ + @Schema(example = "msisdn", required = true, description = "Provides the account identifier type.") + @NotNull + + @Size(min=1,max=256) public String getKey() { + return key; + } + + public void setKey(String key) { + this.key = key; + } + + public Party value(String value) { + this.value = value; + return this; + } + + /** + * Provides the account identifier type value. + * @return value + **/ + @Schema(example = "+33555123456", required = true, description = "Provides the account identifier type value.") + @NotNull + + @Size(min=1,max=256) public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } + + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Party party = (Party) o; + return Objects.equals(this.key, party.key) && + Objects.equals(this.value, party.value); + } + + @Override + public int hashCode() { + return Objects.hash(key, value); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class Party {\n"); + + sb.append(" key: ").append(toIndentedString(key)).append("\n"); + sb.append(" value: ").append(toIndentedString(value)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/Payee.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/Payee.java new file mode 100644 index 000000000..9b40e777d --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/Payee.java @@ -0,0 +1,54 @@ +package org.mifos.connector.gsmastub.model; + +import io.swagger.v3.oas.annotations.media.Schema; +import org.springframework.validation.annotation.Validated; + +import java.util.ArrayList; +import java.util.Objects; + +/** + * A collection of key/value pairs that enable the payee to be identified. Keys include MSISDN and Wallet Identifier. + */ +@Schema(description = "A collection of key/value pairs that enable the payee to be identified. Keys include MSISDN and Wallet Identifier.") +@Validated +@javax.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.SpringCodegen", date = "2022-09-27T11:46:46.417Z[GMT]") + + +public class Payee extends ArrayList { + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + return true; + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode()); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class Payee {\n"); + sb.append(" ").append(toIndentedString(super.toString())).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/PaymentType.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/PaymentType.java new file mode 100644 index 000000000..840d1c53a --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/PaymentType.java @@ -0,0 +1,34 @@ +package org.mifos.connector.gsmastub.model; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonValue; + +/** + * Gets or Sets paymentType + */ +public enum PaymentType { + PARTIALPAYMENT("partialpayment"), + FULLPAYMENT("fullpayment"); + + private String value; + + PaymentType(String value) { + this.value = value; + } + + @Override + @JsonValue + public String toString() { + return String.valueOf(value); + } + + @JsonCreator + public static PaymentType fromValue(String text) { + for (PaymentType b : PaymentType.values()) { + if (String.valueOf(b.value).equals(text)) { + return b; + } + } + return null; + } +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/PostalAddress.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/PostalAddress.java new file mode 100644 index 000000000..c5307f43d --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/PostalAddress.java @@ -0,0 +1,226 @@ +package org.mifos.connector.gsmastub.model; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import org.springframework.validation.annotation.Validated; + +import javax.validation.Valid; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; +import java.util.Objects; + +/** + * PostalAddress + */ +@Validated +@javax.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.SpringCodegen", date = "2022-09-27T11:46:46.417Z[GMT]") + + +public class PostalAddress { + @JsonProperty("addressLine1") + private String addressLine1 = null; + + @JsonProperty("addressLine2") + private String addressLine2 = null; + + @JsonProperty("addressLine3") + private String addressLine3 = null; + + @JsonProperty("city") + private String city = null; + + @JsonProperty("stateProvince") + private String stateProvince = null; + + @JsonProperty("postalCode") + private String postalCode = null; + + @JsonProperty("country") + private Nationality country = null; + + public PostalAddress addressLine1(String addressLine1) { + this.addressLine1 = addressLine1; + return this; + } + + /** + * First line of the address. + * @return addressLine1 + **/ + @Schema(description = "First line of the address.") + + @Size(max=256) public String getAddressLine1() { + return addressLine1; + } + + public void setAddressLine1(String addressLine1) { + this.addressLine1 = addressLine1; + } + + public PostalAddress addressLine2(String addressLine2) { + this.addressLine2 = addressLine2; + return this; + } + + /** + * Second line of the address. + * @return addressLine2 + **/ + @Schema(description = "Second line of the address.") + + @Size(max=256) public String getAddressLine2() { + return addressLine2; + } + + public void setAddressLine2(String addressLine2) { + this.addressLine2 = addressLine2; + } + + public PostalAddress addressLine3(String addressLine3) { + this.addressLine3 = addressLine3; + return this; + } + + /** + * Third line of the address. + * @return addressLine3 + **/ + @Schema(description = "Third line of the address.") + + @Size(max=256) public String getAddressLine3() { + return addressLine3; + } + + public void setAddressLine3(String addressLine3) { + this.addressLine3 = addressLine3; + } + + public PostalAddress city(String city) { + this.city = city; + return this; + } + + /** + * City/Town + * @return city + **/ + @Schema(description = "City/Town") + + @Size(max=256) public String getCity() { + return city; + } + + public void setCity(String city) { + this.city = city; + } + + public PostalAddress stateProvince(String stateProvince) { + this.stateProvince = stateProvince; + return this; + } + + /** + * State or Province + * @return stateProvince + **/ + @Schema(description = "State or Province") + + @Size(max=256) public String getStateProvince() { + return stateProvince; + } + + public void setStateProvince(String stateProvince) { + this.stateProvince = stateProvince; + } + + public PostalAddress postalCode(String postalCode) { + this.postalCode = postalCode; + return this; + } + + /** + * Postal Code + * @return postalCode + **/ + @Schema(description = "Postal Code") + + @Size(max=256) public String getPostalCode() { + return postalCode; + } + + public void setPostalCode(String postalCode) { + this.postalCode = postalCode; + } + + public PostalAddress country(Nationality country) { + this.country = country; + return this; + } + + /** + * Get country + * @return country + **/ + @Schema(required = true, description = "") + @NotNull + + @Valid + public Nationality getCountry() { + return country; + } + + public void setCountry(Nationality country) { + this.country = country; + } + + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + PostalAddress postalAddress = (PostalAddress) o; + return Objects.equals(this.addressLine1, postalAddress.addressLine1) && + Objects.equals(this.addressLine2, postalAddress.addressLine2) && + Objects.equals(this.addressLine3, postalAddress.addressLine3) && + Objects.equals(this.city, postalAddress.city) && + Objects.equals(this.stateProvince, postalAddress.stateProvince) && + Objects.equals(this.postalCode, postalAddress.postalCode) && + Objects.equals(this.country, postalAddress.country); + } + + @Override + public int hashCode() { + return Objects.hash(addressLine1, addressLine2, addressLine3, city, stateProvince, postalCode, country); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class PostalAddress {\n"); + + sb.append(" addressLine1: ").append(toIndentedString(addressLine1)).append("\n"); + sb.append(" addressLine2: ").append(toIndentedString(addressLine2)).append("\n"); + sb.append(" addressLine3: ").append(toIndentedString(addressLine3)).append("\n"); + sb.append(" city: ").append(toIndentedString(city)).append("\n"); + sb.append(" stateProvince: ").append(toIndentedString(stateProvince)).append("\n"); + sb.append(" postalCode: ").append(toIndentedString(postalCode)).append("\n"); + sb.append(" country: ").append(toIndentedString(country)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/QuotationStatus.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/QuotationStatus.java new file mode 100644 index 000000000..c6660de10 --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/QuotationStatus.java @@ -0,0 +1,35 @@ +package org.mifos.connector.gsmastub.model; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonValue; + +/** + * Indicates the creation state of the Quotation. + */ +public enum QuotationStatus { + PENDING("pending"), + REJECTED("rejected"), + COMPLETED("completed"); + + private String value; + + QuotationStatus(String value) { + this.value = value; + } + + @Override + @JsonValue + public String toString() { + return String.valueOf(value); + } + + @JsonCreator + public static QuotationStatus fromValue(String text) { + for (QuotationStatus b : QuotationStatus.values()) { + if (String.valueOf(b.value).equals(text)) { + return b; + } + } + return null; + } +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/QuoteArray.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/QuoteArray.java new file mode 100644 index 000000000..3ce67630b --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/QuoteArray.java @@ -0,0 +1,54 @@ +package org.mifos.connector.gsmastub.model; + +import io.swagger.v3.oas.annotations.media.Schema; +import org.springframework.validation.annotation.Validated; + +import java.util.ArrayList; +import java.util.Objects; + +/** + * A collection of quotes. A quote can be received from a single financial service provider or from multiple providers. + */ +@Schema(description = "A collection of quotes. A quote can be received from a single financial service provider or from multiple providers.") +@Validated +@javax.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.SpringCodegen", date = "2022-09-27T11:46:46.417Z[GMT]") + + +public class QuoteArray extends ArrayList { + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + return true; + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode()); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class QuoteArray {\n"); + sb.append(" ").append(toIndentedString(super.toString())).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/Quotes.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/Quotes.java new file mode 100644 index 000000000..c6119bdc4 --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/Quotes.java @@ -0,0 +1,308 @@ +package org.mifos.connector.gsmastub.model; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import org.springframework.validation.annotation.Validated; +import org.threeten.bp.OffsetDateTime; + +import javax.validation.Valid; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Pattern; +import javax.validation.constraints.Size; +import java.util.Objects; + +/** + * Quotes + */ +@Validated +@javax.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.SpringCodegen", date = "2022-09-27T11:46:46.417Z[GMT]") + + +public class Quotes { + @JsonProperty("quoteId") + private String quoteId = null; + + @JsonProperty("receivingAmount") + private String receivingAmount = null; + + @JsonProperty("receivingCurrency") + private Currency receivingCurrency = null; + + @JsonProperty("sendingAmount") + private String sendingAmount = null; + + @JsonProperty("sendingCurrency") + private Currency sendingCurrency = null; + + @JsonProperty("deliveryMethod") + private DeliveryMethod deliveryMethod = null; + + @JsonProperty("fees") + private FeesArray fees = null; + + @JsonProperty("fxRate") + private String fxRate = null; + + @JsonProperty("quoteExpiryTime") + private OffsetDateTime quoteExpiryTime = null; + + @JsonProperty("receivingServiceProvider") + private String receivingServiceProvider = null; + + public Quotes quoteId(String quoteId) { + this.quoteId = quoteId; + return this; + } + + /** + * The specific quote associated with the quotation. + * @return quoteId + **/ + @Schema(required = true, description = "The specific quote associated with the quotation.") + @NotNull + + @Size(min=1,max=256) public String getQuoteId() { + return quoteId; + } + + public void setQuoteId(String quoteId) { + this.quoteId = quoteId; + } + + public Quotes receivingAmount(String receivingAmount) { + this.receivingAmount = receivingAmount; + return this; + } + + /** + * Get receivingAmount + * @return receivingAmount + **/ + @Schema(example = "15.21", required = true, description = "") + @NotNull + + @Pattern(regexp="^([0]|([1-9][0-9]{0,17}))([.][0-9]{0,3}[0-9])?$") @Size(min=1,max=23) public String getReceivingAmount() { + return receivingAmount; + } + + public void setReceivingAmount(String receivingAmount) { + this.receivingAmount = receivingAmount; + } + + public Quotes receivingCurrency(Currency receivingCurrency) { + this.receivingCurrency = receivingCurrency; + return this; + } + + /** + * Get receivingCurrency + * @return receivingCurrency + **/ + @Schema(required = true, description = "") + @NotNull + + @Valid + public Currency getReceivingCurrency() { + return receivingCurrency; + } + + public void setReceivingCurrency(Currency receivingCurrency) { + this.receivingCurrency = receivingCurrency; + } + + public Quotes sendingAmount(String sendingAmount) { + this.sendingAmount = sendingAmount; + return this; + } + + /** + * Get sendingAmount + * @return sendingAmount + **/ + @Schema(example = "15.21", required = true, description = "") + @NotNull + + @Pattern(regexp="^([0]|([1-9][0-9]{0,17}))([.][0-9]{0,3}[0-9])?$") @Size(min=1,max=23) public String getSendingAmount() { + return sendingAmount; + } + + public void setSendingAmount(String sendingAmount) { + this.sendingAmount = sendingAmount; + } + + public Quotes sendingCurrency(Currency sendingCurrency) { + this.sendingCurrency = sendingCurrency; + return this; + } + + /** + * Get sendingCurrency + * @return sendingCurrency + **/ + @Schema(required = true, description = "") + @NotNull + + @Valid + public Currency getSendingCurrency() { + return sendingCurrency; + } + + public void setSendingCurrency(Currency sendingCurrency) { + this.sendingCurrency = sendingCurrency; + } + + public Quotes deliveryMethod(DeliveryMethod deliveryMethod) { + this.deliveryMethod = deliveryMethod; + return this; + } + + /** + * Get deliveryMethod + * @return deliveryMethod + **/ + @Schema(description = "") + + @Valid + public DeliveryMethod getDeliveryMethod() { + return deliveryMethod; + } + + public void setDeliveryMethod(DeliveryMethod deliveryMethod) { + this.deliveryMethod = deliveryMethod; + } + + public Quotes fees(FeesArray fees) { + this.fees = fees; + return this; + } + + /** + * Get fees + * @return fees + **/ + @Schema(description = "") + + @Valid + public FeesArray getFees() { + return fees; + } + + public void setFees(FeesArray fees) { + this.fees = fees; + } + + public Quotes fxRate(String fxRate) { + this.fxRate = fxRate; + return this; + } + + /** + * The conversion rate applicable between the sending and the receiving currency for the requested transaction. + * @return fxRate + **/ + @Schema(example = "1.3436", description = "The conversion rate applicable between the sending and the receiving currency for the requested transaction.") + + @Pattern(regexp="^([0]|([1-9][0-9]{0,17}))([.][0-9]{0,10}[1-9])?$") @Size(min=4,max=256) public String getFxRate() { + return fxRate; + } + + public void setFxRate(String fxRate) { + this.fxRate = fxRate; + } + + public Quotes quoteExpiryTime(OffsetDateTime quoteExpiryTime) { + this.quoteExpiryTime = quoteExpiryTime; + return this; + } + + /** + * The timestamp when the quote will expire. + * @return quoteExpiryTime + **/ + @Schema(description = "The timestamp when the quote will expire.") + + @Valid + public OffsetDateTime getQuoteExpiryTime() { + return quoteExpiryTime; + } + + public void setQuoteExpiryTime(OffsetDateTime quoteExpiryTime) { + this.quoteExpiryTime = quoteExpiryTime; + } + + public Quotes receivingServiceProvider(String receivingServiceProvider) { + this.receivingServiceProvider = receivingServiceProvider; + return this; + } + + /** + * The name of the receiving service provider, i.e. the provider that the quote is associated with. + * @return receivingServiceProvider + **/ + @Schema(description = "The name of the receiving service provider, i.e. the provider that the quote is associated with.") + + @Size(max=256) public String getReceivingServiceProvider() { + return receivingServiceProvider; + } + + public void setReceivingServiceProvider(String receivingServiceProvider) { + this.receivingServiceProvider = receivingServiceProvider; + } + + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Quotes quotes = (Quotes) o; + return Objects.equals(this.quoteId, quotes.quoteId) && + Objects.equals(this.receivingAmount, quotes.receivingAmount) && + Objects.equals(this.receivingCurrency, quotes.receivingCurrency) && + Objects.equals(this.sendingAmount, quotes.sendingAmount) && + Objects.equals(this.sendingCurrency, quotes.sendingCurrency) && + Objects.equals(this.deliveryMethod, quotes.deliveryMethod) && + Objects.equals(this.fees, quotes.fees) && + Objects.equals(this.fxRate, quotes.fxRate) && + Objects.equals(this.quoteExpiryTime, quotes.quoteExpiryTime) && + Objects.equals(this.receivingServiceProvider, quotes.receivingServiceProvider); + } + + @Override + public int hashCode() { + return Objects.hash(quoteId, receivingAmount, receivingCurrency, sendingAmount, sendingCurrency, deliveryMethod, fees, fxRate, quoteExpiryTime, receivingServiceProvider); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class Quotes {\n"); + + sb.append(" quoteId: ").append(toIndentedString(quoteId)).append("\n"); + sb.append(" receivingAmount: ").append(toIndentedString(receivingAmount)).append("\n"); + sb.append(" receivingCurrency: ").append(toIndentedString(receivingCurrency)).append("\n"); + sb.append(" sendingAmount: ").append(toIndentedString(sendingAmount)).append("\n"); + sb.append(" sendingCurrency: ").append(toIndentedString(sendingCurrency)).append("\n"); + sb.append(" deliveryMethod: ").append(toIndentedString(deliveryMethod)).append("\n"); + sb.append(" fees: ").append(toIndentedString(fees)).append("\n"); + sb.append(" fxRate: ").append(toIndentedString(fxRate)).append("\n"); + sb.append(" quoteExpiryTime: ").append(toIndentedString(quoteExpiryTime)).append("\n"); + sb.append(" receivingServiceProvider: ").append(toIndentedString(receivingServiceProvider)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/RedemptionAccountIdentifiers.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/RedemptionAccountIdentifiers.java new file mode 100644 index 000000000..a4e2f8db8 --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/RedemptionAccountIdentifiers.java @@ -0,0 +1,54 @@ +package org.mifos.connector.gsmastub.model; + +import io.swagger.v3.oas.annotations.media.Schema; +import org.springframework.validation.annotation.Validated; + +import java.util.ArrayList; +import java.util.Objects; + +/** + * A collection of key/value pairs that enable the redemption account to be identified. Keys include MSISDN and Wallet Identifier. + */ +@Schema(description = "A collection of key/value pairs that enable the redemption account to be identified. Keys include MSISDN and Wallet Identifier.") +@Validated +@javax.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.SpringCodegen", date = "2022-09-27T11:46:46.417Z[GMT]") + + +public class RedemptionAccountIdentifiers extends ArrayList { + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + return true; + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode()); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class RedemptionAccountIdentifiers {\n"); + sb.append(" ").append(toIndentedString(super.toString())).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/RedemptionChannels.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/RedemptionChannels.java new file mode 100644 index 000000000..1c49c6ce8 --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/RedemptionChannels.java @@ -0,0 +1,54 @@ +package org.mifos.connector.gsmastub.model; + +import io.swagger.v3.oas.annotations.media.Schema; +import org.springframework.validation.annotation.Validated; + +import java.util.ArrayList; +import java.util.Objects; + +/** + * Indicates the channel(s) that the code can be redeemed against, e.g. ATM, Merchant, etc. + */ +@Schema(description = "Indicates the channel(s) that the code can be redeemed against, e.g. ATM, Merchant, etc.") +@Validated +@javax.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.SpringCodegen", date = "2022-09-27T11:46:46.417Z[GMT]") + + +public class RedemptionChannels extends ArrayList { + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + return true; + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode()); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class RedemptionChannels {\n"); + sb.append(" ").append(toIndentedString(super.toString())).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/RedemptionChannelsInner.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/RedemptionChannelsInner.java new file mode 100644 index 000000000..140c11356 --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/RedemptionChannelsInner.java @@ -0,0 +1,80 @@ +package org.mifos.connector.gsmastub.model; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import org.springframework.validation.annotation.Validated; + +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; +import java.util.Objects; + +/** + * RedemptionChannelsInner + */ +@Validated +@javax.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.SpringCodegen", date = "2022-09-27T11:46:46.417Z[GMT]") + + +public class RedemptionChannelsInner { + @JsonProperty("channelType") + private String channelType = null; + + public RedemptionChannelsInner channelType(String channelType) { + this.channelType = channelType; + return this; + } + + /** + * Identifies the channel type. + * @return channelType + **/ + @Schema(required = true, description = "Identifies the channel type.") + @NotNull + + @Size(min=1,max=256) public String getChannelType() { + return channelType; + } + + public void setChannelType(String channelType) { + this.channelType = channelType; + } + + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + RedemptionChannelsInner redemptionChannelsInner = (RedemptionChannelsInner) o; + return Objects.equals(this.channelType, redemptionChannelsInner.channelType); + } + + @Override + public int hashCode() { + return Objects.hash(channelType); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class RedemptionChannelsInner {\n"); + + sb.append(" channelType: ").append(toIndentedString(channelType)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/RedemptionTransactionTypes.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/RedemptionTransactionTypes.java new file mode 100644 index 000000000..2f44e23b5 --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/RedemptionTransactionTypes.java @@ -0,0 +1,54 @@ +package org.mifos.connector.gsmastub.model; + +import io.swagger.v3.oas.annotations.media.Schema; +import org.springframework.validation.annotation.Validated; + +import java.util.ArrayList; +import java.util.Objects; + +/** + * Indicates the Transaction Types(s) that the code can be redeemed against. + */ +@Schema(description = "Indicates the Transaction Types(s) that the code can be redeemed against.") +@Validated +@javax.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.SpringCodegen", date = "2022-09-27T11:46:46.417Z[GMT]") + + +public class RedemptionTransactionTypes extends ArrayList { + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + return true; + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode()); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class RedemptionTransactionTypes {\n"); + sb.append(" ").append(toIndentedString(super.toString())).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/RedemptionTransactionTypesInner.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/RedemptionTransactionTypesInner.java new file mode 100644 index 000000000..f6215f0f3 --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/RedemptionTransactionTypesInner.java @@ -0,0 +1,106 @@ +package org.mifos.connector.gsmastub.model; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import org.springframework.validation.annotation.Validated; + +import javax.validation.Valid; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; +import java.util.Objects; + +/** + * RedemptionTransactionTypesInner + */ +@Validated +@javax.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.SpringCodegen", date = "2022-09-27T11:46:46.417Z[GMT]") + + +public class RedemptionTransactionTypesInner { + @JsonProperty("transactionType") + private Type transactionType = null; + + @JsonProperty("transactionSubtype") + private String transactionSubtype = null; + + public RedemptionTransactionTypesInner transactionType(Type transactionType) { + this.transactionType = transactionType; + return this; + } + + /** + * Get transactionType + * @return transactionType + **/ + @Schema(required = true, description = "") + @NotNull + + @Valid + public Type getTransactionType() { + return transactionType; + } + + public void setTransactionType(Type transactionType) { + this.transactionType = transactionType; + } + + public RedemptionTransactionTypesInner transactionSubtype(String transactionSubtype) { + this.transactionSubtype = transactionSubtype; + return this; + } + + /** + * A non-harmonised sub-classification of the type of transaction. Values are not fixed, and usage will vary according to Provider. + * @return transactionSubtype + **/ + @Schema(description = "A non-harmonised sub-classification of the type of transaction. Values are not fixed, and usage will vary according to Provider.") + + @Size(max=256) public String getTransactionSubtype() { + return transactionSubtype; + } + + public void setTransactionSubtype(String transactionSubtype) { + this.transactionSubtype = transactionSubtype; + } + + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + RedemptionTransactionTypesInner redemptionTransactionTypesInner = (RedemptionTransactionTypesInner) o; + return Objects.equals(this.transactionType, redemptionTransactionTypesInner.transactionType) && + Objects.equals(this.transactionSubtype, redemptionTransactionTypesInner.transactionSubtype); + } + + @Override + public int hashCode() { + return Objects.hash(transactionType, transactionSubtype); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class RedemptionTransactionTypesInner {\n"); + + sb.append(" transactionType: ").append(toIndentedString(transactionType)).append("\n"); + sb.append(" transactionSubtype: ").append(toIndentedString(transactionSubtype)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/RequestAccount.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/RequestAccount.java new file mode 100644 index 000000000..77a281aa8 --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/RequestAccount.java @@ -0,0 +1,231 @@ +package org.mifos.connector.gsmastub.model; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import org.springframework.validation.annotation.Validated; +import org.threeten.bp.OffsetDateTime; + +import javax.validation.Valid; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; +import java.util.Objects; + +/** + * RequestAccount + */ +@Validated +@javax.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.SpringCodegen", date = "2022-09-27T11:46:46.417Z[GMT]") + + +public class RequestAccount { + @JsonProperty("accountIdentifiers") + private AccountIdentifiersArray accountIdentifiers = null; + + @JsonProperty("identity") + private IdentityRequestArray identity = null; + + @JsonProperty("accountType") + private String accountType = null; + + @JsonProperty("customData") + private CustomDataArray customData = null; + + @JsonProperty("fees") + private FeesArray fees = null; + + @JsonProperty("registeringEntity") + private String registeringEntity = null; + + @JsonProperty("requestDate") + private OffsetDateTime requestDate = null; + + public RequestAccount accountIdentifiers(AccountIdentifiersArray accountIdentifiers) { + this.accountIdentifiers = accountIdentifiers; + return this; + } + + /** + * Get accountIdentifiers + * @return accountIdentifiers + **/ + @Schema(description = "") + + @Valid + public AccountIdentifiersArray getAccountIdentifiers() { + return accountIdentifiers; + } + + public void setAccountIdentifiers(AccountIdentifiersArray accountIdentifiers) { + this.accountIdentifiers = accountIdentifiers; + } + + public RequestAccount identity(IdentityRequestArray identity) { + this.identity = identity; + return this; + } + + /** + * Get identity + * @return identity + **/ + @Schema(required = true, description = "") + @NotNull + + @Valid + public IdentityRequestArray getIdentity() { + return identity; + } + + public void setIdentity(IdentityRequestArray identity) { + this.identity = identity; + } + + public RequestAccount accountType(String accountType) { + this.accountType = accountType; + return this; + } + + /** + * A non-harmonised field that indicates the type of the account. + * @return accountType + **/ + @Schema(description = "A non-harmonised field that indicates the type of the account.") + + @Size(max=256) public String getAccountType() { + return accountType; + } + + public void setAccountType(String accountType) { + this.accountType = accountType; + } + + public RequestAccount customData(CustomDataArray customData) { + this.customData = customData; + return this; + } + + /** + * Get customData + * @return customData + **/ + @Schema(description = "") + + @Valid + public CustomDataArray getCustomData() { + return customData; + } + + public void setCustomData(CustomDataArray customData) { + this.customData = customData; + } + + public RequestAccount fees(FeesArray fees) { + this.fees = fees; + return this; + } + + /** + * Get fees + * @return fees + **/ + @Schema(description = "") + + @Valid + public FeesArray getFees() { + return fees; + } + + public void setFees(FeesArray fees) { + this.fees = fees; + } + + public RequestAccount registeringEntity(String registeringEntity) { + this.registeringEntity = registeringEntity; + return this; + } + + /** + * The entity that registered the account, for example, a mobile money agent. + * @return registeringEntity + **/ + @Schema(description = "The entity that registered the account, for example, a mobile money agent.") + + @Size(max=256) public String getRegisteringEntity() { + return registeringEntity; + } + + public void setRegisteringEntity(String registeringEntity) { + this.registeringEntity = registeringEntity; + } + + public RequestAccount requestDate(OffsetDateTime requestDate) { + this.requestDate = requestDate; + return this; + } + + /** + * The date and time of the request as supplied by the client. + * @return requestDate + **/ + @Schema(description = "The date and time of the request as supplied by the client.") + + @Valid + public OffsetDateTime getRequestDate() { + return requestDate; + } + + public void setRequestDate(OffsetDateTime requestDate) { + this.requestDate = requestDate; + } + + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + RequestAccount requestAccount = (RequestAccount) o; + return Objects.equals(this.accountIdentifiers, requestAccount.accountIdentifiers) && + Objects.equals(this.identity, requestAccount.identity) && + Objects.equals(this.accountType, requestAccount.accountType) && + Objects.equals(this.customData, requestAccount.customData) && + Objects.equals(this.fees, requestAccount.fees) && + Objects.equals(this.registeringEntity, requestAccount.registeringEntity) && + Objects.equals(this.requestDate, requestAccount.requestDate); + } + + @Override + public int hashCode() { + return Objects.hash(accountIdentifiers, identity, accountType, customData, fees, registeringEntity, requestDate); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class RequestAccount {\n"); + + sb.append(" accountIdentifiers: ").append(toIndentedString(accountIdentifiers)).append("\n"); + sb.append(" identity: ").append(toIndentedString(identity)).append("\n"); + sb.append(" accountType: ").append(toIndentedString(accountType)).append("\n"); + sb.append(" customData: ").append(toIndentedString(customData)).append("\n"); + sb.append(" fees: ").append(toIndentedString(fees)).append("\n"); + sb.append(" registeringEntity: ").append(toIndentedString(registeringEntity)).append("\n"); + sb.append(" requestDate: ").append(toIndentedString(requestDate)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/RequestAuthorisationCode.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/RequestAuthorisationCode.java new file mode 100644 index 000000000..7b2be01af --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/RequestAuthorisationCode.java @@ -0,0 +1,358 @@ +package org.mifos.connector.gsmastub.model; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import org.springframework.validation.annotation.Validated; +import org.threeten.bp.OffsetDateTime; + +import javax.validation.Valid; +import javax.validation.constraints.DecimalMin; +import javax.validation.constraints.Pattern; +import javax.validation.constraints.Size; +import java.math.BigDecimal; +import java.util.Objects; + +/** + * RequestAuthorisationCode + */ +@Validated +@javax.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.SpringCodegen", date = "2022-09-27T11:46:46.417Z[GMT]") + + +public class RequestAuthorisationCode { + @JsonProperty("amount") + private String amount = null; + + @JsonProperty("currency") + private Currency currency = null; + + @JsonProperty("amountType") + private AmountType amountType = null; + + @JsonProperty("codeLifetime") + private BigDecimal codeLifetime = null; + + @JsonProperty("holdFundsIndicator") + private Boolean holdFundsIndicator = null; + + @JsonProperty("redemptionAccountIdentifiers") + private RedemptionAccountIdentifiers redemptionAccountIdentifiers = null; + + @JsonProperty("redemptionChannels") + private RedemptionChannels redemptionChannels = null; + + @JsonProperty("redemptionTransactionTypes") + private RedemptionTransactionTypes redemptionTransactionTypes = null; + + @JsonProperty("requestingOrganisation") + private RequestingOrganisation requestingOrganisation = null; + + @JsonProperty("requestDate") + private OffsetDateTime requestDate = null; + + @JsonProperty("customData") + private CustomDataArray customData = null; + + @JsonProperty("metadata") + private MetadataArray metadata = null; + + public RequestAuthorisationCode amount(String amount) { + this.amount = amount; + return this; + } + + /** + * Get amount + * @return amount + **/ + @Schema(example = "15.21", description = "") + + @Pattern(regexp="^([0]|([1-9][0-9]{0,17}))([.][0-9]{0,3}[0-9])?$") @Size(min=1,max=23) public String getAmount() { + return amount; + } + + public void setAmount(String amount) { + this.amount = amount; + } + + public RequestAuthorisationCode currency(Currency currency) { + this.currency = currency; + return this; + } + + /** + * Get currency + * @return currency + **/ + @Schema(description = "") + + @Valid + public Currency getCurrency() { + return currency; + } + + public void setCurrency(Currency currency) { + this.currency = currency; + } + + public RequestAuthorisationCode amountType(AmountType amountType) { + this.amountType = amountType; + return this; + } + + /** + * Get amountType + * @return amountType + **/ + @Schema(description = "") + + @Valid + public AmountType getAmountType() { + return amountType; + } + + public void setAmountType(AmountType amountType) { + this.amountType = amountType; + } + + public RequestAuthorisationCode codeLifetime(BigDecimal codeLifetime) { + this.codeLifetime = codeLifetime; + return this; + } + + /** + * Indicates the expiry time in seconds of the code. + * minimum: 1 + * @return codeLifetime + **/ + @Schema(example = "600", description = "Indicates the expiry time in seconds of the code.") + + @Valid + @DecimalMin("1") public BigDecimal getCodeLifetime() { + return codeLifetime; + } + + public void setCodeLifetime(BigDecimal codeLifetime) { + this.codeLifetime = codeLifetime; + } + + public RequestAuthorisationCode holdFundsIndicator(Boolean holdFundsIndicator) { + this.holdFundsIndicator = holdFundsIndicator; + return this; + } + + /** + * Indicates whether funds should be reserved against the payers account where the payer is the requestor. + * @return holdFundsIndicator + **/ + @Schema(description = "Indicates whether funds should be reserved against the payers account where the payer is the requestor.") + + public Boolean isHoldFundsIndicator() { + return holdFundsIndicator; + } + + public void setHoldFundsIndicator(Boolean holdFundsIndicator) { + this.holdFundsIndicator = holdFundsIndicator; + } + + public RequestAuthorisationCode redemptionAccountIdentifiers(RedemptionAccountIdentifiers redemptionAccountIdentifiers) { + this.redemptionAccountIdentifiers = redemptionAccountIdentifiers; + return this; + } + + /** + * Get redemptionAccountIdentifiers + * @return redemptionAccountIdentifiers + **/ + @Schema(description = "") + + @Valid + public RedemptionAccountIdentifiers getRedemptionAccountIdentifiers() { + return redemptionAccountIdentifiers; + } + + public void setRedemptionAccountIdentifiers(RedemptionAccountIdentifiers redemptionAccountIdentifiers) { + this.redemptionAccountIdentifiers = redemptionAccountIdentifiers; + } + + public RequestAuthorisationCode redemptionChannels(RedemptionChannels redemptionChannels) { + this.redemptionChannels = redemptionChannels; + return this; + } + + /** + * Get redemptionChannels + * @return redemptionChannels + **/ + @Schema(description = "") + + @Valid + public RedemptionChannels getRedemptionChannels() { + return redemptionChannels; + } + + public void setRedemptionChannels(RedemptionChannels redemptionChannels) { + this.redemptionChannels = redemptionChannels; + } + + public RequestAuthorisationCode redemptionTransactionTypes(RedemptionTransactionTypes redemptionTransactionTypes) { + this.redemptionTransactionTypes = redemptionTransactionTypes; + return this; + } + + /** + * Get redemptionTransactionTypes + * @return redemptionTransactionTypes + **/ + @Schema(description = "") + + @Valid + public RedemptionTransactionTypes getRedemptionTransactionTypes() { + return redemptionTransactionTypes; + } + + public void setRedemptionTransactionTypes(RedemptionTransactionTypes redemptionTransactionTypes) { + this.redemptionTransactionTypes = redemptionTransactionTypes; + } + + public RequestAuthorisationCode requestingOrganisation(RequestingOrganisation requestingOrganisation) { + this.requestingOrganisation = requestingOrganisation; + return this; + } + + /** + * Get requestingOrganisation + * @return requestingOrganisation + **/ + @Schema(description = "") + + @Valid + public RequestingOrganisation getRequestingOrganisation() { + return requestingOrganisation; + } + + public void setRequestingOrganisation(RequestingOrganisation requestingOrganisation) { + this.requestingOrganisation = requestingOrganisation; + } + + public RequestAuthorisationCode requestDate(OffsetDateTime requestDate) { + this.requestDate = requestDate; + return this; + } + + /** + * The date and time of the request as supplied by the client. + * @return requestDate + **/ + @Schema(description = "The date and time of the request as supplied by the client.") + + @Valid + public OffsetDateTime getRequestDate() { + return requestDate; + } + + public void setRequestDate(OffsetDateTime requestDate) { + this.requestDate = requestDate; + } + + public RequestAuthorisationCode customData(CustomDataArray customData) { + this.customData = customData; + return this; + } + + /** + * Get customData + * @return customData + **/ + @Schema(description = "") + + @Valid + public CustomDataArray getCustomData() { + return customData; + } + + public void setCustomData(CustomDataArray customData) { + this.customData = customData; + } + + public RequestAuthorisationCode metadata(MetadataArray metadata) { + this.metadata = metadata; + return this; + } + + /** + * Get metadata + * @return metadata + **/ + @Schema(description = "") + + @Valid + public MetadataArray getMetadata() { + return metadata; + } + + public void setMetadata(MetadataArray metadata) { + this.metadata = metadata; + } + + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + RequestAuthorisationCode requestAuthorisationCode = (RequestAuthorisationCode) o; + return Objects.equals(this.amount, requestAuthorisationCode.amount) && + Objects.equals(this.currency, requestAuthorisationCode.currency) && + Objects.equals(this.amountType, requestAuthorisationCode.amountType) && + Objects.equals(this.codeLifetime, requestAuthorisationCode.codeLifetime) && + Objects.equals(this.holdFundsIndicator, requestAuthorisationCode.holdFundsIndicator) && + Objects.equals(this.redemptionAccountIdentifiers, requestAuthorisationCode.redemptionAccountIdentifiers) && + Objects.equals(this.redemptionChannels, requestAuthorisationCode.redemptionChannels) && + Objects.equals(this.redemptionTransactionTypes, requestAuthorisationCode.redemptionTransactionTypes) && + Objects.equals(this.requestingOrganisation, requestAuthorisationCode.requestingOrganisation) && + Objects.equals(this.requestDate, requestAuthorisationCode.requestDate) && + Objects.equals(this.customData, requestAuthorisationCode.customData) && + Objects.equals(this.metadata, requestAuthorisationCode.metadata); + } + + @Override + public int hashCode() { + return Objects.hash(amount, currency, amountType, codeLifetime, holdFundsIndicator, redemptionAccountIdentifiers, redemptionChannels, redemptionTransactionTypes, requestingOrganisation, requestDate, customData, metadata); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class RequestAuthorisationCode {\n"); + + sb.append(" amount: ").append(toIndentedString(amount)).append("\n"); + sb.append(" currency: ").append(toIndentedString(currency)).append("\n"); + sb.append(" amountType: ").append(toIndentedString(amountType)).append("\n"); + sb.append(" codeLifetime: ").append(toIndentedString(codeLifetime)).append("\n"); + sb.append(" holdFundsIndicator: ").append(toIndentedString(holdFundsIndicator)).append("\n"); + sb.append(" redemptionAccountIdentifiers: ").append(toIndentedString(redemptionAccountIdentifiers)).append("\n"); + sb.append(" redemptionChannels: ").append(toIndentedString(redemptionChannels)).append("\n"); + sb.append(" redemptionTransactionTypes: ").append(toIndentedString(redemptionTransactionTypes)).append("\n"); + sb.append(" requestingOrganisation: ").append(toIndentedString(requestingOrganisation)).append("\n"); + sb.append(" requestDate: ").append(toIndentedString(requestDate)).append("\n"); + sb.append(" customData: ").append(toIndentedString(customData)).append("\n"); + sb.append(" metadata: ").append(toIndentedString(metadata)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/RequestBatchTransaction.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/RequestBatchTransaction.java new file mode 100644 index 000000000..2ebdc95ba --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/RequestBatchTransaction.java @@ -0,0 +1,288 @@ +package org.mifos.connector.gsmastub.model; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import org.springframework.validation.annotation.Validated; +import org.threeten.bp.OffsetDateTime; + +import javax.validation.Valid; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +/** + * RequestBatchTransaction + */ +@Validated +@javax.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.SpringCodegen", date = "2022-09-27T11:46:46.417Z[GMT]") + + +public class RequestBatchTransaction { + @JsonProperty("batchStatus") + private BatchStatus batchStatus = null; + + @JsonProperty("transactions") + @Valid + private List transactions = new ArrayList(); + + @JsonProperty("batchTitle") + private String batchTitle = null; + + @JsonProperty("batchdescription") + private String batchdescription = null; + + @JsonProperty("requestingOrganisation") + private RequestingOrganisation requestingOrganisation = null; + + @JsonProperty("scheduledStartDate") + private OffsetDateTime scheduledStartDate = null; + + @JsonProperty("modificationDate") + private OffsetDateTime modificationDate = null; + + @JsonProperty("requestDate") + private OffsetDateTime requestDate = null; + + @JsonProperty("customData") + private CustomDataArray customData = null; + + public RequestBatchTransaction batchStatus(BatchStatus batchStatus) { + this.batchStatus = batchStatus; + return this; + } + + /** + * Get batchStatus + * @return batchStatus + **/ + @Schema(description = "") + + @Valid + public BatchStatus getBatchStatus() { + return batchStatus; + } + + public void setBatchStatus(BatchStatus batchStatus) { + this.batchStatus = batchStatus; + } + + public RequestBatchTransaction transactions(List transactions) { + this.transactions = transactions; + return this; + } + + public RequestBatchTransaction addTransactionsItem(RequestTransaction transactionsItem) { + this.transactions.add(transactionsItem); + return this; + } + + /** + * Collection of Transactions that are to be processed. + * @return transactions + **/ + @Schema(required = true, description = "Collection of Transactions that are to be processed.") + @NotNull + @Valid + @Size(min=1,max=999999) public List getTransactions() { + return transactions; + } + + public void setTransactions(List transactions) { + this.transactions = transactions; + } + + public RequestBatchTransaction batchTitle(String batchTitle) { + this.batchTitle = batchTitle; + return this; + } + + /** + * Client-provided title for the batch. + * @return batchTitle + **/ + @Schema(description = "Client-provided title for the batch.") + + @Size(max=256) public String getBatchTitle() { + return batchTitle; + } + + public void setBatchTitle(String batchTitle) { + this.batchTitle = batchTitle; + } + + public RequestBatchTransaction batchdescription(String batchdescription) { + this.batchdescription = batchdescription; + return this; + } + + /** + * Client-provided description of the batch. + * @return batchdescription + **/ + @Schema(description = "Client-provided description of the batch.") + + @Size(max=256) public String getBatchdescription() { + return batchdescription; + } + + public void setBatchdescription(String batchdescription) { + this.batchdescription = batchdescription; + } + + public RequestBatchTransaction requestingOrganisation(RequestingOrganisation requestingOrganisation) { + this.requestingOrganisation = requestingOrganisation; + return this; + } + + /** + * Get requestingOrganisation + * @return requestingOrganisation + **/ + @Schema(description = "") + + @Valid + public RequestingOrganisation getRequestingOrganisation() { + return requestingOrganisation; + } + + public void setRequestingOrganisation(RequestingOrganisation requestingOrganisation) { + this.requestingOrganisation = requestingOrganisation; + } + + public RequestBatchTransaction scheduledStartDate(OffsetDateTime scheduledStartDate) { + this.scheduledStartDate = scheduledStartDate; + return this; + } + + /** + * If the batch has been scheduled, the expected start time is provided here. + * @return scheduledStartDate + **/ + @Schema(description = "If the batch has been scheduled, the expected start time is provided here.") + + @Valid + public OffsetDateTime getScheduledStartDate() { + return scheduledStartDate; + } + + public void setScheduledStartDate(OffsetDateTime scheduledStartDate) { + this.scheduledStartDate = scheduledStartDate; + } + + public RequestBatchTransaction modificationDate(OffsetDateTime modificationDate) { + this.modificationDate = modificationDate; + return this; + } + + /** + * Date and time when the object was modified by the API Provider. + * @return modificationDate + **/ + @Schema(description = "Date and time when the object was modified by the API Provider.") + + @Valid + public OffsetDateTime getModificationDate() { + return modificationDate; + } + + public void setModificationDate(OffsetDateTime modificationDate) { + this.modificationDate = modificationDate; + } + + public RequestBatchTransaction requestDate(OffsetDateTime requestDate) { + this.requestDate = requestDate; + return this; + } + + /** + * The date and time of the request as supplied by the client. + * @return requestDate + **/ + @Schema(description = "The date and time of the request as supplied by the client.") + + @Valid + public OffsetDateTime getRequestDate() { + return requestDate; + } + + public void setRequestDate(OffsetDateTime requestDate) { + this.requestDate = requestDate; + } + + public RequestBatchTransaction customData(CustomDataArray customData) { + this.customData = customData; + return this; + } + + /** + * Get customData + * @return customData + **/ + @Schema(description = "") + + @Valid + public CustomDataArray getCustomData() { + return customData; + } + + public void setCustomData(CustomDataArray customData) { + this.customData = customData; + } + + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + RequestBatchTransaction requestBatchTransaction = (RequestBatchTransaction) o; + return Objects.equals(this.batchStatus, requestBatchTransaction.batchStatus) && + Objects.equals(this.transactions, requestBatchTransaction.transactions) && + Objects.equals(this.batchTitle, requestBatchTransaction.batchTitle) && + Objects.equals(this.batchdescription, requestBatchTransaction.batchdescription) && + Objects.equals(this.requestingOrganisation, requestBatchTransaction.requestingOrganisation) && + Objects.equals(this.scheduledStartDate, requestBatchTransaction.scheduledStartDate) && + Objects.equals(this.modificationDate, requestBatchTransaction.modificationDate) && + Objects.equals(this.requestDate, requestBatchTransaction.requestDate) && + Objects.equals(this.customData, requestBatchTransaction.customData); + } + + @Override + public int hashCode() { + return Objects.hash(batchStatus, transactions, batchTitle, batchdescription, requestingOrganisation, scheduledStartDate, modificationDate, requestDate, customData); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class RequestBatchTransaction {\n"); + + sb.append(" batchStatus: ").append(toIndentedString(batchStatus)).append("\n"); + sb.append(" transactions: ").append(toIndentedString(transactions)).append("\n"); + sb.append(" batchTitle: ").append(toIndentedString(batchTitle)).append("\n"); + sb.append(" batchdescription: ").append(toIndentedString(batchdescription)).append("\n"); + sb.append(" requestingOrganisation: ").append(toIndentedString(requestingOrganisation)).append("\n"); + sb.append(" scheduledStartDate: ").append(toIndentedString(scheduledStartDate)).append("\n"); + sb.append(" modificationDate: ").append(toIndentedString(modificationDate)).append("\n"); + sb.append(" requestDate: ").append(toIndentedString(requestDate)).append("\n"); + sb.append(" customData: ").append(toIndentedString(customData)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/RequestBillPayment.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/RequestBillPayment.java new file mode 100644 index 000000000..d0e351931 --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/RequestBillPayment.java @@ -0,0 +1,354 @@ +package org.mifos.connector.gsmastub.model; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import org.springframework.validation.annotation.Validated; +import org.threeten.bp.OffsetDateTime; + +import javax.validation.Valid; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Pattern; +import javax.validation.constraints.Size; +import java.util.Objects; + +/** + * RequestBillPayment + */ +@Validated +@javax.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.SpringCodegen", date = "2022-09-27T11:46:46.417Z[GMT]") + + +public class RequestBillPayment { + @JsonProperty("serviceProviderPaymentReference") + private String serviceProviderPaymentReference = null; + + @JsonProperty("requestingOrganisationTransactionReference") + private String requestingOrganisationTransactionReference = null; + + @JsonProperty("paymentType") + private PaymentType paymentType = null; + + @JsonProperty("amountPaid") + private String amountPaid = null; + + @JsonProperty("currency") + private Currency currency = null; + + @JsonProperty("customerReference") + private String customerReference = null; + + @JsonProperty("requestingOrganisation") + private String requestingOrganisation = null; + + @JsonProperty("supplementaryBillReferenceDetails") + private SupplementaryBillReferenceDetailsArray supplementaryBillReferenceDetails = null; + + @JsonProperty("requestDate") + private OffsetDateTime requestDate = null; + + @JsonProperty("customData") + private CustomDataArray customData = null; + + @JsonProperty("metadata") + private MetadataArray metadata = null; + + @JsonProperty("paidAmount") + private String paidAmount = null; + + public RequestBillPayment serviceProviderPaymentReference(String serviceProviderPaymentReference) { + this.serviceProviderPaymentReference = serviceProviderPaymentReference; + return this; + } + + /** + * Reference for the payment generated by the service provider. + * @return serviceProviderPaymentReference + **/ + @Schema(description = "Reference for the payment generated by the service provider.") + + @Size(max=256) public String getServiceProviderPaymentReference() { + return serviceProviderPaymentReference; + } + + public void setServiceProviderPaymentReference(String serviceProviderPaymentReference) { + this.serviceProviderPaymentReference = serviceProviderPaymentReference; + } + + public RequestBillPayment requestingOrganisationTransactionReference(String requestingOrganisationTransactionReference) { + this.requestingOrganisationTransactionReference = requestingOrganisationTransactionReference; + return this; + } + + /** + * A reference provided by the requesting organisation that is to be associated with the transaction. + * @return requestingOrganisationTransactionReference + **/ + @Schema(description = "A reference provided by the requesting organisation that is to be associated with the transaction.") + + @Size(max=256) public String getRequestingOrganisationTransactionReference() { + return requestingOrganisationTransactionReference; + } + + public void setRequestingOrganisationTransactionReference(String requestingOrganisationTransactionReference) { + this.requestingOrganisationTransactionReference = requestingOrganisationTransactionReference; + } + + public RequestBillPayment paymentType(PaymentType paymentType) { + this.paymentType = paymentType; + return this; + } + + /** + * Get paymentType + * @return paymentType + **/ + @Schema(description = "") + + @Valid + public PaymentType getPaymentType() { + return paymentType; + } + + public void setPaymentType(PaymentType paymentType) { + this.paymentType = paymentType; + } + + public RequestBillPayment amountPaid(String amountPaid) { + this.amountPaid = amountPaid; + return this; + } + + /** + * Get amountPaid + * @return amountPaid + **/ + @Schema(example = "15.21", required = true, description = "") + @NotNull + + @Pattern(regexp="^([0]|([1-9][0-9]{0,17}))([.][0-9]{0,3}[0-9])?$") @Size(min=1,max=23) public String getAmountPaid() { + return amountPaid; + } + + public void setAmountPaid(String amountPaid) { + this.amountPaid = amountPaid; + } + + public RequestBillPayment currency(Currency currency) { + this.currency = currency; + return this; + } + + /** + * Get currency + * @return currency + **/ + @Schema(required = true, description = "") + @NotNull + + @Valid + public Currency getCurrency() { + return currency; + } + + public void setCurrency(Currency currency) { + this.currency = currency; + } + + public RequestBillPayment customerReference(String customerReference) { + this.customerReference = customerReference; + return this; + } + + /** + * Textual reference provided by the customer paying the bill. + * @return customerReference + **/ + @Schema(description = "Textual reference provided by the customer paying the bill.") + + @Size(max=256) public String getCustomerReference() { + return customerReference; + } + + public void setCustomerReference(String customerReference) { + this.customerReference = customerReference; + } + + public RequestBillPayment requestingOrganisation(String requestingOrganisation) { + this.requestingOrganisation = requestingOrganisation; + return this; + } + + /** + * The originating mobile money provider or financial institution that holds the wallet/account of the payer. + * @return requestingOrganisation + **/ + @Schema(description = "The originating mobile money provider or financial institution that holds the wallet/account of the payer.") + + @Size(max=256) public String getRequestingOrganisation() { + return requestingOrganisation; + } + + public void setRequestingOrganisation(String requestingOrganisation) { + this.requestingOrganisation = requestingOrganisation; + } + + public RequestBillPayment supplementaryBillReferenceDetails(SupplementaryBillReferenceDetailsArray supplementaryBillReferenceDetails) { + this.supplementaryBillReferenceDetails = supplementaryBillReferenceDetails; + return this; + } + + /** + * Get supplementaryBillReferenceDetails + * @return supplementaryBillReferenceDetails + **/ + @Schema(description = "") + + @Valid + public SupplementaryBillReferenceDetailsArray getSupplementaryBillReferenceDetails() { + return supplementaryBillReferenceDetails; + } + + public void setSupplementaryBillReferenceDetails(SupplementaryBillReferenceDetailsArray supplementaryBillReferenceDetails) { + this.supplementaryBillReferenceDetails = supplementaryBillReferenceDetails; + } + + public RequestBillPayment requestDate(OffsetDateTime requestDate) { + this.requestDate = requestDate; + return this; + } + + /** + * The date and time of the request as supplied by the client. + * @return requestDate + **/ + @Schema(description = "The date and time of the request as supplied by the client.") + + @Valid + public OffsetDateTime getRequestDate() { + return requestDate; + } + + public void setRequestDate(OffsetDateTime requestDate) { + this.requestDate = requestDate; + } + + public RequestBillPayment customData(CustomDataArray customData) { + this.customData = customData; + return this; + } + + /** + * Get customData + * @return customData + **/ + @Schema(description = "") + + @Valid + public CustomDataArray getCustomData() { + return customData; + } + + public void setCustomData(CustomDataArray customData) { + this.customData = customData; + } + + public RequestBillPayment metadata(MetadataArray metadata) { + this.metadata = metadata; + return this; + } + + /** + * Get metadata + * @return metadata + **/ + @Schema(description = "") + + @Valid + public MetadataArray getMetadata() { + return metadata; + } + + public void setMetadata(MetadataArray metadata) { + this.metadata = metadata; + } + + public RequestBillPayment paidAmount(String paidAmount) { + this.paidAmount = paidAmount; + return this; + } + + /** + * Get paidAmount + * @return paidAmount + **/ + @Schema(example = "15.21", description = "") + + @Pattern(regexp="^([0]|([1-9][0-9]{0,17}))([.][0-9]{0,3}[0-9])?$") @Size(min=1,max=23) public String getPaidAmount() { + return paidAmount; + } + + public void setPaidAmount(String paidAmount) { + this.paidAmount = paidAmount; + } + + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + RequestBillPayment requestBillPayment = (RequestBillPayment) o; + return Objects.equals(this.serviceProviderPaymentReference, requestBillPayment.serviceProviderPaymentReference) && + Objects.equals(this.requestingOrganisationTransactionReference, requestBillPayment.requestingOrganisationTransactionReference) && + Objects.equals(this.paymentType, requestBillPayment.paymentType) && + Objects.equals(this.amountPaid, requestBillPayment.amountPaid) && + Objects.equals(this.currency, requestBillPayment.currency) && + Objects.equals(this.customerReference, requestBillPayment.customerReference) && + Objects.equals(this.requestingOrganisation, requestBillPayment.requestingOrganisation) && + Objects.equals(this.supplementaryBillReferenceDetails, requestBillPayment.supplementaryBillReferenceDetails) && + Objects.equals(this.requestDate, requestBillPayment.requestDate) && + Objects.equals(this.customData, requestBillPayment.customData) && + Objects.equals(this.metadata, requestBillPayment.metadata) && + Objects.equals(this.paidAmount, requestBillPayment.paidAmount); + } + + @Override + public int hashCode() { + return Objects.hash(serviceProviderPaymentReference, requestingOrganisationTransactionReference, paymentType, amountPaid, currency, customerReference, requestingOrganisation, supplementaryBillReferenceDetails, requestDate, customData, metadata, paidAmount); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class RequestBillPayment {\n"); + + sb.append(" serviceProviderPaymentReference: ").append(toIndentedString(serviceProviderPaymentReference)).append("\n"); + sb.append(" requestingOrganisationTransactionReference: ").append(toIndentedString(requestingOrganisationTransactionReference)).append("\n"); + sb.append(" paymentType: ").append(toIndentedString(paymentType)).append("\n"); + sb.append(" amountPaid: ").append(toIndentedString(amountPaid)).append("\n"); + sb.append(" currency: ").append(toIndentedString(currency)).append("\n"); + sb.append(" customerReference: ").append(toIndentedString(customerReference)).append("\n"); + sb.append(" requestingOrganisation: ").append(toIndentedString(requestingOrganisation)).append("\n"); + sb.append(" supplementaryBillReferenceDetails: ").append(toIndentedString(supplementaryBillReferenceDetails)).append("\n"); + sb.append(" requestDate: ").append(toIndentedString(requestDate)).append("\n"); + sb.append(" customData: ").append(toIndentedString(customData)).append("\n"); + sb.append(" metadata: ").append(toIndentedString(metadata)).append("\n"); + sb.append(" paidAmount: ").append(toIndentedString(paidAmount)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/RequestBillPayment2.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/RequestBillPayment2.java new file mode 100644 index 000000000..b2ed6a698 --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/RequestBillPayment2.java @@ -0,0 +1,329 @@ +package org.mifos.connector.gsmastub.model; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import org.springframework.validation.annotation.Validated; +import org.threeten.bp.OffsetDateTime; + +import javax.validation.Valid; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Pattern; +import javax.validation.constraints.Size; +import java.util.Objects; + +/** + * RequestBillPayment2 + */ +@Validated +@javax.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.SpringCodegen", date = "2022-09-27T11:46:46.417Z[GMT]") + + +public class RequestBillPayment2 { + @JsonProperty("serviceProviderPaymentReference") + private String serviceProviderPaymentReference = null; + + @JsonProperty("requestingOrganisationTransactionReference") + private String requestingOrganisationTransactionReference = null; + + @JsonProperty("paymentType") + private PaymentType paymentType = null; + + @JsonProperty("amountPaid") + private String amountPaid = null; + + @JsonProperty("currency") + private Currency currency = null; + + @JsonProperty("customerReference") + private String customerReference = null; + + @JsonProperty("requestingOrganisation") + private String requestingOrganisation = null; + + @JsonProperty("requestDate") + private OffsetDateTime requestDate = null; + + @JsonProperty("customData") + private CustomDataArray customData = null; + + @JsonProperty("metadata") + private MetadataArray metadata = null; + + @JsonProperty("paidAmount") + private String paidAmount = null; + + public RequestBillPayment2 serviceProviderPaymentReference(String serviceProviderPaymentReference) { + this.serviceProviderPaymentReference = serviceProviderPaymentReference; + return this; + } + + /** + * Reference for the payment generated by the service provider. + * @return serviceProviderPaymentReference + **/ + @Schema(description = "Reference for the payment generated by the service provider.") + + @Size(max=256) public String getServiceProviderPaymentReference() { + return serviceProviderPaymentReference; + } + + public void setServiceProviderPaymentReference(String serviceProviderPaymentReference) { + this.serviceProviderPaymentReference = serviceProviderPaymentReference; + } + + public RequestBillPayment2 requestingOrganisationTransactionReference(String requestingOrganisationTransactionReference) { + this.requestingOrganisationTransactionReference = requestingOrganisationTransactionReference; + return this; + } + + /** + * A reference provided by the requesting organisation that is to be associated with the transaction. + * @return requestingOrganisationTransactionReference + **/ + @Schema(description = "A reference provided by the requesting organisation that is to be associated with the transaction.") + + @Size(max=256) public String getRequestingOrganisationTransactionReference() { + return requestingOrganisationTransactionReference; + } + + public void setRequestingOrganisationTransactionReference(String requestingOrganisationTransactionReference) { + this.requestingOrganisationTransactionReference = requestingOrganisationTransactionReference; + } + + public RequestBillPayment2 paymentType(PaymentType paymentType) { + this.paymentType = paymentType; + return this; + } + + /** + * Get paymentType + * @return paymentType + **/ + @Schema(description = "") + + @Valid + public PaymentType getPaymentType() { + return paymentType; + } + + public void setPaymentType(PaymentType paymentType) { + this.paymentType = paymentType; + } + + public RequestBillPayment2 amountPaid(String amountPaid) { + this.amountPaid = amountPaid; + return this; + } + + /** + * Get amountPaid + * @return amountPaid + **/ + @Schema(example = "15.21", required = true, description = "") + @NotNull + + @Pattern(regexp="^([0]|([1-9][0-9]{0,17}))([.][0-9]{0,3}[0-9])?$") @Size(min=1,max=23) public String getAmountPaid() { + return amountPaid; + } + + public void setAmountPaid(String amountPaid) { + this.amountPaid = amountPaid; + } + + public RequestBillPayment2 currency(Currency currency) { + this.currency = currency; + return this; + } + + /** + * Get currency + * @return currency + **/ + @Schema(required = true, description = "") + @NotNull + + @Valid + public Currency getCurrency() { + return currency; + } + + public void setCurrency(Currency currency) { + this.currency = currency; + } + + public RequestBillPayment2 customerReference(String customerReference) { + this.customerReference = customerReference; + return this; + } + + /** + * Textual reference provided by the customer paying the bill. + * @return customerReference + **/ + @Schema(description = "Textual reference provided by the customer paying the bill.") + + @Size(max=256) public String getCustomerReference() { + return customerReference; + } + + public void setCustomerReference(String customerReference) { + this.customerReference = customerReference; + } + + public RequestBillPayment2 requestingOrganisation(String requestingOrganisation) { + this.requestingOrganisation = requestingOrganisation; + return this; + } + + /** + * The originating mobile money provider or financial institution that holds the wallet/account of the payer. + * @return requestingOrganisation + **/ + @Schema(description = "The originating mobile money provider or financial institution that holds the wallet/account of the payer.") + + @Size(max=256) public String getRequestingOrganisation() { + return requestingOrganisation; + } + + public void setRequestingOrganisation(String requestingOrganisation) { + this.requestingOrganisation = requestingOrganisation; + } + + public RequestBillPayment2 requestDate(OffsetDateTime requestDate) { + this.requestDate = requestDate; + return this; + } + + /** + * The date and time of the request as supplied by the client. + * @return requestDate + **/ + @Schema(description = "The date and time of the request as supplied by the client.") + + @Valid + public OffsetDateTime getRequestDate() { + return requestDate; + } + + public void setRequestDate(OffsetDateTime requestDate) { + this.requestDate = requestDate; + } + + public RequestBillPayment2 customData(CustomDataArray customData) { + this.customData = customData; + return this; + } + + /** + * Get customData + * @return customData + **/ + @Schema(description = "") + + @Valid + public CustomDataArray getCustomData() { + return customData; + } + + public void setCustomData(CustomDataArray customData) { + this.customData = customData; + } + + public RequestBillPayment2 metadata(MetadataArray metadata) { + this.metadata = metadata; + return this; + } + + /** + * Get metadata + * @return metadata + **/ + @Schema(description = "") + + @Valid + public MetadataArray getMetadata() { + return metadata; + } + + public void setMetadata(MetadataArray metadata) { + this.metadata = metadata; + } + + public RequestBillPayment2 paidAmount(String paidAmount) { + this.paidAmount = paidAmount; + return this; + } + + /** + * Get paidAmount + * @return paidAmount + **/ + @Schema(example = "15.21", description = "") + + @Pattern(regexp="^([0]|([1-9][0-9]{0,17}))([.][0-9]{0,3}[0-9])?$") @Size(min=1,max=23) public String getPaidAmount() { + return paidAmount; + } + + public void setPaidAmount(String paidAmount) { + this.paidAmount = paidAmount; + } + + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + RequestBillPayment2 requestBillPayment2 = (RequestBillPayment2) o; + return Objects.equals(this.serviceProviderPaymentReference, requestBillPayment2.serviceProviderPaymentReference) && + Objects.equals(this.requestingOrganisationTransactionReference, requestBillPayment2.requestingOrganisationTransactionReference) && + Objects.equals(this.paymentType, requestBillPayment2.paymentType) && + Objects.equals(this.amountPaid, requestBillPayment2.amountPaid) && + Objects.equals(this.currency, requestBillPayment2.currency) && + Objects.equals(this.customerReference, requestBillPayment2.customerReference) && + Objects.equals(this.requestingOrganisation, requestBillPayment2.requestingOrganisation) && + Objects.equals(this.requestDate, requestBillPayment2.requestDate) && + Objects.equals(this.customData, requestBillPayment2.customData) && + Objects.equals(this.metadata, requestBillPayment2.metadata) && + Objects.equals(this.paidAmount, requestBillPayment2.paidAmount); + } + + @Override + public int hashCode() { + return Objects.hash(serviceProviderPaymentReference, requestingOrganisationTransactionReference, paymentType, amountPaid, currency, customerReference, requestingOrganisation, requestDate, customData, metadata, paidAmount); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class RequestBillPayment2 {\n"); + + sb.append(" serviceProviderPaymentReference: ").append(toIndentedString(serviceProviderPaymentReference)).append("\n"); + sb.append(" requestingOrganisationTransactionReference: ").append(toIndentedString(requestingOrganisationTransactionReference)).append("\n"); + sb.append(" paymentType: ").append(toIndentedString(paymentType)).append("\n"); + sb.append(" amountPaid: ").append(toIndentedString(amountPaid)).append("\n"); + sb.append(" currency: ").append(toIndentedString(currency)).append("\n"); + sb.append(" customerReference: ").append(toIndentedString(customerReference)).append("\n"); + sb.append(" requestingOrganisation: ").append(toIndentedString(requestingOrganisation)).append("\n"); + sb.append(" requestDate: ").append(toIndentedString(requestDate)).append("\n"); + sb.append(" customData: ").append(toIndentedString(customData)).append("\n"); + sb.append(" metadata: ").append(toIndentedString(metadata)).append("\n"); + sb.append(" paidAmount: ").append(toIndentedString(paidAmount)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/RequestDebitMandate.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/RequestDebitMandate.java new file mode 100644 index 000000000..213802d5f --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/RequestDebitMandate.java @@ -0,0 +1,335 @@ +package org.mifos.connector.gsmastub.model; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import org.springframework.validation.annotation.Validated; +import org.threeten.bp.LocalDate; +import org.threeten.bp.OffsetDateTime; + +import javax.validation.Valid; +import javax.validation.constraints.DecimalMin; +import javax.validation.constraints.NotNull; +import java.math.BigDecimal; +import java.util.Objects; + +/** + * RequestDebitMandate + */ +@Validated +@javax.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.SpringCodegen", date = "2022-09-27T11:46:46.417Z[GMT]") + + +public class RequestDebitMandate { + @JsonProperty("payee") + private Payee payee = null; + + @JsonProperty("mandateStatus") + private MandateStatus mandateStatus = null; + + @JsonProperty("amountLimit") + private Object amountLimit = null; + + @JsonProperty("currency") + private Currency currency = null; + + @JsonProperty("startDate") + private LocalDate startDate = null; + + @JsonProperty("endDate") + private LocalDate endDate = null; + + @JsonProperty("frequencyType") + private FrequencyType frequencyType = null; + + @JsonProperty("numberOfPayments") + private BigDecimal numberOfPayments = null; + + @JsonProperty("requestingOrganisation") + private RequestingOrganisation requestingOrganisation = null; + + @JsonProperty("requestDate") + private OffsetDateTime requestDate = null; + + @JsonProperty("customData") + private CustomDataArray customData = null; + + public RequestDebitMandate payee(Payee payee) { + this.payee = payee; + return this; + } + + /** + * Get payee + * @return payee + **/ + @Schema(description = "") + + @Valid + public Payee getPayee() { + return payee; + } + + public void setPayee(Payee payee) { + this.payee = payee; + } + + public RequestDebitMandate mandateStatus(MandateStatus mandateStatus) { + this.mandateStatus = mandateStatus; + return this; + } + + /** + * Get mandateStatus + * @return mandateStatus + **/ + @Schema(description = "") + + @Valid + public MandateStatus getMandateStatus() { + return mandateStatus; + } + + public void setMandateStatus(MandateStatus mandateStatus) { + this.mandateStatus = mandateStatus; + } + + public RequestDebitMandate amountLimit(Object amountLimit) { + this.amountLimit = amountLimit; + return this; + } + + /** + * The maximum amount that can be taken by the Payee on a payment request. + * @return amountLimit + **/ + @Schema(description = "The maximum amount that can be taken by the Payee on a payment request.") + + public Object getAmountLimit() { + return amountLimit; + } + + public void setAmountLimit(Object amountLimit) { + this.amountLimit = amountLimit; + } + + public RequestDebitMandate currency(Currency currency) { + this.currency = currency; + return this; + } + + /** + * Get currency + * @return currency + **/ + @Schema(description = "") + + @Valid + public Currency getCurrency() { + return currency; + } + + public void setCurrency(Currency currency) { + this.currency = currency; + } + + public RequestDebitMandate startDate(LocalDate startDate) { + this.startDate = startDate; + return this; + } + + /** + * Date on which the mandate starts. If a frequencyType is specified, this will also be the date on which the first payment is to be taken. + * @return startDate + **/ + @Schema(example = "Tue Nov 20 00:00:00 GMT 2018", required = true, description = "Date on which the mandate starts. If a frequencyType is specified, this will also be the date on which the first payment is to be taken.") + @NotNull + + @Valid + public LocalDate getStartDate() { + return startDate; + } + + public void setStartDate(LocalDate startDate) { + this.startDate = startDate; + } + + public RequestDebitMandate endDate(LocalDate endDate) { + this.endDate = endDate; + return this; + } + + /** + * Date on which the mandate ends. + * @return endDate + **/ + @Schema(example = "Tue Nov 20 00:00:00 GMT 2018", description = "Date on which the mandate ends.") + + @Valid + public LocalDate getEndDate() { + return endDate; + } + + public void setEndDate(LocalDate endDate) { + this.endDate = endDate; + } + + public RequestDebitMandate frequencyType(FrequencyType frequencyType) { + this.frequencyType = frequencyType; + return this; + } + + /** + * Get frequencyType + * @return frequencyType + **/ + @Schema(description = "") + + @Valid + public FrequencyType getFrequencyType() { + return frequencyType; + } + + public void setFrequencyType(FrequencyType frequencyType) { + this.frequencyType = frequencyType; + } + + public RequestDebitMandate numberOfPayments(BigDecimal numberOfPayments) { + this.numberOfPayments = numberOfPayments; + return this; + } + + /** + * Indicates the number of consecutive payments that are to be taken. + * minimum: 0 + * @return numberOfPayments + **/ + @Schema(description = "Indicates the number of consecutive payments that are to be taken.") + + @Valid + @DecimalMin("0") public BigDecimal getNumberOfPayments() { + return numberOfPayments; + } + + public void setNumberOfPayments(BigDecimal numberOfPayments) { + this.numberOfPayments = numberOfPayments; + } + + public RequestDebitMandate requestingOrganisation(RequestingOrganisation requestingOrganisation) { + this.requestingOrganisation = requestingOrganisation; + return this; + } + + /** + * Get requestingOrganisation + * @return requestingOrganisation + **/ + @Schema(description = "") + + @Valid + public RequestingOrganisation getRequestingOrganisation() { + return requestingOrganisation; + } + + public void setRequestingOrganisation(RequestingOrganisation requestingOrganisation) { + this.requestingOrganisation = requestingOrganisation; + } + + public RequestDebitMandate requestDate(OffsetDateTime requestDate) { + this.requestDate = requestDate; + return this; + } + + /** + * The date and time of the request as supplied by the client. + * @return requestDate + **/ + @Schema(description = "The date and time of the request as supplied by the client.") + + @Valid + public OffsetDateTime getRequestDate() { + return requestDate; + } + + public void setRequestDate(OffsetDateTime requestDate) { + this.requestDate = requestDate; + } + + public RequestDebitMandate customData(CustomDataArray customData) { + this.customData = customData; + return this; + } + + /** + * Get customData + * @return customData + **/ + @Schema(description = "") + + @Valid + public CustomDataArray getCustomData() { + return customData; + } + + public void setCustomData(CustomDataArray customData) { + this.customData = customData; + } + + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + RequestDebitMandate requestDebitMandate = (RequestDebitMandate) o; + return Objects.equals(this.payee, requestDebitMandate.payee) && + Objects.equals(this.mandateStatus, requestDebitMandate.mandateStatus) && + Objects.equals(this.amountLimit, requestDebitMandate.amountLimit) && + Objects.equals(this.currency, requestDebitMandate.currency) && + Objects.equals(this.startDate, requestDebitMandate.startDate) && + Objects.equals(this.endDate, requestDebitMandate.endDate) && + Objects.equals(this.frequencyType, requestDebitMandate.frequencyType) && + Objects.equals(this.numberOfPayments, requestDebitMandate.numberOfPayments) && + Objects.equals(this.requestingOrganisation, requestDebitMandate.requestingOrganisation) && + Objects.equals(this.requestDate, requestDebitMandate.requestDate) && + Objects.equals(this.customData, requestDebitMandate.customData); + } + + @Override + public int hashCode() { + return Objects.hash(payee, mandateStatus, amountLimit, currency, startDate, endDate, frequencyType, numberOfPayments, requestingOrganisation, requestDate, customData); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class RequestDebitMandate {\n"); + + sb.append(" payee: ").append(toIndentedString(payee)).append("\n"); + sb.append(" mandateStatus: ").append(toIndentedString(mandateStatus)).append("\n"); + sb.append(" amountLimit: ").append(toIndentedString(amountLimit)).append("\n"); + sb.append(" currency: ").append(toIndentedString(currency)).append("\n"); + sb.append(" startDate: ").append(toIndentedString(startDate)).append("\n"); + sb.append(" endDate: ").append(toIndentedString(endDate)).append("\n"); + sb.append(" frequencyType: ").append(toIndentedString(frequencyType)).append("\n"); + sb.append(" numberOfPayments: ").append(toIndentedString(numberOfPayments)).append("\n"); + sb.append(" requestingOrganisation: ").append(toIndentedString(requestingOrganisation)).append("\n"); + sb.append(" requestDate: ").append(toIndentedString(requestDate)).append("\n"); + sb.append(" customData: ").append(toIndentedString(customData)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/RequestGenericPatch.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/RequestGenericPatch.java new file mode 100644 index 000000000..3376b108e --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/RequestGenericPatch.java @@ -0,0 +1,162 @@ +package org.mifos.connector.gsmastub.model; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonValue; +import io.swagger.v3.oas.annotations.media.Schema; +import org.springframework.validation.annotation.Validated; + +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; +import java.util.Objects; + +/** + * RequestGenericPatch + */ +@Validated +@javax.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.SpringCodegen", date = "2022-09-27T11:46:46.417Z[GMT]") + + +public class RequestGenericPatch { + /** + * Indicates the Patch operation to be performed. 'replace' is used to update a field and 'add' is used to add a new field. + */ + public enum OpEnum { + REPLACE("replace"), + + ADD("add"); + + private String value; + + OpEnum(String value) { + this.value = value; + } + + @Override + @JsonValue + public String toString() { + return String.valueOf(value); + } + + @JsonCreator + public static OpEnum fromValue(String text) { + for (OpEnum b : OpEnum.values()) { + if (String.valueOf(b.value).equals(text)) { + return b; + } + } + return null; + } + } + @JsonProperty("op") + private OpEnum op = null; + + @JsonProperty("path") + private String path = null; + + @JsonProperty("value") + private String value = null; + + public RequestGenericPatch op(OpEnum op) { + this.op = op; + return this; + } + + /** + * Indicates the Patch operation to be performed. 'replace' is used to update a field and 'add' is used to add a new field. + * @return op + **/ + @Schema(required = true, description = "Indicates the Patch operation to be performed. 'replace' is used to update a field and 'add' is used to add a new field.") + @NotNull + + public OpEnum getOp() { + return op; + } + + public void setOp(OpEnum op) { + this.op = op; + } + + public RequestGenericPatch path(String path) { + this.path = path; + return this; + } + + /** + * Specify the field to be updated or added preceded by '/'. + * @return path + **/ + @Schema(required = true, description = "Specify the field to be updated or added preceded by '/'.") + @NotNull + + @Size(max=256) public String getPath() { + return path; + } + + public void setPath(String path) { + this.path = path; + } + + public RequestGenericPatch value(String value) { + this.value = value; + return this; + } + + /** + * Specify the value of the field to be updated or added. + * @return value + **/ + @Schema(required = true, description = "Specify the value of the field to be updated or added.") + @NotNull + + @Size(max=256) public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } + + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + RequestGenericPatch requestGenericPatch = (RequestGenericPatch) o; + return Objects.equals(this.op, requestGenericPatch.op) && + Objects.equals(this.path, requestGenericPatch.path) && + Objects.equals(this.value, requestGenericPatch.value); + } + + @Override + public int hashCode() { + return Objects.hash(op, path, value); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class RequestGenericPatch {\n"); + + sb.append(" op: ").append(toIndentedString(op)).append("\n"); + sb.append(" path: ").append(toIndentedString(path)).append("\n"); + sb.append(" value: ").append(toIndentedString(value)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/RequestGenericPatchArray.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/RequestGenericPatchArray.java new file mode 100644 index 000000000..895dea415 --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/RequestGenericPatchArray.java @@ -0,0 +1,54 @@ +package org.mifos.connector.gsmastub.model; + +import io.swagger.v3.oas.annotations.media.Schema; +import org.springframework.validation.annotation.Validated; + +import java.util.ArrayList; +import java.util.Objects; + +/** + * Collection of updates that are to be processed. + */ +@Schema(description = "Collection of updates that are to be processed.") +@Validated +@javax.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.SpringCodegen", date = "2022-09-27T11:46:46.417Z[GMT]") + + +public class RequestGenericPatchArray extends ArrayList { + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + return true; + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode()); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class RequestGenericPatchArray {\n"); + sb.append(" ").append(toIndentedString(super.toString())).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/RequestLink.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/RequestLink.java new file mode 100644 index 000000000..215422ce6 --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/RequestLink.java @@ -0,0 +1,209 @@ +package org.mifos.connector.gsmastub.model; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import org.springframework.validation.annotation.Validated; +import org.threeten.bp.OffsetDateTime; + +import javax.validation.Valid; +import javax.validation.constraints.NotNull; +import java.util.Objects; + +/** + * RequestLink + */ +@Validated +@javax.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.SpringCodegen", date = "2022-09-27T11:46:46.417Z[GMT]") + + +public class RequestLink { + @JsonProperty("sourceAccountIdentifiers") + private DebitPartyArray sourceAccountIdentifiers = null; + + @JsonProperty("mode") + private Mode mode = null; + + @JsonProperty("status") + private Status status = null; + + @JsonProperty("requestingOrganisation") + private RequestingOrganisation requestingOrganisation = null; + + @JsonProperty("requestDate") + private OffsetDateTime requestDate = null; + + @JsonProperty("customData") + private CustomDataArray customData = null; + + public RequestLink sourceAccountIdentifiers(DebitPartyArray sourceAccountIdentifiers) { + this.sourceAccountIdentifiers = sourceAccountIdentifiers; + return this; + } + + /** + * Get sourceAccountIdentifiers + * @return sourceAccountIdentifiers + **/ + @Schema(required = true, description = "") + @NotNull + + @Valid + public DebitPartyArray getSourceAccountIdentifiers() { + return sourceAccountIdentifiers; + } + + public void setSourceAccountIdentifiers(DebitPartyArray sourceAccountIdentifiers) { + this.sourceAccountIdentifiers = sourceAccountIdentifiers; + } + + public RequestLink mode(Mode mode) { + this.mode = mode; + return this; + } + + /** + * Get mode + * @return mode + **/ + @Schema(required = true, description = "") + @NotNull + + @Valid + public Mode getMode() { + return mode; + } + + public void setMode(Mode mode) { + this.mode = mode; + } + + public RequestLink status(Status status) { + this.status = status; + return this; + } + + /** + * Get status + * @return status + **/ + @Schema(required = true, description = "") + @NotNull + + @Valid + public Status getStatus() { + return status; + } + + public void setStatus(Status status) { + this.status = status; + } + + public RequestLink requestingOrganisation(RequestingOrganisation requestingOrganisation) { + this.requestingOrganisation = requestingOrganisation; + return this; + } + + /** + * Get requestingOrganisation + * @return requestingOrganisation + **/ + @Schema(description = "") + + @Valid + public RequestingOrganisation getRequestingOrganisation() { + return requestingOrganisation; + } + + public void setRequestingOrganisation(RequestingOrganisation requestingOrganisation) { + this.requestingOrganisation = requestingOrganisation; + } + + public RequestLink requestDate(OffsetDateTime requestDate) { + this.requestDate = requestDate; + return this; + } + + /** + * The date and time of the request as supplied by the client. + * @return requestDate + **/ + @Schema(description = "The date and time of the request as supplied by the client.") + + @Valid + public OffsetDateTime getRequestDate() { + return requestDate; + } + + public void setRequestDate(OffsetDateTime requestDate) { + this.requestDate = requestDate; + } + + public RequestLink customData(CustomDataArray customData) { + this.customData = customData; + return this; + } + + /** + * Get customData + * @return customData + **/ + @Schema(description = "") + + @Valid + public CustomDataArray getCustomData() { + return customData; + } + + public void setCustomData(CustomDataArray customData) { + this.customData = customData; + } + + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + RequestLink requestLink = (RequestLink) o; + return Objects.equals(this.sourceAccountIdentifiers, requestLink.sourceAccountIdentifiers) && + Objects.equals(this.mode, requestLink.mode) && + Objects.equals(this.status, requestLink.status) && + Objects.equals(this.requestingOrganisation, requestLink.requestingOrganisation) && + Objects.equals(this.requestDate, requestLink.requestDate) && + Objects.equals(this.customData, requestLink.customData); + } + + @Override + public int hashCode() { + return Objects.hash(sourceAccountIdentifiers, mode, status, requestingOrganisation, requestDate, customData); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class RequestLink {\n"); + + sb.append(" sourceAccountIdentifiers: ").append(toIndentedString(sourceAccountIdentifiers)).append("\n"); + sb.append(" mode: ").append(toIndentedString(mode)).append("\n"); + sb.append(" status: ").append(toIndentedString(status)).append("\n"); + sb.append(" requestingOrganisation: ").append(toIndentedString(requestingOrganisation)).append("\n"); + sb.append(" requestDate: ").append(toIndentedString(requestDate)).append("\n"); + sb.append(" customData: ").append(toIndentedString(customData)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/RequestQuotation.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/RequestQuotation.java new file mode 100644 index 000000000..5f9969883 --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/RequestQuotation.java @@ -0,0 +1,460 @@ +package org.mifos.connector.gsmastub.model; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import org.springframework.validation.annotation.Validated; +import org.threeten.bp.OffsetDateTime; + +import javax.validation.Valid; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Pattern; +import javax.validation.constraints.Size; +import java.util.Objects; + +/** + * RequestQuotation + */ +@Validated +@javax.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.SpringCodegen", date = "2022-09-27T11:46:46.417Z[GMT]") + + +public class RequestQuotation { + @JsonProperty("creditParty") + private CreditPartyArray creditParty = null; + + @JsonProperty("debitParty") + private DebitPartyArray debitParty = null; + + @JsonProperty("type") + private Type type = null; + + @JsonProperty("subType") + private String subType = null; + + @JsonProperty("requestAmount") + private String requestAmount = null; + + @JsonProperty("requestCurrency") + private Currency requestCurrency = null; + + @JsonProperty("chosenDeliveryMethod") + private DeliveryMethod chosenDeliveryMethod = null; + + @JsonProperty("originCountry") + private Nationality originCountry = null; + + @JsonProperty("receivingCountry") + private Nationality receivingCountry = null; + + @JsonProperty("recipientKyc") + private Kyc recipientKyc = null; + + @JsonProperty("senderKyc") + private Kyc senderKyc = null; + + @JsonProperty("requestingOrganisation") + private RequestingOrganisation requestingOrganisation = null; + + @JsonProperty("sendingServiceProviderCountry") + private Nationality sendingServiceProviderCountry = null; + + @JsonProperty("requestDate") + private OffsetDateTime requestDate = null; + + @JsonProperty("customData") + private CustomDataArray customData = null; + + @JsonProperty("metadata") + private MetadataArray metadata = null; + + public RequestQuotation creditParty(CreditPartyArray creditParty) { + this.creditParty = creditParty; + return this; + } + + /** + * Get creditParty + * @return creditParty + **/ + @Schema(required = true, description = "") + @NotNull + + @Valid + public CreditPartyArray getCreditParty() { + return creditParty; + } + + public void setCreditParty(CreditPartyArray creditParty) { + this.creditParty = creditParty; + } + + public RequestQuotation debitParty(DebitPartyArray debitParty) { + this.debitParty = debitParty; + return this; + } + + /** + * Get debitParty + * @return debitParty + **/ + @Schema(required = true, description = "") + @NotNull + + @Valid + public DebitPartyArray getDebitParty() { + return debitParty; + } + + public void setDebitParty(DebitPartyArray debitParty) { + this.debitParty = debitParty; + } + + public RequestQuotation type(Type type) { + this.type = type; + return this; + } + + /** + * Get type + * @return type + **/ + @Schema(description = "") + + @Valid + public Type getType() { + return type; + } + + public void setType(Type type) { + this.type = type; + } + + public RequestQuotation subType(String subType) { + this.subType = subType; + return this; + } + + /** + * A non-harmonised sub-classification of the type of transaction. Values are not fixed, and usage will vary according to Provider. + * @return subType + **/ + @Schema(description = "A non-harmonised sub-classification of the type of transaction. Values are not fixed, and usage will vary according to Provider.") + + @Size(max=256) public String getSubType() { + return subType; + } + + public void setSubType(String subType) { + this.subType = subType; + } + + public RequestQuotation requestAmount(String requestAmount) { + this.requestAmount = requestAmount; + return this; + } + + /** + * Get requestAmount + * @return requestAmount + **/ + @Schema(example = "15.21", required = true, description = "") + @NotNull + + @Pattern(regexp="^([0]|([1-9][0-9]{0,17}))([.][0-9]{0,3}[0-9])?$") @Size(min=1,max=23) public String getRequestAmount() { + return requestAmount; + } + + public void setRequestAmount(String requestAmount) { + this.requestAmount = requestAmount; + } + + public RequestQuotation requestCurrency(Currency requestCurrency) { + this.requestCurrency = requestCurrency; + return this; + } + + /** + * Get requestCurrency + * @return requestCurrency + **/ + @Schema(required = true, description = "") + @NotNull + + @Valid + public Currency getRequestCurrency() { + return requestCurrency; + } + + public void setRequestCurrency(Currency requestCurrency) { + this.requestCurrency = requestCurrency; + } + + public RequestQuotation chosenDeliveryMethod(DeliveryMethod chosenDeliveryMethod) { + this.chosenDeliveryMethod = chosenDeliveryMethod; + return this; + } + + /** + * Get chosenDeliveryMethod + * @return chosenDeliveryMethod + **/ + @Schema(description = "") + + @Valid + public DeliveryMethod getChosenDeliveryMethod() { + return chosenDeliveryMethod; + } + + public void setChosenDeliveryMethod(DeliveryMethod chosenDeliveryMethod) { + this.chosenDeliveryMethod = chosenDeliveryMethod; + } + + public RequestQuotation originCountry(Nationality originCountry) { + this.originCountry = originCountry; + return this; + } + + /** + * Get originCountry + * @return originCountry + **/ + @Schema(description = "") + + @Valid + public Nationality getOriginCountry() { + return originCountry; + } + + public void setOriginCountry(Nationality originCountry) { + this.originCountry = originCountry; + } + + public RequestQuotation receivingCountry(Nationality receivingCountry) { + this.receivingCountry = receivingCountry; + return this; + } + + /** + * Get receivingCountry + * @return receivingCountry + **/ + @Schema(description = "") + + @Valid + public Nationality getReceivingCountry() { + return receivingCountry; + } + + public void setReceivingCountry(Nationality receivingCountry) { + this.receivingCountry = receivingCountry; + } + + public RequestQuotation recipientKyc(Kyc recipientKyc) { + this.recipientKyc = recipientKyc; + return this; + } + + /** + * Get recipientKyc + * @return recipientKyc + **/ + @Schema(description = "") + + @Valid + public Kyc getRecipientKyc() { + return recipientKyc; + } + + public void setRecipientKyc(Kyc recipientKyc) { + this.recipientKyc = recipientKyc; + } + + public RequestQuotation senderKyc(Kyc senderKyc) { + this.senderKyc = senderKyc; + return this; + } + + /** + * Get senderKyc + * @return senderKyc + **/ + @Schema(description = "") + + @Valid + public Kyc getSenderKyc() { + return senderKyc; + } + + public void setSenderKyc(Kyc senderKyc) { + this.senderKyc = senderKyc; + } + + public RequestQuotation requestingOrganisation(RequestingOrganisation requestingOrganisation) { + this.requestingOrganisation = requestingOrganisation; + return this; + } + + /** + * Get requestingOrganisation + * @return requestingOrganisation + **/ + @Schema(description = "") + + @Valid + public RequestingOrganisation getRequestingOrganisation() { + return requestingOrganisation; + } + + public void setRequestingOrganisation(RequestingOrganisation requestingOrganisation) { + this.requestingOrganisation = requestingOrganisation; + } + + public RequestQuotation sendingServiceProviderCountry(Nationality sendingServiceProviderCountry) { + this.sendingServiceProviderCountry = sendingServiceProviderCountry; + return this; + } + + /** + * Get sendingServiceProviderCountry + * @return sendingServiceProviderCountry + **/ + @Schema(description = "") + + @Valid + public Nationality getSendingServiceProviderCountry() { + return sendingServiceProviderCountry; + } + + public void setSendingServiceProviderCountry(Nationality sendingServiceProviderCountry) { + this.sendingServiceProviderCountry = sendingServiceProviderCountry; + } + + public RequestQuotation requestDate(OffsetDateTime requestDate) { + this.requestDate = requestDate; + return this; + } + + /** + * The date and time of the request as supplied by the client. + * @return requestDate + **/ + @Schema(description = "The date and time of the request as supplied by the client.") + + @Valid + public OffsetDateTime getRequestDate() { + return requestDate; + } + + public void setRequestDate(OffsetDateTime requestDate) { + this.requestDate = requestDate; + } + + public RequestQuotation customData(CustomDataArray customData) { + this.customData = customData; + return this; + } + + /** + * Get customData + * @return customData + **/ + @Schema(description = "") + + @Valid + public CustomDataArray getCustomData() { + return customData; + } + + public void setCustomData(CustomDataArray customData) { + this.customData = customData; + } + + public RequestQuotation metadata(MetadataArray metadata) { + this.metadata = metadata; + return this; + } + + /** + * Get metadata + * @return metadata + **/ + @Schema(description = "") + + @Valid + public MetadataArray getMetadata() { + return metadata; + } + + public void setMetadata(MetadataArray metadata) { + this.metadata = metadata; + } + + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + RequestQuotation requestQuotation = (RequestQuotation) o; + return Objects.equals(this.creditParty, requestQuotation.creditParty) && + Objects.equals(this.debitParty, requestQuotation.debitParty) && + Objects.equals(this.type, requestQuotation.type) && + Objects.equals(this.subType, requestQuotation.subType) && + Objects.equals(this.requestAmount, requestQuotation.requestAmount) && + Objects.equals(this.requestCurrency, requestQuotation.requestCurrency) && + Objects.equals(this.chosenDeliveryMethod, requestQuotation.chosenDeliveryMethod) && + Objects.equals(this.originCountry, requestQuotation.originCountry) && + Objects.equals(this.receivingCountry, requestQuotation.receivingCountry) && + Objects.equals(this.recipientKyc, requestQuotation.recipientKyc) && + Objects.equals(this.senderKyc, requestQuotation.senderKyc) && + Objects.equals(this.requestingOrganisation, requestQuotation.requestingOrganisation) && + Objects.equals(this.sendingServiceProviderCountry, requestQuotation.sendingServiceProviderCountry) && + Objects.equals(this.requestDate, requestQuotation.requestDate) && + Objects.equals(this.customData, requestQuotation.customData) && + Objects.equals(this.metadata, requestQuotation.metadata); + } + + @Override + public int hashCode() { + return Objects.hash(creditParty, debitParty, type, subType, requestAmount, requestCurrency, chosenDeliveryMethod, originCountry, receivingCountry, recipientKyc, senderKyc, requestingOrganisation, sendingServiceProviderCountry, requestDate, customData, metadata); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class RequestQuotation {\n"); + + sb.append(" creditParty: ").append(toIndentedString(creditParty)).append("\n"); + sb.append(" debitParty: ").append(toIndentedString(debitParty)).append("\n"); + sb.append(" type: ").append(toIndentedString(type)).append("\n"); + sb.append(" subType: ").append(toIndentedString(subType)).append("\n"); + sb.append(" requestAmount: ").append(toIndentedString(requestAmount)).append("\n"); + sb.append(" requestCurrency: ").append(toIndentedString(requestCurrency)).append("\n"); + sb.append(" chosenDeliveryMethod: ").append(toIndentedString(chosenDeliveryMethod)).append("\n"); + sb.append(" originCountry: ").append(toIndentedString(originCountry)).append("\n"); + sb.append(" receivingCountry: ").append(toIndentedString(receivingCountry)).append("\n"); + sb.append(" recipientKyc: ").append(toIndentedString(recipientKyc)).append("\n"); + sb.append(" senderKyc: ").append(toIndentedString(senderKyc)).append("\n"); + sb.append(" requestingOrganisation: ").append(toIndentedString(requestingOrganisation)).append("\n"); + sb.append(" sendingServiceProviderCountry: ").append(toIndentedString(sendingServiceProviderCountry)).append("\n"); + sb.append(" requestDate: ").append(toIndentedString(requestDate)).append("\n"); + sb.append(" customData: ").append(toIndentedString(customData)).append("\n"); + sb.append(" metadata: ").append(toIndentedString(metadata)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/RequestReversal.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/RequestReversal.java new file mode 100644 index 000000000..3d331b0ba --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/RequestReversal.java @@ -0,0 +1,476 @@ +package org.mifos.connector.gsmastub.model; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import org.springframework.validation.annotation.Validated; +import org.threeten.bp.OffsetDateTime; + +import javax.validation.Valid; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Pattern; +import javax.validation.constraints.Size; +import java.util.Objects; + +/** + * RequestReversal + */ +@Validated +@javax.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.SpringCodegen", date = "2022-09-27T11:46:46.417Z[GMT]") + + +public class RequestReversal { + @JsonProperty("requestingOrganisationTransactionReference") + private String requestingOrganisationTransactionReference = null; + + @JsonProperty("creditParty") + private CreditPartyArray creditParty = null; + + @JsonProperty("debitParty") + private DebitPartyArray debitParty = null; + + @JsonProperty("type") + private TypeReversal type = null; + + @JsonProperty("subType") + private String subType = null; + + @JsonProperty("amount") + private String amount = null; + + @JsonProperty("currency") + private Currency currency = null; + + @JsonProperty("descriptionText") + private String descriptionText = null; + + @JsonProperty("fees") + private FeesArray fees = null; + + @JsonProperty("geoCode") + private String geoCode = null; + + @JsonProperty("requestingOrganisation") + private RequestingOrganisation requestingOrganisation = null; + + @JsonProperty("servicingIdentity") + private String servicingIdentity = null; + + @JsonProperty("requestDate") + private OffsetDateTime requestDate = null; + + @JsonProperty("customData") + private CustomDataArray customData = null; + + @JsonProperty("metadata") + private MetadataArray metadata = null; + + @JsonProperty("receivingLei") + private String receivingLei = null; + + @JsonProperty("requestingLei") + private String requestingLei = null; + + public RequestReversal requestingOrganisationTransactionReference(String requestingOrganisationTransactionReference) { + this.requestingOrganisationTransactionReference = requestingOrganisationTransactionReference; + return this; + } + + /** + * A reference provided by the requesting organisation that is to be associated with the transaction. + * @return requestingOrganisationTransactionReference + **/ + @Schema(description = "A reference provided by the requesting organisation that is to be associated with the transaction.") + + @Size(max=256) public String getRequestingOrganisationTransactionReference() { + return requestingOrganisationTransactionReference; + } + + public void setRequestingOrganisationTransactionReference(String requestingOrganisationTransactionReference) { + this.requestingOrganisationTransactionReference = requestingOrganisationTransactionReference; + } + + public RequestReversal creditParty(CreditPartyArray creditParty) { + this.creditParty = creditParty; + return this; + } + + /** + * Get creditParty + * @return creditParty + **/ + @Schema(description = "") + + @Valid + public CreditPartyArray getCreditParty() { + return creditParty; + } + + public void setCreditParty(CreditPartyArray creditParty) { + this.creditParty = creditParty; + } + + public RequestReversal debitParty(DebitPartyArray debitParty) { + this.debitParty = debitParty; + return this; + } + + /** + * Get debitParty + * @return debitParty + **/ + @Schema(description = "") + + @Valid + public DebitPartyArray getDebitParty() { + return debitParty; + } + + public void setDebitParty(DebitPartyArray debitParty) { + this.debitParty = debitParty; + } + + public RequestReversal type(TypeReversal type) { + this.type = type; + return this; + } + + /** + * Get type + * @return type + **/ + @Schema(required = true, description = "") + @NotNull + + @Valid + public TypeReversal getType() { + return type; + } + + public void setType(TypeReversal type) { + this.type = type; + } + + public RequestReversal subType(String subType) { + this.subType = subType; + return this; + } + + /** + * A non-harmonised sub-classification of the type of transaction. Values are not fixed, and usage will vary according to Provider. + * @return subType + **/ + @Schema(description = "A non-harmonised sub-classification of the type of transaction. Values are not fixed, and usage will vary according to Provider.") + + @Size(max=256) public String getSubType() { + return subType; + } + + public void setSubType(String subType) { + this.subType = subType; + } + + public RequestReversal amount(String amount) { + this.amount = amount; + return this; + } + + /** + * Get amount + * @return amount + **/ + @Schema(example = "15.21", description = "") + + @Pattern(regexp="^([0]|([1-9][0-9]{0,17}))([.][0-9]{0,3}[0-9])?$") @Size(min=1,max=23) public String getAmount() { + return amount; + } + + public void setAmount(String amount) { + this.amount = amount; + } + + public RequestReversal currency(Currency currency) { + this.currency = currency; + return this; + } + + /** + * Get currency + * @return currency + **/ + @Schema(description = "") + + @Valid + public Currency getCurrency() { + return currency; + } + + public void setCurrency(Currency currency) { + this.currency = currency; + } + + public RequestReversal descriptionText(String descriptionText) { + this.descriptionText = descriptionText; + return this; + } + + /** + * Free format text description of the transaction provided by the client. This can be provided as a reference for the receiver on a notification SMS and on an account statement. + * @return descriptionText + **/ + @Schema(description = "Free format text description of the transaction provided by the client. This can be provided as a reference for the receiver on a notification SMS and on an account statement.") + + @Size(max=160) public String getDescriptionText() { + return descriptionText; + } + + public void setDescriptionText(String descriptionText) { + this.descriptionText = descriptionText; + } + + public RequestReversal fees(FeesArray fees) { + this.fees = fees; + return this; + } + + /** + * Get fees + * @return fees + **/ + @Schema(description = "") + + @Valid + public FeesArray getFees() { + return fees; + } + + public void setFees(FeesArray fees) { + this.fees = fees; + } + + public RequestReversal geoCode(String geoCode) { + this.geoCode = geoCode; + return this; + } + + /** + * Indicates the geographic location from where the transaction was initiated. + * @return geoCode + **/ + @Schema(example = "37.423825,-122.082900", description = "Indicates the geographic location from where the transaction was initiated.") + + @Pattern(regexp="^(-?(90|(\\d|[1-8]\\d)(\\.\\d{1,6}){0,1}))\\,{1}(-?(180|(\\d|\\d\\d|1[0-7]\\d)(\\.\\d{1,6}){0,1}))$") @Size(max=256) public String getGeoCode() { + return geoCode; + } + + public void setGeoCode(String geoCode) { + this.geoCode = geoCode; + } + + public RequestReversal requestingOrganisation(RequestingOrganisation requestingOrganisation) { + this.requestingOrganisation = requestingOrganisation; + return this; + } + + /** + * Get requestingOrganisation + * @return requestingOrganisation + **/ + @Schema(description = "") + + @Valid + public RequestingOrganisation getRequestingOrganisation() { + return requestingOrganisation; + } + + public void setRequestingOrganisation(RequestingOrganisation requestingOrganisation) { + this.requestingOrganisation = requestingOrganisation; + } + + public RequestReversal servicingIdentity(String servicingIdentity) { + this.servicingIdentity = servicingIdentity; + return this; + } + + /** + * The field is used to identify the servicing identity for transactions, e.g. till, POS ID, assistant ID. + * @return servicingIdentity + **/ + @Schema(description = "The field is used to identify the servicing identity for transactions, e.g. till, POS ID, assistant ID.") + + @Size(max=256) public String getServicingIdentity() { + return servicingIdentity; + } + + public void setServicingIdentity(String servicingIdentity) { + this.servicingIdentity = servicingIdentity; + } + + public RequestReversal requestDate(OffsetDateTime requestDate) { + this.requestDate = requestDate; + return this; + } + + /** + * The date and time of the request as supplied by the client. + * @return requestDate + **/ + @Schema(description = "The date and time of the request as supplied by the client.") + + @Valid + public OffsetDateTime getRequestDate() { + return requestDate; + } + + public void setRequestDate(OffsetDateTime requestDate) { + this.requestDate = requestDate; + } + + public RequestReversal customData(CustomDataArray customData) { + this.customData = customData; + return this; + } + + /** + * Get customData + * @return customData + **/ + @Schema(description = "") + + @Valid + public CustomDataArray getCustomData() { + return customData; + } + + public void setCustomData(CustomDataArray customData) { + this.customData = customData; + } + + public RequestReversal metadata(MetadataArray metadata) { + this.metadata = metadata; + return this; + } + + /** + * Get metadata + * @return metadata + **/ + @Schema(description = "") + + @Valid + public MetadataArray getMetadata() { + return metadata; + } + + public void setMetadata(MetadataArray metadata) { + this.metadata = metadata; + } + + public RequestReversal receivingLei(String receivingLei) { + this.receivingLei = receivingLei; + return this; + } + + /** + * Legal Entity Identifier of the organisation that is receiving the transaction. + * @return receivingLei + **/ + @Schema(description = "Legal Entity Identifier of the organisation that is receiving the transaction.") + + @Pattern(regexp="^[A-Z0-9]{4}00[A-Z0-9]{12}\\d{2}$") @Size(max=20) public String getReceivingLei() { + return receivingLei; + } + + public void setReceivingLei(String receivingLei) { + this.receivingLei = receivingLei; + } + + public RequestReversal requestingLei(String requestingLei) { + this.requestingLei = requestingLei; + return this; + } + + /** + * Legal Entity Identifier of the organisation that is requesting the transaction. + * @return requestingLei + **/ + @Schema(description = "Legal Entity Identifier of the organisation that is requesting the transaction.") + + @Pattern(regexp="^[A-Z0-9]{4}00[A-Z0-9]{12}\\d{2}$") @Size(max=20) public String getRequestingLei() { + return requestingLei; + } + + public void setRequestingLei(String requestingLei) { + this.requestingLei = requestingLei; + } + + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + RequestReversal requestReversal = (RequestReversal) o; + return Objects.equals(this.requestingOrganisationTransactionReference, requestReversal.requestingOrganisationTransactionReference) && + Objects.equals(this.creditParty, requestReversal.creditParty) && + Objects.equals(this.debitParty, requestReversal.debitParty) && + Objects.equals(this.type, requestReversal.type) && + Objects.equals(this.subType, requestReversal.subType) && + Objects.equals(this.amount, requestReversal.amount) && + Objects.equals(this.currency, requestReversal.currency) && + Objects.equals(this.descriptionText, requestReversal.descriptionText) && + Objects.equals(this.fees, requestReversal.fees) && + Objects.equals(this.geoCode, requestReversal.geoCode) && + Objects.equals(this.requestingOrganisation, requestReversal.requestingOrganisation) && + Objects.equals(this.servicingIdentity, requestReversal.servicingIdentity) && + Objects.equals(this.requestDate, requestReversal.requestDate) && + Objects.equals(this.customData, requestReversal.customData) && + Objects.equals(this.metadata, requestReversal.metadata) && + Objects.equals(this.receivingLei, requestReversal.receivingLei) && + Objects.equals(this.requestingLei, requestReversal.requestingLei); + } + + @Override + public int hashCode() { + return Objects.hash(requestingOrganisationTransactionReference, creditParty, debitParty, type, subType, amount, currency, descriptionText, fees, geoCode, requestingOrganisation, servicingIdentity, requestDate, customData, metadata, receivingLei, requestingLei); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class RequestReversal {\n"); + + sb.append(" requestingOrganisationTransactionReference: ").append(toIndentedString(requestingOrganisationTransactionReference)).append("\n"); + sb.append(" creditParty: ").append(toIndentedString(creditParty)).append("\n"); + sb.append(" debitParty: ").append(toIndentedString(debitParty)).append("\n"); + sb.append(" type: ").append(toIndentedString(type)).append("\n"); + sb.append(" subType: ").append(toIndentedString(subType)).append("\n"); + sb.append(" amount: ").append(toIndentedString(amount)).append("\n"); + sb.append(" currency: ").append(toIndentedString(currency)).append("\n"); + sb.append(" descriptionText: ").append(toIndentedString(descriptionText)).append("\n"); + sb.append(" fees: ").append(toIndentedString(fees)).append("\n"); + sb.append(" geoCode: ").append(toIndentedString(geoCode)).append("\n"); + sb.append(" requestingOrganisation: ").append(toIndentedString(requestingOrganisation)).append("\n"); + sb.append(" servicingIdentity: ").append(toIndentedString(servicingIdentity)).append("\n"); + sb.append(" requestDate: ").append(toIndentedString(requestDate)).append("\n"); + sb.append(" customData: ").append(toIndentedString(customData)).append("\n"); + sb.append(" metadata: ").append(toIndentedString(metadata)).append("\n"); + sb.append(" receivingLei: ").append(toIndentedString(receivingLei)).append("\n"); + sb.append(" requestingLei: ").append(toIndentedString(requestingLei)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/RequestStateObject.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/RequestStateObject.java new file mode 100644 index 000000000..207763552 --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/RequestStateObject.java @@ -0,0 +1,323 @@ +package org.mifos.connector.gsmastub.model; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonValue; +import io.swagger.v3.oas.annotations.media.Schema; +import org.springframework.validation.annotation.Validated; +import org.threeten.bp.OffsetDateTime; + +import javax.validation.Valid; +import javax.validation.constraints.DecimalMin; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Pattern; +import javax.validation.constraints.Size; +import java.math.BigDecimal; +import java.util.Objects; + +/** + * RequestStateObject + */ +@Validated +@javax.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.SpringCodegen", date = "2022-09-27T11:46:46.417Z[GMT]") + + +public class RequestStateObject { + @JsonProperty("serverCorrelationId") + private String serverCorrelationId = null; + + @JsonProperty("objectReference") + private String objectReference = null; + + /** + * Indicates the status of the request. + */ + public enum StatusEnum { + PENDING("pending"), + + COMPLETED("completed"), + + FAILED("failed"); + + private String value; + + StatusEnum(String value) { + this.value = value; + } + + @Override + @JsonValue + public String toString() { + return String.valueOf(value); + } + + @JsonCreator + public static StatusEnum fromValue(String text) { + for (StatusEnum b : StatusEnum.values()) { + if (String.valueOf(b.value).equals(text)) { + return b; + } + } + return null; + } + } + @JsonProperty("status") + private StatusEnum status = null; + + /** + * Indicates whether a callback will be issued or whether the client will need to poll. + */ + public enum NotificationMethodEnum { + CALLBACK("callback"), + + POLLING("polling"); + + private String value; + + NotificationMethodEnum(String value) { + this.value = value; + } + + @Override + @JsonValue + public String toString() { + return String.valueOf(value); + } + + @JsonCreator + public static NotificationMethodEnum fromValue(String text) { + for (NotificationMethodEnum b : NotificationMethodEnum.values()) { + if (String.valueOf(b.value).equals(text)) { + return b; + } + } + return null; + } + } + @JsonProperty("notificationMethod") + private NotificationMethodEnum notificationMethod = null; + + @JsonProperty("pendingReason") + private String pendingReason = null; + + @JsonProperty("expiryTime") + private OffsetDateTime expiryTime = null; + + @JsonProperty("pollLimit") + private BigDecimal pollLimit = null; + + @JsonProperty("error") + private ErrorObject error = null; + + public RequestStateObject serverCorrelationId(String serverCorrelationId) { + this.serverCorrelationId = serverCorrelationId; + return this; + } + + /** + * A unique identifier issued by the provider to enable the client to identify the RequestState resource on subsequent polling requests. Must be supplied as a UUID. + * @return serverCorrelationId + **/ + @Schema(required = true, description = "A unique identifier issued by the provider to enable the client to identify the RequestState resource on subsequent polling requests. Must be supplied as a UUID.") + @NotNull + + @Pattern(regexp="^[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{12}$") @Size(min=1,max=256) public String getServerCorrelationId() { + return serverCorrelationId; + } + + public void setServerCorrelationId(String serverCorrelationId) { + this.serverCorrelationId = serverCorrelationId; + } + + public RequestStateObject objectReference(String objectReference) { + this.objectReference = objectReference; + return this; + } + + /** + * Provides a reference to the subject resource, e.g. transaction reference. + * @return objectReference + **/ + @Schema(description = "Provides a reference to the subject resource, e.g. transaction reference.") + + @Size(max=256) public String getObjectReference() { + return objectReference; + } + + public void setObjectReference(String objectReference) { + this.objectReference = objectReference; + } + + public RequestStateObject status(StatusEnum status) { + this.status = status; + return this; + } + + /** + * Indicates the status of the request. + * @return status + **/ + @Schema(required = true, description = "Indicates the status of the request.") + @NotNull + + public StatusEnum getStatus() { + return status; + } + + public void setStatus(StatusEnum status) { + this.status = status; + } + + public RequestStateObject notificationMethod(NotificationMethodEnum notificationMethod) { + this.notificationMethod = notificationMethod; + return this; + } + + /** + * Indicates whether a callback will be issued or whether the client will need to poll. + * @return notificationMethod + **/ + @Schema(required = true, description = "Indicates whether a callback will be issued or whether the client will need to poll.") + @NotNull + + public NotificationMethodEnum getNotificationMethod() { + return notificationMethod; + } + + public void setNotificationMethod(NotificationMethodEnum notificationMethod) { + this.notificationMethod = notificationMethod; + } + + public RequestStateObject pendingReason(String pendingReason) { + this.pendingReason = pendingReason; + return this; + } + + /** + * A textual description that can be provided to describe the reason for a pending status. + * @return pendingReason + **/ + @Schema(description = "A textual description that can be provided to describe the reason for a pending status.") + + @Size(max=256) public String getPendingReason() { + return pendingReason; + } + + public void setPendingReason(String pendingReason) { + this.pendingReason = pendingReason; + } + + public RequestStateObject expiryTime(OffsetDateTime expiryTime) { + this.expiryTime = expiryTime; + return this; + } + + /** + * Indicate the time by which the provider will fail the request if completion criteria have not been met. For an example, a debit party failing to authorise within the allowed period. + * @return expiryTime + **/ + @Schema(description = "Indicate the time by which the provider will fail the request if completion criteria have not been met. For an example, a debit party failing to authorise within the allowed period.") + + @Valid + public OffsetDateTime getExpiryTime() { + return expiryTime; + } + + public void setExpiryTime(OffsetDateTime expiryTime) { + this.expiryTime = expiryTime; + } + + public RequestStateObject pollLimit(BigDecimal pollLimit) { + this.pollLimit = pollLimit; + return this; + } + + /** + * Indicates the number of poll attempts for the given requeststate resource that will be allowed by the provider. + * minimum: 0 + * @return pollLimit + **/ + @Schema(description = "Indicates the number of poll attempts for the given requeststate resource that will be allowed by the provider.") + + @Valid + @DecimalMin("0") public BigDecimal getPollLimit() { + return pollLimit; + } + + public void setPollLimit(BigDecimal pollLimit) { + this.pollLimit = pollLimit; + } + + public RequestStateObject error(ErrorObject error) { + this.error = error; + return this; + } + + /** + * Get error + * @return error + **/ + @Schema(description = "") + + @Valid + public ErrorObject getError() { + return error; + } + + public void setError(ErrorObject error) { + this.error = error; + } + + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + RequestStateObject requestStateObject = (RequestStateObject) o; + return Objects.equals(this.serverCorrelationId, requestStateObject.serverCorrelationId) && + Objects.equals(this.objectReference, requestStateObject.objectReference) && + Objects.equals(this.status, requestStateObject.status) && + Objects.equals(this.notificationMethod, requestStateObject.notificationMethod) && + Objects.equals(this.pendingReason, requestStateObject.pendingReason) && + Objects.equals(this.expiryTime, requestStateObject.expiryTime) && + Objects.equals(this.pollLimit, requestStateObject.pollLimit) && + Objects.equals(this.error, requestStateObject.error); + } + + @Override + public int hashCode() { + return Objects.hash(serverCorrelationId, objectReference, status, notificationMethod, pendingReason, expiryTime, pollLimit, error); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class RequestStateObject {\n"); + + sb.append(" serverCorrelationId: ").append(toIndentedString(serverCorrelationId)).append("\n"); + sb.append(" objectReference: ").append(toIndentedString(objectReference)).append("\n"); + sb.append(" status: ").append(toIndentedString(status)).append("\n"); + sb.append(" notificationMethod: ").append(toIndentedString(notificationMethod)).append("\n"); + sb.append(" pendingReason: ").append(toIndentedString(pendingReason)).append("\n"); + sb.append(" expiryTime: ").append(toIndentedString(expiryTime)).append("\n"); + sb.append(" pollLimit: ").append(toIndentedString(pollLimit)).append("\n"); + sb.append(" error: ").append(toIndentedString(error)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/RequestTransaction.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/RequestTransaction.java new file mode 100644 index 000000000..550d5a85d --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/RequestTransaction.java @@ -0,0 +1,603 @@ +package org.mifos.connector.gsmastub.model; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import org.springframework.validation.annotation.Validated; +import org.threeten.bp.OffsetDateTime; + +import javax.validation.Valid; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Pattern; +import javax.validation.constraints.Size; +import java.util.Objects; + +/** + * RequestTransaction + */ +@Validated +@javax.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.SpringCodegen", date = "2022-09-27T11:46:46.417Z[GMT]") + + +public class RequestTransaction { + @JsonProperty("requestingOrganisationTransactionReference") + private String requestingOrganisationTransactionReference = null; + + @JsonProperty("originalTransactionReference") + private String originalTransactionReference = null; + + @JsonProperty("creditParty") + private CreditPartyArray creditParty = null; + + @JsonProperty("debitParty") + private DebitPartyArray debitParty = null; + + @JsonProperty("type") + private Type type = null; + + @JsonProperty("subType") + private String subType = null; + + @JsonProperty("amount") + private String amount = null; + + @JsonProperty("currency") + private Currency currency = null; + + @JsonProperty("descriptionText") + private String descriptionText = null; + + @JsonProperty("fees") + private FeesArray fees = null; + + @JsonProperty("geoCode") + private String geoCode = null; + + @JsonProperty("internationalTransferInformation") + private InternationalTransferInformation internationalTransferInformation = null; + + @JsonProperty("oneTimeCode") + private String oneTimeCode = null; + + @JsonProperty("recipientKyc") + private Kyc recipientKyc = null; + + @JsonProperty("senderKyc") + private Kyc senderKyc = null; + + @JsonProperty("requestingOrganisation") + private RequestingOrganisation requestingOrganisation = null; + + @JsonProperty("servicingIdentity") + private String servicingIdentity = null; + + @JsonProperty("requestDate") + private OffsetDateTime requestDate = null; + + @JsonProperty("customData") + private CustomDataArray customData = null; + + @JsonProperty("metadata") + private MetadataArray metadata = null; + + @JsonProperty("receivingLei") + private String receivingLei = null; + + @JsonProperty("requestingLei") + private String requestingLei = null; + + public RequestTransaction requestingOrganisationTransactionReference(String requestingOrganisationTransactionReference) { + this.requestingOrganisationTransactionReference = requestingOrganisationTransactionReference; + return this; + } + + /** + * A reference provided by the requesting organisation that is to be associated with the transaction. + * @return requestingOrganisationTransactionReference + **/ + @Schema(description = "A reference provided by the requesting organisation that is to be associated with the transaction.") + + @Size(max=256) public String getRequestingOrganisationTransactionReference() { + return requestingOrganisationTransactionReference; + } + + public void setRequestingOrganisationTransactionReference(String requestingOrganisationTransactionReference) { + this.requestingOrganisationTransactionReference = requestingOrganisationTransactionReference; + } + + public RequestTransaction originalTransactionReference(String originalTransactionReference) { + this.originalTransactionReference = originalTransactionReference; + return this; + } + + /** + * For reversals and refunds, this field indicates the transaction which is the subject of the reversal. + * @return originalTransactionReference + **/ + @Schema(description = "For reversals and refunds, this field indicates the transaction which is the subject of the reversal.") + + @Size(max=256) public String getOriginalTransactionReference() { + return originalTransactionReference; + } + + public void setOriginalTransactionReference(String originalTransactionReference) { + this.originalTransactionReference = originalTransactionReference; + } + + public RequestTransaction creditParty(CreditPartyArray creditParty) { + this.creditParty = creditParty; + return this; + } + + /** + * Get creditParty + * @return creditParty + **/ + @Schema(required = true, description = "") + @NotNull + + @Valid + public CreditPartyArray getCreditParty() { + return creditParty; + } + + public void setCreditParty(CreditPartyArray creditParty) { + this.creditParty = creditParty; + } + + public RequestTransaction debitParty(DebitPartyArray debitParty) { + this.debitParty = debitParty; + return this; + } + + /** + * Get debitParty + * @return debitParty + **/ + @Schema(required = true, description = "") + @NotNull + + @Valid + public DebitPartyArray getDebitParty() { + return debitParty; + } + + public void setDebitParty(DebitPartyArray debitParty) { + this.debitParty = debitParty; + } + + public RequestTransaction type(Type type) { + this.type = type; + return this; + } + + /** + * Get type + * @return type + **/ + @Schema(required = true, description = "") + @NotNull + + @Valid + public Type getType() { + return type; + } + + public void setType(Type type) { + this.type = type; + } + + public RequestTransaction subType(String subType) { + this.subType = subType; + return this; + } + + /** + * A non-harmonised sub-classification of the type of transaction. Values are not fixed, and usage will vary according to Provider. + * @return subType + **/ + @Schema(description = "A non-harmonised sub-classification of the type of transaction. Values are not fixed, and usage will vary according to Provider.") + + @Size(max=256) public String getSubType() { + return subType; + } + + public void setSubType(String subType) { + this.subType = subType; + } + + public RequestTransaction amount(String amount) { + this.amount = amount; + return this; + } + + /** + * Get amount + * @return amount + **/ + @Schema(example = "15.21", required = true, description = "") + @NotNull + + @Pattern(regexp="^([0]|([1-9][0-9]{0,17}))([.][0-9]{0,3}[0-9])?$") @Size(min=1,max=23) public String getAmount() { + return amount; + } + + public void setAmount(String amount) { + this.amount = amount; + } + + public RequestTransaction currency(Currency currency) { + this.currency = currency; + return this; + } + + /** + * Get currency + * @return currency + **/ + @Schema(required = true, description = "") + @NotNull + + @Valid + public Currency getCurrency() { + return currency; + } + + public void setCurrency(Currency currency) { + this.currency = currency; + } + + public RequestTransaction descriptionText(String descriptionText) { + this.descriptionText = descriptionText; + return this; + } + + /** + * Free format text description of the transaction provided by the client. This can be provided as a reference for the receiver on a notification SMS and on an account statement. + * @return descriptionText + **/ + @Schema(description = "Free format text description of the transaction provided by the client. This can be provided as a reference for the receiver on a notification SMS and on an account statement.") + + @Size(max=160) public String getDescriptionText() { + return descriptionText; + } + + public void setDescriptionText(String descriptionText) { + this.descriptionText = descriptionText; + } + + public RequestTransaction fees(FeesArray fees) { + this.fees = fees; + return this; + } + + /** + * Get fees + * @return fees + **/ + @Schema(description = "") + + @Valid + public FeesArray getFees() { + return fees; + } + + public void setFees(FeesArray fees) { + this.fees = fees; + } + + public RequestTransaction geoCode(String geoCode) { + this.geoCode = geoCode; + return this; + } + + /** + * Indicates the geographic location from where the transaction was initiated. + * @return geoCode + **/ + @Schema(example = "37.423825,-122.082900", description = "Indicates the geographic location from where the transaction was initiated.") + + @Pattern(regexp="^(-?(90|(\\d|[1-8]\\d)(\\.\\d{1,6}){0,1}))\\,{1}(-?(180|(\\d|\\d\\d|1[0-7]\\d)(\\.\\d{1,6}){0,1}))$") @Size(max=256) public String getGeoCode() { + return geoCode; + } + + public void setGeoCode(String geoCode) { + this.geoCode = geoCode; + } + + public RequestTransaction internationalTransferInformation(InternationalTransferInformation internationalTransferInformation) { + this.internationalTransferInformation = internationalTransferInformation; + return this; + } + + /** + * Get internationalTransferInformation + * @return internationalTransferInformation + **/ + @Schema(description = "") + + @Valid + public InternationalTransferInformation getInternationalTransferInformation() { + return internationalTransferInformation; + } + + public void setInternationalTransferInformation(InternationalTransferInformation internationalTransferInformation) { + this.internationalTransferInformation = internationalTransferInformation; + } + + public RequestTransaction oneTimeCode(String oneTimeCode) { + this.oneTimeCode = oneTimeCode; + return this; + } + + /** + * A one-time code that can be supplied in the request or can be generated in the response depending upon the use case. An authorisation code can be supplied in this field for requests that have been pre-authorised. + * @return oneTimeCode + **/ + @Schema(description = "A one-time code that can be supplied in the request or can be generated in the response depending upon the use case. An authorisation code can be supplied in this field for requests that have been pre-authorised.") + + @Size(max=256) public String getOneTimeCode() { + return oneTimeCode; + } + + public void setOneTimeCode(String oneTimeCode) { + this.oneTimeCode = oneTimeCode; + } + + public RequestTransaction recipientKyc(Kyc recipientKyc) { + this.recipientKyc = recipientKyc; + return this; + } + + /** + * Get recipientKyc + * @return recipientKyc + **/ + @Schema(description = "") + + @Valid + public Kyc getRecipientKyc() { + return recipientKyc; + } + + public void setRecipientKyc(Kyc recipientKyc) { + this.recipientKyc = recipientKyc; + } + + public RequestTransaction senderKyc(Kyc senderKyc) { + this.senderKyc = senderKyc; + return this; + } + + /** + * Get senderKyc + * @return senderKyc + **/ + @Schema(description = "") + + @Valid + public Kyc getSenderKyc() { + return senderKyc; + } + + public void setSenderKyc(Kyc senderKyc) { + this.senderKyc = senderKyc; + } + + public RequestTransaction requestingOrganisation(RequestingOrganisation requestingOrganisation) { + this.requestingOrganisation = requestingOrganisation; + return this; + } + + /** + * Get requestingOrganisation + * @return requestingOrganisation + **/ + @Schema(description = "") + + @Valid + public RequestingOrganisation getRequestingOrganisation() { + return requestingOrganisation; + } + + public void setRequestingOrganisation(RequestingOrganisation requestingOrganisation) { + this.requestingOrganisation = requestingOrganisation; + } + + public RequestTransaction servicingIdentity(String servicingIdentity) { + this.servicingIdentity = servicingIdentity; + return this; + } + + /** + * The field is used to identify the servicing identity for transactions, e.g. till, POS ID, assistant ID. + * @return servicingIdentity + **/ + @Schema(description = "The field is used to identify the servicing identity for transactions, e.g. till, POS ID, assistant ID.") + + @Size(max=256) public String getServicingIdentity() { + return servicingIdentity; + } + + public void setServicingIdentity(String servicingIdentity) { + this.servicingIdentity = servicingIdentity; + } + + public RequestTransaction requestDate(OffsetDateTime requestDate) { + this.requestDate = requestDate; + return this; + } + + /** + * The date and time of the request as supplied by the client. + * @return requestDate + **/ + @Schema(description = "The date and time of the request as supplied by the client.") + + @Valid + public OffsetDateTime getRequestDate() { + return requestDate; + } + + public void setRequestDate(OffsetDateTime requestDate) { + this.requestDate = requestDate; + } + + public RequestTransaction customData(CustomDataArray customData) { + this.customData = customData; + return this; + } + + /** + * Get customData + * @return customData + **/ + @Schema(description = "") + + @Valid + public CustomDataArray getCustomData() { + return customData; + } + + public void setCustomData(CustomDataArray customData) { + this.customData = customData; + } + + public RequestTransaction metadata(MetadataArray metadata) { + this.metadata = metadata; + return this; + } + + /** + * Get metadata + * @return metadata + **/ + @Schema(description = "") + + @Valid + public MetadataArray getMetadata() { + return metadata; + } + + public void setMetadata(MetadataArray metadata) { + this.metadata = metadata; + } + + public RequestTransaction receivingLei(String receivingLei) { + this.receivingLei = receivingLei; + return this; + } + + /** + * Legal Entity Identifier of the organisation that is receiving the transaction. + * @return receivingLei + **/ + @Schema(description = "Legal Entity Identifier of the organisation that is receiving the transaction.") + + @Pattern(regexp="^[A-Z0-9]{4}00[A-Z0-9]{12}\\d{2}$") @Size(max=20) public String getReceivingLei() { + return receivingLei; + } + + public void setReceivingLei(String receivingLei) { + this.receivingLei = receivingLei; + } + + public RequestTransaction requestingLei(String requestingLei) { + this.requestingLei = requestingLei; + return this; + } + + /** + * Legal Entity Identifier of the organisation that is requesting the transaction. + * @return requestingLei + **/ + @Schema(description = "Legal Entity Identifier of the organisation that is requesting the transaction.") + + @Pattern(regexp="^[A-Z0-9]{4}00[A-Z0-9]{12}\\d{2}$") @Size(max=20) public String getRequestingLei() { + return requestingLei; + } + + public void setRequestingLei(String requestingLei) { + this.requestingLei = requestingLei; + } + + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + RequestTransaction requestTransaction = (RequestTransaction) o; + return Objects.equals(this.requestingOrganisationTransactionReference, requestTransaction.requestingOrganisationTransactionReference) && + Objects.equals(this.originalTransactionReference, requestTransaction.originalTransactionReference) && + Objects.equals(this.creditParty, requestTransaction.creditParty) && + Objects.equals(this.debitParty, requestTransaction.debitParty) && + Objects.equals(this.type, requestTransaction.type) && + Objects.equals(this.subType, requestTransaction.subType) && + Objects.equals(this.amount, requestTransaction.amount) && + Objects.equals(this.currency, requestTransaction.currency) && + Objects.equals(this.descriptionText, requestTransaction.descriptionText) && + Objects.equals(this.fees, requestTransaction.fees) && + Objects.equals(this.geoCode, requestTransaction.geoCode) && + Objects.equals(this.internationalTransferInformation, requestTransaction.internationalTransferInformation) && + Objects.equals(this.oneTimeCode, requestTransaction.oneTimeCode) && + Objects.equals(this.recipientKyc, requestTransaction.recipientKyc) && + Objects.equals(this.senderKyc, requestTransaction.senderKyc) && + Objects.equals(this.requestingOrganisation, requestTransaction.requestingOrganisation) && + Objects.equals(this.servicingIdentity, requestTransaction.servicingIdentity) && + Objects.equals(this.requestDate, requestTransaction.requestDate) && + Objects.equals(this.customData, requestTransaction.customData) && + Objects.equals(this.metadata, requestTransaction.metadata) && + Objects.equals(this.receivingLei, requestTransaction.receivingLei) && + Objects.equals(this.requestingLei, requestTransaction.requestingLei); + } + + @Override + public int hashCode() { + return Objects.hash(requestingOrganisationTransactionReference, originalTransactionReference, creditParty, debitParty, type, subType, amount, currency, descriptionText, fees, geoCode, internationalTransferInformation, oneTimeCode, recipientKyc, senderKyc, requestingOrganisation, servicingIdentity, requestDate, customData, metadata, receivingLei, requestingLei); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class RequestTransaction {\n"); + + sb.append(" requestingOrganisationTransactionReference: ").append(toIndentedString(requestingOrganisationTransactionReference)).append("\n"); + sb.append(" originalTransactionReference: ").append(toIndentedString(originalTransactionReference)).append("\n"); + sb.append(" creditParty: ").append(toIndentedString(creditParty)).append("\n"); + sb.append(" debitParty: ").append(toIndentedString(debitParty)).append("\n"); + sb.append(" type: ").append(toIndentedString(type)).append("\n"); + sb.append(" subType: ").append(toIndentedString(subType)).append("\n"); + sb.append(" amount: ").append(toIndentedString(amount)).append("\n"); + sb.append(" currency: ").append(toIndentedString(currency)).append("\n"); + sb.append(" descriptionText: ").append(toIndentedString(descriptionText)).append("\n"); + sb.append(" fees: ").append(toIndentedString(fees)).append("\n"); + sb.append(" geoCode: ").append(toIndentedString(geoCode)).append("\n"); + sb.append(" internationalTransferInformation: ").append(toIndentedString(internationalTransferInformation)).append("\n"); + sb.append(" oneTimeCode: ").append(toIndentedString(oneTimeCode)).append("\n"); + sb.append(" recipientKyc: ").append(toIndentedString(recipientKyc)).append("\n"); + sb.append(" senderKyc: ").append(toIndentedString(senderKyc)).append("\n"); + sb.append(" requestingOrganisation: ").append(toIndentedString(requestingOrganisation)).append("\n"); + sb.append(" servicingIdentity: ").append(toIndentedString(servicingIdentity)).append("\n"); + sb.append(" requestDate: ").append(toIndentedString(requestDate)).append("\n"); + sb.append(" customData: ").append(toIndentedString(customData)).append("\n"); + sb.append(" metadata: ").append(toIndentedString(metadata)).append("\n"); + sb.append(" receivingLei: ").append(toIndentedString(receivingLei)).append("\n"); + sb.append(" requestingLei: ").append(toIndentedString(requestingLei)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/RequestTransactionType.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/RequestTransactionType.java new file mode 100644 index 000000000..1376c5abe --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/RequestTransactionType.java @@ -0,0 +1,51 @@ +package org.mifos.connector.gsmastub.model; + +import org.springframework.validation.annotation.Validated; + +import java.util.Objects; + +/** + * RequestTransactionType + */ +@Validated +@javax.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.SpringCodegen", date = "2022-09-27T11:46:46.417Z[GMT]") + + +public class RequestTransactionType { + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + return true; + } + + @Override + public int hashCode() { + return Objects.hash(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class RequestTransactionType {\n"); + + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/RequestingOrganisation.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/RequestingOrganisation.java new file mode 100644 index 000000000..40a3ef217 --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/RequestingOrganisation.java @@ -0,0 +1,140 @@ +package org.mifos.connector.gsmastub.model; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonValue; +import io.swagger.v3.oas.annotations.media.Schema; +import org.springframework.validation.annotation.Validated; + +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; +import java.util.Objects; + +/** + * An object that details the originating organisation of the request. + */ +@Schema(description = "An object that details the originating organisation of the request.") +@Validated +@javax.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.SpringCodegen", date = "2022-09-27T11:46:46.417Z[GMT]") + + +public class RequestingOrganisation { + /** + * Identifies the identifier type of the requesting organisation. + */ + public enum RequestingOrganisationIdentifierTypeEnum { + LEI("lei"), + + SWIFTBIC("swiftbic"), + + ORGANISATIONID("organisationid"); + + private String value; + + RequestingOrganisationIdentifierTypeEnum(String value) { + this.value = value; + } + + @Override + @JsonValue + public String toString() { + return String.valueOf(value); + } + + @JsonCreator + public static RequestingOrganisationIdentifierTypeEnum fromValue(String text) { + for (RequestingOrganisationIdentifierTypeEnum b : RequestingOrganisationIdentifierTypeEnum.values()) { + if (String.valueOf(b.value).equals(text)) { + return b; + } + } + return null; + } + } + @JsonProperty("requestingOrganisationIdentifierType") + private RequestingOrganisationIdentifierTypeEnum requestingOrganisationIdentifierType = null; + + @JsonProperty("requestingOrganisationIdentifier") + private String requestingOrganisationIdentifier = null; + + public RequestingOrganisation requestingOrganisationIdentifierType(RequestingOrganisationIdentifierTypeEnum requestingOrganisationIdentifierType) { + this.requestingOrganisationIdentifierType = requestingOrganisationIdentifierType; + return this; + } + + /** + * Identifies the identifier type of the requesting organisation. + * @return requestingOrganisationIdentifierType + **/ + @Schema(required = true, description = "Identifies the identifier type of the requesting organisation.") + @NotNull + + public RequestingOrganisationIdentifierTypeEnum getRequestingOrganisationIdentifierType() { + return requestingOrganisationIdentifierType; + } + + public void setRequestingOrganisationIdentifierType(RequestingOrganisationIdentifierTypeEnum requestingOrganisationIdentifierType) { + this.requestingOrganisationIdentifierType = requestingOrganisationIdentifierType; + } + + public RequestingOrganisation requestingOrganisationIdentifier(String requestingOrganisationIdentifier) { + this.requestingOrganisationIdentifier = requestingOrganisationIdentifier; + return this; + } + + /** + * Contains the requesting organisation identifier. + * @return requestingOrganisationIdentifier + **/ + @Schema(required = true, description = "Contains the requesting organisation identifier.") + @NotNull + + @Size(min=1,max=256) public String getRequestingOrganisationIdentifier() { + return requestingOrganisationIdentifier; + } + + public void setRequestingOrganisationIdentifier(String requestingOrganisationIdentifier) { + this.requestingOrganisationIdentifier = requestingOrganisationIdentifier; + } + + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + RequestingOrganisation requestingOrganisation = (RequestingOrganisation) o; + return Objects.equals(this.requestingOrganisationIdentifierType, requestingOrganisation.requestingOrganisationIdentifierType) && + Objects.equals(this.requestingOrganisationIdentifier, requestingOrganisation.requestingOrganisationIdentifier); + } + + @Override + public int hashCode() { + return Objects.hash(requestingOrganisationIdentifierType, requestingOrganisationIdentifier); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class RequestingOrganisation {\n"); + + sb.append(" requestingOrganisationIdentifierType: ").append(toIndentedString(requestingOrganisationIdentifierType)).append("\n"); + sb.append(" requestingOrganisationIdentifier: ").append(toIndentedString(requestingOrganisationIdentifier)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/ResponseAccount.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/ResponseAccount.java new file mode 100644 index 000000000..c1fa26776 --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/ResponseAccount.java @@ -0,0 +1,482 @@ +package org.mifos.connector.gsmastub.model; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import org.springframework.validation.annotation.Validated; +import org.threeten.bp.OffsetDateTime; + +import javax.validation.Valid; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; +import java.util.Objects; + +/** + * ResponseAccount + */ +@Validated +@javax.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.SpringCodegen", date = "2022-09-27T11:46:46.417Z[GMT]") + + +public class ResponseAccount { + @JsonProperty("accountIdentifiers") + private AccountIdentifiersArray accountIdentifiers = null; + + @JsonProperty("identity") + private IdentityResponseArray identity = null; + + @JsonProperty("accountType") + private String accountType = null; + + @JsonProperty("accountStatus") + private AccountStatus accountStatus = null; + + @JsonProperty("accountSubStatus") + private String accountSubStatus = null; + + @JsonProperty("currentBalance") + private String currentBalance = null; + + @JsonProperty("availableBalance") + private String availableBalance = null; + + @JsonProperty("reservedBalance") + private String reservedBalance = null; + + @JsonProperty("unclearedBalance") + private String unclearedBalance = null; + + @JsonProperty("currency") + private Currency currency = null; + + @JsonProperty("fees") + private FeesArray fees = null; + + @JsonProperty("commissionEarned") + private CommissionEarnedArray commissionEarned = null; + + @JsonProperty("registeringEntity") + private String registeringEntity = null; + + @JsonProperty("creationDate") + private OffsetDateTime creationDate = null; + + @JsonProperty("modificationDate") + private OffsetDateTime modificationDate = null; + + @JsonProperty("requestDate") + private OffsetDateTime requestDate = null; + + @JsonProperty("customData") + private CustomDataArray customData = null; + + public ResponseAccount accountIdentifiers(AccountIdentifiersArray accountIdentifiers) { + this.accountIdentifiers = accountIdentifiers; + return this; + } + + /** + * Get accountIdentifiers + * @return accountIdentifiers + **/ + @Schema(required = true, description = "") + @NotNull + + @Valid + public AccountIdentifiersArray getAccountIdentifiers() { + return accountIdentifiers; + } + + public void setAccountIdentifiers(AccountIdentifiersArray accountIdentifiers) { + this.accountIdentifiers = accountIdentifiers; + } + + public ResponseAccount identity(IdentityResponseArray identity) { + this.identity = identity; + return this; + } + + /** + * Get identity + * @return identity + **/ + @Schema(required = true, description = "") + @NotNull + + @Valid + public IdentityResponseArray getIdentity() { + return identity; + } + + public void setIdentity(IdentityResponseArray identity) { + this.identity = identity; + } + + public ResponseAccount accountType(String accountType) { + this.accountType = accountType; + return this; + } + + /** + * A non-harmonised field that indicates the type of the account. + * @return accountType + **/ + @Schema(description = "A non-harmonised field that indicates the type of the account.") + + @Size(max=256) public String getAccountType() { + return accountType; + } + + public void setAccountType(String accountType) { + this.accountType = accountType; + } + + public ResponseAccount accountStatus(AccountStatus accountStatus) { + this.accountStatus = accountStatus; + return this; + } + + /** + * Get accountStatus + * @return accountStatus + **/ + @Schema(required = true, description = "") + @NotNull + + @Valid + @Size(min=1,max=256) public AccountStatus getAccountStatus() { + return accountStatus; + } + + public void setAccountStatus(AccountStatus accountStatus) { + this.accountStatus = accountStatus; + } + + public ResponseAccount accountSubStatus(String accountSubStatus) { + this.accountSubStatus = accountSubStatus; + return this; + } + + /** + * Field can be used to return a provider-specific status for the account. + * @return accountSubStatus + **/ + @Schema(description = "Field can be used to return a provider-specific status for the account.") + + @Size(max=256) public String getAccountSubStatus() { + return accountSubStatus; + } + + public void setAccountSubStatus(String accountSubStatus) { + this.accountSubStatus = accountSubStatus; + } + + public ResponseAccount currentBalance(String currentBalance) { + this.currentBalance = currentBalance; + return this; + } + + /** + * Get currentBalance + * @return currentBalance + **/ + @Schema(description = "") + + @Valid + public String getCurrentBalance() { + return currentBalance; + } + + public void setCurrentBalance(String currentBalance) { + this.currentBalance = currentBalance; + } + + public ResponseAccount availableBalance(String availableBalance) { + this.availableBalance = availableBalance; + return this; + } + + /** + * Get availableBalance + * @return availableBalance + **/ + @Schema(description = "") + + @Valid + public String getAvailableBalance() { + return availableBalance; + } + + public void setAvailableBalance(String availableBalance) { + this.availableBalance = availableBalance; + } + + public ResponseAccount reservedBalance(String reservedBalance) { + this.reservedBalance = reservedBalance; + return this; + } + + /** + * Get reservedBalance + * @return reservedBalance + **/ + @Schema(description = "") + + @Valid + public String getReservedBalance() { + return reservedBalance; + } + + public void setReservedBalance(String reservedBalance) { + this.reservedBalance = reservedBalance; + } + + public ResponseAccount unclearedBalance(String unclearedBalance) { + this.unclearedBalance = unclearedBalance; + return this; + } + + /** + * Get unclearedBalance + * @return unclearedBalance + **/ + @Schema(description = "") + + @Valid + public String getUnclearedBalance() { + return unclearedBalance; + } + + public void setUnclearedBalance(String unclearedBalance) { + this.unclearedBalance = unclearedBalance; + } + + public ResponseAccount currency(Currency currency) { + this.currency = currency; + return this; + } + + /** + * Get currency + * @return currency + **/ + @Schema(description = "") + + @Valid + public Currency getCurrency() { + return currency; + } + + public void setCurrency(Currency currency) { + this.currency = currency; + } + + public ResponseAccount fees(FeesArray fees) { + this.fees = fees; + return this; + } + + /** + * Get fees + * @return fees + **/ + @Schema(description = "") + + @Valid + public FeesArray getFees() { + return fees; + } + + public void setFees(FeesArray fees) { + this.fees = fees; + } + + public ResponseAccount commissionEarned(CommissionEarnedArray commissionEarned) { + this.commissionEarned = commissionEarned; + return this; + } + + /** + * Get commissionEarned + * @return commissionEarned + **/ + @Schema(description = "") + + @Valid + public CommissionEarnedArray getCommissionEarned() { + return commissionEarned; + } + + public void setCommissionEarned(CommissionEarnedArray commissionEarned) { + this.commissionEarned = commissionEarned; + } + + public ResponseAccount registeringEntity(String registeringEntity) { + this.registeringEntity = registeringEntity; + return this; + } + + /** + * The entity that registered the account, for example, a mobile money agent. + * @return registeringEntity + **/ + @Schema(description = "The entity that registered the account, for example, a mobile money agent.") + + @Size(max=256) public String getRegisteringEntity() { + return registeringEntity; + } + + public void setRegisteringEntity(String registeringEntity) { + this.registeringEntity = registeringEntity; + } + + public ResponseAccount creationDate(OffsetDateTime creationDate) { + this.creationDate = creationDate; + return this; + } + + /** + * Date and time when the object was created by the API Provider. + * @return creationDate + **/ + @Schema(description = "Date and time when the object was created by the API Provider.") + + @Valid + public OffsetDateTime getCreationDate() { + return creationDate; + } + + public void setCreationDate(OffsetDateTime creationDate) { + this.creationDate = creationDate; + } + + public ResponseAccount modificationDate(OffsetDateTime modificationDate) { + this.modificationDate = modificationDate; + return this; + } + + /** + * Date and time when the object was modified by the API Provider. + * @return modificationDate + **/ + @Schema(description = "Date and time when the object was modified by the API Provider.") + + @Valid + public OffsetDateTime getModificationDate() { + return modificationDate; + } + + public void setModificationDate(OffsetDateTime modificationDate) { + this.modificationDate = modificationDate; + } + + public ResponseAccount requestDate(OffsetDateTime requestDate) { + this.requestDate = requestDate; + return this; + } + + /** + * The date and time of the request as supplied by the client. + * @return requestDate + **/ + @Schema(description = "The date and time of the request as supplied by the client.") + + @Valid + public OffsetDateTime getRequestDate() { + return requestDate; + } + + public void setRequestDate(OffsetDateTime requestDate) { + this.requestDate = requestDate; + } + + public ResponseAccount customData(CustomDataArray customData) { + this.customData = customData; + return this; + } + + /** + * Get customData + * @return customData + **/ + @Schema(description = "") + + @Valid + public CustomDataArray getCustomData() { + return customData; + } + + public void setCustomData(CustomDataArray customData) { + this.customData = customData; + } + + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + ResponseAccount responseAccount = (ResponseAccount) o; + return Objects.equals(this.accountIdentifiers, responseAccount.accountIdentifiers) && + Objects.equals(this.identity, responseAccount.identity) && + Objects.equals(this.accountType, responseAccount.accountType) && + Objects.equals(this.accountStatus, responseAccount.accountStatus) && + Objects.equals(this.accountSubStatus, responseAccount.accountSubStatus) && + Objects.equals(this.currentBalance, responseAccount.currentBalance) && + Objects.equals(this.availableBalance, responseAccount.availableBalance) && + Objects.equals(this.reservedBalance, responseAccount.reservedBalance) && + Objects.equals(this.unclearedBalance, responseAccount.unclearedBalance) && + Objects.equals(this.currency, responseAccount.currency) && + Objects.equals(this.fees, responseAccount.fees) && + Objects.equals(this.commissionEarned, responseAccount.commissionEarned) && + Objects.equals(this.registeringEntity, responseAccount.registeringEntity) && + Objects.equals(this.creationDate, responseAccount.creationDate) && + Objects.equals(this.modificationDate, responseAccount.modificationDate) && + Objects.equals(this.requestDate, responseAccount.requestDate) && + Objects.equals(this.customData, responseAccount.customData); + } + + @Override + public int hashCode() { + return Objects.hash(accountIdentifiers, identity, accountType, accountStatus, accountSubStatus, currentBalance, availableBalance, reservedBalance, unclearedBalance, currency, fees, commissionEarned, registeringEntity, creationDate, modificationDate, requestDate, customData); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class ResponseAccount {\n"); + + sb.append(" accountIdentifiers: ").append(toIndentedString(accountIdentifiers)).append("\n"); + sb.append(" identity: ").append(toIndentedString(identity)).append("\n"); + sb.append(" accountType: ").append(toIndentedString(accountType)).append("\n"); + sb.append(" accountStatus: ").append(toIndentedString(accountStatus)).append("\n"); + sb.append(" accountSubStatus: ").append(toIndentedString(accountSubStatus)).append("\n"); + sb.append(" currentBalance: ").append(toIndentedString(currentBalance)).append("\n"); + sb.append(" availableBalance: ").append(toIndentedString(availableBalance)).append("\n"); + sb.append(" reservedBalance: ").append(toIndentedString(reservedBalance)).append("\n"); + sb.append(" unclearedBalance: ").append(toIndentedString(unclearedBalance)).append("\n"); + sb.append(" currency: ").append(toIndentedString(currency)).append("\n"); + sb.append(" fees: ").append(toIndentedString(fees)).append("\n"); + sb.append(" commissionEarned: ").append(toIndentedString(commissionEarned)).append("\n"); + sb.append(" registeringEntity: ").append(toIndentedString(registeringEntity)).append("\n"); + sb.append(" creationDate: ").append(toIndentedString(creationDate)).append("\n"); + sb.append(" modificationDate: ").append(toIndentedString(modificationDate)).append("\n"); + sb.append(" requestDate: ").append(toIndentedString(requestDate)).append("\n"); + sb.append(" customData: ").append(toIndentedString(customData)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/ResponseAccountBalance.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/ResponseAccountBalance.java new file mode 100644 index 000000000..327cbec32 --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/ResponseAccountBalance.java @@ -0,0 +1,205 @@ +package org.mifos.connector.gsmastub.model; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import org.springframework.validation.annotation.Validated; + +import javax.validation.Valid; +import javax.validation.constraints.Size; +import java.util.Objects; + +/** + * ResponseAccountBalance + */ +@Validated +@javax.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.SpringCodegen", date = "2022-09-27T11:46:46.417Z[GMT]") + + +public class ResponseAccountBalance { + @JsonProperty("accountStatus") + private AccountStatus accountStatus = null; + + @JsonProperty("currentBalance") + private String currentBalance = null; + + @JsonProperty("availableBalance") + private String availableBalance = null; + + @JsonProperty("reservedBalance") + private String reservedBalance = null; + + @JsonProperty("unclearedBalance") + private String unclearedBalance = null; + + @JsonProperty("currency") + private Currency currency = null; + + public ResponseAccountBalance accountStatus(AccountStatus accountStatus) { + this.accountStatus = accountStatus; + return this; + } + + /** + * Get accountStatus + * @return accountStatus + **/ + @Schema(description = "") + + @Valid + @Size(min=1,max=256) public AccountStatus getAccountStatus() { + return accountStatus; + } + + public void setAccountStatus(AccountStatus accountStatus) { + this.accountStatus = accountStatus; + } + + public ResponseAccountBalance currentBalance(String currentBalance) { + this.currentBalance = currentBalance; + return this; + } + + /** + * Get currentBalance + * @return currentBalance + **/ + @Schema(description = "") + + @Valid + public String getCurrentBalance() { + return currentBalance; + } + + public void setCurrentBalance(String currentBalance) { + this.currentBalance = currentBalance; + } + + public ResponseAccountBalance availableBalance(String availableBalance) { + this.availableBalance = availableBalance; + return this; + } + + /** + * Get availableBalance + * @return availableBalance + **/ + @Schema(description = "") + + @Valid + public String getAvailableBalance() { + return availableBalance; + } + + public void setAvailableBalance(String availableBalance) { + this.availableBalance = availableBalance; + } + + public ResponseAccountBalance reservedBalance(String reservedBalance) { + this.reservedBalance = reservedBalance; + return this; + } + + /** + * Get reservedBalance + * @return reservedBalance + **/ + @Schema(description = "") + + @Valid + public String getReservedBalance() { + return reservedBalance; + } + + public void setReservedBalance(String reservedBalance) { + this.reservedBalance = reservedBalance; + } + + public ResponseAccountBalance unclearedBalance(String unclearedBalance) { + this.unclearedBalance = unclearedBalance; + return this; + } + + /** + * Get unclearedBalance + * @return unclearedBalance + **/ + @Schema(description = "") + + @Valid + public String getUnclearedBalance() { + return unclearedBalance; + } + + public void setUnclearedBalance(String unclearedBalance) { + this.unclearedBalance = unclearedBalance; + } + + public ResponseAccountBalance currency(Currency currency) { + this.currency = currency; + return this; + } + + /** + * Get currency + * @return currency + **/ + @Schema(description = "") + + @Valid + public Currency getCurrency() { + return currency; + } + + public void setCurrency(Currency currency) { + this.currency = currency; + } + + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + ResponseAccountBalance responseAccountBalance = (ResponseAccountBalance) o; + return Objects.equals(this.accountStatus, responseAccountBalance.accountStatus) && + Objects.equals(this.currentBalance, responseAccountBalance.currentBalance) && + Objects.equals(this.availableBalance, responseAccountBalance.availableBalance) && + Objects.equals(this.reservedBalance, responseAccountBalance.reservedBalance) && + Objects.equals(this.unclearedBalance, responseAccountBalance.unclearedBalance) && + Objects.equals(this.currency, responseAccountBalance.currency); + } + + @Override + public int hashCode() { + return Objects.hash(accountStatus, currentBalance, availableBalance, reservedBalance, unclearedBalance, currency); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class ResponseAccountBalance {\n"); + + sb.append(" accountStatus: ").append(toIndentedString(accountStatus)).append("\n"); + sb.append(" currentBalance: ").append(toIndentedString(currentBalance)).append("\n"); + sb.append(" availableBalance: ").append(toIndentedString(availableBalance)).append("\n"); + sb.append(" reservedBalance: ").append(toIndentedString(reservedBalance)).append("\n"); + sb.append(" unclearedBalance: ").append(toIndentedString(unclearedBalance)).append("\n"); + sb.append(" currency: ").append(toIndentedString(currency)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/ResponseAccountName.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/ResponseAccountName.java new file mode 100644 index 000000000..2147d3fc2 --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/ResponseAccountName.java @@ -0,0 +1,105 @@ +package org.mifos.connector.gsmastub.model; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import org.springframework.validation.annotation.Validated; + +import javax.validation.Valid; +import javax.validation.constraints.Pattern; +import javax.validation.constraints.Size; +import java.util.Objects; + +/** + * ResponseAccountName + */ +@Validated +@javax.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.SpringCodegen", date = "2022-09-27T11:46:46.417Z[GMT]") + + +public class ResponseAccountName { + @JsonProperty("name") + private SubjectName name = null; + + @JsonProperty("lei") + private String lei = null; + + public ResponseAccountName name(SubjectName name) { + this.name = name; + return this; + } + + /** + * Get name + * @return name + **/ + @Schema(description = "") + + @Valid + public SubjectName getName() { + return name; + } + + public void setName(SubjectName name) { + this.name = name; + } + + public ResponseAccountName lei(String lei) { + this.lei = lei; + return this; + } + + /** + * Legal Entity Identifier. + * @return lei + **/ + @Schema(example = "5493000IBP32UQZ0KL24", description = "Legal Entity Identifier.") + + @Pattern(regexp="^[A-Z0-9]{4}00[A-Z0-9]{12}\\d{2}$") @Size(max=20) public String getLei() { + return lei; + } + + public void setLei(String lei) { + this.lei = lei; + } + + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + ResponseAccountName responseAccountName = (ResponseAccountName) o; + return Objects.equals(this.name, responseAccountName.name) && + Objects.equals(this.lei, responseAccountName.lei); + } + + @Override + public int hashCode() { + return Objects.hash(name, lei); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class ResponseAccountName {\n"); + + sb.append(" name: ").append(toIndentedString(name)).append("\n"); + sb.append(" lei: ").append(toIndentedString(lei)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/ResponseAccountStatus.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/ResponseAccountStatus.java new file mode 100644 index 000000000..d1ac11180 --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/ResponseAccountStatus.java @@ -0,0 +1,131 @@ +package org.mifos.connector.gsmastub.model; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import org.springframework.validation.annotation.Validated; + +import javax.validation.Valid; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Pattern; +import javax.validation.constraints.Size; +import java.util.Objects; + +/** + * ResponseAccountStatus + */ +@Validated +@javax.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.SpringCodegen", date = "2022-09-27T11:46:46.417Z[GMT]") + + +public class ResponseAccountStatus { + @JsonProperty("accountStatus") + private AccountStatus accountStatus = null; + + @JsonProperty("subStatus") + private String subStatus = null; + + @JsonProperty("lei") + private String lei = null; + + public ResponseAccountStatus accountStatus(AccountStatus accountStatus) { + this.accountStatus = accountStatus; + return this; + } + + /** + * Get accountStatus + * @return accountStatus + **/ + @Schema(required = true, description = "") + @NotNull + + @Valid + @Size(min=1,max=256) public AccountStatus getAccountStatus() { + return accountStatus; + } + + public void setAccountStatus(AccountStatus accountStatus) { + this.accountStatus = accountStatus; + } + + public ResponseAccountStatus subStatus(String subStatus) { + this.subStatus = subStatus; + return this; + } + + /** + * Can be used to return a provider-specific status for the account. + * @return subStatus + **/ + @Schema(description = "Can be used to return a provider-specific status for the account.") + + @Size(max=256) public String getSubStatus() { + return subStatus; + } + + public void setSubStatus(String subStatus) { + this.subStatus = subStatus; + } + + public ResponseAccountStatus lei(String lei) { + this.lei = lei; + return this; + } + + /** + * Legal Entity Identifier. + * @return lei + **/ + @Schema(example = "5493000IBP32UQZ0KL24", description = "Legal Entity Identifier.") + + @Pattern(regexp="^[A-Z0-9]{4}00[A-Z0-9]{12}\\d{2}$") @Size(max=20) public String getLei() { + return lei; + } + + public void setLei(String lei) { + this.lei = lei; + } + + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + ResponseAccountStatus responseAccountStatus = (ResponseAccountStatus) o; + return Objects.equals(this.accountStatus, responseAccountStatus.accountStatus) && + Objects.equals(this.subStatus, responseAccountStatus.subStatus) && + Objects.equals(this.lei, responseAccountStatus.lei); + } + + @Override + public int hashCode() { + return Objects.hash(accountStatus, subStatus, lei); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class ResponseAccountStatus {\n"); + + sb.append(" accountStatus: ").append(toIndentedString(accountStatus)).append("\n"); + sb.append(" subStatus: ").append(toIndentedString(subStatus)).append("\n"); + sb.append(" lei: ").append(toIndentedString(lei)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/ResponseAuthorisationCode.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/ResponseAuthorisationCode.java new file mode 100644 index 000000000..e61646ff7 --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/ResponseAuthorisationCode.java @@ -0,0 +1,460 @@ +package org.mifos.connector.gsmastub.model; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import org.springframework.validation.annotation.Validated; +import org.threeten.bp.OffsetDateTime; + +import javax.validation.Valid; +import javax.validation.constraints.DecimalMin; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Pattern; +import javax.validation.constraints.Size; +import java.math.BigDecimal; +import java.util.Objects; + +/** + * ResponseAuthorisationCode + */ +@Validated +@javax.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.SpringCodegen", date = "2022-09-27T11:46:46.417Z[GMT]") + + +public class ResponseAuthorisationCode { + @JsonProperty("authorisationCode") + private String authorisationCode = null; + + @JsonProperty("codeState") + private CodeState codeState = null; + + @JsonProperty("amount") + private String amount = null; + + @JsonProperty("currency") + private Currency currency = null; + + @JsonProperty("amountType") + private AmountType amountType = null; + + @JsonProperty("codeLifetime") + private BigDecimal codeLifetime = null; + + @JsonProperty("holdFundsIndicator") + private Boolean holdFundsIndicator = null; + + @JsonProperty("redemptionAccountIdentifiers") + private RedemptionAccountIdentifiers redemptionAccountIdentifiers = null; + + @JsonProperty("redemptionChannels") + private RedemptionChannels redemptionChannels = null; + + @JsonProperty("redemptionTransactionTypes") + private RedemptionTransactionTypes redemptionTransactionTypes = null; + + @JsonProperty("requestingOrganisation") + private RequestingOrganisation requestingOrganisation = null; + + @JsonProperty("creationDate") + private OffsetDateTime creationDate = null; + + @JsonProperty("modificationDate") + private OffsetDateTime modificationDate = null; + + @JsonProperty("requestDate") + private OffsetDateTime requestDate = null; + + @JsonProperty("customData") + private CustomDataArray customData = null; + + @JsonProperty("metadata") + private MetadataArray metadata = null; + + public ResponseAuthorisationCode authorisationCode(String authorisationCode) { + this.authorisationCode = authorisationCode; + return this; + } + + /** + * The code that will be presented to the other party for redemption. + * @return authorisationCode + **/ + @Schema(required = true, description = "The code that will be presented to the other party for redemption.") + @NotNull + + @Size(max=256) public String getAuthorisationCode() { + return authorisationCode; + } + + public void setAuthorisationCode(String authorisationCode) { + this.authorisationCode = authorisationCode; + } + + public ResponseAuthorisationCode codeState(CodeState codeState) { + this.codeState = codeState; + return this; + } + + /** + * Get codeState + * @return codeState + **/ + @Schema(required = true, description = "") + @NotNull + + @Valid + public CodeState getCodeState() { + return codeState; + } + + public void setCodeState(CodeState codeState) { + this.codeState = codeState; + } + + public ResponseAuthorisationCode amount(String amount) { + this.amount = amount; + return this; + } + + /** + * Get amount + * @return amount + **/ + @Schema(example = "15.21", description = "") + + @Pattern(regexp="^([0]|([1-9][0-9]{0,17}))([.][0-9]{0,3}[0-9])?$") @Size(min=1,max=23) public String getAmount() { + return amount; + } + + public void setAmount(String amount) { + this.amount = amount; + } + + public ResponseAuthorisationCode currency(Currency currency) { + this.currency = currency; + return this; + } + + /** + * Get currency + * @return currency + **/ + @Schema(description = "") + + @Valid + public Currency getCurrency() { + return currency; + } + + public void setCurrency(Currency currency) { + this.currency = currency; + } + + public ResponseAuthorisationCode amountType(AmountType amountType) { + this.amountType = amountType; + return this; + } + + /** + * Get amountType + * @return amountType + **/ + @Schema(description = "") + + @Valid + public AmountType getAmountType() { + return amountType; + } + + public void setAmountType(AmountType amountType) { + this.amountType = amountType; + } + + public ResponseAuthorisationCode codeLifetime(BigDecimal codeLifetime) { + this.codeLifetime = codeLifetime; + return this; + } + + /** + * Indicates the expiry time in seconds of the code. + * minimum: 1 + * @return codeLifetime + **/ + @Schema(example = "600", description = "Indicates the expiry time in seconds of the code.") + + @Valid + @DecimalMin("1") public BigDecimal getCodeLifetime() { + return codeLifetime; + } + + public void setCodeLifetime(BigDecimal codeLifetime) { + this.codeLifetime = codeLifetime; + } + + public ResponseAuthorisationCode holdFundsIndicator(Boolean holdFundsIndicator) { + this.holdFundsIndicator = holdFundsIndicator; + return this; + } + + /** + * Indicates whether funds should be reserved against the payers account where the payer is the requestor. + * @return holdFundsIndicator + **/ + @Schema(description = "Indicates whether funds should be reserved against the payers account where the payer is the requestor.") + + public Boolean isHoldFundsIndicator() { + return holdFundsIndicator; + } + + public void setHoldFundsIndicator(Boolean holdFundsIndicator) { + this.holdFundsIndicator = holdFundsIndicator; + } + + public ResponseAuthorisationCode redemptionAccountIdentifiers(RedemptionAccountIdentifiers redemptionAccountIdentifiers) { + this.redemptionAccountIdentifiers = redemptionAccountIdentifiers; + return this; + } + + /** + * Get redemptionAccountIdentifiers + * @return redemptionAccountIdentifiers + **/ + @Schema(description = "") + + @Valid + public RedemptionAccountIdentifiers getRedemptionAccountIdentifiers() { + return redemptionAccountIdentifiers; + } + + public void setRedemptionAccountIdentifiers(RedemptionAccountIdentifiers redemptionAccountIdentifiers) { + this.redemptionAccountIdentifiers = redemptionAccountIdentifiers; + } + + public ResponseAuthorisationCode redemptionChannels(RedemptionChannels redemptionChannels) { + this.redemptionChannels = redemptionChannels; + return this; + } + + /** + * Get redemptionChannels + * @return redemptionChannels + **/ + @Schema(description = "") + + @Valid + public RedemptionChannels getRedemptionChannels() { + return redemptionChannels; + } + + public void setRedemptionChannels(RedemptionChannels redemptionChannels) { + this.redemptionChannels = redemptionChannels; + } + + public ResponseAuthorisationCode redemptionTransactionTypes(RedemptionTransactionTypes redemptionTransactionTypes) { + this.redemptionTransactionTypes = redemptionTransactionTypes; + return this; + } + + /** + * Get redemptionTransactionTypes + * @return redemptionTransactionTypes + **/ + @Schema(description = "") + + @Valid + public RedemptionTransactionTypes getRedemptionTransactionTypes() { + return redemptionTransactionTypes; + } + + public void setRedemptionTransactionTypes(RedemptionTransactionTypes redemptionTransactionTypes) { + this.redemptionTransactionTypes = redemptionTransactionTypes; + } + + public ResponseAuthorisationCode requestingOrganisation(RequestingOrganisation requestingOrganisation) { + this.requestingOrganisation = requestingOrganisation; + return this; + } + + /** + * Get requestingOrganisation + * @return requestingOrganisation + **/ + @Schema(description = "") + + @Valid + public RequestingOrganisation getRequestingOrganisation() { + return requestingOrganisation; + } + + public void setRequestingOrganisation(RequestingOrganisation requestingOrganisation) { + this.requestingOrganisation = requestingOrganisation; + } + + public ResponseAuthorisationCode creationDate(OffsetDateTime creationDate) { + this.creationDate = creationDate; + return this; + } + + /** + * Date and time when the object was created by the API Provider. + * @return creationDate + **/ + @Schema(description = "Date and time when the object was created by the API Provider.") + + @Valid + public OffsetDateTime getCreationDate() { + return creationDate; + } + + public void setCreationDate(OffsetDateTime creationDate) { + this.creationDate = creationDate; + } + + public ResponseAuthorisationCode modificationDate(OffsetDateTime modificationDate) { + this.modificationDate = modificationDate; + return this; + } + + /** + * Date and time when the object was modified by the API Provider. + * @return modificationDate + **/ + @Schema(description = "Date and time when the object was modified by the API Provider.") + + @Valid + public OffsetDateTime getModificationDate() { + return modificationDate; + } + + public void setModificationDate(OffsetDateTime modificationDate) { + this.modificationDate = modificationDate; + } + + public ResponseAuthorisationCode requestDate(OffsetDateTime requestDate) { + this.requestDate = requestDate; + return this; + } + + /** + * The date and time of the request as supplied by the client. + * @return requestDate + **/ + @Schema(description = "The date and time of the request as supplied by the client.") + + @Valid + public OffsetDateTime getRequestDate() { + return requestDate; + } + + public void setRequestDate(OffsetDateTime requestDate) { + this.requestDate = requestDate; + } + + public ResponseAuthorisationCode customData(CustomDataArray customData) { + this.customData = customData; + return this; + } + + /** + * Get customData + * @return customData + **/ + @Schema(description = "") + + @Valid + public CustomDataArray getCustomData() { + return customData; + } + + public void setCustomData(CustomDataArray customData) { + this.customData = customData; + } + + public ResponseAuthorisationCode metadata(MetadataArray metadata) { + this.metadata = metadata; + return this; + } + + /** + * Get metadata + * @return metadata + **/ + @Schema(description = "") + + @Valid + public MetadataArray getMetadata() { + return metadata; + } + + public void setMetadata(MetadataArray metadata) { + this.metadata = metadata; + } + + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + ResponseAuthorisationCode responseAuthorisationCode = (ResponseAuthorisationCode) o; + return Objects.equals(this.authorisationCode, responseAuthorisationCode.authorisationCode) && + Objects.equals(this.codeState, responseAuthorisationCode.codeState) && + Objects.equals(this.amount, responseAuthorisationCode.amount) && + Objects.equals(this.currency, responseAuthorisationCode.currency) && + Objects.equals(this.amountType, responseAuthorisationCode.amountType) && + Objects.equals(this.codeLifetime, responseAuthorisationCode.codeLifetime) && + Objects.equals(this.holdFundsIndicator, responseAuthorisationCode.holdFundsIndicator) && + Objects.equals(this.redemptionAccountIdentifiers, responseAuthorisationCode.redemptionAccountIdentifiers) && + Objects.equals(this.redemptionChannels, responseAuthorisationCode.redemptionChannels) && + Objects.equals(this.redemptionTransactionTypes, responseAuthorisationCode.redemptionTransactionTypes) && + Objects.equals(this.requestingOrganisation, responseAuthorisationCode.requestingOrganisation) && + Objects.equals(this.creationDate, responseAuthorisationCode.creationDate) && + Objects.equals(this.modificationDate, responseAuthorisationCode.modificationDate) && + Objects.equals(this.requestDate, responseAuthorisationCode.requestDate) && + Objects.equals(this.customData, responseAuthorisationCode.customData) && + Objects.equals(this.metadata, responseAuthorisationCode.metadata); + } + + @Override + public int hashCode() { + return Objects.hash(authorisationCode, codeState, amount, currency, amountType, codeLifetime, holdFundsIndicator, redemptionAccountIdentifiers, redemptionChannels, redemptionTransactionTypes, requestingOrganisation, creationDate, modificationDate, requestDate, customData, metadata); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class ResponseAuthorisationCode {\n"); + + sb.append(" authorisationCode: ").append(toIndentedString(authorisationCode)).append("\n"); + sb.append(" codeState: ").append(toIndentedString(codeState)).append("\n"); + sb.append(" amount: ").append(toIndentedString(amount)).append("\n"); + sb.append(" currency: ").append(toIndentedString(currency)).append("\n"); + sb.append(" amountType: ").append(toIndentedString(amountType)).append("\n"); + sb.append(" codeLifetime: ").append(toIndentedString(codeLifetime)).append("\n"); + sb.append(" holdFundsIndicator: ").append(toIndentedString(holdFundsIndicator)).append("\n"); + sb.append(" redemptionAccountIdentifiers: ").append(toIndentedString(redemptionAccountIdentifiers)).append("\n"); + sb.append(" redemptionChannels: ").append(toIndentedString(redemptionChannels)).append("\n"); + sb.append(" redemptionTransactionTypes: ").append(toIndentedString(redemptionTransactionTypes)).append("\n"); + sb.append(" requestingOrganisation: ").append(toIndentedString(requestingOrganisation)).append("\n"); + sb.append(" creationDate: ").append(toIndentedString(creationDate)).append("\n"); + sb.append(" modificationDate: ").append(toIndentedString(modificationDate)).append("\n"); + sb.append(" requestDate: ").append(toIndentedString(requestDate)).append("\n"); + sb.append(" customData: ").append(toIndentedString(customData)).append("\n"); + sb.append(" metadata: ").append(toIndentedString(metadata)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/ResponseBatchTransaction.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/ResponseBatchTransaction.java new file mode 100644 index 000000000..3be46318c --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/ResponseBatchTransaction.java @@ -0,0 +1,487 @@ +package org.mifos.connector.gsmastub.model; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import org.springframework.validation.annotation.Validated; +import org.threeten.bp.OffsetDateTime; + +import javax.validation.Valid; +import javax.validation.constraints.DecimalMin; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; +import java.math.BigDecimal; +import java.util.Objects; + +/** + * ResponseBatchTransaction + */ +@Validated +@javax.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.SpringCodegen", date = "2022-09-27T11:46:46.417Z[GMT]") + + +public class ResponseBatchTransaction { + @JsonProperty("batchId") + private String batchId = null; + + @JsonProperty("batchStatus") + private BatchStatus batchStatus = null; + + @JsonProperty("approvalDate") + private OffsetDateTime approvalDate = null; + + @JsonProperty("completionDate") + private OffsetDateTime completionDate = null; + + @JsonProperty("batchTitle") + private String batchTitle = null; + + @JsonProperty("batchdescription") + private String batchdescription = null; + + @JsonProperty("processingFlag") + private Boolean processingFlag = null; + + @JsonProperty("completedCount") + private BigDecimal completedCount = null; + + @JsonProperty("rejectionCount") + private BigDecimal rejectionCount = null; + + @JsonProperty("parsingSuccessCount") + private BigDecimal parsingSuccessCount = null; + + @JsonProperty("requestingOrganisation") + private RequestingOrganisation requestingOrganisation = null; + + @JsonProperty("scheduledStartDate") + private OffsetDateTime scheduledStartDate = null; + + @JsonProperty("creationDate") + private OffsetDateTime creationDate = null; + + @JsonProperty("modificationDate") + private OffsetDateTime modificationDate = null; + + @JsonProperty("requestDate") + private OffsetDateTime requestDate = null; + + @JsonProperty("customData") + private CustomDataArray customData = null; + + @JsonProperty("completedDate") + private OffsetDateTime completedDate = null; + + public ResponseBatchTransaction batchId(String batchId) { + this.batchId = batchId; + return this; + } + + /** + * Identifier for the Batch that is assigned by the API provider. This ID is used by the client on subsequent GET or PATCH methods. + * @return batchId + **/ + @Schema(required = true, description = "Identifier for the Batch that is assigned by the API provider. This ID is used by the client on subsequent GET or PATCH methods.") + @NotNull + + @Size(min=1,max=256) public String getBatchId() { + return batchId; + } + + public void setBatchId(String batchId) { + this.batchId = batchId; + } + + public ResponseBatchTransaction batchStatus(BatchStatus batchStatus) { + this.batchStatus = batchStatus; + return this; + } + + /** + * Get batchStatus + * @return batchStatus + **/ + @Schema(required = true, description = "") + @NotNull + + @Valid + public BatchStatus getBatchStatus() { + return batchStatus; + } + + public void setBatchStatus(BatchStatus batchStatus) { + this.batchStatus = batchStatus; + } + + public ResponseBatchTransaction approvalDate(OffsetDateTime approvalDate) { + this.approvalDate = approvalDate; + return this; + } + + /** + * Indicates when the batch was approved as recorded by the API. + * @return approvalDate + **/ + @Schema(required = true, description = "Indicates when the batch was approved as recorded by the API.") + @NotNull + + @Valid + public OffsetDateTime getApprovalDate() { + return approvalDate; + } + + public void setApprovalDate(OffsetDateTime approvalDate) { + this.approvalDate = approvalDate; + } + + public ResponseBatchTransaction completionDate(OffsetDateTime completionDate) { + this.completionDate = completionDate; + return this; + } + + /** + * Indicates when the batch was completed as recorded by the API. + * @return completionDate + **/ + @Schema(required = true, description = "Indicates when the batch was completed as recorded by the API.") + @NotNull + + @Valid + public OffsetDateTime getCompletionDate() { + return completionDate; + } + + public void setCompletionDate(OffsetDateTime completionDate) { + this.completionDate = completionDate; + } + + public ResponseBatchTransaction batchTitle(String batchTitle) { + this.batchTitle = batchTitle; + return this; + } + + /** + * Client-provided title for the batch. + * @return batchTitle + **/ + @Schema(description = "Client-provided title for the batch.") + + @Size(max=256) public String getBatchTitle() { + return batchTitle; + } + + public void setBatchTitle(String batchTitle) { + this.batchTitle = batchTitle; + } + + public ResponseBatchTransaction batchdescription(String batchdescription) { + this.batchdescription = batchdescription; + return this; + } + + /** + * Client-provided description of the batch. + * @return batchdescription + **/ + @Schema(description = "Client-provided description of the batch.") + + @Size(max=256) public String getBatchdescription() { + return batchdescription; + } + + public void setBatchdescription(String batchdescription) { + this.batchdescription = batchdescription; + } + + public ResponseBatchTransaction processingFlag(Boolean processingFlag) { + this.processingFlag = processingFlag; + return this; + } + + /** + * Indicates whether the batch is currently undergoing processing by the API Provider. + * @return processingFlag + **/ + @Schema(description = "Indicates whether the batch is currently undergoing processing by the API Provider.") + + public Boolean isProcessingFlag() { + return processingFlag; + } + + public void setProcessingFlag(Boolean processingFlag) { + this.processingFlag = processingFlag; + } + + public ResponseBatchTransaction completedCount(BigDecimal completedCount) { + this.completedCount = completedCount; + return this; + } + + /** + * Indicates the number of records that have been successful completed. + * minimum: 0 + * @return completedCount + **/ + @Schema(description = "Indicates the number of records that have been successful completed.") + + @Valid + @DecimalMin("0") public BigDecimal getCompletedCount() { + return completedCount; + } + + public void setCompletedCount(BigDecimal completedCount) { + this.completedCount = completedCount; + } + + public ResponseBatchTransaction rejectionCount(BigDecimal rejectionCount) { + this.rejectionCount = rejectionCount; + return this; + } + + /** + * Indicates the number of records that have been rejected, either during parsing or during final processing. + * minimum: 0 + * @return rejectionCount + **/ + @Schema(description = "Indicates the number of records that have been rejected, either during parsing or during final processing.") + + @Valid + @DecimalMin("0") public BigDecimal getRejectionCount() { + return rejectionCount; + } + + public void setRejectionCount(BigDecimal rejectionCount) { + this.rejectionCount = rejectionCount; + } + + public ResponseBatchTransaction parsingSuccessCount(BigDecimal parsingSuccessCount) { + this.parsingSuccessCount = parsingSuccessCount; + return this; + } + + /** + * Indicates the number of records that have been parsed successfully. + * minimum: 0 + * @return parsingSuccessCount + **/ + @Schema(description = "Indicates the number of records that have been parsed successfully.") + + @Valid + @DecimalMin("0") public BigDecimal getParsingSuccessCount() { + return parsingSuccessCount; + } + + public void setParsingSuccessCount(BigDecimal parsingSuccessCount) { + this.parsingSuccessCount = parsingSuccessCount; + } + + public ResponseBatchTransaction requestingOrganisation(RequestingOrganisation requestingOrganisation) { + this.requestingOrganisation = requestingOrganisation; + return this; + } + + /** + * Get requestingOrganisation + * @return requestingOrganisation + **/ + @Schema(description = "") + + @Valid + public RequestingOrganisation getRequestingOrganisation() { + return requestingOrganisation; + } + + public void setRequestingOrganisation(RequestingOrganisation requestingOrganisation) { + this.requestingOrganisation = requestingOrganisation; + } + + public ResponseBatchTransaction scheduledStartDate(OffsetDateTime scheduledStartDate) { + this.scheduledStartDate = scheduledStartDate; + return this; + } + + /** + * If the batch has been scheduled, the expected start time is provided here. + * @return scheduledStartDate + **/ + @Schema(description = "If the batch has been scheduled, the expected start time is provided here.") + + @Valid + public OffsetDateTime getScheduledStartDate() { + return scheduledStartDate; + } + + public void setScheduledStartDate(OffsetDateTime scheduledStartDate) { + this.scheduledStartDate = scheduledStartDate; + } + + public ResponseBatchTransaction creationDate(OffsetDateTime creationDate) { + this.creationDate = creationDate; + return this; + } + + /** + * Date and time when the object was created by the API Provider. + * @return creationDate + **/ + @Schema(description = "Date and time when the object was created by the API Provider.") + + @Valid + public OffsetDateTime getCreationDate() { + return creationDate; + } + + public void setCreationDate(OffsetDateTime creationDate) { + this.creationDate = creationDate; + } + + public ResponseBatchTransaction modificationDate(OffsetDateTime modificationDate) { + this.modificationDate = modificationDate; + return this; + } + + /** + * Date and time when the object was modified by the API Provider. + * @return modificationDate + **/ + @Schema(description = "Date and time when the object was modified by the API Provider.") + + @Valid + public OffsetDateTime getModificationDate() { + return modificationDate; + } + + public void setModificationDate(OffsetDateTime modificationDate) { + this.modificationDate = modificationDate; + } + + public ResponseBatchTransaction requestDate(OffsetDateTime requestDate) { + this.requestDate = requestDate; + return this; + } + + /** + * The date and time of the request as supplied by the client. + * @return requestDate + **/ + @Schema(description = "The date and time of the request as supplied by the client.") + + @Valid + public OffsetDateTime getRequestDate() { + return requestDate; + } + + public void setRequestDate(OffsetDateTime requestDate) { + this.requestDate = requestDate; + } + + public ResponseBatchTransaction customData(CustomDataArray customData) { + this.customData = customData; + return this; + } + + /** + * Get customData + * @return customData + **/ + @Schema(description = "") + + @Valid + public CustomDataArray getCustomData() { + return customData; + } + + public void setCustomData(CustomDataArray customData) { + this.customData = customData; + } + + public ResponseBatchTransaction completedDate(OffsetDateTime completedDate) { + this.completedDate = completedDate; + return this; + } + + /** + * Indicates when the batch was completed as recorded by the API. + * @return completedDate + **/ + @Schema(description = "Indicates when the batch was completed as recorded by the API.") + + @Valid + public OffsetDateTime getCompletedDate() { + return completedDate; + } + + public void setCompletedDate(OffsetDateTime completedDate) { + this.completedDate = completedDate; + } + + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + ResponseBatchTransaction responseBatchTransaction = (ResponseBatchTransaction) o; + return Objects.equals(this.batchId, responseBatchTransaction.batchId) && + Objects.equals(this.batchStatus, responseBatchTransaction.batchStatus) && + Objects.equals(this.approvalDate, responseBatchTransaction.approvalDate) && + Objects.equals(this.completionDate, responseBatchTransaction.completionDate) && + Objects.equals(this.batchTitle, responseBatchTransaction.batchTitle) && + Objects.equals(this.batchdescription, responseBatchTransaction.batchdescription) && + Objects.equals(this.processingFlag, responseBatchTransaction.processingFlag) && + Objects.equals(this.completedCount, responseBatchTransaction.completedCount) && + Objects.equals(this.rejectionCount, responseBatchTransaction.rejectionCount) && + Objects.equals(this.parsingSuccessCount, responseBatchTransaction.parsingSuccessCount) && + Objects.equals(this.requestingOrganisation, responseBatchTransaction.requestingOrganisation) && + Objects.equals(this.scheduledStartDate, responseBatchTransaction.scheduledStartDate) && + Objects.equals(this.creationDate, responseBatchTransaction.creationDate) && + Objects.equals(this.modificationDate, responseBatchTransaction.modificationDate) && + Objects.equals(this.requestDate, responseBatchTransaction.requestDate) && + Objects.equals(this.customData, responseBatchTransaction.customData) && + Objects.equals(this.completedDate, responseBatchTransaction.completedDate); + } + + @Override + public int hashCode() { + return Objects.hash(batchId, batchStatus, approvalDate, completionDate, batchTitle, batchdescription, processingFlag, completedCount, rejectionCount, parsingSuccessCount, requestingOrganisation, scheduledStartDate, creationDate, modificationDate, requestDate, customData, completedDate); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class ResponseBatchTransaction {\n"); + + sb.append(" batchId: ").append(toIndentedString(batchId)).append("\n"); + sb.append(" batchStatus: ").append(toIndentedString(batchStatus)).append("\n"); + sb.append(" approvalDate: ").append(toIndentedString(approvalDate)).append("\n"); + sb.append(" completionDate: ").append(toIndentedString(completionDate)).append("\n"); + sb.append(" batchTitle: ").append(toIndentedString(batchTitle)).append("\n"); + sb.append(" batchdescription: ").append(toIndentedString(batchdescription)).append("\n"); + sb.append(" processingFlag: ").append(toIndentedString(processingFlag)).append("\n"); + sb.append(" completedCount: ").append(toIndentedString(completedCount)).append("\n"); + sb.append(" rejectionCount: ").append(toIndentedString(rejectionCount)).append("\n"); + sb.append(" parsingSuccessCount: ").append(toIndentedString(parsingSuccessCount)).append("\n"); + sb.append(" requestingOrganisation: ").append(toIndentedString(requestingOrganisation)).append("\n"); + sb.append(" scheduledStartDate: ").append(toIndentedString(scheduledStartDate)).append("\n"); + sb.append(" creationDate: ").append(toIndentedString(creationDate)).append("\n"); + sb.append(" modificationDate: ").append(toIndentedString(modificationDate)).append("\n"); + sb.append(" requestDate: ").append(toIndentedString(requestDate)).append("\n"); + sb.append(" customData: ").append(toIndentedString(customData)).append("\n"); + sb.append(" completedDate: ").append(toIndentedString(completedDate)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/ResponseBatchTransactionCompletion.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/ResponseBatchTransactionCompletion.java new file mode 100644 index 000000000..833105dc1 --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/ResponseBatchTransactionCompletion.java @@ -0,0 +1,259 @@ +package org.mifos.connector.gsmastub.model; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import org.springframework.validation.annotation.Validated; +import org.threeten.bp.OffsetDateTime; + +import javax.validation.Valid; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; +import java.util.Objects; + +/** + * ResponseBatchTransactionCompletion + */ +@Validated +@javax.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.SpringCodegen", date = "2022-09-27T11:46:46.417Z[GMT]") + + +public class ResponseBatchTransactionCompletion { + @JsonProperty("transactionReference") + private String transactionReference = null; + + @JsonProperty("requestingOrganisationTransactionReference") + private String requestingOrganisationTransactionReference = null; + + @JsonProperty("creditParty") + private CreditPartyArray creditParty = null; + + @JsonProperty("debitParty") + private DebitPartyArray debitParty = null; + + @JsonProperty("completionDate") + private OffsetDateTime completionDate = null; + + @JsonProperty("link") + private String link = null; + + @JsonProperty("customData") + private CustomDataArray customData = null; + + @JsonProperty("completedDate") + private OffsetDateTime completedDate = null; + + public ResponseBatchTransactionCompletion transactionReference(String transactionReference) { + this.transactionReference = transactionReference; + return this; + } + + /** + * Unique reference for the transaction. This is returned in the response by API provider. + * @return transactionReference + **/ + @Schema(required = true, description = "Unique reference for the transaction. This is returned in the response by API provider.") + @NotNull + + @Size(min=1,max=256) public String getTransactionReference() { + return transactionReference; + } + + public void setTransactionReference(String transactionReference) { + this.transactionReference = transactionReference; + } + + public ResponseBatchTransactionCompletion requestingOrganisationTransactionReference(String requestingOrganisationTransactionReference) { + this.requestingOrganisationTransactionReference = requestingOrganisationTransactionReference; + return this; + } + + /** + * A reference provided by the requesting organisation that is to be associated with the transaction. + * @return requestingOrganisationTransactionReference + **/ + @Schema(description = "A reference provided by the requesting organisation that is to be associated with the transaction.") + + @Size(max=256) public String getRequestingOrganisationTransactionReference() { + return requestingOrganisationTransactionReference; + } + + public void setRequestingOrganisationTransactionReference(String requestingOrganisationTransactionReference) { + this.requestingOrganisationTransactionReference = requestingOrganisationTransactionReference; + } + + public ResponseBatchTransactionCompletion creditParty(CreditPartyArray creditParty) { + this.creditParty = creditParty; + return this; + } + + /** + * Get creditParty + * @return creditParty + **/ + @Schema(required = true, description = "") + @NotNull + + @Valid + public CreditPartyArray getCreditParty() { + return creditParty; + } + + public void setCreditParty(CreditPartyArray creditParty) { + this.creditParty = creditParty; + } + + public ResponseBatchTransactionCompletion debitParty(DebitPartyArray debitParty) { + this.debitParty = debitParty; + return this; + } + + /** + * Get debitParty + * @return debitParty + **/ + @Schema(required = true, description = "") + @NotNull + + @Valid + public DebitPartyArray getDebitParty() { + return debitParty; + } + + public void setDebitParty(DebitPartyArray debitParty) { + this.debitParty = debitParty; + } + + public ResponseBatchTransactionCompletion completionDate(OffsetDateTime completionDate) { + this.completionDate = completionDate; + return this; + } + + /** + * Date and time indicating when the transaction was completed. + * @return completionDate + **/ + @Schema(required = true, description = "Date and time indicating when the transaction was completed.") + @NotNull + + @Valid + public OffsetDateTime getCompletionDate() { + return completionDate; + } + + public void setCompletionDate(OffsetDateTime completionDate) { + this.completionDate = completionDate; + } + + public ResponseBatchTransactionCompletion link(String link) { + this.link = link; + return this; + } + + /** + * Provides a URL to the resource. + * @return link + **/ + @Schema(required = true, description = "Provides a URL to the resource.") + @NotNull + + @Size(min=1,max=256) public String getLink() { + return link; + } + + public void setLink(String link) { + this.link = link; + } + + public ResponseBatchTransactionCompletion customData(CustomDataArray customData) { + this.customData = customData; + return this; + } + + /** + * Get customData + * @return customData + **/ + @Schema(description = "") + + @Valid + public CustomDataArray getCustomData() { + return customData; + } + + public void setCustomData(CustomDataArray customData) { + this.customData = customData; + } + + public ResponseBatchTransactionCompletion completedDate(OffsetDateTime completedDate) { + this.completedDate = completedDate; + return this; + } + + /** + * Date and time indicating when the transaction was completed. + * @return completedDate + **/ + @Schema(description = "Date and time indicating when the transaction was completed.") + + @Valid + public OffsetDateTime getCompletedDate() { + return completedDate; + } + + public void setCompletedDate(OffsetDateTime completedDate) { + this.completedDate = completedDate; + } + + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + ResponseBatchTransactionCompletion responseBatchTransactionCompletion = (ResponseBatchTransactionCompletion) o; + return Objects.equals(this.transactionReference, responseBatchTransactionCompletion.transactionReference) && + Objects.equals(this.requestingOrganisationTransactionReference, responseBatchTransactionCompletion.requestingOrganisationTransactionReference) && + Objects.equals(this.creditParty, responseBatchTransactionCompletion.creditParty) && + Objects.equals(this.debitParty, responseBatchTransactionCompletion.debitParty) && + Objects.equals(this.completionDate, responseBatchTransactionCompletion.completionDate) && + Objects.equals(this.link, responseBatchTransactionCompletion.link) && + Objects.equals(this.customData, responseBatchTransactionCompletion.customData) && + Objects.equals(this.completedDate, responseBatchTransactionCompletion.completedDate); + } + + @Override + public int hashCode() { + return Objects.hash(transactionReference, requestingOrganisationTransactionReference, creditParty, debitParty, completionDate, link, customData, completedDate); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class ResponseBatchTransactionCompletion {\n"); + + sb.append(" transactionReference: ").append(toIndentedString(transactionReference)).append("\n"); + sb.append(" requestingOrganisationTransactionReference: ").append(toIndentedString(requestingOrganisationTransactionReference)).append("\n"); + sb.append(" creditParty: ").append(toIndentedString(creditParty)).append("\n"); + sb.append(" debitParty: ").append(toIndentedString(debitParty)).append("\n"); + sb.append(" completionDate: ").append(toIndentedString(completionDate)).append("\n"); + sb.append(" link: ").append(toIndentedString(link)).append("\n"); + sb.append(" customData: ").append(toIndentedString(customData)).append("\n"); + sb.append(" completedDate: ").append(toIndentedString(completedDate)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/ResponseBatchTransactionRejection.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/ResponseBatchTransactionRejection.java new file mode 100644 index 000000000..6855f0d39 --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/ResponseBatchTransactionRejection.java @@ -0,0 +1,258 @@ +package org.mifos.connector.gsmastub.model; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import org.springframework.validation.annotation.Validated; +import org.threeten.bp.OffsetDateTime; + +import javax.validation.Valid; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; +import java.util.Objects; + +/** + * ResponseBatchTransactionRejection + */ +@Validated +@javax.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.SpringCodegen", date = "2022-09-27T11:46:46.417Z[GMT]") + + +public class ResponseBatchTransactionRejection { + @JsonProperty("transactionReference") + private String transactionReference = null; + + @JsonProperty("requestingOrganisationTransactionReference") + private String requestingOrganisationTransactionReference = null; + + @JsonProperty("creditParty") + private CreditPartyArray creditParty = null; + + @JsonProperty("debitParty") + private DebitPartyArray debitParty = null; + + @JsonProperty("rejectionReason") + private String rejectionReason = null; + + @JsonProperty("rejectionDate") + private OffsetDateTime rejectionDate = null; + + @JsonProperty("customData") + private CustomDataArray customData = null; + + @JsonProperty("dateRejected") + private OffsetDateTime dateRejected = null; + + public ResponseBatchTransactionRejection transactionReference(String transactionReference) { + this.transactionReference = transactionReference; + return this; + } + + /** + * Unique reference for the transaction. This is returned in the response by API provider. + * @return transactionReference + **/ + @Schema(description = "Unique reference for the transaction. This is returned in the response by API provider.") + + @Size(min=1,max=256) public String getTransactionReference() { + return transactionReference; + } + + public void setTransactionReference(String transactionReference) { + this.transactionReference = transactionReference; + } + + public ResponseBatchTransactionRejection requestingOrganisationTransactionReference(String requestingOrganisationTransactionReference) { + this.requestingOrganisationTransactionReference = requestingOrganisationTransactionReference; + return this; + } + + /** + * A reference provided by the requesting organisation that is to be associated with the transaction. + * @return requestingOrganisationTransactionReference + **/ + @Schema(description = "A reference provided by the requesting organisation that is to be associated with the transaction.") + + @Size(max=256) public String getRequestingOrganisationTransactionReference() { + return requestingOrganisationTransactionReference; + } + + public void setRequestingOrganisationTransactionReference(String requestingOrganisationTransactionReference) { + this.requestingOrganisationTransactionReference = requestingOrganisationTransactionReference; + } + + public ResponseBatchTransactionRejection creditParty(CreditPartyArray creditParty) { + this.creditParty = creditParty; + return this; + } + + /** + * Get creditParty + * @return creditParty + **/ + @Schema(required = true, description = "") + @NotNull + + @Valid + public CreditPartyArray getCreditParty() { + return creditParty; + } + + public void setCreditParty(CreditPartyArray creditParty) { + this.creditParty = creditParty; + } + + public ResponseBatchTransactionRejection debitParty(DebitPartyArray debitParty) { + this.debitParty = debitParty; + return this; + } + + /** + * Get debitParty + * @return debitParty + **/ + @Schema(required = true, description = "") + @NotNull + + @Valid + public DebitPartyArray getDebitParty() { + return debitParty; + } + + public void setDebitParty(DebitPartyArray debitParty) { + this.debitParty = debitParty; + } + + public ResponseBatchTransactionRejection rejectionReason(String rejectionReason) { + this.rejectionReason = rejectionReason; + return this; + } + + /** + * The reason for the transaction request as indicated by the API provider. + * @return rejectionReason + **/ + @Schema(required = true, description = "The reason for the transaction request as indicated by the API provider.") + @NotNull + + @Size(min=1,max=256) public String getRejectionReason() { + return rejectionReason; + } + + public void setRejectionReason(String rejectionReason) { + this.rejectionReason = rejectionReason; + } + + public ResponseBatchTransactionRejection rejectionDate(OffsetDateTime rejectionDate) { + this.rejectionDate = rejectionDate; + return this; + } + + /** + * Date and time of the rejection. + * @return rejectionDate + **/ + @Schema(required = true, description = "Date and time of the rejection.") + @NotNull + + @Valid + public OffsetDateTime getRejectionDate() { + return rejectionDate; + } + + public void setRejectionDate(OffsetDateTime rejectionDate) { + this.rejectionDate = rejectionDate; + } + + public ResponseBatchTransactionRejection customData(CustomDataArray customData) { + this.customData = customData; + return this; + } + + /** + * Get customData + * @return customData + **/ + @Schema(description = "") + + @Valid + public CustomDataArray getCustomData() { + return customData; + } + + public void setCustomData(CustomDataArray customData) { + this.customData = customData; + } + + public ResponseBatchTransactionRejection dateRejected(OffsetDateTime dateRejected) { + this.dateRejected = dateRejected; + return this; + } + + /** + * Date and time of the rejection. + * @return dateRejected + **/ + @Schema(description = "Date and time of the rejection.") + + @Valid + public OffsetDateTime getDateRejected() { + return dateRejected; + } + + public void setDateRejected(OffsetDateTime dateRejected) { + this.dateRejected = dateRejected; + } + + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + ResponseBatchTransactionRejection responseBatchTransactionRejection = (ResponseBatchTransactionRejection) o; + return Objects.equals(this.transactionReference, responseBatchTransactionRejection.transactionReference) && + Objects.equals(this.requestingOrganisationTransactionReference, responseBatchTransactionRejection.requestingOrganisationTransactionReference) && + Objects.equals(this.creditParty, responseBatchTransactionRejection.creditParty) && + Objects.equals(this.debitParty, responseBatchTransactionRejection.debitParty) && + Objects.equals(this.rejectionReason, responseBatchTransactionRejection.rejectionReason) && + Objects.equals(this.rejectionDate, responseBatchTransactionRejection.rejectionDate) && + Objects.equals(this.customData, responseBatchTransactionRejection.customData) && + Objects.equals(this.dateRejected, responseBatchTransactionRejection.dateRejected); + } + + @Override + public int hashCode() { + return Objects.hash(transactionReference, requestingOrganisationTransactionReference, creditParty, debitParty, rejectionReason, rejectionDate, customData, dateRejected); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class ResponseBatchTransactionRejection {\n"); + + sb.append(" transactionReference: ").append(toIndentedString(transactionReference)).append("\n"); + sb.append(" requestingOrganisationTransactionReference: ").append(toIndentedString(requestingOrganisationTransactionReference)).append("\n"); + sb.append(" creditParty: ").append(toIndentedString(creditParty)).append("\n"); + sb.append(" debitParty: ").append(toIndentedString(debitParty)).append("\n"); + sb.append(" rejectionReason: ").append(toIndentedString(rejectionReason)).append("\n"); + sb.append(" rejectionDate: ").append(toIndentedString(rejectionDate)).append("\n"); + sb.append(" customData: ").append(toIndentedString(customData)).append("\n"); + sb.append(" dateRejected: ").append(toIndentedString(dateRejected)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/ResponseBillCompanies.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/ResponseBillCompanies.java new file mode 100644 index 000000000..3d2f502ec --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/ResponseBillCompanies.java @@ -0,0 +1,189 @@ +package org.mifos.connector.gsmastub.model; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import org.springframework.validation.annotation.Validated; + +import javax.validation.Valid; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +/** + * ResponseBillCompanies + */ +@Validated +@javax.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.SpringCodegen", date = "2022-09-27T11:46:46.417Z[GMT]") + + +public class ResponseBillCompanies { + @JsonProperty("serviceProvider") + private String serviceProvider = null; + + @JsonProperty("serviceProviderType") + private String serviceProviderType = null; + + @JsonProperty("serviceProviderSubType") + private String serviceProviderSubType = null; + + @JsonProperty("companyName") + private String companyName = null; + + @JsonProperty("supplementaryServiceProviderDetails") + @Valid + private List supplementaryServiceProviderDetails = null; + + public ResponseBillCompanies serviceProvider(String serviceProvider) { + this.serviceProvider = serviceProvider; + return this; + } + + /** + * Service Provider Reference Code. + * @return serviceProvider + **/ + @Schema(required = true, description = "Service Provider Reference Code.") + @NotNull + + @Size(max=256) public String getServiceProvider() { + return serviceProvider; + } + + public void setServiceProvider(String serviceProvider) { + this.serviceProvider = serviceProvider; + } + + public ResponseBillCompanies serviceProviderType(String serviceProviderType) { + this.serviceProviderType = serviceProviderType; + return this; + } + + /** + * Type of Service Provider that accepts payments. + * @return serviceProviderType + **/ + @Schema(description = "Type of Service Provider that accepts payments.") + + @Size(max=256) public String getServiceProviderType() { + return serviceProviderType; + } + + public void setServiceProviderType(String serviceProviderType) { + this.serviceProviderType = serviceProviderType; + } + + public ResponseBillCompanies serviceProviderSubType(String serviceProviderSubType) { + this.serviceProviderSubType = serviceProviderSubType; + return this; + } + + /** + * Sub-Type of Service Provider. + * @return serviceProviderSubType + **/ + @Schema(description = "Sub-Type of Service Provider.") + + @Size(max=256) public String getServiceProviderSubType() { + return serviceProviderSubType; + } + + public void setServiceProviderSubType(String serviceProviderSubType) { + this.serviceProviderSubType = serviceProviderSubType; + } + + public ResponseBillCompanies companyName(String companyName) { + this.companyName = companyName; + return this; + } + + /** + * Display Name for the Service Provider. + * @return companyName + **/ + @Schema(required = true, description = "Display Name for the Service Provider.") + @NotNull + + @Size(max=256) public String getCompanyName() { + return companyName; + } + + public void setCompanyName(String companyName) { + this.companyName = companyName; + } + + public ResponseBillCompanies supplementaryServiceProviderDetails(List supplementaryServiceProviderDetails) { + this.supplementaryServiceProviderDetails = supplementaryServiceProviderDetails; + return this; + } + + public ResponseBillCompanies addSupplementaryServiceProviderDetailsItem(Metadata supplementaryServiceProviderDetailsItem) { + if (this.supplementaryServiceProviderDetails == null) { + this.supplementaryServiceProviderDetails = new ArrayList(); + } + this.supplementaryServiceProviderDetails.add(supplementaryServiceProviderDetailsItem); + return this; + } + + /** + * Get supplementaryServiceProviderDetails + * @return supplementaryServiceProviderDetails + **/ + @Schema(description = "") + @Valid + @Size(max=20) public List getSupplementaryServiceProviderDetails() { + return supplementaryServiceProviderDetails; + } + + public void setSupplementaryServiceProviderDetails(List supplementaryServiceProviderDetails) { + this.supplementaryServiceProviderDetails = supplementaryServiceProviderDetails; + } + + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + ResponseBillCompanies responseBillCompanies = (ResponseBillCompanies) o; + return Objects.equals(this.serviceProvider, responseBillCompanies.serviceProvider) && + Objects.equals(this.serviceProviderType, responseBillCompanies.serviceProviderType) && + Objects.equals(this.serviceProviderSubType, responseBillCompanies.serviceProviderSubType) && + Objects.equals(this.companyName, responseBillCompanies.companyName) && + Objects.equals(this.supplementaryServiceProviderDetails, responseBillCompanies.supplementaryServiceProviderDetails); + } + + @Override + public int hashCode() { + return Objects.hash(serviceProvider, serviceProviderType, serviceProviderSubType, companyName, supplementaryServiceProviderDetails); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class ResponseBillCompanies {\n"); + + sb.append(" serviceProvider: ").append(toIndentedString(serviceProvider)).append("\n"); + sb.append(" serviceProviderType: ").append(toIndentedString(serviceProviderType)).append("\n"); + sb.append(" serviceProviderSubType: ").append(toIndentedString(serviceProviderSubType)).append("\n"); + sb.append(" companyName: ").append(toIndentedString(companyName)).append("\n"); + sb.append(" supplementaryServiceProviderDetails: ").append(toIndentedString(supplementaryServiceProviderDetails)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/ResponseBillPayment.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/ResponseBillPayment.java new file mode 100644 index 000000000..4d4afc81e --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/ResponseBillPayment.java @@ -0,0 +1,477 @@ +package org.mifos.connector.gsmastub.model; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import org.springframework.validation.annotation.Validated; +import org.threeten.bp.OffsetDateTime; + +import javax.validation.Valid; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Pattern; +import javax.validation.constraints.Size; +import java.util.Objects; + +/** + * ResponseBillPayment + */ +@Validated +@javax.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.SpringCodegen", date = "2022-09-27T11:46:46.417Z[GMT]") + + +public class ResponseBillPayment { + @JsonProperty("serviceProviderPaymentReference") + private String serviceProviderPaymentReference = null; + + @JsonProperty("requestingOrganisationTransactionReference") + private String requestingOrganisationTransactionReference = null; + + @JsonProperty("customerReference") + private String customerReference = null; + + @JsonProperty("paymentType") + private PaymentType paymentType = null; + + @JsonProperty("billPaymentStatus") + private String billPaymentStatus = null; + + @JsonProperty("amountPaid") + private String amountPaid = null; + + @JsonProperty("currency") + private Currency currency = null; + + @JsonProperty("requestingOrganisation") + private String requestingOrganisation = null; + + @JsonProperty("supplementaryBillReferenceDetails") + private SupplementaryBillReferenceDetailsArray supplementaryBillReferenceDetails = null; + + @JsonProperty("serviceProviderComment") + private String serviceProviderComment = null; + + @JsonProperty("serviceProviderNotification") + private String serviceProviderNotification = null; + + @JsonProperty("requestDate") + private OffsetDateTime requestDate = null; + + @JsonProperty("creationDate") + private OffsetDateTime creationDate = null; + + @JsonProperty("modificationDate") + private OffsetDateTime modificationDate = null; + + @JsonProperty("customData") + private CustomDataArray customData = null; + + @JsonProperty("metadata") + private MetadataArray metadata = null; + + @JsonProperty("paidAmount") + private String paidAmount = null; + + public ResponseBillPayment serviceProviderPaymentReference(String serviceProviderPaymentReference) { + this.serviceProviderPaymentReference = serviceProviderPaymentReference; + return this; + } + + /** + * Reference for the payment generated by the service provider. + * @return serviceProviderPaymentReference + **/ + @Schema(description = "Reference for the payment generated by the service provider.") + + @Size(max=256) public String getServiceProviderPaymentReference() { + return serviceProviderPaymentReference; + } + + public void setServiceProviderPaymentReference(String serviceProviderPaymentReference) { + this.serviceProviderPaymentReference = serviceProviderPaymentReference; + } + + public ResponseBillPayment requestingOrganisationTransactionReference(String requestingOrganisationTransactionReference) { + this.requestingOrganisationTransactionReference = requestingOrganisationTransactionReference; + return this; + } + + /** + * A reference provided by the requesting organisation that is to be associated with the transaction. + * @return requestingOrganisationTransactionReference + **/ + @Schema(description = "A reference provided by the requesting organisation that is to be associated with the transaction.") + + @Size(max=256) public String getRequestingOrganisationTransactionReference() { + return requestingOrganisationTransactionReference; + } + + public void setRequestingOrganisationTransactionReference(String requestingOrganisationTransactionReference) { + this.requestingOrganisationTransactionReference = requestingOrganisationTransactionReference; + } + + public ResponseBillPayment customerReference(String customerReference) { + this.customerReference = customerReference; + return this; + } + + /** + * Textual reference provided by the customer paying the bill. + * @return customerReference + **/ + @Schema(description = "Textual reference provided by the customer paying the bill.") + + @Size(max=256) public String getCustomerReference() { + return customerReference; + } + + public void setCustomerReference(String customerReference) { + this.customerReference = customerReference; + } + + public ResponseBillPayment paymentType(PaymentType paymentType) { + this.paymentType = paymentType; + return this; + } + + /** + * Get paymentType + * @return paymentType + **/ + @Schema(description = "") + + @Valid + public PaymentType getPaymentType() { + return paymentType; + } + + public void setPaymentType(PaymentType paymentType) { + this.paymentType = paymentType; + } + + public ResponseBillPayment billPaymentStatus(String billPaymentStatus) { + this.billPaymentStatus = billPaymentStatus; + return this; + } + + /** + * Indicates the status of the bill payment as stored by the API provider. + * @return billPaymentStatus + **/ + @Schema(required = true, description = "Indicates the status of the bill payment as stored by the API provider.") + @NotNull + + @Size(max=256) public String getBillPaymentStatus() { + return billPaymentStatus; + } + + public void setBillPaymentStatus(String billPaymentStatus) { + this.billPaymentStatus = billPaymentStatus; + } + + public ResponseBillPayment amountPaid(String amountPaid) { + this.amountPaid = amountPaid; + return this; + } + + /** + * Get amountPaid + * @return amountPaid + **/ + @Schema(example = "15.21", required = true, description = "") + @NotNull + + @Pattern(regexp="^([0]|([1-9][0-9]{0,17}))([.][0-9]{0,3}[0-9])?$") @Size(min=1,max=23) public String getAmountPaid() { + return amountPaid; + } + + public void setAmountPaid(String amountPaid) { + this.amountPaid = amountPaid; + } + + public ResponseBillPayment currency(Currency currency) { + this.currency = currency; + return this; + } + + /** + * Get currency + * @return currency + **/ + @Schema(required = true, description = "") + @NotNull + + @Valid + public Currency getCurrency() { + return currency; + } + + public void setCurrency(Currency currency) { + this.currency = currency; + } + + public ResponseBillPayment requestingOrganisation(String requestingOrganisation) { + this.requestingOrganisation = requestingOrganisation; + return this; + } + + /** + * The originating mobile money provider or financial institution that holds the wallet/account of the payer. + * @return requestingOrganisation + **/ + @Schema(description = "The originating mobile money provider or financial institution that holds the wallet/account of the payer.") + + @Size(max=256) public String getRequestingOrganisation() { + return requestingOrganisation; + } + + public void setRequestingOrganisation(String requestingOrganisation) { + this.requestingOrganisation = requestingOrganisation; + } + + public ResponseBillPayment supplementaryBillReferenceDetails(SupplementaryBillReferenceDetailsArray supplementaryBillReferenceDetails) { + this.supplementaryBillReferenceDetails = supplementaryBillReferenceDetails; + return this; + } + + /** + * Get supplementaryBillReferenceDetails + * @return supplementaryBillReferenceDetails + **/ + @Schema(description = "") + + @Valid + public SupplementaryBillReferenceDetailsArray getSupplementaryBillReferenceDetails() { + return supplementaryBillReferenceDetails; + } + + public void setSupplementaryBillReferenceDetails(SupplementaryBillReferenceDetailsArray supplementaryBillReferenceDetails) { + this.supplementaryBillReferenceDetails = supplementaryBillReferenceDetails; + } + + public ResponseBillPayment serviceProviderComment(String serviceProviderComment) { + this.serviceProviderComment = serviceProviderComment; + return this; + } + + /** + * Allows the Service Provider to include specific information regarding the bill payment. + * @return serviceProviderComment + **/ + @Schema(description = "Allows the Service Provider to include specific information regarding the bill payment.") + + @Size(max=256) public String getServiceProviderComment() { + return serviceProviderComment; + } + + public void setServiceProviderComment(String serviceProviderComment) { + this.serviceProviderComment = serviceProviderComment; + } + + public ResponseBillPayment serviceProviderNotification(String serviceProviderNotification) { + this.serviceProviderNotification = serviceProviderNotification; + return this; + } + + /** + * Allows the Service Provider to include specific information that will be included on the notification to the customer by the mobile money provider. + * @return serviceProviderNotification + **/ + @Schema(description = "Allows the Service Provider to include specific information that will be included on the notification to the customer by the mobile money provider.") + + @Size(max=256) public String getServiceProviderNotification() { + return serviceProviderNotification; + } + + public void setServiceProviderNotification(String serviceProviderNotification) { + this.serviceProviderNotification = serviceProviderNotification; + } + + public ResponseBillPayment requestDate(OffsetDateTime requestDate) { + this.requestDate = requestDate; + return this; + } + + /** + * The date and time of the request as supplied by the client. + * @return requestDate + **/ + @Schema(description = "The date and time of the request as supplied by the client.") + + @Valid + public OffsetDateTime getRequestDate() { + return requestDate; + } + + public void setRequestDate(OffsetDateTime requestDate) { + this.requestDate = requestDate; + } + + public ResponseBillPayment creationDate(OffsetDateTime creationDate) { + this.creationDate = creationDate; + return this; + } + + /** + * Date and time when the object was created by the API Provider. + * @return creationDate + **/ + @Schema(description = "Date and time when the object was created by the API Provider.") + + @Valid + public OffsetDateTime getCreationDate() { + return creationDate; + } + + public void setCreationDate(OffsetDateTime creationDate) { + this.creationDate = creationDate; + } + + public ResponseBillPayment modificationDate(OffsetDateTime modificationDate) { + this.modificationDate = modificationDate; + return this; + } + + /** + * Date and time when the object was modified by the API Provider. + * @return modificationDate + **/ + @Schema(description = "Date and time when the object was modified by the API Provider.") + + @Valid + public OffsetDateTime getModificationDate() { + return modificationDate; + } + + public void setModificationDate(OffsetDateTime modificationDate) { + this.modificationDate = modificationDate; + } + + public ResponseBillPayment customData(CustomDataArray customData) { + this.customData = customData; + return this; + } + + /** + * Get customData + * @return customData + **/ + @Schema(description = "") + + @Valid + public CustomDataArray getCustomData() { + return customData; + } + + public void setCustomData(CustomDataArray customData) { + this.customData = customData; + } + + public ResponseBillPayment metadata(MetadataArray metadata) { + this.metadata = metadata; + return this; + } + + /** + * Get metadata + * @return metadata + **/ + @Schema(description = "") + + @Valid + public MetadataArray getMetadata() { + return metadata; + } + + public void setMetadata(MetadataArray metadata) { + this.metadata = metadata; + } + + public ResponseBillPayment paidAmount(String paidAmount) { + this.paidAmount = paidAmount; + return this; + } + + /** + * Get paidAmount + * @return paidAmount + **/ + @Schema(example = "15.21", description = "") + + @Pattern(regexp="^([0]|([1-9][0-9]{0,17}))([.][0-9]{0,3}[0-9])?$") @Size(min=1,max=23) public String getPaidAmount() { + return paidAmount; + } + + public void setPaidAmount(String paidAmount) { + this.paidAmount = paidAmount; + } + + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + ResponseBillPayment responseBillPayment = (ResponseBillPayment) o; + return Objects.equals(this.serviceProviderPaymentReference, responseBillPayment.serviceProviderPaymentReference) && + Objects.equals(this.requestingOrganisationTransactionReference, responseBillPayment.requestingOrganisationTransactionReference) && + Objects.equals(this.customerReference, responseBillPayment.customerReference) && + Objects.equals(this.paymentType, responseBillPayment.paymentType) && + Objects.equals(this.billPaymentStatus, responseBillPayment.billPaymentStatus) && + Objects.equals(this.amountPaid, responseBillPayment.amountPaid) && + Objects.equals(this.currency, responseBillPayment.currency) && + Objects.equals(this.requestingOrganisation, responseBillPayment.requestingOrganisation) && + Objects.equals(this.supplementaryBillReferenceDetails, responseBillPayment.supplementaryBillReferenceDetails) && + Objects.equals(this.serviceProviderComment, responseBillPayment.serviceProviderComment) && + Objects.equals(this.serviceProviderNotification, responseBillPayment.serviceProviderNotification) && + Objects.equals(this.requestDate, responseBillPayment.requestDate) && + Objects.equals(this.creationDate, responseBillPayment.creationDate) && + Objects.equals(this.modificationDate, responseBillPayment.modificationDate) && + Objects.equals(this.customData, responseBillPayment.customData) && + Objects.equals(this.metadata, responseBillPayment.metadata) && + Objects.equals(this.paidAmount, responseBillPayment.paidAmount); + } + + @Override + public int hashCode() { + return Objects.hash(serviceProviderPaymentReference, requestingOrganisationTransactionReference, customerReference, paymentType, billPaymentStatus, amountPaid, currency, requestingOrganisation, supplementaryBillReferenceDetails, serviceProviderComment, serviceProviderNotification, requestDate, creationDate, modificationDate, customData, metadata, paidAmount); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class ResponseBillPayment {\n"); + + sb.append(" serviceProviderPaymentReference: ").append(toIndentedString(serviceProviderPaymentReference)).append("\n"); + sb.append(" requestingOrganisationTransactionReference: ").append(toIndentedString(requestingOrganisationTransactionReference)).append("\n"); + sb.append(" customerReference: ").append(toIndentedString(customerReference)).append("\n"); + sb.append(" paymentType: ").append(toIndentedString(paymentType)).append("\n"); + sb.append(" billPaymentStatus: ").append(toIndentedString(billPaymentStatus)).append("\n"); + sb.append(" amountPaid: ").append(toIndentedString(amountPaid)).append("\n"); + sb.append(" currency: ").append(toIndentedString(currency)).append("\n"); + sb.append(" requestingOrganisation: ").append(toIndentedString(requestingOrganisation)).append("\n"); + sb.append(" supplementaryBillReferenceDetails: ").append(toIndentedString(supplementaryBillReferenceDetails)).append("\n"); + sb.append(" serviceProviderComment: ").append(toIndentedString(serviceProviderComment)).append("\n"); + sb.append(" serviceProviderNotification: ").append(toIndentedString(serviceProviderNotification)).append("\n"); + sb.append(" requestDate: ").append(toIndentedString(requestDate)).append("\n"); + sb.append(" creationDate: ").append(toIndentedString(creationDate)).append("\n"); + sb.append(" modificationDate: ").append(toIndentedString(modificationDate)).append("\n"); + sb.append(" customData: ").append(toIndentedString(customData)).append("\n"); + sb.append(" metadata: ").append(toIndentedString(metadata)).append("\n"); + sb.append(" paidAmount: ").append(toIndentedString(paidAmount)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/ResponseBillPayment2.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/ResponseBillPayment2.java new file mode 100644 index 000000000..c2d635710 --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/ResponseBillPayment2.java @@ -0,0 +1,452 @@ +package org.mifos.connector.gsmastub.model; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import org.springframework.validation.annotation.Validated; +import org.threeten.bp.OffsetDateTime; + +import javax.validation.Valid; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Pattern; +import javax.validation.constraints.Size; +import java.util.Objects; + +/** + * ResponseBillPayment2 + */ +@Validated +@javax.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.SpringCodegen", date = "2022-09-27T11:46:46.417Z[GMT]") + + +public class ResponseBillPayment2 { + @JsonProperty("serviceProviderPaymentReference") + private String serviceProviderPaymentReference = null; + + @JsonProperty("requestingOrganisationTransactionReference") + private String requestingOrganisationTransactionReference = null; + + @JsonProperty("customerReference") + private String customerReference = null; + + @JsonProperty("paymentType") + private PaymentType paymentType = null; + + @JsonProperty("billPaymentStatus") + private String billPaymentStatus = null; + + @JsonProperty("amountPaid") + private String amountPaid = null; + + @JsonProperty("currency") + private Currency currency = null; + + @JsonProperty("requestingOrganisation") + private String requestingOrganisation = null; + + @JsonProperty("serviceProviderComment") + private String serviceProviderComment = null; + + @JsonProperty("serviceProviderNotification") + private String serviceProviderNotification = null; + + @JsonProperty("requestDate") + private OffsetDateTime requestDate = null; + + @JsonProperty("creationDate") + private OffsetDateTime creationDate = null; + + @JsonProperty("modificationDate") + private OffsetDateTime modificationDate = null; + + @JsonProperty("customData") + private CustomDataArray customData = null; + + @JsonProperty("metadata") + private MetadataArray metadata = null; + + @JsonProperty("paidAmount") + private String paidAmount = null; + + public ResponseBillPayment2 serviceProviderPaymentReference(String serviceProviderPaymentReference) { + this.serviceProviderPaymentReference = serviceProviderPaymentReference; + return this; + } + + /** + * Reference for the payment generated by the service provider. + * @return serviceProviderPaymentReference + **/ + @Schema(description = "Reference for the payment generated by the service provider.") + + @Size(max=256) public String getServiceProviderPaymentReference() { + return serviceProviderPaymentReference; + } + + public void setServiceProviderPaymentReference(String serviceProviderPaymentReference) { + this.serviceProviderPaymentReference = serviceProviderPaymentReference; + } + + public ResponseBillPayment2 requestingOrganisationTransactionReference(String requestingOrganisationTransactionReference) { + this.requestingOrganisationTransactionReference = requestingOrganisationTransactionReference; + return this; + } + + /** + * A reference provided by the requesting organisation that is to be associated with the transaction. + * @return requestingOrganisationTransactionReference + **/ + @Schema(description = "A reference provided by the requesting organisation that is to be associated with the transaction.") + + @Size(max=256) public String getRequestingOrganisationTransactionReference() { + return requestingOrganisationTransactionReference; + } + + public void setRequestingOrganisationTransactionReference(String requestingOrganisationTransactionReference) { + this.requestingOrganisationTransactionReference = requestingOrganisationTransactionReference; + } + + public ResponseBillPayment2 customerReference(String customerReference) { + this.customerReference = customerReference; + return this; + } + + /** + * Textual reference provided by the customer paying the bill. + * @return customerReference + **/ + @Schema(description = "Textual reference provided by the customer paying the bill.") + + @Size(max=256) public String getCustomerReference() { + return customerReference; + } + + public void setCustomerReference(String customerReference) { + this.customerReference = customerReference; + } + + public ResponseBillPayment2 paymentType(PaymentType paymentType) { + this.paymentType = paymentType; + return this; + } + + /** + * Get paymentType + * @return paymentType + **/ + @Schema(description = "") + + @Valid + public PaymentType getPaymentType() { + return paymentType; + } + + public void setPaymentType(PaymentType paymentType) { + this.paymentType = paymentType; + } + + public ResponseBillPayment2 billPaymentStatus(String billPaymentStatus) { + this.billPaymentStatus = billPaymentStatus; + return this; + } + + /** + * Indicates the status of the bill payment as stored by the API provider. + * @return billPaymentStatus + **/ + @Schema(required = true, description = "Indicates the status of the bill payment as stored by the API provider.") + @NotNull + + @Size(max=256) public String getBillPaymentStatus() { + return billPaymentStatus; + } + + public void setBillPaymentStatus(String billPaymentStatus) { + this.billPaymentStatus = billPaymentStatus; + } + + public ResponseBillPayment2 amountPaid(String amountPaid) { + this.amountPaid = amountPaid; + return this; + } + + /** + * Get amountPaid + * @return amountPaid + **/ + @Schema(example = "15.21", required = true, description = "") + @NotNull + + @Pattern(regexp="^([0]|([1-9][0-9]{0,17}))([.][0-9]{0,3}[0-9])?$") @Size(min=1,max=23) public String getAmountPaid() { + return amountPaid; + } + + public void setAmountPaid(String amountPaid) { + this.amountPaid = amountPaid; + } + + public ResponseBillPayment2 currency(Currency currency) { + this.currency = currency; + return this; + } + + /** + * Get currency + * @return currency + **/ + @Schema(required = true, description = "") + @NotNull + + @Valid + public Currency getCurrency() { + return currency; + } + + public void setCurrency(Currency currency) { + this.currency = currency; + } + + public ResponseBillPayment2 requestingOrganisation(String requestingOrganisation) { + this.requestingOrganisation = requestingOrganisation; + return this; + } + + /** + * The originating mobile money provider or financial institution that holds the wallet/account of the payer. + * @return requestingOrganisation + **/ + @Schema(description = "The originating mobile money provider or financial institution that holds the wallet/account of the payer.") + + @Size(max=256) public String getRequestingOrganisation() { + return requestingOrganisation; + } + + public void setRequestingOrganisation(String requestingOrganisation) { + this.requestingOrganisation = requestingOrganisation; + } + + public ResponseBillPayment2 serviceProviderComment(String serviceProviderComment) { + this.serviceProviderComment = serviceProviderComment; + return this; + } + + /** + * Allows the Service Provider to include specific information regarding the bill payment. + * @return serviceProviderComment + **/ + @Schema(description = "Allows the Service Provider to include specific information regarding the bill payment.") + + @Size(max=256) public String getServiceProviderComment() { + return serviceProviderComment; + } + + public void setServiceProviderComment(String serviceProviderComment) { + this.serviceProviderComment = serviceProviderComment; + } + + public ResponseBillPayment2 serviceProviderNotification(String serviceProviderNotification) { + this.serviceProviderNotification = serviceProviderNotification; + return this; + } + + /** + * Allows the Service Provider to include specific information that will be included on the notification to the customer by the mobile money provider. + * @return serviceProviderNotification + **/ + @Schema(description = "Allows the Service Provider to include specific information that will be included on the notification to the customer by the mobile money provider.") + + @Size(max=256) public String getServiceProviderNotification() { + return serviceProviderNotification; + } + + public void setServiceProviderNotification(String serviceProviderNotification) { + this.serviceProviderNotification = serviceProviderNotification; + } + + public ResponseBillPayment2 requestDate(OffsetDateTime requestDate) { + this.requestDate = requestDate; + return this; + } + + /** + * The date and time of the request as supplied by the client. + * @return requestDate + **/ + @Schema(description = "The date and time of the request as supplied by the client.") + + @Valid + public OffsetDateTime getRequestDate() { + return requestDate; + } + + public void setRequestDate(OffsetDateTime requestDate) { + this.requestDate = requestDate; + } + + public ResponseBillPayment2 creationDate(OffsetDateTime creationDate) { + this.creationDate = creationDate; + return this; + } + + /** + * Date and time when the object was created by the API Provider. + * @return creationDate + **/ + @Schema(description = "Date and time when the object was created by the API Provider.") + + @Valid + public OffsetDateTime getCreationDate() { + return creationDate; + } + + public void setCreationDate(OffsetDateTime creationDate) { + this.creationDate = creationDate; + } + + public ResponseBillPayment2 modificationDate(OffsetDateTime modificationDate) { + this.modificationDate = modificationDate; + return this; + } + + /** + * Date and time when the object was modified by the API Provider. + * @return modificationDate + **/ + @Schema(description = "Date and time when the object was modified by the API Provider.") + + @Valid + public OffsetDateTime getModificationDate() { + return modificationDate; + } + + public void setModificationDate(OffsetDateTime modificationDate) { + this.modificationDate = modificationDate; + } + + public ResponseBillPayment2 customData(CustomDataArray customData) { + this.customData = customData; + return this; + } + + /** + * Get customData + * @return customData + **/ + @Schema(description = "") + + @Valid + public CustomDataArray getCustomData() { + return customData; + } + + public void setCustomData(CustomDataArray customData) { + this.customData = customData; + } + + public ResponseBillPayment2 metadata(MetadataArray metadata) { + this.metadata = metadata; + return this; + } + + /** + * Get metadata + * @return metadata + **/ + @Schema(description = "") + + @Valid + public MetadataArray getMetadata() { + return metadata; + } + + public void setMetadata(MetadataArray metadata) { + this.metadata = metadata; + } + + public ResponseBillPayment2 paidAmount(String paidAmount) { + this.paidAmount = paidAmount; + return this; + } + + /** + * Get paidAmount + * @return paidAmount + **/ + @Schema(example = "15.21", description = "") + + @Pattern(regexp="^([0]|([1-9][0-9]{0,17}))([.][0-9]{0,3}[0-9])?$") @Size(min=1,max=23) public String getPaidAmount() { + return paidAmount; + } + + public void setPaidAmount(String paidAmount) { + this.paidAmount = paidAmount; + } + + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + ResponseBillPayment2 responseBillPayment2 = (ResponseBillPayment2) o; + return Objects.equals(this.serviceProviderPaymentReference, responseBillPayment2.serviceProviderPaymentReference) && + Objects.equals(this.requestingOrganisationTransactionReference, responseBillPayment2.requestingOrganisationTransactionReference) && + Objects.equals(this.customerReference, responseBillPayment2.customerReference) && + Objects.equals(this.paymentType, responseBillPayment2.paymentType) && + Objects.equals(this.billPaymentStatus, responseBillPayment2.billPaymentStatus) && + Objects.equals(this.amountPaid, responseBillPayment2.amountPaid) && + Objects.equals(this.currency, responseBillPayment2.currency) && + Objects.equals(this.requestingOrganisation, responseBillPayment2.requestingOrganisation) && + Objects.equals(this.serviceProviderComment, responseBillPayment2.serviceProviderComment) && + Objects.equals(this.serviceProviderNotification, responseBillPayment2.serviceProviderNotification) && + Objects.equals(this.requestDate, responseBillPayment2.requestDate) && + Objects.equals(this.creationDate, responseBillPayment2.creationDate) && + Objects.equals(this.modificationDate, responseBillPayment2.modificationDate) && + Objects.equals(this.customData, responseBillPayment2.customData) && + Objects.equals(this.metadata, responseBillPayment2.metadata) && + Objects.equals(this.paidAmount, responseBillPayment2.paidAmount); + } + + @Override + public int hashCode() { + return Objects.hash(serviceProviderPaymentReference, requestingOrganisationTransactionReference, customerReference, paymentType, billPaymentStatus, amountPaid, currency, requestingOrganisation, serviceProviderComment, serviceProviderNotification, requestDate, creationDate, modificationDate, customData, metadata, paidAmount); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class ResponseBillPayment2 {\n"); + + sb.append(" serviceProviderPaymentReference: ").append(toIndentedString(serviceProviderPaymentReference)).append("\n"); + sb.append(" requestingOrganisationTransactionReference: ").append(toIndentedString(requestingOrganisationTransactionReference)).append("\n"); + sb.append(" customerReference: ").append(toIndentedString(customerReference)).append("\n"); + sb.append(" paymentType: ").append(toIndentedString(paymentType)).append("\n"); + sb.append(" billPaymentStatus: ").append(toIndentedString(billPaymentStatus)).append("\n"); + sb.append(" amountPaid: ").append(toIndentedString(amountPaid)).append("\n"); + sb.append(" currency: ").append(toIndentedString(currency)).append("\n"); + sb.append(" requestingOrganisation: ").append(toIndentedString(requestingOrganisation)).append("\n"); + sb.append(" serviceProviderComment: ").append(toIndentedString(serviceProviderComment)).append("\n"); + sb.append(" serviceProviderNotification: ").append(toIndentedString(serviceProviderNotification)).append("\n"); + sb.append(" requestDate: ").append(toIndentedString(requestDate)).append("\n"); + sb.append(" creationDate: ").append(toIndentedString(creationDate)).append("\n"); + sb.append(" modificationDate: ").append(toIndentedString(modificationDate)).append("\n"); + sb.append(" customData: ").append(toIndentedString(customData)).append("\n"); + sb.append(" metadata: ").append(toIndentedString(metadata)).append("\n"); + sb.append(" paidAmount: ").append(toIndentedString(paidAmount)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/ResponseBills.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/ResponseBills.java new file mode 100644 index 000000000..59b0c2873 --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/ResponseBills.java @@ -0,0 +1,329 @@ +package org.mifos.connector.gsmastub.model; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import org.springframework.validation.annotation.Validated; +import org.threeten.bp.LocalDate; +import org.threeten.bp.OffsetDateTime; + +import javax.validation.Valid; +import javax.validation.constraints.Pattern; +import javax.validation.constraints.Size; +import java.util.Objects; + +/** + * ResponseBills + */ +@Validated +@javax.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.SpringCodegen", date = "2022-09-27T11:46:46.417Z[GMT]") + + +public class ResponseBills { + @JsonProperty("billReference") + private String billReference = null; + + @JsonProperty("billStatus") + private BillStatus billStatus = null; + + @JsonProperty("amountDue") + private String amountDue = null; + + @JsonProperty("currency") + private Currency currency = null; + + @JsonProperty("billdescription") + private String billdescription = null; + + @JsonProperty("dueDate") + private LocalDate dueDate = null; + + @JsonProperty("minimumAmountDue") + private String minimumAmountDue = null; + + @JsonProperty("creationDate") + private OffsetDateTime creationDate = null; + + @JsonProperty("modificationDate") + private OffsetDateTime modificationDate = null; + + @JsonProperty("customData") + private CustomDataArray customData = null; + + @JsonProperty("metadata") + private MetadataArray metadata = null; + + public ResponseBills billReference(String billReference) { + this.billReference = billReference; + return this; + } + + /** + * Reference number for the Bill that the payer can use when making a payment. + * @return billReference + **/ + @Schema(description = "Reference number for the Bill that the payer can use when making a payment.") + + @Size(max=256) public String getBillReference() { + return billReference; + } + + public void setBillReference(String billReference) { + this.billReference = billReference; + } + + public ResponseBills billStatus(BillStatus billStatus) { + this.billStatus = billStatus; + return this; + } + + /** + * Get billStatus + * @return billStatus + **/ + @Schema(description = "") + + @Valid + public BillStatus getBillStatus() { + return billStatus; + } + + public void setBillStatus(BillStatus billStatus) { + this.billStatus = billStatus; + } + + public ResponseBills amountDue(String amountDue) { + this.amountDue = amountDue; + return this; + } + + /** + * Get amountDue + * @return amountDue + **/ + @Schema(example = "15.21", description = "") + + @Pattern(regexp="^([0]|([1-9][0-9]{0,17}))([.][0-9]{0,3}[0-9])?$") @Size(min=1,max=23) public String getAmountDue() { + return amountDue; + } + + public void setAmountDue(String amountDue) { + this.amountDue = amountDue; + } + + public ResponseBills currency(Currency currency) { + this.currency = currency; + return this; + } + + /** + * Get currency + * @return currency + **/ + @Schema(description = "") + + @Valid + public Currency getCurrency() { + return currency; + } + + public void setCurrency(Currency currency) { + this.currency = currency; + } + + public ResponseBills billdescription(String billdescription) { + this.billdescription = billdescription; + return this; + } + + /** + * Description of the bill that is to be paid + * @return billdescription + **/ + @Schema(description = "Description of the bill that is to be paid") + + @Size(max=256) public String getBilldescription() { + return billdescription; + } + + public void setBilldescription(String billdescription) { + this.billdescription = billdescription; + } + + public ResponseBills dueDate(LocalDate dueDate) { + this.dueDate = dueDate; + return this; + } + + /** + * Date on which the Bill is due to be paid. + * @return dueDate + **/ + @Schema(example = "Tue Nov 20 00:00:00 GMT 2018", description = "Date on which the Bill is due to be paid.") + + @Valid + public LocalDate getDueDate() { + return dueDate; + } + + public void setDueDate(LocalDate dueDate) { + this.dueDate = dueDate; + } + + public ResponseBills minimumAmountDue(String minimumAmountDue) { + this.minimumAmountDue = minimumAmountDue; + return this; + } + + /** + * Get minimumAmountDue + * @return minimumAmountDue + **/ + @Schema(example = "15.21", description = "") + + @Pattern(regexp="^([0]|([1-9][0-9]{0,17}))([.][0-9]{0,3}[0-9])?$") @Size(min=1,max=23) public String getMinimumAmountDue() { + return minimumAmountDue; + } + + public void setMinimumAmountDue(String minimumAmountDue) { + this.minimumAmountDue = minimumAmountDue; + } + + public ResponseBills creationDate(OffsetDateTime creationDate) { + this.creationDate = creationDate; + return this; + } + + /** + * Date and time when the object was created by the API Provider. + * @return creationDate + **/ + @Schema(description = "Date and time when the object was created by the API Provider.") + + @Valid + public OffsetDateTime getCreationDate() { + return creationDate; + } + + public void setCreationDate(OffsetDateTime creationDate) { + this.creationDate = creationDate; + } + + public ResponseBills modificationDate(OffsetDateTime modificationDate) { + this.modificationDate = modificationDate; + return this; + } + + /** + * Date and time when the object was modified by the API Provider. + * @return modificationDate + **/ + @Schema(description = "Date and time when the object was modified by the API Provider.") + + @Valid + public OffsetDateTime getModificationDate() { + return modificationDate; + } + + public void setModificationDate(OffsetDateTime modificationDate) { + this.modificationDate = modificationDate; + } + + public ResponseBills customData(CustomDataArray customData) { + this.customData = customData; + return this; + } + + /** + * Get customData + * @return customData + **/ + @Schema(description = "") + + @Valid + public CustomDataArray getCustomData() { + return customData; + } + + public void setCustomData(CustomDataArray customData) { + this.customData = customData; + } + + public ResponseBills metadata(MetadataArray metadata) { + this.metadata = metadata; + return this; + } + + /** + * Get metadata + * @return metadata + **/ + @Schema(description = "") + + @Valid + public MetadataArray getMetadata() { + return metadata; + } + + public void setMetadata(MetadataArray metadata) { + this.metadata = metadata; + } + + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + ResponseBills responseBills = (ResponseBills) o; + return Objects.equals(this.billReference, responseBills.billReference) && + Objects.equals(this.billStatus, responseBills.billStatus) && + Objects.equals(this.amountDue, responseBills.amountDue) && + Objects.equals(this.currency, responseBills.currency) && + Objects.equals(this.billdescription, responseBills.billdescription) && + Objects.equals(this.dueDate, responseBills.dueDate) && + Objects.equals(this.minimumAmountDue, responseBills.minimumAmountDue) && + Objects.equals(this.creationDate, responseBills.creationDate) && + Objects.equals(this.modificationDate, responseBills.modificationDate) && + Objects.equals(this.customData, responseBills.customData) && + Objects.equals(this.metadata, responseBills.metadata); + } + + @Override + public int hashCode() { + return Objects.hash(billReference, billStatus, amountDue, currency, billdescription, dueDate, minimumAmountDue, creationDate, modificationDate, customData, metadata); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class ResponseBills {\n"); + + sb.append(" billReference: ").append(toIndentedString(billReference)).append("\n"); + sb.append(" billStatus: ").append(toIndentedString(billStatus)).append("\n"); + sb.append(" amountDue: ").append(toIndentedString(amountDue)).append("\n"); + sb.append(" currency: ").append(toIndentedString(currency)).append("\n"); + sb.append(" billdescription: ").append(toIndentedString(billdescription)).append("\n"); + sb.append(" dueDate: ").append(toIndentedString(dueDate)).append("\n"); + sb.append(" minimumAmountDue: ").append(toIndentedString(minimumAmountDue)).append("\n"); + sb.append(" creationDate: ").append(toIndentedString(creationDate)).append("\n"); + sb.append(" modificationDate: ").append(toIndentedString(modificationDate)).append("\n"); + sb.append(" customData: ").append(toIndentedString(customData)).append("\n"); + sb.append(" metadata: ").append(toIndentedString(metadata)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/ResponseDebitMandate.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/ResponseDebitMandate.java new file mode 100644 index 000000000..1a3e8f7dd --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/ResponseDebitMandate.java @@ -0,0 +1,461 @@ +package org.mifos.connector.gsmastub.model; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import org.springframework.validation.annotation.Validated; +import org.threeten.bp.LocalDate; +import org.threeten.bp.OffsetDateTime; + +import javax.validation.Valid; +import javax.validation.constraints.DecimalMin; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Pattern; +import javax.validation.constraints.Size; +import java.math.BigDecimal; +import java.util.Objects; + +/** + * ResponseDebitMandate + */ +@Validated +@javax.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.SpringCodegen", date = "2022-09-27T11:46:46.417Z[GMT]") + + +public class ResponseDebitMandate { + @JsonProperty("mandateReference") + private String mandateReference = null; + + @JsonProperty("payee") + private Payee payee = null; + + @JsonProperty("mandateStatus") + private MandateStatus mandateStatus = null; + + @JsonProperty("startDate") + private LocalDate startDate = null; + + @JsonProperty("amountLimit") + private String amountLimit = null; + + @JsonProperty("currency") + private Currency currency = null; + + @JsonProperty("endDate") + private LocalDate endDate = null; + + @JsonProperty("frequencyType") + private FrequencyType frequencyType = null; + + @JsonProperty("numberOfPayments") + private BigDecimal numberOfPayments = null; + + @JsonProperty("requestingOrganisation") + private RequestingOrganisation requestingOrganisation = null; + + @JsonProperty("creationDate") + private OffsetDateTime creationDate = null; + + @JsonProperty("modificationDate") + private OffsetDateTime modificationDate = null; + + @JsonProperty("requestDate") + private OffsetDateTime requestDate = null; + + @JsonProperty("customData") + private CustomDataArray customData = null; + + @JsonProperty("dateCreated") + private OffsetDateTime dateCreated = null; + + @JsonProperty("dateModified") + private OffsetDateTime dateModified = null; + + public ResponseDebitMandate mandateReference(String mandateReference) { + this.mandateReference = mandateReference; + return this; + } + + /** + * Unique reference provided by the API Provider for the mandate. + * @return mandateReference + **/ + @Schema(required = true, description = "Unique reference provided by the API Provider for the mandate.") + @NotNull + + @Size(max=256) public String getMandateReference() { + return mandateReference; + } + + public void setMandateReference(String mandateReference) { + this.mandateReference = mandateReference; + } + + public ResponseDebitMandate payee(Payee payee) { + this.payee = payee; + return this; + } + + /** + * Get payee + * @return payee + **/ + @Schema(description = "") + + @Valid + public Payee getPayee() { + return payee; + } + + public void setPayee(Payee payee) { + this.payee = payee; + } + + public ResponseDebitMandate mandateStatus(MandateStatus mandateStatus) { + this.mandateStatus = mandateStatus; + return this; + } + + /** + * Get mandateStatus + * @return mandateStatus + **/ + @Schema(description = "") + + @Valid + public MandateStatus getMandateStatus() { + return mandateStatus; + } + + public void setMandateStatus(MandateStatus mandateStatus) { + this.mandateStatus = mandateStatus; + } + + public ResponseDebitMandate startDate(LocalDate startDate) { + this.startDate = startDate; + return this; + } + + /** + * Date on which the mandate starts. If a frequencyType is specified, this will also be the date on which the first payment is to be taken. + * @return startDate + **/ + @Schema(example = "Tue Nov 20 00:00:00 GMT 2018", description = "Date on which the mandate starts. If a frequencyType is specified, this will also be the date on which the first payment is to be taken.") + + @Valid + public LocalDate getStartDate() { + return startDate; + } + + public void setStartDate(LocalDate startDate) { + this.startDate = startDate; + } + + public ResponseDebitMandate amountLimit(String amountLimit) { + this.amountLimit = amountLimit; + return this; + } + + /** + * Get amountLimit + * @return amountLimit + **/ + @Schema(example = "15.21", description = "") + + @Pattern(regexp="^([0]|([1-9][0-9]{0,17}))([.][0-9]{0,3}[0-9])?$") @Size(min=1,max=23) public String getAmountLimit() { + return amountLimit; + } + + public void setAmountLimit(String amountLimit) { + this.amountLimit = amountLimit; + } + + public ResponseDebitMandate currency(Currency currency) { + this.currency = currency; + return this; + } + + /** + * Get currency + * @return currency + **/ + @Schema(description = "") + + @Valid + public Currency getCurrency() { + return currency; + } + + public void setCurrency(Currency currency) { + this.currency = currency; + } + + public ResponseDebitMandate endDate(LocalDate endDate) { + this.endDate = endDate; + return this; + } + + /** + * Date on which the mandate ends. + * @return endDate + **/ + @Schema(example = "Tue Nov 20 00:00:00 GMT 2018", description = "Date on which the mandate ends.") + + @Valid + public LocalDate getEndDate() { + return endDate; + } + + public void setEndDate(LocalDate endDate) { + this.endDate = endDate; + } + + public ResponseDebitMandate frequencyType(FrequencyType frequencyType) { + this.frequencyType = frequencyType; + return this; + } + + /** + * Get frequencyType + * @return frequencyType + **/ + @Schema(description = "") + + @Valid + public FrequencyType getFrequencyType() { + return frequencyType; + } + + public void setFrequencyType(FrequencyType frequencyType) { + this.frequencyType = frequencyType; + } + + public ResponseDebitMandate numberOfPayments(BigDecimal numberOfPayments) { + this.numberOfPayments = numberOfPayments; + return this; + } + + /** + * Indicates the number of consecutive payments that are to be taken. + * minimum: 0 + * @return numberOfPayments + **/ + @Schema(description = "Indicates the number of consecutive payments that are to be taken.") + + @Valid + @DecimalMin("0") public BigDecimal getNumberOfPayments() { + return numberOfPayments; + } + + public void setNumberOfPayments(BigDecimal numberOfPayments) { + this.numberOfPayments = numberOfPayments; + } + + public ResponseDebitMandate requestingOrganisation(RequestingOrganisation requestingOrganisation) { + this.requestingOrganisation = requestingOrganisation; + return this; + } + + /** + * Get requestingOrganisation + * @return requestingOrganisation + **/ + @Schema(description = "") + + @Valid + public RequestingOrganisation getRequestingOrganisation() { + return requestingOrganisation; + } + + public void setRequestingOrganisation(RequestingOrganisation requestingOrganisation) { + this.requestingOrganisation = requestingOrganisation; + } + + public ResponseDebitMandate creationDate(OffsetDateTime creationDate) { + this.creationDate = creationDate; + return this; + } + + /** + * Date and time when the object was created by the API Provider. + * @return creationDate + **/ + @Schema(description = "Date and time when the object was created by the API Provider.") + + @Valid + public OffsetDateTime getCreationDate() { + return creationDate; + } + + public void setCreationDate(OffsetDateTime creationDate) { + this.creationDate = creationDate; + } + + public ResponseDebitMandate modificationDate(OffsetDateTime modificationDate) { + this.modificationDate = modificationDate; + return this; + } + + /** + * Date and time when the object was modified by the API Provider. + * @return modificationDate + **/ + @Schema(description = "Date and time when the object was modified by the API Provider.") + + @Valid + public OffsetDateTime getModificationDate() { + return modificationDate; + } + + public void setModificationDate(OffsetDateTime modificationDate) { + this.modificationDate = modificationDate; + } + + public ResponseDebitMandate requestDate(OffsetDateTime requestDate) { + this.requestDate = requestDate; + return this; + } + + /** + * The date and time of the request as supplied by the client. + * @return requestDate + **/ + @Schema(description = "The date and time of the request as supplied by the client.") + + @Valid + public OffsetDateTime getRequestDate() { + return requestDate; + } + + public void setRequestDate(OffsetDateTime requestDate) { + this.requestDate = requestDate; + } + + public ResponseDebitMandate customData(CustomDataArray customData) { + this.customData = customData; + return this; + } + + /** + * Get customData + * @return customData + **/ + @Schema(description = "") + + @Valid + public CustomDataArray getCustomData() { + return customData; + } + + public void setCustomData(CustomDataArray customData) { + this.customData = customData; + } + + public ResponseDebitMandate dateCreated(OffsetDateTime dateCreated) { + this.dateCreated = dateCreated; + return this; + } + + /** + * Date and time when the object was created by the API Provider. + * @return dateCreated + **/ + @Schema(description = "Date and time when the object was created by the API Provider.") + + @Valid + public OffsetDateTime getDateCreated() { + return dateCreated; + } + + public void setDateCreated(OffsetDateTime dateCreated) { + this.dateCreated = dateCreated; + } + + public ResponseDebitMandate dateModified(OffsetDateTime dateModified) { + this.dateModified = dateModified; + return this; + } + + /** + * Date and time when the object was modified by the API Provider. + * @return dateModified + **/ + @Schema(description = "Date and time when the object was modified by the API Provider.") + + @Valid + public OffsetDateTime getDateModified() { + return dateModified; + } + + public void setDateModified(OffsetDateTime dateModified) { + this.dateModified = dateModified; + } + + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + ResponseDebitMandate responseDebitMandate = (ResponseDebitMandate) o; + return Objects.equals(this.mandateReference, responseDebitMandate.mandateReference) && + Objects.equals(this.payee, responseDebitMandate.payee) && + Objects.equals(this.mandateStatus, responseDebitMandate.mandateStatus) && + Objects.equals(this.startDate, responseDebitMandate.startDate) && + Objects.equals(this.amountLimit, responseDebitMandate.amountLimit) && + Objects.equals(this.currency, responseDebitMandate.currency) && + Objects.equals(this.endDate, responseDebitMandate.endDate) && + Objects.equals(this.frequencyType, responseDebitMandate.frequencyType) && + Objects.equals(this.numberOfPayments, responseDebitMandate.numberOfPayments) && + Objects.equals(this.requestingOrganisation, responseDebitMandate.requestingOrganisation) && + Objects.equals(this.creationDate, responseDebitMandate.creationDate) && + Objects.equals(this.modificationDate, responseDebitMandate.modificationDate) && + Objects.equals(this.requestDate, responseDebitMandate.requestDate) && + Objects.equals(this.customData, responseDebitMandate.customData) && + Objects.equals(this.dateCreated, responseDebitMandate.dateCreated) && + Objects.equals(this.dateModified, responseDebitMandate.dateModified); + } + + @Override + public int hashCode() { + return Objects.hash(mandateReference, payee, mandateStatus, startDate, amountLimit, currency, endDate, frequencyType, numberOfPayments, requestingOrganisation, creationDate, modificationDate, requestDate, customData, dateCreated, dateModified); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class ResponseDebitMandate {\n"); + + sb.append(" mandateReference: ").append(toIndentedString(mandateReference)).append("\n"); + sb.append(" payee: ").append(toIndentedString(payee)).append("\n"); + sb.append(" mandateStatus: ").append(toIndentedString(mandateStatus)).append("\n"); + sb.append(" startDate: ").append(toIndentedString(startDate)).append("\n"); + sb.append(" amountLimit: ").append(toIndentedString(amountLimit)).append("\n"); + sb.append(" currency: ").append(toIndentedString(currency)).append("\n"); + sb.append(" endDate: ").append(toIndentedString(endDate)).append("\n"); + sb.append(" frequencyType: ").append(toIndentedString(frequencyType)).append("\n"); + sb.append(" numberOfPayments: ").append(toIndentedString(numberOfPayments)).append("\n"); + sb.append(" requestingOrganisation: ").append(toIndentedString(requestingOrganisation)).append("\n"); + sb.append(" creationDate: ").append(toIndentedString(creationDate)).append("\n"); + sb.append(" modificationDate: ").append(toIndentedString(modificationDate)).append("\n"); + sb.append(" requestDate: ").append(toIndentedString(requestDate)).append("\n"); + sb.append(" customData: ").append(toIndentedString(customData)).append("\n"); + sb.append(" dateCreated: ").append(toIndentedString(dateCreated)).append("\n"); + sb.append(" dateModified: ").append(toIndentedString(dateModified)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/ResponseHeartbeat.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/ResponseHeartbeat.java new file mode 100644 index 000000000..f88c23f24 --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/ResponseHeartbeat.java @@ -0,0 +1,133 @@ +package org.mifos.connector.gsmastub.model; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import org.springframework.validation.annotation.Validated; +import org.threeten.bp.OffsetDateTime; + +import javax.validation.Valid; +import javax.validation.constraints.NotNull; +import java.math.BigDecimal; +import java.util.Objects; + +/** + * ResponseHeartbeat + */ +@Validated +@javax.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.SpringCodegen", date = "2022-09-27T11:46:46.417Z[GMT]") + + +public class ResponseHeartbeat { + @JsonProperty("serviceStatus") + private ServiceStatus serviceStatus = null; + + @JsonProperty("delay") + private BigDecimal delay = null; + + @JsonProperty("plannedRestorationTime") + private OffsetDateTime plannedRestorationTime = null; + + public ResponseHeartbeat serviceStatus(ServiceStatus serviceStatus) { + this.serviceStatus = serviceStatus; + return this; + } + + /** + * Get serviceStatus + * @return serviceStatus + **/ + @Schema(required = true, description = "") + @NotNull + + @Valid + public ServiceStatus getServiceStatus() { + return serviceStatus; + } + + public void setServiceStatus(ServiceStatus serviceStatus) { + this.serviceStatus = serviceStatus; + } + + public ResponseHeartbeat delay(BigDecimal delay) { + this.delay = delay; + return this; + } + + /** + * The anticipated processing delay in milliseconds. + * @return delay + **/ + @Schema(description = "The anticipated processing delay in milliseconds.") + + @Valid + public BigDecimal getDelay() { + return delay; + } + + public void setDelay(BigDecimal delay) { + this.delay = delay; + } + + public ResponseHeartbeat plannedRestorationTime(OffsetDateTime plannedRestorationTime) { + this.plannedRestorationTime = plannedRestorationTime; + return this; + } + + /** + * Where the planned restoration time is known (e.g. scheduled maintenance), it can be provided in this field. + * @return plannedRestorationTime + **/ + @Schema(description = "Where the planned restoration time is known (e.g. scheduled maintenance), it can be provided in this field.") + + @Valid + public OffsetDateTime getPlannedRestorationTime() { + return plannedRestorationTime; + } + + public void setPlannedRestorationTime(OffsetDateTime plannedRestorationTime) { + this.plannedRestorationTime = plannedRestorationTime; + } + + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + ResponseHeartbeat responseHeartbeat = (ResponseHeartbeat) o; + return Objects.equals(this.serviceStatus, responseHeartbeat.serviceStatus) && + Objects.equals(this.delay, responseHeartbeat.delay) && + Objects.equals(this.plannedRestorationTime, responseHeartbeat.plannedRestorationTime); + } + + @Override + public int hashCode() { + return Objects.hash(serviceStatus, delay, plannedRestorationTime); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class ResponseHeartbeat {\n"); + + sb.append(" serviceStatus: ").append(toIndentedString(serviceStatus)).append("\n"); + sb.append(" delay: ").append(toIndentedString(delay)).append("\n"); + sb.append(" plannedRestorationTime: ").append(toIndentedString(plannedRestorationTime)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/ResponseLink.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/ResponseLink.java new file mode 100644 index 000000000..e3e8f158b --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/ResponseLink.java @@ -0,0 +1,285 @@ +package org.mifos.connector.gsmastub.model; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import org.springframework.validation.annotation.Validated; +import org.threeten.bp.OffsetDateTime; + +import javax.validation.Valid; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; +import java.util.Objects; + +/** + * ResponseLink + */ +@Validated +@javax.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.SpringCodegen", date = "2022-09-27T11:46:46.417Z[GMT]") + + +public class ResponseLink { + @JsonProperty("linkReference") + private String linkReference = null; + + @JsonProperty("sourceAccountIdentifiers") + private DebitPartyArray sourceAccountIdentifiers = null; + + @JsonProperty("mode") + private Mode mode = null; + + @JsonProperty("status") + private Status status = null; + + @JsonProperty("requestingOrganisation") + private RequestingOrganisation requestingOrganisation = null; + + @JsonProperty("creationDate") + private OffsetDateTime creationDate = null; + + @JsonProperty("modificationDate") + private OffsetDateTime modificationDate = null; + + @JsonProperty("requestDate") + private OffsetDateTime requestDate = null; + + @JsonProperty("customData") + private CustomDataArray customData = null; + + public ResponseLink linkReference(String linkReference) { + this.linkReference = linkReference; + return this; + } + + /** + * Indicates the Link reference. This enables a linked account to be uniquely identified. + * @return linkReference + **/ + @Schema(required = true, description = "Indicates the Link reference. This enables a linked account to be uniquely identified.") + @NotNull + + @Size(min=1,max=256) public String getLinkReference() { + return linkReference; + } + + public void setLinkReference(String linkReference) { + this.linkReference = linkReference; + } + + public ResponseLink sourceAccountIdentifiers(DebitPartyArray sourceAccountIdentifiers) { + this.sourceAccountIdentifiers = sourceAccountIdentifiers; + return this; + } + + /** + * Get sourceAccountIdentifiers + * @return sourceAccountIdentifiers + **/ + @Schema(required = true, description = "") + @NotNull + + @Valid + public DebitPartyArray getSourceAccountIdentifiers() { + return sourceAccountIdentifiers; + } + + public void setSourceAccountIdentifiers(DebitPartyArray sourceAccountIdentifiers) { + this.sourceAccountIdentifiers = sourceAccountIdentifiers; + } + + public ResponseLink mode(Mode mode) { + this.mode = mode; + return this; + } + + /** + * Get mode + * @return mode + **/ + @Schema(required = true, description = "") + @NotNull + + @Valid + public Mode getMode() { + return mode; + } + + public void setMode(Mode mode) { + this.mode = mode; + } + + public ResponseLink status(Status status) { + this.status = status; + return this; + } + + /** + * Get status + * @return status + **/ + @Schema(required = true, description = "") + @NotNull + + @Valid + public Status getStatus() { + return status; + } + + public void setStatus(Status status) { + this.status = status; + } + + public ResponseLink requestingOrganisation(RequestingOrganisation requestingOrganisation) { + this.requestingOrganisation = requestingOrganisation; + return this; + } + + /** + * Get requestingOrganisation + * @return requestingOrganisation + **/ + @Schema(description = "") + + @Valid + public RequestingOrganisation getRequestingOrganisation() { + return requestingOrganisation; + } + + public void setRequestingOrganisation(RequestingOrganisation requestingOrganisation) { + this.requestingOrganisation = requestingOrganisation; + } + + public ResponseLink creationDate(OffsetDateTime creationDate) { + this.creationDate = creationDate; + return this; + } + + /** + * Date and time when the object was created by the API Provider. + * @return creationDate + **/ + @Schema(description = "Date and time when the object was created by the API Provider.") + + @Valid + public OffsetDateTime getCreationDate() { + return creationDate; + } + + public void setCreationDate(OffsetDateTime creationDate) { + this.creationDate = creationDate; + } + + public ResponseLink modificationDate(OffsetDateTime modificationDate) { + this.modificationDate = modificationDate; + return this; + } + + /** + * Date and time when the object was modified by the API Provider. + * @return modificationDate + **/ + @Schema(description = "Date and time when the object was modified by the API Provider.") + + @Valid + public OffsetDateTime getModificationDate() { + return modificationDate; + } + + public void setModificationDate(OffsetDateTime modificationDate) { + this.modificationDate = modificationDate; + } + + public ResponseLink requestDate(OffsetDateTime requestDate) { + this.requestDate = requestDate; + return this; + } + + /** + * The date and time of the request as supplied by the client. + * @return requestDate + **/ + @Schema(description = "The date and time of the request as supplied by the client.") + + @Valid + public OffsetDateTime getRequestDate() { + return requestDate; + } + + public void setRequestDate(OffsetDateTime requestDate) { + this.requestDate = requestDate; + } + + public ResponseLink customData(CustomDataArray customData) { + this.customData = customData; + return this; + } + + /** + * Get customData + * @return customData + **/ + @Schema(description = "") + + @Valid + public CustomDataArray getCustomData() { + return customData; + } + + public void setCustomData(CustomDataArray customData) { + this.customData = customData; + } + + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + ResponseLink responseLink = (ResponseLink) o; + return Objects.equals(this.linkReference, responseLink.linkReference) && + Objects.equals(this.sourceAccountIdentifiers, responseLink.sourceAccountIdentifiers) && + Objects.equals(this.mode, responseLink.mode) && + Objects.equals(this.status, responseLink.status) && + Objects.equals(this.requestingOrganisation, responseLink.requestingOrganisation) && + Objects.equals(this.creationDate, responseLink.creationDate) && + Objects.equals(this.modificationDate, responseLink.modificationDate) && + Objects.equals(this.requestDate, responseLink.requestDate) && + Objects.equals(this.customData, responseLink.customData); + } + + @Override + public int hashCode() { + return Objects.hash(linkReference, sourceAccountIdentifiers, mode, status, requestingOrganisation, creationDate, modificationDate, requestDate, customData); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class ResponseLink {\n"); + + sb.append(" linkReference: ").append(toIndentedString(linkReference)).append("\n"); + sb.append(" sourceAccountIdentifiers: ").append(toIndentedString(sourceAccountIdentifiers)).append("\n"); + sb.append(" mode: ").append(toIndentedString(mode)).append("\n"); + sb.append(" status: ").append(toIndentedString(status)).append("\n"); + sb.append(" requestingOrganisation: ").append(toIndentedString(requestingOrganisation)).append("\n"); + sb.append(" creationDate: ").append(toIndentedString(creationDate)).append("\n"); + sb.append(" modificationDate: ").append(toIndentedString(modificationDate)).append("\n"); + sb.append(" requestDate: ").append(toIndentedString(requestDate)).append("\n"); + sb.append(" customData: ").append(toIndentedString(customData)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/ResponseQuotation.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/ResponseQuotation.java new file mode 100644 index 000000000..5ace2243b --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/ResponseQuotation.java @@ -0,0 +1,708 @@ +package org.mifos.connector.gsmastub.model; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import org.springframework.validation.annotation.Validated; +import org.threeten.bp.OffsetDateTime; + +import javax.validation.Valid; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Pattern; +import javax.validation.constraints.Size; +import java.util.Objects; + +/** + * ResponseQuotation + */ +@Validated +@javax.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.SpringCodegen", date = "2022-09-27T11:46:46.417Z[GMT]") + + +public class ResponseQuotation { + @JsonProperty("quotationReference") + private String quotationReference = null; + + @JsonProperty("creditParty") + private CreditPartyArray creditParty = null; + + @JsonProperty("debitParty") + private DebitPartyArray debitParty = null; + + @JsonProperty("type") + private Type type = null; + + @JsonProperty("subType") + private String subType = null; + + @JsonProperty("quotationStatus") + private QuotationStatus quotationStatus = null; + + @JsonProperty("requestAmount") + private String requestAmount = null; + + @JsonProperty("requestCurrency") + private Currency requestCurrency = null; + + @JsonProperty("availableDeliveryMethod") + private DeliveryMethod availableDeliveryMethod = null; + + @JsonProperty("chosenDeliveryMethod") + private DeliveryMethod chosenDeliveryMethod = null; + + @JsonProperty("originCountry") + private Nationality originCountry = null; + + @JsonProperty("receivingCountry") + private Nationality receivingCountry = null; + + @JsonProperty("quotes") + private QuoteArray quotes = null; + + @JsonProperty("recipientKyc") + private Kyc recipientKyc = null; + + @JsonProperty("senderKyc") + private Kyc senderKyc = null; + + @JsonProperty("recipientBlockingReason") + private String recipientBlockingReason = null; + + @JsonProperty("senderBlockingReason") + private String senderBlockingReason = null; + + @JsonProperty("requestingOrganisation") + private RequestingOrganisation requestingOrganisation = null; + + @JsonProperty("sendingServiceProviderCountry") + private Nationality sendingServiceProviderCountry = null; + + @JsonProperty("creationDate") + private OffsetDateTime creationDate = null; + + @JsonProperty("modificationDate") + private OffsetDateTime modificationDate = null; + + @JsonProperty("requestDate") + private OffsetDateTime requestDate = null; + + @JsonProperty("dateCreated") + private OffsetDateTime dateCreated = null; + + @JsonProperty("dateModified") + private OffsetDateTime dateModified = null; + + @JsonProperty("customData") + private CustomDataArray customData = null; + + @JsonProperty("metadata") + private MetadataArray metadata = null; + + public ResponseQuotation quotationReference(String quotationReference) { + this.quotationReference = quotationReference; + return this; + } + + /** + * Reference for the quotation that was provided to the sender. + * @return quotationReference + **/ + @Schema(required = true, description = "Reference for the quotation that was provided to the sender.") + @NotNull + + @Size(min=1,max=256) public String getQuotationReference() { + return quotationReference; + } + + public void setQuotationReference(String quotationReference) { + this.quotationReference = quotationReference; + } + + public ResponseQuotation creditParty(CreditPartyArray creditParty) { + this.creditParty = creditParty; + return this; + } + + /** + * Get creditParty + * @return creditParty + **/ + @Schema(required = true, description = "") + @NotNull + + @Valid + public CreditPartyArray getCreditParty() { + return creditParty; + } + + public void setCreditParty(CreditPartyArray creditParty) { + this.creditParty = creditParty; + } + + public ResponseQuotation debitParty(DebitPartyArray debitParty) { + this.debitParty = debitParty; + return this; + } + + /** + * Get debitParty + * @return debitParty + **/ + @Schema(required = true, description = "") + @NotNull + + @Valid + public DebitPartyArray getDebitParty() { + return debitParty; + } + + public void setDebitParty(DebitPartyArray debitParty) { + this.debitParty = debitParty; + } + + public ResponseQuotation type(Type type) { + this.type = type; + return this; + } + + /** + * Get type + * @return type + **/ + @Schema(description = "") + + @Valid + public Type getType() { + return type; + } + + public void setType(Type type) { + this.type = type; + } + + public ResponseQuotation subType(String subType) { + this.subType = subType; + return this; + } + + /** + * A non-harmonised sub-classification of the type of transaction. Values are not fixed, and usage will vary according to Provider. + * @return subType + **/ + @Schema(description = "A non-harmonised sub-classification of the type of transaction. Values are not fixed, and usage will vary according to Provider.") + + @Size(max=256) public String getSubType() { + return subType; + } + + public void setSubType(String subType) { + this.subType = subType; + } + + public ResponseQuotation quotationStatus(QuotationStatus quotationStatus) { + this.quotationStatus = quotationStatus; + return this; + } + + /** + * Get quotationStatus + * @return quotationStatus + **/ + @Schema(description = "") + + @Valid + public QuotationStatus getQuotationStatus() { + return quotationStatus; + } + + public void setQuotationStatus(QuotationStatus quotationStatus) { + this.quotationStatus = quotationStatus; + } + + public ResponseQuotation requestAmount(String requestAmount) { + this.requestAmount = requestAmount; + return this; + } + + /** + * Get requestAmount + * @return requestAmount + **/ + @Schema(example = "15.21", required = true, description = "") + @NotNull + + @Pattern(regexp="^([0]|([1-9][0-9]{0,17}))([.][0-9]{0,3}[0-9])?$") @Size(min=1,max=23) public String getRequestAmount() { + return requestAmount; + } + + public void setRequestAmount(String requestAmount) { + this.requestAmount = requestAmount; + } + + public ResponseQuotation requestCurrency(Currency requestCurrency) { + this.requestCurrency = requestCurrency; + return this; + } + + /** + * Get requestCurrency + * @return requestCurrency + **/ + @Schema(required = true, description = "") + @NotNull + + @Valid + public Currency getRequestCurrency() { + return requestCurrency; + } + + public void setRequestCurrency(Currency requestCurrency) { + this.requestCurrency = requestCurrency; + } + + public ResponseQuotation availableDeliveryMethod(DeliveryMethod availableDeliveryMethod) { + this.availableDeliveryMethod = availableDeliveryMethod; + return this; + } + + /** + * Get availableDeliveryMethod + * @return availableDeliveryMethod + **/ + @Schema(description = "") + + @Valid + public DeliveryMethod getAvailableDeliveryMethod() { + return availableDeliveryMethod; + } + + public void setAvailableDeliveryMethod(DeliveryMethod availableDeliveryMethod) { + this.availableDeliveryMethod = availableDeliveryMethod; + } + + public ResponseQuotation chosenDeliveryMethod(DeliveryMethod chosenDeliveryMethod) { + this.chosenDeliveryMethod = chosenDeliveryMethod; + return this; + } + + /** + * Get chosenDeliveryMethod + * @return chosenDeliveryMethod + **/ + @Schema(description = "") + + @Valid + public DeliveryMethod getChosenDeliveryMethod() { + return chosenDeliveryMethod; + } + + public void setChosenDeliveryMethod(DeliveryMethod chosenDeliveryMethod) { + this.chosenDeliveryMethod = chosenDeliveryMethod; + } + + public ResponseQuotation originCountry(Nationality originCountry) { + this.originCountry = originCountry; + return this; + } + + /** + * Get originCountry + * @return originCountry + **/ + @Schema(description = "") + + @Valid + public Nationality getOriginCountry() { + return originCountry; + } + + public void setOriginCountry(Nationality originCountry) { + this.originCountry = originCountry; + } + + public ResponseQuotation receivingCountry(Nationality receivingCountry) { + this.receivingCountry = receivingCountry; + return this; + } + + /** + * Get receivingCountry + * @return receivingCountry + **/ + @Schema(description = "") + + @Valid + public Nationality getReceivingCountry() { + return receivingCountry; + } + + public void setReceivingCountry(Nationality receivingCountry) { + this.receivingCountry = receivingCountry; + } + + public ResponseQuotation quotes(QuoteArray quotes) { + this.quotes = quotes; + return this; + } + + /** + * Get quotes + * @return quotes + **/ + @Schema(description = "") + + @Valid + public QuoteArray getQuotes() { + return quotes; + } + + public void setQuotes(QuoteArray quotes) { + this.quotes = quotes; + } + + public ResponseQuotation recipientKyc(Kyc recipientKyc) { + this.recipientKyc = recipientKyc; + return this; + } + + /** + * Get recipientKyc + * @return recipientKyc + **/ + @Schema(description = "") + + @Valid + public Kyc getRecipientKyc() { + return recipientKyc; + } + + public void setRecipientKyc(Kyc recipientKyc) { + this.recipientKyc = recipientKyc; + } + + public ResponseQuotation senderKyc(Kyc senderKyc) { + this.senderKyc = senderKyc; + return this; + } + + /** + * Get senderKyc + * @return senderKyc + **/ + @Schema(description = "") + + @Valid + public Kyc getSenderKyc() { + return senderKyc; + } + + public void setSenderKyc(Kyc senderKyc) { + this.senderKyc = senderKyc; + } + + public ResponseQuotation recipientBlockingReason(String recipientBlockingReason) { + this.recipientBlockingReason = recipientBlockingReason; + return this; + } + + /** + * The reason for blocking the quotation, based on AML checks on the recipient. + * @return recipientBlockingReason + **/ + @Schema(description = "The reason for blocking the quotation, based on AML checks on the recipient.") + + @Size(max=256) public String getRecipientBlockingReason() { + return recipientBlockingReason; + } + + public void setRecipientBlockingReason(String recipientBlockingReason) { + this.recipientBlockingReason = recipientBlockingReason; + } + + public ResponseQuotation senderBlockingReason(String senderBlockingReason) { + this.senderBlockingReason = senderBlockingReason; + return this; + } + + /** + * The reason for blocking the quotation, based on AML checks on the sender. + * @return senderBlockingReason + **/ + @Schema(description = "The reason for blocking the quotation, based on AML checks on the sender.") + + @Size(max=256) public String getSenderBlockingReason() { + return senderBlockingReason; + } + + public void setSenderBlockingReason(String senderBlockingReason) { + this.senderBlockingReason = senderBlockingReason; + } + + public ResponseQuotation requestingOrganisation(RequestingOrganisation requestingOrganisation) { + this.requestingOrganisation = requestingOrganisation; + return this; + } + + /** + * Get requestingOrganisation + * @return requestingOrganisation + **/ + @Schema(description = "") + + @Valid + public RequestingOrganisation getRequestingOrganisation() { + return requestingOrganisation; + } + + public void setRequestingOrganisation(RequestingOrganisation requestingOrganisation) { + this.requestingOrganisation = requestingOrganisation; + } + + public ResponseQuotation sendingServiceProviderCountry(Nationality sendingServiceProviderCountry) { + this.sendingServiceProviderCountry = sendingServiceProviderCountry; + return this; + } + + /** + * Get sendingServiceProviderCountry + * @return sendingServiceProviderCountry + **/ + @Schema(description = "") + + @Valid + public Nationality getSendingServiceProviderCountry() { + return sendingServiceProviderCountry; + } + + public void setSendingServiceProviderCountry(Nationality sendingServiceProviderCountry) { + this.sendingServiceProviderCountry = sendingServiceProviderCountry; + } + + public ResponseQuotation creationDate(OffsetDateTime creationDate) { + this.creationDate = creationDate; + return this; + } + + /** + * Date and time when the object was created by the API Provider. + * @return creationDate + **/ + @Schema(description = "Date and time when the object was created by the API Provider.") + + @Valid + public OffsetDateTime getCreationDate() { + return creationDate; + } + + public void setCreationDate(OffsetDateTime creationDate) { + this.creationDate = creationDate; + } + + public ResponseQuotation modificationDate(OffsetDateTime modificationDate) { + this.modificationDate = modificationDate; + return this; + } + + /** + * Date and time when the object was modified by the API Provider. + * @return modificationDate + **/ + @Schema(description = "Date and time when the object was modified by the API Provider.") + + @Valid + public OffsetDateTime getModificationDate() { + return modificationDate; + } + + public void setModificationDate(OffsetDateTime modificationDate) { + this.modificationDate = modificationDate; + } + + public ResponseQuotation requestDate(OffsetDateTime requestDate) { + this.requestDate = requestDate; + return this; + } + + /** + * The date and time of the request as supplied by the client. + * @return requestDate + **/ + @Schema(description = "The date and time of the request as supplied by the client.") + + @Valid + public OffsetDateTime getRequestDate() { + return requestDate; + } + + public void setRequestDate(OffsetDateTime requestDate) { + this.requestDate = requestDate; + } + + public ResponseQuotation dateCreated(OffsetDateTime dateCreated) { + this.dateCreated = dateCreated; + return this; + } + + /** + * Date and time when the object was created by the API Provider. + * @return dateCreated + **/ + @Schema(description = "Date and time when the object was created by the API Provider.") + + @Valid + public OffsetDateTime getDateCreated() { + return dateCreated; + } + + public void setDateCreated(OffsetDateTime dateCreated) { + this.dateCreated = dateCreated; + } + + public ResponseQuotation dateModified(OffsetDateTime dateModified) { + this.dateModified = dateModified; + return this; + } + + /** + * Date and time when the object was modified by the API Provider. + * @return dateModified + **/ + @Schema(description = "Date and time when the object was modified by the API Provider.") + + @Valid + public OffsetDateTime getDateModified() { + return dateModified; + } + + public void setDateModified(OffsetDateTime dateModified) { + this.dateModified = dateModified; + } + + public ResponseQuotation customData(CustomDataArray customData) { + this.customData = customData; + return this; + } + + /** + * Get customData + * @return customData + **/ + @Schema(description = "") + + @Valid + public CustomDataArray getCustomData() { + return customData; + } + + public void setCustomData(CustomDataArray customData) { + this.customData = customData; + } + + public ResponseQuotation metadata(MetadataArray metadata) { + this.metadata = metadata; + return this; + } + + /** + * Get metadata + * @return metadata + **/ + @Schema(description = "") + + @Valid + public MetadataArray getMetadata() { + return metadata; + } + + public void setMetadata(MetadataArray metadata) { + this.metadata = metadata; + } + + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + ResponseQuotation responseQuotation = (ResponseQuotation) o; + return Objects.equals(this.quotationReference, responseQuotation.quotationReference) && + Objects.equals(this.creditParty, responseQuotation.creditParty) && + Objects.equals(this.debitParty, responseQuotation.debitParty) && + Objects.equals(this.type, responseQuotation.type) && + Objects.equals(this.subType, responseQuotation.subType) && + Objects.equals(this.quotationStatus, responseQuotation.quotationStatus) && + Objects.equals(this.requestAmount, responseQuotation.requestAmount) && + Objects.equals(this.requestCurrency, responseQuotation.requestCurrency) && + Objects.equals(this.availableDeliveryMethod, responseQuotation.availableDeliveryMethod) && + Objects.equals(this.chosenDeliveryMethod, responseQuotation.chosenDeliveryMethod) && + Objects.equals(this.originCountry, responseQuotation.originCountry) && + Objects.equals(this.receivingCountry, responseQuotation.receivingCountry) && + Objects.equals(this.quotes, responseQuotation.quotes) && + Objects.equals(this.recipientKyc, responseQuotation.recipientKyc) && + Objects.equals(this.senderKyc, responseQuotation.senderKyc) && + Objects.equals(this.recipientBlockingReason, responseQuotation.recipientBlockingReason) && + Objects.equals(this.senderBlockingReason, responseQuotation.senderBlockingReason) && + Objects.equals(this.requestingOrganisation, responseQuotation.requestingOrganisation) && + Objects.equals(this.sendingServiceProviderCountry, responseQuotation.sendingServiceProviderCountry) && + Objects.equals(this.creationDate, responseQuotation.creationDate) && + Objects.equals(this.modificationDate, responseQuotation.modificationDate) && + Objects.equals(this.requestDate, responseQuotation.requestDate) && + Objects.equals(this.dateCreated, responseQuotation.dateCreated) && + Objects.equals(this.dateModified, responseQuotation.dateModified) && + Objects.equals(this.customData, responseQuotation.customData) && + Objects.equals(this.metadata, responseQuotation.metadata); + } + + @Override + public int hashCode() { + return Objects.hash(quotationReference, creditParty, debitParty, type, subType, quotationStatus, requestAmount, requestCurrency, availableDeliveryMethod, chosenDeliveryMethod, originCountry, receivingCountry, quotes, recipientKyc, senderKyc, recipientBlockingReason, senderBlockingReason, requestingOrganisation, sendingServiceProviderCountry, creationDate, modificationDate, requestDate, dateCreated, dateModified, customData, metadata); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class ResponseQuotation {\n"); + + sb.append(" quotationReference: ").append(toIndentedString(quotationReference)).append("\n"); + sb.append(" creditParty: ").append(toIndentedString(creditParty)).append("\n"); + sb.append(" debitParty: ").append(toIndentedString(debitParty)).append("\n"); + sb.append(" type: ").append(toIndentedString(type)).append("\n"); + sb.append(" subType: ").append(toIndentedString(subType)).append("\n"); + sb.append(" quotationStatus: ").append(toIndentedString(quotationStatus)).append("\n"); + sb.append(" requestAmount: ").append(toIndentedString(requestAmount)).append("\n"); + sb.append(" requestCurrency: ").append(toIndentedString(requestCurrency)).append("\n"); + sb.append(" availableDeliveryMethod: ").append(toIndentedString(availableDeliveryMethod)).append("\n"); + sb.append(" chosenDeliveryMethod: ").append(toIndentedString(chosenDeliveryMethod)).append("\n"); + sb.append(" originCountry: ").append(toIndentedString(originCountry)).append("\n"); + sb.append(" receivingCountry: ").append(toIndentedString(receivingCountry)).append("\n"); + sb.append(" quotes: ").append(toIndentedString(quotes)).append("\n"); + sb.append(" recipientKyc: ").append(toIndentedString(recipientKyc)).append("\n"); + sb.append(" senderKyc: ").append(toIndentedString(senderKyc)).append("\n"); + sb.append(" recipientBlockingReason: ").append(toIndentedString(recipientBlockingReason)).append("\n"); + sb.append(" senderBlockingReason: ").append(toIndentedString(senderBlockingReason)).append("\n"); + sb.append(" requestingOrganisation: ").append(toIndentedString(requestingOrganisation)).append("\n"); + sb.append(" sendingServiceProviderCountry: ").append(toIndentedString(sendingServiceProviderCountry)).append("\n"); + sb.append(" creationDate: ").append(toIndentedString(creationDate)).append("\n"); + sb.append(" modificationDate: ").append(toIndentedString(modificationDate)).append("\n"); + sb.append(" requestDate: ").append(toIndentedString(requestDate)).append("\n"); + sb.append(" dateCreated: ").append(toIndentedString(dateCreated)).append("\n"); + sb.append(" dateModified: ").append(toIndentedString(dateModified)).append("\n"); + sb.append(" customData: ").append(toIndentedString(customData)).append("\n"); + sb.append(" metadata: ").append(toIndentedString(metadata)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/ResponseResponse.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/ResponseResponse.java new file mode 100644 index 000000000..977b07796 --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/ResponseResponse.java @@ -0,0 +1,80 @@ +package org.mifos.connector.gsmastub.model; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import org.springframework.validation.annotation.Validated; + +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; +import java.util.Objects; + +/** + * ResponseResponse + */ +@Validated +@javax.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.SpringCodegen", date = "2022-09-27T11:46:46.417Z[GMT]") + + +public class ResponseResponse { + @JsonProperty("link") + private String link = null; + + public ResponseResponse link(String link) { + this.link = link; + return this; + } + + /** + * Provides a URL to the resource. + * @return link + **/ + @Schema(required = true, description = "Provides a URL to the resource.") + @NotNull + + @Size(min=1,max=256) public String getLink() { + return link; + } + + public void setLink(String link) { + this.link = link; + } + + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + ResponseResponse responseResponse = (ResponseResponse) o; + return Objects.equals(this.link, responseResponse.link); + } + + @Override + public int hashCode() { + return Objects.hash(link); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class ResponseResponse {\n"); + + sb.append(" link: ").append(toIndentedString(link)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/ResponseReversal.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/ResponseReversal.java new file mode 100644 index 000000000..2ad4cf6a8 --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/ResponseReversal.java @@ -0,0 +1,675 @@ +package org.mifos.connector.gsmastub.model; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import org.springframework.validation.annotation.Validated; +import org.threeten.bp.OffsetDateTime; + +import javax.validation.Valid; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Pattern; +import javax.validation.constraints.Size; +import java.util.Objects; + +/** + * ResponseReversal + */ +@Validated +@javax.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.SpringCodegen", date = "2022-09-27T11:46:46.417Z[GMT]") + + +public class ResponseReversal { + @JsonProperty("transactionReference") + private String transactionReference = null; + + @JsonProperty("requestingOrganisationTransactionReference") + private String requestingOrganisationTransactionReference = null; + + @JsonProperty("originalTransactionReference") + private String originalTransactionReference = null; + + @JsonProperty("creditParty") + private DebitPartyArray creditParty = null; + + @JsonProperty("debitParty") + private DebitPartyArray debitParty = null; + + @JsonProperty("type") + private TypeReversal type = null; + + @JsonProperty("subType") + private String subType = null; + + @JsonProperty("transactionStatus") + private String transactionStatus = null; + + @JsonProperty("amount") + private String amount = null; + + @JsonProperty("currency") + private Currency currency = null; + + @JsonProperty("descriptionText") + private String descriptionText = null; + + @JsonProperty("fees") + private FeesArray fees = null; + + @JsonProperty("geoCode") + private String geoCode = null; + + @JsonProperty("requestingOrganisation") + private RequestingOrganisation requestingOrganisation = null; + + @JsonProperty("servicingIdentity") + private String servicingIdentity = null; + + @JsonProperty("transactionReceipt") + private String transactionReceipt = null; + + @JsonProperty("creationDate") + private OffsetDateTime creationDate = null; + + @JsonProperty("modificationDate") + private OffsetDateTime modificationDate = null; + + @JsonProperty("requestDate") + private OffsetDateTime requestDate = null; + + @JsonProperty("customData") + private CustomDataArray customData = null; + + @JsonProperty("metadata") + private MetadataArray metadata = null; + + @JsonProperty("dateCreated") + private OffsetDateTime dateCreated = null; + + @JsonProperty("dateModified") + private OffsetDateTime dateModified = null; + + @JsonProperty("receivingLei") + private String receivingLei = null; + + @JsonProperty("requestingLei") + private String requestingLei = null; + + public ResponseReversal transactionReference(String transactionReference) { + this.transactionReference = transactionReference; + return this; + } + + /** + * Unique reference for the transaction. This is returned in the response by API provider. + * @return transactionReference + **/ + @Schema(required = true, description = "Unique reference for the transaction. This is returned in the response by API provider.") + @NotNull + + @Size(min=1,max=256) public String getTransactionReference() { + return transactionReference; + } + + public void setTransactionReference(String transactionReference) { + this.transactionReference = transactionReference; + } + + public ResponseReversal requestingOrganisationTransactionReference(String requestingOrganisationTransactionReference) { + this.requestingOrganisationTransactionReference = requestingOrganisationTransactionReference; + return this; + } + + /** + * A reference provided by the requesting organisation that is to be associated with the transaction. + * @return requestingOrganisationTransactionReference + **/ + @Schema(description = "A reference provided by the requesting organisation that is to be associated with the transaction.") + + @Size(max=256) public String getRequestingOrganisationTransactionReference() { + return requestingOrganisationTransactionReference; + } + + public void setRequestingOrganisationTransactionReference(String requestingOrganisationTransactionReference) { + this.requestingOrganisationTransactionReference = requestingOrganisationTransactionReference; + } + + public ResponseReversal originalTransactionReference(String originalTransactionReference) { + this.originalTransactionReference = originalTransactionReference; + return this; + } + + /** + * For reversals and refunds, this field indicates the transaction which is the subject of the reversal. + * @return originalTransactionReference + **/ + @Schema(required = true, description = "For reversals and refunds, this field indicates the transaction which is the subject of the reversal.") + @NotNull + + @Size(max=256) public String getOriginalTransactionReference() { + return originalTransactionReference; + } + + public void setOriginalTransactionReference(String originalTransactionReference) { + this.originalTransactionReference = originalTransactionReference; + } + + public ResponseReversal creditParty(DebitPartyArray creditParty) { + this.creditParty = creditParty; + return this; + } + + /** + * Get creditParty + * @return creditParty + **/ + @Schema(description = "") + + @Valid + public DebitPartyArray getCreditParty() { + return creditParty; + } + + public void setCreditParty(DebitPartyArray creditParty) { + this.creditParty = creditParty; + } + + public ResponseReversal debitParty(DebitPartyArray debitParty) { + this.debitParty = debitParty; + return this; + } + + /** + * Get debitParty + * @return debitParty + **/ + @Schema(description = "") + + @Valid + public DebitPartyArray getDebitParty() { + return debitParty; + } + + public void setDebitParty(DebitPartyArray debitParty) { + this.debitParty = debitParty; + } + + public ResponseReversal type(TypeReversal type) { + this.type = type; + return this; + } + + /** + * Get type + * @return type + **/ + @Schema(required = true, description = "") + @NotNull + + @Valid + public TypeReversal getType() { + return type; + } + + public void setType(TypeReversal type) { + this.type = type; + } + + public ResponseReversal subType(String subType) { + this.subType = subType; + return this; + } + + /** + * A non-harmonised sub-classification of the type of transaction. Values are not fixed, and usage will vary according to Provider. + * @return subType + **/ + @Schema(description = "A non-harmonised sub-classification of the type of transaction. Values are not fixed, and usage will vary according to Provider.") + + @Size(max=256) public String getSubType() { + return subType; + } + + public void setSubType(String subType) { + this.subType = subType; + } + + public ResponseReversal transactionStatus(String transactionStatus) { + this.transactionStatus = transactionStatus; + return this; + } + + /** + * Indicates the status of the transaction as stored by the API provider. + * @return transactionStatus + **/ + @Schema(required = true, description = "Indicates the status of the transaction as stored by the API provider.") + @NotNull + + @Size(min=1,max=256) public String getTransactionStatus() { + return transactionStatus; + } + + public void setTransactionStatus(String transactionStatus) { + this.transactionStatus = transactionStatus; + } + + public ResponseReversal amount(String amount) { + this.amount = amount; + return this; + } + + /** + * Get amount + * @return amount + **/ + @Schema(example = "15.21", description = "") + + @Pattern(regexp="^([0]|([1-9][0-9]{0,17}))([.][0-9]{0,3}[0-9])?$") @Size(min=1,max=23) public String getAmount() { + return amount; + } + + public void setAmount(String amount) { + this.amount = amount; + } + + public ResponseReversal currency(Currency currency) { + this.currency = currency; + return this; + } + + /** + * Get currency + * @return currency + **/ + @Schema(description = "") + + @Valid + public Currency getCurrency() { + return currency; + } + + public void setCurrency(Currency currency) { + this.currency = currency; + } + + public ResponseReversal descriptionText(String descriptionText) { + this.descriptionText = descriptionText; + return this; + } + + /** + * Free format text description of the transaction provided by the client. This can be provided as a reference for the receiver on a notification SMS and on an account statement. + * @return descriptionText + **/ + @Schema(description = "Free format text description of the transaction provided by the client. This can be provided as a reference for the receiver on a notification SMS and on an account statement.") + + @Size(max=160) public String getDescriptionText() { + return descriptionText; + } + + public void setDescriptionText(String descriptionText) { + this.descriptionText = descriptionText; + } + + public ResponseReversal fees(FeesArray fees) { + this.fees = fees; + return this; + } + + /** + * Get fees + * @return fees + **/ + @Schema(description = "") + + @Valid + public FeesArray getFees() { + return fees; + } + + public void setFees(FeesArray fees) { + this.fees = fees; + } + + public ResponseReversal geoCode(String geoCode) { + this.geoCode = geoCode; + return this; + } + + /** + * Indicates the geographic location from where the transaction was initiated. + * @return geoCode + **/ + @Schema(example = "37.423825,-122.082900", description = "Indicates the geographic location from where the transaction was initiated.") + + @Pattern(regexp="^(-?(90|(\\d|[1-8]\\d)(\\.\\d{1,6}){0,1}))\\,{1}(-?(180|(\\d|\\d\\d|1[0-7]\\d)(\\.\\d{1,6}){0,1}))$") @Size(max=256) public String getGeoCode() { + return geoCode; + } + + public void setGeoCode(String geoCode) { + this.geoCode = geoCode; + } + + public ResponseReversal requestingOrganisation(RequestingOrganisation requestingOrganisation) { + this.requestingOrganisation = requestingOrganisation; + return this; + } + + /** + * Get requestingOrganisation + * @return requestingOrganisation + **/ + @Schema(description = "") + + @Valid + public RequestingOrganisation getRequestingOrganisation() { + return requestingOrganisation; + } + + public void setRequestingOrganisation(RequestingOrganisation requestingOrganisation) { + this.requestingOrganisation = requestingOrganisation; + } + + public ResponseReversal servicingIdentity(String servicingIdentity) { + this.servicingIdentity = servicingIdentity; + return this; + } + + /** + * The field is used to identify the servicing identity for transactions, e.g. till, POS ID, assistant ID. + * @return servicingIdentity + **/ + @Schema(description = "The field is used to identify the servicing identity for transactions, e.g. till, POS ID, assistant ID.") + + @Size(max=256) public String getServicingIdentity() { + return servicingIdentity; + } + + public void setServicingIdentity(String servicingIdentity) { + this.servicingIdentity = servicingIdentity; + } + + public ResponseReversal transactionReceipt(String transactionReceipt) { + this.transactionReceipt = transactionReceipt; + return this; + } + + /** + * Transaction receipt number as notified to the parties. This may differ from the Transaction Reference. + * @return transactionReceipt + **/ + @Schema(description = "Transaction receipt number as notified to the parties. This may differ from the Transaction Reference.") + + @Size(max=256) public String getTransactionReceipt() { + return transactionReceipt; + } + + public void setTransactionReceipt(String transactionReceipt) { + this.transactionReceipt = transactionReceipt; + } + + public ResponseReversal creationDate(OffsetDateTime creationDate) { + this.creationDate = creationDate; + return this; + } + + /** + * Date and time when the object was created by the API Provider. + * @return creationDate + **/ + @Schema(description = "Date and time when the object was created by the API Provider.") + + @Valid + public OffsetDateTime getCreationDate() { + return creationDate; + } + + public void setCreationDate(OffsetDateTime creationDate) { + this.creationDate = creationDate; + } + + public ResponseReversal modificationDate(OffsetDateTime modificationDate) { + this.modificationDate = modificationDate; + return this; + } + + /** + * Date and time when the object was modified by the API Provider. + * @return modificationDate + **/ + @Schema(description = "Date and time when the object was modified by the API Provider.") + + @Valid + public OffsetDateTime getModificationDate() { + return modificationDate; + } + + public void setModificationDate(OffsetDateTime modificationDate) { + this.modificationDate = modificationDate; + } + + public ResponseReversal requestDate(OffsetDateTime requestDate) { + this.requestDate = requestDate; + return this; + } + + /** + * The date and time of the request as supplied by the client. + * @return requestDate + **/ + @Schema(description = "The date and time of the request as supplied by the client.") + + @Valid + public OffsetDateTime getRequestDate() { + return requestDate; + } + + public void setRequestDate(OffsetDateTime requestDate) { + this.requestDate = requestDate; + } + + public ResponseReversal customData(CustomDataArray customData) { + this.customData = customData; + return this; + } + + /** + * Get customData + * @return customData + **/ + @Schema(description = "") + + @Valid + public CustomDataArray getCustomData() { + return customData; + } + + public void setCustomData(CustomDataArray customData) { + this.customData = customData; + } + + public ResponseReversal metadata(MetadataArray metadata) { + this.metadata = metadata; + return this; + } + + /** + * Get metadata + * @return metadata + **/ + @Schema(description = "") + + @Valid + public MetadataArray getMetadata() { + return metadata; + } + + public void setMetadata(MetadataArray metadata) { + this.metadata = metadata; + } + + public ResponseReversal dateCreated(OffsetDateTime dateCreated) { + this.dateCreated = dateCreated; + return this; + } + + /** + * Date and time when the object was created by the API Provider. + * @return dateCreated + **/ + @Schema(description = "Date and time when the object was created by the API Provider.") + + @Valid + public OffsetDateTime getDateCreated() { + return dateCreated; + } + + public void setDateCreated(OffsetDateTime dateCreated) { + this.dateCreated = dateCreated; + } + + public ResponseReversal dateModified(OffsetDateTime dateModified) { + this.dateModified = dateModified; + return this; + } + + /** + * Date and time when the object was modified by the API Provider. + * @return dateModified + **/ + @Schema(description = "Date and time when the object was modified by the API Provider.") + + @Valid + public OffsetDateTime getDateModified() { + return dateModified; + } + + public void setDateModified(OffsetDateTime dateModified) { + this.dateModified = dateModified; + } + + public ResponseReversal receivingLei(String receivingLei) { + this.receivingLei = receivingLei; + return this; + } + + /** + * Legal Entity Identifier of the organisation that is receiving the transaction. + * @return receivingLei + **/ + @Schema(description = "Legal Entity Identifier of the organisation that is receiving the transaction.") + + @Pattern(regexp="^[A-Z0-9]{4}00[A-Z0-9]{12}\\d{2}$") @Size(max=20) public String getReceivingLei() { + return receivingLei; + } + + public void setReceivingLei(String receivingLei) { + this.receivingLei = receivingLei; + } + + public ResponseReversal requestingLei(String requestingLei) { + this.requestingLei = requestingLei; + return this; + } + + /** + * Legal Entity Identifier of the organisation that is requesting the transaction. + * @return requestingLei + **/ + @Schema(description = "Legal Entity Identifier of the organisation that is requesting the transaction.") + + @Pattern(regexp="^[A-Z0-9]{4}00[A-Z0-9]{12}\\d{2}$") @Size(max=20) public String getRequestingLei() { + return requestingLei; + } + + public void setRequestingLei(String requestingLei) { + this.requestingLei = requestingLei; + } + + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + ResponseReversal responseReversal = (ResponseReversal) o; + return Objects.equals(this.transactionReference, responseReversal.transactionReference) && + Objects.equals(this.requestingOrganisationTransactionReference, responseReversal.requestingOrganisationTransactionReference) && + Objects.equals(this.originalTransactionReference, responseReversal.originalTransactionReference) && + Objects.equals(this.creditParty, responseReversal.creditParty) && + Objects.equals(this.debitParty, responseReversal.debitParty) && + Objects.equals(this.type, responseReversal.type) && + Objects.equals(this.subType, responseReversal.subType) && + Objects.equals(this.transactionStatus, responseReversal.transactionStatus) && + Objects.equals(this.amount, responseReversal.amount) && + Objects.equals(this.currency, responseReversal.currency) && + Objects.equals(this.descriptionText, responseReversal.descriptionText) && + Objects.equals(this.fees, responseReversal.fees) && + Objects.equals(this.geoCode, responseReversal.geoCode) && + Objects.equals(this.requestingOrganisation, responseReversal.requestingOrganisation) && + Objects.equals(this.servicingIdentity, responseReversal.servicingIdentity) && + Objects.equals(this.transactionReceipt, responseReversal.transactionReceipt) && + Objects.equals(this.creationDate, responseReversal.creationDate) && + Objects.equals(this.modificationDate, responseReversal.modificationDate) && + Objects.equals(this.requestDate, responseReversal.requestDate) && + Objects.equals(this.customData, responseReversal.customData) && + Objects.equals(this.metadata, responseReversal.metadata) && + Objects.equals(this.dateCreated, responseReversal.dateCreated) && + Objects.equals(this.dateModified, responseReversal.dateModified) && + Objects.equals(this.receivingLei, responseReversal.receivingLei) && + Objects.equals(this.requestingLei, responseReversal.requestingLei); + } + + @Override + public int hashCode() { + return Objects.hash(transactionReference, requestingOrganisationTransactionReference, originalTransactionReference, creditParty, debitParty, type, subType, transactionStatus, amount, currency, descriptionText, fees, geoCode, requestingOrganisation, servicingIdentity, transactionReceipt, creationDate, modificationDate, requestDate, customData, metadata, dateCreated, dateModified, receivingLei, requestingLei); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class ResponseReversal {\n"); + + sb.append(" transactionReference: ").append(toIndentedString(transactionReference)).append("\n"); + sb.append(" requestingOrganisationTransactionReference: ").append(toIndentedString(requestingOrganisationTransactionReference)).append("\n"); + sb.append(" originalTransactionReference: ").append(toIndentedString(originalTransactionReference)).append("\n"); + sb.append(" creditParty: ").append(toIndentedString(creditParty)).append("\n"); + sb.append(" debitParty: ").append(toIndentedString(debitParty)).append("\n"); + sb.append(" type: ").append(toIndentedString(type)).append("\n"); + sb.append(" subType: ").append(toIndentedString(subType)).append("\n"); + sb.append(" transactionStatus: ").append(toIndentedString(transactionStatus)).append("\n"); + sb.append(" amount: ").append(toIndentedString(amount)).append("\n"); + sb.append(" currency: ").append(toIndentedString(currency)).append("\n"); + sb.append(" descriptionText: ").append(toIndentedString(descriptionText)).append("\n"); + sb.append(" fees: ").append(toIndentedString(fees)).append("\n"); + sb.append(" geoCode: ").append(toIndentedString(geoCode)).append("\n"); + sb.append(" requestingOrganisation: ").append(toIndentedString(requestingOrganisation)).append("\n"); + sb.append(" servicingIdentity: ").append(toIndentedString(servicingIdentity)).append("\n"); + sb.append(" transactionReceipt: ").append(toIndentedString(transactionReceipt)).append("\n"); + sb.append(" creationDate: ").append(toIndentedString(creationDate)).append("\n"); + sb.append(" modificationDate: ").append(toIndentedString(modificationDate)).append("\n"); + sb.append(" requestDate: ").append(toIndentedString(requestDate)).append("\n"); + sb.append(" customData: ").append(toIndentedString(customData)).append("\n"); + sb.append(" metadata: ").append(toIndentedString(metadata)).append("\n"); + sb.append(" dateCreated: ").append(toIndentedString(dateCreated)).append("\n"); + sb.append(" dateModified: ").append(toIndentedString(dateModified)).append("\n"); + sb.append(" receivingLei: ").append(toIndentedString(receivingLei)).append("\n"); + sb.append(" requestingLei: ").append(toIndentedString(requestingLei)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/ResponseStatementEntries.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/ResponseStatementEntries.java new file mode 100644 index 000000000..2f3dfb496 --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/ResponseStatementEntries.java @@ -0,0 +1,433 @@ +package org.mifos.connector.gsmastub.model; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import org.springframework.validation.annotation.Validated; +import org.threeten.bp.OffsetDateTime; + +import javax.validation.Valid; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Pattern; +import javax.validation.constraints.Size; +import java.util.Objects; + +/** + * ResponseStatementEntries + */ +@Validated +@javax.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.SpringCodegen", date = "2022-09-27T11:46:46.417Z[GMT]") + + +public class ResponseStatementEntries { + @JsonProperty("transactionReference") + private String transactionReference = null; + + @JsonProperty("creditParty") + private CreditPartyArray creditParty = null; + + @JsonProperty("debitParty") + private DebitPartyArray debitParty = null; + + @JsonProperty("transactionStatus") + private String transactionStatus = null; + + @JsonProperty("amount") + private String amount = null; + + @JsonProperty("currency") + private Currency currency = null; + + @JsonProperty("descriptionText") + private String descriptionText = null; + + @JsonProperty("displayType") + private String displayType = null; + + @JsonProperty("transactionReceipt") + private String transactionReceipt = null; + + @JsonProperty("creationDate") + private OffsetDateTime creationDate = null; + + @JsonProperty("modificationDate") + private OffsetDateTime modificationDate = null; + + @JsonProperty("requestDate") + private OffsetDateTime requestDate = null; + + @JsonProperty("customData") + private CustomDataArray customData = null; + + @JsonProperty("dateCreated") + private OffsetDateTime dateCreated = null; + + @JsonProperty("dateModified") + private OffsetDateTime dateModified = null; + + public ResponseStatementEntries transactionReference(String transactionReference) { + this.transactionReference = transactionReference; + return this; + } + + /** + * Unique reference for the transaction. This is returned in the response by API provider. + * @return transactionReference + **/ + @Schema(required = true, description = "Unique reference for the transaction. This is returned in the response by API provider.") + @NotNull + + @Size(min=1,max=256) public String getTransactionReference() { + return transactionReference; + } + + public void setTransactionReference(String transactionReference) { + this.transactionReference = transactionReference; + } + + public ResponseStatementEntries creditParty(CreditPartyArray creditParty) { + this.creditParty = creditParty; + return this; + } + + /** + * Get creditParty + * @return creditParty + **/ + @Schema(required = true, description = "") + @NotNull + + @Valid + public CreditPartyArray getCreditParty() { + return creditParty; + } + + public void setCreditParty(CreditPartyArray creditParty) { + this.creditParty = creditParty; + } + + public ResponseStatementEntries debitParty(DebitPartyArray debitParty) { + this.debitParty = debitParty; + return this; + } + + /** + * Get debitParty + * @return debitParty + **/ + @Schema(required = true, description = "") + @NotNull + + @Valid + public DebitPartyArray getDebitParty() { + return debitParty; + } + + public void setDebitParty(DebitPartyArray debitParty) { + this.debitParty = debitParty; + } + + public ResponseStatementEntries transactionStatus(String transactionStatus) { + this.transactionStatus = transactionStatus; + return this; + } + + /** + * Indicates the status of the transaction as stored by the API provider. + * @return transactionStatus + **/ + @Schema(required = true, description = "Indicates the status of the transaction as stored by the API provider.") + @NotNull + + @Size(min=1,max=256) public String getTransactionStatus() { + return transactionStatus; + } + + public void setTransactionStatus(String transactionStatus) { + this.transactionStatus = transactionStatus; + } + + public ResponseStatementEntries amount(String amount) { + this.amount = amount; + return this; + } + + /** + * Get amount + * @return amount + **/ + @Schema(example = "15.21", required = true, description = "") + @NotNull + + @Pattern(regexp="^([0]|([1-9][0-9]{0,17}))([.][0-9]{0,3}[0-9])?$") @Size(min=1,max=23) public String getAmount() { + return amount; + } + + public void setAmount(String amount) { + this.amount = amount; + } + + public ResponseStatementEntries currency(Currency currency) { + this.currency = currency; + return this; + } + + /** + * Get currency + * @return currency + **/ + @Schema(required = true, description = "") + @NotNull + + @Valid + public Currency getCurrency() { + return currency; + } + + public void setCurrency(Currency currency) { + this.currency = currency; + } + + public ResponseStatementEntries descriptionText(String descriptionText) { + this.descriptionText = descriptionText; + return this; + } + + /** + * Free format text description of the transaction provided by the client. This can be provided as a reference for the receiver on a notification SMS and on an account statement. + * @return descriptionText + **/ + @Schema(description = "Free format text description of the transaction provided by the client. This can be provided as a reference for the receiver on a notification SMS and on an account statement.") + + @Size(max=160) public String getDescriptionText() { + return descriptionText; + } + + public void setDescriptionText(String descriptionText) { + this.descriptionText = descriptionText; + } + + public ResponseStatementEntries displayType(String displayType) { + this.displayType = displayType; + return this; + } + + /** + * The transaction type that is to be used for presentation to the account holder as determined by the API provider. This is not necessarily the actual transaction type. + * @return displayType + **/ + @Schema(description = "The transaction type that is to be used for presentation to the account holder as determined by the API provider. This is not necessarily the actual transaction type.") + + @Size(max=256) public String getDisplayType() { + return displayType; + } + + public void setDisplayType(String displayType) { + this.displayType = displayType; + } + + public ResponseStatementEntries transactionReceipt(String transactionReceipt) { + this.transactionReceipt = transactionReceipt; + return this; + } + + /** + * Transaction receipt number as notified to the parties. This may differ from the Transaction Reference. + * @return transactionReceipt + **/ + @Schema(description = "Transaction receipt number as notified to the parties. This may differ from the Transaction Reference.") + + @Size(max=256) public String getTransactionReceipt() { + return transactionReceipt; + } + + public void setTransactionReceipt(String transactionReceipt) { + this.transactionReceipt = transactionReceipt; + } + + public ResponseStatementEntries creationDate(OffsetDateTime creationDate) { + this.creationDate = creationDate; + return this; + } + + /** + * Date and time when the object was created by the API Provider. + * @return creationDate + **/ + @Schema(description = "Date and time when the object was created by the API Provider.") + + @Valid + public OffsetDateTime getCreationDate() { + return creationDate; + } + + public void setCreationDate(OffsetDateTime creationDate) { + this.creationDate = creationDate; + } + + public ResponseStatementEntries modificationDate(OffsetDateTime modificationDate) { + this.modificationDate = modificationDate; + return this; + } + + /** + * Date and time when the object was modified by the API Provider. + * @return modificationDate + **/ + @Schema(description = "Date and time when the object was modified by the API Provider.") + + @Valid + public OffsetDateTime getModificationDate() { + return modificationDate; + } + + public void setModificationDate(OffsetDateTime modificationDate) { + this.modificationDate = modificationDate; + } + + public ResponseStatementEntries requestDate(OffsetDateTime requestDate) { + this.requestDate = requestDate; + return this; + } + + /** + * The date and time of the request as supplied by the client. + * @return requestDate + **/ + @Schema(description = "The date and time of the request as supplied by the client.") + + @Valid + public OffsetDateTime getRequestDate() { + return requestDate; + } + + public void setRequestDate(OffsetDateTime requestDate) { + this.requestDate = requestDate; + } + + public ResponseStatementEntries customData(CustomDataArray customData) { + this.customData = customData; + return this; + } + + /** + * Get customData + * @return customData + **/ + @Schema(description = "") + + @Valid + public CustomDataArray getCustomData() { + return customData; + } + + public void setCustomData(CustomDataArray customData) { + this.customData = customData; + } + + public ResponseStatementEntries dateCreated(OffsetDateTime dateCreated) { + this.dateCreated = dateCreated; + return this; + } + + /** + * Date and time when the object was created by the API Provider. + * @return dateCreated + **/ + @Schema(description = "Date and time when the object was created by the API Provider.") + + @Valid + public OffsetDateTime getDateCreated() { + return dateCreated; + } + + public void setDateCreated(OffsetDateTime dateCreated) { + this.dateCreated = dateCreated; + } + + public ResponseStatementEntries dateModified(OffsetDateTime dateModified) { + this.dateModified = dateModified; + return this; + } + + /** + * Date and time when the object was modified by the API Provider. + * @return dateModified + **/ + @Schema(description = "Date and time when the object was modified by the API Provider.") + + @Valid + public OffsetDateTime getDateModified() { + return dateModified; + } + + public void setDateModified(OffsetDateTime dateModified) { + this.dateModified = dateModified; + } + + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + ResponseStatementEntries responseStatementEntries = (ResponseStatementEntries) o; + return Objects.equals(this.transactionReference, responseStatementEntries.transactionReference) && + Objects.equals(this.creditParty, responseStatementEntries.creditParty) && + Objects.equals(this.debitParty, responseStatementEntries.debitParty) && + Objects.equals(this.transactionStatus, responseStatementEntries.transactionStatus) && + Objects.equals(this.amount, responseStatementEntries.amount) && + Objects.equals(this.currency, responseStatementEntries.currency) && + Objects.equals(this.descriptionText, responseStatementEntries.descriptionText) && + Objects.equals(this.displayType, responseStatementEntries.displayType) && + Objects.equals(this.transactionReceipt, responseStatementEntries.transactionReceipt) && + Objects.equals(this.creationDate, responseStatementEntries.creationDate) && + Objects.equals(this.modificationDate, responseStatementEntries.modificationDate) && + Objects.equals(this.requestDate, responseStatementEntries.requestDate) && + Objects.equals(this.customData, responseStatementEntries.customData) && + Objects.equals(this.dateCreated, responseStatementEntries.dateCreated) && + Objects.equals(this.dateModified, responseStatementEntries.dateModified); + } + + @Override + public int hashCode() { + return Objects.hash(transactionReference, creditParty, debitParty, transactionStatus, amount, currency, descriptionText, displayType, transactionReceipt, creationDate, modificationDate, requestDate, customData, dateCreated, dateModified); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class ResponseStatementEntries {\n"); + + sb.append(" transactionReference: ").append(toIndentedString(transactionReference)).append("\n"); + sb.append(" creditParty: ").append(toIndentedString(creditParty)).append("\n"); + sb.append(" debitParty: ").append(toIndentedString(debitParty)).append("\n"); + sb.append(" transactionStatus: ").append(toIndentedString(transactionStatus)).append("\n"); + sb.append(" amount: ").append(toIndentedString(amount)).append("\n"); + sb.append(" currency: ").append(toIndentedString(currency)).append("\n"); + sb.append(" descriptionText: ").append(toIndentedString(descriptionText)).append("\n"); + sb.append(" displayType: ").append(toIndentedString(displayType)).append("\n"); + sb.append(" transactionReceipt: ").append(toIndentedString(transactionReceipt)).append("\n"); + sb.append(" creationDate: ").append(toIndentedString(creationDate)).append("\n"); + sb.append(" modificationDate: ").append(toIndentedString(modificationDate)).append("\n"); + sb.append(" requestDate: ").append(toIndentedString(requestDate)).append("\n"); + sb.append(" customData: ").append(toIndentedString(customData)).append("\n"); + sb.append(" dateCreated: ").append(toIndentedString(dateCreated)).append("\n"); + sb.append(" dateModified: ").append(toIndentedString(dateModified)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/ResponseTransaction.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/ResponseTransaction.java new file mode 100644 index 000000000..d0594cb55 --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/ResponseTransaction.java @@ -0,0 +1,777 @@ +package org.mifos.connector.gsmastub.model; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import org.springframework.validation.annotation.Validated; +import org.threeten.bp.OffsetDateTime; + +import javax.validation.Valid; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Pattern; +import javax.validation.constraints.Size; +import java.util.Objects; + +/** + * ResponseTransaction + */ +@Validated +@javax.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.SpringCodegen", date = "2022-09-27T11:46:46.417Z[GMT]") + + +public class ResponseTransaction { + @JsonProperty("transactionReference") + private String transactionReference = null; + + @JsonProperty("originalTransactionReference") + private String originalTransactionReference = null; + + @JsonProperty("requestingOrganisationTransactionReference") + private String requestingOrganisationTransactionReference = null; + + @JsonProperty("creditParty") + private CreditPartyArray creditParty = null; + + @JsonProperty("debitParty") + private DebitPartyArray debitParty = null; + + @JsonProperty("type") + private Type type = null; + + @JsonProperty("subType") + private String subType = null; + + @JsonProperty("transactionStatus") + private String transactionStatus = null; + + @JsonProperty("amount") + private String amount = null; + + @JsonProperty("currency") + private Currency currency = null; + + @JsonProperty("descriptionText") + private String descriptionText = null; + + @JsonProperty("fees") + private FeesArray fees = null; + + @JsonProperty("geoCode") + private String geoCode = null; + + @JsonProperty("internationalTransferInformation") + private InternationalTransferInformationResponse internationalTransferInformation = null; + + @JsonProperty("oneTimeCode") + private String oneTimeCode = null; + + @JsonProperty("recipientKyc") + private Kyc recipientKyc = null; + + @JsonProperty("senderKyc") + private Kyc senderKyc = null; + + @JsonProperty("requestingOrganisation") + private RequestingOrganisation requestingOrganisation = null; + + @JsonProperty("servicingIdentity") + private String servicingIdentity = null; + + @JsonProperty("transactionReceipt") + private String transactionReceipt = null; + + @JsonProperty("creationDate") + private OffsetDateTime creationDate = null; + + @JsonProperty("modificationDate") + private OffsetDateTime modificationDate = null; + + @JsonProperty("requestDate") + private OffsetDateTime requestDate = null; + + @JsonProperty("customData") + private CustomDataArray customData = null; + + @JsonProperty("metadata") + private MetadataArray metadata = null; + + @JsonProperty("dateCreated") + private OffsetDateTime dateCreated = null; + + @JsonProperty("dateModified") + private OffsetDateTime dateModified = null; + + @JsonProperty("receivingLei") + private String receivingLei = null; + + @JsonProperty("requestingLei") + private String requestingLei = null; + + public ResponseTransaction transactionReference(String transactionReference) { + this.transactionReference = transactionReference; + return this; + } + + /** + * Unique reference for the transaction. This is returned in the response by API provider. + * @return transactionReference + **/ + @Schema(required = true, description = "Unique reference for the transaction. This is returned in the response by API provider.") + @NotNull + + @Size(min=1,max=256) public String getTransactionReference() { + return transactionReference; + } + + public void setTransactionReference(String transactionReference) { + this.transactionReference = transactionReference; + } + + public ResponseTransaction originalTransactionReference(String originalTransactionReference) { + this.originalTransactionReference = originalTransactionReference; + return this; + } + + /** + * For reversals and refunds, this field indicates the transaction which is the subject of the reversal. + * @return originalTransactionReference + **/ + @Schema(description = "For reversals and refunds, this field indicates the transaction which is the subject of the reversal.") + + @Size(max=256) public String getOriginalTransactionReference() { + return originalTransactionReference; + } + + public void setOriginalTransactionReference(String originalTransactionReference) { + this.originalTransactionReference = originalTransactionReference; + } + + public ResponseTransaction requestingOrganisationTransactionReference(String requestingOrganisationTransactionReference) { + this.requestingOrganisationTransactionReference = requestingOrganisationTransactionReference; + return this; + } + + /** + * A reference provided by the requesting organisation that is to be associated with the transaction. + * @return requestingOrganisationTransactionReference + **/ + @Schema(description = "A reference provided by the requesting organisation that is to be associated with the transaction.") + + @Size(max=256) public String getRequestingOrganisationTransactionReference() { + return requestingOrganisationTransactionReference; + } + + public void setRequestingOrganisationTransactionReference(String requestingOrganisationTransactionReference) { + this.requestingOrganisationTransactionReference = requestingOrganisationTransactionReference; + } + + public ResponseTransaction creditParty(CreditPartyArray creditParty) { + this.creditParty = creditParty; + return this; + } + + /** + * Get creditParty + * @return creditParty + **/ + @Schema(required = true, description = "") + @NotNull + + @Valid + public CreditPartyArray getCreditParty() { + return creditParty; + } + + public void setCreditParty(CreditPartyArray creditParty) { + this.creditParty = creditParty; + } + + public ResponseTransaction debitParty(DebitPartyArray debitParty) { + this.debitParty = debitParty; + return this; + } + + /** + * Get debitParty + * @return debitParty + **/ + @Schema(required = true, description = "") + @NotNull + + @Valid + public DebitPartyArray getDebitParty() { + return debitParty; + } + + public void setDebitParty(DebitPartyArray debitParty) { + this.debitParty = debitParty; + } + + public ResponseTransaction type(Type type) { + this.type = type; + return this; + } + + /** + * Get type + * @return type + **/ + @Schema(required = true, description = "") + @NotNull + + @Valid + public Type getType() { + return type; + } + + public void setType(Type type) { + this.type = type; + } + + public ResponseTransaction subType(String subType) { + this.subType = subType; + return this; + } + + /** + * A non-harmonised sub-classification of the type of transaction. Values are not fixed, and usage will vary according to Provider. + * @return subType + **/ + @Schema(description = "A non-harmonised sub-classification of the type of transaction. Values are not fixed, and usage will vary according to Provider.") + + @Size(max=256) public String getSubType() { + return subType; + } + + public void setSubType(String subType) { + this.subType = subType; + } + + public ResponseTransaction transactionStatus(String transactionStatus) { + this.transactionStatus = transactionStatus; + return this; + } + + /** + * Indicates the status of the transaction as stored by the API provider. + * @return transactionStatus + **/ + @Schema(required = true, description = "Indicates the status of the transaction as stored by the API provider.") + @NotNull + + @Size(min=1,max=256) public String getTransactionStatus() { + return transactionStatus; + } + + public void setTransactionStatus(String transactionStatus) { + this.transactionStatus = transactionStatus; + } + + public ResponseTransaction amount(String amount) { + this.amount = amount; + return this; + } + + /** + * Get amount + * @return amount + **/ + @Schema(example = "15.21", required = true, description = "") + @NotNull + + @Pattern(regexp="^([0]|([1-9][0-9]{0,17}))([.][0-9]{0,3}[0-9])?$") @Size(min=1,max=23) public String getAmount() { + return amount; + } + + public void setAmount(String amount) { + this.amount = amount; + } + + public ResponseTransaction currency(Currency currency) { + this.currency = currency; + return this; + } + + /** + * Get currency + * @return currency + **/ + @Schema(required = true, description = "") + @NotNull + + @Valid + public Currency getCurrency() { + return currency; + } + + public void setCurrency(Currency currency) { + this.currency = currency; + } + + public ResponseTransaction descriptionText(String descriptionText) { + this.descriptionText = descriptionText; + return this; + } + + /** + * Free format text description of the transaction provided by the client. This can be provided as a reference for the receiver on a notification SMS and on an account statement. + * @return descriptionText + **/ + @Schema(description = "Free format text description of the transaction provided by the client. This can be provided as a reference for the receiver on a notification SMS and on an account statement.") + + @Size(max=160) public String getDescriptionText() { + return descriptionText; + } + + public void setDescriptionText(String descriptionText) { + this.descriptionText = descriptionText; + } + + public ResponseTransaction fees(FeesArray fees) { + this.fees = fees; + return this; + } + + /** + * Get fees + * @return fees + **/ + @Schema(description = "") + + @Valid + public FeesArray getFees() { + return fees; + } + + public void setFees(FeesArray fees) { + this.fees = fees; + } + + public ResponseTransaction geoCode(String geoCode) { + this.geoCode = geoCode; + return this; + } + + /** + * Indicates the geographic location from where the transaction was initiated. + * @return geoCode + **/ + @Schema(example = "37.423825,-122.082900", description = "Indicates the geographic location from where the transaction was initiated.") + + @Pattern(regexp="^(-?(90|(\\d|[1-8]\\d)(\\.\\d{1,6}){0,1}))\\,{1}(-?(180|(\\d|\\d\\d|1[0-7]\\d)(\\.\\d{1,6}){0,1}))$") @Size(max=256) public String getGeoCode() { + return geoCode; + } + + public void setGeoCode(String geoCode) { + this.geoCode = geoCode; + } + + public ResponseTransaction internationalTransferInformation(InternationalTransferInformationResponse internationalTransferInformation) { + this.internationalTransferInformation = internationalTransferInformation; + return this; + } + + /** + * Get internationalTransferInformation + * @return internationalTransferInformation + **/ + @Schema(description = "") + + @Valid + public InternationalTransferInformationResponse getInternationalTransferInformation() { + return internationalTransferInformation; + } + + public void setInternationalTransferInformation(InternationalTransferInformationResponse internationalTransferInformation) { + this.internationalTransferInformation = internationalTransferInformation; + } + + public ResponseTransaction oneTimeCode(String oneTimeCode) { + this.oneTimeCode = oneTimeCode; + return this; + } + + /** + * A one-time code that can be supplied in the request or can be generated in the response depending upon the use case. An authorisation code can be supplied in this field for requests that have been pre-authorised. + * @return oneTimeCode + **/ + @Schema(description = "A one-time code that can be supplied in the request or can be generated in the response depending upon the use case. An authorisation code can be supplied in this field for requests that have been pre-authorised.") + + @Size(max=256) public String getOneTimeCode() { + return oneTimeCode; + } + + public void setOneTimeCode(String oneTimeCode) { + this.oneTimeCode = oneTimeCode; + } + + public ResponseTransaction recipientKyc(Kyc recipientKyc) { + this.recipientKyc = recipientKyc; + return this; + } + + /** + * Get recipientKyc + * @return recipientKyc + **/ + @Schema(description = "") + + @Valid + public Kyc getRecipientKyc() { + return recipientKyc; + } + + public void setRecipientKyc(Kyc recipientKyc) { + this.recipientKyc = recipientKyc; + } + + public ResponseTransaction senderKyc(Kyc senderKyc) { + this.senderKyc = senderKyc; + return this; + } + + /** + * Get senderKyc + * @return senderKyc + **/ + @Schema(description = "") + + @Valid + public Kyc getSenderKyc() { + return senderKyc; + } + + public void setSenderKyc(Kyc senderKyc) { + this.senderKyc = senderKyc; + } + + public ResponseTransaction requestingOrganisation(RequestingOrganisation requestingOrganisation) { + this.requestingOrganisation = requestingOrganisation; + return this; + } + + /** + * Get requestingOrganisation + * @return requestingOrganisation + **/ + @Schema(description = "") + + @Valid + public RequestingOrganisation getRequestingOrganisation() { + return requestingOrganisation; + } + + public void setRequestingOrganisation(RequestingOrganisation requestingOrganisation) { + this.requestingOrganisation = requestingOrganisation; + } + + public ResponseTransaction servicingIdentity(String servicingIdentity) { + this.servicingIdentity = servicingIdentity; + return this; + } + + /** + * The field is used to identify the servicing identity for transactions, e.g. till, POS ID, assistant ID. + * @return servicingIdentity + **/ + @Schema(description = "The field is used to identify the servicing identity for transactions, e.g. till, POS ID, assistant ID.") + + @Size(max=256) public String getServicingIdentity() { + return servicingIdentity; + } + + public void setServicingIdentity(String servicingIdentity) { + this.servicingIdentity = servicingIdentity; + } + + public ResponseTransaction transactionReceipt(String transactionReceipt) { + this.transactionReceipt = transactionReceipt; + return this; + } + + /** + * Transaction receipt number as notified to the parties. This may differ from the Transaction Reference. + * @return transactionReceipt + **/ + @Schema(description = "Transaction receipt number as notified to the parties. This may differ from the Transaction Reference.") + + @Size(max=256) public String getTransactionReceipt() { + return transactionReceipt; + } + + public void setTransactionReceipt(String transactionReceipt) { + this.transactionReceipt = transactionReceipt; + } + + public ResponseTransaction creationDate(OffsetDateTime creationDate) { + this.creationDate = creationDate; + return this; + } + + /** + * Date and time when the object was created by the API Provider. + * @return creationDate + **/ + @Schema(description = "Date and time when the object was created by the API Provider.") + + @Valid + public OffsetDateTime getCreationDate() { + return creationDate; + } + + public void setCreationDate(OffsetDateTime creationDate) { + this.creationDate = creationDate; + } + + public ResponseTransaction modificationDate(OffsetDateTime modificationDate) { + this.modificationDate = modificationDate; + return this; + } + + /** + * Date and time when the object was modified by the API Provider. + * @return modificationDate + **/ + @Schema(description = "Date and time when the object was modified by the API Provider.") + + @Valid + public OffsetDateTime getModificationDate() { + return modificationDate; + } + + public void setModificationDate(OffsetDateTime modificationDate) { + this.modificationDate = modificationDate; + } + + public ResponseTransaction requestDate(OffsetDateTime requestDate) { + this.requestDate = requestDate; + return this; + } + + /** + * The date and time of the request as supplied by the client. + * @return requestDate + **/ + @Schema(description = "The date and time of the request as supplied by the client.") + + @Valid + public OffsetDateTime getRequestDate() { + return requestDate; + } + + public void setRequestDate(OffsetDateTime requestDate) { + this.requestDate = requestDate; + } + + public ResponseTransaction customData(CustomDataArray customData) { + this.customData = customData; + return this; + } + + /** + * Get customData + * @return customData + **/ + @Schema(description = "") + + @Valid + public CustomDataArray getCustomData() { + return customData; + } + + public void setCustomData(CustomDataArray customData) { + this.customData = customData; + } + + public ResponseTransaction metadata(MetadataArray metadata) { + this.metadata = metadata; + return this; + } + + /** + * Get metadata + * @return metadata + **/ + @Schema(description = "") + + @Valid + public MetadataArray getMetadata() { + return metadata; + } + + public void setMetadata(MetadataArray metadata) { + this.metadata = metadata; + } + + public ResponseTransaction dateCreated(OffsetDateTime dateCreated) { + this.dateCreated = dateCreated; + return this; + } + + /** + * Date and time when the object was created by the API Provider. + * @return dateCreated + **/ + @Schema(description = "Date and time when the object was created by the API Provider.") + + @Valid + public OffsetDateTime getDateCreated() { + return dateCreated; + } + + public void setDateCreated(OffsetDateTime dateCreated) { + this.dateCreated = dateCreated; + } + + public ResponseTransaction dateModified(OffsetDateTime dateModified) { + this.dateModified = dateModified; + return this; + } + + /** + * Date and time when the object was modified by the API Provider. + * @return dateModified + **/ + @Schema(description = "Date and time when the object was modified by the API Provider.") + + @Valid + public OffsetDateTime getDateModified() { + return dateModified; + } + + public void setDateModified(OffsetDateTime dateModified) { + this.dateModified = dateModified; + } + + public ResponseTransaction receivingLei(String receivingLei) { + this.receivingLei = receivingLei; + return this; + } + + /** + * Legal Entity Identifier of the organisation that is receiving the transaction. + * @return receivingLei + **/ + @Schema(description = "Legal Entity Identifier of the organisation that is receiving the transaction.") + + @Pattern(regexp="^[A-Z0-9]{4}00[A-Z0-9]{12}\\d{2}$") @Size(max=20) public String getReceivingLei() { + return receivingLei; + } + + public void setReceivingLei(String receivingLei) { + this.receivingLei = receivingLei; + } + + public ResponseTransaction requestingLei(String requestingLei) { + this.requestingLei = requestingLei; + return this; + } + + /** + * Legal Entity Identifier of the organisation that is requesting the transaction. + * @return requestingLei + **/ + @Schema(description = "Legal Entity Identifier of the organisation that is requesting the transaction.") + + @Pattern(regexp="^[A-Z0-9]{4}00[A-Z0-9]{12}\\d{2}$") @Size(max=20) public String getRequestingLei() { + return requestingLei; + } + + public void setRequestingLei(String requestingLei) { + this.requestingLei = requestingLei; + } + + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + ResponseTransaction responseTransaction = (ResponseTransaction) o; + return Objects.equals(this.transactionReference, responseTransaction.transactionReference) && + Objects.equals(this.originalTransactionReference, responseTransaction.originalTransactionReference) && + Objects.equals(this.requestingOrganisationTransactionReference, responseTransaction.requestingOrganisationTransactionReference) && + Objects.equals(this.creditParty, responseTransaction.creditParty) && + Objects.equals(this.debitParty, responseTransaction.debitParty) && + Objects.equals(this.type, responseTransaction.type) && + Objects.equals(this.subType, responseTransaction.subType) && + Objects.equals(this.transactionStatus, responseTransaction.transactionStatus) && + Objects.equals(this.amount, responseTransaction.amount) && + Objects.equals(this.currency, responseTransaction.currency) && + Objects.equals(this.descriptionText, responseTransaction.descriptionText) && + Objects.equals(this.fees, responseTransaction.fees) && + Objects.equals(this.geoCode, responseTransaction.geoCode) && + Objects.equals(this.internationalTransferInformation, responseTransaction.internationalTransferInformation) && + Objects.equals(this.oneTimeCode, responseTransaction.oneTimeCode) && + Objects.equals(this.recipientKyc, responseTransaction.recipientKyc) && + Objects.equals(this.senderKyc, responseTransaction.senderKyc) && + Objects.equals(this.requestingOrganisation, responseTransaction.requestingOrganisation) && + Objects.equals(this.servicingIdentity, responseTransaction.servicingIdentity) && + Objects.equals(this.transactionReceipt, responseTransaction.transactionReceipt) && + Objects.equals(this.creationDate, responseTransaction.creationDate) && + Objects.equals(this.modificationDate, responseTransaction.modificationDate) && + Objects.equals(this.requestDate, responseTransaction.requestDate) && + Objects.equals(this.customData, responseTransaction.customData) && + Objects.equals(this.metadata, responseTransaction.metadata) && + Objects.equals(this.dateCreated, responseTransaction.dateCreated) && + Objects.equals(this.dateModified, responseTransaction.dateModified) && + Objects.equals(this.receivingLei, responseTransaction.receivingLei) && + Objects.equals(this.requestingLei, responseTransaction.requestingLei); + } + + @Override + public int hashCode() { + return Objects.hash(transactionReference, originalTransactionReference, requestingOrganisationTransactionReference, creditParty, debitParty, type, subType, transactionStatus, amount, currency, descriptionText, fees, geoCode, internationalTransferInformation, oneTimeCode, recipientKyc, senderKyc, requestingOrganisation, servicingIdentity, transactionReceipt, creationDate, modificationDate, requestDate, customData, metadata, dateCreated, dateModified, receivingLei, requestingLei); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class ResponseTransaction {\n"); + + sb.append(" transactionReference: ").append(toIndentedString(transactionReference)).append("\n"); + sb.append(" originalTransactionReference: ").append(toIndentedString(originalTransactionReference)).append("\n"); + sb.append(" requestingOrganisationTransactionReference: ").append(toIndentedString(requestingOrganisationTransactionReference)).append("\n"); + sb.append(" creditParty: ").append(toIndentedString(creditParty)).append("\n"); + sb.append(" debitParty: ").append(toIndentedString(debitParty)).append("\n"); + sb.append(" type: ").append(toIndentedString(type)).append("\n"); + sb.append(" subType: ").append(toIndentedString(subType)).append("\n"); + sb.append(" transactionStatus: ").append(toIndentedString(transactionStatus)).append("\n"); + sb.append(" amount: ").append(toIndentedString(amount)).append("\n"); + sb.append(" currency: ").append(toIndentedString(currency)).append("\n"); + sb.append(" descriptionText: ").append(toIndentedString(descriptionText)).append("\n"); + sb.append(" fees: ").append(toIndentedString(fees)).append("\n"); + sb.append(" geoCode: ").append(toIndentedString(geoCode)).append("\n"); + sb.append(" internationalTransferInformation: ").append(toIndentedString(internationalTransferInformation)).append("\n"); + sb.append(" oneTimeCode: ").append(toIndentedString(oneTimeCode)).append("\n"); + sb.append(" recipientKyc: ").append(toIndentedString(recipientKyc)).append("\n"); + sb.append(" senderKyc: ").append(toIndentedString(senderKyc)).append("\n"); + sb.append(" requestingOrganisation: ").append(toIndentedString(requestingOrganisation)).append("\n"); + sb.append(" servicingIdentity: ").append(toIndentedString(servicingIdentity)).append("\n"); + sb.append(" transactionReceipt: ").append(toIndentedString(transactionReceipt)).append("\n"); + sb.append(" creationDate: ").append(toIndentedString(creationDate)).append("\n"); + sb.append(" modificationDate: ").append(toIndentedString(modificationDate)).append("\n"); + sb.append(" requestDate: ").append(toIndentedString(requestDate)).append("\n"); + sb.append(" customData: ").append(toIndentedString(customData)).append("\n"); + sb.append(" metadata: ").append(toIndentedString(metadata)).append("\n"); + sb.append(" dateCreated: ").append(toIndentedString(dateCreated)).append("\n"); + sb.append(" dateModified: ").append(toIndentedString(dateModified)).append("\n"); + sb.append(" receivingLei: ").append(toIndentedString(receivingLei)).append("\n"); + sb.append(" requestingLei: ").append(toIndentedString(requestingLei)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/ResponseTransactionType.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/ResponseTransactionType.java new file mode 100644 index 000000000..05a25953a --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/ResponseTransactionType.java @@ -0,0 +1,51 @@ +package org.mifos.connector.gsmastub.model; + +import org.springframework.validation.annotation.Validated; + +import java.util.Objects; + +/** + * ResponseTransactionType + */ +@Validated +@javax.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.SpringCodegen", date = "2022-09-27T11:46:46.417Z[GMT]") + + +public class ResponseTransactionType { + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + return true; + } + + @Override + public int hashCode() { + return Objects.hash(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class ResponseTransactionType {\n"); + + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/ServiceStatus.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/ServiceStatus.java new file mode 100644 index 000000000..188079d8c --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/ServiceStatus.java @@ -0,0 +1,35 @@ +package org.mifos.connector.gsmastub.model; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonValue; + +/** + * Provides the status of the requested service. + */ +public enum ServiceStatus { + AVAILABLE("available"), + UNAVAILABLE("unavailable"), + DEGRADED("degraded"); + + private String value; + + ServiceStatus(String value) { + this.value = value; + } + + @Override + @JsonValue + public String toString() { + return String.valueOf(value); + } + + @JsonCreator + public static ServiceStatus fromValue(String text) { + for (ServiceStatus b : ServiceStatus.values()) { + if (String.valueOf(b.value).equals(text)) { + return b; + } + } + return null; + } +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/Status.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/Status.java new file mode 100644 index 000000000..76b61985f --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/Status.java @@ -0,0 +1,34 @@ +package org.mifos.connector.gsmastub.model; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonValue; + +/** + * Gets or Sets status + */ +public enum Status { + ACTIVE("active"), + INACTIVE("inactive"); + + private String value; + + Status(String value) { + this.value = value; + } + + @Override + @JsonValue + public String toString() { + return String.valueOf(value); + } + + @JsonCreator + public static Status fromValue(String text) { + for (Status b : Status.values()) { + if (String.valueOf(b.value).equals(text)) { + return b; + } + } + return null; + } +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/SubjectName.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/SubjectName.java new file mode 100644 index 000000000..7a5a6c875 --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/SubjectName.java @@ -0,0 +1,198 @@ +package org.mifos.connector.gsmastub.model; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import org.springframework.validation.annotation.Validated; + +import javax.validation.constraints.Size; +import java.util.Objects; + +/** + * SubjectName + */ +@Validated +@javax.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.SpringCodegen", date = "2022-09-27T11:46:46.417Z[GMT]") + + +public class SubjectName { + @JsonProperty("title") + private String title = null; + + @JsonProperty("firstName") + private String firstName = null; + + @JsonProperty("middleName") + private String middleName = null; + + @JsonProperty("lastName") + private String lastName = null; + + @JsonProperty("fullName") + private String fullName = null; + + @JsonProperty("nativeName") + private String nativeName = null; + + public SubjectName title(String title) { + this.title = title; + return this; + } + + /** + * The given title of the KYC subject, e.g. Mr, Mrs, Dr. + * @return title + **/ + @Schema(description = "The given title of the KYC subject, e.g. Mr, Mrs, Dr.") + + @Size(max=256) public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public SubjectName firstName(String firstName) { + this.firstName = firstName; + return this; + } + + /** + * First name (also referred to as given name) of the KYC subject. + * @return firstName + **/ + @Schema(description = "First name (also referred to as given name) of the KYC subject.") + + @Size(max=256) public String getFirstName() { + return firstName; + } + + public void setFirstName(String firstName) { + this.firstName = firstName; + } + + public SubjectName middleName(String middleName) { + this.middleName = middleName; + return this; + } + + /** + * Middle Name of the KYC subject. + * @return middleName + **/ + @Schema(description = "Middle Name of the KYC subject.") + + @Size(max=256) public String getMiddleName() { + return middleName; + } + + public void setMiddleName(String middleName) { + this.middleName = middleName; + } + + public SubjectName lastName(String lastName) { + this.lastName = lastName; + return this; + } + + /** + * Surname (also referred to as last or family name) of the KYC subject. + * @return lastName + **/ + @Schema(description = "Surname (also referred to as last or family name) of the KYC subject.") + + @Size(max=256) public String getLastName() { + return lastName; + } + + public void setLastName(String lastName) { + this.lastName = lastName; + } + + public SubjectName fullName(String fullName) { + this.fullName = fullName; + return this; + } + + /** + * The full name of the KYC subject. + * @return fullName + **/ + @Schema(description = "The full name of the KYC subject.") + + @Size(max=256) public String getFullName() { + return fullName; + } + + public void setFullName(String fullName) { + this.fullName = fullName; + } + + public SubjectName nativeName(String nativeName) { + this.nativeName = nativeName; + return this; + } + + /** + * The full name expressed as in the native language. + * @return nativeName + **/ + @Schema(description = "The full name expressed as in the native language.") + + @Size(max=256) public String getNativeName() { + return nativeName; + } + + public void setNativeName(String nativeName) { + this.nativeName = nativeName; + } + + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + SubjectName subjectName = (SubjectName) o; + return Objects.equals(this.title, subjectName.title) && + Objects.equals(this.firstName, subjectName.firstName) && + Objects.equals(this.middleName, subjectName.middleName) && + Objects.equals(this.lastName, subjectName.lastName) && + Objects.equals(this.fullName, subjectName.fullName) && + Objects.equals(this.nativeName, subjectName.nativeName); + } + + @Override + public int hashCode() { + return Objects.hash(title, firstName, middleName, lastName, fullName, nativeName); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class SubjectName {\n"); + + sb.append(" title: ").append(toIndentedString(title)).append("\n"); + sb.append(" firstName: ").append(toIndentedString(firstName)).append("\n"); + sb.append(" middleName: ").append(toIndentedString(middleName)).append("\n"); + sb.append(" lastName: ").append(toIndentedString(lastName)).append("\n"); + sb.append(" fullName: ").append(toIndentedString(fullName)).append("\n"); + sb.append(" nativeName: ").append(toIndentedString(nativeName)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/SupplementaryBillReferenceDetails.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/SupplementaryBillReferenceDetails.java new file mode 100644 index 000000000..d267e63d9 --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/SupplementaryBillReferenceDetails.java @@ -0,0 +1,105 @@ +package org.mifos.connector.gsmastub.model; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import org.springframework.validation.annotation.Validated; + +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; +import java.util.Objects; + +/** + * SupplementaryBillReferenceDetails + */ +@Validated +@javax.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.SpringCodegen", date = "2022-09-27T11:46:46.417Z[GMT]") + + +public class SupplementaryBillReferenceDetails { + @JsonProperty("paymentReferenceType") + private String paymentReferenceType = null; + + @JsonProperty("paymentReferenceValue") + private String paymentReferenceValue = null; + + public SupplementaryBillReferenceDetails paymentReferenceType(String paymentReferenceType) { + this.paymentReferenceType = paymentReferenceType; + return this; + } + + /** + * Identifies the type of the additional payment reference. + * @return paymentReferenceType + **/ + @Schema(required = true, description = "Identifies the type of the additional payment reference.") + @NotNull + + @Size(min=1,max=256) public String getPaymentReferenceType() { + return paymentReferenceType; + } + + public void setPaymentReferenceType(String paymentReferenceType) { + this.paymentReferenceType = paymentReferenceType; + } + + public SupplementaryBillReferenceDetails paymentReferenceValue(String paymentReferenceValue) { + this.paymentReferenceValue = paymentReferenceValue; + return this; + } + + /** + * Identifies the value of the additional payment reference. + * @return paymentReferenceValue + **/ + @Schema(required = true, description = "Identifies the value of the additional payment reference.") + @NotNull + + @Size(min=1,max=256) public String getPaymentReferenceValue() { + return paymentReferenceValue; + } + + public void setPaymentReferenceValue(String paymentReferenceValue) { + this.paymentReferenceValue = paymentReferenceValue; + } + + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + SupplementaryBillReferenceDetails supplementaryBillReferenceDetails = (SupplementaryBillReferenceDetails) o; + return Objects.equals(this.paymentReferenceType, supplementaryBillReferenceDetails.paymentReferenceType) && + Objects.equals(this.paymentReferenceValue, supplementaryBillReferenceDetails.paymentReferenceValue); + } + + @Override + public int hashCode() { + return Objects.hash(paymentReferenceType, paymentReferenceValue); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class SupplementaryBillReferenceDetails {\n"); + + sb.append(" paymentReferenceType: ").append(toIndentedString(paymentReferenceType)).append("\n"); + sb.append(" paymentReferenceValue: ").append(toIndentedString(paymentReferenceValue)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/SupplementaryBillReferenceDetailsArray.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/SupplementaryBillReferenceDetailsArray.java new file mode 100644 index 000000000..134b3bce6 --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/SupplementaryBillReferenceDetailsArray.java @@ -0,0 +1,54 @@ +package org.mifos.connector.gsmastub.model; + +import io.swagger.v3.oas.annotations.media.Schema; +import org.springframework.validation.annotation.Validated; + +import java.util.ArrayList; +import java.util.Objects; + +/** + * In some cases, a single reference is not sufficient to identify a bill. This key-value collection enables further reference information to be supplied. + */ +@Schema(description = "In some cases, a single reference is not sufficient to identify a bill. This key-value collection enables further reference information to be supplied.") +@Validated +@javax.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.SpringCodegen", date = "2022-09-27T11:46:46.417Z[GMT]") + + +public class SupplementaryBillReferenceDetailsArray extends ArrayList { + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + return true; + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode()); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class SupplementaryBillReferenceDetailsArray {\n"); + sb.append(" ").append(toIndentedString(super.toString())).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/Type.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/Type.java new file mode 100644 index 000000000..eaa29f116 --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/Type.java @@ -0,0 +1,41 @@ +package org.mifos.connector.gsmastub.model; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonValue; + +/** + * The harmonised Transaction Type. + */ +public enum Type { + BILLPAY("billpay"), + DEPOSIT("deposit"), + DISBURSEMENT("disbursement"), + TRANSFER("transfer"), + MERCHANTPAY("merchantpay"), + INTTRANSFER("inttransfer"), + ADJUSTMENT("adjustment"), + REVERSAL("reversal"), + WITHDRAWAL("withdrawal"); + + private String value; + + Type(String value) { + this.value = value; + } + + @Override + @JsonValue + public String toString() { + return String.valueOf(value); + } + + @JsonCreator + public static Type fromValue(String text) { + for (Type b : Type.values()) { + if (String.valueOf(b.value).equals(text)) { + return b; + } + } + return null; + } +} diff --git a/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/TypeReversal.java b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/TypeReversal.java new file mode 100644 index 000000000..4cf1ff1b6 --- /dev/null +++ b/ph-ee-connector-channel/src/main/java/org/mifos/connector/gsmastub/model/TypeReversal.java @@ -0,0 +1,34 @@ +package org.mifos.connector.gsmastub.model; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonValue; + +/** + * The harmonised Transaction Type. + */ +public enum TypeReversal { + ADJUSTMENT("adjustment"), + REVERSAL("reversal"); + + private String value; + + TypeReversal(String value) { + this.value = value; + } + + @Override + @JsonValue + public String toString() { + return String.valueOf(value); + } + + @JsonCreator + public static TypeReversal fromValue(String text) { + for (TypeReversal b : TypeReversal.values()) { + if (String.valueOf(b.value).equals(text)) { + return b; + } + } + return null; + } +} diff --git a/ph-ee-connector-channel/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/ph-ee-connector-channel/src/main/resources/META-INF/additional-spring-configuration-metadata.json new file mode 100644 index 000000000..e57201234 --- /dev/null +++ b/ph-ee-connector-channel/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -0,0 +1,8 @@ +{ + "properties": [ + { + "name": "camel.server-port", + "type": "java.lang.String", + "description": "Description for camel.server-port." + } +] } diff --git a/ph-ee-connector-channel/src/main/resources/application-bb.yml b/ph-ee-connector-channel/src/main/resources/application-bb.yml new file mode 100644 index 000000000..5ad2f67a3 --- /dev/null +++ b/ph-ee-connector-channel/src/main/resources/application-bb.yml @@ -0,0 +1,12 @@ +operations: + url: "http://bb-operations.mifos.io/api/v1" + +identity: + channel: + clients: + - clientId: ${CHANNEL_TENANTPRIMARY_CLIENTID:channel-tn03} + clientSecret: ${CHANNEL_TENANTPRIMARY_CLIENTSECRET:p1234} + tenant: ${CHANNEL_TENANTPRIMARY_TENANT:tn03} + - clientId: ${CHANNEL_TENANTSECONDARY_CLIENTID:channel-tn04} + clientSecret: ${CHANNEL_TENANTSECONDARY_CLIENTSECRET:p1234} + tenant: ${CHANNEL_TENANTSECONDARY_TENANT:tn04} diff --git a/ph-ee-connector-channel/src/main/resources/application-large.yml b/ph-ee-connector-channel/src/main/resources/application-large.yml new file mode 100644 index 000000000..cfc505543 --- /dev/null +++ b/ph-ee-connector-channel/src/main/resources/application-large.yml @@ -0,0 +1,12 @@ +operations: + url: "http://large-operations.mifos.io/api/v1" + +identity: + channel: + clients: + - clientId: channel-tn01 + clientSecret: p3456 + tenant: tn01 + - clientId: channel-tn02 + clientSecret: p3456 + tenant: tn02 diff --git a/ph-ee-connector-channel/src/main/resources/application-med.yml b/ph-ee-connector-channel/src/main/resources/application-med.yml new file mode 100644 index 000000000..89323f4e9 --- /dev/null +++ b/ph-ee-connector-channel/src/main/resources/application-med.yml @@ -0,0 +1,12 @@ +operations: + url: "http://med-operations.mifos.io/api/v1" + +identity: + channel: + clients: + - clientId: channel-tn05 + clientSecret: p2345 + tenant: tn05 + - clientId: channel-tn06 + clientSecret: p2345 + tenant: tn06 diff --git a/ph-ee-connector-channel/src/main/resources/application-tenants.yml b/ph-ee-connector-channel/src/main/resources/application-tenants.yml new file mode 100644 index 000000000..56824b6c8 --- /dev/null +++ b/ph-ee-connector-channel/src/main/resources/application-tenants.yml @@ -0,0 +1,13 @@ +bpmns: + tenants: + - id: "lion" + flows: + payment-transfer: "minimal_mock_fund_transfer-{dfspid}" + - id: "gorilla" + flows: + payment-transfer: "PayerFundTransfer-{dfspid}" + outbound-transfer-request: "{ps}_flow_{ams}-{dfspid}" + - id: "rhino" + flows: + payment-transfer: "minimal_mock_fund_transfer_account_lookup-{dfspid}" + outbound-transfer-request: "minimal_mock_transfer_request-{dfspid}" diff --git a/ph-ee-connector-channel/src/main/resources/application.yml b/ph-ee-connector-channel/src/main/resources/application.yml new file mode 100644 index 000000000..5b8618f83 --- /dev/null +++ b/ph-ee-connector-channel/src/main/resources/application.yml @@ -0,0 +1,119 @@ +camel: + server-port: 5000 + springboot: + main-run-controller: true + dataformat: + json-jackson: + auto-discover-object-mapper: true + +dfspids: "DFSPID" + +transaction-id-length: -1 + +mpesa: + notification: + success: + enabled: false + failure: + enabled: true + +timer: "PT45S" + +server: + ssl: + key-alias: "tomcat-https" + key-store: "classpath:keystore.jks" + key-store-type: JKS + key-password: "" + key-store-password: "" + port: 8443 + +operations: + url: "http://bb-operations.mifos.io/api/v1" + auth-enabled: false + endpoint: + transfers: "/transfers?page=0&size=1&" + transactionReq: "/transactionRequests/?" + +security: + jws: + enable: false + response: + enable: false + +bpmn: + flows: + payment-transfer: "PayerFundTransfer-{dfspid}" + special-payment-transfer: "SpecialPayerFundTransfer-{dfspid}" + transaction-request: "payee_transaction_request-{dfspid}" + party-registration: "party-registration-{dfspid}" + gsma-base-transaction: "gsma_base_transaction-{dfspid}" + gsma-int-transfer: "gsma_int_transfer" + gsma-payee-process: "gsma_payee_process" + gsma-bill-payment: "gsma_bill_payment" + gsma-link-based-payment: "gsma_link_transfer" + international-remittance-payee: "international_remittance_payee_process-{dfspid}" + international-remittance-payer: "international_remittance_payer_process-{dfspid}" + inboundTransactionReq-flow: "{ps}_flow_{ams}-{dfspid}" + +ams: + groups: + - identifier: "accountid" + value: "roster" + - identifier: "foundationalid" + value: "paygops" + - identifier: "default" + value : "paygops" + +zeebe: + client: + max-execution-threads: 1000 + evenly-allocated-max-jobs: 1000 +# max-execution-threads: 100 +# number-of-workers: 5 +# evenly-allocated-max-jobs: "#{${zeebe.client.max-execution-threads} / ${zeebe.client.number-of-workers}}" + broker: + contactpoint: "localhost:26500" + +rest: + authorization: + enabled: false + host: http://localhost:8080 + header: "Basic Y2xpZW50Og==" + +management: +# server: +# port: 8443 + endpoint: + health: + probes: + enabled: true + liveness: + enabled: true + readiness: + enabled: true +# show-details: always +logging: + level: + root: INFO + pattern: + console: "%clr(%d{dd-MM-yyyy HH:mm:ss.SSS}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr([%35.35t]){faint} %clr(%-28.28logger{28}){cyan} %clr(:){faint}%X{BUSINESS-LOG} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}" + +springdoc: + writer-with-order-by-keys: true + +destination: + dfspid: "jupiter" + +redis: + host: "127.0.0.1" + port: 6379 + password: "RHVViU1ip9" + database: 1 + cacheRetencyDuration: 30 # in days + idempotency: + enabled: true + keyFormat: "clientCorrelationId_tenant_api" + apiList: "/channel/transfer,/channel/collection,/channel/gsma/transaction,/channel/transactionRequest" + +default_headers: "user-agent,accept,postman-token,host,accept-encoding,connection,content-type,content-length" diff --git a/ph-ee-connector-channel/src/main/resources/keystore.jks b/ph-ee-connector-channel/src/main/resources/keystore.jks new file mode 100644 index 000000000..f0040c545 Binary files /dev/null and b/ph-ee-connector-channel/src/main/resources/keystore.jks differ diff --git a/ph-ee-connector-channel/src/main/resources/logback.xml b/ph-ee-connector-channel/src/main/resources/logback.xml new file mode 100644 index 000000000..dbc48cea5 --- /dev/null +++ b/ph-ee-connector-channel/src/main/resources/logback.xml @@ -0,0 +1,18 @@ + + + + + + + + + + ${CONSOLE_LOG_PATTERN} + utf8 + + + + + + + diff --git a/ph-ee-connector-channel/src/test/java/org/mifos/connector/channel/TestUtil.java b/ph-ee-connector-channel/src/test/java/org/mifos/connector/channel/TestUtil.java new file mode 100644 index 000000000..5c0c7e5ad --- /dev/null +++ b/ph-ee-connector-channel/src/test/java/org/mifos/connector/channel/TestUtil.java @@ -0,0 +1,16 @@ +package org.mifos.connector.channel; + +import java.util.UUID; +import org.junit.jupiter.api.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class TestUtil { + + private Logger log = LoggerFactory.getLogger(TestUtil.class); + + @Test + public void test1() { + log.debug(" {}", UUID.randomUUID().toString()); + } +} diff --git a/ph-ee-connector-common/.circleci/config.yml b/ph-ee-connector-common/.circleci/config.yml new file mode 100644 index 000000000..269c4b02c --- /dev/null +++ b/ph-ee-connector-common/.circleci/config.yml @@ -0,0 +1,56 @@ +version: 2.1 +executors: + default: + docker: + - image: openjdk:17 +jobs: + Deploy_tag_version: + docker: + - image: cimg/openjdk:17.0.0 + environment: + JVM_OPTS: -Xmx512m + TERM: dumb + GITHUB_TOKEN: ${GITHUB_TOKEN} # Add the GitHub token as an environment variable + steps: + - checkout + - setup_remote_docker: + version: 20.10.24 + - run: + name: Set Build Description + command: | + echo "Tag: $CIRCLE_TAG" + - run: + name: Check if tag exists + command: | + # TAG_EXIST=$(curl -u "$USERNAME:$PASSWORD" -sSf "https://jfrog.sandbox.fynarfin.io/artifactory/fyn-libs-snapshot/org/mifos/ph-ee-connector-common/" | grep -o "$CIRCLE_TAG" | awk '{print tolower($0)}') + + echo "TAG_EXIST: $TAG_EXIST" + + if [ -z "$TAG_EXIST" ]; then + echo "Tag doesn't exist. Deploying artifact..." + + # Backup original files + cp settings.gradle settings.gradle.bak + cp build.gradle build.gradle.bak + + # Replace placeholders with credentials and URLs + sed -i "s,,$USERNAME,g" settings.gradle + sed -i "s,,$PASSWORD,g" settings.gradle + sed -i "s,https://fynarfin.jfrog.io/artifactory,https://jfrog.sandbox.fynarfin.io/artifactory,g" build.gradle + + # Publish artifact + ./gradlew artifactoryPublish + # deployment steps here + else + echo "Tag already exists. Skipping deployment." + fi + +workflows: + version: 2 + build_and_deploy: + jobs: + - Deploy_tag_version: + filters: + tags: + only: + - /^v\d+\.\d+\.\d+$/ # Deploy only on version tags \ No newline at end of file diff --git a/ph-ee-connector-common/.github/pull_request_template.md b/ph-ee-connector-common/.github/pull_request_template.md new file mode 100644 index 000000000..739047e49 --- /dev/null +++ b/ph-ee-connector-common/.github/pull_request_template.md @@ -0,0 +1,20 @@ +## Description + +* Describe the changes made and why they were made. +* Add a link to teh design document or include the design bullet points related to this PR here. + + _(Ignore if these details are present on the associated JIRA ticket)_ + +## Checklist + +Please make sure these boxes are checked before submitting your pull request - thanks! + +- [ ] Design related bullet points or design document link related to this PR added in the description above. + +- [ ] Updated corresponding Postman Collection or Api documentation for the changes in this PR. + +- [ ] Create/update unit or integration tests for verifying the changes made. + +- [ ] Add required Swagger annotation and update API documentation with details of any API changes if applicable + +- [ ] Followed the naming conventions as given in https://docs.google.com/document/d/1Q4vaMSzrTxxh9TS0RILuNkSkYCxotuYk1Xe0CMIkkCU/edit?usp=sharing diff --git a/ph-ee-connector-common/.gitignore b/ph-ee-connector-common/.gitignore new file mode 100644 index 000000000..f772270b3 --- /dev/null +++ b/ph-ee-connector-common/.gitignore @@ -0,0 +1,33 @@ +target/ + +.gradle +.gradle/ +!gradle/wrapper/gradle-wrapper.jar + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +.DS_Store + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ + +### VS Code ### +.vscode/ diff --git a/ph-ee-connector-common/Jenkinsfile b/ph-ee-connector-common/Jenkinsfile new file mode 100644 index 000000000..f05fd022c --- /dev/null +++ b/ph-ee-connector-common/Jenkinsfile @@ -0,0 +1,23 @@ +pipeline { + agent any + stages { + stage('build') { + steps { + sh 'mvn --version' + sh 'mvn -U clean package' + } + } + stage('deploy') { + steps { + sh 'mvn deploy' + } + } + stage('trigger others') { + steps { + build job: "ph-ee-connector-ams-mifos", wait: false + build job: "ph-ee-connector-channel", wait: false + build job: "ph-ee-connector-mojaloop-java", wait: false + } + } + } +} \ No newline at end of file diff --git a/ph-ee-connector-common/LICENSE b/ph-ee-connector-common/LICENSE new file mode 100644 index 000000000..a612ad981 --- /dev/null +++ b/ph-ee-connector-common/LICENSE @@ -0,0 +1,373 @@ +Mozilla Public License Version 2.0 +================================== + +1. Definitions +-------------- + +1.1. "Contributor" + means each individual or legal entity that creates, contributes to + the creation of, or owns Covered Software. + +1.2. "Contributor Version" + means the combination of the Contributions of others (if any) used + by a Contributor and that particular Contributor's Contribution. + +1.3. "Contribution" + means Covered Software of a particular Contributor. + +1.4. "Covered Software" + means Source Code Form to which the initial Contributor has attached + the notice in Exhibit A, the Executable Form of such Source Code + Form, and Modifications of such Source Code Form, in each case + including portions thereof. + +1.5. "Incompatible With Secondary Licenses" + means + + (a) that the initial Contributor has attached the notice described + in Exhibit B to the Covered Software; or + + (b) that the Covered Software was made available under the terms of + version 1.1 or earlier of the License, but not also under the + terms of a Secondary License. + +1.6. "Executable Form" + means any form of the work other than Source Code Form. + +1.7. "Larger Work" + means a work that combines Covered Software with other material, in + a separate file or files, that is not Covered Software. + +1.8. "License" + means this document. + +1.9. "Licensable" + means having the right to grant, to the maximum extent possible, + whether at the time of the initial grant or subsequently, any and + all of the rights conveyed by this License. + +1.10. "Modifications" + means any of the following: + + (a) any file in Source Code Form that results from an addition to, + deletion from, or modification of the contents of Covered + Software; or + + (b) any new file in Source Code Form that contains any Covered + Software. + +1.11. "Patent Claims" of a Contributor + means any patent claim(s), including without limitation, method, + process, and apparatus claims, in any patent Licensable by such + Contributor that would be infringed, but for the grant of the + License, by the making, using, selling, offering for sale, having + made, import, or transfer of either its Contributions or its + Contributor Version. + +1.12. "Secondary License" + means either the GNU General Public License, Version 2.0, the GNU + Lesser General Public License, Version 2.1, the GNU Affero General + Public License, Version 3.0, or any later versions of those + licenses. + +1.13. "Source Code Form" + means the form of the work preferred for making modifications. + +1.14. "You" (or "Your") + means an individual or a legal entity exercising rights under this + License. For legal entities, "You" includes any entity that + controls, is controlled by, or is under common control with You. For + purposes of this definition, "control" means (a) the power, direct + or indirect, to cause the direction or management of such entity, + whether by contract or otherwise, or (b) ownership of more than + fifty percent (50%) of the outstanding shares or beneficial + ownership of such entity. + +2. License Grants and Conditions +-------------------------------- + +2.1. Grants + +Each Contributor hereby grants You a world-wide, royalty-free, +non-exclusive license: + +(a) under intellectual property rights (other than patent or trademark) + Licensable by such Contributor to use, reproduce, make available, + modify, display, perform, distribute, and otherwise exploit its + Contributions, either on an unmodified basis, with Modifications, or + as part of a Larger Work; and + +(b) under Patent Claims of such Contributor to make, use, sell, offer + for sale, have made, import, and otherwise transfer either its + Contributions or its Contributor Version. + +2.2. Effective Date + +The licenses granted in Section 2.1 with respect to any Contribution +become effective for each Contribution on the date the Contributor first +distributes such Contribution. + +2.3. Limitations on Grant Scope + +The licenses granted in this Section 2 are the only rights granted under +this License. No additional rights or licenses will be implied from the +distribution or licensing of Covered Software under this License. +Notwithstanding Section 2.1(b) above, no patent license is granted by a +Contributor: + +(a) for any code that a Contributor has removed from Covered Software; + or + +(b) for infringements caused by: (i) Your and any other third party's + modifications of Covered Software, or (ii) the combination of its + Contributions with other software (except as part of its Contributor + Version); or + +(c) under Patent Claims infringed by Covered Software in the absence of + its Contributions. + +This License does not grant any rights in the trademarks, service marks, +or logos of any Contributor (except as may be necessary to comply with +the notice requirements in Section 3.4). + +2.4. Subsequent Licenses + +No Contributor makes additional grants as a result of Your choice to +distribute the Covered Software under a subsequent version of this +License (see Section 10.2) or under the terms of a Secondary License (if +permitted under the terms of Section 3.3). + +2.5. Representation + +Each Contributor represents that the Contributor believes its +Contributions are its original creation(s) or it has sufficient rights +to grant the rights to its Contributions conveyed by this License. + +2.6. Fair Use + +This License is not intended to limit any rights You have under +applicable copyright doctrines of fair use, fair dealing, or other +equivalents. + +2.7. Conditions + +Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted +in Section 2.1. + +3. Responsibilities +------------------- + +3.1. Distribution of Source Form + +All distribution of Covered Software in Source Code Form, including any +Modifications that You create or to which You contribute, must be under +the terms of this License. You must inform recipients that the Source +Code Form of the Covered Software is governed by the terms of this +License, and how they can obtain a copy of this License. You may not +attempt to alter or restrict the recipients' rights in the Source Code +Form. + +3.2. Distribution of Executable Form + +If You distribute Covered Software in Executable Form then: + +(a) such Covered Software must also be made available in Source Code + Form, as described in Section 3.1, and You must inform recipients of + the Executable Form how they can obtain a copy of such Source Code + Form by reasonable means in a timely manner, at a charge no more + than the cost of distribution to the recipient; and + +(b) You may distribute such Executable Form under the terms of this + License, or sublicense it under different terms, provided that the + license for the Executable Form does not attempt to limit or alter + the recipients' rights in the Source Code Form under this License. + +3.3. Distribution of a Larger Work + +You may create and distribute a Larger Work under terms of Your choice, +provided that You also comply with the requirements of this License for +the Covered Software. If the Larger Work is a combination of Covered +Software with a work governed by one or more Secondary Licenses, and the +Covered Software is not Incompatible With Secondary Licenses, this +License permits You to additionally distribute such Covered Software +under the terms of such Secondary License(s), so that the recipient of +the Larger Work may, at their option, further distribute the Covered +Software under the terms of either this License or such Secondary +License(s). + +3.4. Notices + +You may not remove or alter the substance of any license notices +(including copyright notices, patent notices, disclaimers of warranty, +or limitations of liability) contained within the Source Code Form of +the Covered Software, except that You may alter any license notices to +the extent required to remedy known factual inaccuracies. + +3.5. Application of Additional Terms + +You may choose to offer, and to charge a fee for, warranty, support, +indemnity or liability obligations to one or more recipients of Covered +Software. However, You may do so only on Your own behalf, and not on +behalf of any Contributor. You must make it absolutely clear that any +such warranty, support, indemnity, or liability obligation is offered by +You alone, and You hereby agree to indemnify every Contributor for any +liability incurred by such Contributor as a result of warranty, support, +indemnity or liability terms You offer. You may include additional +disclaimers of warranty and limitations of liability specific to any +jurisdiction. + +4. Inability to Comply Due to Statute or Regulation +--------------------------------------------------- + +If it is impossible for You to comply with any of the terms of this +License with respect to some or all of the Covered Software due to +statute, judicial order, or regulation then You must: (a) comply with +the terms of this License to the maximum extent possible; and (b) +describe the limitations and the code they affect. Such description must +be placed in a text file included with all distributions of the Covered +Software under this License. Except to the extent prohibited by statute +or regulation, such description must be sufficiently detailed for a +recipient of ordinary skill to be able to understand it. + +5. Termination +-------------- + +5.1. The rights granted under this License will terminate automatically +if You fail to comply with any of its terms. However, if You become +compliant, then the rights granted under this License from a particular +Contributor are reinstated (a) provisionally, unless and until such +Contributor explicitly and finally terminates Your grants, and (b) on an +ongoing basis, if such Contributor fails to notify You of the +non-compliance by some reasonable means prior to 60 days after You have +come back into compliance. Moreover, Your grants from a particular +Contributor are reinstated on an ongoing basis if such Contributor +notifies You of the non-compliance by some reasonable means, this is the +first time You have received notice of non-compliance with this License +from such Contributor, and You become compliant prior to 30 days after +Your receipt of the notice. + +5.2. If You initiate litigation against any entity by asserting a patent +infringement claim (excluding declaratory judgment actions, +counter-claims, and cross-claims) alleging that a Contributor Version +directly or indirectly infringes any patent, then the rights granted to +You by any and all Contributors for the Covered Software under Section +2.1 of this License shall terminate. + +5.3. In the event of termination under Sections 5.1 or 5.2 above, all +end user license agreements (excluding distributors and resellers) which +have been validly granted by You or Your distributors under this License +prior to termination shall survive termination. + +************************************************************************ +* * +* 6. Disclaimer of Warranty * +* ------------------------- * +* * +* Covered Software is provided under this License on an "as is" * +* basis, without warranty of any kind, either expressed, implied, or * +* statutory, including, without limitation, warranties that the * +* Covered Software is free of defects, merchantable, fit for a * +* particular purpose or non-infringing. The entire risk as to the * +* quality and performance of the Covered Software is with You. * +* Should any Covered Software prove defective in any respect, You * +* (not any Contributor) assume the cost of any necessary servicing, * +* repair, or correction. This disclaimer of warranty constitutes an * +* essential part of this License. No use of any Covered Software is * +* authorized under this License except under this disclaimer. * +* * +************************************************************************ + +************************************************************************ +* * +* 7. Limitation of Liability * +* -------------------------- * +* * +* Under no circumstances and under no legal theory, whether tort * +* (including negligence), contract, or otherwise, shall any * +* Contributor, or anyone who distributes Covered Software as * +* permitted above, be liable to You for any direct, indirect, * +* special, incidental, or consequential damages of any character * +* including, without limitation, damages for lost profits, loss of * +* goodwill, work stoppage, computer failure or malfunction, or any * +* and all other commercial damages or losses, even if such party * +* shall have been informed of the possibility of such damages. This * +* limitation of liability shall not apply to liability for death or * +* personal injury resulting from such party's negligence to the * +* extent applicable law prohibits such limitation. Some * +* jurisdictions do not allow the exclusion or limitation of * +* incidental or consequential damages, so this exclusion and * +* limitation may not apply to You. * +* * +************************************************************************ + +8. Litigation +------------- + +Any litigation relating to this License may be brought only in the +courts of a jurisdiction where the defendant maintains its principal +place of business and such litigation shall be governed by laws of that +jurisdiction, without reference to its conflict-of-law provisions. +Nothing in this Section shall prevent a party's ability to bring +cross-claims or counter-claims. + +9. Miscellaneous +---------------- + +This License represents the complete agreement concerning the subject +matter hereof. If any provision of this License is held to be +unenforceable, such provision shall be reformed only to the extent +necessary to make it enforceable. Any law or regulation which provides +that the language of a contract shall be construed against the drafter +shall not be used to construe this License against a Contributor. + +10. Versions of the License +--------------------------- + +10.1. New Versions + +Mozilla Foundation is the license steward. Except as provided in Section +10.3, no one other than the license steward has the right to modify or +publish new versions of this License. Each version will be given a +distinguishing version number. + +10.2. Effect of New Versions + +You may distribute the Covered Software under the terms of the version +of the License under which You originally received the Covered Software, +or under the terms of any subsequent version published by the license +steward. + +10.3. Modified Versions + +If you create software not governed by this License, and you want to +create a new license for such software, you may create and use a +modified version of this License if you rename the license and remove +any references to the name of the license steward (except to note that +such modified license differs from this License). + +10.4. Distributing Source Code Form that is Incompatible With Secondary +Licenses + +If You choose to distribute Source Code Form that is Incompatible With +Secondary Licenses under the terms of this version of the License, the +notice described in Exhibit B of this License must be attached. + +Exhibit A - Source Code Form License Notice +------------------------------------------- + + This Source Code Form is subject to the terms of the Mozilla Public + License, v. 2.0. If a copy of the MPL was not distributed with this + file, You can obtain one at http://mozilla.org/MPL/2.0/. + +If it is not possible or desirable to put the notice in a particular +file, then You may include the notice in a location (such as a LICENSE +file in a relevant directory) where a recipient would be likely to look +for such a notice. + +You may add additional accurate notices of copyright ownership. + +Exhibit B - "Incompatible With Secondary Licenses" Notice +--------------------------------------------------------- + + This Source Code Form is "Incompatible With Secondary Licenses", as + defined by the Mozilla Public License, v. 2.0. diff --git a/ph-ee-connector-common/README.md b/ph-ee-connector-common/README.md new file mode 100644 index 000000000..aea8859f8 --- /dev/null +++ b/ph-ee-connector-common/README.md @@ -0,0 +1,37 @@ +# payment-hub-ee +Payment Hub Enterprise Edition middleware for integration to real-time payment systems. + +# How to enable JWSWebInterceptor +Step1: Add `@EnableJsonWebSignature` annotation to the main application class of your microservice. +Step2: Use below mention configuration in application.yaml to disable or enable the JsonWebSignatureInterceptor. + +```yaml +security: + jws: + enable: true + response: + enable: true +``` + +# How to generate signature + +```java +JsonWebSignature jwsSignature = new JsonWebSignature.JsonWebSignatureBuilder() +.setClientCorrelationId(UUID.randomUUID().toString()) +.setTenantId("rhino").setData("/src/main/resources/demo.csv").build(); + +String signature = jwsSignature.getSignature(""); +``` + + +# Checkstyle +Use below command to execute the checkstyle test. +```shell +./gradlew checkstyleMain +``` + +## Spotless +Use below command to execute the spotless apply. +```shell +./gradlew spotlessApply +``` diff --git a/ph-ee-connector-common/bin/.gitignore b/ph-ee-connector-common/bin/.gitignore new file mode 100644 index 000000000..ddf9c6563 --- /dev/null +++ b/ph-ee-connector-common/bin/.gitignore @@ -0,0 +1 @@ +/main/ diff --git a/ph-ee-connector-common/bin/test/application.yml b/ph-ee-connector-common/bin/test/application.yml new file mode 100644 index 000000000..2612467ee --- /dev/null +++ b/ph-ee-connector-common/bin/test/application.yml @@ -0,0 +1,114 @@ +onboarding: + enabled: true + +oracle: + host: "http://account-oracle.mifos.io:4100" + endpoint: "/oracle/participants/{partyIdType}/{partyIdentifier}" + +local: + central-ledger-host: http://localhost:3001 + +mojaloop: + local: false + currency: "TZS" + contact-email: "contact@email.com" + host: "http://40.114.81.46" + account-lookup-service: "account-lookup-service-admin.local" + central-ledger-service: "central-ledger.local" + do-hub-onboard: false + participants: + endpoint: "/participants" + position-and-limit-endpoint: "${mojaloop.participants.endpoint}/{dfspid}/initialPositionAndLimits" + registration-endpoint: "${mojaloop.participants.endpoint}/{dfspid}/endpoints" + accounts-endpoint: "${mojaloop.participants.endpoint}/{dfspid}/accounts/{settlementAccountId}" + hub: + endpoint: "/Hub" + accounts: "${mojaloop.participants.endpoint}${mojaloop.participants.hub.endpoint}/accounts" + endpoints: "${mojaloop.participants.endpoint}${mojaloop.participants.hub.endpoint}/endpoints" + do-oracle-onboard: false + oracles: + type: "MSISDN" + endpoint: /oracles + do-dfsp-onboard: true + callbackMappings: + - type: "FSPIOP_CALLBACK_URL_PARTICIPANT_PUT" + value: "{dfspDomain}/participants/{{partyIdType}}/{{partyIdentifier}}" + - type: "FSPIOP_CALLBACK_URL_PARTICIPANT_PUT_ERROR" + value: "{dfspDomain}/participants/{{partyIdType}}/{{partyIdentifier}}/error" + - type: "FSPIOP_CALLBACK_URL_PARTICIPANT_BATCH_PUT" + value: "{dfspDomain}/participants/{{requestId}}" + - type: "FSPIOP_CALLBACK_URL_PARTICIPANT_BATCH_PUT_ERROR" + value: "{dfspDomain}/participants/{{requestId}}/error" + - type: "FSPIOP_CALLBACK_URL_PARTIES_GET" + value: "{dfspDomain}/parties/{{partyIdType}}/{{partyIdentifier}}" + - type: "FSPIOP_CALLBACK_URL_PARTIES_PUT" + value: "{dfspDomain}/parties/{{partyIdType}}/{{partyIdentifier}}" + - type: "FSPIOP_CALLBACK_URL_PARTIES_PUT_ERROR" + value: "{dfspDomain}/parties/{{partyIdType}}/{{partyIdentifier}}/error" + - type: "FSPIOP_CALLBACK_URL_QUOTES" + value: "{dfspDomain}" + - type: "FSPIOP_CALLBACK_URL_TRANSFER_POST" + value: "{dfspDomain}/transfers" + - type: "FSPIOP_CALLBACK_URL_TRANSFER_PUT" + value: "{dfspDomain}/transfers/{{transferId}}" + - type: "FSPIOP_CALLBACK_URL_TRANSFER_ERROR" + value: "{dfspDomain}/transfers/{{transferId}}/error" + - type: "FSPIOP_CALLBACK_URL_TRX_REQ_SERVICE" + value: "{dfspDomain}" + - type: "FSPIOP_CALLBACK_URL_AUTHORIZATIONS" + value: "{dfspDomain}" + - type: "NET_DEBIT_CAP_ADJUSTMENT_EMAIL" + value: "{dfspDomain}" + - type: "SETTLEMENT_TRANSFER_POSITION_CHANGE_EMAIL" + value: "{dfspDomain}" + - type: "NET_DEBIT_CAP_THRESHOLD_BREACH_EMAIL" + value: "{dfspDomain}" + dfsps: + - enabled: true + addToExternalOracle: false + registerOnlyCallbackUrls: true + id: "in01tn01" + partyIdType: "MSISDN" + partyIdentifier: "27710101999" + fundsInPrepareAmount: "1000000" + domain: "http://${mojaloop.dfsps[0].id}.mifos.io/switch" + - enabled: true + addToExternalOracle: false + registerOnlyCallbackUrls: true + id: "in01tn02" + partyIdType: "MSISDN" + partyIdentifier: "27710102999" + fundsInPrepareAmount: "1000000" + domain: "http://${mojaloop.dfsps[1].id}.mifos.io/switch" + - enabled: false + addToExternalOracle: false + registerOnlyCallbackUrls: false + id: "in02tn03" + partyIdType: "MSISDN" + partyIdentifier: "27710203999" + fundsInPrepareAmount: "1000000" + domain: "http://${mojaloop.dfsps[2].id}.mifos.io/switch" + - enabled: false + addToExternalOracle: false + registerOnlyCallbackUrls: false + id: "in02tn04" + partyIdType: "MSISDN" + partyIdentifier: "27710204999" + fundsInPrepareAmount: "1000000" + domain: "http://${mojaloop.dfsps[3].id}.mifos.io/switch" + - enabled: false + addToExternalOracle: false + registerOnlyCallbackUrls: false + id: "in03tn05" + partyIdType: "MSISDN" + partyIdentifier: "27710305999" + fundsInPrepareAmount: "1000000" + domain: "http://${mojaloop.dfsps[4].id}.mifos.io/switch" + - enabled: false + addToExternalOracle: false + registerOnlyCallbackUrls: false + id: "in03tn06" + partyIdType: "MSISDN" + partyIdentifier: "27710306999" + fundsInPrepareAmount: "1000000" + domain: "http://${mojaloop.dfsps[5].id}.mifos.io/switch" diff --git a/ph-ee-connector-common/bin/test/logback.xml b/ph-ee-connector-common/bin/test/logback.xml new file mode 100644 index 000000000..59a5024db --- /dev/null +++ b/ph-ee-connector-common/bin/test/logback.xml @@ -0,0 +1,18 @@ + + + + + + + + + ${CONSOLE_LOG_PATTERN} + utf8 + + + + + + + \ No newline at end of file diff --git a/ph-ee-connector-common/bin/test/org/mifos/mojaloop/CallbackMapping.class b/ph-ee-connector-common/bin/test/org/mifos/mojaloop/CallbackMapping.class new file mode 100644 index 000000000..7a78e59a0 Binary files /dev/null and b/ph-ee-connector-common/bin/test/org/mifos/mojaloop/CallbackMapping.class differ diff --git a/ph-ee-connector-common/bin/test/org/mifos/mojaloop/CallbackMappingProperties.class b/ph-ee-connector-common/bin/test/org/mifos/mojaloop/CallbackMappingProperties.class new file mode 100644 index 000000000..b8c0d94dd Binary files /dev/null and b/ph-ee-connector-common/bin/test/org/mifos/mojaloop/CallbackMappingProperties.class differ diff --git a/ph-ee-connector-common/bin/test/org/mifos/mojaloop/Dfsp.class b/ph-ee-connector-common/bin/test/org/mifos/mojaloop/Dfsp.class new file mode 100644 index 000000000..a949d2618 Binary files /dev/null and b/ph-ee-connector-common/bin/test/org/mifos/mojaloop/Dfsp.class differ diff --git a/ph-ee-connector-common/bin/test/org/mifos/mojaloop/DfspProperties.class b/ph-ee-connector-common/bin/test/org/mifos/mojaloop/DfspProperties.class new file mode 100644 index 000000000..46c8bf09c Binary files /dev/null and b/ph-ee-connector-common/bin/test/org/mifos/mojaloop/DfspProperties.class differ diff --git a/ph-ee-connector-common/bin/test/org/mifos/mojaloop/OnboardDfsps.class b/ph-ee-connector-common/bin/test/org/mifos/mojaloop/OnboardDfsps.class new file mode 100644 index 000000000..943d258b5 Binary files /dev/null and b/ph-ee-connector-common/bin/test/org/mifos/mojaloop/OnboardDfsps.class differ diff --git a/ph-ee-connector-common/bin/test/org/mifos/mojaloop/TestConfig.class b/ph-ee-connector-common/bin/test/org/mifos/mojaloop/TestConfig.class new file mode 100644 index 000000000..f3219012d Binary files /dev/null and b/ph-ee-connector-common/bin/test/org/mifos/mojaloop/TestConfig.class differ diff --git a/ph-ee-connector-common/build.gradle b/ph-ee-connector-common/build.gradle new file mode 100644 index 000000000..79e7a51c2 --- /dev/null +++ b/ph-ee-connector-common/build.gradle @@ -0,0 +1,215 @@ +/* + * This file was generated by the Gradle 'init' task. + */ + +plugins { + id 'java' + id 'eclipse' + id 'maven-publish' + id 'checkstyle' + id "com.jfrog.artifactory" version "4.24.23" + id 'org.springframework.boot' version '2.6.2' + id 'com.diffplug.spotless' version '6.19.0' +} +apply plugin: "io.spring.dependency-management" + +repositories { + // mavenLocal() + maven { + url = uri('https://repo.maven.apache.org/maven2') + } +} + +apply plugin:'com.diffplug.spotless' +spotless { + format 'misc', { + target '**/*.md', '**/*.properties', '**/.gitignore', '**/.openapi-generator-ignore', '**/*.yml', '**/*.xml', '**/**.json', '**/*.sql' + targetExclude '**/build/**', '**/bin/**', '**/.settings/**', '**/.idea/**', '**/.gradle/**', '**/gradlew.bat', '**/licenses/**', '**/banner.txt', '.vscode/**' + indentWithSpaces(4) + endWithNewline() + trimTrailingWhitespace() + } + + groovyGradle { + target '*.gradle', '**/*.gradle' + targetExclude '**/build/**' + greclipse() + indentWithSpaces(4) + endWithNewline() + trimTrailingWhitespace() + } + + lineEndings 'UNIX' +} + +dependencies { + implementation 'org.springframework.boot:spring-boot-autoconfigure' + implementation 'org.springframework:spring-webmvc' + implementation 'javax.servlet:javax.servlet-api:3.1.0' + implementation 'com.auth0:java-jwt:3.10.2' + implementation 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.10.1' + implementation 'org.json:json:20190722' + implementation 'io.camunda:zeebe-client-java:8.1.1' + implementation 'org.apache.camel:camel-core:3.4.0' + implementation 'commons-codec:commons-codec:1.15' + implementation 'commons-io:commons-io:2.11.0' + implementation 'org.apache.commons:commons-lang3:3.14.0' + testImplementation 'org.springframework:spring-web:5.2.2.RELEASE' + testImplementation 'org.springframework.boot:spring-boot-starter-test:2.2.2.RELEASE' + testImplementation 'org.junit.jupiter:junit-jupiter-api:5.6.2' + testImplementation 'org.junit.jupiter:junit-jupiter-engine:5.6.2' + compileOnly 'org.hibernate.validator:hibernate-validator:6.0.20.Final' + + compileOnly 'org.projectlombok:lombok:1.18.24' + annotationProcessor 'org.projectlombok:lombok:1.18.24' + checkstyle 'com.puppycrawl.tools:checkstyle:10.9.3' + checkstyle 'com.github.sevntu-checkstyle:sevntu-checks:1.44.1' + implementation 'com.diffplug.gradle.spotless:spotless:2.4.1' + implementation 'com.diffplug.spotless:spotless-plugin-gradle:6.17.0' + implementation 'org.springframework.boot:spring-boot-starter-webflux:2.4.1' +} + +configure(this) { + // NOTE: order matters! + apply plugin: 'java' + apply plugin: 'idea' + apply plugin: 'eclipse' + apply plugin: 'checkstyle' + configurations { + implementation.setCanBeResolved(true) + api.setCanBeResolved(true) + } + tasks.withType(JavaCompile) { + options.compilerArgs += [ + "-Xlint:unchecked", + "-Xlint:cast", + "-Xlint:auxiliaryclass", + "-Xlint:deprecation", + "-Xlint:dep-ann", + "-Xlint:divzero", + "-Xlint:empty", + "-Xlint:exports", + "-Xlint:fallthrough", + "-Xlint:finally", + "-Xlint:module", + "-Xlint:opens", + "-Xlint:options", + "-Xlint:overloads", + "-Xlint:overrides", + "-Xlint:path", + "-Xlint:processing", + "-Xlint:removal", + "-Xlint:requires-automatic", + "-Xlint:requires-transitive-automatic", + "-Xlint:try", + "-Xlint:varargs", + "-Xlint:preview", + "-Xlint:static", + // -Werror needs to be disabled because EclipseLink's static weaving doesn't generate warning-free code + // and during an IntelliJ recompilation, it fails + //"-Werror", + "-Xmaxwarns", + 1500, + "-Xmaxerrs", + 1500 + ] + options.deprecation = true + } + // Configuration for the spotless plugin + // https://github.com/diffplug/spotless/tree/main/plugin-gradle + spotless { + java { + targetExclude '**/build/**', '**/bin/**', '**/out/**' + importOrder() //sort imports alphabetically + removeUnusedImports() + eclipse().configFile "$rootDir/ph-ee-connector-common/config/common-formatter.xml" + endWithNewline() + trimTrailingWhitespace() + // Enforce style modifier order + custom 'Modifier ordering', { + def modifierRanking = [ + public : 1, + protected : 2, + private : 3, + abstract : 4, + default : 5, + static : 6, + final : 7, + transient : 8, + volatile : 9, + synchronized: 10, + native : 11, + strictfp : 12] + // Find any instance of multiple modifiers. Lead with a non-word character to avoid + // accidental matching against for instance, "an alternative default value" + it.replaceAll(/\W(?:public |protected |private |abstract |default |static |final |transient |volatile |synchronized |native |strictfp ){2,}/, { + // Do not replace the leading non-word character. Identify the modifiers + it.replaceAll(/(?:public |protected |private |abstract |default |static |final |transient |volatile |synchronized |native |strictfp ){2,}/, { + // Sort the modifiers according to the ranking above + it.split().sort({ modifierRanking[it] }).join(' ') + ' ' + } + ) + } + ) + } + } + lineEndings 'UNIX' + } + // If we are running Gradle within Eclipse to enhance classes, + // set the classes directory to point to Eclipse's default build directory + if (project.hasProperty('env') && project.getProperty('env') == 'eclipse') { + sourceSets.main.java.outputDir = file("$projectDir/bin/main") + } + // Configuration for the Checkstyle plugin + // https://docs.gradle.org/current/userguide/checkstyle_plugin.html + dependencies { + checkstyle 'com.puppycrawl.tools:checkstyle:10.3.1' + checkstyle 'com.github.sevntu-checkstyle:sevntu-checks:1.42.0' + } + + dependencies { + implementation("io.netty:netty-all:4.1.68.Final") + } +} + +group = 'org.mifos' +version = '0.0.0' +sourceCompatibility = JavaVersion.VERSION_17 +def artifactId = 'ph-ee-connector-common' +def versionNumber = version + +publishing { + publications { + mavenJava(MavenPublication) { + from(components.java) + } + } +} +tasks.withType(JavaCompile) { + options.encoding = 'UTF-8' +} + +jar { + enabled = true +} + +artifactory { + contextUrl = 'https://jfrog.sandbox.fynarfin.io/artifactory' // base artifactory url + publish { + repository { + repoKey = 'fyn-libs-snapshot' //Artifactory repository key to publish to + // username = 'avik@fynarfin.io' publisher user name + // password = '****' publisher password + username = gradle.app_username + password = gradle.app_password + maven = true + } + defaults { + publications('mavenJava') + } + } +} + +artifactoryPublish { + dependsOn jar +} diff --git a/ph-ee-connector-common/config/checkstyle/checkstyle.xml b/ph-ee-connector-common/config/checkstyle/checkstyle.xml new file mode 100644 index 000000000..5183efef5 --- /dev/null +++ b/ph-ee-connector-common/config/checkstyle/checkstyle.xml @@ -0,0 +1,266 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ph-ee-connector-common/config/checkstyle/suppressions.xml b/ph-ee-connector-common/config/checkstyle/suppressions.xml new file mode 100644 index 000000000..f4e5b54c3 --- /dev/null +++ b/ph-ee-connector-common/config/checkstyle/suppressions.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + diff --git a/ph-ee-connector-common/config/common-cleanup.xml b/ph-ee-connector-common/config/common-cleanup.xml new file mode 100644 index 000000000..0042addbb --- /dev/null +++ b/ph-ee-connector-common/config/common-cleanup.xml @@ -0,0 +1,71 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ph-ee-connector-common/config/common-formatter.xml b/ph-ee-connector-common/config/common-formatter.xml new file mode 100644 index 000000000..07085327a --- /dev/null +++ b/ph-ee-connector-common/config/common-formatter.xml @@ -0,0 +1,366 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ph-ee-connector-common/gradle/wrapper/gradle-wrapper.jar b/ph-ee-connector-common/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 000000000..490fda857 Binary files /dev/null and b/ph-ee-connector-common/gradle/wrapper/gradle-wrapper.jar differ diff --git a/ph-ee-connector-common/gradle/wrapper/gradle-wrapper.properties b/ph-ee-connector-common/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 000000000..e750102e0 --- /dev/null +++ b/ph-ee-connector-common/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-7.3-bin.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/ph-ee-connector-common/gradlew b/ph-ee-connector-common/gradlew new file mode 100755 index 000000000..2fe81a7d9 --- /dev/null +++ b/ph-ee-connector-common/gradlew @@ -0,0 +1,183 @@ +#!/usr/bin/env sh + +# +# Copyright 2015 the original author or authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn () { + echo "$*" +} + +die () { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin or MSYS, switch paths to Windows format before running java +if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=`expr $i + 1` + done + case $i in + 0) set -- ;; + 1) set -- "$args0" ;; + 2) set -- "$args0" "$args1" ;; + 3) set -- "$args0" "$args1" "$args2" ;; + 4) set -- "$args0" "$args1" "$args2" "$args3" ;; + 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=`save "$@"` + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +exec "$JAVACMD" "$@" diff --git a/ph-ee-connector-common/gradlew.bat b/ph-ee-connector-common/gradlew.bat new file mode 100644 index 000000000..9109989e3 --- /dev/null +++ b/ph-ee-connector-common/gradlew.bat @@ -0,0 +1,103 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windows variants + +if not "%OS%" == "Windows_NT" goto win9xME_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/ph-ee-connector-common/settings.gradle b/ph-ee-connector-common/settings.gradle new file mode 100644 index 000000000..6ed560ed2 --- /dev/null +++ b/ph-ee-connector-common/settings.gradle @@ -0,0 +1,13 @@ +/* + * This file was generated by the Gradle 'init' task. + */ +//app_username = '' +//app_password = '' +// app_name = 'ph-ee-connector-common' +// version = '1.0.0-SNAPSHOT' + +gradle.ext{ + app_username = '' + app_password = '' +} +rootProject.name = 'ph-ee-connector-common' \ No newline at end of file diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/ams/dto/AccountType.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/ams/dto/AccountType.java new file mode 100644 index 000000000..9f5aeb597 --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/ams/dto/AccountType.java @@ -0,0 +1,44 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.mifos.connector.common.ams.dto; + +public enum AccountType { + + INVALID(0, "accountType.invalid"), // + INDIVIDUAL(1, "accountType.individual"), // + GROUP(2, "accountType.group"), // + JLG(3, "accountType.jlg");// JLG account given in group context + + private final Integer value; + private final String code; + + AccountType(final Integer value, final String code) { + this.value = value; + this.code = code; + } + + public Integer getValue() { + return this.value; + } + + public String getCode() { + return this.code; + } + +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/ams/dto/Action.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/ams/dto/Action.java new file mode 100644 index 000000000..950cd1287 --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/ams/dto/Action.java @@ -0,0 +1,61 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.mifos.connector.common.ams.dto; + +public class Action { + + private String identifier; + private String name; + private String description; + private String transactionType; + + public Action() {} + + public String getIdentifier() { + return this.identifier; + } + + public void setIdentifier(final String identifier) { + this.identifier = identifier; + } + + public String getName() { + return this.name; + } + + public void setName(final String name) { + this.name = name; + } + + public String getDescription() { + return this.description; + } + + public void setDescription(final String description) { + this.description = description; + } + + public String getTransactionType() { + return this.transactionType; + } + + public void setTransactionType(final String transactionType) { + this.transactionType = transactionType; + } +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/ams/dto/Address.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/ams/dto/Address.java new file mode 100644 index 000000000..6cf566a29 --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/ams/dto/Address.java @@ -0,0 +1,77 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.mifos.connector.common.ams.dto; + +public final class Address { + + private String street; + private String city; + private String region; + private String postalCode; + private String countryCode; + private String country; + + public String getStreet() { + return street; + } + + public void setStreet(String street) { + this.street = street; + } + + public String getCity() { + return city; + } + + public void setCity(String city) { + this.city = city; + } + + public String getRegion() { + return region; + } + + public void setRegion(String region) { + this.region = region; + } + + public String getPostalCode() { + return postalCode; + } + + public void setPostalCode(String postalCode) { + this.postalCode = postalCode; + } + + public String getCountryCode() { + return countryCode; + } + + public void setCountryCode(String countryCode) { + this.countryCode = countryCode; + } + + public String getCountry() { + return country; + } + + public void setCountry(String country) { + this.country = country; + } +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/ams/dto/Charge.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/ams/dto/Charge.java new file mode 100644 index 000000000..649b570f1 --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/ams/dto/Charge.java @@ -0,0 +1,79 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.mifos.connector.common.ams.dto; + +public class Charge { + + private String actionIdentifier; + private String incomeAccountIdentifier; + private String name; + private String description; + private Boolean proportional; + private Double amount; + + public Charge() {} + + public String getActionIdentifier() { + return this.actionIdentifier; + } + + public void setActionIdentifier(final String actionIdentifier) { + this.actionIdentifier = actionIdentifier; + } + + public String getIncomeAccountIdentifier() { + return this.incomeAccountIdentifier; + } + + public void setIncomeAccountIdentifier(final String incomeAccountIdentifier) { + this.incomeAccountIdentifier = incomeAccountIdentifier; + } + + public String getName() { + return this.name; + } + + public void setName(final String name) { + this.name = name; + } + + public String getDescription() { + return this.description; + } + + public void setDescription(final String description) { + this.description = description; + } + + public Boolean getProportional() { + return this.proportional; + } + + public void setProportional(final Boolean proportional) { + this.proportional = proportional; + } + + public Double getAmount() { + return this.amount; + } + + public void setAmount(final Double amount) { + this.amount = amount; + } +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/ams/dto/ClientData.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/ams/dto/ClientData.java new file mode 100644 index 000000000..c5396d74a --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/ams/dto/ClientData.java @@ -0,0 +1,279 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.mifos.connector.common.ams.dto; + +import com.fasterxml.jackson.annotation.JsonProperty; +import java.time.LocalDate; + +public class ClientData { + + private Long id; + private String accountNo; + private String externalId; + private EnumOptionData status; + private EnumOptionData legalForm; + private CodeValueData subStatus; + private Boolean active; + private LocalDate activationDate; + private String firstname; + private String middlename; + private String lastname; + private String fullname; + private String displayName; + private String mobileNo; + private String emailAddress; + private LocalDate dateOfBirth; + private CodeValueData gender; + private CodeValueData clientType; + private CodeValueData clientClassification; + @JsonProperty(value = "isStaff") + private Boolean isStaff; + private Long officeId; + private String officeName; + private Long transferToOfficeId; + private String transferToOfficeName; + private Long imageId; + private Boolean imagePresent; + private Long staffId; + private String staffName; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getAccountNo() { + return accountNo; + } + + public void setAccountNo(String accountNo) { + this.accountNo = accountNo; + } + + public String getExternalId() { + return externalId; + } + + public void setExternalId(String externalId) { + this.externalId = externalId; + } + + public EnumOptionData getStatus() { + return status; + } + + public void setStatus(EnumOptionData status) { + this.status = status; + } + + public EnumOptionData getLegalForm() { + return legalForm; + } + + public void setLegalForm(EnumOptionData legalForm) { + this.legalForm = legalForm; + } + + public CodeValueData getSubStatus() { + return subStatus; + } + + public void setSubStatus(CodeValueData subStatus) { + this.subStatus = subStatus; + } + + public Boolean getActive() { + return active; + } + + public void setActive(Boolean active) { + this.active = active; + } + + public LocalDate getActivationDate() { + return activationDate; + } + + public void setActivationDate(LocalDate activationDate) { + this.activationDate = activationDate; + } + + public String getFirstname() { + return firstname; + } + + public void setFirstname(String firstname) { + this.firstname = firstname; + } + + public String getMiddlename() { + return middlename; + } + + public void setMiddlename(String middlename) { + this.middlename = middlename; + } + + public String getLastname() { + return lastname; + } + + public void setLastname(String lastname) { + this.lastname = lastname; + } + + public String getFullname() { + return fullname; + } + + public void setFullname(String fullname) { + this.fullname = fullname; + } + + public String getDisplayName() { + return displayName; + } + + public void setDisplayName(String displayName) { + this.displayName = displayName; + } + + public String getMobileNo() { + return mobileNo; + } + + public void setMobileNo(String mobileNo) { + this.mobileNo = mobileNo; + } + + public String getEmailAddress() { + return emailAddress; + } + + public void setEmailAddress(String emailAddress) { + this.emailAddress = emailAddress; + } + + public LocalDate getDateOfBirth() { + return dateOfBirth; + } + + public void setDateOfBirth(LocalDate dateOfBirth) { + this.dateOfBirth = dateOfBirth; + } + + public CodeValueData getGender() { + return gender; + } + + public void setGender(CodeValueData gender) { + this.gender = gender; + } + + public CodeValueData getClientType() { + return clientType; + } + + public void setClientType(CodeValueData clientType) { + this.clientType = clientType; + } + + public CodeValueData getClientClassification() { + return clientClassification; + } + + public void setClientClassification(CodeValueData clientClassification) { + this.clientClassification = clientClassification; + } + + public Boolean getStaff() { + return isStaff; + } + + public void setStaff(Boolean staff) { + isStaff = staff; + } + + public Long getOfficeId() { + return officeId; + } + + public void setOfficeId(Long officeId) { + this.officeId = officeId; + } + + public String getOfficeName() { + return officeName; + } + + public void setOfficeName(String officeName) { + this.officeName = officeName; + } + + public Long getTransferToOfficeId() { + return transferToOfficeId; + } + + public void setTransferToOfficeId(Long transferToOfficeId) { + this.transferToOfficeId = transferToOfficeId; + } + + public String getTransferToOfficeName() { + return transferToOfficeName; + } + + public void setTransferToOfficeName(String transferToOfficeName) { + this.transferToOfficeName = transferToOfficeName; + } + + public Long getImageId() { + return imageId; + } + + public void setImageId(Long imageId) { + this.imageId = imageId; + } + + public Boolean getImagePresent() { + return imagePresent; + } + + public void setImagePresent(Boolean imagePresent) { + this.imagePresent = imagePresent; + } + + public Long getStaffId() { + return staffId; + } + + public void setStaffId(Long staffId) { + this.staffId = staffId; + } + + public String getStaffName() { + return staffName; + } + + public void setStaffName(String staffName) { + this.staffName = staffName; + } +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/ams/dto/ClientTimelineData.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/ams/dto/ClientTimelineData.java new file mode 100644 index 000000000..b800581eb --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/ams/dto/ClientTimelineData.java @@ -0,0 +1,135 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.mifos.connector.common.ams.dto; + +import java.time.LocalDate; + +public class ClientTimelineData { + + private LocalDate submittedOnDate; + private String submittedByUsername; + private String submittedByFirstname; + private String submittedByLastname; + + private LocalDate activatedOnDate; + private String activatedByUsername; + private String activatedByFirstname; + private String activatedByLastname; + + private LocalDate closedOnDate; + private String closedByUsername; + private String closedByFirstname; + private String closedByLastname; + + public LocalDate getSubmittedOnDate() { + return submittedOnDate; + } + + public void setSubmittedOnDate(LocalDate submittedOnDate) { + this.submittedOnDate = submittedOnDate; + } + + public String getSubmittedByUsername() { + return submittedByUsername; + } + + public void setSubmittedByUsername(String submittedByUsername) { + this.submittedByUsername = submittedByUsername; + } + + public String getSubmittedByFirstname() { + return submittedByFirstname; + } + + public void setSubmittedByFirstname(String submittedByFirstname) { + this.submittedByFirstname = submittedByFirstname; + } + + public String getSubmittedByLastname() { + return submittedByLastname; + } + + public void setSubmittedByLastname(String submittedByLastname) { + this.submittedByLastname = submittedByLastname; + } + + public LocalDate getActivatedOnDate() { + return activatedOnDate; + } + + public void setActivatedOnDate(LocalDate activatedOnDate) { + this.activatedOnDate = activatedOnDate; + } + + public String getActivatedByUsername() { + return activatedByUsername; + } + + public void setActivatedByUsername(String activatedByUsername) { + this.activatedByUsername = activatedByUsername; + } + + public String getActivatedByFirstname() { + return activatedByFirstname; + } + + public void setActivatedByFirstname(String activatedByFirstname) { + this.activatedByFirstname = activatedByFirstname; + } + + public String getActivatedByLastname() { + return activatedByLastname; + } + + public void setActivatedByLastname(String activatedByLastname) { + this.activatedByLastname = activatedByLastname; + } + + public LocalDate getClosedOnDate() { + return closedOnDate; + } + + public void setClosedOnDate(LocalDate closedOnDate) { + this.closedOnDate = closedOnDate; + } + + public String getClosedByUsername() { + return closedByUsername; + } + + public void setClosedByUsername(String closedByUsername) { + this.closedByUsername = closedByUsername; + } + + public String getClosedByFirstname() { + return closedByFirstname; + } + + public void setClosedByFirstname(String closedByFirstname) { + this.closedByFirstname = closedByFirstname; + } + + public String getClosedByLastname() { + return closedByLastname; + } + + public void setClosedByLastname(String closedByLastname) { + this.closedByLastname = closedByLastname; + } +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/ams/dto/CodeValueData.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/ams/dto/CodeValueData.java new file mode 100644 index 000000000..a2faed658 --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/ams/dto/CodeValueData.java @@ -0,0 +1,55 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.mifos.connector.common.ams.dto; + +import java.io.Serializable; + +public class CodeValueData implements Serializable { + + private Long id; + private String name; + private Integer position; + private String description; + private boolean active; + private boolean mandatory; + + public Long getId() { + return id; + } + + public String getName() { + return name; + } + + public Integer getPosition() { + return position; + } + + public String getDescription() { + return description; + } + + public boolean isActive() { + return active; + } + + public boolean isMandatory() { + return mandatory; + } +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/ams/dto/Currency.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/ams/dto/Currency.java new file mode 100644 index 000000000..a5ccd2169 --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/ams/dto/Currency.java @@ -0,0 +1,61 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.mifos.connector.common.ams.dto; + +public class Currency { + + private String code; + private String name; + private String sign; + private Integer scale; + + public Currency() {} + + public String getCode() { + return this.code; + } + + public void setCode(final String code) { + this.code = code; + } + + public String getName() { + return this.name; + } + + public void setName(final String name) { + this.name = name; + } + + public String getSign() { + return this.sign; + } + + public void setSign(final String sign) { + this.sign = sign; + } + + public Integer getScale() { + return this.scale; + } + + public void setScale(final Integer scale) { + this.scale = scale; + } +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/ams/dto/Customer.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/ams/dto/Customer.java new file mode 100644 index 000000000..547875f17 --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/ams/dto/Customer.java @@ -0,0 +1,185 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.mifos.connector.common.ams.dto; + +public class Customer { + + private String identifier; + private LegalForm type; + private String givenName; + private String middleName; + private String surname; + private DateOfBirth dateOfBirth; + private Boolean member; + private String accountBeneficiary; + private String referenceCustomer; + private String assignedOffice; + private String assignedEmployee; + private Address address; + private CustomerState currentState; + private String applicationDate; + private String createdBy; + private String createdOn; + private String lastModifiedBy; + private String lastModifiedOn; + + public String getIdentifier() { + return identifier; + } + + public void setIdentifier(String identifier) { + this.identifier = identifier; + } + + public LegalForm getType() { + return type; + } + + public void setType(LegalForm type) { + this.type = type; + } + + public String getGivenName() { + return givenName; + } + + public void setGivenName(String givenName) { + this.givenName = givenName; + } + + public String getMiddleName() { + return middleName; + } + + public void setMiddleName(String middleName) { + this.middleName = middleName; + } + + public String getSurname() { + return surname; + } + + public void setSurname(String surname) { + this.surname = surname; + } + + public DateOfBirth getDateOfBirth() { + return dateOfBirth; + } + + public void setDateOfBirth(DateOfBirth dateOfBirth) { + this.dateOfBirth = dateOfBirth; + } + + public Boolean getMember() { + return member; + } + + public void setMember(Boolean member) { + this.member = member; + } + + public String getAccountBeneficiary() { + return accountBeneficiary; + } + + public void setAccountBeneficiary(String accountBeneficiary) { + this.accountBeneficiary = accountBeneficiary; + } + + public String getReferenceCustomer() { + return referenceCustomer; + } + + public void setReferenceCustomer(String referenceCustomer) { + this.referenceCustomer = referenceCustomer; + } + + public String getAssignedOffice() { + return assignedOffice; + } + + public void setAssignedOffice(String assignedOffice) { + this.assignedOffice = assignedOffice; + } + + public String getAssignedEmployee() { + return assignedEmployee; + } + + public void setAssignedEmployee(String assignedEmployee) { + this.assignedEmployee = assignedEmployee; + } + + public Address getAddress() { + return address; + } + + public void setAddress(Address address) { + this.address = address; + } + + public CustomerState getCurrentState() { + return currentState; + } + + public void setCurrentState(CustomerState currentState) { + this.currentState = currentState; + } + + public String getApplicationDate() { + return applicationDate; + } + + public void setApplicationDate(String applicationDate) { + this.applicationDate = applicationDate; + } + + public String getCreatedBy() { + return createdBy; + } + + public void setCreatedBy(String createdBy) { + this.createdBy = createdBy; + } + + public String getCreatedOn() { + return createdOn; + } + + public void setCreatedOn(String createdOn) { + this.createdOn = createdOn; + } + + public String getLastModifiedBy() { + return lastModifiedBy; + } + + public void setLastModifiedBy(String lastModifiedBy) { + this.lastModifiedBy = lastModifiedBy; + } + + public String getLastModifiedOn() { + return lastModifiedOn; + } + + public void setLastModifiedOn(String lastModifiedOn) { + this.lastModifiedOn = lastModifiedOn; + } +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/ams/dto/CustomerState.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/ams/dto/CustomerState.java new file mode 100644 index 000000000..fc969c9df --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/ams/dto/CustomerState.java @@ -0,0 +1,5 @@ +package org.mifos.connector.common.ams.dto; + +public enum CustomerState { + PENDING, ACTIVE, LOCKED, CLOSED +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/ams/dto/DateOfBirth.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/ams/dto/DateOfBirth.java new file mode 100644 index 000000000..512b2d406 --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/ams/dto/DateOfBirth.java @@ -0,0 +1,54 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.mifos.connector.common.ams.dto; + +public class DateOfBirth { + + private Integer year; + private Integer month; + private Integer day; + + public Integer getYear() { + return year; + } + + public void setYear(Integer year) { + this.year = year; + } + + public Integer getMonth() { + return month; + } + + public void setMonth(Integer month) { + this.month = month; + } + + public Integer getDay() { + return day; + } + + public void setDay(Integer day) { + this.day = day; + } + + public String toString() { + return String.valueOf(year) + "-" + (month < 10 ? "0" + month : month) + "-" + (day < 10 ? "0" + day : day); + } +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/ams/dto/DepositAccountType.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/ams/dto/DepositAccountType.java new file mode 100644 index 000000000..731ae70f8 --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/ams/dto/DepositAccountType.java @@ -0,0 +1,44 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.mifos.connector.common.ams.dto; + +public enum DepositAccountType { + + INVALID(0, "depositAccountType.invalid"), // + SAVINGS_DEPOSIT(100, "depositAccountType.savingsDeposit"), // + FIXED_DEPOSIT(200, "depositAccountType.fixedDeposit"), // + RECURRING_DEPOSIT(300, "depositAccountType.recurringDeposit"), // + CURRENT_DEPOSIT(400, "depositAccountType.currentDeposit"); + + private final Integer value; + private final String code; + + DepositAccountType(final Integer value, final String code) { + this.value = value; + this.code = code; + } + + public Integer getValue() { + return this.value; + } + + public String getCode() { + return this.code; + } +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/ams/dto/DividendDistribution.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/ams/dto/DividendDistribution.java new file mode 100644 index 000000000..9676e2547 --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/ams/dto/DividendDistribution.java @@ -0,0 +1,43 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.mifos.connector.common.ams.dto; + +public class DividendDistribution { + + private DateOfBirth dueDate; + private String dividendRate; + + public DividendDistribution() {} + + public DateOfBirth getDueDate() { + return this.dueDate; + } + + public void setDueDate(final DateOfBirth dueDate) { + this.dueDate = dueDate; + } + + public String getDividendRate() { + return this.dividendRate; + } + + public void setDividendRate(final String dividendRate) { + this.dividendRate = dividendRate; + } +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/ams/dto/EnumOptionData.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/ams/dto/EnumOptionData.java new file mode 100644 index 000000000..9a3357e9b --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/ams/dto/EnumOptionData.java @@ -0,0 +1,38 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.mifos.connector.common.ams.dto; + +public class EnumOptionData { + + private Long id; + private String code; + private String value; + + public Long getId() { + return id; + } + + public String getCode() { + return code; + } + + public String getValue() { + return value; + } +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/ams/dto/InterestPayable.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/ams/dto/InterestPayable.java new file mode 100644 index 000000000..6ecec815c --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/ams/dto/InterestPayable.java @@ -0,0 +1,23 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.mifos.connector.common.ams.dto; + +public enum InterestPayable { + MATURITY, ANNUALLY, MONTHLY, QUARTERLY +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/ams/dto/InteropAccountDTO.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/ams/dto/InteropAccountDTO.java new file mode 100644 index 000000000..0d7b92831 --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/ams/dto/InteropAccountDTO.java @@ -0,0 +1,182 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.mifos.connector.common.ams.dto; + +import java.math.BigDecimal; +import java.time.LocalDate; +import java.util.List; + +public class InteropAccountDTO { + + private String accountId; + private String savingProductId; + private String productName; + private String shortProductName; + private String currency; + private BigDecimal accountBalance; + private BigDecimal availableBalance; + private SavingsAccountStatusType status; + private SavingsAccountSubStatusEnum subStatus; + private AccountType accountType; + private DepositAccountType depositType; + private LocalDate activatedOn; + private LocalDate statusUpdateOn; + private LocalDate withdrawnOn; + private LocalDate balanceOn; + private List identifiers; + private String clientId; + + public InteropAccountDTO() {} + + public String getAccountId() { + return accountId; + } + + public void setAccountId(String accountId) { + this.accountId = accountId; + } + + public String getSavingProductId() { + return savingProductId; + } + + public void setSavingProductId(String savingProductId) { + this.savingProductId = savingProductId; + } + + public String getProductName() { + return productName; + } + + public void setProductName(String productName) { + this.productName = productName; + } + + public String getShortProductName() { + return shortProductName; + } + + public void setShortProductName(String shortProductName) { + this.shortProductName = shortProductName; + } + + public String getCurrency() { + return currency; + } + + public void setCurrency(String currency) { + this.currency = currency; + } + + public BigDecimal getAccountBalance() { + return accountBalance; + } + + public void setAccountBalance(BigDecimal accountBalance) { + this.accountBalance = accountBalance; + } + + public BigDecimal getAvailableBalance() { + return availableBalance; + } + + public void setAvailableBalance(BigDecimal availableBalance) { + this.availableBalance = availableBalance; + } + + public SavingsAccountStatusType getStatus() { + return status; + } + + public void setStatus(SavingsAccountStatusType status) { + this.status = status; + } + + public SavingsAccountSubStatusEnum getSubStatus() { + return subStatus; + } + + public void setSubStatus(SavingsAccountSubStatusEnum subStatus) { + this.subStatus = subStatus; + } + + public AccountType getAccountType() { + return accountType; + } + + public void setAccountType(AccountType accountType) { + this.accountType = accountType; + } + + public DepositAccountType getDepositType() { + return depositType; + } + + public void setDepositType(DepositAccountType depositType) { + this.depositType = depositType; + } + + public LocalDate getActivatedOn() { + return activatedOn; + } + + public void setActivatedOn(LocalDate activatedOn) { + this.activatedOn = activatedOn; + } + + public LocalDate getStatusUpdateOn() { + return statusUpdateOn; + } + + public void setStatusUpdateOn(LocalDate statusUpdateOn) { + this.statusUpdateOn = statusUpdateOn; + } + + public LocalDate getWithdrawnOn() { + return withdrawnOn; + } + + public void setWithdrawnOn(LocalDate withdrawnOn) { + this.withdrawnOn = withdrawnOn; + } + + public LocalDate getBalanceOn() { + return balanceOn; + } + + public void setBalanceOn(LocalDate balanceOn) { + this.balanceOn = balanceOn; + } + + public List getIdentifiers() { + return identifiers; + } + + public void setIdentifiers(List identifiers) { + this.identifiers = identifiers; + } + + public String getClientId() { + return clientId; + } + + public void setClientId(String clientId) { + this.clientId = clientId; + } +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/ams/dto/InteropIdentifierData.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/ams/dto/InteropIdentifierData.java new file mode 100644 index 000000000..df8424ac9 --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/ams/dto/InteropIdentifierData.java @@ -0,0 +1,52 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.mifos.connector.common.ams.dto; + +public class InteropIdentifierData { + + private InteropIdentifierType idType; + private String idValue; + private String subIdOrType; + + public InteropIdentifierData() {} + + public InteropIdentifierType getIdType() { + return idType; + } + + public void setIdType(InteropIdentifierType idType) { + this.idType = idType; + } + + public String getIdValue() { + return idValue; + } + + public void setIdValue(String idValue) { + this.idValue = idValue; + } + + public String getSubIdOrType() { + return subIdOrType; + } + + public void setSubIdOrType(String subIdOrType) { + this.subIdOrType = subIdOrType; + } +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/ams/dto/InteropIdentifierType.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/ams/dto/InteropIdentifierType.java new file mode 100644 index 000000000..d389c2000 --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/ams/dto/InteropIdentifierType.java @@ -0,0 +1,24 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.mifos.connector.common.ams.dto; + +public enum InteropIdentifierType { + + MSISDN, EMAIL, PERSONAL_ID, BUSINESS, DEVICE, ACCOUNT_ID, IBAN, ALIAS +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/ams/dto/LegalForm.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/ams/dto/LegalForm.java new file mode 100644 index 000000000..eeabe324f --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/ams/dto/LegalForm.java @@ -0,0 +1,56 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.mifos.connector.common.ams.dto; + +public enum LegalForm { + + PERSON(1, "legalFormType.person"), + + ENTITY(2, "legalFormType.entity"); + + private final Integer value; + private final String code; + + LegalForm(final Integer value, final String code) { + this.value = value; + this.code = code; + } + + public Integer getValue() { + return this.value; + } + + public String getCode() { + return this.code; + } + + public static LegalForm fromValue(final Integer type) { + + LegalForm legalForm = null; + switch (type) { + case 1: + legalForm = LegalForm.PERSON; + break; + case 2: + legalForm = LegalForm.ENTITY; + break; + } + return legalForm; + } +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/ams/dto/LoanRepaymentDTO.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/ams/dto/LoanRepaymentDTO.java new file mode 100644 index 000000000..37ff77a01 --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/ams/dto/LoanRepaymentDTO.java @@ -0,0 +1,76 @@ +package org.mifos.connector.common.ams.dto; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; + +@JsonInclude(JsonInclude.Include.NON_NULL) +public class LoanRepaymentDTO { + + @JsonProperty("transactionDate") + public String transactionDate; + @JsonProperty("paymentTypeId") + public String paymentTypeId; + @JsonProperty("transactionAmount") + public String transactionAmount; + @JsonProperty("locale") + public String locale; + @JsonProperty("dateFormat") + public String dateFormat; + + @Override + public String toString() { + return "LoanRepaymentDTO{" + "transactionDate='" + transactionDate + '\'' + ", paymentTypeId='" + paymentTypeId + '\'' + + ", transactionAmount='" + transactionAmount + '\'' + ", locale='" + locale + '\'' + ", dateFormat='" + dateFormat + '\'' + + '}'; + } + + public String getTransactionDate() { + return transactionDate; + } + + public void setTransactionDate(String transactionDate) { + this.transactionDate = transactionDate; + } + + public String getPaymentTypeId() { + return paymentTypeId; + } + + public void setPaymentTypeId(String paymentTypeId) { + this.paymentTypeId = paymentTypeId; + } + + public String getTransactionAmount() { + return transactionAmount; + } + + public void setTransactionAmount(String transactionAmount) { + this.transactionAmount = transactionAmount; + } + + public String getLocale() { + return locale; + } + + public void setLocale(String locale) { + this.locale = locale; + } + + public String getDateFormat() { + return dateFormat; + } + + public void setDateFormat(String dateFormat) { + this.dateFormat = dateFormat; + } + + public LoanRepaymentDTO() {} + + public LoanRepaymentDTO(String transactionDate, String paymentTypeId, String transactionAmount, String locale, String dateFormat) { + this.transactionDate = transactionDate; + this.paymentTypeId = paymentTypeId; + this.transactionAmount = transactionAmount; + this.locale = locale; + this.dateFormat = dateFormat; + } +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/ams/dto/LoginFineractCnResponseDTO.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/ams/dto/LoginFineractCnResponseDTO.java new file mode 100644 index 000000000..6d3063664 --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/ams/dto/LoginFineractCnResponseDTO.java @@ -0,0 +1,59 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla + * Public License, v. 2.0. If a copy of the MPL was not distributed + * with this file, You can obtain one at + * + * https://mozilla.org/MPL/2.0/. + */ +package org.mifos.connector.common.ams.dto; + +import java.util.Date; + +public class LoginFineractCnResponseDTO implements LoginFspResponse { + + private String tokenType; + private String accessToken; + private Date accessTokenExpiration; + private Date refreshTokenExpiration; + private Date passwordExpiration; + + public String getTokenType() { + return tokenType; + } + + public void setTokenType(String tokenType) { + this.tokenType = tokenType; + } + + public String getAccessToken() { + return accessToken; + } + + public void setAccessToken(String accessToken) { + this.accessToken = accessToken; + } + + public Date getAccessTokenExpiration() { + return accessTokenExpiration; + } + + public void setAccessTokenExpiration(Date accessTokenExpiration) { + this.accessTokenExpiration = accessTokenExpiration; + } + + public Date getRefreshTokenExpiration() { + return refreshTokenExpiration; + } + + public void setRefreshTokenExpiration(Date refreshTokenExpiration) { + this.refreshTokenExpiration = refreshTokenExpiration; + } + + public Date getPasswordExpiration() { + return passwordExpiration; + } + + public void setPasswordExpiration(Date passwordExpiration) { + this.passwordExpiration = passwordExpiration; + } +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/ams/dto/LoginFineractXResponseDTO.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/ams/dto/LoginFineractXResponseDTO.java new file mode 100644 index 000000000..4bd084568 --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/ams/dto/LoginFineractXResponseDTO.java @@ -0,0 +1,113 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla + * Public License, v. 2.0. If a copy of the MPL was not distributed + * with this file, You can obtain one at + * + * https://mozilla.org/MPL/2.0/. + */ +package org.mifos.connector.common.ams.dto; + +import java.util.Collection; +import java.util.Date; + +public class LoginFineractXResponseDTO implements LoginFspResponse { + + private String username; + private Long userId; + private String base64EncodedAuthenticationKey; + private boolean authenticated; + private Long officeId; + private String officeName; + private Collection roles; + private Collection permissions; + private boolean shouldRenewPassword; + private boolean isTwoFactorAuthenticationRequired; + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public Long getUserId() { + return userId; + } + + public void setUserId(Long userId) { + this.userId = userId; + } + + public String getBase64EncodedAuthenticationKey() { + return base64EncodedAuthenticationKey; + } + + public void setBase64EncodedAuthenticationKey(String base64EncodedAuthenticationKey) { + this.base64EncodedAuthenticationKey = base64EncodedAuthenticationKey; + } + + public boolean isAuthenticated() { + return authenticated; + } + + public void setAuthenticated(boolean authenticated) { + this.authenticated = authenticated; + } + + public boolean isShouldRenewPassword() { + return shouldRenewPassword; + } + + public void setShouldRenewPassword(boolean shouldRenewPassword) { + this.shouldRenewPassword = shouldRenewPassword; + } + + public boolean getIsTwoFactorAuthenticationRequired() { + return isTwoFactorAuthenticationRequired; + } + + public void setIsTwoFactorAuthenticationRequired(boolean isTwoFactorAuthenticationRequired) { + this.isTwoFactorAuthenticationRequired = isTwoFactorAuthenticationRequired; + } + + public Long getOfficeId() { + return officeId; + } + + public void setOfficeId(Long officeId) { + this.officeId = officeId; + } + + public String getOfficeName() { + return officeName; + } + + public void setOfficeName(String officeName) { + this.officeName = officeName; + } + + public Collection getRoles() { + return roles; + } + + public void setRoles(Collection roles) { + this.roles = roles; + } + + public Collection getPermissions() { + return permissions; + } + + public void setPermissions(Collection permissions) { + this.permissions = permissions; + } + + public String getAccessToken() { + return base64EncodedAuthenticationKey; + } + + public Date getAccessTokenExpiration() { + return shouldRenewPassword ? new Date(System.currentTimeMillis() + 5 * 60 * 60 * 1000) : null; // TODO: TIMEZONE + } +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/ams/dto/LoginFspResponse.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/ams/dto/LoginFspResponse.java new file mode 100644 index 000000000..f48d0d408 --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/ams/dto/LoginFspResponse.java @@ -0,0 +1,17 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla + * Public License, v. 2.0. If a copy of the MPL was not distributed + * with this file, You can obtain one at + * + * https://mozilla.org/MPL/2.0/. + */ +package org.mifos.connector.common.ams.dto; + +import java.util.Date; + +public interface LoginFspResponse { + + String getAccessToken(); + + Date getAccessTokenExpiration(); +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/ams/dto/PartyFspResponseDTO.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/ams/dto/PartyFspResponseDTO.java new file mode 100644 index 000000000..842502ec4 --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/ams/dto/PartyFspResponseDTO.java @@ -0,0 +1,21 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla + * Public License, v. 2.0. If a copy of the MPL was not distributed + * with this file, You can obtain one at + * + * https://mozilla.org/MPL/2.0/. + */ +package org.mifos.connector.common.ams.dto; + +public class PartyFspResponseDTO { + + private String accountId; + + public String getAccountId() { + return accountId; + } + + public void setAccountId(String accountId) { + this.accountId = accountId; + } +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/ams/dto/ProductDefinition.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/ams/dto/ProductDefinition.java new file mode 100644 index 000000000..2c9922cd8 --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/ams/dto/ProductDefinition.java @@ -0,0 +1,162 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.mifos.connector.common.ams.dto; + +import java.util.Set; + +public class ProductDefinition { + + private Type type; + private String identifier; + private String name; + private String description; + private Currency currency; + private Double minimumBalance; + private String equityLedgerIdentifier; + private String cashAccountIdentifier; + private String expenseAccountIdentifier; + private String accrueAccountIdentifier; + private Double interest; + private Term term; + private Set charges; + private Boolean flexible; + private Boolean active; + + public ProductDefinition() {} + + public String getType() { + return this.type.name(); + } + + public void setType(final String type) { + this.type = Type.valueOf(type); + } + + public String getIdentifier() { + return this.identifier; + } + + public void setIdentifier(final String identifier) { + this.identifier = identifier; + } + + public String getName() { + return this.name; + } + + public void setName(final String name) { + this.name = name; + } + + public String getDescription() { + return this.description; + } + + public void setDescription(final String description) { + this.description = description; + } + + public Currency getCurrency() { + return this.currency; + } + + public void setCurrency(final Currency currency) { + this.currency = currency; + } + + public Double getMinimumBalance() { + return this.minimumBalance; + } + + public void setMinimumBalance(final Double minimumBalance) { + this.minimumBalance = minimumBalance; + } + + public String getEquityLedgerIdentifier() { + return this.equityLedgerIdentifier; + } + + public void setEquityLedgerIdentifier(final String equityLedgerIdentifier) { + this.equityLedgerIdentifier = equityLedgerIdentifier; + } + + public String getCashAccountIdentifier() { + return this.cashAccountIdentifier; + } + + public void setCashAccountIdentifier(final String cashAccountIdentifier) { + this.cashAccountIdentifier = cashAccountIdentifier; + } + + public String getExpenseAccountIdentifier() { + return this.expenseAccountIdentifier; + } + + public void setExpenseAccountIdentifier(final String expenseAccountIdentifier) { + this.expenseAccountIdentifier = expenseAccountIdentifier; + } + + public String getAccrueAccountIdentifier() { + return this.accrueAccountIdentifier; + } + + public void setAccrueAccountIdentifier(final String accrueAccountIdentifier) { + this.accrueAccountIdentifier = accrueAccountIdentifier; + } + + public Double getInterest() { + return this.interest; + } + + public void setInterest(final Double interest) { + this.interest = interest; + } + + public Term getTerm() { + return this.term; + } + + public void setTerm(final Term term) { + this.term = term; + } + + public Set getCharges() { + return this.charges; + } + + public void setCharges(final Set charges) { + this.charges = charges; + } + + public Boolean getFlexible() { + return this.flexible; + } + + public void setFlexible(final Boolean flexible) { + this.flexible = flexible; + } + + public Boolean getActive() { + return this.active; + } + + public void setActive(final Boolean active) { + this.active = active; + } +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/ams/dto/ProductInstance.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/ams/dto/ProductInstance.java new file mode 100644 index 000000000..e0dc28c9f --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/ams/dto/ProductInstance.java @@ -0,0 +1,106 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.mifos.connector.common.ams.dto; + +import java.util.Set; + +public class ProductInstance { + + private String customerIdentifier; + private String productIdentifier; + private String accountIdentifier; + private String alternativeAccountNumber; + private Set beneficiaries; + private String openedOn; + private String lastTransactionDate; + private String state; + private Double balance; + + public String getCustomerIdentifier() { + return customerIdentifier; + } + + public void setCustomerIdentifier(String customerIdentifier) { + this.customerIdentifier = customerIdentifier; + } + + public String getProductIdentifier() { + return productIdentifier; + } + + public void setProductIdentifier(String productIdentifier) { + this.productIdentifier = productIdentifier; + } + + public String getAccountIdentifier() { + return accountIdentifier; + } + + public void setAccountIdentifier(String accountIdentifier) { + this.accountIdentifier = accountIdentifier; + } + + public String getAlternativeAccountNumber() { + return alternativeAccountNumber; + } + + public void setAlternativeAccountNumber(String alternativeAccountNumber) { + this.alternativeAccountNumber = alternativeAccountNumber; + } + + public Set getBeneficiaries() { + return beneficiaries; + } + + public void setBeneficiaries(Set beneficiaries) { + this.beneficiaries = beneficiaries; + } + + public String getOpenedOn() { + return openedOn; + } + + public void setOpenedOn(String openedOn) { + this.openedOn = openedOn; + } + + public String getLastTransactionDate() { + return lastTransactionDate; + } + + public void setLastTransactionDate(String lastTransactionDate) { + this.lastTransactionDate = lastTransactionDate; + } + + public String getState() { + return state; + } + + public void setState(String state) { + this.state = state; + } + + public Double getBalance() { + return balance; + } + + public void setBalance(Double balance) { + this.balance = balance; + } +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/ams/dto/QuoteFspRequestDTO.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/ams/dto/QuoteFspRequestDTO.java new file mode 100644 index 000000000..cddedcd2e --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/ams/dto/QuoteFspRequestDTO.java @@ -0,0 +1,103 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla + * Public License, v. 2.0. If a copy of the MPL was not distributed + * with this file, You can obtain one at + * + * https://mozilla.org/MPL/2.0/. + */ +package org.mifos.connector.common.ams.dto; + +import org.mifos.connector.common.mojaloop.dto.FspMoneyData; +import org.mifos.connector.common.mojaloop.dto.TransactionType; +import org.mifos.connector.common.mojaloop.type.AmountType; +import org.mifos.connector.common.mojaloop.type.TransactionRole; + +public class QuoteFspRequestDTO { + + private String transactionCode; + private String requestCode; + private String quoteCode; + private String accountId; + private FspMoneyData amount; + private AmountType amountType; + private TransactionRole transactionRole; + private TransactionType transactionType; + + public QuoteFspRequestDTO() {} + + public QuoteFspRequestDTO(String transactionCode, String requestCode, String quoteCode, String accountId, FspMoneyData amount, + AmountType amountType, TransactionRole transactionRole, TransactionType transactionType) { + this.transactionCode = transactionCode; + this.requestCode = requestCode; + this.quoteCode = quoteCode; + this.accountId = accountId; + this.amount = amount; + this.amountType = amountType; + this.transactionRole = transactionRole; + this.transactionType = transactionType; + } + + public String getTransactionCode() { + return transactionCode; + } + + public void setTransactionCode(String transactionCode) { + this.transactionCode = transactionCode; + } + + public String getRequestCode() { + return requestCode; + } + + public void setRequestCode(String requestCode) { + this.requestCode = requestCode; + } + + public String getQuoteCode() { + return quoteCode; + } + + public void setQuoteCode(String quoteCode) { + this.quoteCode = quoteCode; + } + + public String getAccountId() { + return accountId; + } + + public void setAccountId(String accountId) { + this.accountId = accountId; + } + + public FspMoneyData getAmount() { + return amount; + } + + public void setAmount(FspMoneyData amount) { + this.amount = amount; + } + + public AmountType getAmountType() { + return amountType; + } + + public void setAmountType(AmountType amountType) { + this.amountType = amountType; + } + + public TransactionRole getTransactionRole() { + return transactionRole; + } + + public void setTransactionRole(TransactionRole transactionRole) { + this.transactionRole = transactionRole; + } + + public TransactionType getTransactionType() { + return transactionType; + } + + public void setTransactionType(TransactionType transactionType) { + this.transactionType = transactionType; + } +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/ams/dto/QuoteFspResponseDTO.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/ams/dto/QuoteFspResponseDTO.java new file mode 100644 index 000000000..29c20d67a --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/ams/dto/QuoteFspResponseDTO.java @@ -0,0 +1,87 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla + * Public License, v. 2.0. If a copy of the MPL was not distributed + * with this file, You can obtain one at + * + * https://mozilla.org/MPL/2.0/. + */ +package org.mifos.connector.common.ams.dto; + +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer; +import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer; +import java.time.LocalDateTime; +import java.util.List; +import org.mifos.connector.common.mojaloop.dto.Extension; +import org.mifos.connector.common.mojaloop.dto.FspMoneyData; +import org.mifos.connector.common.mojaloop.type.TransactionRequestState; + +public class QuoteFspResponseDTO { + + private String transactionCode; // mandatory + private String quoteCode; // mandatory + private TransactionRequestState state; // mandatory + private FspMoneyData fspFee; + private FspMoneyData fspCommission; + @JsonSerialize(using = LocalDateTimeSerializer.class) + @JsonDeserialize(using = LocalDateTimeDeserializer.class) + private LocalDateTime expiration; + private List extensionList; + + public String getTransactionCode() { + return transactionCode; + } + + public void setTransactionCode(String transactionCode) { + this.transactionCode = transactionCode; + } + + public String getQuoteCode() { + return quoteCode; + } + + public void setQuoteCode(String quoteCode) { + this.quoteCode = quoteCode; + } + + public TransactionRequestState getState() { + return state; + } + + public void setState(TransactionRequestState state) { + this.state = state; + } + + public FspMoneyData getFspFee() { + return fspFee; + } + + public void setFspFee(FspMoneyData fspFee) { + this.fspFee = fspFee; + } + + public FspMoneyData getFspCommission() { + return fspCommission; + } + + public void setFspCommission(FspMoneyData fspCommission) { + this.fspCommission = fspCommission; + } + + public LocalDateTime getExpiration() { + return expiration; + } + + public void setExpiration(LocalDateTime expiration) { + this.expiration = expiration; + } + + public List getExtensionList() { + return extensionList; + } + + public void setExtensionList(List extensionList) { + this.extensionList = extensionList; + } +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/ams/dto/RoleData.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/ams/dto/RoleData.java new file mode 100644 index 000000000..055ea150e --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/ams/dto/RoleData.java @@ -0,0 +1,32 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla + * Public License, v. 2.0. If a copy of the MPL was not distributed + * with this file, You can obtain one at + * + * https://mozilla.org/MPL/2.0/. + */ +package org.mifos.connector.common.ams.dto; + +public class RoleData { + + private Long id; + private String name; + private String description; + private Boolean disabled; + + public Long getId() { + return id; + } + + public String getName() { + return name; + } + + public String getDescription() { + return description; + } + + public Boolean getDisabled() { + return disabled; + } +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/ams/dto/SavingsAccountStatusType.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/ams/dto/SavingsAccountStatusType.java new file mode 100644 index 000000000..79fb68bf4 --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/ams/dto/SavingsAccountStatusType.java @@ -0,0 +1,49 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.mifos.connector.common.ams.dto; + +public enum SavingsAccountStatusType { + + INVALID(0, "savingsAccountStatusType.invalid"), // + SUBMITTED_AND_PENDING_APPROVAL(100, "savingsAccountStatusType.submitted.and.pending.approval"), // + APPROVED(200, "savingsAccountStatusType.approved"), // + ACTIVE(300, "savingsAccountStatusType.active"), // + TRANSFER_IN_PROGRESS(303, "savingsAccountStatusType.transfer.in.progress"), // + TRANSFER_ON_HOLD(304, "savingsAccountStatusType.transfer.on.hold"), // + WITHDRAWN_BY_APPLICANT(400, "savingsAccountStatusType.withdrawn.by.applicant"), // + REJECTED(500, "savingsAccountStatusType.rejected"), // + CLOSED(600, "savingsAccountStatusType.closed"), PRE_MATURE_CLOSURE(700, "savingsAccountStatusType.pre.mature.closure"), MATURED(800, + "savingsAccountStatusType.matured"); + + private final Integer value; + private final String code; + + SavingsAccountStatusType(final Integer value, final String code) { + this.value = value; + this.code = code; + } + + public Integer getValue() { + return this.value; + } + + public String getCode() { + return this.code; + } +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/ams/dto/SavingsAccountSubStatusEnum.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/ams/dto/SavingsAccountSubStatusEnum.java new file mode 100644 index 000000000..4ddf1af0f --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/ams/dto/SavingsAccountSubStatusEnum.java @@ -0,0 +1,44 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.mifos.connector.common.ams.dto; + +public enum SavingsAccountSubStatusEnum { + + NONE(0, "SavingsAccountSubStatusEnum.none"), // + INACTIVE(100, "SavingsAccountSubStatusEnum.inactive"), // + DORMANT(200, "SavingsAccountSubStatusEnum.dormant"), ESCHEAT(300, "SavingsAccountSubStatusEnum.escheat"), BLOCK(400, + "SavingsAccountSubStatusEnum.block"), BLOCK_CREDIT(500, + "SavingsAccountSubStatusEnum.blockCredit"), BLOCK_DEBIT(600, "SavingsAccountSubStatusEnum.blockDebit"); + + private final Integer value; + private final String code; + + SavingsAccountSubStatusEnum(final Integer value, final String code) { + this.value = value; + this.code = code; + } + + public Integer getValue() { + return this.value; + } + + public String getCode() { + return this.code; + } +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/ams/dto/Term.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/ams/dto/Term.java new file mode 100644 index 000000000..3b85bdae2 --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/ams/dto/Term.java @@ -0,0 +1,58 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.mifos.connector.common.ams.dto; + +public class Term { + + private Integer period; + private TimeUnit timeUnit; + private InterestPayable interestPayable; + + public Term() {} + + public Integer getPeriod() { + return this.period; + } + + public void setPeriod(final Integer period) { + this.period = period; + } + + public String getTimeUnit() { + if (this.timeUnit != null) { + return this.timeUnit.name(); + } else { + return null; + } + } + + public void setTimeUnit(final String timeUnit) { + if (timeUnit != null) { + this.timeUnit = TimeUnit.valueOf(timeUnit); + } + } + + public String getInterestPayable() { + return this.interestPayable.name(); + } + + public void setInterestPayable(final String interestPayable) { + this.interestPayable = InterestPayable.valueOf(interestPayable); + } +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/ams/dto/TimeUnit.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/ams/dto/TimeUnit.java new file mode 100644 index 000000000..3a11da064 --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/ams/dto/TimeUnit.java @@ -0,0 +1,23 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.mifos.connector.common.ams.dto; + +public enum TimeUnit { + MONTH, YEAR +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/ams/dto/TransactionRequestFspRequestDTO.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/ams/dto/TransactionRequestFspRequestDTO.java new file mode 100644 index 000000000..96ef0370b --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/ams/dto/TransactionRequestFspRequestDTO.java @@ -0,0 +1,147 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla + * Public License, v. 2.0. If a copy of the MPL was not distributed + * with this file, You can obtain one at + * + * https://mozilla.org/MPL/2.0/. + */ +package org.mifos.connector.common.ams.dto; + +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer; +import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer; +import java.time.LocalDateTime; +import java.util.List; +import org.mifos.connector.common.mojaloop.dto.Extension; +import org.mifos.connector.common.mojaloop.dto.FspMoneyData; +import org.mifos.connector.common.mojaloop.dto.GeoCode; +import org.mifos.connector.common.mojaloop.dto.TransactionType; +import org.mifos.connector.common.mojaloop.type.TransactionRole; + +public class TransactionRequestFspRequestDTO { + + private String transactionCode; // mandatory + private String requestCode; // mandatory + private String accountId; // mandatory + private FspMoneyData amount; // mandatory + private TransactionRole transactionRole; // mandatory + private TransactionType transactionType; + private String note; + private GeoCode geoCode; + @JsonSerialize(using = LocalDateTimeSerializer.class) + @JsonDeserialize(using = LocalDateTimeDeserializer.class) + private LocalDateTime expiration; + private List extensionList; + + TransactionRequestFspRequestDTO() {} + + public TransactionRequestFspRequestDTO(String transactionCode, String requestCode, String accountId, FspMoneyData amount, + TransactionRole transactionRole, TransactionType transactionType, String note, GeoCode geoCode, LocalDateTime expiration, + List extensionList) { + this.transactionCode = transactionCode; + this.requestCode = requestCode; + this.accountId = accountId; + this.amount = amount; + this.transactionRole = transactionRole; + this.transactionType = transactionType; + this.note = note; + this.geoCode = geoCode; + this.expiration = expiration; + this.extensionList = extensionList; + } + + public TransactionRequestFspRequestDTO(String transactionCode, String requestCode, String accountId, FspMoneyData amount, + TransactionRole transactionRole) { + this(transactionCode, requestCode, accountId, amount, transactionRole, null, null, null, null, null); + } + + public String getTransactionCode() { + return transactionCode; + } + + public void setTransactionCode(String transactionCode) { + this.transactionCode = transactionCode; + } + + public String getRequestCode() { + return requestCode; + } + + public void setRequestCode(String requestCode) { + this.requestCode = requestCode; + } + + public String getAccountId() { + return accountId; + } + + public void setAccountId(String accountId) { + this.accountId = accountId; + } + + public FspMoneyData getAmount() { + return amount; + } + + public void setAmount(FspMoneyData amount) { + this.amount = amount; + } + + public TransactionRole getTransactionRole() { + return transactionRole; + } + + public void setTransactionRole(TransactionRole transactionRole) { + this.transactionRole = transactionRole; + } + + public TransactionType getTransactionType() { + return transactionType; + } + + public void setTransactionType(TransactionType transactionType) { + this.transactionType = transactionType; + } + + public String getNote() { + return note; + } + + public void setNote(String note) { + this.note = note; + } + + public GeoCode getGeoCode() { + return geoCode; + } + + public void setGeoCode(GeoCode geoCode) { + this.geoCode = geoCode; + } + + public LocalDateTime getExpiration() { + return expiration; + } + + public void setExpiration(LocalDateTime expiration) { + this.expiration = expiration; + } + + public List getExtensionList() { + return extensionList; + } + + public Extension getExtension(String key) { + for (Extension extension : extensionList) { + if (extension.getKey().equals(key)) { + return extension; + } + } + return null; + } + + public void setExtensionList(List extensionList) { + this.extensionList = extensionList; + } +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/ams/dto/TransactionRequestFspResponseDTO.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/ams/dto/TransactionRequestFspResponseDTO.java new file mode 100644 index 000000000..8a6be5e1d --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/ams/dto/TransactionRequestFspResponseDTO.java @@ -0,0 +1,68 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla + * Public License, v. 2.0. If a copy of the MPL was not distributed + * with this file, You can obtain one at + * + * https://mozilla.org/MPL/2.0/. + */ +package org.mifos.connector.common.ams.dto; + +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer; +import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer; +import java.time.LocalDateTime; +import java.util.List; +import org.mifos.connector.common.mojaloop.dto.Extension; +import org.mifos.connector.common.mojaloop.type.TransactionRequestState; + +public class TransactionRequestFspResponseDTO { + + private String transactionCode; + private String requestCode; + private TransactionRequestState state; + @JsonSerialize(using = LocalDateTimeSerializer.class) + @JsonDeserialize(using = LocalDateTimeDeserializer.class) + private LocalDateTime expiration; // mandatory + private List extensionList; + + public String getTransactionCode() { + return transactionCode; + } + + public void setTransactionCode(String transactionCode) { + this.transactionCode = transactionCode; + } + + public String getRequestCode() { + return requestCode; + } + + public void setRequestCode(String requestCode) { + this.requestCode = requestCode; + } + + public TransactionRequestState getState() { + return state; + } + + public void setState(TransactionRequestState state) { + this.state = state; + } + + public LocalDateTime getExpiration() { + return expiration; + } + + public void setExpiration(LocalDateTime expiration) { + this.expiration = expiration; + } + + public List getExtensionList() { + return extensionList; + } + + public void setExtensionList(List extensionList) { + this.extensionList = extensionList; + } +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/ams/dto/TransferActionType.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/ams/dto/TransferActionType.java new file mode 100644 index 000000000..7aa1f7a76 --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/ams/dto/TransferActionType.java @@ -0,0 +1,13 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla + * Public License, v. 2.0. If a copy of the MPL was not distributed + * with this file, You can obtain one at + * + * https://mozilla.org/MPL/2.0/. + */ +package org.mifos.connector.common.ams.dto; + +public enum TransferActionType { + + PREPARE, CREATE, RELEASE; +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/ams/dto/TransferFspRequestDTO.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/ams/dto/TransferFspRequestDTO.java new file mode 100644 index 000000000..015a54b86 --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/ams/dto/TransferFspRequestDTO.java @@ -0,0 +1,117 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla + * Public License, v. 2.0. If a copy of the MPL was not distributed + * with this file, You can obtain one at + * + * https://mozilla.org/MPL/2.0/. + */ +package org.mifos.connector.common.ams.dto; + +import org.mifos.connector.common.mojaloop.dto.FspMoneyData; +import org.mifos.connector.common.mojaloop.dto.TransactionType; +import org.mifos.connector.common.mojaloop.type.TransactionRole; + +public class TransferFspRequestDTO { + + private String transactionCode; + private String transferCode; + private String accountId; + private FspMoneyData amount; + private FspMoneyData fspFee; + private FspMoneyData fspCommission; + private TransactionRole transactionRole; + private TransactionType transactionType; + private String note; + + TransferFspRequestDTO() {} + + public TransferFspRequestDTO(String transactionCode, String transferCode, String accountId, FspMoneyData amount, FspMoneyData fspFee, + FspMoneyData fspCommission, TransactionRole transactionRole, TransactionType transactionType, String note) { + this.transactionCode = transactionCode; + this.transferCode = transferCode; + this.accountId = accountId; + this.amount = amount; + this.fspFee = fspFee; + this.fspCommission = fspCommission; + this.transactionRole = transactionRole; + this.transactionType = transactionType; + this.note = note; + } + + public TransferFspRequestDTO(String transactionCode, String transferCode, String accountId, FspMoneyData amount, + TransactionRole transactionRole) { + this(transactionCode, transferCode, accountId, amount, null, null, transactionRole, null, null); + } + + public String getTransactionCode() { + return transactionCode; + } + + public void setTransactionCode(String transactionCode) { + this.transactionCode = transactionCode; + } + + public String getTransferCode() { + return transferCode; + } + + public void setTransferCode(String transferCode) { + this.transferCode = transferCode; + } + + public String getAccountId() { + return accountId; + } + + public void setAccountId(String accountId) { + this.accountId = accountId; + } + + public FspMoneyData getAmount() { + return amount; + } + + public void setAmount(FspMoneyData amount) { + this.amount = amount; + } + + public FspMoneyData getFspFee() { + return fspFee; + } + + public void setFspFee(FspMoneyData fspFee) { + this.fspFee = fspFee; + } + + public FspMoneyData getFspCommission() { + return fspCommission; + } + + public void setFspCommission(FspMoneyData fspCommission) { + this.fspCommission = fspCommission; + } + + public TransactionRole getTransactionRole() { + return transactionRole; + } + + public void setTransactionRole(TransactionRole transactionRole) { + this.transactionRole = transactionRole; + } + + public TransactionType getTransactionType() { + return transactionType; + } + + public void setTransactionType(TransactionType transactionType) { + this.transactionType = transactionType; + } + + public String getNote() { + return note; + } + + public void setNote(String note) { + this.note = note; + } +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/ams/dto/TransferFspResponseDTO.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/ams/dto/TransferFspResponseDTO.java new file mode 100644 index 000000000..d96ef9d72 --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/ams/dto/TransferFspResponseDTO.java @@ -0,0 +1,79 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla + * Public License, v. 2.0. If a copy of the MPL was not distributed + * with this file, You can obtain one at + * + * https://mozilla.org/MPL/2.0/. + */ +package org.mifos.connector.common.ams.dto; + +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer; +import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer; +import java.time.LocalDateTime; +import java.util.List; +import org.mifos.connector.common.mojaloop.dto.Extension; +import org.mifos.connector.common.mojaloop.type.TransactionRequestState; + +public class TransferFspResponseDTO { + + private String transactionCode; // mandatory + private String transferCode; // mandatory + private TransactionRequestState state; // mandatory + @JsonSerialize(using = LocalDateTimeSerializer.class) + @JsonDeserialize(using = LocalDateTimeDeserializer.class) + private LocalDateTime completedTimestamp; + @JsonSerialize(using = LocalDateTimeSerializer.class) + @JsonDeserialize(using = LocalDateTimeDeserializer.class) + private LocalDateTime expiration; + private List extensionList; + + public String getTransactionCode() { + return transactionCode; + } + + public void setTransactionCode(String transactionCode) { + this.transactionCode = transactionCode; + } + + public String getTransferCode() { + return transferCode; + } + + public void setTransferCode(String transferCode) { + this.transferCode = transferCode; + } + + public TransactionRequestState getState() { + return state; + } + + public void setState(TransactionRequestState state) { + this.state = state; + } + + public LocalDateTime getCompletedTimestamp() { + return completedTimestamp; + } + + public void setCompletedTimestamp(LocalDateTime completedTimestamp) { + this.completedTimestamp = completedTimestamp; + } + + public LocalDateTime getExpiration() { + return expiration; + } + + public void setExpiration(LocalDateTime expiration) { + this.expiration = expiration; + } + + public List getExtensionList() { + return extensionList; + } + + public void setExtensionList(List extensionList) { + this.extensionList = extensionList; + } +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/ams/dto/Type.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/ams/dto/Type.java new file mode 100644 index 000000000..991324c1e --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/ams/dto/Type.java @@ -0,0 +1,23 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.mifos.connector.common.ams.dto; + +public enum Type { + CHECKING, SAVINGS, SHARE +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/batch/dto/AuthorizationRequest.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/batch/dto/AuthorizationRequest.java new file mode 100644 index 000000000..d708b18d2 --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/batch/dto/AuthorizationRequest.java @@ -0,0 +1,21 @@ +package org.mifos.connector.common.batch.dto; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +public class AuthorizationRequest { + + private String batchId; + + private String payerIdentifier; + + private String currency; + + private String amount; +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/batch/dto/AuthorizationResponse.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/batch/dto/AuthorizationResponse.java new file mode 100644 index 000000000..3539d3a37 --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/batch/dto/AuthorizationResponse.java @@ -0,0 +1,19 @@ +package org.mifos.connector.common.batch.dto; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +public class AuthorizationResponse { + + private String clientCorrelationId; + + private String status; + + private String reason; +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/camel/AuthConfig.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/camel/AuthConfig.java new file mode 100644 index 000000000..26d31c477 --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/camel/AuthConfig.java @@ -0,0 +1,38 @@ +package org.mifos.connector.common.camel; + +import com.auth0.jwt.JWT; +import com.auth0.jwt.JWTVerifier; +import com.auth0.jwt.algorithms.Algorithm; +import java.security.KeyFactory; +import java.security.interfaces.RSAPublicKey; +import java.security.spec.X509EncodedKeySpec; +import java.util.Base64; +import org.apache.camel.CamelContext; +import org.apache.camel.Exchange; +import org.apache.camel.ProducerTemplate; +import org.apache.camel.support.DefaultExchange; +import org.json.JSONObject; +import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Lazy; + +@Configuration +@ConditionalOnExpression("${rest.authorization.enabled:false}") +public class AuthConfig { + + @Bean + @Lazy + public JWTVerifier verifier(CamelContext camelContext, ProducerTemplate producerTemplate) throws Exception { + Exchange exchange = new DefaultExchange(camelContext); + producerTemplate.send("direct:get-public-key", exchange); + JSONObject response = new JSONObject(exchange.getIn().getBody(String.class)); + String publicKeyContent = response.getString("value"); + publicKeyContent = publicKeyContent.replaceAll("\\n", "").replace("-----BEGIN PUBLIC KEY-----", "") + .replace("-----END PUBLIC KEY-----", ""); + KeyFactory kf = KeyFactory.getInstance("RSA"); + X509EncodedKeySpec keySpecX509 = new X509EncodedKeySpec(Base64.getDecoder().decode(publicKeyContent)); + RSAPublicKey pubKey = (RSAPublicKey) kf.generatePublic(keySpecX509); + return JWT.require(Algorithm.RSA256(pubKey)).build(); + } +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/camel/AuthProcessor.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/camel/AuthProcessor.java new file mode 100644 index 000000000..1a9646e85 --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/camel/AuthProcessor.java @@ -0,0 +1,52 @@ +package org.mifos.connector.common.camel; + +import static org.mifos.connector.common.camel.AuthRouteBuilder.AUTH_ERROR; +import static org.mifos.connector.common.camel.AuthRouteBuilder.HAS_AUTHORITY; +import static org.mifos.connector.common.camel.AuthRouteBuilder.UNKNOWN_ERROR; + +import com.auth0.jwt.exceptions.JWTVerificationException; +import com.auth0.jwt.interfaces.DecodedJWT; +import com.auth0.jwt.interfaces.JWTVerifier; +import java.util.stream.Stream; +import org.apache.camel.Exchange; +import org.apache.camel.Processor; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; +import org.springframework.context.annotation.Lazy; +import org.springframework.stereotype.Component; + +@Component +@ConditionalOnExpression("${rest.authorization.enabled:false}") +public class AuthProcessor implements Processor { + + private static Logger logger = LoggerFactory.getLogger(AuthRouteBuilder.class); + + @Autowired + @Lazy + private JWTVerifier verifier; + + @Override + public void process(Exchange e) { + try { + String authorization = e.getIn().getHeader("Authorization", String.class); + if (authorization == null || authorization.length() < 1) { + throw new JWTVerificationException("Invalid or empty Authorization header!"); + } + + String token = authorization.split("Bearer")[1].trim(); + DecodedJWT decoded = verifier.verify(token); + String[] authorities = decoded.getClaim("authorities").asArray(String.class); + String hasAuthority = e.getProperty(HAS_AUTHORITY, String.class); + Stream.of(authorities).filter(hasAuthority::equals).findFirst() + .orElseThrow(() -> new JWTVerificationException("Invalid authorities!")); + } catch (JWTVerificationException ex) { + logger.error("Invalid Authorization!", ex); + e.setProperty(AUTH_ERROR, true); + } catch (Exception ex) { + logger.error("Unknown error!", ex); + e.setProperty(UNKNOWN_ERROR, true); + } + } +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/camel/AuthProperties.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/camel/AuthProperties.java new file mode 100644 index 000000000..8951f28c0 --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/camel/AuthProperties.java @@ -0,0 +1,21 @@ +package org.mifos.connector.common.camel; + +import java.util.ArrayList; +import java.util.List; +import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +@Component +@ConditionalOnExpression("${rest.authorization.enabled:false}") +@ConfigurationProperties(prefix = "rest.authorization") +public class AuthProperties { + + private List settings = new ArrayList<>(); + + public AuthProperties() {} + + public List getSettings() { + return settings; + } +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/camel/AuthRouteBuilder.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/camel/AuthRouteBuilder.java new file mode 100644 index 000000000..f991c09c1 --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/camel/AuthRouteBuilder.java @@ -0,0 +1,22 @@ +package org.mifos.connector.common.camel; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; +import org.springframework.stereotype.Component; + +@Component +@ConditionalOnExpression("${rest.authorization.enabled:false}") +public class AuthRouteBuilder extends ErrorHandlerRouteBuilder { + + public static final String AUTH_ERROR = "AUTH_ERROR"; + public static final String UNKNOWN_ERROR = "UNKNOWN_ERROR"; + public static final String HAS_AUTHORITY = "HAS_AUTHORITY"; + + public AuthRouteBuilder() { + super.configure(); + } + + @Override + public void configure() { + from("direct:get-public-key").id("get-public-key").toD("rest:GET:/oauth/token_key?host={{rest.authorization.host}}"); + } +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/camel/EndpointSetting.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/camel/EndpointSetting.java new file mode 100644 index 000000000..4fb2d01a2 --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/camel/EndpointSetting.java @@ -0,0 +1,25 @@ +package org.mifos.connector.common.camel; + +public class EndpointSetting { + + private String endpoint; + private String authority; + + public EndpointSetting() {} + + public String getEndpoint() { + return endpoint; + } + + public void setEndpoint(String endpoint) { + this.endpoint = endpoint; + } + + public String getAuthority() { + return authority; + } + + public void setAuthority(String authority) { + this.authority = authority; + } +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/camel/ErrorHandlerRouteBuilder.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/camel/ErrorHandlerRouteBuilder.java new file mode 100644 index 000000000..f8942ed8a --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/camel/ErrorHandlerRouteBuilder.java @@ -0,0 +1,69 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla + * Public License, v. 2.0. If a copy of the MPL was not distributed + * with this file, You can obtain one at + * + * https://mozilla.org/MPL/2.0/. + */ +package org.mifos.connector.common.camel; + +import static org.apache.camel.Exchange.HTTP_RESPONSE_CODE; +import static org.mifos.connector.common.camel.AuthRouteBuilder.AUTH_ERROR; +import static org.mifos.connector.common.camel.AuthRouteBuilder.HAS_AUTHORITY; +import static org.mifos.connector.common.camel.AuthRouteBuilder.UNKNOWN_ERROR; + +import org.apache.camel.Exchange; +import org.apache.camel.LoggingLevel; +import org.apache.camel.builder.RouteBuilder; +import org.json.JSONObject; + +public abstract class ErrorHandlerRouteBuilder extends RouteBuilder { + + private AuthProcessor authProcessor; + private AuthProperties properties; + + public ErrorHandlerRouteBuilder() {} + + public ErrorHandlerRouteBuilder(AuthProcessor authProcessor, AuthProperties properties) { + this.authProcessor = authProcessor; + this.properties = properties; + } + + public static JSONObject createError(String errorCode, String errorDescription) { + JSONObject errorObject = new JSONObject(); + JSONObject error = new JSONObject(); + error.put("errorCode", errorCode); + error.put("errorDescription", errorDescription); + errorObject.put("errorInformation", error); + return errorObject; + } + + @Override + public void configure() { + onException(Exception.class).routeId("errorHandlerRoute") + .log(LoggingLevel.ERROR, "@@ unhandled exception. Body: ${body}, stacktrace: ${exception.stacktrace}").process(e -> { + boolean isHttpOrServletHeaderExist = e.getIn().getHeaders().entrySet().stream().anyMatch(h -> { + String headerKey = h.getKey(); + return headerKey != null && (headerKey.startsWith("CamelHttp") || headerKey.startsWith("CamelServlet")); + }); + if (isHttpOrServletHeaderExist) { + e.getIn().setBody(null); + e.getIn().setHeader(Exchange.HTTP_RESPONSE_CODE, 400); + } + }).handled(true).stop(); + + if (authProcessor != null && properties != null) { + properties.getSettings().forEach(s -> configureEndpointWithAuthority(s.getEndpoint(), s.getAuthority())); + } + } + + private void configureEndpointWithAuthority(String endpoint, String requiredAuthority) { + interceptFrom(endpoint).process(e -> { + e.setProperty(HAS_AUTHORITY, requiredAuthority); + }).process(authProcessor).choice().when(simple("${exchangeProperty." + AUTH_ERROR + "} == true")).process(e -> { + e.getIn().setHeader(HTTP_RESPONSE_CODE, 401); + }).stop().endChoice().when(simple("${exchangeProperty." + UNKNOWN_ERROR + "} == true")).process(e -> { + e.getIn().setHeader(HTTP_RESPONSE_CODE, 400); + }).stop().endChoice().end(); + } +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/camel/JWSProcessor.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/camel/JWSProcessor.java new file mode 100644 index 000000000..cb936ab07 --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/camel/JWSProcessor.java @@ -0,0 +1,42 @@ +package org.mifos.connector.common.camel; + +import java.util.List; +import java.util.Map; +import lombok.extern.slf4j.Slf4j; +import org.apache.camel.Exchange; +import org.apache.camel.Processor; +import org.mifos.connector.common.interceptor.JWSUtil; +import org.mifos.connector.common.interceptor.WebSignatureInterceptor; +import org.mifos.connector.common.interceptor.service.JsonWebSignatureService; +import org.mifos.connector.common.util.Constant; +import org.mifos.connector.common.zeebe.ZeebeVariables; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; +import org.springframework.stereotype.Component; + +@Component +@Slf4j +@ConditionalOnExpression("${security.jws.enable:false}") +public class JWSProcessor implements Processor { + + @Autowired + WebSignatureInterceptor webSignatureInterceptor; + + @Autowired + private JsonWebSignatureService jsonWebSignatureService; + + @Value("#{'${jws.header.order}'.split(',')}") + private List headerOrder; + + @Override + public void process(Exchange exchange) throws Exception { + String body = exchange.getIn().getBody(String.class); + Map headers = exchange.getIn().getHeaders(); + String signatureData = JWSUtil.getDataToBeHashed(headers, body, headerOrder); + log.debug("Signature data: {}", signatureData); + String tenant = exchange.getProperty(ZeebeVariables.TENANT_ID, String.class); + String signature = jsonWebSignatureService.signForTenant(signatureData, tenant); + exchange.getIn().setHeader(Constant.HEADER_JWS, signature); + } +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/camel/JWSRoute.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/camel/JWSRoute.java new file mode 100644 index 000000000..19de25f66 --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/camel/JWSRoute.java @@ -0,0 +1,19 @@ +package org.mifos.connector.common.camel; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; +import org.springframework.stereotype.Component; + +@Component +@ConditionalOnExpression("${security.jws.enable:false}") +public class JWSRoute extends ErrorHandlerRouteBuilder { + + @Autowired + private JWSProcessor jwsProcessor; + + @Override + public void configure() { + from("direct:set-jws-signature").id("set-jws-signature").process(jwsProcessor); + } + +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/channel/dto/EnumNamePattern.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/channel/dto/EnumNamePattern.java new file mode 100644 index 000000000..58521b58d --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/channel/dto/EnumNamePattern.java @@ -0,0 +1,21 @@ +package org.mifos.connector.common.channel.dto; + +import static java.lang.annotation.ElementType.FIELD; +import static java.lang.annotation.ElementType.TYPE_USE; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; +import javax.validation.Constraint; + +@Target({ FIELD, TYPE_USE }) +@Retention(RUNTIME) +@Documented +@Constraint(validatedBy = EnumNamePatternValidator.class) +public @interface EnumNamePattern { + + Class enumType(); + + String message() default "must match enum values"; +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/channel/dto/EnumNamePatternValidator.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/channel/dto/EnumNamePatternValidator.java new file mode 100644 index 000000000..d82be0a16 --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/channel/dto/EnumNamePatternValidator.java @@ -0,0 +1,20 @@ +package org.mifos.connector.common.channel.dto; + +import java.util.stream.Stream; +import javax.validation.ConstraintValidator; +import javax.validation.ConstraintValidatorContext; + +public class EnumNamePatternValidator implements ConstraintValidator> { + + private Class enumType; + + @Override + public void initialize(EnumNamePattern annotation) { + enumType = annotation.enumType(); + } + + @Override + public boolean isValid(Enum value, ConstraintValidatorContext context) { + return value != null && Stream.of(enumType.getEnumConstants()).filter(e -> e.equals(value)).findFirst().orElse(null) != null; + } +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/channel/dto/ErrorParameter.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/channel/dto/ErrorParameter.java new file mode 100644 index 000000000..35ceebf3c --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/channel/dto/ErrorParameter.java @@ -0,0 +1,16 @@ +package org.mifos.connector.common.channel.dto; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +@AllArgsConstructor +public class ErrorParameter { + + private String key; + + private String value; + +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/channel/dto/Errors.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/channel/dto/Errors.java new file mode 100644 index 000000000..726257e83 --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/channel/dto/Errors.java @@ -0,0 +1,21 @@ +package org.mifos.connector.common.channel.dto; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import lombok.ToString; + +import java.util.List; + +@Getter +@Setter +@ToString +@NoArgsConstructor +@AllArgsConstructor +public class Errors { + public String errorCategory; + public String errorCode; + public String errorDescription; + public List errorParameters; +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/channel/dto/PhErrorDTO.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/channel/dto/PhErrorDTO.java new file mode 100644 index 000000000..4210e6ac4 --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/channel/dto/PhErrorDTO.java @@ -0,0 +1,144 @@ +package org.mifos.connector.common.channel.dto; + +import java.util.ArrayList; +import java.util.List; +import javax.validation.constraints.NotNull; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import lombok.ToString; +import org.mifos.connector.common.validation.ValidatorBuilder; +import org.mifos.connector.common.exception.PaymentHubError; +import org.mifos.connector.common.exception.PaymentHubException; + +@Getter +@Setter +@ToString +@NoArgsConstructor +public final class PhErrorDTO { + + @NotNull + private String errorCategory; + @NotNull + private String errorCode; + @NotNull + private String errorDescription; + private String developerMessage; + private String defaultUserMessage; + private List errorParameters; + private List errors; + + private PhErrorDTO(PhErrorDTOBuilder builder) { + this.errorCategory = builder.errorCategory; + this.errorCode = builder.errorCode; + this.errorDescription = builder.errorDescription; + this.developerMessage = builder.developerMessage; + this.defaultUserMessage = builder.defaultUserMessage; + this.errorParameters = builder.errorParameters; + this.errors = builder.errors; + } + + /** + * Creates builder to build {@link PhErrorDTO}. + * + * Example: new PhErrorDTOBuilder(PaymentHubError.IdNotFound).build() + * + * new PhErrorDTOBuilder("idnotfound).build() + * + * new PhErrorDTOBuilder(PaymentHubError.IdNotFound) .addErrorParameter("accountId", "1231231").build() + */ + public static class PhErrorDTOBuilder { + + private String errorCategory; + private String errorCode; + private String errorDescription; + private String developerMessage; + private String defaultUserMessage; + private List errorParameters; + private List errors; + + // sets not null fields using [PaymentHubError] object + public PhErrorDTOBuilder(PaymentHubError error) { + setupUsingPaymentHubErrorObject(error); + } + + // sets not null fields using [PaymentHubException] object + public PhErrorDTOBuilder(PaymentHubException exception) { + PaymentHubError paymentHubError = PaymentHubError.fromCode(exception.getErrorCode()); + setupUsingPaymentHubErrorObject(paymentHubError); + } + + // sets not null fields using valid error code in [String] format + public PhErrorDTOBuilder(String errorCode) { + PaymentHubError paymentHubError = PaymentHubError.fromCode(errorCode); + setupUsingPaymentHubErrorObject(paymentHubError); + } + + // method to set the not null fields using [PaymentHubError] object + private void setupUsingPaymentHubErrorObject(PaymentHubError error) { + this.errorCategory = error.getErrorCategory().name(); + this.errorCode = error.getErrorCode(); + this.errorDescription = error.getErrorDescription(); + } + + // validates the not null fields + private void validate() { + if (this.errorCode == null) { + throw new IllegalArgumentException("Error code is required"); + } + if (this.defaultUserMessage == null) { + this.defaultUserMessage = ""; + } + if (this.developerMessage == null) { + this.developerMessage = ""; + } + } + + // sets the developer message + public PhErrorDTOBuilder developerMessage(String developerMessage) { + this.developerMessage = developerMessage; + return this; + } + + // sets the default user message + public PhErrorDTOBuilder defaultUserMessage(String defaultUserMessage) { + this.defaultUserMessage = defaultUserMessage; + return this; + } + + public PhErrorDTOBuilder addErrorParameter(String key, String value) { + if (this.errorParameters == null) { + this.errorParameters = new ArrayList<>(); + } + this.errorParameters.add(new ErrorParameter(key, value)); + return this; + } + + public PhErrorDTOBuilder addErrors(String errorCategory, String errorCode, String errorDescription, + List errorParameters) { + if (this.errors == null) { + this.errors = new ArrayList<>(); + } + this.errors.add(new Errors(errorCategory, errorCode, errorDescription, errorParameters)); + return this; + } + + public PhErrorDTOBuilder fromValidatorBuilder(ValidatorBuilder validatorBuilder) { + this.errorCategory = validatorBuilder.getErrorCategory(); + this.errorCode = validatorBuilder.getErrorCode(); + this.errorDescription = validatorBuilder.getErrorDescription(); + this.developerMessage = validatorBuilder.getDeveloperMessage(); + this.defaultUserMessage = validatorBuilder.getDefaultUserMessage(); + this.errorParameters = validatorBuilder.getErrorParameters(); + this.errors = validatorBuilder.getErrorsList(); + return this; + } + + // validates and builds the PhErrorDTO object + public PhErrorDTO build() { + validate(); + return new PhErrorDTO(this); + } + + } +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/channel/dto/RegisterAliasRequestDTO.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/channel/dto/RegisterAliasRequestDTO.java new file mode 100644 index 000000000..8c92c7a98 --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/channel/dto/RegisterAliasRequestDTO.java @@ -0,0 +1,46 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla + * Public License, v. 2.0. If a copy of the MPL was not distributed + * with this file, You can obtain one at + * + * https://mozilla.org/MPL/2.0/. + */ +package org.mifos.connector.common.channel.dto; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import org.mifos.connector.common.mojaloop.type.IdentifierType; + +public class RegisterAliasRequestDTO { + + @NotEmpty + private String accountId; + @NotNull + private IdentifierType idType; + @NotEmpty + private String idValue; + + public String getAccountId() { + return accountId; + } + + public void setAccountId(String accountId) { + this.accountId = accountId; + } + + public IdentifierType getIdType() { + return idType; + } + + public void setIdType(IdentifierType idType) { + this.idType = idType; + } + + public String getIdValue() { + return idValue; + } + + public void setIdValue(String idValue) { + this.idValue = idValue; + } +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/channel/dto/TransactionChannelC2BRequestDTO.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/channel/dto/TransactionChannelC2BRequestDTO.java new file mode 100644 index 000000000..3e73a8c98 --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/channel/dto/TransactionChannelC2BRequestDTO.java @@ -0,0 +1,45 @@ +package org.mifos.connector.common.channel.dto; + +import java.util.Arrays; +import org.mifos.connector.common.gsma.dto.GsmaParty; +import org.mifos.connector.common.mojaloop.dto.MoneyData; +import org.mifos.connector.common.mojaloop.dto.TransactionType; + +public class TransactionChannelC2BRequestDTO { + + private GsmaParty[] payer; + private MoneyData amount; + private TransactionType transactionType; + + public TransactionChannelC2BRequestDTO() {} + + public GsmaParty[] getPayer() { + return payer; + } + + public void setPayer(GsmaParty[] payer) { + this.payer = payer; + } + + public MoneyData getAmount() { + return amount; + } + + public void setAmount(MoneyData amount) { + this.amount = amount; + } + + public TransactionType getTransactionType() { + return transactionType; + } + + public void setTransactionType(TransactionType transactionType) { + this.transactionType = transactionType; + } + + @Override + public String toString() { + return "TransactionChannelCollectionRequestDTO{" + "payer=" + Arrays.toString(payer) + ", amount='" + amount + '\'' + + ", transactionType=" + transactionType + '}'; + } +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/channel/dto/TransactionChannelRequestDTO.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/channel/dto/TransactionChannelRequestDTO.java new file mode 100644 index 000000000..7ce15f7f5 --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/channel/dto/TransactionChannelRequestDTO.java @@ -0,0 +1,130 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla + * Public License, v. 2.0. If a copy of the MPL was not distributed + * with this file, You can obtain one at + * + * https://mozilla.org/MPL/2.0/. + */ +package org.mifos.connector.common.channel.dto; + +import java.util.List; +import javax.validation.constraints.NotNull; +import org.mifos.connector.common.gsma.dto.CustomData; +import org.mifos.connector.common.mojaloop.dto.ExtensionList; +import org.mifos.connector.common.mojaloop.dto.GeoCode; +import org.mifos.connector.common.mojaloop.dto.MoneyData; +import org.mifos.connector.common.mojaloop.dto.Party; +import org.mifos.connector.common.mojaloop.dto.TransactionType; +import org.mifos.connector.common.mojaloop.type.AmountType; + +public class TransactionChannelRequestDTO { + + private String clientRefId; + @NotNull + private Party payer; + private Party payee; + private AmountType amountType; + @NotNull + private MoneyData amount; + private TransactionType transactionType; + private GeoCode geoCode; + private String note; + private String expiration; + private ExtensionList extensionList; + private List customData; + + public List getCustomData() { + return customData; + } + + public void setCustomData(List customData) { + this.customData = customData; + } + + public String getClientRefId() { + return clientRefId; + } + + public void setClientRefId(String clientRefId) { + this.clientRefId = clientRefId; + } + + public Party getPayer() { + return payer; + } + + public void setPayer(Party payer) { + this.payer = payer; + } + + public Party getPayee() { + return payee; + } + + public void setPayee(Party payee) { + this.payee = payee; + } + + public AmountType getAmountType() { + return amountType; + } + + public void setAmountType(AmountType amountType) { + this.amountType = amountType; + } + + public MoneyData getAmount() { + return amount; + } + + public void setAmount(MoneyData amount) { + this.amount = amount; + } + + public TransactionType getTransactionType() { + return transactionType; + } + + public void setTransactionType(TransactionType transactionType) { + this.transactionType = transactionType; + } + + public GeoCode getGeoCode() { + return geoCode; + } + + public void setGeoCode(GeoCode geoCode) { + this.geoCode = geoCode; + } + + public String getNote() { + return note; + } + + public void setNote(String note) { + this.note = note; + } + + public String getExpiration() { + return expiration; + } + + public void setExpiration(String expiration) { + this.expiration = expiration; + } + + public ExtensionList getExtensionList() { + return extensionList; + } + + public void setExtensionList(ExtensionList extensionList) { + this.extensionList = extensionList; + } + + @Override + public String toString() { + return "TransactionChannelRequestDTO{" + "clientRefId='" + clientRefId + '\'' + ", payer=" + payer + ", payee=" + payee + + ", amountType=" + amountType + ", amount=" + amount + ", transactionType=" + transactionType + ", note='" + note + '\'' + + ", expiration='" + expiration + '\'' + ", customData=" + customData + '}'; + } +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/channel/dto/TransactionStatusResponseDTO.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/channel/dto/TransactionStatusResponseDTO.java new file mode 100644 index 000000000..bacc3a021 --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/channel/dto/TransactionStatusResponseDTO.java @@ -0,0 +1,62 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla + * Public License, v. 2.0. If a copy of the MPL was not distributed + * with this file, You can obtain one at + * + * https://mozilla.org/MPL/2.0/. + */ +package org.mifos.connector.common.channel.dto; + +import java.time.LocalDateTime; +import org.mifos.connector.common.mojaloop.type.TransferState; + +public class TransactionStatusResponseDTO { + + private String clientRefId; + private String transactionId; + private LocalDateTime completedTimestamp; + private String transferId; + private TransferState transferState; + + public TransactionStatusResponseDTO() {} + + public String getClientRefId() { + return clientRefId; + } + + public void setClientRefId(String clientRefId) { + this.clientRefId = clientRefId; + } + + public String getTransactionId() { + return transactionId; + } + + public void setTransactionId(String transactionId) { + this.transactionId = transactionId; + } + + public LocalDateTime getCompletedTimestampDate() { + return completedTimestamp; + } + + public void setCompletedTimestamp(LocalDateTime completedTimestamp) { + this.completedTimestamp = completedTimestamp; + } + + public String getTransferId() { + return transferId; + } + + public void setTransferId(String transferId) { + this.transferId = transferId; + } + + public TransferState getTransferState() { + return transferState; + } + + public void setTransferState(TransferState transferState) { + this.transferState = transferState; + } +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/exception/PaymentHubError.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/exception/PaymentHubError.java new file mode 100644 index 000000000..2f0ff3f9a --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/exception/PaymentHubError.java @@ -0,0 +1,132 @@ +package org.mifos.connector.common.exception; + +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; +import lombok.Getter; + +@Getter +public enum PaymentHubError { + + // Interoperability Errors; + CommunicationError(PaymentHubErrorCategory.Interop, "CommunicationError", "Communication error"), DestinationCommunicationError( + PaymentHubErrorCategory.Interop, "DestinationCommunicationError", + "Destination communication error"), ExtGenericServerError(PaymentHubErrorCategory.Interop, "ExtGenericServerError", + "Generic server error"), ExtInternalServerError(PaymentHubErrorCategory.Interop, "ExtInternalServerError", + "Internal server error"), NotImplemented(PaymentHubErrorCategory.Interop, "NotImplemented", + "Not implemented"), ServiceDenied(PaymentHubErrorCategory.Interop, "ServiceDenied", + "Service currently unavailable"), TimeOut(PaymentHubErrorCategory.Interop, "TimeOut", + "Server timed-out"), ConnectionReset(PaymentHubErrorCategory.Interop, "ConnectionReset", + "Connection reset by server/ request cancelled"), GenericClientError( + PaymentHubErrorCategory.Interop, "GenericClientError", + "Generic client error"), UnknownURL(PaymentHubErrorCategory.Interop, + "UnknownURL", "Unknown URI"), AddPartyError( + PaymentHubErrorCategory.Interop, "AddPartyError", + "Add Party information error"), ExtValidationError( + PaymentHubErrorCategory.Interop, + "ExtValidationError", + "Generic validation error"), SyntaxError( + PaymentHubErrorCategory.Interop, + "SyntaxError", + "Malformed syntax"), RequiredElement( + PaymentHubErrorCategory.Interop, + "RequiredElement", + "Missing mandatory element"), IdNotFound( + PaymentHubErrorCategory.Interop, + "IdNotFound", + "Generic ID not found"), PayerFSPIdNotFound( + PaymentHubErrorCategory.Interop, + "PayerFSPIdNotFound", + "Payer FSP ID not found"), PayeeFSPIdNotFound( + PaymentHubErrorCategory.Interop, + "PayeeFSPIdNotFound", + "Payee FSP ID not found"), PayerNotFound( + PaymentHubErrorCategory.Interop, + "PayerNotFound", + "Payer not found"), PayeeNotFound( + PaymentHubErrorCategory.Interop, + "PayeeNotFound", + "Payee not found"), CurrencyPairNotFound( + PaymentHubErrorCategory.Interop, + "CurrencyPairNotFound", + "Currency pair not found"), TransactionIdNotFound( + PaymentHubErrorCategory.Interop, + "TransactionIdNotFound", + "Transaction ID not found"), TransferIdNotFound( + PaymentHubErrorCategory.Interop, + "TransferIdNotFound", + "Transfer ID not found"), InactiveAccountStatus( + PaymentHubErrorCategory.Interop, + "InactiveAccountStatus", + "Inactive account status"), TransferExpired( + PaymentHubErrorCategory.Interop, + "TransferExpired", + "Transfer expired"), PayerCurrencyInvalid( + PaymentHubErrorCategory.Interop, + "PayerCurrencyInvalid", + "Payer currency invalid"), GenericPayerError( + PaymentHubErrorCategory.Interop, + "GenericPayerError", + "Generic Payer error"), PayerFSPTransactionTypeInvalid( + PaymentHubErrorCategory.Interop, + "PayerFSPTransactionTypeInvalid", + "Payer FSP Unsupported Transaction type"), PayerInsufficientBalance( + PaymentHubErrorCategory.Interop, + "PayerInsufficientBalance", + "Payer Party Insufficient Balance"), PayeeCurrencyInvalid( + PaymentHubErrorCategory.Interop, + "PayeeCurrencyInvalid", + "Payee currency invalid"), PayeeUnauthorized( + PaymentHubErrorCategory.Interop, + "PayeeUnauthorized", + "Payee permission error"), PayeeFSPTransactionTypeInvalid( + PaymentHubErrorCategory.Interop, + "PayeeFSPTransactionTypeInvalid", + "Payee FSP unsupported transaction type"), PayerFspNotConfigured( + PaymentHubErrorCategory.Interop, + "PayerFspNotConfigured", + "Payer FSP not configured"), PayeeFspNotConfigured( + PaymentHubErrorCategory.Interop, + "PayeeFspNotConfigured", + "Payee FSP not configured"), + // validation errors + FormatError(PaymentHubErrorCategory.Validation, "FormatError", + "The specified property contents do not conform to the format required for this Property."), NegativeValue( + PaymentHubErrorCategory.Validation, "NegativeValue", + "The amount supplied is negative and this is not allowed for the given service."), MandatoryValueNotSupplied( + PaymentHubErrorCategory.Validation, "MandatoryValueNotSupplied", + "A mandatory value has not been provided in the header and/or JSON body."), SamePartiesError( + PaymentHubErrorCategory.BusinessRule, "SamePartiesError", + "The debit and credit parties are the same."), InvalidJsonWebSignature( + PaymentHubErrorCategory.Validation, "InvalidJsonWebSignature", + "The JWS passed is not valid"), InvalidPublicKeyConfigured(PaymentHubErrorCategory.Validation, + "InvalidPublicKeyConfigured", + "The public key configured is invalid"), JWSVerificationServerError( + PaymentHubErrorCategory.System, "JWSVerificationServerError", + "Internal server error while verifying JWS"), TransactionExistsError( + PaymentHubErrorCategory.Validation, "TransactionExists", + "Transaction already exists"); + + private PaymentHubErrorCategory errorCategory; + private String errorCode; + private String errorDescription; + + PaymentHubError(PaymentHubErrorCategory errorCategory, String code, String errorMessage) { + this.errorCategory = errorCategory; + this.errorCode = code; + this.errorDescription = errorMessage; + } + + public static PaymentHubErrorCategory getCategory(String errorCode) { + return fromCode(errorCode).getErrorCategory(); + } + + public static PaymentHubError fromCode(String code) { + return Arrays.stream(values()).filter(ec -> ec.getErrorCode().equalsIgnoreCase(code)).findFirst() + .orElseThrow(() -> new RuntimeException("Can not get unknown errorCode: " + code)); + } + + public static List fromCategory(PaymentHubErrorCategory errorCategory) { + return Arrays.stream(values()).filter(ec -> ec.errorCategory == errorCategory).collect(Collectors.toList()); + } +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/exception/PaymentHubErrorCategory.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/exception/PaymentHubErrorCategory.java new file mode 100644 index 000000000..5ee79da9a --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/exception/PaymentHubErrorCategory.java @@ -0,0 +1,5 @@ +package org.mifos.connector.common.exception; + +public enum PaymentHubErrorCategory { + Interop, System, BusinessRule, Validation +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/exception/PaymentHubException.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/exception/PaymentHubException.java new file mode 100644 index 000000000..b47c1980a --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/exception/PaymentHubException.java @@ -0,0 +1,79 @@ +package org.mifos.connector.common.exception; + +import lombok.Getter; + +@Getter +public final class PaymentHubException extends Exception { + + private final String errorCode; + private final String errorDescription; + + private PaymentHubException(PhExceptionBuilder builder) { + this.errorCode = builder.errorCode; + this.errorDescription = builder.errorDescription; + } + + public void throwException() throws PaymentHubException { + throw this; + } + + /** + * Builder class for PaymentHubException + * + * Ways to create an exception object + * + * 1. Set error code and description (Can be used for creating custom errors) new + * PaymentHubException.PhExceptionBuilder() .withErrorCode(ec) .withErrorDescription(ed) .build() + * + * 2. Set [PaymentHubErrors] enum (Can be used for creating predefined errors) new + * PaymentHubException.PhExceptionBuilder() .withErrorInformation(PaymentHubErrors.PayerFSPIdNotFound) .build(); + * + * 3. Set error code (can be used when error code belong to existing list of errors) new + * PaymentHubException.PhExceptionBuilder() .withErrorCode("PayerFSPIdNotFound") .build(); + * + */ + public static class PhExceptionBuilder { + + private String errorCode; + private String errorDescription; + + public PhExceptionBuilder withErrorCode(String errorCode) { + this.errorCode = errorCode; + return this; + } + + public PhExceptionBuilder withErrorDescription(String errorInformation) { + this.errorDescription = errorInformation; + return this; + } + + public PhExceptionBuilder withErrorInformation(PaymentHubError errorInformation) { + this.errorCode = errorInformation.getErrorCode(); + this.errorDescription = errorInformation.getErrorDescription(); + return this; + } + + public PaymentHubException build() { + validate(); + return new PaymentHubException(this); + } + + // builds and throws an PaymentHubException + public void throwException() throws PaymentHubException { + build().throwException(); + } + + // validates the fields and fetches default values for error code + private void validate() { + if (errorCode == null) { + throw new IllegalArgumentException("Error code is required"); + } + if (errorDescription == null) { + PaymentHubError paymentHubErrors = PaymentHubError.fromCode(this.errorCode); + this.errorCode = paymentHubErrors.getErrorCode(); + this.errorDescription = paymentHubErrors.getErrorDescription(); + } + } + } + +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/exception/ValidationException.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/exception/ValidationException.java new file mode 100644 index 000000000..93dffdd90 --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/exception/ValidationException.java @@ -0,0 +1,13 @@ +package org.mifos.connector.common.exception; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import org.mifos.connector.common.channel.dto.PhErrorDTO; + +@Getter +@RequiredArgsConstructor +public class ValidationException extends RuntimeException { + + private final PhErrorDTO phErrorDTO; + +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/exception/mapper/ErrorMapper.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/exception/mapper/ErrorMapper.java new file mode 100644 index 000000000..2069f2cfc --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/exception/mapper/ErrorMapper.java @@ -0,0 +1,48 @@ +package org.mifos.connector.common.exception.mapper; + +import java.util.HashMap; +import java.util.Map; +import org.mifos.connector.common.exception.PaymentHubError; + +/** + * Default implementation of mapper. This class can be used in ams or payment schema connector for creating there + * respective mappings of external error codes. + */ +public abstract class ErrorMapper implements Mapper { + + private Map errorMap = new HashMap<>(); + + public ErrorMapper() { + configure(); + } + + @Override + public void add(String externalErrorCode, PaymentHubError internalError) { + errorMap.put(externalErrorCode, internalError); + } + + @Override + public void add(String externalErrorCode, String internalError) { + errorMap.put(externalErrorCode, PaymentHubError.fromCode(internalError)); + } + + @Override + public PaymentHubError getInternalError(String externalErrorCode) { + return errorMap.get(externalErrorCode); + } + + @Override + public String getExternalError(String internalErrorCode) { + PaymentHubError paymentHubErrors = PaymentHubError.fromCode(internalErrorCode); + PaymentHubError filterResult = errorMap.values().stream().filter(paymentHubErrors::equals).findFirst() + .orElseThrow(() -> new RuntimeException("Can not get external error code for internal error code: " + internalErrorCode)); + return filterResult.getErrorCode(); + } + + @Override + public String getExternalError(PaymentHubError internalErrorCode) { + PaymentHubError filterResult = errorMap.values().stream().filter(internalErrorCode::equals).findFirst() + .orElseThrow(() -> new RuntimeException("Can not get external error code for internal error code: " + internalErrorCode)); + return filterResult.getErrorCode(); + } +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/exception/mapper/GlobalExceptionMapper.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/exception/mapper/GlobalExceptionMapper.java new file mode 100644 index 000000000..ebfe14188 --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/exception/mapper/GlobalExceptionMapper.java @@ -0,0 +1,14 @@ +package org.mifos.connector.common.exception.mapper; + +import org.mifos.connector.common.channel.dto.PhErrorDTO; +import org.mifos.connector.common.exception.ValidationException; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.ExceptionHandler; + +public class GlobalExceptionMapper { + @ExceptionHandler(ValidationException.class) + public ResponseEntity handleValidationException(ValidationException ex) { + return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(ex.getPhErrorDTO()); + } +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/exception/mapper/Mapper.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/exception/mapper/Mapper.java new file mode 100644 index 000000000..ca2e6feb9 --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/exception/mapper/Mapper.java @@ -0,0 +1,27 @@ +package org.mifos.connector.common.exception.mapper; + +import org.mifos.connector.common.exception.PaymentHubError; + +/** + * Interface for creating external error code mapper + */ +public interface Mapper { + + // adds the mapping of externalErrorCode - [PaymentHubErrors] + void add(String externalErrorCode, PaymentHubError internalError); + + // adds the mapping of externalErrorCode - [PaymentHubErrors] (fetches enum using the string passed) + void add(String externalErrorCode, String internalError); + + // getting the internal error code using the external error code + PaymentHubError getInternalError(String externalErrorCode); + + // getting the external error code using the internal error code + String getExternalError(String internalErrorCode); + + // getting the external error code using the internal error code enum + String getExternalError(PaymentHubError internalErrorCode); + + // method to configure all the mappings + void configure(); +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/gsma/dto/AccessTokenDTO.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/gsma/dto/AccessTokenDTO.java new file mode 100644 index 000000000..b5404ab65 --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/gsma/dto/AccessTokenDTO.java @@ -0,0 +1,37 @@ +package org.mifos.connector.common.gsma.dto; + +public class AccessTokenDTO { + + private String accessToken; + private int expiresIn; + + public AccessTokenDTO() { + + } + + @Override + public String toString() { + return "AccessTokenDTO{" + "accessToken='" + accessToken + '\'' + ", expiresIn=" + expiresIn + '}'; + } + + public String getaccessToken() { + return accessToken; + } + + public void setaccessToken(String accessToken) { + this.accessToken = accessToken; + } + + public int getexpiresIn() { + return expiresIn; + } + + public void setexpiresIn(int expiresIn) { + this.expiresIn = expiresIn; + } + + public AccessTokenDTO(String accessToken, int expiresIn) { + this.accessToken = accessToken; + this.expiresIn = expiresIn; + } +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/gsma/dto/AccountBalanceResponseDTO.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/gsma/dto/AccountBalanceResponseDTO.java new file mode 100644 index 000000000..b0a44c35b --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/gsma/dto/AccountBalanceResponseDTO.java @@ -0,0 +1,66 @@ +package org.mifos.connector.common.gsma.dto; + +public class AccountBalanceResponseDTO { + + private String currentBalance; + private String availableBalance; + private String reservedBalance; + private String unclearedBalance; + private String currency; + private String accountStatus; + + public String getCurrentBalance() { + return currentBalance; + } + + public void setCurrentBalance(String currentBalance) { + this.currentBalance = currentBalance; + } + + public String getAvailableBalance() { + return availableBalance; + } + + public void setAvailableBalance(String availableBalance) { + this.availableBalance = availableBalance; + } + + public String getReservedBalance() { + return reservedBalance; + } + + public void setReservedBalance(String reservedBalance) { + this.reservedBalance = reservedBalance; + } + + public String getUnclearedBalance() { + return unclearedBalance; + } + + public void setUnclearedBalance(String unclearedBalance) { + this.unclearedBalance = unclearedBalance; + } + + public String getCurrency() { + return currency; + } + + public void setCurrency(String currency) { + this.currency = currency; + } + + public String getAccountStatus() { + return accountStatus; + } + + public void setAccountStatus(String accountStatus) { + this.accountStatus = accountStatus; + } + + @Override + public String toString() { + return "AccountBalanceResponseDTO{" + "currentBalance='" + currentBalance + '\'' + ", availableBalance='" + availableBalance + '\'' + + ", reservedBalance='" + reservedBalance + '\'' + ", unclearedBalance='" + unclearedBalance + '\'' + ", currency='" + + currency + '\'' + ", accountStatus='" + accountStatus + '\'' + '}'; + } +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/gsma/dto/AccountNameResponseDTO.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/gsma/dto/AccountNameResponseDTO.java new file mode 100644 index 000000000..f63a4f6cf --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/gsma/dto/AccountNameResponseDTO.java @@ -0,0 +1,14 @@ +package org.mifos.connector.common.gsma.dto; + +public class AccountNameResponseDTO { + + private Name name; + + public Name getName() { + return name; + } + + public void setName(Name name) { + this.name = name; + } +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/gsma/dto/AccountStatus.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/gsma/dto/AccountStatus.java new file mode 100644 index 000000000..7b4ef0b20 --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/gsma/dto/AccountStatus.java @@ -0,0 +1,51 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla + * Public License, v. 2.0. If a copy of the MPL was not distributed + * with this file, You can obtain one at + * + * https://mozilla.org/MPL/2.0/. + */ + +/** +@Author Sidhant Gupta +*/ +package org.mifos.connector.common.gsma.dto; + +/* +{ + "status": "available", + "subStatus": null, + "lei": "AAAA0012345678901299" +} + */ +//Refactor to use interoperability APIs instead. +public class AccountStatus { + + String status; + String subStatus; + String lei; + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } + + public String getSubStatus() { + return subStatus; + } + + public void setSubStatus(String subStatus) { + this.subStatus = subStatus; + } + + public String getLei() { + return lei; + } + + public void setLei(String lei) { + this.lei = lei; + } +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/gsma/dto/AccountStatusRequest.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/gsma/dto/AccountStatusRequest.java new file mode 100644 index 000000000..def95ab8f --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/gsma/dto/AccountStatusRequest.java @@ -0,0 +1,23 @@ +package org.mifos.connector.common.gsma.dto; + +public class AccountStatusRequest { + + public String identifierType; + public String identifier; + + public String getIdentifierType() { + return identifierType; + } + + public void setIdentifierType(String identifierType) { + this.identifierType = identifierType; + } + + public String getIdentifier() { + return identifier; + } + + public void setIdentifier(String identifier) { + this.identifier = identifier; + } +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/gsma/dto/AccountStatusResponseDTO.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/gsma/dto/AccountStatusResponseDTO.java new file mode 100644 index 000000000..e8eda00c5 --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/gsma/dto/AccountStatusResponseDTO.java @@ -0,0 +1,14 @@ +package org.mifos.connector.common.gsma.dto; + +public class AccountStatusResponseDTO { + + public String accountStatus; + + public String getAccountStatus() { + return accountStatus; + } + + public void setAccountStatus(String accountStatus) { + this.accountStatus = accountStatus; + } +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/gsma/dto/AuthErrorDTO.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/gsma/dto/AuthErrorDTO.java new file mode 100644 index 000000000..c3eda0671 --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/gsma/dto/AuthErrorDTO.java @@ -0,0 +1,32 @@ +package org.mifos.connector.common.gsma.dto; + +public class AuthErrorDTO { + + private String errorCode; + private String errorMessage; + + public AuthErrorDTO() { + + } + + public AuthErrorDTO(String errorCode, String errorMessage) { + this.errorCode = errorCode; + this.errorMessage = errorMessage; + } + + public String getErrorCode() { + return errorCode; + } + + public void setErrorCode(String errorCode) { + this.errorCode = errorCode; + } + + public String getErrorMessage() { + return errorMessage; + } + + public void setErrorMessage(String errorMessage) { + this.errorMessage = errorMessage; + } +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/gsma/dto/AuthorizationCodeDTO.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/gsma/dto/AuthorizationCodeDTO.java new file mode 100644 index 000000000..6f05e1a01 --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/gsma/dto/AuthorizationCodeDTO.java @@ -0,0 +1,126 @@ +package org.mifos.connector.common.gsma.dto; + +import java.util.Arrays; + +public class AuthorizationCodeDTO { + + private String authorisationCode; + private String codeState; + private String codeLifetime; + private String requestDate; + private String amount; + private String currency; + private String amountType; + private String holdFundsIndicator; + + private RedemptionChannel[] redemptionChannels; + private RedemptionTransactionType[] redemptionTransactionTypes; + private GsmaParty[] redemptionAccountIdentifiers; + private GsmaParty[] metadata; + + public String getAuthorisationCode() { + return authorisationCode; + } + + public void setAuthorisationCode(String authorisationCode) { + this.authorisationCode = authorisationCode; + } + + public String getCodeState() { + return codeState; + } + + public void setCodeState(String codeState) { + this.codeState = codeState; + } + + public String getCodeLifetime() { + return codeLifetime; + } + + public void setCodeLifetime(String codeLifetime) { + this.codeLifetime = codeLifetime; + } + + public String getRequestDate() { + return requestDate; + } + + public void setRequestDate(String requestDate) { + this.requestDate = requestDate; + } + + public String getAmount() { + return amount; + } + + public void setAmount(String amount) { + this.amount = amount; + } + + public String getCurrency() { + return currency; + } + + public void setCurrency(String currency) { + this.currency = currency; + } + + public String getAmountType() { + return amountType; + } + + public void setAmountType(String amountType) { + this.amountType = amountType; + } + + public String getHoldFundsIndicator() { + return holdFundsIndicator; + } + + public void setHoldFundsIndicator(String holdFundsIndicator) { + this.holdFundsIndicator = holdFundsIndicator; + } + + public RedemptionChannel[] getRedemptionChannels() { + return redemptionChannels; + } + + public void setRedemptionChannels(RedemptionChannel[] redemptionChannels) { + this.redemptionChannels = redemptionChannels; + } + + public RedemptionTransactionType[] getRedemptionTransactionTypes() { + return redemptionTransactionTypes; + } + + public void setRedemptionTransactionTypes(RedemptionTransactionType[] redemptionTransactionTypes) { + this.redemptionTransactionTypes = redemptionTransactionTypes; + } + + public GsmaParty[] getRedemptionAccountIdentifiers() { + return redemptionAccountIdentifiers; + } + + public void setRedemptionAccountIdentifiers(GsmaParty[] redemptionAccountIdentifiers) { + this.redemptionAccountIdentifiers = redemptionAccountIdentifiers; + } + + public GsmaParty[] getMetadata() { + return metadata; + } + + public void setMetadata(GsmaParty[] metadata) { + this.metadata = metadata; + } + + @Override + public String toString() { + return "AuthorizationCodeDTO{" + "authorisationCode='" + authorisationCode + '\'' + ", codeState='" + codeState + '\'' + + ", codeLifetime='" + codeLifetime + '\'' + ", requestDate='" + requestDate + '\'' + ", amount='" + amount + '\'' + + ", currency='" + currency + '\'' + ", amountType='" + amountType + '\'' + ", holdFundsIndicator='" + holdFundsIndicator + + '\'' + ", redemptionChannels=" + Arrays.toString(redemptionChannels) + ", redemptionTransactionTypes=" + + Arrays.toString(redemptionTransactionTypes) + ", redemptionAccountIdentifiers=" + + Arrays.toString(redemptionAccountIdentifiers) + ", metadata=" + Arrays.toString(metadata) + '}'; + } +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/gsma/dto/Bill.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/gsma/dto/Bill.java new file mode 100644 index 000000000..321feff35 --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/gsma/dto/Bill.java @@ -0,0 +1,50 @@ +package org.mifos.connector.common.gsma.dto; + +public class Bill { + + private String currency; + private String amountDue; + private String dueDate; + private String billReference; + private String minimumAmountDue; + + public String getCurrency() { + return currency; + } + + public void setCurrency(String currency) { + this.currency = currency; + } + + public String getAmountDue() { + return amountDue; + } + + public void setAmountDue(String amountDue) { + this.amountDue = amountDue; + } + + public String getDueDate() { + return dueDate; + } + + public void setDueDate(String dueDate) { + this.dueDate = dueDate; + } + + public String getBillReference() { + return billReference; + } + + public void setBillReference(String billReference) { + this.billReference = billReference; + } + + public String getMinimumAmountDue() { + return minimumAmountDue; + } + + public void setMinimumAmountDue(String minimumAmountDue) { + this.minimumAmountDue = minimumAmountDue; + } +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/gsma/dto/BillPaymentDTO.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/gsma/dto/BillPaymentDTO.java new file mode 100644 index 000000000..a5477de0c --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/gsma/dto/BillPaymentDTO.java @@ -0,0 +1,122 @@ +package org.mifos.connector.common.gsma.dto; + +public class BillPaymentDTO { + + private String currency; + private String amountPaid; + private String paidAmount; + private String serviceProviderPaymentReference; + private String billPaymentStatus; + private String requestingOrganisation; + private String requestingOrganisationTransactionReference; + private String customerReference; + private String paymentType; + private String serviceProviderComment; + private String serviceProviderNotification; + private SupplementaryBillReferenceDetail[] supplementaryBillReferenceDetails; + private GsmaParty[] metadata; + + public String getCurrency() { + return currency; + } + + public void setCurrency(String currency) { + this.currency = currency; + } + + public String getAmountPaid() { + return amountPaid; + } + + public void setAmountPaid(String amountPaid) { + this.amountPaid = amountPaid; + } + + public String getPaidAmount() { + return paidAmount; + } + + public void setPaidAmount(String paidAmount) { + this.paidAmount = paidAmount; + } + + public String getServiceProviderPaymentReference() { + return serviceProviderPaymentReference; + } + + public void setServiceProviderPaymentReference(String serviceProviderPaymentReference) { + this.serviceProviderPaymentReference = serviceProviderPaymentReference; + } + + public String getBillPaymentStatus() { + return billPaymentStatus; + } + + public void setBillPaymentStatus(String billPaymentStatus) { + this.billPaymentStatus = billPaymentStatus; + } + + public String getRequestingOrganisation() { + return requestingOrganisation; + } + + public void setRequestingOrganisation(String requestingOrganisation) { + this.requestingOrganisation = requestingOrganisation; + } + + public String getRequestingOrganisationTransactionReference() { + return requestingOrganisationTransactionReference; + } + + public void setRequestingOrganisationTransactionReference(String requestingOrganisationTransactionReference) { + this.requestingOrganisationTransactionReference = requestingOrganisationTransactionReference; + } + + public String getCustomerReference() { + return customerReference; + } + + public void setCustomerReference(String customerReference) { + this.customerReference = customerReference; + } + + public String getPaymentType() { + return paymentType; + } + + public void setPaymentType(String paymentType) { + this.paymentType = paymentType; + } + + public String getServiceProviderComment() { + return serviceProviderComment; + } + + public void setServiceProviderComment(String serviceProviderComment) { + this.serviceProviderComment = serviceProviderComment; + } + + public String getServiceProviderNotification() { + return serviceProviderNotification; + } + + public void setServiceProviderNotification(String serviceProviderNotification) { + this.serviceProviderNotification = serviceProviderNotification; + } + + public SupplementaryBillReferenceDetail[] getSupplementaryBillReferenceDetails() { + return supplementaryBillReferenceDetails; + } + + public void setSupplementaryBillReferenceDetails(SupplementaryBillReferenceDetail[] supplementaryBillReferenceDetails) { + this.supplementaryBillReferenceDetails = supplementaryBillReferenceDetails; + } + + public GsmaParty[] getMetadata() { + return metadata; + } + + public void setMetadata(GsmaParty[] metadata) { + this.metadata = metadata; + } +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/gsma/dto/CustomData.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/gsma/dto/CustomData.java new file mode 100644 index 000000000..260cb6ec7 --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/gsma/dto/CustomData.java @@ -0,0 +1,18 @@ +package org.mifos.connector.common.gsma.dto; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import lombok.ToString; + +@Getter +@Setter +@ToString +@NoArgsConstructor +@AllArgsConstructor +public class CustomData { + + public String key; + public Object value; +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/gsma/dto/DebitMandateDTO.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/gsma/dto/DebitMandateDTO.java new file mode 100644 index 000000000..39188ee9a --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/gsma/dto/DebitMandateDTO.java @@ -0,0 +1,122 @@ +package org.mifos.connector.common.gsma.dto; + +public class DebitMandateDTO { + + private String currency; + private String amountLimit; + private String startDate; + private String endDate; + private Integer numberOfPayments; + private String frequencyType; + private String mandateStatus; + private String requestDate; + private String mandateReference; + private String creationDate; + private String modificationDate; + private String dateCreated; + private String dateModified; + + public String getCurrency() { + return currency; + } + + public void setCurrency(String currency) { + this.currency = currency; + } + + public String getAmountLimit() { + return amountLimit; + } + + public void setAmountLimit(String amountLimit) { + this.amountLimit = amountLimit; + } + + public String getStartDate() { + return startDate; + } + + public void setStartDate(String startDate) { + this.startDate = startDate; + } + + public String getEndDate() { + return endDate; + } + + public void setEndDate(String endDate) { + this.endDate = endDate; + } + + public Integer getNumberOfPayments() { + return numberOfPayments; + } + + public void setNumberOfPayments(Integer numberOfPayments) { + this.numberOfPayments = numberOfPayments; + } + + public String getFrequencyType() { + return frequencyType; + } + + public void setFrequencyType(String frequencyType) { + this.frequencyType = frequencyType; + } + + public String getMandateStatus() { + return mandateStatus; + } + + public void setMandateStatus(String mandateStatus) { + this.mandateStatus = mandateStatus; + } + + public String getRequestDate() { + return requestDate; + } + + public void setRequestDate(String requestDate) { + this.requestDate = requestDate; + } + + public String getMandateReference() { + return mandateReference; + } + + public void setMandateReference(String mandateReference) { + this.mandateReference = mandateReference; + } + + public String getCreationDate() { + return creationDate; + } + + public void setCreationDate(String creationDate) { + this.creationDate = creationDate; + } + + public String getModificationDate() { + return modificationDate; + } + + public void setModificationDate(String modificationDate) { + this.modificationDate = modificationDate; + } + + public String getDateCreated() { + return dateCreated; + } + + public void setDateCreated(String dateCreated) { + this.dateCreated = dateCreated; + } + + public String getDateModified() { + return dateModified; + } + + public void setDateModified(String dateModified) { + this.dateModified = dateModified; + } +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/gsma/dto/ErrorDTO.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/gsma/dto/ErrorDTO.java new file mode 100644 index 000000000..bc3da23ba --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/gsma/dto/ErrorDTO.java @@ -0,0 +1,58 @@ +package org.mifos.connector.common.gsma.dto; + +import java.util.List; + +public class ErrorDTO { + + public String errorCategory; + public String errorCode; + public String errorDescription; + public String errorDateTime; + public List errorParameters = null; + + public String getErrorCategory() { + return errorCategory; + } + + public void setErrorCategory(String errorCategory) { + this.errorCategory = errorCategory; + } + + public String getErrorCode() { + return errorCode; + } + + public void setErrorCode(String errorCode) { + this.errorCode = errorCode; + } + + public String getErrorDescription() { + return errorDescription; + } + + public void setErrorDescription(String errorDescription) { + this.errorDescription = errorDescription; + } + + public String getErrorDateTime() { + return errorDateTime; + } + + public void setErrorDateTime(String errorDateTime) { + this.errorDateTime = errorDateTime; + } + + public List getErrorParameters() { + return errorParameters; + } + + public void setErrorParameters(List errorParameters) { + this.errorParameters = errorParameters; + } + + @Override + public String toString() { + return "ErrorDTO{" + "errorCategory='" + errorCategory + '\'' + ", errorCode='" + errorCode + '\'' + ", errorDescription='" + + errorDescription + '\'' + ", errorDateTime='" + errorDateTime + '\'' + ", errorParameters=" + errorParameters + '}'; + } +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/gsma/dto/ErrorParameter.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/gsma/dto/ErrorParameter.java new file mode 100644 index 000000000..ee74ba2b0 --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/gsma/dto/ErrorParameter.java @@ -0,0 +1,23 @@ +package org.mifos.connector.common.gsma.dto; + +public class ErrorParameter { + + public String key; + public String value; + + public String getKey() { + return key; + } + + public void setKey(String key) { + this.key = key; + } + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/gsma/dto/Fee.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/gsma/dto/Fee.java new file mode 100644 index 000000000..5453c9c62 --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/gsma/dto/Fee.java @@ -0,0 +1,37 @@ +package org.mifos.connector.common.gsma.dto; + +public class Fee { + + private String feeType; + private String feeAmount; + private String feeCurrency; + + public String getFeeType() { + return feeType; + } + + public void setFeeType(String feeType) { + this.feeType = feeType; + } + + public String getFeeAmount() { + return feeAmount; + } + + public void setFeeAmount(String feeAmount) { + this.feeAmount = feeAmount; + } + + public String getFeeCurrency() { + return feeCurrency; + } + + public void setFeeCurrency(String feeCurrency) { + this.feeCurrency = feeCurrency; + } + + @Override + public String toString() { + return "Fee{" + "feeType='" + feeType + '\'' + ", feeAmount='" + feeAmount + '\'' + ", feeCurrency='" + feeCurrency + '\'' + '}'; + } +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/gsma/dto/FineractTransaction.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/gsma/dto/FineractTransaction.java new file mode 100644 index 000000000..ad7d3aee7 --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/gsma/dto/FineractTransaction.java @@ -0,0 +1,110 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla + * Public License, v. 2.0. If a copy of the MPL was not distributed + * with this file, You can obtain one at + * + * https://mozilla.org/MPL/2.0/. + */ + +/** +@Author Sidhant Gupta +*/ + +package org.mifos.connector.common.gsma.dto; + +public class FineractTransaction { + + public FineractTransaction() {} + + String locale; + String dateFormat; + String transactionDate; + String transactionAmount; + String paymentTypeId; + String accountNumber; + String checkNumber; + String routingCode; + String receiptNumber; + String bankNumber; + + public String getLocale() { + return locale; + } + + public void setLocale(String locale) { + this.locale = locale; + } + + public String getDateFormat() { + return dateFormat; + } + + public void setDateFormat(String dateFormat) { + this.dateFormat = dateFormat; + } + + public String getTransactionDate() { + return transactionDate; + } + + public void setTransactionDate(String transactionDate) { + this.transactionDate = transactionDate; + } + + public String getTransactionAmount() { + return transactionAmount; + } + + public void setTransactionAmount(String transactionAmount) { + this.transactionAmount = transactionAmount; + } + + public String getPaymentTypeId() { + return paymentTypeId; + } + + public void setPaymentTypeId(String paymentTypeId) { + this.paymentTypeId = paymentTypeId; + } + + public String getAccountNumber() { + return accountNumber; + } + + public void setAccountNumber(String accountNumber) { + this.accountNumber = accountNumber; + } + + public String getCheckNumber() { + return checkNumber; + } + + public void setCheckNumber(String checkNumber) { + this.checkNumber = checkNumber; + } + + public String getRoutingCode() { + return routingCode; + } + + public void setRoutingCode(String routingCode) { + this.routingCode = routingCode; + } + + public String getReceiptNumber() { + return receiptNumber; + } + + public void setReceiptNumber(String receiptNumber) { + this.receiptNumber = receiptNumber; + } + + public String getBankNumber() { + return bankNumber; + } + + public void setBankNumber(String bankNumber) { + this.bankNumber = bankNumber; + } + +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/gsma/dto/GSMATransaction.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/gsma/dto/GSMATransaction.java new file mode 100644 index 000000000..830584c68 --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/gsma/dto/GSMATransaction.java @@ -0,0 +1,276 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla + * Public License, v. 2.0. If a copy of the MPL was not distributed + * with this file, You can obtain one at + * + * https://mozilla.org/MPL/2.0/. + */ + +/** + * @Author Sidhant Gupta + */ +package org.mifos.connector.common.gsma.dto; + +import java.util.Arrays; + +public class GSMATransaction { + + String amount; + String currency; + String type; + String subType; + String descriptionText; + String requestDate; + String requestingOrganisationTransactionReference; + String oneTimeCode; + String geoCode; + + GsmaParty[] debitParty; + GsmaParty[] creditParty; + + Kyc senderKyc; + Kyc receiverKyc; + + String originalTransactionReference; + + String servicingIdentity; + + Fee[] fees; + + String requestingLei; + String receivingLei; + + GsmaParty[] metadata; + + String transactionStatus; + String creationDate; + String modificationDate; + String transactionReference; + String transactionReceipt; + String convLockKey; + + InternationalTransferInformation internationalTransferInformation; + + public String getAmount() { + return amount; + } + + public void setAmount(String amount) { + this.amount = amount; + } + + public String getCurrency() { + return currency; + } + + public void setCurrency(String currency) { + this.currency = currency; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public String getSubType() { + return subType; + } + + public void setSubType(String subType) { + this.subType = subType; + } + + public String getDescriptionText() { + return descriptionText; + } + + public void setDescriptionText(String descriptionText) { + this.descriptionText = descriptionText; + } + + public String getRequestDate() { + return requestDate; + } + + public void setRequestDate(String requestDate) { + this.requestDate = requestDate; + } + + public String getRequestingOrganisationTransactionReference() { + return requestingOrganisationTransactionReference; + } + + public void setRequestingOrganisationTransactionReference(String requestingOrganisationTransactionReference) { + this.requestingOrganisationTransactionReference = requestingOrganisationTransactionReference; + } + + public String getOneTimeCode() { + return oneTimeCode; + } + + public void setOneTimeCode(String oneTimeCode) { + this.oneTimeCode = oneTimeCode; + } + + public String getGeoCode() { + return geoCode; + } + + public void setGeoCode(String geoCode) { + this.geoCode = geoCode; + } + + public Kyc getSenderKyc() { + return senderKyc; + } + + public void setSenderKyc(Kyc senderKyc) { + this.senderKyc = senderKyc; + } + + public Kyc getReceiverKyc() { + return receiverKyc; + } + + public void setReceiverKyc(Kyc receiverKyc) { + this.receiverKyc = receiverKyc; + } + + public String getOriginalTransactionReference() { + return originalTransactionReference; + } + + public void setOriginalTransactionReference(String originalTransactionReference) { + this.originalTransactionReference = originalTransactionReference; + } + + public String getServicingIdentity() { + return servicingIdentity; + } + + public void setServicingIdentity(String servicingIdentity) { + this.servicingIdentity = servicingIdentity; + } + + public String getRequestingLei() { + return requestingLei; + } + + public void setRequestingLei(String requestingLei) { + this.requestingLei = requestingLei; + } + + public String getReceivingLei() { + return receivingLei; + } + + public void setReceivingLei(String receivingLei) { + this.receivingLei = receivingLei; + } + + public String getTransactionStatus() { + return transactionStatus; + } + + public void setTransactionStatus(String transactionStatus) { + this.transactionStatus = transactionStatus; + } + + public String getCreationDate() { + return creationDate; + } + + public void setCreationDate(String creationDate) { + this.creationDate = creationDate; + } + + public String getModificationDate() { + return modificationDate; + } + + public void setModificationDate(String modificationDate) { + this.modificationDate = modificationDate; + } + + public String getTransactionReference() { + return transactionReference; + } + + public void setTransactionReference(String transactionReference) { + this.transactionReference = transactionReference; + } + + public String getTransactionReceipt() { + return transactionReceipt; + } + + public void setTransactionReceipt(String transactionReceipt) { + this.transactionReceipt = transactionReceipt; + } + + public InternationalTransferInformation getInternationalTransferInformation() { + return internationalTransferInformation; + } + + public void setInternationalTransferInformation(InternationalTransferInformation internationalTransferInformation) { + this.internationalTransferInformation = internationalTransferInformation; + } + + public GsmaParty[] getDebitParty() { + return debitParty; + } + + public void setDebitParty(GsmaParty[] debitParty) { + this.debitParty = debitParty; + } + + public GsmaParty[] getCreditParty() { + return creditParty; + } + + public void setCreditParty(GsmaParty[] creditParty) { + this.creditParty = creditParty; + } + + public GsmaParty[] getMetadata() { + return metadata; + } + + public void setMetadata(GsmaParty[] metadata) { + this.metadata = metadata; + } + + public Fee[] getFees() { + return fees; + } + + public void setFees(Fee[] fees) { + this.fees = fees; + } + + public String getConvLockKey() { + return convLockKey; + } + + public void setConvLockKey(String convLockKey) { + this.convLockKey = convLockKey; + } + + @Override + public String toString() { + return "GSMATransaction{" + "amount='" + amount + '\'' + ", currency='" + currency + '\'' + ", type='" + type + '\'' + ", subType='" + + subType + '\'' + ", descriptionText='" + descriptionText + '\'' + ", requestDate='" + requestDate + '\'' + + ", requestingOrganisationTransactionReference='" + requestingOrganisationTransactionReference + '\'' + ", oneTimeCode='" + + oneTimeCode + '\'' + ", geoCode='" + geoCode + '\'' + ", debitParty=" + Arrays.toString(debitParty) + ", creditParty=" + + Arrays.toString(creditParty) + ", senderKyc=" + senderKyc + ", receiverKyc=" + receiverKyc + + ", originalTransactionReference='" + originalTransactionReference + '\'' + ", servicingIdentity='" + servicingIdentity + + '\'' + ", requestingLei='" + requestingLei + '\'' + ", receivingLei='" + receivingLei + '\'' + ", metadata=" + + Arrays.toString(metadata) + ", transactionStatus='" + transactionStatus + '\'' + ", creationDate='" + creationDate + '\'' + + ", modificationDate='" + modificationDate + '\'' + ", transactionReference='" + transactionReference + '\'' + + ", transactionReceipt='" + transactionReceipt + '\'' + ", internationalTransferInformation=" + + internationalTransferInformation + ", convLockKey=" + convLockKey + '}'; + } +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/gsma/dto/GsmaParty.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/gsma/dto/GsmaParty.java new file mode 100644 index 000000000..7db09f3e1 --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/gsma/dto/GsmaParty.java @@ -0,0 +1,34 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla + * Public License, v. 2.0. If a copy of the MPL was not distributed + * with this file, You can obtain one at + * + * https://mozilla.org/MPL/2.0/. + */ + +/** +@Author Sidhant Gupta +*/ +package org.mifos.connector.common.gsma.dto; + +public class GsmaParty { + + String key; + String value; + + public String getKey() { + return key; + } + + public void setKey(String key) { + this.key = key; + } + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/gsma/dto/GsmaTransfer.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/gsma/dto/GsmaTransfer.java new file mode 100644 index 000000000..27d808b42 --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/gsma/dto/GsmaTransfer.java @@ -0,0 +1,38 @@ +package org.mifos.connector.common.gsma.dto; + +import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.List; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import lombok.ToString; + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +@ToString +public class GsmaTransfer { + + @JsonProperty("requestingOrganisationTransactionReference") + private String requestingOrganisationTransactionReference; + @JsonProperty("subType") + private String subType; + @JsonProperty("type") + private String type; + @JsonProperty("amount") + private String amount; + @JsonProperty("currency") + private String currency; + @JsonProperty("descriptionText") + private String descriptionText; + @JsonProperty("requestDate") + private String requestDate; + @JsonProperty("customData") + private List customData; + @JsonProperty("payer") + private List payer; + @JsonProperty("payee") + private List payee; +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/gsma/dto/IdDocument.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/gsma/dto/IdDocument.java new file mode 100644 index 000000000..95918b087 --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/gsma/dto/IdDocument.java @@ -0,0 +1,88 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla + * Public License, v. 2.0. If a copy of the MPL was not distributed + * with this file, You can obtain one at + * + * https://mozilla.org/MPL/2.0/. + */ + +/** +@Author Sidhant Gupta +*/ +package org.mifos.connector.common.gsma.dto; + +public class IdDocument { + + String idType; + String idNumber; + String issueDate; + String expiryDate; + String issuer; + String issuerPlace; + String issuerCountry; + String otherIdDescription; + + public String getIdType() { + return idType; + } + + public void setIdType(String idType) { + this.idType = idType; + } + + public String getIdNumber() { + return idNumber; + } + + public void setIdNumber(String idNumber) { + this.idNumber = idNumber; + } + + public String getIssueDate() { + return issueDate; + } + + public void setIssueDate(String issueDate) { + this.issueDate = issueDate; + } + + public String getExpiryDate() { + return expiryDate; + } + + public void setExpiryDate(String expiryDate) { + this.expiryDate = expiryDate; + } + + public String getIssuer() { + return issuer; + } + + public void setIssuer(String issuer) { + this.issuer = issuer; + } + + public String getIssuerPlace() { + return issuerPlace; + } + + public void setIssuerPlace(String issuerPlace) { + this.issuerPlace = issuerPlace; + } + + public String getIssuerCountry() { + return issuerCountry; + } + + public void setIssuerCountry(String issuerCountry) { + this.issuerCountry = issuerCountry; + } + + public String getOtherIdDescription() { + return otherIdDescription; + } + + public void setOtherIdDescription(String otherIdDescription) { + this.otherIdDescription = otherIdDescription; + } +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/gsma/dto/InternationalTransferInformation.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/gsma/dto/InternationalTransferInformation.java new file mode 100644 index 000000000..2274deef0 --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/gsma/dto/InternationalTransferInformation.java @@ -0,0 +1,156 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla + * Public License, v. 2.0. If a copy of the MPL was not distributed + * with this file, You can obtain one at + * + * https://mozilla.org/MPL/2.0/. + */ + +/** +@Author Sidhant Gupta +*/ +package org.mifos.connector.common.gsma.dto; + +/* +"internationalTransferInformation": { + "originCountry": "AD", + "quotationReference": "string", + "quoteId": "string", + "receivingCountry": "AD", + "remittancePurpose": "string", + "relationshipSender": "string", + "deliveryMethod": "directtoaccount", + "senderBlockingReason": "string", + "recipientBlockingReason": "string" +} +*/ + +public class InternationalTransferInformation { + + String originCountry; + String quotationReference; + String quoteId; + String receivingCountry; + String remittancePurpose; + String relationshipSender; + String deliveryMethod; + String senderBlockingReason; + String recipientBlockingReason; + String receivingCurrency; + String senderCurrency; + String currencyPair; + String currencyPairRate; + String receivingAmount; + + public String getOriginCountry() { + return originCountry; + } + + public void setOriginCountry(String originCountry) { + this.originCountry = originCountry; + } + + public String getQuotationReference() { + return quotationReference; + } + + public void setQuotationReference(String quotationReference) { + this.quotationReference = quotationReference; + } + + public String getQuoteId() { + return quoteId; + } + + public void setQuoteId(String quoteId) { + this.quoteId = quoteId; + } + + public String getReceivingCountry() { + return receivingCountry; + } + + public void setReceivingCountry(String receivingCountry) { + this.receivingCountry = receivingCountry; + } + + public String getRemittancePurpose() { + return remittancePurpose; + } + + public void setRemittancePurpose(String remittancePurpose) { + this.remittancePurpose = remittancePurpose; + } + + public String getRelationshipSender() { + return relationshipSender; + } + + public void setRelationshipSender(String relationshipSender) { + this.relationshipSender = relationshipSender; + } + + public String getDeliveryMethod() { + return deliveryMethod; + } + + public void setDeliveryMethod(String deliveryMethod) { + this.deliveryMethod = deliveryMethod; + } + + public String getSenderBlockingReason() { + return senderBlockingReason; + } + + public void setSenderBlockingReason(String senderBlockingReason) { + this.senderBlockingReason = senderBlockingReason; + } + + public String getRecipientBlockingReason() { + return recipientBlockingReason; + } + + public void setRecipientBlockingReason(String recipientBlockingReason) { + this.recipientBlockingReason = recipientBlockingReason; + } + + public String getReceivingCurrency() { + return receivingCurrency; + } + + public void setReceivingCurrency(String receivingCurrency) { + this.receivingCurrency = receivingCurrency; + } + + public String getSenderCurrency() { + return senderCurrency; + } + + public void setSenderCurrency(String senderCurrency) { + this.senderCurrency = senderCurrency; + } + + public String getCurrencyPair() { + return currencyPair; + } + + public void setCurrencyPair(String currencyPair) { + this.currencyPair = currencyPair; + } + + public String getCurrencyPairRate() { + return currencyPairRate; + } + + public void setCurrencyPairRate(String currencyPairRate) { + this.currencyPairRate = currencyPairRate; + } + + public String getReceivingAmount() { + return receivingAmount; + } + + public void setReceivingAmount(String receivingAmount) { + this.receivingAmount = receivingAmount; + } +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/gsma/dto/Kyc.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/gsma/dto/Kyc.java new file mode 100644 index 000000000..349590b15 --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/gsma/dto/Kyc.java @@ -0,0 +1,162 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla + * Public License, v. 2.0. If a copy of the MPL was not distributed + * with this file, You can obtain one at + * + * https://mozilla.org/MPL/2.0/. + */ + +/** +@Author Sidhant Gupta +*/ +package org.mifos.connector.common.gsma.dto; + +/* +"senderKyc": { + "nationality": "AD", + "dateOfBirth": "string", + "occupation": "string", + "employerName": "string", + "contactPhone": "string", + "gender": "m", + "idDocument": [ + { + "idType": "passport", + "idNumber": "string", + "issueDate": "string", + "expiryDate": "string", + "issuer": "string", + "issuerPlace": "string", + "issuerCountry": "AD", + "otherIdDescription": "string" + } + ], + "postalAddress": { + "addressLine1": "string", + "addressLine2": "string", + "addressLine3": "string", + "city": "string", + "stateProvince": "string", + "postalCode": "string", + "country": "AD" + }, + "subjectName": { + "title": "string", + "firstName": "string", + "middleName": "string", + "lastName": "string", + "fullName": "string", + "nativeName": "string" + }, + "emailAddress": "string", + "birthCountry": "AD" + } + */ + +public class Kyc { + + String nationality; + String dateOfBirth; + String occupation; + String employerName; + String contactPhone; + char gender; + + IdDocument[] idDocument; + + PostalAddress postalAddress; + + SubjectName subjectName; + + String emailAddress; + String birthCountry; + + public String getNationality() { + return nationality; + } + + public void setNationality(String nationality) { + this.nationality = nationality; + } + + public String getDateOfBirth() { + return dateOfBirth; + } + + public void setDateOfBirth(String dateOfBirth) { + this.dateOfBirth = dateOfBirth; + } + + public String getOccupation() { + return occupation; + } + + public void setOccupation(String occupation) { + this.occupation = occupation; + } + + public String getEmployerName() { + return employerName; + } + + public void setEmployerName(String employerName) { + this.employerName = employerName; + } + + public String getContactPhone() { + return contactPhone; + } + + public void setContactPhone(String contactPhone) { + this.contactPhone = contactPhone; + } + + public char getGender() { + return gender; + } + + public void setGender(char gender) { + this.gender = gender; + } + + public IdDocument[] getIdDocument() { + return idDocument; + } + + public void setIdDocument(IdDocument[] idDocument) { + this.idDocument = idDocument; + } + + public PostalAddress getPostalAddress() { + return postalAddress; + } + + public void setPostalAddress(PostalAddress postalAddress) { + this.postalAddress = postalAddress; + } + + public SubjectName getSubjectName() { + return subjectName; + } + + public void setSubjectName(SubjectName subjectName) { + this.subjectName = subjectName; + } + + public String getEmailAddress() { + return emailAddress; + } + + public void setEmailAddress(String emailAddress) { + this.emailAddress = emailAddress; + } + + public String getBirthCountry() { + return birthCountry; + } + + public void setBirthCountry(String birthCountry) { + this.birthCountry = birthCountry; + } + +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/gsma/dto/LinksDTO.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/gsma/dto/LinksDTO.java new file mode 100644 index 000000000..b8335c5c0 --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/gsma/dto/LinksDTO.java @@ -0,0 +1,42 @@ +package org.mifos.connector.common.gsma.dto; + +public class LinksDTO { + + private String linkReference; + private GsmaParty[] sourceAccountIdentifiers; + private String status; + private String mode; + + public String getLinkReference() { + return linkReference; + } + + public void setLinkReference(String linkReference) { + this.linkReference = linkReference; + } + + public GsmaParty[] getSourceAccountIdentifiers() { + return sourceAccountIdentifiers; + } + + public void setSourceAccountIdentifiers(GsmaParty[] sourceAccountIdentifiers) { + this.sourceAccountIdentifiers = sourceAccountIdentifiers; + } + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } + + public String getMode() { + return mode; + } + + public void setMode(String mode) { + this.mode = mode; + } + +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/gsma/dto/Name.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/gsma/dto/Name.java new file mode 100644 index 000000000..73933f721 --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/gsma/dto/Name.java @@ -0,0 +1,65 @@ +package org.mifos.connector.common.gsma.dto; + +public class Name { + + private String title; + private String firstName; + private String middleName; + private String lastName; + private String fullName; + private String nativeName; + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getFirstName() { + return firstName; + } + + public void setFirstName(String firstName) { + this.firstName = firstName; + } + + public String getMiddleName() { + return middleName; + } + + public void setMiddleName(String middleName) { + this.middleName = middleName; + } + + public String getLastName() { + return lastName; + } + + public void setLastName(String lastName) { + this.lastName = lastName; + } + + public String getFullName() { + return fullName; + } + + public void setFullName(String fullName) { + this.fullName = fullName; + } + + public String getNativeName() { + return nativeName; + } + + public void setNativeName(String nativeName) { + this.nativeName = nativeName; + } + + @Override + public String toString() { + return "Name{" + "title='" + title + '\'' + ", firstName='" + firstName + '\'' + ", middleName='" + middleName + '\'' + + ", lastName='" + lastName + '\'' + ", fullName='" + fullName + '\'' + ", nativeName='" + nativeName + '\'' + '}'; + } +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/gsma/dto/Party.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/gsma/dto/Party.java new file mode 100644 index 000000000..6e2e9d2ae --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/gsma/dto/Party.java @@ -0,0 +1,16 @@ +package org.mifos.connector.common.gsma.dto; + +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import lombok.ToString; + +@Getter +@Setter +@ToString +@NoArgsConstructor +public class Party { + + public String partyIdType; + public String partyIdIdentifier; +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/gsma/dto/PostalAddress.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/gsma/dto/PostalAddress.java new file mode 100644 index 000000000..91f06ba41 --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/gsma/dto/PostalAddress.java @@ -0,0 +1,91 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla + * Public License, v. 2.0. If a copy of the MPL was not distributed + * with this file, You can obtain one at + * + * https://mozilla.org/MPL/2.0/. + */ + +/** +@Author Sidhant Gupta +*/ +package org.mifos.connector.common.gsma.dto; + +/* +"postalAddress": { + "addressLine1": "string", + "addressLine2": "string", + "addressLine3": "string", + "city": "string", + "stateProvince": "string", + "postalCode": "string", + "country": "AD" +} +*/ + +public class PostalAddress { + + String addressLine1; + String addressLine2; + String addressLine3; + String city; + String stateProvince; + String postalCode; + String country; + + public String getAddressLine1() { + return addressLine1; + } + + public void setAddressLine1(String addressLine1) { + this.addressLine1 = addressLine1; + } + + public String getAddressLine2() { + return addressLine2; + } + + public void setAddressLine2(String addressLine2) { + this.addressLine2 = addressLine2; + } + + public String getAddressLine3() { + return addressLine3; + } + + public void setAddressLine3(String addressLine3) { + this.addressLine3 = addressLine3; + } + + public String getCity() { + return city; + } + + public void setCity(String city) { + this.city = city; + } + + public String getStateProvince() { + return stateProvince; + } + + public void setStateProvince(String stateProvince) { + this.stateProvince = stateProvince; + } + + public String getPostalCode() { + return postalCode; + } + + public void setPostalCode(String postalCode) { + this.postalCode = postalCode; + } + + public String getCountry() { + return country; + } + + public void setCountry(String country) { + this.country = country; + } +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/gsma/dto/Quote.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/gsma/dto/Quote.java new file mode 100644 index 000000000..267cca07d --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/gsma/dto/Quote.java @@ -0,0 +1,95 @@ +package org.mifos.connector.common.gsma.dto; + +public class Quote { + + private String quoteId; + private String quoteExpiryTime; + private String receivingServiceProvider; + private String sendingAmount; + private String sendingCurrency; + private String receivingAmount; + private String receivingCurrency; + private String fxRate; + private String deliveryMethod; + private Fee[] fees; + + public String getQuoteId() { + return quoteId; + } + + public void setQuoteId(String quoteId) { + this.quoteId = quoteId; + } + + public String getQuoteExpiryTime() { + return quoteExpiryTime; + } + + public void setQuoteExpiryTime(String quoteExpiryTime) { + this.quoteExpiryTime = quoteExpiryTime; + } + + public String getReceivingServiceProvider() { + return receivingServiceProvider; + } + + public void setReceivingServiceProvider(String receivingServiceProvider) { + this.receivingServiceProvider = receivingServiceProvider; + } + + public String getSendingAmount() { + return sendingAmount; + } + + public void setSendingAmount(String sendingAmount) { + this.sendingAmount = sendingAmount; + } + + public String getSendingCurrency() { + return sendingCurrency; + } + + public void setSendingCurrency(String sendingCurrency) { + this.sendingCurrency = sendingCurrency; + } + + public String getReceivingAmount() { + return receivingAmount; + } + + public void setReceivingAmount(String receivingAmount) { + this.receivingAmount = receivingAmount; + } + + public String getReceivingCurrency() { + return receivingCurrency; + } + + public void setReceivingCurrency(String receivingCurrency) { + this.receivingCurrency = receivingCurrency; + } + + public String getFxRate() { + return fxRate; + } + + public void setFxRate(String fxRate) { + this.fxRate = fxRate; + } + + public String getDeliveryMethod() { + return deliveryMethod; + } + + public void setDeliveryMethod(String deliveryMethod) { + this.deliveryMethod = deliveryMethod; + } + + public Fee[] getFees() { + return fees; + } + + public void setFees(Fee[] fees) { + this.fees = fees; + } +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/gsma/dto/QuotesDTO.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/gsma/dto/QuotesDTO.java new file mode 100644 index 000000000..f8d996c47 --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/gsma/dto/QuotesDTO.java @@ -0,0 +1,194 @@ +package org.mifos.connector.common.gsma.dto; + +public class QuotesDTO { + + private String requestDate; + private GsmaParty[] debitParty; + private GsmaParty[] creditParty; + private Kyc senderKyc; + private Kyc recipientKyc; + private String requestAmount; + private String requestCurrency; + private String type; + private String subType; + private String chosenDeliveryMethod; + private Quote[] quotes; + private String senderBlockingReason; + private String recipientBlockingReason; + private GsmaParty[] metadata; + private String quotationReference; + private String quotationStatus; + private String creationDate; + private String modificationDate; + private String dateCreated; + private String dateModified; + private String availableDeliveryMethod; + + public String getRequestDate() { + return requestDate; + } + + public void setRequestDate(String requestDate) { + this.requestDate = requestDate; + } + + public GsmaParty[] getDebitParty() { + return debitParty; + } + + public void setDebitParty(GsmaParty[] debitParty) { + this.debitParty = debitParty; + } + + public GsmaParty[] getCreditParty() { + return creditParty; + } + + public void setCreditParty(GsmaParty[] creditParty) { + this.creditParty = creditParty; + } + + public Kyc getSenderKyc() { + return senderKyc; + } + + public void setSenderKyc(Kyc senderKyc) { + this.senderKyc = senderKyc; + } + + public Kyc getRecipientKyc() { + return recipientKyc; + } + + public void setRecipientKyc(Kyc recipientKyc) { + this.recipientKyc = recipientKyc; + } + + public String getRequestAmount() { + return requestAmount; + } + + public void setRequestAmount(String requestAmount) { + this.requestAmount = requestAmount; + } + + public String getRequestCurrency() { + return requestCurrency; + } + + public void setRequestCurrency(String requestCurrency) { + this.requestCurrency = requestCurrency; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public String getSubType() { + return subType; + } + + public void setSubType(String subType) { + this.subType = subType; + } + + public String getChosenDeliveryMethod() { + return chosenDeliveryMethod; + } + + public void setChosenDeliveryMethod(String chosenDeliveryMethod) { + this.chosenDeliveryMethod = chosenDeliveryMethod; + } + + public Quote[] getQuotes() { + return quotes; + } + + public void setQuotes(Quote[] quotes) { + this.quotes = quotes; + } + + public String getSenderBlockingReason() { + return senderBlockingReason; + } + + public void setSenderBlockingReason(String senderBlockingReason) { + this.senderBlockingReason = senderBlockingReason; + } + + public String getRecipientBlockingReason() { + return recipientBlockingReason; + } + + public void setRecipientBlockingReason(String recipientBlockingReason) { + this.recipientBlockingReason = recipientBlockingReason; + } + + public GsmaParty[] getMetadata() { + return metadata; + } + + public void setMetadata(GsmaParty[] metadata) { + this.metadata = metadata; + } + + public String getQuotationReference() { + return quotationReference; + } + + public void setQuotationReference(String quotationReference) { + this.quotationReference = quotationReference; + } + + public String getQuotationStatus() { + return quotationStatus; + } + + public void setQuotationStatus(String quotationStatus) { + this.quotationStatus = quotationStatus; + } + + public String getCreationDate() { + return creationDate; + } + + public void setCreationDate(String creationDate) { + this.creationDate = creationDate; + } + + public String getModificationDate() { + return modificationDate; + } + + public void setModificationDate(String modificationDate) { + this.modificationDate = modificationDate; + } + + public String getDateCreated() { + return dateCreated; + } + + public void setDateCreated(String dateCreated) { + this.dateCreated = dateCreated; + } + + public String getDateModified() { + return dateModified; + } + + public void setDateModified(String dateModified) { + this.dateModified = dateModified; + } + + public String getAvailableDeliveryMethod() { + return availableDeliveryMethod; + } + + public void setAvailableDeliveryMethod(String availableDeliveryMethod) { + this.availableDeliveryMethod = availableDeliveryMethod; + } +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/gsma/dto/RedemptionChannel.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/gsma/dto/RedemptionChannel.java new file mode 100644 index 000000000..f936fa050 --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/gsma/dto/RedemptionChannel.java @@ -0,0 +1,6 @@ +package org.mifos.connector.common.gsma.dto; + +public class RedemptionChannel { + + private String channelType; +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/gsma/dto/RedemptionTransactionType.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/gsma/dto/RedemptionTransactionType.java new file mode 100644 index 000000000..d0c15153c --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/gsma/dto/RedemptionTransactionType.java @@ -0,0 +1,23 @@ +package org.mifos.connector.common.gsma.dto; + +public class RedemptionTransactionType { + + private String transactionType; + private String transactionSubtype; + + public String getTransactionType() { + return transactionType; + } + + public void setTransactionType(String transactionType) { + this.transactionType = transactionType; + } + + public String getTransactionSubtype() { + return transactionSubtype; + } + + public void setTransactionSubtype(String transactionSubtype) { + this.transactionSubtype = transactionSubtype; + } +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/gsma/dto/RequestStateDTO.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/gsma/dto/RequestStateDTO.java new file mode 100644 index 000000000..fd3350381 --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/gsma/dto/RequestStateDTO.java @@ -0,0 +1,84 @@ +package org.mifos.connector.common.gsma.dto; + +public class RequestStateDTO { + + private String notificationMethod; + private String serverCorrelationId; + private String status; + private String pendingReason; + private String objectReference; + private String expiryTime; + private String pollLimit; + private ErrorDTO error; + + public String getNotificationMethod() { + return notificationMethod; + } + + public void setNotificationMethod(String notificationMethod) { + this.notificationMethod = notificationMethod; + } + + public String getServerCorrelationId() { + return serverCorrelationId; + } + + public void setServerCorrelationId(String serverCorrelationId) { + this.serverCorrelationId = serverCorrelationId; + } + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } + + public String getPendingReason() { + return pendingReason; + } + + public void setPendingReason(String pendingReason) { + this.pendingReason = pendingReason; + } + + public String getObjectReference() { + return objectReference; + } + + public void setObjectReference(String objectReference) { + this.objectReference = objectReference; + } + + public String getExpiryTime() { + return expiryTime; + } + + public void setExpiryTime(String expiryTime) { + this.expiryTime = expiryTime; + } + + public String getPollLimit() { + return pollLimit; + } + + public void setPollLimit(String pollLimit) { + this.pollLimit = pollLimit; + } + + public ErrorDTO getError() { + return error; + } + + public void setError(ErrorDTO error) { + this.error = error; + } + + @Override + public String toString() { + return "RequestStateDTO{" + "notificationMethod='" + notificationMethod + '\'' + ", serverCorrelationId='" + serverCorrelationId + + '\'' + ", status='" + status + '\'' + ", pendingReason='" + pendingReason + '\'' + ", objectReference='" + objectReference + + '\'' + ", expiryTime='" + expiryTime + '\'' + ", pollLimit='" + pollLimit + '\'' + ", error=" + error + '}'; + } +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/gsma/dto/ResponseLinkDTO.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/gsma/dto/ResponseLinkDTO.java new file mode 100644 index 000000000..7cc61fd43 --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/gsma/dto/ResponseLinkDTO.java @@ -0,0 +1,15 @@ +package org.mifos.connector.common.gsma.dto; + +public class ResponseLinkDTO { + + String link; + + public String getLink() { + return link; + } + + public void setLink(String link) { + this.link = link; + } + +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/gsma/dto/SubjectName.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/gsma/dto/SubjectName.java new file mode 100644 index 000000000..ff7ce3a0c --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/gsma/dto/SubjectName.java @@ -0,0 +1,72 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla + * Public License, v. 2.0. If a copy of the MPL was not distributed + * with this file, You can obtain one at + * + * https://mozilla.org/MPL/2.0/. + */ + +/** +@Author Sidhant Gupta +*/ +package org.mifos.connector.common.gsma.dto; + +/* +"subjectName": { + "title": "string", + "firstName": "string", + "middleName": "string", + "lastName": "string", + "fullName": "string", + "nativeName": "string" + } +*/ + +public class SubjectName { + + String title; + String firstName; + String middleName; + String lastName; + String nativeName; + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getFirstName() { + return firstName; + } + + public void setFirstName(String firstName) { + this.firstName = firstName; + } + + public String getMiddleName() { + return middleName; + } + + public void setMiddleName(String middleName) { + this.middleName = middleName; + } + + public String getLastName() { + return lastName; + } + + public void setLastName(String lastName) { + this.lastName = lastName; + } + + public String getNativeName() { + return nativeName; + } + + public void setNativeName(String nativeName) { + this.nativeName = nativeName; + } +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/gsma/dto/SupplementaryBillReferenceDetail.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/gsma/dto/SupplementaryBillReferenceDetail.java new file mode 100644 index 000000000..0ceac6475 --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/gsma/dto/SupplementaryBillReferenceDetail.java @@ -0,0 +1,23 @@ +package org.mifos.connector.common.gsma.dto; + +public class SupplementaryBillReferenceDetail { + + private String paymentReferenceType; + private String paymentReferenceValue; + + public String getPaymentReferenceType() { + return paymentReferenceType; + } + + public void setPaymentReferenceType(String paymentReferenceType) { + this.paymentReferenceType = paymentReferenceType; + } + + public String getPaymentReferenceValue() { + return paymentReferenceValue; + } + + public void setPaymentReferenceValue(String paymentReferenceValue) { + this.paymentReferenceValue = paymentReferenceValue; + } +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/identityaccountmapper/dto/AccountLookupResponseDTO.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/identityaccountmapper/dto/AccountLookupResponseDTO.java new file mode 100644 index 000000000..b03bfaec7 --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/identityaccountmapper/dto/AccountLookupResponseDTO.java @@ -0,0 +1,31 @@ +package org.mifos.connector.common.identityaccountmapper.dto; + +import java.util.List; + +public class AccountLookupResponseDTO { + + private String payeeIdentity; + private List paymentModalityList; + + public AccountLookupResponseDTO(String payeeIdentity, List paymentModalityList) { + this.payeeIdentity = payeeIdentity; + this.paymentModalityList = paymentModalityList; + } + + public String getPayeeIdentity() { + return payeeIdentity; + } + + public void setPayeeIdentity(String payeeIdentity) { + this.payeeIdentity = payeeIdentity; + } + + public List getPaymentModalityList() { + return paymentModalityList; + } + + public void setPaymentModalityList(List paymentModalityList) { + this.paymentModalityList = paymentModalityList; + } + +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/identityaccountmapper/dto/AccountMapperRequestDTO.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/identityaccountmapper/dto/AccountMapperRequestDTO.java new file mode 100644 index 000000000..da46a8473 --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/identityaccountmapper/dto/AccountMapperRequestDTO.java @@ -0,0 +1,40 @@ +package org.mifos.connector.common.identityaccountmapper.dto; + +import java.util.List; + +public class AccountMapperRequestDTO { + + private String requestID; + private String sourceBBID; + private List beneficiaries; + + public AccountMapperRequestDTO(String requestID, String sourceBBID, List beneficiaries) { + this.requestID = requestID; + this.sourceBBID = sourceBBID; + this.beneficiaries = beneficiaries; + } + + public String getRequestID() { + return requestID; + } + + public void setRequestID(String requestID) { + this.requestID = requestID; + } + + public String getSourceBBID() { + return sourceBBID; + } + + public void setSourceBBID(String sourceBBID) { + this.sourceBBID = sourceBBID; + } + + public List getBeneficiaries() { + return beneficiaries; + } + + public void setBeneficiaries(List beneficiaries) { + this.beneficiaries = beneficiaries; + } +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/identityaccountmapper/dto/BeneficiaryDTO.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/identityaccountmapper/dto/BeneficiaryDTO.java new file mode 100644 index 000000000..d59b16001 --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/identityaccountmapper/dto/BeneficiaryDTO.java @@ -0,0 +1,49 @@ +package org.mifos.connector.common.identityaccountmapper.dto; + +public class BeneficiaryDTO { + + private String payeeIdentity; + private String paymentModality; + private String financialAddress; + private String bankingInstitutionCode; + + public BeneficiaryDTO(String payeeIdentity, String paymentModality, String financialAddress, String bankingInstitutionCode) { + this.payeeIdentity = payeeIdentity; + this.paymentModality = paymentModality; + this.financialAddress = financialAddress; + this.bankingInstitutionCode = bankingInstitutionCode; + } + + public String getBankingInstitutionCode() { + return bankingInstitutionCode; + } + + public void setBankingInstitutionCode(String bankingInstitutionCode) { + this.bankingInstitutionCode = bankingInstitutionCode; + } + + public String getPayeeIdentity() { + return payeeIdentity; + } + + public void setPayeeIdentity(String payeeIdentity) { + this.payeeIdentity = payeeIdentity; + } + + public String getPaymentModality() { + return paymentModality; + } + + public void setPaymentModality(String paymentModality) { + this.paymentModality = paymentModality; + } + + public String getFinancialAddress() { + return financialAddress; + } + + public void setFinancialAddress(String financialAddress) { + this.financialAddress = financialAddress; + } + +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/identityaccountmapper/dto/CallbackDTO.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/identityaccountmapper/dto/CallbackDTO.java new file mode 100644 index 000000000..3acc09a5a --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/identityaccountmapper/dto/CallbackDTO.java @@ -0,0 +1,50 @@ +package org.mifos.connector.common.identityaccountmapper.dto; + +import java.util.List; + +public class CallbackDTO { + + private String requestID; + private String registerRequestID; + private int numberFailedCases; + private List failedCases; + + public CallbackDTO(String requestID, String registerRequestID, int numberFailedCases, List failedCases) { + this.requestID = requestID; + this.registerRequestID = registerRequestID; + this.numberFailedCases = numberFailedCases; + this.failedCases = failedCases; + } + + public String getRequestID() { + return requestID; + } + + public void setRequestID(String requestID) { + this.requestID = requestID; + } + + public String getRegisterRequestID() { + return registerRequestID; + } + + public void setRegisterRequestID(String registerRequestID) { + this.registerRequestID = registerRequestID; + } + + public int getNumberFailedCases() { + return numberFailedCases; + } + + public void setNumberFailedCases(int numberFailedCases) { + this.numberFailedCases = numberFailedCases; + } + + public List getFailedCases() { + return failedCases; + } + + public void setFailedCases(List failedCases) { + this.failedCases = failedCases; + } +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/identityaccountmapper/dto/FailedCaseDTO.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/identityaccountmapper/dto/FailedCaseDTO.java new file mode 100644 index 000000000..816275f42 --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/identityaccountmapper/dto/FailedCaseDTO.java @@ -0,0 +1,38 @@ +package org.mifos.connector.common.identityaccountmapper.dto; + +public class FailedCaseDTO { + + private String payeeIdentity; + private String paymentModality; + private String failureReason; + + public FailedCaseDTO(String payeeIdentity, String paymentModality, String failureReason) { + this.payeeIdentity = payeeIdentity; + this.paymentModality = paymentModality; + this.failureReason = failureReason; + } + + public String getPayeeIdentity() { + return payeeIdentity; + } + + public void setPayeeIdentity(String payeeIdentity) { + this.payeeIdentity = payeeIdentity; + } + + public String getPaymentModality() { + return paymentModality; + } + + public void setPaymentModality(String paymentModality) { + this.paymentModality = paymentModality; + } + + public String getFailureReason() { + return failureReason; + } + + public void setFailureReason(String failureReason) { + this.failureReason = failureReason; + } +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/identityaccountmapper/dto/PaymentModalityDTO.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/identityaccountmapper/dto/PaymentModalityDTO.java new file mode 100644 index 000000000..430ad15b9 --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/identityaccountmapper/dto/PaymentModalityDTO.java @@ -0,0 +1,38 @@ +package org.mifos.connector.common.identityaccountmapper.dto; + +public class PaymentModalityDTO { + + private String paymentModality; + private String financialAddress; + private String bankingInstitutionCode; + + public PaymentModalityDTO(String paymentModality, String financialAddress, String bankingInstitutionCode) { + this.paymentModality = paymentModality; + this.financialAddress = financialAddress; + this.bankingInstitutionCode = bankingInstitutionCode; + } + + public String getPaymentModality() { + return paymentModality; + } + + public void setPaymentModality(String paymentModality) { + this.paymentModality = paymentModality; + } + + public String getFinancialAddress() { + return financialAddress; + } + + public void setFinancialAddress(String financialAddress) { + this.financialAddress = financialAddress; + } + + public String getBankingInstitutionCode() { + return bankingInstitutionCode; + } + + public void setBankingInstitutionCode(String bankingInstitutionCode) { + this.bankingInstitutionCode = bankingInstitutionCode; + } +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/interceptor/JWSFilterStrategy.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/interceptor/JWSFilterStrategy.java new file mode 100644 index 000000000..4824872cd --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/interceptor/JWSFilterStrategy.java @@ -0,0 +1,62 @@ +package org.mifos.connector.common.interceptor; + +import java.io.IOException; +import java.util.List; +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletResponse; +import lombok.extern.slf4j.Slf4j; +import org.mifos.connector.common.interceptor.service.JsonWebSignatureService; +import org.mifos.connector.common.util.Constant; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; +import org.springframework.stereotype.Component; +import org.springframework.web.filter.GenericFilterBean; +import org.springframework.web.util.ContentCachingResponseWrapper; + +@Component +@ConditionalOnExpression("${security.jws.enable} and ${security.jws.response.enable}") +@Slf4j +public class JWSFilterStrategy extends GenericFilterBean { + + @Value("#{'${jws.header.order}'.split(',')}") + private List headerOrder; + + @Autowired + private JsonWebSignatureService jsonWebSignatureService; + + @Override + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { + log.debug("Started doFilter"); + + HttpServletResponse httpResponse = (HttpServletResponse) response; + ContentCachingResponseWrapper wrappedResponse = new ContentCachingResponseWrapper(httpResponse); + chain.doFilter(request, wrappedResponse); + + byte[] responseBytes = wrappedResponse.getContentAsByteArray(); + String responseBody = new String(responseBytes, httpResponse.getCharacterEncoding()); + + String tenant = httpResponse.getHeader(Constant.HEADER_PLATFORM_TENANT_ID); + log.debug("Platform-TenantId: {}", tenant); + try { + log.debug("Fetching data to be hashed from doFilter"); + String dataToBeHashed = JWSUtil.getDataToBeHashed(httpResponse, responseBody, headerOrder); + String signature = jsonWebSignatureService.signForTenant(dataToBeHashed, tenant); + + wrappedResponse.setHeader(Constant.HEADER_JWS, signature); + log.debug("Response str: {}", responseBody); + log.debug("Out data: {}", dataToBeHashed); + log.debug("Signature: {}", signature); + } catch (Exception e) { + log.debug("{}", e.getMessage()); + log.error("Error while creating signature(SERVER TO CLIENT) stacktrace: {}", e.getMessage()); + } finally { + wrappedResponse.copyBodyToResponse(); + } + log.debug("Ended doFilter"); + } + +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/interceptor/JWSUtil.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/interceptor/JWSUtil.java new file mode 100644 index 000000000..13f9b6292 --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/interceptor/JWSUtil.java @@ -0,0 +1,238 @@ +package org.mifos.connector.common.interceptor; + +import com.fasterxml.jackson.annotation.JsonAutoDetect; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.nio.charset.Charset; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.io.IOUtils; +import org.mifos.connector.common.channel.dto.PhErrorDTO; +import org.mifos.connector.common.exception.PaymentHubErrorCategory; +import org.mifos.connector.common.util.Constant; +import org.springframework.http.HttpMethod; +import static org.springframework.http.HttpHeaders.CONTENT_TYPE; + +@Slf4j +public final class JWSUtil { + + private JWSUtil() {} + + /** + * Takes necessary information and formats it in a specific order, this is the format which is to be used while + * verifying the JWS. The order of header is added as a configuration, refer to jws.header.order in + * application-jws.yaml. + * + * @param request + * request object passed to the controller + * @param payload + * can be raw/json body or the form data + * @param headerOrder + * list of headers in specific order from configuration + * @return data which is to be verified in particular format + */ + public static String getDataToBeHashed(HttpServletRequest request, String payload, List headerOrder) { + HashMap headers = new HashMap<>(); + Enumeration headersEnumeration = request.getHeaderNames(); + while (headersEnumeration.hasMoreElements()) { + String headerKey = headersEnumeration.nextElement().toUpperCase(); + headers.put(headerKey, request.getHeader(headerKey)); + } + log.debug("Headers: {}", headers); + return getDataToBeHashed(headers, payload, headerOrder); + } + + /** + * Takes necessary information and formats it in a specific order, this is the format which is to be used while + * verifying the JWS. The order of header is added as a configuration, refer to jws.header.order in + * application-jws.yaml. + * + * @param response + * response object + * @param payload + * can be raw/json body or the form data + * @param headerOrder + * list of headers in specific order from configuration + * @return data which is to be verified in particular format + */ + public static String getDataToBeHashed(HttpServletResponse response, String payload, List headerOrder) { + HashMap headers = new HashMap<>(); + for (String headerKey : response.getHeaderNames()) { + headers.put(headerKey, response.getHeader(headerKey)); + } + return getDataToBeHashed(headers, payload, headerOrder); + } + + /** + * Takes necessary information and formats it in a specific order, this is the format which is to be used while + * verifying the JWS. The order of header is added as a configuration, refer to jws.header.order in + * application-jws.yaml. + * + * @param header + * hashmap of header, with all the header in capital case + * @param payload + * can be raw/json body or the form data + * @param headerOrder + * list of headers in specific order from configuration + * @return data which is to be verified in particular format + */ + public static String getDataToBeHashed(Map header, String payload, List headerOrder) { + StringBuilder dataBuilder = new StringBuilder(); + for (String headerKey : headerOrder) { + String headerValue = (String) header.get(headerKey.toUpperCase()); + log.debug("Header: {} : {}", headerKey, headerValue); + if (headerValue != null) { + dataBuilder.append(headerValue).append(Constant.REST_REQUEST_DATA_SEPARATOR); + } + } + if (payload != null && !payload.isEmpty()) { + dataBuilder.append(payload); + } else { + // remove the last added [Constant.REST_REQUEST_DATA_SEPARATOR] + dataBuilder.deleteCharAt(dataBuilder.length() - 1); + } + return dataBuilder.toString(); + } + + /** + * Writes the response to the output stream, used for returning the error response in case of JWS verification + * failure + * + * @param response + * instance of [HttpServletResponse] + * @param errorDTO + * error object containing valid PH-EE error + * @see PhErrorDTO + */ + public static void writeErrorResponse(HttpServletResponse response, PhErrorDTO errorDTO) { + if (errorDTO.getErrorCategory().equals(PaymentHubErrorCategory.System.name())) { + response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); + } else { + response.setStatus(HttpServletResponse.SC_BAD_REQUEST); + } + try { + response.setHeader(CONTENT_TYPE, "application/json"); + response.getWriter().write(getObjectMapper().writeValueAsString(errorDTO)); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + /** + * Created the data which is to be validated against the JWS passed + * + * @param request + * request object passed to the controller + * @return data for verification in form of string + * @throws IOException + * throws as part of input stream + */ + public static String parseBodyPayload(HttpServletRequest request) throws IOException { + log.debug("Content-type: {}", request.getHeader(CONTENT_TYPE)); + String data = null; + String body = IOUtils.toString(request.getInputStream(), Charset.defaultCharset()); + if (isMultipartRequest(request) && + !request.getMethod().equals(HttpMethod.GET.name())) { + // parse form data only if body is empty and REQUEST TYPE is not GET + data = parseFormData(request); + } else { + data = body; + } + log.debug("Parsed data: {}", data); + return data; + } + + // parses the boundary value form the content type + // works if content type is of below kind + // 'multipart/form-data; boundary=--------------------------188270859567880981670528' + public static String parseBoundaryValueFromContentTypeValue(String contentType) { + String[] contentTypeArray = contentType.split("boundary="); + if (contentTypeArray.length < 2) { + return ""; + } + String boundary = contentTypeArray[1].strip(); + int pos = boundary.indexOf(';'); + return pos == -1 ? boundary : boundary.substring(0,pos).strip(); + } + + /** + * Use to parse the string data from the multipart data passed in api + * + * @param request + * request object passed to the controller + * @return multipart data in form of string + * @throws IOException + */ + public static String parseFormData(HttpServletRequest request) throws IOException { + log.debug("Parsing form data"); + String contentTypeHeaderValue = request.getHeader(CONTENT_TYPE); + String boundary = parseBoundaryValueFromContentTypeValue(contentTypeHeaderValue); + return parseFormData(request.getInputStream(), boundary); + } + + /** + * Use to parse the multipart/form-data from the input stream + * + * @param inputStream + * @param boundary the boundary can be parsed from CONTENT-TYPE header in + * API request header + * @return parsed data in the form of String + * @throws IOException + */ + public static String parseFormData(InputStream inputStream, String boundary) throws IOException { + log.debug("inside MultipartParser"); + BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream)); + StringBuilder partContent = new StringBuilder(); + String line; + while ((line = reader.readLine()) != null) { + if (line.contains(boundary)) { + // Read and process the part headers + while ((line = reader.readLine()) != null && !line.isEmpty()) { + // Process part headers if needed + } + + // Read and process the part content + while ((line = reader.readLine()) != null && !line.equals(boundary) + && !line.contains(boundary) && !line.equals("\n") && !line.isEmpty()) { + partContent.append(line); + partContent.append("\n"); + } + } + } + return partContent.toString().trim(); + } + + // returns true if the request is of multipart type + public static boolean isMultipartRequest(HttpServletRequest request) { + return request.getHeader(CONTENT_TYPE).contains("multipart/form-data"); + } + + /** + * Need object mapper for serializing the error response + * + * @return instance of [ObjectMapper] + */ + public static ObjectMapper getObjectMapper() { + ObjectMapper objectMapper = new ObjectMapper(); + objectMapper.registerModule(new JavaTimeModule()); + objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false); + objectMapper.setVisibilityChecker(objectMapper.getSerializationConfig().getDefaultVisibilityChecker() + .withFieldVisibility(JsonAutoDetect.Visibility.ANY).withGetterVisibility(JsonAutoDetect.Visibility.NONE)); + return objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL) + .configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true) + .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + } + +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/interceptor/MultiReadFilter.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/interceptor/MultiReadFilter.java new file mode 100644 index 000000000..ff4e425e1 --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/interceptor/MultiReadFilter.java @@ -0,0 +1,24 @@ +package org.mifos.connector.common.interceptor; + +import lombok.extern.slf4j.Slf4j; +import org.mifos.connector.common.interceptor.helper.MultiReadHttpServletRequest; +import org.springframework.web.filter.GenericFilterBean; + +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; +import java.io.IOException; + +@Slf4j +public class MultiReadFilter extends GenericFilterBean { + + @Override + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) + throws IOException, ServletException { + log.debug("Inside caching filter"); + MultiReadHttpServletRequest multiReadRequest = new MultiReadHttpServletRequest((HttpServletRequest) request); + chain.doFilter(multiReadRequest, response); + } +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/interceptor/WebMvcConfig.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/interceptor/WebMvcConfig.java new file mode 100644 index 000000000..29df1e5f9 --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/interceptor/WebMvcConfig.java @@ -0,0 +1,55 @@ +package org.mifos.connector.common.interceptor; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.web.servlet.FilterRegistrationBean; +import org.springframework.context.annotation.Bean; +import org.springframework.core.Ordered; +import org.springframework.stereotype.Component; +import org.springframework.web.servlet.config.annotation.InterceptorRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport; + +import javax.servlet.annotation.MultipartConfig; + +@Component("JWSMvcConfig") +@Slf4j +@ConditionalOnExpression("${security.jws.enable:false}") +public class WebMvcConfig extends WebMvcConfigurationSupport { + + @Autowired + private WebSignatureInterceptor webSignatureInterceptor; + + @Autowired(required = false) + private JWSFilterStrategy jwsFilterStrategy; + + @Override + public void addInterceptors(InterceptorRegistry registry) { + log.debug("Added interceptor"); + registry.addInterceptor(webSignatureInterceptor); + super.addInterceptors(registry); + } + + @Bean + public FilterRegistrationBean cachingFilter() { + FilterRegistrationBean registrationBean = new FilterRegistrationBean(); + registrationBean.setFilter(new MultiReadFilter()); + registrationBean.addUrlPatterns("/*"); + registrationBean.setOrder(Ordered.HIGHEST_PRECEDENCE); + return registrationBean; + } + + + @Bean + @ConditionalOnProperty(prefix = "security.jws.response", name = "enable", havingValue = "true") + public FilterRegistrationBean jwsFilter() { + log.debug("Registered filter"); + FilterRegistrationBean registration = new FilterRegistrationBean(); + registration.setFilter(jwsFilterStrategy); + registration.addUrlPatterns("/*"); + registration.setOrder(Integer.MIN_VALUE + 2); + return registration; + } + +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/interceptor/WebSignatureInterceptor.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/interceptor/WebSignatureInterceptor.java new file mode 100644 index 000000000..2be46fa91 --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/interceptor/WebSignatureInterceptor.java @@ -0,0 +1,88 @@ +package org.mifos.connector.common.interceptor; + +import java.util.List; +import java.util.Set; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import lombok.Getter; +import lombok.extern.slf4j.Slf4j; +import org.mifos.connector.common.channel.dto.PhErrorDTO; +import org.mifos.connector.common.exception.PaymentHubError; +import org.mifos.connector.common.interceptor.service.JsonWebSignatureService; +import org.mifos.connector.common.util.Constant; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; +import org.springframework.web.servlet.HandlerInterceptor; + +@Component +@Slf4j +@Getter +public class WebSignatureInterceptor implements HandlerInterceptor { + + @Autowired + private JsonWebSignatureService jsonWebSignatureService; + + @Value("#{'${jws.header.order}'.split(',')}") + private List headerOrder; + + @Value("#{'${jws.exception-endpoints}'.split(',')}") + protected List exceptionEndpoints; + + @Override + public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { + // return true means forward this request and false means don;t forward this to controller + log.info("Request at interceptor"); + for (String endpoint: exceptionEndpoints) { + if (request.getRequestURL().toString().contains(endpoint)) { + log.info("This is exception endpoint, hence passing the request without JWS validation"); + return true; + } + } + log.info("URL: {}", request.getRequestURL().toString()); + if (headerOrder.size() == 0) { + throw new RuntimeException("Header is null"); + } + PhErrorDTO errorDTO = null; + + String signature = request.getHeader(Constant.HEADER_JWS); + log.debug("Signature inbound: {}", signature); + String data = null; + try { + data = JWSUtil.parseBodyPayload(request); + } catch (Exception e) { + errorDTO = new PhErrorDTO.PhErrorDTOBuilder(PaymentHubError.JWSVerificationServerError) + .developerMessage("Make sure to pass valid payload and header along with signature").build(); + JWSUtil.writeErrorResponse(response, errorDTO); + return false; + } + String dataToBeHashed = JWSUtil.getDataToBeHashed(request, data, headerOrder); + log.debug("Data to be hashed: {}", dataToBeHashed); + + String tenant = request.getHeader(Constant.HEADER_PLATFORM_TENANT_ID); + + Boolean isValidSignature = null; + try { + isValidSignature = jsonWebSignatureService.verifyForTenant(dataToBeHashed, signature, tenant); + } catch (Exception e) { + errorDTO = new PhErrorDTO.PhErrorDTOBuilder(PaymentHubError.InvalidPublicKeyConfigured) + .developerMessage("Certificate" + jsonWebSignatureService.getTenantKeysProperties().getCertificate(tenant)).build(); + JWSUtil.writeErrorResponse(response, errorDTO); + return false; + } + + if (isValidSignature) { + log.info("Signature is valid"); + } else { + log.error("JWS Signature verification failed: {}", signature); + errorDTO = new PhErrorDTO.PhErrorDTOBuilder(PaymentHubError.InvalidJsonWebSignature) + .addErrorParameter(Constant.HEADER_JWS, signature) + .developerMessage("Pass the valid header value for " + Constant.HEADER_JWS).build(); + JWSUtil.writeErrorResponse(response, errorDTO); + response.setStatus(400); + } + response.setHeader(Constant.HEADER_PLATFORM_TENANT_ID, tenant); + log.info("Request ended at interceptor"); + return isValidSignature; + } +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/interceptor/annotation/EnableJsonWebSignature.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/interceptor/annotation/EnableJsonWebSignature.java new file mode 100644 index 000000000..90369d4d2 --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/interceptor/annotation/EnableJsonWebSignature.java @@ -0,0 +1,14 @@ +package org.mifos.connector.common.interceptor.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import org.mifos.connector.common.interceptor.config.WebSignatureConfiguration; +import org.mifos.connector.common.interceptor.properties.TenantKeysProperties; +import org.springframework.context.annotation.Import; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +@Import({ WebSignatureConfiguration.class, TenantKeysProperties.class }) +public @interface EnableJsonWebSignature {} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/interceptor/config/WebSignatureConfiguration.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/interceptor/config/WebSignatureConfiguration.java new file mode 100644 index 000000000..c5b1df725 --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/interceptor/config/WebSignatureConfiguration.java @@ -0,0 +1,12 @@ +package org.mifos.connector.common.interceptor.config; + +import org.mifos.connector.common.camel.JWSRoute; +import org.mifos.connector.common.interceptor.WebSignatureInterceptor; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.PropertySource; + +@ComponentScan(basePackageClasses = { WebSignatureInterceptor.class, JWSRoute.class }) +@Configuration +@PropertySource(value = { "classpath:application-jws.yaml" }, factory = YamlPropertySourceFactory.class) +public class WebSignatureConfiguration {} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/interceptor/config/YamlPropertySourceFactory.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/interceptor/config/YamlPropertySourceFactory.java new file mode 100644 index 000000000..cc25d153a --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/interceptor/config/YamlPropertySourceFactory.java @@ -0,0 +1,21 @@ +package org.mifos.connector.common.interceptor.config; + +import java.util.Properties; +import org.springframework.beans.factory.config.YamlPropertiesFactoryBean; +import org.springframework.core.env.PropertiesPropertySource; +import org.springframework.core.env.PropertySource; +import org.springframework.core.io.support.EncodedResource; +import org.springframework.core.io.support.PropertySourceFactory; + +public class YamlPropertySourceFactory implements PropertySourceFactory { + + @Override + public PropertySource createPropertySource(String name, EncodedResource encodedResource) { + YamlPropertiesFactoryBean factory = new YamlPropertiesFactoryBean(); + factory.setResources(encodedResource.getResource()); + + Properties properties = factory.getObject(); + + return new PropertiesPropertySource(encodedResource.getResource().getFilename(), properties); + } +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/interceptor/helper/ByteArrayServletInputStream.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/interceptor/helper/ByteArrayServletInputStream.java new file mode 100644 index 000000000..91b3ddcb7 --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/interceptor/helper/ByteArrayServletInputStream.java @@ -0,0 +1,35 @@ +package org.mifos.connector.common.interceptor.helper; + +import javax.servlet.ReadListener; +import javax.servlet.ServletInputStream; +import java.io.ByteArrayInputStream; +import java.io.IOException; + +public class ByteArrayServletInputStream extends ServletInputStream { + + private final ByteArrayInputStream inputStream; + + public ByteArrayServletInputStream(byte[] bytes) { + inputStream = new ByteArrayInputStream(bytes); + } + + @Override + public int read() throws IOException { + return inputStream.read(); + } + + @Override + public boolean isFinished() { + return inputStream.available() == 0; + } + + @Override + public boolean isReady() { + return true; + } + + @Override + public void setReadListener(ReadListener readListener) { + } + +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/interceptor/helper/MultiReadHttpServletRequest.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/interceptor/helper/MultiReadHttpServletRequest.java new file mode 100644 index 000000000..938982485 --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/interceptor/helper/MultiReadHttpServletRequest.java @@ -0,0 +1,53 @@ +package org.mifos.connector.common.interceptor.helper; + +import lombok.Getter; +import lombok.Setter; +import org.springframework.util.StreamUtils; + +import javax.servlet.ServletException; +import javax.servlet.ServletInputStream; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletRequestWrapper; +import javax.servlet.http.Part; +import java.io.BufferedReader; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStreamReader; +import java.util.Collection; + +public class MultiReadHttpServletRequest extends HttpServletRequestWrapper { + + private byte[] body; + + /** + * Creates a ServletRequest adaptor wrapping the given request object. + * + * @param request + * @throws IllegalArgumentException if the request is null + */ + public MultiReadHttpServletRequest(HttpServletRequest request) { + super(request); + try { + body = StreamUtils.copyToByteArray(request.getInputStream()); + }catch (IOException e) { + throw new RuntimeException(e); + } + } + + @Override + public ServletInputStream getInputStream() throws IOException { + return new ByteArrayServletInputStream(body); + } + + @Override + public BufferedReader getReader() throws IOException { + ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(this.body); + return new BufferedReader(new InputStreamReader(byteArrayInputStream)); + } + + @Override + public Collection getParts() throws IOException, ServletException { + return ((HttpServletRequest) getRequest()).getParts(); + } + +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/interceptor/properties/TenantKeys.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/interceptor/properties/TenantKeys.java new file mode 100644 index 000000000..92caac946 --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/interceptor/properties/TenantKeys.java @@ -0,0 +1,13 @@ +package org.mifos.connector.common.interceptor.properties; + +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public class TenantKeys { + + private String name; + private String privateKey; + private String certificate; +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/interceptor/properties/TenantKeysProperties.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/interceptor/properties/TenantKeysProperties.java new file mode 100644 index 000000000..eb9d2c799 --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/interceptor/properties/TenantKeysProperties.java @@ -0,0 +1,32 @@ +package org.mifos.connector.common.interceptor.properties; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import lombok.Getter; +import lombok.Setter; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +@Component +@ConfigurationProperties(prefix = "jws") +@Getter +@Setter +public class TenantKeysProperties { + + private List tenantKeys = new ArrayList<>(); + + public TenantKeys getTenantKeys(String tenantName) { + Optional tenantKeys = getTenantKeys().stream().filter(t -> t.getName().equalsIgnoreCase(tenantName)).findFirst(); + return tenantKeys.orElseGet(() -> getTenantKeys().stream().filter(t -> t.getName().equalsIgnoreCase("default")).findFirst().get()); + } + + public String getPrivateKey(String tenantName) { + return getTenantKeys(tenantName).getPrivateKey(); + } + + public String getCertificate(String tenantName) { + return getTenantKeys(tenantName).getCertificate(); + } + +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/interceptor/service/JsonWebSignature.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/interceptor/service/JsonWebSignature.java new file mode 100644 index 000000000..d7865ee85 --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/interceptor/service/JsonWebSignature.java @@ -0,0 +1,17 @@ +package org.mifos.connector.common.interceptor.service; + +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.security.spec.InvalidKeySpecException; +import javax.crypto.BadPaddingException; +import javax.crypto.IllegalBlockSizeException; +import javax.crypto.NoSuchPaddingException; + +public interface JsonWebSignature { + + boolean verify(String data, String signature, String publicKey) throws NoSuchPaddingException, IllegalBlockSizeException, + NoSuchAlgorithmException, BadPaddingException, InvalidKeySpecException, InvalidKeyException; + + String create(String data, String privateKey) throws NoSuchPaddingException, IllegalBlockSizeException, NoSuchAlgorithmException, + BadPaddingException, InvalidKeySpecException, InvalidKeyException; +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/interceptor/service/JsonWebSignatureService.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/interceptor/service/JsonWebSignatureService.java new file mode 100644 index 000000000..caea725ff --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/interceptor/service/JsonWebSignatureService.java @@ -0,0 +1,98 @@ +package org.mifos.connector.common.interceptor.service; + +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.security.cert.CertificateException; +import java.security.spec.InvalidKeySpecException; +import javax.crypto.BadPaddingException; +import javax.crypto.IllegalBlockSizeException; +import javax.crypto.NoSuchPaddingException; +import lombok.Getter; +import org.mifos.connector.common.interceptor.properties.TenantKeysProperties; +import org.mifos.connector.common.util.CertificateUtil; +import org.mifos.connector.common.util.SecurityUtil; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component +@Getter +public class JsonWebSignatureService implements JsonWebSignature { + + @Autowired + private TenantKeysProperties tenantKeysProperties; + + /** + * Takes data,signature and tenantName. And verifies if signature is valid or not. TenantName is used to fetch + * respective keys + * + * @param data + * data for which signature to be verified as a string + * @param signature + * signature in string format + * @param tenantName + * name of the tenant + * @return [boolean] true if signature is verified false otherwise + * @throws NoSuchPaddingException + * thrown while parsing public key + * @throws IllegalBlockSizeException + * thrown while parsing public key + * @throws NoSuchAlgorithmException + * thrown while parsing public key + * @throws BadPaddingException + * thrown while parsing public key + * @throws InvalidKeySpecException + * thrown while parsing public key + * @throws InvalidKeyException + * thrown while parsing public key + */ + public boolean verifyForTenant(String data, String signature, String tenantName) + throws NoSuchPaddingException, IllegalBlockSizeException, NoSuchAlgorithmException, BadPaddingException, + InvalidKeySpecException, InvalidKeyException, CertificateException { + String certificate = tenantKeysProperties.getCertificate(tenantName); + String publicKeyString = CertificateUtil.getPublicKey(certificate); + return verify(data, signature, publicKeyString); + } + + /** + * Takes data and create the corresponding signature. TenantName is used to fetch respective keys + * + * @param data + * the data which is to be signed + * @param tenantName + * name of the tenant + * @return signature for the data passed in form of String + * @throws NoSuchPaddingException + * thrown while parsing public key + * @throws IllegalBlockSizeException + * thrown while parsing public key + * @throws NoSuchAlgorithmException + * thrown while parsing public key + * @throws BadPaddingException + * thrown while parsing public key + * @throws InvalidKeySpecException + * thrown while parsing public key + * @throws InvalidKeyException + * thrown while parsing public key + */ + public String signForTenant(String data, String tenantName) throws NoSuchPaddingException, IllegalBlockSizeException, + NoSuchAlgorithmException, BadPaddingException, InvalidKeySpecException, InvalidKeyException { + String privateKey = tenantKeysProperties.getPrivateKey(tenantName); + return create(data, privateKey); + } + + @Override + public boolean verify(String data, String signature, String publicKey) throws NoSuchPaddingException, IllegalBlockSizeException, + NoSuchAlgorithmException, BadPaddingException, InvalidKeySpecException, InvalidKeyException { + String hashedBody = SecurityUtil.hash(data); + String decodedHash = SecurityUtil.decryptUsingPublicKey(signature, publicKey); + return hashedBody.equals(decodedHash); + } + + @Override + public String create(String data, String privateKey) throws NoSuchPaddingException, IllegalBlockSizeException, NoSuchAlgorithmException, + BadPaddingException, InvalidKeySpecException, InvalidKeyException { + String hashedBody = SecurityUtil.hash(data); + return SecurityUtil.encryptUsingPrivateKey(hashedBody, privateKey); + } + +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/mobilemoney/airtel/dto/AirtelEnquiryResponseDTO.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/mobilemoney/airtel/dto/AirtelEnquiryResponseDTO.java new file mode 100644 index 000000000..abc273a90 --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/mobilemoney/airtel/dto/AirtelEnquiryResponseDTO.java @@ -0,0 +1,16 @@ +package org.mifos.connector.common.mobilemoney.airtel.dto; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +public class AirtelEnquiryResponseDTO { + + private AirtelEnquiryResponseDataDTO data; + private AirtelResponseStatusDTO status; +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/mobilemoney/airtel/dto/AirtelEnquiryResponseDataDTO.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/mobilemoney/airtel/dto/AirtelEnquiryResponseDataDTO.java new file mode 100644 index 000000000..47307b262 --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/mobilemoney/airtel/dto/AirtelEnquiryResponseDataDTO.java @@ -0,0 +1,15 @@ +package org.mifos.connector.common.mobilemoney.airtel.dto; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +public class AirtelEnquiryResponseDataDTO { + + private AirtelEnquiryResponseDataTransactionDTO transaction; +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/mobilemoney/airtel/dto/AirtelEnquiryResponseDataTransactionDTO.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/mobilemoney/airtel/dto/AirtelEnquiryResponseDataTransactionDTO.java new file mode 100644 index 000000000..9b37f96b7 --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/mobilemoney/airtel/dto/AirtelEnquiryResponseDataTransactionDTO.java @@ -0,0 +1,18 @@ +package org.mifos.connector.common.mobilemoney.airtel.dto; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +public class AirtelEnquiryResponseDataTransactionDTO { + + private String airtelMoneyId; + private String id; + private String message; + private String status; +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/mobilemoney/airtel/dto/AirtelPaymentRequestDTO.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/mobilemoney/airtel/dto/AirtelPaymentRequestDTO.java new file mode 100644 index 000000000..c129c93b6 --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/mobilemoney/airtel/dto/AirtelPaymentRequestDTO.java @@ -0,0 +1,17 @@ +package org.mifos.connector.common.mobilemoney.airtel.dto; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +public class AirtelPaymentRequestDTO { + + private String reference; + private AirtelPaymentRequestSubscriberDTO subscriber; + private AirtelPaymentRequestTransactionDTO transaction; +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/mobilemoney/airtel/dto/AirtelPaymentRequestSubscriberDTO.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/mobilemoney/airtel/dto/AirtelPaymentRequestSubscriberDTO.java new file mode 100644 index 000000000..94e38d9c9 --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/mobilemoney/airtel/dto/AirtelPaymentRequestSubscriberDTO.java @@ -0,0 +1,17 @@ +package org.mifos.connector.common.mobilemoney.airtel.dto; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +public class AirtelPaymentRequestSubscriberDTO { + + private String country; + private String currency; + private String msisdn; +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/mobilemoney/airtel/dto/AirtelPaymentRequestTransactionDTO.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/mobilemoney/airtel/dto/AirtelPaymentRequestTransactionDTO.java new file mode 100644 index 000000000..2815ff2e6 --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/mobilemoney/airtel/dto/AirtelPaymentRequestTransactionDTO.java @@ -0,0 +1,18 @@ +package org.mifos.connector.common.mobilemoney.airtel.dto; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +public class AirtelPaymentRequestTransactionDTO { + + private int amount; + private String country; + private String currency; + private String id; +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/mobilemoney/airtel/dto/AirtelPaymentResponseDTO.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/mobilemoney/airtel/dto/AirtelPaymentResponseDTO.java new file mode 100644 index 000000000..de48b8484 --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/mobilemoney/airtel/dto/AirtelPaymentResponseDTO.java @@ -0,0 +1,16 @@ +package org.mifos.connector.common.mobilemoney.airtel.dto; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +public class AirtelPaymentResponseDTO { + + private AirtelPaymentResponseDataDTO data; + private AirtelResponseStatusDTO status; +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/mobilemoney/airtel/dto/AirtelPaymentResponseDataDTO.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/mobilemoney/airtel/dto/AirtelPaymentResponseDataDTO.java new file mode 100644 index 000000000..b8e3d1714 --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/mobilemoney/airtel/dto/AirtelPaymentResponseDataDTO.java @@ -0,0 +1,15 @@ +package org.mifos.connector.common.mobilemoney.airtel.dto; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +public class AirtelPaymentResponseDataDTO { + + private AirtelPaymentResponseDataTransactionDTO transaction; +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/mobilemoney/airtel/dto/AirtelPaymentResponseDataTransactionDTO.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/mobilemoney/airtel/dto/AirtelPaymentResponseDataTransactionDTO.java new file mode 100644 index 000000000..00eb4c06f --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/mobilemoney/airtel/dto/AirtelPaymentResponseDataTransactionDTO.java @@ -0,0 +1,16 @@ +package org.mifos.connector.common.mobilemoney.airtel.dto; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +public class AirtelPaymentResponseDataTransactionDTO { + + private boolean id; + private String status; +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/mobilemoney/airtel/dto/AirtelResponseStatusDTO.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/mobilemoney/airtel/dto/AirtelResponseStatusDTO.java new file mode 100644 index 000000000..c0d4826a7 --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/mobilemoney/airtel/dto/AirtelResponseStatusDTO.java @@ -0,0 +1,19 @@ +package org.mifos.connector.common.mobilemoney.airtel.dto; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +public class AirtelResponseStatusDTO { + + private String code; + private String message; + private String resultCode; + private String responseCode; + private Boolean success; +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/mojaloop/dto/ComplexName.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/mojaloop/dto/ComplexName.java new file mode 100644 index 000000000..d6c3256cd --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/mojaloop/dto/ComplexName.java @@ -0,0 +1,39 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla + * Public License, v. 2.0. If a copy of the MPL was not distributed + * with this file, You can obtain one at + * + * https://mozilla.org/MPL/2.0/. + */ +package org.mifos.connector.common.mojaloop.dto; + +public class ComplexName extends PartyIdInfo { + + private String firstName; + private String middleName; + private String lastName; + + public String getFirstName() { + return firstName; + } + + public void setFirstName(String firstName) { + this.firstName = firstName; + } + + public String getMiddleName() { + return middleName; + } + + public void setMiddleName(String middleName) { + this.middleName = middleName; + } + + public String getLastName() { + return lastName; + } + + public void setLastName(String lastName) { + this.lastName = lastName; + } +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/mojaloop/dto/ErrorInformation.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/mojaloop/dto/ErrorInformation.java new file mode 100644 index 000000000..5bdc944ca --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/mojaloop/dto/ErrorInformation.java @@ -0,0 +1,55 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla + * Public License, v. 2.0. If a copy of the MPL was not distributed + * with this file, You can obtain one at + * + * https://mozilla.org/MPL/2.0/. + */ +package org.mifos.connector.common.mojaloop.dto; + +import java.util.Arrays; +import java.util.List; + +public class ErrorInformation { + + private short errorCode; // mandatory, 4 digits + private String errorDescription; // mandatory + private List extensionList; + + public ErrorInformation() {} + + public ErrorInformation(short errorCode, String errorDescription) { + this.errorCode = errorCode; + this.errorDescription = errorDescription; + } + + public short getErrorCode() { + return errorCode; + } + + public void setErrorCode(short errorCode) { + this.errorCode = errorCode; + } + + public String getErrorDescription() { + return errorDescription; + } + + public void setErrorDescription(String errorDescription) { + this.errorDescription = errorDescription; + } + + public List getExtensionList() { + return extensionList; + } + + public void setExtensionList(List extensionList) { + this.extensionList = extensionList; + } + + @Override + public String toString() { + return "ErrorInformation{" + "errorCode:" + errorCode + ", errorDescription:'" + errorDescription + '\'' + ", extensionList:" + + (extensionList == null ? "" : Arrays.toString(extensionList.toArray())) + '}'; + } +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/mojaloop/dto/ErrorSwitchResponseDTO.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/mojaloop/dto/ErrorSwitchResponseDTO.java new file mode 100644 index 000000000..9fb21f6e7 --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/mojaloop/dto/ErrorSwitchResponseDTO.java @@ -0,0 +1,26 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla + * Public License, v. 2.0. If a copy of the MPL was not distributed + * with this file, You can obtain one at + * + * https://mozilla.org/MPL/2.0/. + */ +package org.mifos.connector.common.mojaloop.dto; + +public class ErrorSwitchResponseDTO { + + private ErrorInformation errorInformation; + + public ErrorInformation getErrorInformation() { + return errorInformation; + } + + public void setErrorInformation(ErrorInformation errorInformation) { + this.errorInformation = errorInformation; + } + + @Override + public String toString() { + return "ErrorSwitchResponseDTO{" + "errorInformation:" + errorInformation + '}'; + } +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/mojaloop/dto/Extension.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/mojaloop/dto/Extension.java new file mode 100644 index 000000000..931806bef --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/mojaloop/dto/Extension.java @@ -0,0 +1,37 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla + * Public License, v. 2.0. If a copy of the MPL was not distributed + * with this file, You can obtain one at + * + * https://mozilla.org/MPL/2.0/. + */ +package org.mifos.connector.common.mojaloop.dto; + +public class Extension { + + private String key; // mandatory, String(1..32) + private String value; // mandatory, String(1..128) + + Extension() {} + + public Extension(String key, String value) { + this.key = key; + this.value = value; + } + + public String getKey() { + return key; + } + + void setKey(String key) { + this.key = key; + } + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/mojaloop/dto/ExtensionList.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/mojaloop/dto/ExtensionList.java new file mode 100644 index 000000000..046eeb84c --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/mojaloop/dto/ExtensionList.java @@ -0,0 +1,25 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla + * Public License, v. 2.0. If a copy of the MPL was not distributed + * with this file, You can obtain one at + * + * https://mozilla.org/MPL/2.0/. + */ +package org.mifos.connector.common.mojaloop.dto; + +import java.util.List; + +public class ExtensionList { + + private List extension; + + public ExtensionList() {} + + public List getExtension() { + return extension; + } + + public void setExtension(List extension) { + this.extension = extension; + } +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/mojaloop/dto/FspMoneyData.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/mojaloop/dto/FspMoneyData.java new file mode 100644 index 000000000..043ea5579 --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/mojaloop/dto/FspMoneyData.java @@ -0,0 +1,58 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla + * Public License, v. 2.0. If a copy of the MPL was not distributed + * with this file, You can obtain one at + * + * https://mozilla.org/MPL/2.0/. + */ +package org.mifos.connector.common.mojaloop.dto; + +import java.beans.Transient; +import java.math.BigDecimal; + +public class FspMoneyData { + + private BigDecimal amount; + private String currency; + + public FspMoneyData() {} + + public FspMoneyData(BigDecimal amount, String currency) { + this.amount = amount; + this.currency = currency; + } + + public BigDecimal getAmount() { + return amount; + } + + public void setAmount(BigDecimal amount) { + this.amount = amount; + } + + public String getCurrency() { + return currency; + } + + public void setCurrency(String currency) { + this.currency = currency; + } + + // @Transient + // public Money toIlpMoney() { + // Money money = new Money(); + // money.setAmount(ContextUtil.formatAmount(amount)); + // money.setCurrency(currency); + // return money; + // } + + @Transient + public static MoneyData toMoneyData(FspMoneyData moneyData) { + return moneyData == null ? null : moneyData.toMoneyData(); + } + + @Transient + public MoneyData toMoneyData() { + return new MoneyData(amount, currency); + } +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/mojaloop/dto/GeoCode.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/mojaloop/dto/GeoCode.java new file mode 100644 index 000000000..4a52edef2 --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/mojaloop/dto/GeoCode.java @@ -0,0 +1,30 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla + * Public License, v. 2.0. If a copy of the MPL was not distributed + * with this file, You can obtain one at + * + * https://mozilla.org/MPL/2.0/. + */ +package org.mifos.connector.common.mojaloop.dto; + +public class GeoCode { + + private String longitude; + private String latitude; + + public String getLongitude() { + return longitude; + } + + public void setLongitude(String longitude) { + this.longitude = longitude; + } + + public String getLatitude() { + return latitude; + } + + public void setLatitude(String latitude) { + this.latitude = latitude; + } +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/mojaloop/dto/MoneyData.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/mojaloop/dto/MoneyData.java new file mode 100644 index 000000000..2b754e752 --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/mojaloop/dto/MoneyData.java @@ -0,0 +1,83 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla + * Public License, v. 2.0. If a copy of the MPL was not distributed + * with this file, You can obtain one at + * + * https://mozilla.org/MPL/2.0/. + */ +package org.mifos.connector.common.mojaloop.dto; + +import java.beans.Transient; +import java.math.BigDecimal; +import javax.validation.constraints.NotEmpty; +import org.hibernate.validator.constraints.Length; +import org.mifos.connector.common.util.ContextUtil; + +public class MoneyData { + + @NotEmpty + private String amount; + + @NotEmpty + @Length(min = 3, max = 3) + private String currency; + + public MoneyData() {} + + @Override + public String toString() { + return "MoneyData{" + "amount='" + amount + '\'' + ", currency='" + currency + '\'' + '}'; + } + + public MoneyData(String amount, String currency) { + this.amount = amount; + this.currency = currency; + } + + public MoneyData(BigDecimal amount, String currency) { + this(ContextUtil.formatAmount(amount), currency); + } + + public String getAmount() { + return amount; + } + + public void setAmount(String amount) { + this.amount = amount; + } + + @Transient + public BigDecimal getAmountDecimal() { + return ContextUtil.parseAmount(amount); + } + + public void setAmount(BigDecimal amount) { + this.amount = ContextUtil.formatAmount(amount); + } + + public String getCurrency() { + return currency; + } + + public void setCurrency(String currency) { + this.currency = currency; + } + + // @Transient + // public Money getIlpMoney() { + // Money money = new Money(); + // money.setAmount(amount); + // money.setCurrency(currency); + // return money; + // } + + @Transient + public static FspMoneyData toFspMoneyData(MoneyData moneyData) { + return moneyData == null ? null : moneyData.toFspMoneyData(); + } + + @Transient + public FspMoneyData toFspMoneyData() { + return new FspMoneyData(getAmountDecimal(), currency); + } +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/mojaloop/dto/ParticipantSwitchRequestDTO.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/mojaloop/dto/ParticipantSwitchRequestDTO.java new file mode 100644 index 000000000..5bce1b7b1 --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/mojaloop/dto/ParticipantSwitchRequestDTO.java @@ -0,0 +1,30 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla + * Public License, v. 2.0. If a copy of the MPL was not distributed + * with this file, You can obtain one at + * + * https://mozilla.org/MPL/2.0/. + */ +package org.mifos.connector.common.mojaloop.dto; + +public class ParticipantSwitchRequestDTO { + + private String fspId; + private String currency; + + public String getFspId() { + return fspId; + } + + public void setFspId(String fspId) { + this.fspId = fspId; + } + + public String getCurrency() { + return currency; + } + + public void setCurrency(String currency) { + this.currency = currency; + } +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/mojaloop/dto/ParticipantSwitchResponseDTO.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/mojaloop/dto/ParticipantSwitchResponseDTO.java new file mode 100644 index 000000000..6d1357ac7 --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/mojaloop/dto/ParticipantSwitchResponseDTO.java @@ -0,0 +1,21 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla + * Public License, v. 2.0. If a copy of the MPL was not distributed + * with this file, You can obtain one at + * + * https://mozilla.org/MPL/2.0/. + */ +package org.mifos.connector.common.mojaloop.dto; + +public class ParticipantSwitchResponseDTO { + + private String fspId; + + public String getFspId() { + return fspId; + } + + public void setFspId(String fspId) { + this.fspId = fspId; + } +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/mojaloop/dto/Party.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/mojaloop/dto/Party.java new file mode 100644 index 000000000..a516f57c6 --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/mojaloop/dto/Party.java @@ -0,0 +1,98 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla + * Public License, v. 2.0. If a copy of the MPL was not distributed + * with this file, You can obtain one at + * + * https://mozilla.org/MPL/2.0/. + */ +package org.mifos.connector.common.mojaloop.dto; + +import javax.validation.constraints.NotNull; + +public class Party { + + @NotNull + private PartyIdInfo partyIdInfo; // mandatory + private String merchantClassificationCode; // optional + private String name; // optional + private PersonalInfo personalInfo; // optional + + @Override + public String toString() { + return "Party{" + "partyIdInfo=" + partyIdInfo + ", merchantClassificationCode='" + merchantClassificationCode + '\'' + ", name='" + + name + '\'' + ", personalInfo=" + personalInfo + '}'; + } + + public PartyIdInfo getPartyIdInfo() { + return partyIdInfo; + } + + public void setPartyIdInfo(PartyIdInfo partyIdInfo) { + this.partyIdInfo = partyIdInfo; + } + + public String getMerchantClassificationCode() { + return merchantClassificationCode; + } + + public void setMerchantClassificationCode(String merchantClassificationCode) { + this.merchantClassificationCode = merchantClassificationCode; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public PersonalInfo getPersonalInfo() { + return personalInfo; + } + + public void setPersonalInfo(PersonalInfo personalInfo) { + this.personalInfo = personalInfo; + } + + public Party() {} + + public Party(PartyIdInfo partyIdInfo, String merchantClassificationCode, String name, PersonalInfo personalInfo) { + this.partyIdInfo = partyIdInfo; + this.merchantClassificationCode = merchantClassificationCode; + this.name = name; + this.personalInfo = personalInfo; + } + + public Party(PartyIdInfo partyIdInfo) { + this(partyIdInfo, null, null, null); + } + + // @Transient + // public com.ilp.conditions.models.pdp.Party getIlpParty() { + // com.ilp.conditions.models.pdp.Party ilpParty = new com.ilp.conditions.models.pdp.Party(); + // ilpParty.setMerchantClassificationCode(merchantClassificationCode); + // ilpParty.setName(name); + // + // com.ilp.conditions.models.pdp.PartyIdInfo ilpPartyIdInfo = new com.ilp.conditions.models.pdp.PartyIdInfo(); + // ilpPartyIdInfo.setFspId(partyIdInfo.getFspId()); + // ilpPartyIdInfo.setPartyIdentifier(partyIdInfo.getPartyIdentifier()); + // ilpPartyIdInfo.setPartyIdType(partyIdInfo.getPartyIdType().name()); + // ilpPartyIdInfo.setPartySubIdOrType(partyIdInfo.getPartySubIdOrType()); + // ilpParty.setPartyIdInfo(ilpPartyIdInfo); + // + // if (personalInfo != null) { + // PartyPersonalInfo ilpPersonalInfo = new PartyPersonalInfo(); + // ilpPersonalInfo.setDateOfBirth(personalInfo.getDateOfBirth()); + // PartyComplexName payerComplexName = new PartyComplexName(); + // ComplexName complexName = personalInfo.getComplexName(); + // payerComplexName.setFirstName(complexName.getFirstName()); + // payerComplexName.setLastName(complexName.getLastName()); + // payerComplexName.setMiddleName(complexName.getMiddleName()); + // ilpPersonalInfo.setComplexName(payerComplexName); + // ilpParty.setPersonalInfo(ilpPersonalInfo); + // } + // + // return ilpParty; + // } +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/mojaloop/dto/PartyIdInfo.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/mojaloop/dto/PartyIdInfo.java new file mode 100644 index 000000000..20d0af043 --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/mojaloop/dto/PartyIdInfo.java @@ -0,0 +1,125 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla + * Public License, v. 2.0. If a copy of the MPL was not distributed + * with this file, You can obtain one at + * + * https://mozilla.org/MPL/2.0/. + */ +package org.mifos.connector.common.mojaloop.dto; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import org.mifos.connector.common.mojaloop.type.IdentifierType; + +public class PartyIdInfo { + + @NotNull + private IdentifierType partyIdType; // mandatory, immutable + @NotEmpty + private String partyIdentifier; // mandatory, immutable + private String partySubIdOrType; // optional, immutable + private String fspId; // optional + + PartyIdInfo() {} + + public PartyIdInfo(IdentifierType partyIdType, String partyIdentifier, String partySubIdOrType, String fspId) { + this.partyIdType = partyIdType; + this.partyIdentifier = partyIdentifier; + this.partySubIdOrType = partySubIdOrType; + this.fspId = fspId; + } + + public PartyIdInfo(IdentifierType partyIdType, String partyIdentifier, String partySubIdOrType) { + this(partyIdType, partyIdentifier, partySubIdOrType, null); + } + + public PartyIdInfo(IdentifierType partyIdType, String partyIdentifier) { + this(partyIdType, partyIdentifier, null, null); + } + + public IdentifierType getPartyIdType() { + return partyIdType; + } + + void setPartyIdType(IdentifierType partyIdType) { + this.partyIdType = partyIdType; + } + + public String getPartyIdentifier() { + return partyIdentifier; + } + + void setPartyIdentifier(String partyIdentifier) { + this.partyIdentifier = partyIdentifier; + } + + public String getPartySubIdOrType() { + return partySubIdOrType; + } + + void setPartySubIdOrType(String partySubIdOrType) { + this.partySubIdOrType = partySubIdOrType; + } + + public String getFspId() { + return fspId; + } + + public void setFspId(String fspId) { + if (fspId == null) { + return; + } + if (this.fspId != null && !this.fspId.equals(fspId)) { + throw new RuntimeException("Technical error: try to change fspId from " + this.fspId + " to " + fspId); + } + this.fspId = fspId; + } + + public void update(PartyIdInfo oInfo) { + if (oInfo == null) { + return; + } + if (!equals(oInfo)) { + throw new RuntimeException("Incompatible party info " + this + '/' + oInfo); + } + + String oFspId = oInfo.fspId; + if (oFspId != null) { + fspId = oFspId; + } + } + + @Override + public String toString() { + return "PartyIdInfo{" + "idType:" + partyIdType + ", id:'" + partyIdentifier + '\'' + ", subIdOrType:'" + partySubIdOrType + '\'' + + ", fspId:'" + fspId + '\'' + '}'; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + PartyIdInfo that = (PartyIdInfo) o; + + if (partyIdType != that.partyIdType) { + return false; + } + if (!partyIdentifier.equals(that.partyIdentifier)) { + return false; + } + return partySubIdOrType != null ? partySubIdOrType.equals(that.partySubIdOrType) : that.partySubIdOrType == null; + } + + @Override + public int hashCode() { + int result = partyIdType.hashCode(); + result = 31 * result + partyIdentifier.hashCode(); + result = 31 * result + (partySubIdOrType != null ? partySubIdOrType.hashCode() : 0); + return result; + } +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/mojaloop/dto/PartySwitchResponseDTO.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/mojaloop/dto/PartySwitchResponseDTO.java new file mode 100644 index 000000000..d89ec04b3 --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/mojaloop/dto/PartySwitchResponseDTO.java @@ -0,0 +1,27 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla + * Public License, v. 2.0. If a copy of the MPL was not distributed + * with this file, You can obtain one at + * + * https://mozilla.org/MPL/2.0/. + */ +package org.mifos.connector.common.mojaloop.dto; + +public class PartySwitchResponseDTO { + + private Party party; + + PartySwitchResponseDTO() {} + + public PartySwitchResponseDTO(Party party) { + this.party = party; + } + + public Party getParty() { + return party; + } + + public void setParty(Party party) { + this.party = party; + } +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/mojaloop/dto/Payee.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/mojaloop/dto/Payee.java new file mode 100644 index 000000000..e08ee1bb7 --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/mojaloop/dto/Payee.java @@ -0,0 +1,30 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla + * Public License, v. 2.0. If a copy of the MPL was not distributed + * with this file, You can obtain one at + * + * https://mozilla.org/MPL/2.0/. + */ +package org.mifos.connector.common.mojaloop.dto; + +public class Payee { + + private PartyIdInfo partyIdInfo; + private String merchantClassificationCode; + + public PartyIdInfo getPartyIdInfo() { + return partyIdInfo; + } + + public void setPartyIdInfo(PartyIdInfo partyIdInfo) { + this.partyIdInfo = partyIdInfo; + } + + public String getMerchantClassificationCode() { + return merchantClassificationCode; + } + + public void setMerchantClassificationCode(String merchantClassificationCode) { + this.merchantClassificationCode = merchantClassificationCode; + } +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/mojaloop/dto/Payer.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/mojaloop/dto/Payer.java new file mode 100644 index 000000000..c9b0bdf4b --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/mojaloop/dto/Payer.java @@ -0,0 +1,21 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla + * Public License, v. 2.0. If a copy of the MPL was not distributed + * with this file, You can obtain one at + * + * https://mozilla.org/MPL/2.0/. + */ +package org.mifos.connector.common.mojaloop.dto; + +public class Payer { + + private PartyIdInfo partyIdInfo; + + public PartyIdInfo getPartyIdInfo() { + return partyIdInfo; + } + + public void setPartyIdInfo(PartyIdInfo partyIdInfo) { + this.partyIdInfo = partyIdInfo; + } +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/mojaloop/dto/PersonalInfo.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/mojaloop/dto/PersonalInfo.java new file mode 100644 index 000000000..3395f5d22 --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/mojaloop/dto/PersonalInfo.java @@ -0,0 +1,30 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla + * Public License, v. 2.0. If a copy of the MPL was not distributed + * with this file, You can obtain one at + * + * https://mozilla.org/MPL/2.0/. + */ +package org.mifos.connector.common.mojaloop.dto; + +public class PersonalInfo { + + private ComplexName complexName; + private String dateOfBirth; + + public ComplexName getComplexName() { + return complexName; + } + + public void setComplexName(ComplexName complexName) { + this.complexName = complexName; + } + + public String getDateOfBirth() { + return dateOfBirth; + } + + public void setDateOfBirth(String dateOfBirth) { + this.dateOfBirth = dateOfBirth; + } +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/mojaloop/dto/QuoteSwitchRequestDTO.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/mojaloop/dto/QuoteSwitchRequestDTO.java new file mode 100644 index 000000000..6bf09fdf4 --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/mojaloop/dto/QuoteSwitchRequestDTO.java @@ -0,0 +1,153 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla + * Public License, v. 2.0. If a copy of the MPL was not distributed + * with this file, You can obtain one at + * + * https://mozilla.org/MPL/2.0/. + */ +package org.mifos.connector.common.mojaloop.dto; + +import java.time.LocalDateTime; +import org.mifos.connector.common.mojaloop.type.AmountType; +import org.mifos.connector.common.util.ContextUtil; + +public class QuoteSwitchRequestDTO { + + private String transactionId; + private String transactionRequestId; + private String quoteId; + private Party payee; + private Party payer; + private AmountType amountType; + private MoneyData amount; + private MoneyData fees; + private TransactionType transactionType; + private GeoCode geoCode; + private String note; + private String expiration; + private ExtensionList extensionList; + + public QuoteSwitchRequestDTO() {} + + public QuoteSwitchRequestDTO(String transactionId, String transactionRequestId, String quoteId, Party payee, Party payer, + AmountType amountType, MoneyData amount, MoneyData fees, TransactionType transactionType, GeoCode geoCode, String note, + LocalDateTime expiration, ExtensionList extensionList) { + this.transactionId = transactionId; + this.transactionRequestId = transactionRequestId; + this.quoteId = quoteId; + this.payee = payee; + this.payer = payer; + this.amountType = amountType; + this.amount = amount; + this.fees = fees; + this.transactionType = transactionType; + this.geoCode = geoCode; + this.note = note; + this.expiration = ContextUtil.formatDate(expiration); + this.extensionList = extensionList; + } + + public String getTransactionId() { + return transactionId; + } + + public void setTransactionId(String transactionId) { + this.transactionId = transactionId; + } + + public String getTransactionRequestId() { + return transactionRequestId; + } + + public void setTransactionRequestId(String transactionRequestId) { + this.transactionRequestId = transactionRequestId; + } + + public String getQuoteId() { + return quoteId; + } + + public void setQuoteId(String quoteId) { + this.quoteId = quoteId; + } + + public Party getPayee() { + return payee; + } + + public void setPayee(Party payee) { + this.payee = payee; + } + + public Party getPayer() { + return payer; + } + + public void setPayer(Party payer) { + this.payer = payer; + } + + public AmountType getAmountType() { + return amountType; + } + + public void setAmountType(AmountType amountType) { + this.amountType = amountType; + } + + public MoneyData getAmount() { + return amount; + } + + public void setAmount(MoneyData amount) { + this.amount = amount; + } + + public MoneyData getFees() { + return fees; + } + + public void setFees(MoneyData fees) { + this.fees = fees; + } + + public TransactionType getTransactionType() { + return transactionType; + } + + public void setTransactionType(TransactionType transactionType) { + this.transactionType = transactionType; + } + + public GeoCode getGeoCode() { + return geoCode; + } + + public void setGeoCode(GeoCode geoCode) { + this.geoCode = geoCode; + } + + public String getNote() { + return note; + } + + public void setNote(String note) { + this.note = note; + } + + public String getExpiration() { + return expiration; + } + + public void setExpiration(String expiration) { + this.expiration = expiration; + } + + public ExtensionList getExtensionList() { + return extensionList; + } + + public void setExtensionList(ExtensionList extensionList) { + this.extensionList = extensionList; + } +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/mojaloop/dto/QuoteSwitchResponseDTO.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/mojaloop/dto/QuoteSwitchResponseDTO.java new file mode 100644 index 000000000..354364938 --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/mojaloop/dto/QuoteSwitchResponseDTO.java @@ -0,0 +1,108 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla + * Public License, v. 2.0. If a copy of the MPL was not distributed + * with this file, You can obtain one at + * + * https://mozilla.org/MPL/2.0/. + */ +package org.mifos.connector.common.mojaloop.dto; + +import java.time.LocalDateTime; +import org.mifos.connector.common.util.ContextUtil; + +public class QuoteSwitchResponseDTO { + + private MoneyData transferAmount; // mandatory + private MoneyData payeeReceiveAmount; + private MoneyData payeeFspFee; + private MoneyData payeeFspCommission; + private String expiration; // mandatory + private GeoCode geoCode; + private String ilpPacket; // mandatory + private String condition; // mandatory + private ExtensionList extensionList; + + public QuoteSwitchResponseDTO() {} + + public QuoteSwitchResponseDTO(MoneyData transferAmount, MoneyData payeeReceiveAmount, MoneyData payeeFspFee, + MoneyData payeeFspCommission, LocalDateTime expiration, GeoCode geoCode, String ilpPacket, String condition, + ExtensionList extensionList) { + this.transferAmount = transferAmount; + this.payeeReceiveAmount = payeeReceiveAmount; + this.payeeFspFee = payeeFspFee; + this.payeeFspCommission = payeeFspCommission; + this.expiration = ContextUtil.formatDate(expiration); + this.geoCode = geoCode; + this.ilpPacket = ilpPacket; + this.condition = condition; + this.extensionList = extensionList; + } + + public MoneyData getTransferAmount() { + return transferAmount; + } + + public void setTransferAmount(MoneyData transferAmount) { + this.transferAmount = transferAmount; + } + + public MoneyData getPayeeReceiveAmount() { + return payeeReceiveAmount; + } + + public void setPayeeReceiveAmount(MoneyData payeeReceiveAmount) { + this.payeeReceiveAmount = payeeReceiveAmount; + } + + public MoneyData getPayeeFspFee() { + return payeeFspFee; + } + + public void setPayeeFspFee(MoneyData payeeFspFee) { + this.payeeFspFee = payeeFspFee; + } + + public MoneyData getPayeeFspCommission() { + return payeeFspCommission; + } + + public void setPayeeFspCommission(MoneyData payeeFspCommission) { + this.payeeFspCommission = payeeFspCommission; + } + + public String getExpiration() { + return expiration; + } + + public void setExpiration(String expiration) { + this.expiration = expiration; + } + + public void setExtensionList(ExtensionList extensionList) { + this.extensionList = extensionList; + } + + public GeoCode getGeoCode() { + return geoCode; + } + + public void setGeoCode(GeoCode geoCode) { + this.geoCode = geoCode; + } + + public String getIlpPacket() { + return ilpPacket; + } + + public void setIlpPacket(String ilpPacket) { + this.ilpPacket = ilpPacket; + } + + public String getCondition() { + return condition; + } + + public void setCondition(String condition) { + this.condition = condition; + } +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/mojaloop/dto/Refund.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/mojaloop/dto/Refund.java new file mode 100644 index 000000000..c3afeb097 --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/mojaloop/dto/Refund.java @@ -0,0 +1,30 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla + * Public License, v. 2.0. If a copy of the MPL was not distributed + * with this file, You can obtain one at + * + * https://mozilla.org/MPL/2.0/. + */ +package org.mifos.connector.common.mojaloop.dto; + +public class Refund { + + private String originalTransactionId; + private String refundReason; + + public String getOriginalTransactionId() { + return originalTransactionId; + } + + public void setOriginalTransactionId(String originalTransactionId) { + this.originalTransactionId = originalTransactionId; + } + + public String getRefundReason() { + return refundReason; + } + + public void setRefundReason(String refundReason) { + this.refundReason = refundReason; + } +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/mojaloop/dto/TransactionRequestSwitchRequestDTO.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/mojaloop/dto/TransactionRequestSwitchRequestDTO.java new file mode 100644 index 000000000..37154c931 --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/mojaloop/dto/TransactionRequestSwitchRequestDTO.java @@ -0,0 +1,111 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla + * Public License, v. 2.0. If a copy of the MPL was not distributed + * with this file, You can obtain one at + * + * https://mozilla.org/MPL/2.0/. + */ +package org.mifos.connector.common.mojaloop.dto; + +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer; +import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer; +import java.time.LocalDateTime; +import org.mifos.connector.common.mojaloop.type.AuthenticationType; + +public class TransactionRequestSwitchRequestDTO { + + private String transactionRequestId; + private Party payee; + private PartyIdInfo payer; + private MoneyData amount; + private TransactionType transactionType; + private String note; + private GeoCode geoCode; + private AuthenticationType authenticationType; + @JsonSerialize(using = LocalDateTimeSerializer.class) + @JsonDeserialize(using = LocalDateTimeDeserializer.class) + private LocalDateTime expiration; + private ExtensionList extensionList; + + public String getTransactionRequestId() { + return transactionRequestId; + } + + public void setTransactionRequestId(String transactionRequestId) { + this.transactionRequestId = transactionRequestId; + } + + public Party getPayee() { + return payee; + } + + public void setPayee(Party payee) { + this.payee = payee; + } + + public PartyIdInfo getPayer() { + return payer; + } + + public void setPayer(PartyIdInfo payer) { + this.payer = payer; + } + + public MoneyData getAmount() { + return amount; + } + + public void setAmount(MoneyData amount) { + this.amount = amount; + } + + public TransactionType getTransactionType() { + return transactionType; + } + + public void setTransactionType(TransactionType transactionType) { + this.transactionType = transactionType; + } + + public String getNote() { + return note; + } + + public void setNote(String note) { + this.note = note; + } + + public GeoCode getGeoCode() { + return geoCode; + } + + public void setGeoCode(GeoCode geoCode) { + this.geoCode = geoCode; + } + + public AuthenticationType getAuthenticationType() { + return authenticationType; + } + + public void setAuthenticationType(AuthenticationType authenticationType) { + this.authenticationType = authenticationType; + } + + public LocalDateTime getExpiration() { + return expiration; + } + + public void setExpiration(LocalDateTime expiration) { + this.expiration = expiration; + } + + public ExtensionList getExtensionList() { + return extensionList; + } + + public void setExtensionList(ExtensionList extensionList) { + this.extensionList = extensionList; + } +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/mojaloop/dto/TransactionRequestSwitchResponseDTO.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/mojaloop/dto/TransactionRequestSwitchResponseDTO.java new file mode 100644 index 000000000..28c9fea8a --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/mojaloop/dto/TransactionRequestSwitchResponseDTO.java @@ -0,0 +1,41 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla + * Public License, v. 2.0. If a copy of the MPL was not distributed + * with this file, You can obtain one at + * + * https://mozilla.org/MPL/2.0/. + */ +package org.mifos.connector.common.mojaloop.dto; + +import org.mifos.connector.common.mojaloop.type.TransactionRequestState; + +public class TransactionRequestSwitchResponseDTO { + + private String transactionId; + private TransactionRequestState transactionRequestState; + private ExtensionList extensionList; + + public String getTransactionId() { + return transactionId; + } + + public void setTransactionId(String transactionId) { + this.transactionId = transactionId; + } + + public TransactionRequestState getTransactionRequestState() { + return transactionRequestState; + } + + public void setTransactionRequestState(TransactionRequestState transactionRequestState) { + this.transactionRequestState = transactionRequestState; + } + + public ExtensionList getExtensionList() { + return extensionList; + } + + public void setExtensionList(ExtensionList extensionList) { + this.extensionList = extensionList; + } +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/mojaloop/dto/TransactionType.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/mojaloop/dto/TransactionType.java new file mode 100644 index 000000000..77575036f --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/mojaloop/dto/TransactionType.java @@ -0,0 +1,70 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla + * Public License, v. 2.0. If a copy of the MPL was not distributed + * with this file, You can obtain one at + * + * https://mozilla.org/MPL/2.0/. + */ +package org.mifos.connector.common.mojaloop.dto; + +import org.mifos.connector.common.mojaloop.type.InitiatorType; +import org.mifos.connector.common.mojaloop.type.Scenario; +import org.mifos.connector.common.mojaloop.type.TransactionRole; + +public class TransactionType { + + private Scenario scenario; + private String subScenario; + private TransactionRole initiator; + private InitiatorType initiatorType; + private Refund refundInfo; + private String balanceOfPayments; // 3 digits number, see https://www.imf.org/external/np/sta/bopcode/ + + public Scenario getScenario() { + return scenario; + } + + public void setScenario(Scenario scenario) { + this.scenario = scenario; + } + + public String getSubScenario() { + return subScenario; + } + + public void setSubScenario(String subScenario) { + this.subScenario = subScenario; + } + + public TransactionRole getInitiator() { + return initiator; + } + + public void setInitiator(TransactionRole initiator) { + this.initiator = initiator; + } + + public InitiatorType getInitiatorType() { + return initiatorType; + } + + public void setInitiatorType(InitiatorType initiatorType) { + this.initiatorType = initiatorType; + } + + public Refund getRefundInfo() { + return refundInfo; + } + + public void setRefundInfo(Refund refundInfo) { + this.refundInfo = refundInfo; + } + + public String getBalanceOfPayments() { + return balanceOfPayments; + } + + public void setBalanceOfPayments(String balanceOfPayments) { + this.balanceOfPayments = balanceOfPayments; + } +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/mojaloop/dto/TransferSwitchRequestDTO.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/mojaloop/dto/TransferSwitchRequestDTO.java new file mode 100644 index 000000000..59a1dcb4d --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/mojaloop/dto/TransferSwitchRequestDTO.java @@ -0,0 +1,101 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla + * Public License, v. 2.0. If a copy of the MPL was not distributed + * with this file, You can obtain one at + * + * https://mozilla.org/MPL/2.0/. + */ +package org.mifos.connector.common.mojaloop.dto; + +import java.time.LocalDateTime; +import org.mifos.connector.common.util.ContextUtil; + +public class TransferSwitchRequestDTO { + + private String transferId; + private String payerFsp; + private String payeeFsp; + private MoneyData amount; + private String ilpPacket; + private String condition; + private String expiration; + private ExtensionList extensionList; + + public TransferSwitchRequestDTO() {} + + public TransferSwitchRequestDTO(String transferId, String payerFsp, String payeeFsp, MoneyData amount, String ilpPacket, + String condition, LocalDateTime expiration, ExtensionList extensionList) { + this.transferId = transferId; + this.payerFsp = payerFsp; + this.payeeFsp = payeeFsp; + this.amount = amount; + this.ilpPacket = ilpPacket; + this.condition = condition; + this.expiration = ContextUtil.formatDate(expiration); + this.extensionList = extensionList; + } + + public String getTransferId() { + return transferId; + } + + public void setTransferId(String transferId) { + this.transferId = transferId; + } + + public String getPayerFsp() { + return payerFsp; + } + + public void setPayerFsp(String payerFsp) { + this.payerFsp = payerFsp; + } + + public String getPayeeFsp() { + return payeeFsp; + } + + public void setPayeeFsp(String payeeFsp) { + this.payeeFsp = payeeFsp; + } + + public MoneyData getAmount() { + return amount; + } + + public void setAmount(MoneyData amount) { + this.amount = amount; + } + + public String getIlpPacket() { + return ilpPacket; + } + + public void setIlpPacket(String ilpPacket) { + this.ilpPacket = ilpPacket; + } + + public String getCondition() { + return condition; + } + + public void setCondition(String condition) { + this.condition = condition; + } + + public String getExpiration() { + return expiration; + } + + public void setExpiration(String expiration) { + this.expiration = expiration; + } + + public ExtensionList getExtensionList() { + return extensionList; + } + + public void setExtensionList(ExtensionList extensionList) { + this.extensionList = extensionList; + } +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/mojaloop/dto/TransferSwitchResponseDTO.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/mojaloop/dto/TransferSwitchResponseDTO.java new file mode 100644 index 000000000..803257b34 --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/mojaloop/dto/TransferSwitchResponseDTO.java @@ -0,0 +1,66 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla + * Public License, v. 2.0. If a copy of the MPL was not distributed + * with this file, You can obtain one at + * + * https://mozilla.org/MPL/2.0/. + */ +package org.mifos.connector.common.mojaloop.dto; + +import java.time.LocalDateTime; +import org.mifos.connector.common.mojaloop.type.TransferState; +import org.mifos.connector.common.util.ContextUtil; + +public class TransferSwitchResponseDTO { + + private String fulfilment; + private String completedTimestamp; + private TransferState transferState; // mandatory + private ExtensionList extensionList; + + public TransferSwitchResponseDTO() {} + + public TransferSwitchResponseDTO(String fulfilment, LocalDateTime completedTimestamp, TransferState transferState, + ExtensionList extensionList) { + this.fulfilment = fulfilment; + this.completedTimestamp = ContextUtil.formatDate(completedTimestamp); + this.transferState = transferState; + this.extensionList = extensionList; + } + + public TransferSwitchResponseDTO(TransferState transferState) { + this(null, null, transferState, null); + } + + public String getFulfilment() { + return fulfilment; + } + + public void setFulfilment(String fulfilment) { + this.fulfilment = fulfilment; + } + + public String getCompletedTimestamp() { + return completedTimestamp; + } + + public void setCompletedTimestamp(String completedTimestamp) { + this.completedTimestamp = completedTimestamp; + } + + public TransferState getTransferState() { + return transferState; + } + + public void setTransferState(TransferState transferState) { + this.transferState = transferState; + } + + public ExtensionList getExtensionList() { + return extensionList; + } + + public void setExtensionList(ExtensionList extensionList) { + this.extensionList = extensionList; + } +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/mojaloop/ilp/CodecContextFactory.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/mojaloop/ilp/CodecContextFactory.java new file mode 100644 index 000000000..d8c26ac5b --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/mojaloop/ilp/CodecContextFactory.java @@ -0,0 +1,45 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla + * Public License, v. 2.0. If a copy of the MPL was not distributed + * with this file, You can obtain one at + * + * https://mozilla.org/MPL/2.0/. + */ +package org.mifos.connector.common.mojaloop.ilp; + +// public class CodecContextFactory { +// +// public static CodecContext interledger() { +// return (new CodecContext()) +// .register(OerUint8Codec.OerUint8.class, new OerUint8Codec()) +// .register(OerUint32Codec.OerUint32.class, new OerUint32Codec()) +// .register(OerUint64Codec.OerUint64.class, new OerUint64Codec()) +// .register(OerUint256Codec.OerUint256.class, new OerUint256Codec()) +// .register(OerLengthPrefixCodec.OerLengthPrefix.class, new OerLengthPrefixCodec()) +// .register(OerIA5StringCodec.OerIA5String.class, new OerIA5StringCodec()) +// .register(OerOctetStringCodec.OerOctetString.class, new OerOctetStringCodec()) +// .register(OerGeneralizedTimeCodec.OerGeneralizedTime.class, new OerGeneralizedTimeCodec()) +// .register(InterledgerAddress.class, new InterledgerAddressOerCodec()) +// .register(InterledgerPacketType.class, new InterledgerPacketTypeOerCodec()) +// .register(org.interledger.ilp.InterledgerPayment.class, new +// org.interledger.codecs.oer.ilp.InterledgerPaymentOerCodec()) +// .register(InterledgerPaymentRequest.class, new InterledgerPaymentRequestOerCodec()) +// .register(Condition.class, new ConditionOerCodec()) +// .register(QuoteByDestinationAmountRequest.class, new QuoteByDestinationAmountRequestOerCodec()) +// .register(QuoteByDestinationAmountResponse.class, new QuoteByDestinationAmountResponseOerCodec()) +// .register(QuoteBySourceAmountRequest.class, new QuoteBySourceAmountRequestOerCodec()) +// .register(QuoteBySourceAmountResponse.class, new QuoteBySourceAmountResponseOerCodec()) +// .register(QuoteLiquidityRequest.class, new QuoteLiquidityRequestOerCodec()) +// .register(QuoteLiquidityResponse.class, new QuoteLiquidityResponseOerCodec()) +// .register(PskMessage.class, new PskMessageBinaryCodec()) +// .register(InterledgerPayment.class, new InterledgerPaymentOerCodec()); +// } +// +// public static CodecContext interledgerJson() { +// throw new RuntimeException("Not yet implemented!"); +// } +// +// public static CodecContext interledgerProtobuf() { +// throw new RuntimeException("Not yet implemented!"); +// } +// } diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/mojaloop/ilp/Ilp.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/mojaloop/ilp/Ilp.java new file mode 100644 index 000000000..8cc2d6123 --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/mojaloop/ilp/Ilp.java @@ -0,0 +1,66 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla + * Public License, v. 2.0. If a copy of the MPL was not distributed + * with this file, You can obtain one at + * + * https://mozilla.org/MPL/2.0/. + */ +package org.mifos.connector.common.mojaloop.ilp; + +// +// +// public class Ilp { +// +// private final String packet; // mandatory +// private final String condition; // mandatory +// private final String fulfilment; // optional +// private final Transaction transaction; // mandatory +// +// public Ilp(String packet, String condition, String fulfilment, Transaction transaction) { +// this.packet = packet; +// this.condition = condition; +// this.fulfilment = fulfilment; +// this.transaction = transaction; +// } +// +// public Ilp(String packet, String condition, Transaction transaction) { +// this(packet, condition, null, transaction); +// } +// +// public String getPacket() { +// return packet; +// } +// +// public String getCondition() { +// return condition; +// } +// +// public String getFulfilment() { +// return fulfilment; +// } +// +// public Transaction getTransaction() { +// return transaction; +// } +// +// void update(Ilp oIlp) { +// if (oIlp == null) +// return; +// if (!packet.equals(oIlp.getPacket())) +// throw new RuntimeException("Ilp packet is not valid " + packet + " vs." + oIlp.getPacket()); +// if (!condition.equals(oIlp.getCondition())) +// throw new RuntimeException("Ilp condition is not valid " + packet + " vs." + oIlp.getPacket()); +// if (fulfilment != null && oIlp.getFulfilment() != null && !fulfilment.equals(oIlp.getFulfilment())) +// throw new RuntimeException("Ilp fulfilment is not valid " + fulfilment + " vs." + oIlp.getFulfilment()); +// +// } +// +// @Override +// public String toString() { +// return "Ilp{" + +// "packet:'" + packet + '\'' + +// ", condition:'" + condition + '\'' + +// ", fulfilment:'" + fulfilment + '\'' + +// '}'; +// } +// } diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/mojaloop/ilp/InterledgerPayment.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/mojaloop/ilp/InterledgerPayment.java new file mode 100644 index 000000000..7723c026f --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/mojaloop/ilp/InterledgerPayment.java @@ -0,0 +1,104 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla + * Public License, v. 2.0. If a copy of the MPL was not distributed + * with this file, You can obtain one at + * + * https://mozilla.org/MPL/2.0/. + */ +package org.mifos.connector.common.mojaloop.ilp; + +import java.util.Arrays; +import java.util.Objects; + +public interface InterledgerPayment { + // extends InterledgerPacket + + // static InterledgerPayment.Builder builder() { + // return new InterledgerPayment.Builder(); + // } + + // InterledgerAddress getDestinationAccount(); + + String getDestinationAmount(); + + byte[] getData(); + + class Builder { + + // private InterledgerAddress destinationAccount; + private String destinationAmount; + private byte[] data; + + public Builder() {} + + // public InterledgerPayment.Builder destinationAccount(InterledgerAddress destinationAccount) { + // this.destinationAccount = (InterledgerAddress)Objects.requireNonNull(destinationAccount); + // return this; + // } + + public InterledgerPayment.Builder destinationAmount(String destinationAmount) { + this.destinationAmount = (String) Objects.requireNonNull(destinationAmount); + return this; + } + + public InterledgerPayment.Builder data(byte[] data) { + this.data = (byte[]) Objects.requireNonNull(data); + return this; + } + + public InterledgerPayment build() { + return new InterledgerPayment.Builder.Impl(this); + } + + private static final class Impl implements InterledgerPayment { + + // private final InterledgerAddress destinationAccount; + private final String destinationAmount; + private final byte[] data; + + private Impl(InterledgerPayment.Builder builder) { + Objects.requireNonNull(builder); + // this.destinationAccount = (InterledgerAddress)Objects.requireNonNull(builder.destinationAccount, + // "destinationAccount must not be null!"); + this.destinationAmount = (String) Objects.requireNonNull(builder.destinationAmount, "destinationAmount must not be null!"); + this.data = (byte[]) Objects.requireNonNull(builder.data, "data must not be null!"); + } + + // public InterledgerAddress getDestinationAccount() { + // return this.destinationAccount; + // } + + public String getDestinationAmount() { + return this.destinationAmount; + } + + public byte[] getData() { + return Arrays.copyOf(this.data, this.data.length); + } + + // public boolean equals(Object obj) { + // if (this == obj) { + // return true; + // } else if (obj != null && this.getClass() == obj.getClass()) { + // InterledgerPayment.Builder.Impl impl = (InterledgerPayment.Builder.Impl)obj; + // return this.destinationAccount.equals(impl.destinationAccount) && + // this.destinationAmount.equals(impl.destinationAmount) && Arrays.equals(this.data, impl.data); + // } else { + // return false; + // } + // } + // + // public int hashCode() { + // int result = this.destinationAccount.hashCode(); + // result = 31 * result + this.destinationAmount.hashCode(); + // result = 31 * result + Arrays.hashCode(this.data); + // return result; + // } + + // public String toString() { + // return "InterledgerPayment.Impl{destinationAccount=" + this.destinationAccount + ", destinationAmount=" + + // this.destinationAmount + ", data=" + Arrays.toString(this.data) + '}'; + // } + } + } +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/mojaloop/ilp/InterledgerPaymentCodec.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/mojaloop/ilp/InterledgerPaymentCodec.java new file mode 100644 index 000000000..ee084a861 --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/mojaloop/ilp/InterledgerPaymentCodec.java @@ -0,0 +1,16 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla + * Public License, v. 2.0. If a copy of the MPL was not distributed + * with this file, You can obtain one at + * + * https://mozilla.org/MPL/2.0/. + */ +package org.mifos.connector.common.mojaloop.ilp; + +// public interface InterledgerPaymentCodec extends InterledgerPacketCodec { +// InterledgerPacketType TYPE = new PaymentPacketType(); +// +// default InterledgerPacketType getTypeId() { +// return TYPE; +// } +// } diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/mojaloop/ilp/InterledgerPaymentOerCodec.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/mojaloop/ilp/InterledgerPaymentOerCodec.java new file mode 100644 index 000000000..0936b7e4b --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/mojaloop/ilp/InterledgerPaymentOerCodec.java @@ -0,0 +1,35 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla + * Public License, v. 2.0. If a copy of the MPL was not distributed + * with this file, You can obtain one at + * + * https://mozilla.org/MPL/2.0/. + */ +package org.mifos.connector.common.mojaloop.ilp; + +// public class InterledgerPaymentOerCodec implements InterledgerPaymentCodec { +// public InterledgerPaymentOerCodec() { +// } +// +// public InterledgerPayment read(CodecContext context, InputStream inputStream) throws IOException { +// Objects.requireNonNull(context); +// Objects.requireNonNull(inputStream); +// String destinationAmount = context.read(OerIA5StringCodec.OerIA5String.class, inputStream).getValue(); +// InterledgerAddress destinationAccount = context.read(InterledgerAddress.class, inputStream); +// byte[] data = context.read(OerOctetStringCodec.OerOctetString.class, inputStream).getValue(); +// return +// InterledgerPayment.builder().destinationAmount(destinationAmount).destinationAccount(destinationAccount).data(data).build(); +// } +// +// public void write(CodecContext context, InterledgerPayment instance, OutputStream outputStream) throws IOException { +// Objects.requireNonNull(context); +// Objects.requireNonNull(instance); +// Objects.requireNonNull(outputStream); +// context.write(InterledgerPacketType.class, this.getTypeId(), outputStream); +// context.write(OerIA5StringCodec.OerIA5String.class, new +// OerIA5StringCodec.OerIA5String(instance.getDestinationAmount()), outputStream); +// context.write(InterledgerAddress.class, instance.getDestinationAccount(), outputStream); +// context.write(OerOctetStringCodec.OerOctetString.class, new OerOctetStringCodec.OerOctetString(instance.getData()), +// outputStream); +// } +// } diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/mojaloop/type/AmountType.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/mojaloop/type/AmountType.java new file mode 100644 index 000000000..195e2001c --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/mojaloop/type/AmountType.java @@ -0,0 +1,13 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla + * Public License, v. 2.0. If a copy of the MPL was not distributed + * with this file, You can obtain one at + * + * https://mozilla.org/MPL/2.0/. + */ +package org.mifos.connector.common.mojaloop.type; + +public enum AmountType { + + SEND, RECEIVE; +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/mojaloop/type/AuthenticationType.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/mojaloop/type/AuthenticationType.java new file mode 100644 index 000000000..d12e3e32a --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/mojaloop/type/AuthenticationType.java @@ -0,0 +1,13 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla + * Public License, v. 2.0. If a copy of the MPL was not distributed + * with this file, You can obtain one at + * + * https://mozilla.org/MPL/2.0/. + */ +package org.mifos.connector.common.mojaloop.type; + +public enum AuthenticationType { + + OTP, QRCODE; +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/mojaloop/type/ErrorCode.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/mojaloop/type/ErrorCode.java new file mode 100644 index 000000000..4e279f1f2 --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/mojaloop/type/ErrorCode.java @@ -0,0 +1,135 @@ +package org.mifos.connector.common.mojaloop.type; + +import java.util.Arrays; + +/** + * Error code format: (Higher-level category)(Lower-level category)(Sepcific error) 1 digit 1 digit 2 digit + */ +public enum ErrorCode { + + // callback errors from mojaloop to fsp + COMMUNICATION_ERROR(1000, "Generic communication error."), DESTINATION_COMMUNICATION_ERROR(1001, + "Destination of the request failed to be reached. This usually indicates that a Peer FSP failed to respond from an intermediate entity."), + + // server side errors from fsp + GENERIC_SERVER_ERROR(2000, + "Generic server error to be used in order not to disclose information that may be considered private."), INTERNAL_SERVER_ERROR( + 2001, "Generic unexpected exception. This usually indicates a bug or unhandled error case."), NOT_IMPLEMENTED(2002, + "Service requested is not supported by the server."), SERVICE_CURRENTLY_UNAVAILABLE(2003, + "Service requested is currently unavailable on the server. This could be because maintenance is taking place, or because of a temporary failure."), SERVER_TIMED_OUT( + 2004, + "Timeout has occurred, meaning the next Party in the chain did not send a callback in time. This could be because a timeout is set too low or because something took longer than expected."), SERVER_BUSY( + 2005, "Server is rejecting requests due to overloading. Try again later."), + + // (client) mojaloop errors + GENERIC_CLIENT_ERROR(3000, + "Generic client error, used in order not to disclose information that may be considered private."), UNACCEPTABLE_VERSION_REQUESTED( + 3001, "Client requested to use a protocol version which is not supported by the server."), UNKNOWN_URI(3002, + "Provided URI was unknown to the server."), ADD_PARTY_INFORMATION_ERROR(3003, + "Error occurred while adding or updating information regarding a Party."), GENERIC_VALIDATION_ERROR( + 3100, + "Generic validation error to be used in order not to disclose information that may be considered private."), MALFORMED_SYNTAX( + 3101, + "Format of the parameter is not valid. For example, amount set to 5.ABC. The error description field should specify which information element is erroneous."), MISSING_MANDATORY_ELEMENT( + 3102, + "Mandatory element in the data model was missing."), TOO_MANY_ELEMENTS(3103, + "Number of elements of an array exceeds the maximum number allowed."), TOO_LARGE_PAYLOAD( + 3104, + "Size of the payload exceeds the maximum size."), INVALID_SIGNATURE( + 3105, + "Some parameters have changed in the message, making the signature invalid. This may indicate that the message may have been modified maliciously."), MODIFIED_REQUEST( + 3106, + "Request with the same ID has previously been processed in which the parameters are not the same."), MISSING_MANDATORY_EXTENSION_PARAMETER( + 3107, + "Scheme-mandatory extension parameter was missing."), GENERIC_ID_NOT_FOUND( + 3200, + "Generic ID error provided by the client."), DESTINATION_FSP_ERROR( + 3201, + "Destination FSP does not exist or cannot be found."), PAYER_FSP_ID_NOT_FOUND( + 3202, + "Provided Payer FSP ID not found."), PAYEE_FSP_ID_NOT_FOUND( + 3203, + "Provided Payee FSP ID not found."), PARTY_NOT_FOUND( + 3204, + "Party with the provided identifier, identifier type, and optional sub id or type was not found."), QUOTE_ID_NOT_FOUND( + 3205, + "Provided Quote ID was not found on the server."), TRANSACTION_REQUEST_ID_NOT_FOUND( + 3206, + "Provided Transaction Request ID was not found on the server."), TRANSACTION_ID_NOT_FOUND( + 3207, + "Provided Transaction ID was not found on the server."), TRANSFER_ID_NOT_FOUND( + 3208, + "Provided Transfer ID was not found on the server."), BULK_QUOTE_ID_NOT_FOUND( + 3209, + "Provided Bulk Quote ID was not found on the server."), BULK_TRANSFER_ID_NOT_FOUND( + 3210, + "Provided Bulk Transfer ID was not found on the server."), GENERIC_EXPIRED_ERROR( + 3300, + "Generic expired object error, to be used in order not to disclose information that may be considered private."), TRANSACTION_REQUEST_EXPIRED( + 3301, + "Client requested to use a transaction request that has already expired."), QUOTE_EXPIRED( + 3302, + "Client requested to use a quote that has already expired."), TRANSFER_EXPIRED( + 3303, + "Client requested to use a transfer that has already expired."), + + // payer side business error + GENERIC_PAYER_ERROR(4000, + "Generic error related to the Payer or Payer FSP. Used for protecting information that may be considered private."), PAYER_FSP_INSUFFICIENT_LIQUIDITY( + 4001, "Payer FSP has insufficient liquidity to perform the transfer."), GENERIC_PAYER_REJECTION(4100, + "Payer or Payer FSP rejected the request."), PAYER_REJECTED_TRANSACTION_REQUEST(4101, + "Payer rejected the transaction request from the Payee."), PAYER_FSP_UNSUPPORTED_TRANSACTION_TYPE(4102, + "Payer FSP does not support or rejected the requested transaction type"), PAYER_UNSUPPORTED_CURRENCY( + 4103, + "Payer does not have an account which supports the requested currency."), PAYER_LIMIT_ERROR( + 4200, + "Generic limit error, for example, the Payer is making more payments per day or per month than they are allowed to, or is making a payment which is larger than the allowed maximum per transaction."), PAYER_PERMISSION_ERROR( + 4300, + "Generic permission error, the Payer or Payer FSP does not have the access rights to perform the service."), GENERIC_PAYER_BLOCKED_ERROR( + 4400, + "Generic Payer blocked error; the Payer is blocked or has failed regulatory screenings."), + + // payee side business error + GENERIC_PAYEE_ERROR(5000, + "Generic error due to the Payer or Payer FSP, to be used in order not to disclose information that may be considered private."), PAYEE_FSP_INSUFFICIENT_LIQUIDITY( + 5001, "Payee FSP has insufficient liquidity to perform the transfer."), GENERIC_PAYEE_REJECTION(5100, + "Payee or Payee FSP rejected the request."), PAYEE_REJECTED_QUOTE(5101, + "Payee does not want to proceed with the financial transaction after receiving a quote."), PAYEE_FSP_UNSUPPORTED_TRANSACTION_TYPE( + 5102, + "Payee FSP does not support or has rejected the requested transaction type."), PAYEE_FSP_REJECTED_QUOTE( + 5103, + "Payee FSP does not want to proceed with the financial transaction after receiving a quote."), PAYEE_REJECTED_TRANSACTION( + 5104, + "Payee rejected the financial transaction."), PAYEE_FSP_REJECTED_TRANSACTION( + 5105, + "Payee FSP rejected the financial transaction."), PAYEE_UNSUPPORTED_CURRENCY( + 5106, + "Payee does not have an account that supports the requested currency."), PAYEE_LIMIT_ERROR( + 5200, + "Generic limit error, for example, the Payee is receiving more payments per day or per month than they are allowed to, or is receiving a payment that is larger than the allowed maximum per transaction."), PAYEE_PERMISSION_ERROR( + 5300, + "Generic permission error, the Payee or Payee FSP does not have the access rights to perform the service."), GENERIC_PAYEE_BLOCKED_ERROR( + 5400, + "Generic Payee Blocked error, the Payee is blocked or has failed regulatory screenings."); + + private int code; + private String errorMessage; + + ErrorCode(int code, String errorMessage) { + this.code = code; + this.errorMessage = errorMessage; + } + + public int getCode() { + return code; + } + + public String getErrorMessage() { + return errorMessage; + } + + public static ErrorCode fromCode(int code) { + return Arrays.stream(values()).filter(ec -> ec.getCode() == code).findFirst() + .orElseThrow(() -> new RuntimeException("Can not get unknown errorCode: " + code)); + } +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/mojaloop/type/IdentifierType.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/mojaloop/type/IdentifierType.java new file mode 100644 index 000000000..7929c5031 --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/mojaloop/type/IdentifierType.java @@ -0,0 +1,15 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla + * Public License, v. 2.0. If a copy of the MPL was not distributed + * with this file, You can obtain one at + * + * https://mozilla.org/MPL/2.0/. + */ +package org.mifos.connector.common.mojaloop.type; + +public enum IdentifierType { + + MSISDN, EMAIL, PERSONAL_ID, BUSINESS, DEVICE, ACCOUNT_ID, IBAN, ALIAS; + + public static final String[] REGEX_VALUES = { "a" }; +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/mojaloop/type/InitiatorType.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/mojaloop/type/InitiatorType.java new file mode 100644 index 000000000..7a9cdf61c --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/mojaloop/type/InitiatorType.java @@ -0,0 +1,13 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla + * Public License, v. 2.0. If a copy of the MPL was not distributed + * with this file, You can obtain one at + * + * https://mozilla.org/MPL/2.0/. + */ +package org.mifos.connector.common.mojaloop.type; + +public enum InitiatorType { + + CONSUMER, AGENT, BUSINESS, DEVICE; +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/mojaloop/type/InteroperabilityType.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/mojaloop/type/InteroperabilityType.java new file mode 100644 index 000000000..ff3e5db4d --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/mojaloop/type/InteroperabilityType.java @@ -0,0 +1,30 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla + * Public License, v. 2.0. If a copy of the MPL was not distributed + * with this file, You can obtain one at + * + * https://mozilla.org/MPL/2.0/. + */ +package org.mifos.connector.common.mojaloop.type; + +public enum InteroperabilityType { + + PARTIES_CONTENT_TYPE("application/vnd.interoperability.parties+json;version=1.0"), PARTIES_ACCEPT_TYPE( + "application/vnd.interoperability.parties+json;version=1.0"), QUOTES_CONTENT_TYPE( + "application/vnd.interoperability.quotes+json;version=1.0"), QUOTES_ACCEPT_TYPE( + "application/vnd.interoperability.quotes+json;version=1.0"), TRANSFERS_CONTENT_TYPE( + "application/vnd.interoperability.transfers+json;version=1.0"), TRANSFERS_ACCEPT_TYPE( + "application/vnd.interoperability.transfers+json;version=1.0"), TRANSACTIONS_CONTENT_TYPE( + "application/vnd.interoperability.transactionRequests+json;version=1.0"), TRANSACTIONS_ACCEPT_TYPE( + "application/vnd.interoperability.transactionRequests+json;version=1.0"); + + private String headerValue; + + InteroperabilityType(String headerValue) { + this.headerValue = headerValue; + } + + public String headerValue() { + return this.headerValue; + } +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/mojaloop/type/MojaloopHeaders.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/mojaloop/type/MojaloopHeaders.java new file mode 100644 index 000000000..afea9e5f6 --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/mojaloop/type/MojaloopHeaders.java @@ -0,0 +1,16 @@ +package org.mifos.connector.common.mojaloop.type; + +public enum MojaloopHeaders { + + FSPIOP_SOURCE("fspiop-source"), FSPIOP_DESTINATION("fspiop-destination"); + + private String headerName; + + MojaloopHeaders(String headerName) { + this.headerName = headerName; + } + + public String headerName() { + return this.headerName; + } +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/mojaloop/type/Scenario.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/mojaloop/type/Scenario.java new file mode 100644 index 000000000..a8736103b --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/mojaloop/type/Scenario.java @@ -0,0 +1,13 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla + * Public License, v. 2.0. If a copy of the MPL was not distributed + * with this file, You can obtain one at + * + * https://mozilla.org/MPL/2.0/. + */ +package org.mifos.connector.common.mojaloop.type; + +public enum Scenario { + + DEPOSIT, WITHDRAWAL, TRANSFER, PAYMENT, REFUND, MPESA; +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/mojaloop/type/TransactionRequestState.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/mojaloop/type/TransactionRequestState.java new file mode 100644 index 000000000..431cb1398 --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/mojaloop/type/TransactionRequestState.java @@ -0,0 +1,13 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla + * Public License, v. 2.0. If a copy of the MPL was not distributed + * with this file, You can obtain one at + * + * https://mozilla.org/MPL/2.0/. + */ +package org.mifos.connector.common.mojaloop.type; + +public enum TransactionRequestState { + + RECEIVED, PENDING, ACCEPTED, REJECTED; +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/mojaloop/type/TransactionRole.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/mojaloop/type/TransactionRole.java new file mode 100644 index 000000000..57069bada --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/mojaloop/type/TransactionRole.java @@ -0,0 +1,15 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla + * Public License, v. 2.0. If a copy of the MPL was not distributed + * with this file, You can obtain one at + * + * https://mozilla.org/MPL/2.0/. + */ +package org.mifos.connector.common.mojaloop.type; + +public enum TransactionRole { + + PAYER, PAYEE; + + public static TransactionRole[] VALUES = values(); +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/mojaloop/type/TransferState.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/mojaloop/type/TransferState.java new file mode 100644 index 000000000..f19af4275 --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/mojaloop/type/TransferState.java @@ -0,0 +1,13 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla + * Public License, v. 2.0. If a copy of the MPL was not distributed + * with this file, You can obtain one at + * + * https://mozilla.org/MPL/2.0/. + */ +package org.mifos.connector.common.mojaloop.type; + +public enum TransferState { + + RECEIVED, RESERVED, COMMITTED, ABORTED; +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/operations/dto/Transfer.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/operations/dto/Transfer.java new file mode 100644 index 000000000..270b4a44f --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/operations/dto/Transfer.java @@ -0,0 +1,43 @@ +package org.mifos.connector.common.operations.dto; + +import java.math.BigDecimal; +import java.util.Date; + +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import org.mifos.connector.common.operations.type.TransferStatus; + +@Getter +@Setter +@NoArgsConstructor +public class Transfer { + + private Long workflowInstanceKey; + private String transactionId; + private Date startedAt; + private Date completedAt; + private TransferStatus status; + private String statusDetail; + private String payeeDfspId; + private String payeePartyId; + private String payeePartyIdType; + private BigDecimal payeeFee; + private String payeeFeeCurrency; + private String payeeQuoteCode; + private String payerDfspId; + private String payerPartyId; + private String payerPartyIdType; + private BigDecimal payerFee; + private String payerFeeCurrency; + private String payerQuoteCode; + private BigDecimal amount; + private String currency; + private String direction; + + private String errorInformation; + + private String batchId; + + private String clientCorrelationId; +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/operations/type/TransferStatus.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/operations/type/TransferStatus.java new file mode 100644 index 000000000..433f31b3d --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/operations/type/TransferStatus.java @@ -0,0 +1,5 @@ +package org.mifos.connector.common.operations.type; + +public enum TransferStatus { + COMPLETED, FAILED, IN_PROGRESS, UNKNOWN +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/util/CertificateUtil.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/util/CertificateUtil.java new file mode 100644 index 000000000..4ca01dd10 --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/util/CertificateUtil.java @@ -0,0 +1,56 @@ +package org.mifos.connector.common.util; + +import java.io.ByteArrayInputStream; +import java.io.InputStream; +import java.nio.charset.Charset; +import java.security.PublicKey; +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; +import org.apache.commons.codec.binary.Base64; + +public final class CertificateUtil { + + private CertificateUtil() {} + + /** + * Parses the public key from X509 certificate and returns it in form of string + * + * @param encodedCertificate + * the base64 encoded string of X509 certificate + * @return public key in form of string + * @throws CertificateException + * error thrown in case of invalid certificate + */ + public static String getPublicKey(String encodedCertificate) throws CertificateException { + X509Certificate certificate = parseX509Certificate(encodedCertificate); + PublicKey publicKey = parseRSAPublicKey(certificate); + return new String(Base64.encodeBase64(publicKey.getEncoded()), Charset.defaultCharset()); + } + + /** + * Takes the base64 encoded string of certificate and returns the instance of the X509Certificate class + * + * @param encodedCertificate + * the base64 encoded string of certificate + * @return [X509Certificate] the instance of X509Certificate class + */ + public static X509Certificate parseX509Certificate(String encodedCertificate) throws CertificateException { + byte[] certificateBytes = Base64.decodeBase64(encodedCertificate); + InputStream in = new ByteArrayInputStream(certificateBytes); + CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509"); + return (X509Certificate) certificateFactory.generateCertificate(in); + } + + /** + * Takes the X509Certificate certificate object and extracts the public key from it + * + * @param certificate + * the instance of X509Certificate + * @return [PublicKey] the instance of PublicKey class + */ + public static PublicKey parseRSAPublicKey(X509Certificate certificate) { + return certificate.getPublicKey(); + } + +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/util/Constant.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/util/Constant.java new file mode 100644 index 000000000..d84e90cbf --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/util/Constant.java @@ -0,0 +1,12 @@ +package org.mifos.connector.common.util; + +public final class Constant { + + private Constant() {} + + public static String HEADER_JWS = "X-SIGNATURE"; + public static String HEADER_PLATFORM_TENANT_ID = "Platform-TenantId"; + public static final String HEADER_CORRELATION_ID = "X-CorrelationID"; + public static String REST_REQUEST_DATA_SEPARATOR = ":"; + +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/util/ContextUtil.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/util/ContextUtil.java new file mode 100644 index 000000000..1a2cef7ea --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/util/ContextUtil.java @@ -0,0 +1,67 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla + * Public License, v. 2.0. If a copy of the MPL was not distributed + * with this file, You can obtain one at + * + * https://mozilla.org/MPL/2.0/. + */ +package org.mifos.connector.common.util; + +import java.math.BigDecimal; +import java.text.DecimalFormat; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.time.Instant; +import java.time.LocalDateTime; +import java.time.ZoneOffset; +import java.util.Date; +import java.util.Locale; +import java.util.TimeZone; + +public final class ContextUtil { + + private ContextUtil() {} + + private static final SimpleDateFormat LOCAL_DATE_TIME_FORMAT = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXXX"); + private static final DecimalFormat AMOUNT_FORMAT = new DecimalFormat("#.####"); + private static final SimpleDateFormat DATE_HEADER_FORMATTER = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z", Locale.ENGLISH); + + public static LocalDateTime parseDate(String date) { + if (date == null) { + return null; + } + try { + return LocalDateTime.ofInstant(Instant.ofEpochMilli(LOCAL_DATE_TIME_FORMAT.parse(date).getTime()), ZoneOffset.UTC); + } catch (ParseException e) { + throw new RuntimeException(e); + } + } + + public static LocalDateTime parseMojaDate(String date) { + if (date == null) { + return null; + } + try { + return LocalDateTime.ofInstant(Instant.ofEpochMilli(DATE_HEADER_FORMATTER.parse(date).getTime()), ZoneOffset.UTC); + } catch (ParseException e) { + throw new RuntimeException(e); + } + } + + public static String formatToDateHeader(long date) { + DATE_HEADER_FORMATTER.setTimeZone(TimeZone.getTimeZone("GMT")); + return DATE_HEADER_FORMATTER.format(Date.from(Instant.ofEpochMilli(date))); + } + + public static String formatDate(LocalDateTime date) { + return date == null ? null : LOCAL_DATE_TIME_FORMAT.format(Date.from(date.toInstant(ZoneOffset.UTC))); + } + + public static BigDecimal parseAmount(String amount) { + return amount == null ? null : new BigDecimal(amount); + } + + public static String formatAmount(BigDecimal amount) { + return amount == null ? null : AMOUNT_FORMAT.format(amount); + } +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/util/JsonWebSignature.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/util/JsonWebSignature.java new file mode 100644 index 000000000..6f9d43c27 --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/util/JsonWebSignature.java @@ -0,0 +1,195 @@ +package org.mifos.connector.common.util; + +import lombok.Getter; +import org.springframework.util.StringUtils; +import javax.crypto.BadPaddingException; +import javax.crypto.IllegalBlockSizeException; +import javax.crypto.NoSuchPaddingException; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.security.spec.InvalidKeySpecException; +import java.util.UUID; + +/** + * This class represents a JSON Web Signature (JWS) object. It contains a hashed data field and a method to generate a + * signature using a private key. + * + * Usage example: + * + * JsonWebSignatureBuilder jwsBuilder = new JsonWebSignature.JsonWebSignatureBuilder(); + * jwsBuilder.setClientCorrelationId(clientCorrelationId) + * jwsBuilder.setTenantId(tenantId) + * jwsBuilder.setData(absoluteFilePath); + * + * JsonWebSignature jwsSignature = jwsBuilder.build(); + * + * String signature = jwsSignature.getSignature(privateKey); + * + */ +@Getter +public class JsonWebSignature { + + /** + * The hashed data used in the JWS object. + */ + private String data; + + /** + * Generates a signature using a private key. + * + * @param privateKey the private key used to generate the signature + * @return the generated signature + * @throws NoSuchPaddingException if the padding algorithm is not available + * @throws IllegalBlockSizeException if the block size is not valid for this encryption algorithm + * @throws NoSuchAlgorithmException if the encryption algorithm is not available + * @throws BadPaddingException if the padding is invalid + * @throws InvalidKeySpecException if the key specification is invalid + * @throws InvalidKeyException if the key is invalid + */ + public String getSignature(String privateKey) throws NoSuchPaddingException, IllegalBlockSizeException, + NoSuchAlgorithmException, BadPaddingException, InvalidKeySpecException, InvalidKeyException { + return SecurityUtil.encryptUsingPrivateKey(this.data, privateKey); + } + + /** + * This class provides a builder for creating a JSON Web Signature (JWS) object. + */ + public static class JsonWebSignatureBuilder { + + /** + * The batch ID used in the JWS object. + */ + private String batchId; + /** + * The client correlation ID used in the JWS object. + */ + private String clientCorrelationId; + /** + * The tenant ID used in the JWS object. + */ + private String tenantId; + /** + * The data used in the JWS object. + */ + private String data; + /** + * A flag indicating whether the data is a file. + */ + private boolean isDataAFile = false; + /** + * The JWS data separator used to separate the JWS header and payload. + */ + protected static String jwsDataSeparator = ":"; + + /** + * Sets the batch ID for the JWS object. + * + * @param batchId The batch ID to set. + * @return This builder object. + */ + public JsonWebSignatureBuilder setBatchId(String batchId) { + this.batchId = batchId; + return this; + } + + /** + * Sets the client correlation ID for the JWS object. + * + * @param clientCorrelationId The client correlation ID to set. + * @return This builder object. + */ + public JsonWebSignatureBuilder setClientCorrelationId(String clientCorrelationId) { + this.clientCorrelationId = clientCorrelationId; + return this; + } + + /** + * Sets the tenant ID for the JWS object. + * + * @param tenantId The tenant ID to set. + * @return This builder object. + */ + public JsonWebSignatureBuilder setTenantId(String tenantId) { + this.tenantId = tenantId; + return this; + } + + /** + * Sets the data/filepath for the JWS object. + * In case of file, make sure to pass the absolute file path + * + * @param data The data to set. + * @return This builder object. + */ + public JsonWebSignatureBuilder setData(String data) { + this.data = data; + return this; + } + + /** + * Sets whether the data is a file or not. + * + * @param isDataAFile Whether the data is a file or not. + * @return This builder object. + */ + public JsonWebSignatureBuilder setIsDataAsFile(boolean isDataAFile) { + this.isDataAFile = isDataAFile; + return this; + } + + /** + * Builds the JWS object using the provided parameters. + * + * @return The JWS object. + * @throws IOException If an error occurs while reading the file data. + */ + public JsonWebSignature build() throws IOException { + JsonWebSignature jsonWebSignature = new JsonWebSignature(); + jsonWebSignature.data = SecurityUtil.hash(getDataToBeHashed()); + return jsonWebSignature; + } + + /** + * Gets the data to be hashed for the JWS object. + * + * @return The data to be hashed. + * @throws IOException If an error occurs while reading the file data. + */ + private String getDataToBeHashed() throws IOException { + StringBuilder jwsDataToBeHashedBuilder = new StringBuilder(); + + if (!StringUtils.hasText(this.batchId) && !StringUtils.hasText(this.clientCorrelationId) && + !StringUtils.hasText(this.tenantId) && !StringUtils.hasText(this.data)) { + throw new RuntimeException("Signature must contain at least one identifier among " + + "[batchId, clientCorrelationId, tenantId, data/filepath]"); + } + + if (StringUtils.hasText(this.batchId)) { + jwsDataToBeHashedBuilder.append(this.batchId).append(JsonWebSignatureBuilder.jwsDataSeparator); + } + + if (StringUtils.hasText(this.clientCorrelationId)) { + jwsDataToBeHashedBuilder.append(this.clientCorrelationId).append(JsonWebSignatureBuilder.jwsDataSeparator); + } + + if (StringUtils.hasText(this.tenantId)) { + jwsDataToBeHashedBuilder.append(this.tenantId).append(JsonWebSignatureBuilder.jwsDataSeparator); + } + + if (StringUtils.hasText(this.data)) { + if (isDataAFile) { + String fileContent = Files.readString(Paths.get(data)); + jwsDataToBeHashedBuilder.append(fileContent).append(JsonWebSignatureBuilder.jwsDataSeparator); + } else { + jwsDataToBeHashedBuilder.append(data).append(JsonWebSignatureBuilder.jwsDataSeparator); + } + } + + // remove the last "separator" and return the string + return jwsDataToBeHashedBuilder.substring(0, jwsDataToBeHashedBuilder.length()-1); + } + } +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/util/MpesaUtils.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/util/MpesaUtils.java new file mode 100644 index 000000000..c1806d011 --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/util/MpesaUtils.java @@ -0,0 +1,60 @@ +package org.mifos.connector.common.util; + +import org.json.JSONArray; +import org.json.JSONObject; + +public final class MpesaUtils { + + private MpesaUtils() {} + + public static String mpesaChannelRequestToChannelRequestConvertor(String channelRequest) { + + JSONObject mpesaChannelRequestJson = new JSONObject(); + + JSONObject channelRequestJson = new JSONObject(channelRequest); + + JSONObject amountJson = channelRequestJson.getJSONObject("amount"); + JSONArray payerArray = channelRequestJson.getJSONArray("payer"); + + // setting amount json + mpesaChannelRequestJson.put("amount", amountJson); + + String payer; + String payee; + + // payer payee conversion + if (((JSONObject) payerArray.get(0)).getString("key").equals("MSISDN")) { + // case when 0th index is MSISDN + String msisdn = ((JSONObject) payerArray.get(0)).getString("value"); + String accountId = ((JSONObject) payerArray.get(1)).getString("value"); + + payer = ((JSONObject) payerArray.get(0)).getString("key") + " " + msisdn; + payee = ((JSONObject) payerArray.get(1)).getString("key") + " " + accountId; + } else { + // case when 0th index is ACCOUNTID + String msisdn = ((JSONObject) payerArray.get(1)).getString("value"); + String accountId = ((JSONObject) payerArray.get(0)).getString("value"); + + payer = ((JSONObject) payerArray.get(1)).getString("key") + " " + msisdn; + payee = ((JSONObject) payerArray.get(0)).getString("key") + " " + accountId; + } + + // setting payer and payee + mpesaChannelRequestJson.put("payer", getPartyInfoJson(payer.split(" ")[0], payer.split(" ")[1])); + + mpesaChannelRequestJson.put("payee", getPartyInfoJson(payee.split(" ")[0], payee.split(" ")[1])); + + return mpesaChannelRequestJson.toString(); + } + + public static JSONObject getPartyInfoJson(String partyIdType, String partyIdentifier) { + JSONObject partyIdInfo = new JSONObject(); + partyIdInfo.put("partyIdType", partyIdType); + partyIdInfo.put("partyIdentifier", partyIdentifier); + + JSONObject party = new JSONObject(); + party.put("partyIdInfo", partyIdInfo); + + return party; + } +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/util/SecurityUtil.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/util/SecurityUtil.java new file mode 100644 index 000000000..30b9a1a92 --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/util/SecurityUtil.java @@ -0,0 +1,219 @@ +package org.mifos.connector.common.util; + +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import java.security.InvalidKeyException; +import java.security.Key; +import java.security.KeyFactory; +import java.security.NoSuchAlgorithmException; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.spec.EncodedKeySpec; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.KeySpec; +import java.security.spec.PKCS8EncodedKeySpec; +import java.security.spec.X509EncodedKeySpec; +import javax.crypto.BadPaddingException; +import javax.crypto.Cipher; +import javax.crypto.IllegalBlockSizeException; +import javax.crypto.NoSuchPaddingException; +import javax.crypto.SecretKey; +import javax.crypto.SecretKeyFactory; +import javax.crypto.spec.PBEKeySpec; +import javax.crypto.spec.SecretKeySpec; +import org.apache.commons.codec.binary.Base64; +import org.apache.commons.codec.digest.DigestUtils; + +public final class SecurityUtil { + + private SecurityUtil() {} + + public static String hash(String data) { + return new DigestUtils("SHA3-256").digestAsHex(data); + } + + /** + * Encrypts the [content] using the [privateKey] + * + * @param content + * data to be encrypted + * @param key + * encryption key + * @return encrypted data + * @throws NoSuchPaddingException + * see @getSecretKey + * @throws IllegalBlockSizeException + * see @encryptFromCipher + * @throws NoSuchAlgorithmException + * see @getCipher + * @throws BadPaddingException + * see @encryptFromCipher + * @throws InvalidKeySpecException + * see @getSecretKey + * @throws InvalidKeyException + * see @encrypt + */ + public static String signContent(String content, String key) throws NoSuchPaddingException, IllegalBlockSizeException, + NoSuchAlgorithmException, BadPaddingException, InvalidKeySpecException, InvalidKeyException { + + return encryptUsingPublicKey(content, key); + } + + /** + * Generates [SecretKey] instance using custom password and salt + * + * @param key + * the base key used for generating secret + * @return [SecretKey] An instance of the [SecretKey] + */ + public static SecretKey getSecretKey(String key) throws NoSuchAlgorithmException, InvalidKeySpecException { + SecretKeyFactory factory = SecretKeyFactory.getInstance("RSA"); + KeySpec spec = new PBEKeySpec(key.toCharArray(), key.getBytes(), 65536, 2048); + return new SecretKeySpec(factory.generateSecret(spec).getEncoded(), "RSA"); + } + + /** + * Generates [PublicKey] object from String public key + * + * @param key + * string value of public key + * @return + * @throws NoSuchAlgorithmException + * @throws InvalidKeySpecException + */ + public static PublicKey getPublicKeyFromString(String key) throws NoSuchAlgorithmException, InvalidKeySpecException { + byte[] keyBytes = Base64.decodeBase64(key); + EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(keyBytes); + KeyFactory keyFactory = KeyFactory.getInstance("RSA"); + return keyFactory.generatePublic(publicKeySpec); + } + + public static String getStringFromPublicKey(PublicKey publicKey) { + byte[] keyBytes = publicKey.getEncoded(); + return new String(Base64.encodeBase64(keyBytes), Charset.defaultCharset()); + } + + /** + * Generates [PrivateKey] object from String public key + * + * @param key + * string value of public key + * @return + * @throws NoSuchAlgorithmException + * @throws InvalidKeySpecException + */ + public static PrivateKey getPrivateKeyFromString(String key) throws NoSuchAlgorithmException, InvalidKeySpecException { + byte[] keyBytes = Base64.decodeBase64(key); + EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes); + KeyFactory keyFactory = getKeyFactory(); + return keyFactory.generatePrivate(keySpec); + } + + /** + * Applies given cipher on a plain text + * + * @param input + * text to be encoded + * @param cipher + * teh instance of the [Cipher] + * @return [String] encrypted data as a Base64 encoded text + */ + private static String encryptFromCipher(String input, Cipher cipher) throws IllegalBlockSizeException, BadPaddingException { + byte[] cipherText = cipher.doFinal(input.getBytes(StandardCharsets.UTF_8)); + return Base64.encodeBase64String(cipherText); + } + + /** + * Applies given cipher on a plain text + * + * @param input + * text to be encoded + * @param cipher + * teh instance of the [Cipher] + * @return [String] encrypted data as a Base64 encoded text + */ + private static String decryptFromCipher(String input, Cipher cipher) throws IllegalBlockSizeException, BadPaddingException { + byte[] cipherText = cipher.doFinal(Base64.decodeBase64(input)); + return new String(cipherText, StandardCharsets.UTF_8); + } + + // get key factory + private static KeyFactory getKeyFactory() throws NoSuchAlgorithmException { + return KeyFactory.getInstance("RSA"); + } + + /** + * @return [Cipher] returns the default instance of [Cipher] + */ + private static Cipher getCipher() throws NoSuchPaddingException, NoSuchAlgorithmException { + return Cipher.getInstance("RSA"); + } + + private static String applyCipher(String input, Key key, int cipherMode) + throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException { + Cipher cipher = getCipher(); + switch (cipherMode) { + case (Cipher.ENCRYPT_MODE): + cipher.init(Cipher.ENCRYPT_MODE, key); + return encryptFromCipher(input, cipher); + case (Cipher.DECRYPT_MODE): + cipher.init(Cipher.DECRYPT_MODE, key); + return decryptFromCipher(input, cipher); + default: + return null; + } + } + + /** + * Encrypts the string data using [key] (SecretKey) and [iv] (IvParameterSpec) + * + * @param input + * text to be encoded + * @param encKey + * secret key to be used for encryption + * @return [String] encoded data as plain text + */ + public static String encryptUsingPublicKey(String input, String encKey) throws NoSuchPaddingException, NoSuchAlgorithmException, + InvalidKeyException, IllegalBlockSizeException, BadPaddingException, InvalidKeySpecException { + PublicKey publicKey = getPublicKeyFromString(encKey); + return encrypt(input, publicKey); + } + + public static String encryptUsingPrivateKey(String input, String encKey) throws NoSuchPaddingException, NoSuchAlgorithmException, + InvalidKeyException, IllegalBlockSizeException, BadPaddingException, InvalidKeySpecException { + PrivateKey publicKey = getPrivateKeyFromString(encKey); + return encrypt(input, publicKey); + } + + public static String encrypt(String input, PublicKey publicKey) + throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException { + return applyCipher(input, publicKey, Cipher.ENCRYPT_MODE); + } + + public static String encrypt(String input, PrivateKey privateKey) + throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException { + return applyCipher(input, privateKey, Cipher.ENCRYPT_MODE); + } + + public static String decryptUsingPrivateKey(String input, String decKey) throws NoSuchPaddingException, NoSuchAlgorithmException, + InvalidKeyException, IllegalBlockSizeException, BadPaddingException, InvalidKeySpecException { + PrivateKey privateKey = getPrivateKeyFromString(decKey); + return decrypt(input, privateKey); + } + + public static String decryptUsingPublicKey(String input, String decKey) throws NoSuchPaddingException, NoSuchAlgorithmException, + InvalidKeyException, IllegalBlockSizeException, BadPaddingException, InvalidKeySpecException { + PublicKey privateKey = getPublicKeyFromString(decKey); + return decrypt(input, privateKey); + } + + public static String decrypt(String input, PublicKey publicKey) + throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException { + return applyCipher(input, publicKey, Cipher.DECRYPT_MODE); + } + + public static String decrypt(String input, PrivateKey privateKey) + throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException { + return applyCipher(input, privateKey, Cipher.DECRYPT_MODE); + } +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/util/ZeebeUtil.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/util/ZeebeUtil.java new file mode 100644 index 000000000..c2a34375c --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/util/ZeebeUtil.java @@ -0,0 +1,37 @@ +package org.mifos.connector.common.util; + +import java.util.UUID; +import org.springframework.beans.factory.annotation.Value; + +public class ZeebeUtil { + + @Value("${transaction-id-length}") + private int transactionIdLength; + + public String generateTransactionId() { + return UUID.randomUUID().toString(); + } + + public String randomCharOfSize(int size) { + String data = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; + char[] arr = data.toCharArray(); + StringBuilder s = new StringBuilder(); + for (int i = 0; i < size; i++) { + int index = (int) (Math.random() * (data.length())); + s.append(arr[index]); + } + return s.toString(); + } + + public String customSizeTransactionId() { + String transactionId = generateTransactionId(); + if (transactionIdLength == -1 || transactionIdLength < 13) { + return transactionId; + } + String originalUUID = transactionId.replace("-", ""); + String uuid12digits = originalUUID.substring(0, 12); + String randomString = randomCharOfSize(transactionIdLength - 12); + return uuid12digits + randomString; + + } +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/validation/ValidationCodeType.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/validation/ValidationCodeType.java new file mode 100644 index 000000000..f346a88de --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/validation/ValidationCodeType.java @@ -0,0 +1,8 @@ +package org.mifos.connector.common.validation; + +public interface ValidationCodeType { + + String getCode(); + String getCategory(); + String getMessage(); +} \ No newline at end of file diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/validation/ValidationEnums.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/validation/ValidationEnums.java new file mode 100644 index 000000000..bfe700622 --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/validation/ValidationEnums.java @@ -0,0 +1,35 @@ +package org.mifos.connector.common.validation; + +import org.mifos.connector.common.exception.PaymentHubErrorCategory; + +public enum ValidationEnums implements ValidationCodeType { + INVALID_LENGTH("INVALID_LENGTH", "length is invalid"), + INVALID_LIST("INVALID_LIST", "list is invalid"), + INVALID_NEGATIVE_FIELD("INVALID_NEGATIVE_FIELD", "this field cannot be negative"), + INVALID_MAX_LENGTH("INVALID_MAX_LENGTH", "cannot exceed the maximum length"); + + private final String code; + private final String category; + private final String message; + + ValidationEnums(String code, String message) { + this.code = code; + this.category = PaymentHubErrorCategory.Validation.toString(); + this.message = message; + } + + @Override + public String getCode() { + return this.code; + } + + @Override + public String getCategory() { + return this.category; + } + + @Override + public String getMessage() { + return message; + } +} \ No newline at end of file diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/validation/ValidatorBuilder.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/validation/ValidatorBuilder.java new file mode 100644 index 000000000..74db3749f --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/validation/ValidatorBuilder.java @@ -0,0 +1,301 @@ +package org.mifos.connector.common.validation; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.ToString; +import org.apache.commons.lang3.StringUtils; +import org.mifos.connector.common.channel.dto.ErrorParameter; +import org.mifos.connector.common.channel.dto.Errors; + +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.List; + +@Getter +@ToString +@AllArgsConstructor +public class ValidatorBuilder { + private String errorCategory; + private String errorCode; + private String errorDescription; + private String developerMessage; + private String defaultUserMessage; + private String resource; + private String parameter; + private Object value; + private List errorParameters; + private List errorsList; + private boolean ignoreNullValue = false; + + public ValidatorBuilder() { + this(new ArrayList<>()); + } + + public ValidatorBuilder(List errorsList) { + this.errorsList = errorsList; + } + + public ValidatorBuilder reset() { + return new ValidatorBuilder(this.errorsList); + } + + public void merge(ValidatorBuilder other) { + errorsList.addAll(other.errorsList); + } + + public boolean hasError() { + return !errorsList.isEmpty(); + } + + public List getErrorsList() { + return errorsList; + } + + public ValidatorBuilder errorCategory(final String errorCategory) { + this.errorCategory = errorCategory; + return this; + } + + public ValidatorBuilder errorCode(final String errorCode) { + this.errorCode = errorCode; + return this; + } + + public ValidatorBuilder errorDescription(final String errorDescription) { + this.errorDescription = errorDescription; + return this; + } + + public ValidatorBuilder developerMessage(final String developerMessage) { + this.developerMessage = developerMessage; + return this; + } + + public ValidatorBuilder defaultUserMessage(final String defaultUserMessage) { + this.defaultUserMessage = defaultUserMessage; + return this; + } + + + public ValidatorBuilder resource(final String resource) { + this.resource = resource; + return this; + } + + public ValidatorBuilder parameter(final String parameter) { + this.parameter = parameter; + return this; + } + + public ValidatorBuilder value(final Object value) { + this.value = value; + return this; + } + + public ValidatorBuilder errorParameters(final List errorParameters) { + this.errorParameters = errorParameters; + return this; + } + + public ValidatorBuilder ignoreIfNull() { + this.ignoreNullValue = true; + return this; + } + + public Boolean isNullOrEmpty() { + if (this.value == null) return true; + + if (this.value instanceof String) { + return ((String) this.value).isEmpty(); + } else if (this.value instanceof List) { + return ((List) this.value).isEmpty(); + } + return false; + } + + public ValidatorBuilder isNullWithFailureCode(final ValidationCodeType errorCode) { + if (isNullOrEmpty()) { + failWithCode(errorCode); + } + return this; + } + + public void failWithCode(final ValidationCodeType errorCode) { + final Errors error = new Errors(errorCode.getCategory(), errorCode.getCode(), errorCode.getMessage(), null); + this.errorsList.add(error); + } + + public void failWithCodeAndErrorParams(final ValidationCodeType errorCode, final List errorParameters) { + final Errors error = new Errors(errorCode.getCategory(), errorCode.getCode(), errorCode.getMessage(), errorParameters); + this.errorsList.add(error); + } + + public ValidatorBuilder validateFieldNotBlankAndLength(final int expectedLength) { + if (this.value == null && this.ignoreNullValue) { + return this; + } + + if (this.value != null) { + final String stringValue = this.value.toString(); + if (StringUtils.isBlank(stringValue) || stringValue.length() != expectedLength) { + failWithCode(ValidationEnums.INVALID_LENGTH); + } + } + return this; + } + + public ValidatorBuilder validateFieldNotBlankAndLengthWithFailureCode(final int expectedLength, final ValidationCodeType errorCode) { + if (this.value == null && this.ignoreNullValue) { + return this; + } + + if (isNullOrEmpty()) { + failWithCode(errorCode); + } else if (this.value != null) { + final String stringValue = this.value.toString(); + if (StringUtils.isBlank(stringValue) || stringValue.length() != expectedLength) { + failWithCode(errorCode); + } + } + return this; + } + + public ValidatorBuilder validateFieldNotBlankAndLengthWithFailureCodeAndErrorParams(final int expectedLength, final ValidationCodeType errorCode) { + if (this.value == null && this.ignoreNullValue) { + return this; + } + + List errorParam = List.of(new ErrorParameter(getParameter(), String.valueOf(expectedLength))); + if (isNullOrEmpty()) { + failWithCodeAndErrorParams(errorCode, errorParam); + } else if (this.value != null) { + final String stringValue = this.value.toString(); + if (StringUtils.isBlank(stringValue) || stringValue.length() != expectedLength) { + failWithCodeAndErrorParams(errorCode, errorParam); + } + } + return this; + } + + public ValidatorBuilder validateListNotEmpty() { + if (this.value == null && this.ignoreNullValue) { + return this; + } + + if (this.value != null && this.value instanceof List && ((List) this.value).isEmpty()) { + failWithCode(ValidationEnums.INVALID_LIST); + } + return this; + } + + public ValidatorBuilder validateBigDecimalFieldNotNegative() { + if (this.value == null && this.ignoreNullValue) { + return this; + } + + if (this.value != null) { + try { + final BigDecimal amount = new BigDecimal(this.value.toString()); + if (amount.compareTo(BigDecimal.ZERO) < 0) { + failWithCode(ValidationEnums.INVALID_NEGATIVE_FIELD); + } + } catch (NumberFormatException e) { + throw new RuntimeException("An error has occurred" + e.getMessage()); + } + } + return this; + } + + public ValidatorBuilder validateBigDecimalFieldNotNegativeWithFailureCode(final ValidationCodeType errorCode) { + if (this.value == null && this.ignoreNullValue) { + return this; + } + + if (this.value != null) { + try { + final BigDecimal amount = new BigDecimal(this.value.toString()); + if (amount.compareTo(BigDecimal.ZERO) < 0) { + failWithCode(errorCode); + } + } catch (NumberFormatException e) { + throw new RuntimeException("An error has occurred" + e.getMessage()); + } + } + return this; + } + + public ValidatorBuilder validateFieldMaxLength(final int maxLength) { + if (this.value == null && this.ignoreNullValue) { + return this; + } + + if (this.value != null) { + final String stringValue = this.value.toString(); + if (stringValue.length() > maxLength) { + failWithCode(ValidationEnums.INVALID_MAX_LENGTH); + } + } + return this; + } + + public ValidatorBuilder validateFieldMaxLengthWithFailureCode(final int maxLength, final ValidationCodeType errorCode) { + if (this.value == null && this.ignoreNullValue) { + return this; + } + + if (isNullOrEmpty()) { + failWithCode(errorCode); + } else if (this.value != null) { + final String stringValue = this.value.toString(); + if (stringValue.length() > maxLength) { + failWithCode(errorCode); + } + } + return this; + } + + public ValidatorBuilder validateFieldMaxLengthWithFailureCodeAndErrorParams(final int maxLength, final ValidationCodeType errorCode) { + if (this.value == null && this.ignoreNullValue) { + return this; + } + + List errorParam = List.of(new ErrorParameter(getParameter(), String.valueOf(maxLength))); + if (isNullOrEmpty()) { + failWithCodeAndErrorParams(errorCode, errorParam); + } else if (this.value != null) { + final String stringValue = this.value.toString(); + if (stringValue.length() > maxLength) { + failWithCodeAndErrorParams(errorCode, errorParam); + } + } + return this; + } + + public ValidatorBuilder validateFieldIgnoreNullAndMaxLengthWithFailureCode(String resource, String parameter, Object value, + int maxLength, ValidationCodeType maxLengthErrorCode) { + + return reset().resource(resource).parameter(parameter).value(value).ignoreIfNull().validateFieldMaxLengthWithFailureCodeAndErrorParams(maxLength, + maxLengthErrorCode); + } + + public ValidatorBuilder validateFieldIgnoreNullAndExactLengthWithFailureCode(String resource, String parameter, Object value, + int exactLength, ValidationCodeType exactLengthErrorCode) { + + return reset().resource(resource).parameter(parameter).value(value).ignoreIfNull() + .validateFieldNotBlankAndLengthWithFailureCodeAndErrorParams(exactLength, exactLengthErrorCode); + } + + public ValidatorBuilder validateFieldIsNullAndMaxLengthWithFailureCode(String resource, String parameter, Object value, + ValidationCodeType nullErrorCode, int maxLength, ValidationCodeType maxLengthErrorCode) { + + return reset().resource(resource).parameter(parameter).value(value).isNullWithFailureCode(nullErrorCode) + .validateFieldMaxLengthWithFailureCodeAndErrorParams(maxLength, maxLengthErrorCode); + } + + public ValidatorBuilder validateFieldIsNullAndExactLengthWithFailureCode(String resource, String parameter, Object value, + ValidationCodeType nullErrorCode, int exactLength, ValidationCodeType exactLengthErrorCode) { + + return reset().resource(resource).parameter(parameter).value(value).isNullWithFailureCode(nullErrorCode) + .validateFieldNotBlankAndLengthWithFailureCodeAndErrorParams(exactLength, exactLengthErrorCode); + } +} \ No newline at end of file diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/vouchers/dto/CallbackRequestDTO.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/vouchers/dto/CallbackRequestDTO.java new file mode 100644 index 000000000..84b303ae9 --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/vouchers/dto/CallbackRequestDTO.java @@ -0,0 +1,20 @@ +package org.mifos.connector.common.vouchers.dto; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +import java.util.List; + + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +public class CallbackRequestDTO { + private String requestID; + private String batchID; + private List voucherInstructions; + +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/vouchers/dto/FailedCaseDTO.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/vouchers/dto/FailedCaseDTO.java new file mode 100644 index 000000000..0e3d8c4f2 --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/vouchers/dto/FailedCaseDTO.java @@ -0,0 +1,15 @@ +package org.mifos.connector.common.vouchers.dto; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +public class FailedCaseDTO { + private String serialNumber; + private String failureReason; +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/vouchers/dto/RedeemVoucherRequestDTO.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/vouchers/dto/RedeemVoucherRequestDTO.java new file mode 100644 index 000000000..80ef8e18e --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/vouchers/dto/RedeemVoucherRequestDTO.java @@ -0,0 +1,17 @@ +package org.mifos.connector.common.vouchers.dto; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +public class RedeemVoucherRequestDTO { + private String requestId; + private String agentId; + private String voucherSerialNumber; + private String voucherSecretNumber; +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/vouchers/dto/RedeemVoucherResponseDTO.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/vouchers/dto/RedeemVoucherResponseDTO.java new file mode 100644 index 000000000..38469c754 --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/vouchers/dto/RedeemVoucherResponseDTO.java @@ -0,0 +1,19 @@ +package org.mifos.connector.common.vouchers.dto; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +public class RedeemVoucherResponseDTO { + private String status; + private String message; + private String serialNumber; + private String value; + private String timestamp; + private String transactionId; +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/vouchers/dto/RequestDTO.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/vouchers/dto/RequestDTO.java new file mode 100644 index 000000000..4b8dd186b --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/vouchers/dto/RequestDTO.java @@ -0,0 +1,18 @@ +package org.mifos.connector.common.vouchers.dto; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +import java.util.ArrayList; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +public class RequestDTO { + public String requestID ; + public String batchID; + public ArrayList voucherInstructions; +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/vouchers/dto/ResponseDTO.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/vouchers/dto/ResponseDTO.java new file mode 100644 index 000000000..d07d3bd22 --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/vouchers/dto/ResponseDTO.java @@ -0,0 +1,16 @@ +package org.mifos.connector.common.vouchers.dto; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +public class ResponseDTO { + private String ResponseCode; + private String ResponseDescription; + private String RequestID; +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/vouchers/dto/SuccessfulVouchers.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/vouchers/dto/SuccessfulVouchers.java new file mode 100644 index 000000000..5c9364fd9 --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/vouchers/dto/SuccessfulVouchers.java @@ -0,0 +1,21 @@ +package org.mifos.connector.common.vouchers.dto; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +import java.math.BigDecimal; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +public class SuccessfulVouchers { + private String instructionID ; + private String currency ; + private BigDecimal amount; + private String narration; + private String voucherNumber; + private String serialNumber; +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/vouchers/dto/ValidityDTO.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/vouchers/dto/ValidityDTO.java new file mode 100644 index 000000000..861501833 --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/vouchers/dto/ValidityDTO.java @@ -0,0 +1,15 @@ +package org.mifos.connector.common.vouchers.dto; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +public class ValidityDTO { + private String serialNumber; + private Boolean isValid; +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/vouchers/dto/VoucherInstruction.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/vouchers/dto/VoucherInstruction.java new file mode 100644 index 000000000..6bb029baf --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/vouchers/dto/VoucherInstruction.java @@ -0,0 +1,24 @@ +package org.mifos.connector.common.vouchers.dto; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +import java.math.BigDecimal; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +public class VoucherInstruction { + private String instructionID ; + private String groupCode; + private String currency ; + private BigDecimal amount; + private String payeeFunctionalID ; + private String narration; + private String voucherNumber; + private String serialNumber; + private String status; +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/vouchers/dto/VoucherLifecycleCallbackResponseDTO.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/vouchers/dto/VoucherLifecycleCallbackResponseDTO.java new file mode 100644 index 000000000..f1e23bb90 --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/vouchers/dto/VoucherLifecycleCallbackResponseDTO.java @@ -0,0 +1,19 @@ +package org.mifos.connector.common.vouchers.dto; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +import java.util.List; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +public class VoucherLifecycleCallbackResponseDTO { + private String requestId; + private String registerRequestId; + private Integer numberFailedCases; + private List failedCases; +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/webclient/WebClientAdapter.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/webclient/WebClientAdapter.java new file mode 100644 index 000000000..a6fcf80d3 --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/webclient/WebClientAdapter.java @@ -0,0 +1,135 @@ +package org.mifos.connector.common.webclient; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; +import org.springframework.stereotype.Component; +import org.springframework.web.reactive.function.BodyInserters; +import org.springframework.web.reactive.function.client.WebClient; +import reactor.core.publisher.Mono; + +import java.util.concurrent.CompletableFuture; + +@Component +public class WebClientAdapter { + + private static final Logger log = LoggerFactory.getLogger(WebClientAdapter.class); + private final WebClient webClient; + + public WebClientAdapter() { + this.webClient = WebClient.builder().build(); + } + + // GET + public CompletableFuture getRequest(String url, HttpHeaders headers, Class responseType) { + log.info("Executing GET request to URL: {}", url); + return webClient.get() + .uri(url) + .headers(httpHeaders -> httpHeaders.addAll(headers)) + .retrieve() + .bodyToMono(responseType) + .doOnSuccess(responseBody -> log.debug("GET request to {} succeeded, response Body {}", url, responseBody)) + .doOnError(error -> log.error("GET request to {} failed: {}", url, error.getMessage())) + .toFuture(); + } + + public CompletableFuture getRequest(String url, Class responseType) { + return getRequest(url, new HttpHeaders(), responseType); + } + + // POST + public CompletableFuture postRequest(String url, T body, HttpHeaders headers, MediaType mediaType, Class responseType) { + log.info("Executing POST request to URL: {}", url); + return webClient.post() + .uri(url) + .contentType(mediaType) + .headers(httpHeaders -> httpHeaders.addAll(headers)) + .body(Mono.just(body), body.getClass()) + .retrieve() + .bodyToMono(responseType) + .doOnSuccess(responseBody -> log.debug("POST request to {} succeeded with response {}", url, responseBody)) + .doOnError(error -> log.error("POST request to {} failed: {}", url, error.getMessage())) + .toFuture(); + } + + public CompletableFuture postRequest(String url, T body, Class responseType) { + return postRequest(url, body, new HttpHeaders(), MediaType.APPLICATION_JSON, responseType); + } + + public CompletableFuture postRequest(String url, HttpHeaders headers, MediaType mediaType, Class responseType) { + log.info("Executing POST request to URL: {} without a body", url); + return webClient.post() + .uri(url) + .contentType(mediaType) + .headers(httpHeaders -> httpHeaders.addAll(headers)) + .retrieve() + .bodyToMono(responseType) + .doOnSuccess(responseBody -> log.debug("POST request to {} succeeded with response {}", url, responseBody)) + .doOnError(error -> log.error("POST request to {} failed: {}", url, error.getMessage())) + .toFuture(); + } + + public CompletableFuture postRequest(String url, Class responseType) { + return postRequest(url, new HttpHeaders(), MediaType.APPLICATION_JSON, responseType); + } + public CompletableFuture postRequestWithoutBodyAndHeaders(String url, Class responseType) { + log.info("Executing POST request to URL: {} without a body and headers", url); + return webClient.post() + .uri(url) + .retrieve() + .bodyToMono(responseType) + .doOnSuccess(responseBody -> log.debug("POST request to {} succeeded, response {}", url, responseBody)) + .doOnError(error -> log.error("POST request to {} failed: {}", url, error.getMessage())) + .toFuture(); + } + // PUT + public CompletableFuture putRequest(String url, T body, HttpHeaders headers, MediaType mediaType, Class responseType) { + log.info("Executing PUT request to URL: {}", url); + return webClient.put() + .uri(url) + .contentType(mediaType) + .headers(httpHeaders -> httpHeaders.addAll(headers)) + .body(BodyInserters.fromValue(body)) + .retrieve() + .bodyToMono(responseType) + .doOnSuccess(responseBody -> log.debug("PUT request to {} succeeded, response {}", url, body)) + .doOnError(error -> log.error("PUT request to {} failed: {}", url, error.getMessage())) + .toFuture(); + } + + public CompletableFuture putRequest(String url, T body, Class responseType) { + return putRequest(url, body, new HttpHeaders(), MediaType.APPLICATION_JSON, responseType); + } + + // DELETE + public CompletableFuture deleteRequest(String url, HttpHeaders headers) { + log.info("Executing DELETE request to URL: {}", url); + return webClient.delete() + .uri(url) + .headers(httpHeaders -> httpHeaders.addAll(headers)) + .retrieve() + .bodyToMono(String.class) + .doOnSuccess(responseBody -> log.debug("DELETE request to {} succeeded, response body {}", url, responseBody)) + .doOnError(error -> log.error("DELETE request to {} failed: {}", url, error.getMessage())) + .toFuture(); + } + + public CompletableFuture deleteRequest(String url) { + return deleteRequest(url, new HttpHeaders()); + } + + public CompletableFuture sendCallBackPost(String url, T body, HttpHeaders headers, MediaType mediaType, Class responseType) + { + String headerName = "X-Correlation-ID"; + log.info("Client Correlation Id: {}", headers.getFirst(headerName)); + return postRequest(url, body, headers, mediaType, responseType); + } + + public CompletableFuture sendCallBackPut(String url, T body, HttpHeaders headers, MediaType mediaType, Class responseType) + { + String headerName = "X-Correlation-ID"; + log.info("Client Correlation Id: {}", headers.getFirst(headerName)); + return putRequest(url, body, headers, mediaType, responseType); + } +} diff --git a/ph-ee-connector-common/src/main/java/org/mifos/connector/common/zeebe/ZeebeVariables.java b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/zeebe/ZeebeVariables.java new file mode 100644 index 000000000..c89b24350 --- /dev/null +++ b/ph-ee-connector-common/src/main/java/org/mifos/connector/common/zeebe/ZeebeVariables.java @@ -0,0 +1,12 @@ +package org.mifos.connector.common.zeebe; + +public final class ZeebeVariables { + + private ZeebeVariables() {} + + public static final String CHANNEL_REQUEST = "channelRequest"; + public static final String MPESA_CHANNEL_REQUEST = "mpesaChannelRequest"; + public static final String ORIGIN_DATE = "originDate"; + public static final String TRANSACTION_ID = "transactionId"; + public static final String TENANT_ID = "tenantId"; +} diff --git a/ph-ee-connector-common/src/main/resources/application-jws.yaml b/ph-ee-connector-common/src/main/resources/application-jws.yaml new file mode 100644 index 000000000..371c5737e --- /dev/null +++ b/ph-ee-connector-common/src/main/resources/application-jws.yaml @@ -0,0 +1,12 @@ +jws: + tenantKeys: + - name: "gorilla" + certificate: ${JWS_TENANTKEYS_CERTIFICATE:MIIDvDCCAqQCCQDZK/l5vKIt7jANBgkqhkiG9w0BAQsFADCBnzELMAkGA1UEBhMCSU4xEjAQBgNVBAgMCUtBUk5BVEFLQTETMBEGA1UEBwwKRE9NQVNBTkRSQTERMA8GA1UECgwIRllOQVJGSU4xFDASBgNVBAsMC0RFVkVMT1BNRU5UMR0wGwYDVQQDDBRodHRwczovL2Z5bmFyZmluLmlvLzEfMB0GCSqGSIb3DQEJARYQYXZpa0BmeW5hcmZpbi5pbzAeFw0yMzA0MDUwNjExMDNaFw0yMzA1MDUwNjExMDNaMIGfMQswCQYDVQQGEwJJTjESMBAGA1UECAwJS0FSTkFUQUtBMRMwEQYDVQQHDApET01BU0FORFJBMREwDwYDVQQKDAhGWU5BUkZJTjEUMBIGA1UECwwLREVWRUxPUE1FTlQxHTAbBgNVBAMMFGh0dHBzOi8vZnluYXJmaW4uaW8vMR8wHQYJKoZIhvcNAQkBFhBhdmlrQGZ5bmFyZmluLmlvMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtO38XREJbL1r4IAYK6K5ONNXHcmfTKlehRf0YF+vjptt4D/6zBObBOf/zqButSlN3RI/aYXBx/OOU7sjRMnOFYasXtYM5eFSGZDo/v9qsWLwrD9Ur97cE7Pnw3xb+TQNWV6orME5YI0di6X9bXrxUBDswfVmLx/wbvZIK9gJRzD1evm+4HCYo/+1tYZ3YgpNmoW4u6F44zgxeMhFPcjQIaKYm3uM8zF/hTuHhWKVJq40ucL7+mgGp36HiDE8IRfNRo/Vd6x3+FLA91RMe+96uxj7l5WUi8oja1Anb8SE4fnVvGPSArgk8t2xW6dfx86D3c5JFJczzSi5S4ldsOBHMQIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQBPhTd+DhzbUGqAvsU6T34Iu3k+6Br4N6m90dkvBeMgYL8J7J6Fa7hm7f6xEeDqM+RTPhuFXNlS5swjqUYg/j85jKqVtgYAB6IE7z7BTwBAtF4tJ+jVOV4PfS/lSqvfxwo/qThqU1iXFz9xU38zlqxH5JuWZjeV58uUP/vZC8Ys44RDhU4X1qDbt51Vs8E+DeV1A4aweoEVc/txEdShbxnR2MVpPpca1NOElYW2cTAWjJypgw5bJZX4G0gZmHCZhQtgXSIMC1KSqMM7DK+HA7xTfKNJ+vnD08FOzBAb6nl2cHVb/zySdNWwsPu6w3FmzgFit9Hq2zE2F41167GvRBEL} + privateKey: ${JWS_TENANTKEYS_PRIVATEKEY:MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC07fxdEQlsvWvggBgrork401cdyZ9MqV6FF/RgX6+Om23gP/rME5sE5//OoG61KU3dEj9phcHH845TuyNEyc4Vhqxe1gzl4VIZkOj+/2qxYvCsP1Sv3twTs+fDfFv5NA1ZXqiswTlgjR2Lpf1tevFQEOzB9WYvH/Bu9kgr2AlHMPV6+b7gcJij/7W1hndiCk2ahbi7oXjjODF4yEU9yNAhopibe4zzMX+FO4eFYpUmrjS5wvv6aAanfoeIMTwhF81Gj9V3rHf4UsD3VEx773q7GPuXlZSLyiNrUCdvxITh+dW8Y9ICuCTy3bFbp1/HzoPdzkkUlzPNKLlLiV2w4EcxAgMBAAECggEAMjqHfwbFyQxlMHQfQa3xIdd6LejVcqDqfqSB0Wd/A2YfAMyCQbmHpbsKh0B+u4h191OjixX5EBuLfa9MQUKNFejHXaSq+/6rnjFenbwm0IwZKJiEWDbUfhvJ0blqhypuMktXJG6YETfb5fL1AjnJWGL6d3Y7IgYJ56QzsQhOuxZidSqw468xc4sIF0CoTeJdrSC2yDCVuVlLNifm/2SXBJD8mgc1WCz0rkJhvvpW4k5G9rRSkS5f0013ZNfsfiDXoqiKkafoYNEbk7TZQNInqSuONm/UECn5GLm6IXdXSGfm1O2Lt0Kk7uxW/3W00mIPeZD+hiOObheRm/2HoOEKiQKBgQDreVFQihXAEDviIB2s6fphvPcMw/IonE8tX565i3303ubQMDIyZmsi3apN5pqSjm1TKq1KIgY2D4vYTu6vO5x9MhEO2CCZWNwC+awrIYa32FwiT8D8eZ9g+DJ4/IwXyz1fG38RCz/eIsJ0NsS9z8RKBIbfMmM+WnXRez3Fq+cbRwKBgQDEs35qXThbbFUYo1QkO0vIo85iczu9NllRxo1nAqQkfu1oTYQQobxcGk/aZk0B02r9kt2eob8zfG+X3LadIhQ0/LalnGNKI9jWLkdW4dxi7xMU99MYc3NRXmR49xGxgOVkLzKyGMisUvkTnE5v/S1nhu5uFr3JPkWcCScLOTjVxwKBgHNWsDq3+GFkUkC3pHF/BhJ7wbLyA5pavfmmnZOavO6FhB8zjFLdkdq5IuMXcl0ZAHm9LLZkJhCy2rfwKb+RflxgerR/rrAOM24Np4RU3q0MgEyaLhg85pFT4T0bzu8UsRH14O6TSQxgkEjmTsX+j9IFl56aCryPCKi8Kgy53/CfAoGAdV2kUFLPDb3WCJ1r1zKKRW1398ZKHtwO73xJYu1wg1Y40cNuyX23pj0M6IOh7zT24dZ/5ecc7tuQukw3qgprhDJFyQtHMzWwbBuw9WZO2blM6XX1vuEkLajkykihhggi12RSG3IuSqQ3ejwJkUi/jsYz/fwTwcAmSLQtV8UM5IECgYEAh4h1EkMx3NXzVFmLsb4QLMXw8+Rnn9oG+NGObldQ+nmknUPu7iz5kl9lTJy+jWtqHlHL8ZtV1cZZSZnFxX5WQH5/lcz/UD+GqWoSlWuTU34PPTJqLKSYgkoOJQDEZVMVphLySS9tuo+K/h10lRS1r9KDm3RZASa1JnnWopBZIz4=} + - name: "default" + certificate: ${JWS_TENANTKEYS_CERTIFICATE_DEFAULT:MIIDvDCCAqQCCQDZK/l5vKIt7jANBgkqhkiG9w0BAQsFADCBnzELMAkGA1UEBhMCSU4xEjAQBgNVBAgMCUtBUk5BVEFLQTETMBEGA1UEBwwKRE9NQVNBTkRSQTERMA8GA1UECgwIRllOQVJGSU4xFDASBgNVBAsMC0RFVkVMT1BNRU5UMR0wGwYDVQQDDBRodHRwczovL2Z5bmFyZmluLmlvLzEfMB0GCSqGSIb3DQEJARYQYXZpa0BmeW5hcmZpbi5pbzAeFw0yMzA0MDUwNjExMDNaFw0yMzA1MDUwNjExMDNaMIGfMQswCQYDVQQGEwJJTjESMBAGA1UECAwJS0FSTkFUQUtBMRMwEQYDVQQHDApET01BU0FORFJBMREwDwYDVQQKDAhGWU5BUkZJTjEUMBIGA1UECwwLREVWRUxPUE1FTlQxHTAbBgNVBAMMFGh0dHBzOi8vZnluYXJmaW4uaW8vMR8wHQYJKoZIhvcNAQkBFhBhdmlrQGZ5bmFyZmluLmlvMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtO38XREJbL1r4IAYK6K5ONNXHcmfTKlehRf0YF+vjptt4D/6zBObBOf/zqButSlN3RI/aYXBx/OOU7sjRMnOFYasXtYM5eFSGZDo/v9qsWLwrD9Ur97cE7Pnw3xb+TQNWV6orME5YI0di6X9bXrxUBDswfVmLx/wbvZIK9gJRzD1evm+4HCYo/+1tYZ3YgpNmoW4u6F44zgxeMhFPcjQIaKYm3uM8zF/hTuHhWKVJq40ucL7+mgGp36HiDE8IRfNRo/Vd6x3+FLA91RMe+96uxj7l5WUi8oja1Anb8SE4fnVvGPSArgk8t2xW6dfx86D3c5JFJczzSi5S4ldsOBHMQIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQBPhTd+DhzbUGqAvsU6T34Iu3k+6Br4N6m90dkvBeMgYL8J7J6Fa7hm7f6xEeDqM+RTPhuFXNlS5swjqUYg/j85jKqVtgYAB6IE7z7BTwBAtF4tJ+jVOV4PfS/lSqvfxwo/qThqU1iXFz9xU38zlqxH5JuWZjeV58uUP/vZC8Ys44RDhU4X1qDbt51Vs8E+DeV1A4aweoEVc/txEdShbxnR2MVpPpca1NOElYW2cTAWjJypgw5bJZX4G0gZmHCZhQtgXSIMC1KSqMM7DK+HA7xTfKNJ+vnD08FOzBAb6nl2cHVb/zySdNWwsPu6w3FmzgFit9Hq2zE2F41167GvRBEL"} + privateKey: ${JWS_TENANTKEYS_PRIVATEKEY_DEFAULT:MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC07fxdEQlsvWvggBgrork401cdyZ9MqV6FF/RgX6+Om23gP/rME5sE5//OoG61KU3dEj9phcHH845TuyNEyc4Vhqxe1gzl4VIZkOj+/2qxYvCsP1Sv3twTs+fDfFv5NA1ZXqiswTlgjR2Lpf1tevFQEOzB9WYvH/Bu9kgr2AlHMPV6+b7gcJij/7W1hndiCk2ahbi7oXjjODF4yEU9yNAhopibe4zzMX+FO4eFYpUmrjS5wvv6aAanfoeIMTwhF81Gj9V3rHf4UsD3VEx773q7GPuXlZSLyiNrUCdvxITh+dW8Y9ICuCTy3bFbp1/HzoPdzkkUlzPNKLlLiV2w4EcxAgMBAAECggEAMjqHfwbFyQxlMHQfQa3xIdd6LejVcqDqfqSB0Wd/A2YfAMyCQbmHpbsKh0B+u4h191OjixX5EBuLfa9MQUKNFejHXaSq+/6rnjFenbwm0IwZKJiEWDbUfhvJ0blqhypuMktXJG6YETfb5fL1AjnJWGL6d3Y7IgYJ56QzsQhOuxZidSqw468xc4sIF0CoTeJdrSC2yDCVuVlLNifm/2SXBJD8mgc1WCz0rkJhvvpW4k5G9rRSkS5f0013ZNfsfiDXoqiKkafoYNEbk7TZQNInqSuONm/UECn5GLm6IXdXSGfm1O2Lt0Kk7uxW/3W00mIPeZD+hiOObheRm/2HoOEKiQKBgQDreVFQihXAEDviIB2s6fphvPcMw/IonE8tX565i3303ubQMDIyZmsi3apN5pqSjm1TKq1KIgY2D4vYTu6vO5x9MhEO2CCZWNwC+awrIYa32FwiT8D8eZ9g+DJ4/IwXyz1fG38RCz/eIsJ0NsS9z8RKBIbfMmM+WnXRez3Fq+cbRwKBgQDEs35qXThbbFUYo1QkO0vIo85iczu9NllRxo1nAqQkfu1oTYQQobxcGk/aZk0B02r9kt2eob8zfG+X3LadIhQ0/LalnGNKI9jWLkdW4dxi7xMU99MYc3NRXmR49xGxgOVkLzKyGMisUvkTnE5v/S1nhu5uFr3JPkWcCScLOTjVxwKBgHNWsDq3+GFkUkC3pHF/BhJ7wbLyA5pavfmmnZOavO6FhB8zjFLdkdq5IuMXcl0ZAHm9LLZkJhCy2rfwKb+RflxgerR/rrAOM24Np4RU3q0MgEyaLhg85pFT4T0bzu8UsRH14O6TSQxgkEjmTsX+j9IFl56aCryPCKi8Kgy53/CfAoGAdV2kUFLPDb3WCJ1r1zKKRW1398ZKHtwO73xJYu1wg1Y40cNuyX23pj0M6IOh7zT24dZ/5ecc7tuQukw3qgprhDJFyQtHMzWwbBuw9WZO2blM6XX1vuEkLajkykihhggi12RSG3IuSqQ3ejwJkUi/jsYz/fwTwcAmSLQtV8UM5IECgYEAh4h1EkMx3NXzVFmLsb4QLMXw8+Rnn9oG+NGObldQ+nmknUPu7iz5kl9lTJy+jWtqHlHL8ZtV1cZZSZnFxX5WQH5/lcz/UD+GqWoSlWuTU34PPTJqLKSYgkoOJQDEZVMVphLySS9tuo+K/h10lRS1r9KDm3RZASa1JnnWopBZIz4="} + header: + order: "X-BatchID,X-CorrelationID,Platform-TenantId" + # below are the exceptions in jws feature + exception-endpoints: "authorization/callback" diff --git a/ph-ee-connector-common/src/main/resources/application.yaml b/ph-ee-connector-common/src/main/resources/application.yaml new file mode 100644 index 000000000..e5224ca32 --- /dev/null +++ b/ph-ee-connector-common/src/main/resources/application.yaml @@ -0,0 +1,13 @@ +zeebe: + client: + max-execution-threads: 1000 + evenly-allocated-max-jobs: 1000 + # max-execution-threads: 100 + # number-of-workers: 5 + # evenly-allocated-max-jobs: "#{${zeebe.client.max-execution-threads} / ${zeebe.client.number-of-workers}}" + broker: + contactpoint: "localhost:26500" + +timer: "PT45S" + +transaction-id-length: -1 diff --git a/ph-ee-connector-common/src/test/java/org/mifos/mojaloop/CallbackMapping.java b/ph-ee-connector-common/src/test/java/org/mifos/mojaloop/CallbackMapping.java new file mode 100644 index 000000000..340572a10 --- /dev/null +++ b/ph-ee-connector-common/src/test/java/org/mifos/mojaloop/CallbackMapping.java @@ -0,0 +1,24 @@ +package org.mifos.mojaloop; + +public class CallbackMapping { + + private String type, value; + + public CallbackMapping() {} + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } +} diff --git a/ph-ee-connector-common/src/test/java/org/mifos/mojaloop/CallbackMappingProperties.java b/ph-ee-connector-common/src/test/java/org/mifos/mojaloop/CallbackMappingProperties.java new file mode 100644 index 000000000..ca0a391df --- /dev/null +++ b/ph-ee-connector-common/src/test/java/org/mifos/mojaloop/CallbackMappingProperties.java @@ -0,0 +1,23 @@ +package org.mifos.mojaloop; + +import java.util.ArrayList; +import java.util.List; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +@Component +@ConfigurationProperties(prefix = "mojaloop") +public class CallbackMappingProperties { + + private List callbackMappings = new ArrayList<>(); + + public CallbackMappingProperties() {} + + public List getCallbackMappings() { + return callbackMappings; + } + + public void setCallbackMappings(List callbackMappings) { + this.callbackMappings = callbackMappings; + } +} diff --git a/ph-ee-connector-common/src/test/java/org/mifos/mojaloop/Dfsp.java b/ph-ee-connector-common/src/test/java/org/mifos/mojaloop/Dfsp.java new file mode 100644 index 000000000..e85ed88a7 --- /dev/null +++ b/ph-ee-connector-common/src/test/java/org/mifos/mojaloop/Dfsp.java @@ -0,0 +1,73 @@ +package org.mifos.mojaloop; + +public class Dfsp { + + private boolean enabled, addToExternalOracle, registerOnlyCallbackUrls; + private String id, partyIdType, partyIdentifier, fundsInPrepareAmount, domain; + + public Dfsp() {} + + public boolean isRegisterOnlyCallbackUrls() { + return registerOnlyCallbackUrls; + } + + public void setRegisterOnlyCallbackUrls(boolean registerOnlyCallbackUrls) { + this.registerOnlyCallbackUrls = registerOnlyCallbackUrls; + } + + public boolean isEnabled() { + return enabled; + } + + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getPartyIdType() { + return partyIdType; + } + + public void setPartyIdType(String partyIdType) { + this.partyIdType = partyIdType; + } + + public String getPartyIdentifier() { + return partyIdentifier; + } + + public void setPartyIdentifier(String partyIdentifier) { + this.partyIdentifier = partyIdentifier; + } + + public String getFundsInPrepareAmount() { + return fundsInPrepareAmount; + } + + public void setFundsInPrepareAmount(String fundsInPrepareAmount) { + this.fundsInPrepareAmount = fundsInPrepareAmount; + } + + public String getDomain() { + return domain; + } + + public void setDomain(String domain) { + this.domain = domain; + } + + public boolean isAddToExternalOracle() { + return addToExternalOracle; + } + + public void setAddToExternalOracle(boolean addToExternalOracle) { + this.addToExternalOracle = addToExternalOracle; + } +} diff --git a/ph-ee-connector-common/src/test/java/org/mifos/mojaloop/DfspProperties.java b/ph-ee-connector-common/src/test/java/org/mifos/mojaloop/DfspProperties.java new file mode 100644 index 000000000..53505319e --- /dev/null +++ b/ph-ee-connector-common/src/test/java/org/mifos/mojaloop/DfspProperties.java @@ -0,0 +1,23 @@ +package org.mifos.mojaloop; + +import java.util.ArrayList; +import java.util.List; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +@Component +@ConfigurationProperties(prefix = "mojaloop") +public class DfspProperties { + + private List dfsps = new ArrayList<>(); + + public DfspProperties() {} + + public List getDfsps() { + return dfsps; + } + + public void setDfsps(List dfsps) { + this.dfsps = dfsps; + } +} diff --git a/ph-ee-connector-common/src/test/java/org/mifos/mojaloop/OnboardDfsps.java b/ph-ee-connector-common/src/test/java/org/mifos/mojaloop/OnboardDfsps.java new file mode 100644 index 000000000..1e7f3bb69 --- /dev/null +++ b/ph-ee-connector-common/src/test/java/org/mifos/mojaloop/OnboardDfsps.java @@ -0,0 +1,341 @@ +package org.mifos.mojaloop; + +import static java.util.Spliterators.spliteratorUnknownSize; +import static java.util.stream.StreamSupport.stream; + +import java.util.Spliterator; +import java.util.UUID; +import java.util.function.Consumer; +import org.json.JSONArray; +import org.json.JSONObject; +import org.junit.jupiter.api.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.ResponseEntity; +import org.springframework.web.client.RestTemplate; + +/** + * !!!READ COMMENTS!!! Compatible with Mojaloop version: 11.0.0 + */ +@SpringBootApplication +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE) +public class OnboardDfsps { + + private Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Value("${mojaloop.local}") + private boolean isLocalMojaloop; + + @Value("${local.central-ledger-host}") + private String localCentralLedger; + + @Value("${onboarding.enabled:false}") + private boolean onboardingEnabled; + + @Value("${oracle.host}") + private String oracleHost; + + @Value("${oracle.endpoint}") + private String oraclePath; + + @Value("${mojaloop.host}") + private String mojaHost; + + @Value("${mojaloop.currency}") + private String mojaCurrency; + + @Value("${mojaloop.contact-email}") + private String mojaConectacEmail; + + @Value("${mojaloop.central-ledger-service}") + private String mojaCentralLedgerService; + + @Value("${mojaloop.account-lookup-service}") + private String mojaAccountLookupService; + + @Value("${mojaloop.do-hub-onboard:true}") + private boolean doHubOnboard; + + @Value("${mojaloop.do-oracle-onboard:true}") + private boolean doOracleOnboard; + + @Value("${mojaloop.do-dfsp-onboard:true}") + private boolean doDfspOnboard; + + @Value("${mojaloop.participants.hub.endpoints}") + private String participantsHubEndpointsPath; + + @Value("${mojaloop.participants.hub.accounts}") + private String participantsHubAccountsPath; + + @Value("${mojaloop.oracles.endpoint}") + private String oraclesPath; + + @Value("${mojaloop.oracles.type}") + private String oraclesType; + + @Value("${mojaloop.participants.endpoint}") + private String participantsPath; + + @Value("${mojaloop.participants.position-and-limit-endpoint}") + private String participantsPositionAndLimitPath; + + @Value("${mojaloop.participants.registration-endpoint}") + private String participantsRegistrationPath; + + @Value("${mojaloop.participants.accounts-endpoint}") + private String participantsAccountsPath; + + @Autowired + private DfspProperties dfspProperties; + + @Autowired + private CallbackMappingProperties callbackMappingProperties; + + @Autowired + private RestTemplate template; + + public OnboardDfsps() { + System.setProperty("sun.net.http.allowRestrictedHeaders", "true"); + } + + @Test + public void onboard() { + /** + * Check also if you want to execute against a local installment or remote with peroperty: {mojaloop.local} + */ + if (!onboardingEnabled) { + logger.info("Onboarding turned off"); + return; + } + + /* + * these should be only run once / Mojaloop deployment, turn off manually after first run + */ + if (doHubOnboard) { + addHubAccountReconciliation(); + addHubAccountMultilateralSettlement(); + setHubEndpointSettlementTransferPositionChangeEmail(); + setHubEndpointNetDebitCapAdjustmentEmail(); + setHubEndpointNetDebitCapThresholdBreachEmail(); + } + + /* + * external oracle system called by Mojaloop to lookup participants, not the same as oracles in Mojaloop context + * this should be only run once / Mojaloop deployment, turn off manually after first run + */ + if (doOracleOnboard) { + createOracle(); + } + + /* + * every dfsp can be added separately, turn off selected ones from property + */ + if (doDfspOnboard) { + for (Dfsp dfsp : dfspProperties.getDfsps()) { + logger.info("Dfsp {} enabled: {}", dfsp.getId(), dfsp.isEnabled()); + if (dfsp.isEnabled()) { + logger.info("Onboarding dfsp: {}", dfsp.getId()); + if (dfsp.isRegisterOnlyCallbackUrls()) { + logger.info("Updating only dfsp callback urls: {}", dfsp.getId()); + updateCallbackUrls(dfsp); + continue; + } + String response = addDfsp(dfsp); + int settlementAccountId = ((JSONObject) stream( + spliteratorUnknownSize(new JSONObject(response).getJSONArray("accounts").iterator(), Spliterator.ORDERED), + false).filter(a -> "SETTLEMENT".equals(((JSONObject) a).getString("ledgerAccountType"))).findFirst() + .orElseThrow(() -> new RuntimeException("No SETTLEMENT account found!"))).getInt("id"); + addInitialPositionAndLimit(dfsp); + updateCallbackUrls(dfsp); + recordFundsInDfsp(dfsp, settlementAccountId); + /** + * if participants were already added to the external oracle before -> this part should be skipped + * this part is not dependant to mojaloop installment + */ + if (dfsp.isAddToExternalOracle()) { + addParticipantToDfsp(dfsp); // TODO multiple participants in single dfsp + } + } + } + } + } + + private void updateCallbackUrls(Dfsp dfsp) { + for (CallbackMapping mapping : callbackMappingProperties.getCallbackMappings()) { + addCallbackUrl(dfsp, mapping); + } + } + + private void addHubAccountReconciliation() { + JSONObject body = new JSONObject(); + String hub = "HUB_RECONCILIATION"; + body.put("type", hub); + body.put("currency", mojaCurrency); + + rest((isLocalMojaloop ? localCentralLedger : mojaHost) + participantsHubAccountsPath, mojaCentralLedgerService, body.toString(), + h -> {}); + logger.info("Hub '{}' added", hub); + } + + private void addHubAccountMultilateralSettlement() { + JSONObject body = new JSONObject(); + String hub = "HUB_MULTILATERAL_SETTLEMENT"; + body.put("type", hub); + body.put("currency", mojaCurrency); + + rest((isLocalMojaloop ? localCentralLedger : mojaHost) + participantsHubAccountsPath, mojaCentralLedgerService, body.toString(), + h -> {}); + logger.info("Hub '{}' added", hub); + } + + private void setHubEndpointSettlementTransferPositionChangeEmail() { + JSONObject body = new JSONObject(); + String email = "SETTLEMENT_TRANSFER_POSITION_CHANGE_EMAIL"; + body.put("type", email); + body.put("value", mojaConectacEmail); + + rest((isLocalMojaloop ? localCentralLedger : mojaHost) + participantsHubEndpointsPath, mojaCentralLedgerService, body.toString(), + h -> {}); + logger.info("Email '{}' added", email); + } + + private void setHubEndpointNetDebitCapAdjustmentEmail() { + JSONObject body = new JSONObject(); + String email = "NET_DEBIT_CAP_ADJUSTMENT_EMAIL"; + body.put("type", email); + body.put("value", mojaConectacEmail); + + rest((isLocalMojaloop ? localCentralLedger : mojaHost) + participantsHubEndpointsPath, mojaCentralLedgerService, body.toString(), + h -> {}); + logger.info("Email '{}' added", email); + } + + private void setHubEndpointNetDebitCapThresholdBreachEmail() { + JSONObject body = new JSONObject(); + String email = "NET_DEBIT_CAP_THRESHOLD_BREACH_EMAIL"; + body.put("type", email); + body.put("value", mojaConectacEmail); + + rest((isLocalMojaloop ? localCentralLedger : mojaHost) + participantsHubEndpointsPath, mojaCentralLedgerService, body.toString(), + h -> {}); + logger.info("Email '{}' added", email); + } + + private void createOracle() { + JSONObject body = new JSONObject(); + body.put("oracleIdType", oraclesType); + body.put("currency", mojaCurrency); + body.put("isDefault", true); + JSONObject endpoint = new JSONObject(); + endpoint.put("value", oracleHost + "/oracle"); + endpoint.put("endpointType", "URL"); + body.put("endpoint", endpoint); + + rest(mojaHost + oraclesPath, mojaAccountLookupService, body.toString(), h -> h.add("Date", "2019-09-20 08:52:19")); + logger.info("Oracle type '{}' with currency '{}' added", oraclesType, mojaCurrency); + } + + private String addDfsp(Dfsp dfsp) { + JSONObject body = new JSONObject(); + body.put("name", dfsp.getId()); + body.put("currency", mojaCurrency); + + String response = rest((isLocalMojaloop ? localCentralLedger : mojaHost) + participantsPath, mojaCentralLedgerService, + body.toString(), h -> {}); + logger.info("Dfsp added: {}", dfsp.getId()); + return response; + } + + private void addInitialPositionAndLimit(Dfsp dfsp) { + JSONObject body = new JSONObject(); + body.put("initialPosition", 0); + body.put("currency", mojaCurrency); + JSONObject limit = new JSONObject(); + limit.put("type", "NET_DEBIT_CAP"); + limit.put("value", dfsp.getFundsInPrepareAmount()); + body.put("limit", limit); + + rest((isLocalMojaloop ? localCentralLedger : mojaHost) + participantsPositionAndLimitPath.replace("{dfspid}", dfsp.getId()), + mojaCentralLedgerService, body.toString(), h -> {}); + logger.info("Dfsp limits and position added"); + } + + private void addCallbackUrl(Dfsp dfsp, CallbackMapping mapping) { + JSONObject body = new JSONObject(); + body.put("type", mapping.getType()); + String registeredValue = mapping.getType().contains("EMAIL") ? mapping.getValue().replace("{dfspDomain}", mojaConectacEmail) + : mapping.getValue().replace("{dfspDomain}", dfsp.getDomain()); + body.put("value", registeredValue); + + rest((isLocalMojaloop ? localCentralLedger : mojaHost) + participantsRegistrationPath.replace("{dfspid}", dfsp.getId()), + mojaCentralLedgerService, body.toString(), h -> {}); + logger.info("Registration success type: {} value: {}", mapping.getType(), registeredValue); + } + + private void recordFundsInDfsp(Dfsp dfsp, int settlementAccountId) { + JSONObject body = new JSONObject(); + body.put("transferId", UUID.randomUUID().toString()); + body.put("externalReference", "string"); + body.put("action", "recordFundsIn"); + body.put("reason", "string"); + JSONObject amount = new JSONObject(); + amount.put("amount", Integer.parseInt(dfsp.getFundsInPrepareAmount())); + amount.put("currency", mojaCurrency); + body.put("amount", amount); + JSONObject extensionList = new JSONObject(); + JSONArray extensionArray = new JSONArray(); + JSONObject extension = new JSONObject(); + extension.put("key", "string"); + extension.put("value", "string"); + extensionArray.put(extension); + extensionList.put("extension", extensionArray); + body.put("extensionList", extensionList); + + rest((isLocalMojaloop ? localCentralLedger : mojaHost) + participantsAccountsPath.replace("{dfspid}", dfsp.getId()) + .replace("{settlementAccountId}", String.valueOf(settlementAccountId)), mojaCentralLedgerService, body.toString(), h -> {}); + logger.info("Dfsp fund recorded: {} on settlement account: {}", Integer.parseInt(dfsp.getFundsInPrepareAmount()), + settlementAccountId); + } + + private void addParticipantToDfsp(Dfsp dfsp) { + JSONObject body = new JSONObject(); + body.put("fspId", dfsp.getId()); + body.put("currency", mojaCurrency); + + rest(oracleHost + + oraclePath.replace("{partyIdType}", dfsp.getPartyIdType()).replace("{partyIdentifier}", dfsp.getPartyIdentifier()), null, + body.toString(), h -> h.add("Date", "2019-09-20 08:52:19")); + logger.info("Client with type {} value {} added to {}", dfsp.getPartyIdType(), dfsp.getPartyIdentifier(), dfsp.getId()); + } + + private String rest(String url, String service, String body, Consumer extraHeaders) { + HttpHeaders headers = new HttpHeaders(); + headers.add("Content-Type", "application/json"); + if (service != null) { + headers.add("Host", service); + } + extraHeaders.accept(headers); + + try { + ResponseEntity exchange = template.exchange(url, HttpMethod.POST, new HttpEntity<>(body, headers), String.class); + if (exchange.getStatusCodeValue() < 200 || exchange.getStatusCodeValue() > 299) { + logger.error("Invalid code {} response {}", exchange.getStatusCodeValue(), exchange.getBody()); + throw new RuntimeException("Invalid response!"); + } else { + logger.info("Succes: {} status: {}", exchange.getBody(), exchange.getStatusCode()); + return exchange.getBody(); + } + } catch (Exception ex) { + logger.error("Error!", ex); + throw new RuntimeException("Invalid response!"); + } + } +} diff --git a/ph-ee-connector-common/src/test/java/org/mifos/mojaloop/TestConfig.java b/ph-ee-connector-common/src/test/java/org/mifos/mojaloop/TestConfig.java new file mode 100644 index 000000000..2f576c411 --- /dev/null +++ b/ph-ee-connector-common/src/test/java/org/mifos/mojaloop/TestConfig.java @@ -0,0 +1,15 @@ +package org.mifos.mojaloop; + +import org.springframework.boot.web.client.RestTemplateBuilder; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.client.RestTemplate; + +@Configuration +public class TestConfig { + + @Bean + public RestTemplate template(RestTemplateBuilder builder) { + return builder.build(); + } +} diff --git a/ph-ee-connector-common/src/test/resources/application.yml b/ph-ee-connector-common/src/test/resources/application.yml new file mode 100644 index 000000000..2612467ee --- /dev/null +++ b/ph-ee-connector-common/src/test/resources/application.yml @@ -0,0 +1,114 @@ +onboarding: + enabled: true + +oracle: + host: "http://account-oracle.mifos.io:4100" + endpoint: "/oracle/participants/{partyIdType}/{partyIdentifier}" + +local: + central-ledger-host: http://localhost:3001 + +mojaloop: + local: false + currency: "TZS" + contact-email: "contact@email.com" + host: "http://40.114.81.46" + account-lookup-service: "account-lookup-service-admin.local" + central-ledger-service: "central-ledger.local" + do-hub-onboard: false + participants: + endpoint: "/participants" + position-and-limit-endpoint: "${mojaloop.participants.endpoint}/{dfspid}/initialPositionAndLimits" + registration-endpoint: "${mojaloop.participants.endpoint}/{dfspid}/endpoints" + accounts-endpoint: "${mojaloop.participants.endpoint}/{dfspid}/accounts/{settlementAccountId}" + hub: + endpoint: "/Hub" + accounts: "${mojaloop.participants.endpoint}${mojaloop.participants.hub.endpoint}/accounts" + endpoints: "${mojaloop.participants.endpoint}${mojaloop.participants.hub.endpoint}/endpoints" + do-oracle-onboard: false + oracles: + type: "MSISDN" + endpoint: /oracles + do-dfsp-onboard: true + callbackMappings: + - type: "FSPIOP_CALLBACK_URL_PARTICIPANT_PUT" + value: "{dfspDomain}/participants/{{partyIdType}}/{{partyIdentifier}}" + - type: "FSPIOP_CALLBACK_URL_PARTICIPANT_PUT_ERROR" + value: "{dfspDomain}/participants/{{partyIdType}}/{{partyIdentifier}}/error" + - type: "FSPIOP_CALLBACK_URL_PARTICIPANT_BATCH_PUT" + value: "{dfspDomain}/participants/{{requestId}}" + - type: "FSPIOP_CALLBACK_URL_PARTICIPANT_BATCH_PUT_ERROR" + value: "{dfspDomain}/participants/{{requestId}}/error" + - type: "FSPIOP_CALLBACK_URL_PARTIES_GET" + value: "{dfspDomain}/parties/{{partyIdType}}/{{partyIdentifier}}" + - type: "FSPIOP_CALLBACK_URL_PARTIES_PUT" + value: "{dfspDomain}/parties/{{partyIdType}}/{{partyIdentifier}}" + - type: "FSPIOP_CALLBACK_URL_PARTIES_PUT_ERROR" + value: "{dfspDomain}/parties/{{partyIdType}}/{{partyIdentifier}}/error" + - type: "FSPIOP_CALLBACK_URL_QUOTES" + value: "{dfspDomain}" + - type: "FSPIOP_CALLBACK_URL_TRANSFER_POST" + value: "{dfspDomain}/transfers" + - type: "FSPIOP_CALLBACK_URL_TRANSFER_PUT" + value: "{dfspDomain}/transfers/{{transferId}}" + - type: "FSPIOP_CALLBACK_URL_TRANSFER_ERROR" + value: "{dfspDomain}/transfers/{{transferId}}/error" + - type: "FSPIOP_CALLBACK_URL_TRX_REQ_SERVICE" + value: "{dfspDomain}" + - type: "FSPIOP_CALLBACK_URL_AUTHORIZATIONS" + value: "{dfspDomain}" + - type: "NET_DEBIT_CAP_ADJUSTMENT_EMAIL" + value: "{dfspDomain}" + - type: "SETTLEMENT_TRANSFER_POSITION_CHANGE_EMAIL" + value: "{dfspDomain}" + - type: "NET_DEBIT_CAP_THRESHOLD_BREACH_EMAIL" + value: "{dfspDomain}" + dfsps: + - enabled: true + addToExternalOracle: false + registerOnlyCallbackUrls: true + id: "in01tn01" + partyIdType: "MSISDN" + partyIdentifier: "27710101999" + fundsInPrepareAmount: "1000000" + domain: "http://${mojaloop.dfsps[0].id}.mifos.io/switch" + - enabled: true + addToExternalOracle: false + registerOnlyCallbackUrls: true + id: "in01tn02" + partyIdType: "MSISDN" + partyIdentifier: "27710102999" + fundsInPrepareAmount: "1000000" + domain: "http://${mojaloop.dfsps[1].id}.mifos.io/switch" + - enabled: false + addToExternalOracle: false + registerOnlyCallbackUrls: false + id: "in02tn03" + partyIdType: "MSISDN" + partyIdentifier: "27710203999" + fundsInPrepareAmount: "1000000" + domain: "http://${mojaloop.dfsps[2].id}.mifos.io/switch" + - enabled: false + addToExternalOracle: false + registerOnlyCallbackUrls: false + id: "in02tn04" + partyIdType: "MSISDN" + partyIdentifier: "27710204999" + fundsInPrepareAmount: "1000000" + domain: "http://${mojaloop.dfsps[3].id}.mifos.io/switch" + - enabled: false + addToExternalOracle: false + registerOnlyCallbackUrls: false + id: "in03tn05" + partyIdType: "MSISDN" + partyIdentifier: "27710305999" + fundsInPrepareAmount: "1000000" + domain: "http://${mojaloop.dfsps[4].id}.mifos.io/switch" + - enabled: false + addToExternalOracle: false + registerOnlyCallbackUrls: false + id: "in03tn06" + partyIdType: "MSISDN" + partyIdentifier: "27710306999" + fundsInPrepareAmount: "1000000" + domain: "http://${mojaloop.dfsps[5].id}.mifos.io/switch" diff --git a/ph-ee-connector-common/src/test/resources/logback.xml b/ph-ee-connector-common/src/test/resources/logback.xml new file mode 100644 index 000000000..2a3aae5a4 --- /dev/null +++ b/ph-ee-connector-common/src/test/resources/logback.xml @@ -0,0 +1,18 @@ + + + + + + + + + ${CONSOLE_LOG_PATTERN} + utf8 + + + + + + + diff --git a/ph-ee-connector-crm/.circleci/config.yml b/ph-ee-connector-crm/.circleci/config.yml new file mode 100644 index 000000000..cad17bee7 --- /dev/null +++ b/ph-ee-connector-crm/.circleci/config.yml @@ -0,0 +1,101 @@ +version: 2.1 +executors: + docker-executor: + docker: + - image: circleci/openjdk:17-buster-node-browsers-legacy + auth: + username: $DOCKERHUB_USERNAME + password: $DOCKERHUB_PASSWORD + +jobs: + build_and_push_tag_image: + executor: docker-executor + environment: + JVM_OPTS: -Xmx512m + TERM: dumb + GITHUB_TOKEN: ${GITHUB_TOKEN} # Add the GitHub token as an environment variable + + steps: + - checkout + - setup_remote_docker: + version: 20.10.14 + - run: + name: Build and Push Docker tag Image + command: | + # Set environment variables + IMAGE_TAG=$CIRCLE_TAG + + # Check if the Docker image with the same tag already exists in Docker Hub + if curl -s -f -u "$DOCKERHUB_USERNAME":"$DOCKERHUB_PASSWORD" "https://hub.docker.com/v2/repositories/fynarfin/ph-ee-connector-crm/tags/$IMAGE_TAG" > /dev/null; then + echo "Skipping the build and push as the tag $IMAGE_TAG already exists in Docker Hub." + exit 0 + fi + + # Build and tag the Docker image + ./gradlew bootJar + docker build -t "fynarfin/ph-ee-connector-crm:$IMAGE_TAG" . + + # Push the Docker image to Docker Hub + docker login -u "$DOCKERHUB_USERNAME" -p "$DOCKERHUB_PASSWORD" + docker push "fynarfin/ph-ee-connector-crm:$IMAGE_TAG" + + # when: always # The job will be executed even if there's no match for the tag filter + + build_and_push_latest_image: + executor: docker-executor + environment: + JVM_OPTS: -Xmx512m + TERM: dumb + + steps: + - checkout + # Install Docker to build and push the image + - setup_remote_docker: + version: 20.10.14 + + # Build the Docker image + - run: + name: Build Docker image + command: | + ./gradlew bootJar + docker build -t fynarfin/ph-ee-connector-crm:latest . + if [ "$CIRCLE_BRANCH" != "develop" ]; then + PR_NUMBER=$(basename $CIRCLE_PULL_REQUEST) + PR_TITLE=$(curl -sSL "https://api.github.com/repos/fynarfin/$CIRCLE_PR_REPONAME/pulls/$PR_NUMBER" | jq -r '.title') + JIRA_STORY=$(echo $PR_TITLE | cut -d "[" -f2 | cut -d "]" -f1 | tr '[A-Z]' '[a-z]') + if [ -z "$JIRA_STORY" ]; then echo "Invalid PR title" && exit 1; else echo "Ticket NO: $JIRA_STORY"; fi + docker image tag fynarfin/$CIRCLE_PR_REPONAME:latest fynarfin/$CIRCLE_PR_REPONAME:$JIRA_STORY + fi + + # Log in to DockerHub using environment variables + - run: + name: Login to DockerHub + command: echo "${DOCKERHUB_PASSWORD}" | docker login -u "${DOCKERHUB_USERNAME}" --password-stdin + + # Push the Docker image to DockerHub + - run: + name: Push Docker image to DockerHub + command: | + if [ "$CIRCLE_BRANCH" = "develop" ]; then + docker push fynarfin/ph-ee-connector-crm:latest + fi + if [ "$CIRCLE_BRANCH" != "develop" ]; then + PR_NUMBER=$(basename $CIRCLE_PULL_REQUEST) + PR_TITLE=$(curl -sSL "https://api.github.com/repos/fynarfin/$CIRCLE_PR_REPONAME/pulls/$PR_NUMBER" | jq -r '.title') + JIRA_STORY=$(echo $PR_TITLE | cut -d "[" -f2 | cut -d "]" -f1 | tr '[A-Z]' '[a-z]') + docker push fynarfin/$CIRCLE_PR_REPONAME:${JIRA_STORY} + fi + +workflows: + version: 2 + build-and-push: + jobs: + - build_and_push_tag_image: + filters: + tags: + only: /^v\d+\.\d+\.\d+$/ # Match tags in the format v1.2.3 + context: + - DOCKER + - build_and_push_latest_image: + context: + - DOCKER diff --git a/ph-ee-connector-crm/.github/pull_request_template.md b/ph-ee-connector-crm/.github/pull_request_template.md new file mode 100644 index 000000000..1d44d4817 --- /dev/null +++ b/ph-ee-connector-crm/.github/pull_request_template.md @@ -0,0 +1,22 @@ +## Description + +* PR title should have jira ticket enclosed in `[]`.
+ Format: ``` [jira_ticket] description```
+ ex: [phee-123] PR title. +* Add a link to the Jira ticket. +* Describe the changes made and why they were made. + +## Checklist + +Please make sure these boxes are checked before submitting your pull request - thanks! +- [ ] Followed the PR title naming convention mentioned above. + +- [ ] Design related bullet points or design document link related to this PR added in the description above. + +- [ ] Updated corresponding Postman Collection or Api documentation for the changes in this PR. + +- [ ] Create/update unit or integration tests for verifying the changes made. + +- [ ] Add required Swagger annotation and update API documentation with details of any API changes if applicable + +- [ ] Followed the naming conventions as given in https://docs.google.com/document/d/1Q4vaMSzrTxxh9TS0RILuNkSkYCxotuYk1Xe0CMIkkCU/edit?usp=sharing diff --git a/ph-ee-connector-crm/.gitignore b/ph-ee-connector-crm/.gitignore new file mode 100644 index 000000000..c2065bc26 --- /dev/null +++ b/ph-ee-connector-crm/.gitignore @@ -0,0 +1,37 @@ +HELP.md +.gradle +build/ +!gradle/wrapper/gradle-wrapper.jar +!**/src/main/**/build/ +!**/src/test/**/build/ + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache +bin/ +!**/src/main/**/bin/ +!**/src/test/**/bin/ + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr +out/ +!**/src/main/**/out/ +!**/src/test/**/out/ + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ + +### VS Code ### +.vscode/ diff --git a/ph-ee-connector-crm/Dockerfile b/ph-ee-connector-crm/Dockerfile new file mode 100644 index 000000000..7477fba78 --- /dev/null +++ b/ph-ee-connector-crm/Dockerfile @@ -0,0 +1,5 @@ +FROM openjdk:17 +EXPOSE 8080 + +COPY build/libs/*.jar ./ +CMD java -jar *.jar diff --git a/ph-ee-connector-crm/LICENSE b/ph-ee-connector-crm/LICENSE new file mode 100644 index 000000000..a612ad981 --- /dev/null +++ b/ph-ee-connector-crm/LICENSE @@ -0,0 +1,373 @@ +Mozilla Public License Version 2.0 +================================== + +1. Definitions +-------------- + +1.1. "Contributor" + means each individual or legal entity that creates, contributes to + the creation of, or owns Covered Software. + +1.2. "Contributor Version" + means the combination of the Contributions of others (if any) used + by a Contributor and that particular Contributor's Contribution. + +1.3. "Contribution" + means Covered Software of a particular Contributor. + +1.4. "Covered Software" + means Source Code Form to which the initial Contributor has attached + the notice in Exhibit A, the Executable Form of such Source Code + Form, and Modifications of such Source Code Form, in each case + including portions thereof. + +1.5. "Incompatible With Secondary Licenses" + means + + (a) that the initial Contributor has attached the notice described + in Exhibit B to the Covered Software; or + + (b) that the Covered Software was made available under the terms of + version 1.1 or earlier of the License, but not also under the + terms of a Secondary License. + +1.6. "Executable Form" + means any form of the work other than Source Code Form. + +1.7. "Larger Work" + means a work that combines Covered Software with other material, in + a separate file or files, that is not Covered Software. + +1.8. "License" + means this document. + +1.9. "Licensable" + means having the right to grant, to the maximum extent possible, + whether at the time of the initial grant or subsequently, any and + all of the rights conveyed by this License. + +1.10. "Modifications" + means any of the following: + + (a) any file in Source Code Form that results from an addition to, + deletion from, or modification of the contents of Covered + Software; or + + (b) any new file in Source Code Form that contains any Covered + Software. + +1.11. "Patent Claims" of a Contributor + means any patent claim(s), including without limitation, method, + process, and apparatus claims, in any patent Licensable by such + Contributor that would be infringed, but for the grant of the + License, by the making, using, selling, offering for sale, having + made, import, or transfer of either its Contributions or its + Contributor Version. + +1.12. "Secondary License" + means either the GNU General Public License, Version 2.0, the GNU + Lesser General Public License, Version 2.1, the GNU Affero General + Public License, Version 3.0, or any later versions of those + licenses. + +1.13. "Source Code Form" + means the form of the work preferred for making modifications. + +1.14. "You" (or "Your") + means an individual or a legal entity exercising rights under this + License. For legal entities, "You" includes any entity that + controls, is controlled by, or is under common control with You. For + purposes of this definition, "control" means (a) the power, direct + or indirect, to cause the direction or management of such entity, + whether by contract or otherwise, or (b) ownership of more than + fifty percent (50%) of the outstanding shares or beneficial + ownership of such entity. + +2. License Grants and Conditions +-------------------------------- + +2.1. Grants + +Each Contributor hereby grants You a world-wide, royalty-free, +non-exclusive license: + +(a) under intellectual property rights (other than patent or trademark) + Licensable by such Contributor to use, reproduce, make available, + modify, display, perform, distribute, and otherwise exploit its + Contributions, either on an unmodified basis, with Modifications, or + as part of a Larger Work; and + +(b) under Patent Claims of such Contributor to make, use, sell, offer + for sale, have made, import, and otherwise transfer either its + Contributions or its Contributor Version. + +2.2. Effective Date + +The licenses granted in Section 2.1 with respect to any Contribution +become effective for each Contribution on the date the Contributor first +distributes such Contribution. + +2.3. Limitations on Grant Scope + +The licenses granted in this Section 2 are the only rights granted under +this License. No additional rights or licenses will be implied from the +distribution or licensing of Covered Software under this License. +Notwithstanding Section 2.1(b) above, no patent license is granted by a +Contributor: + +(a) for any code that a Contributor has removed from Covered Software; + or + +(b) for infringements caused by: (i) Your and any other third party's + modifications of Covered Software, or (ii) the combination of its + Contributions with other software (except as part of its Contributor + Version); or + +(c) under Patent Claims infringed by Covered Software in the absence of + its Contributions. + +This License does not grant any rights in the trademarks, service marks, +or logos of any Contributor (except as may be necessary to comply with +the notice requirements in Section 3.4). + +2.4. Subsequent Licenses + +No Contributor makes additional grants as a result of Your choice to +distribute the Covered Software under a subsequent version of this +License (see Section 10.2) or under the terms of a Secondary License (if +permitted under the terms of Section 3.3). + +2.5. Representation + +Each Contributor represents that the Contributor believes its +Contributions are its original creation(s) or it has sufficient rights +to grant the rights to its Contributions conveyed by this License. + +2.6. Fair Use + +This License is not intended to limit any rights You have under +applicable copyright doctrines of fair use, fair dealing, or other +equivalents. + +2.7. Conditions + +Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted +in Section 2.1. + +3. Responsibilities +------------------- + +3.1. Distribution of Source Form + +All distribution of Covered Software in Source Code Form, including any +Modifications that You create or to which You contribute, must be under +the terms of this License. You must inform recipients that the Source +Code Form of the Covered Software is governed by the terms of this +License, and how they can obtain a copy of this License. You may not +attempt to alter or restrict the recipients' rights in the Source Code +Form. + +3.2. Distribution of Executable Form + +If You distribute Covered Software in Executable Form then: + +(a) such Covered Software must also be made available in Source Code + Form, as described in Section 3.1, and You must inform recipients of + the Executable Form how they can obtain a copy of such Source Code + Form by reasonable means in a timely manner, at a charge no more + than the cost of distribution to the recipient; and + +(b) You may distribute such Executable Form under the terms of this + License, or sublicense it under different terms, provided that the + license for the Executable Form does not attempt to limit or alter + the recipients' rights in the Source Code Form under this License. + +3.3. Distribution of a Larger Work + +You may create and distribute a Larger Work under terms of Your choice, +provided that You also comply with the requirements of this License for +the Covered Software. If the Larger Work is a combination of Covered +Software with a work governed by one or more Secondary Licenses, and the +Covered Software is not Incompatible With Secondary Licenses, this +License permits You to additionally distribute such Covered Software +under the terms of such Secondary License(s), so that the recipient of +the Larger Work may, at their option, further distribute the Covered +Software under the terms of either this License or such Secondary +License(s). + +3.4. Notices + +You may not remove or alter the substance of any license notices +(including copyright notices, patent notices, disclaimers of warranty, +or limitations of liability) contained within the Source Code Form of +the Covered Software, except that You may alter any license notices to +the extent required to remedy known factual inaccuracies. + +3.5. Application of Additional Terms + +You may choose to offer, and to charge a fee for, warranty, support, +indemnity or liability obligations to one or more recipients of Covered +Software. However, You may do so only on Your own behalf, and not on +behalf of any Contributor. You must make it absolutely clear that any +such warranty, support, indemnity, or liability obligation is offered by +You alone, and You hereby agree to indemnify every Contributor for any +liability incurred by such Contributor as a result of warranty, support, +indemnity or liability terms You offer. You may include additional +disclaimers of warranty and limitations of liability specific to any +jurisdiction. + +4. Inability to Comply Due to Statute or Regulation +--------------------------------------------------- + +If it is impossible for You to comply with any of the terms of this +License with respect to some or all of the Covered Software due to +statute, judicial order, or regulation then You must: (a) comply with +the terms of this License to the maximum extent possible; and (b) +describe the limitations and the code they affect. Such description must +be placed in a text file included with all distributions of the Covered +Software under this License. Except to the extent prohibited by statute +or regulation, such description must be sufficiently detailed for a +recipient of ordinary skill to be able to understand it. + +5. Termination +-------------- + +5.1. The rights granted under this License will terminate automatically +if You fail to comply with any of its terms. However, if You become +compliant, then the rights granted under this License from a particular +Contributor are reinstated (a) provisionally, unless and until such +Contributor explicitly and finally terminates Your grants, and (b) on an +ongoing basis, if such Contributor fails to notify You of the +non-compliance by some reasonable means prior to 60 days after You have +come back into compliance. Moreover, Your grants from a particular +Contributor are reinstated on an ongoing basis if such Contributor +notifies You of the non-compliance by some reasonable means, this is the +first time You have received notice of non-compliance with this License +from such Contributor, and You become compliant prior to 30 days after +Your receipt of the notice. + +5.2. If You initiate litigation against any entity by asserting a patent +infringement claim (excluding declaratory judgment actions, +counter-claims, and cross-claims) alleging that a Contributor Version +directly or indirectly infringes any patent, then the rights granted to +You by any and all Contributors for the Covered Software under Section +2.1 of this License shall terminate. + +5.3. In the event of termination under Sections 5.1 or 5.2 above, all +end user license agreements (excluding distributors and resellers) which +have been validly granted by You or Your distributors under this License +prior to termination shall survive termination. + +************************************************************************ +* * +* 6. Disclaimer of Warranty * +* ------------------------- * +* * +* Covered Software is provided under this License on an "as is" * +* basis, without warranty of any kind, either expressed, implied, or * +* statutory, including, without limitation, warranties that the * +* Covered Software is free of defects, merchantable, fit for a * +* particular purpose or non-infringing. The entire risk as to the * +* quality and performance of the Covered Software is with You. * +* Should any Covered Software prove defective in any respect, You * +* (not any Contributor) assume the cost of any necessary servicing, * +* repair, or correction. This disclaimer of warranty constitutes an * +* essential part of this License. No use of any Covered Software is * +* authorized under this License except under this disclaimer. * +* * +************************************************************************ + +************************************************************************ +* * +* 7. Limitation of Liability * +* -------------------------- * +* * +* Under no circumstances and under no legal theory, whether tort * +* (including negligence), contract, or otherwise, shall any * +* Contributor, or anyone who distributes Covered Software as * +* permitted above, be liable to You for any direct, indirect, * +* special, incidental, or consequential damages of any character * +* including, without limitation, damages for lost profits, loss of * +* goodwill, work stoppage, computer failure or malfunction, or any * +* and all other commercial damages or losses, even if such party * +* shall have been informed of the possibility of such damages. This * +* limitation of liability shall not apply to liability for death or * +* personal injury resulting from such party's negligence to the * +* extent applicable law prohibits such limitation. Some * +* jurisdictions do not allow the exclusion or limitation of * +* incidental or consequential damages, so this exclusion and * +* limitation may not apply to You. * +* * +************************************************************************ + +8. Litigation +------------- + +Any litigation relating to this License may be brought only in the +courts of a jurisdiction where the defendant maintains its principal +place of business and such litigation shall be governed by laws of that +jurisdiction, without reference to its conflict-of-law provisions. +Nothing in this Section shall prevent a party's ability to bring +cross-claims or counter-claims. + +9. Miscellaneous +---------------- + +This License represents the complete agreement concerning the subject +matter hereof. If any provision of this License is held to be +unenforceable, such provision shall be reformed only to the extent +necessary to make it enforceable. Any law or regulation which provides +that the language of a contract shall be construed against the drafter +shall not be used to construe this License against a Contributor. + +10. Versions of the License +--------------------------- + +10.1. New Versions + +Mozilla Foundation is the license steward. Except as provided in Section +10.3, no one other than the license steward has the right to modify or +publish new versions of this License. Each version will be given a +distinguishing version number. + +10.2. Effect of New Versions + +You may distribute the Covered Software under the terms of the version +of the License under which You originally received the Covered Software, +or under the terms of any subsequent version published by the license +steward. + +10.3. Modified Versions + +If you create software not governed by this License, and you want to +create a new license for such software, you may create and use a +modified version of this License if you rename the license and remove +any references to the name of the license steward (except to note that +such modified license differs from this License). + +10.4. Distributing Source Code Form that is Incompatible With Secondary +Licenses + +If You choose to distribute Source Code Form that is Incompatible With +Secondary Licenses under the terms of this version of the License, the +notice described in Exhibit B of this License must be attached. + +Exhibit A - Source Code Form License Notice +------------------------------------------- + + This Source Code Form is subject to the terms of the Mozilla Public + License, v. 2.0. If a copy of the MPL was not distributed with this + file, You can obtain one at http://mozilla.org/MPL/2.0/. + +If it is not possible or desirable to put the notice in a particular +file, then You may include the notice in a location (such as a LICENSE +file in a relevant directory) where a recipient would be likely to look +for such a notice. + +You may add additional accurate notices of copyright ownership. + +Exhibit B - "Incompatible With Secondary Licenses" Notice +--------------------------------------------------------- + + This Source Code Form is "Incompatible With Secondary Licenses", as + defined by the Mozilla Public License, v. 2.0. diff --git a/ph-ee-connector-crm/README.md b/ph-ee-connector-crm/README.md new file mode 100644 index 000000000..83f861711 --- /dev/null +++ b/ph-ee-connector-crm/README.md @@ -0,0 +1,4 @@ +# payment-hub-ee +Payment Hub Enterprise Edition middleware for integration to real-time payment systems. + +For detailed documentation check the documentation: https://app.gitbook.com/@mifos/s/docs/payment-hub-ee/overview diff --git a/ph-ee-connector-crm/build.gradle b/ph-ee-connector-crm/build.gradle new file mode 100644 index 000000000..fe2201444 --- /dev/null +++ b/ph-ee-connector-crm/build.gradle @@ -0,0 +1,305 @@ +/* + * This file was generated by the Gradle 'init' task. + */ + +plugins { + id 'java' + id 'maven-publish' + id 'eclipse' + id 'checkstyle' + id 'org.springframework.boot' version '2.6.2' + id 'com.diffplug.spotless' version '6.19.0' + id 'net.ltgt.errorprone' version '3.1.0' +} + +repositories { + mavenLocal() + maven { + url = uri('https://repo.maven.apache.org/maven2') + } + + maven { + url = uri('https://jfrog.sandbox.fynarfin.io/artifactory/fyn-libs-snapshot') + } +} + +apply plugin:'com.diffplug.spotless' +spotless { + format 'misc', { + target '**/*.md', '**/*.properties', '**/.gitignore', '**/.openapi-generator-ignore', '**/*.yml', '**/*.xml', '**/**.json', '**/*.sql' + targetExclude '**/build/**','**/gsmastub/**', '**/bin/**', '**/.settings/**', '**/.idea/**', '**/.gradle/**', '**/gradlew.bat', '**/licenses/**', '**/banner.txt', '.vscode/**' + indentWithSpaces(4) + endWithNewline() + trimTrailingWhitespace() + } + + groovyGradle { + target '*.gradle', '**/*.gradle' + targetExclude '**/build/**', '**/gsmastub/**' + greclipse() + indentWithSpaces(4) + endWithNewline() + trimTrailingWhitespace() + } + + lineEndings 'UNIX' +} + +ext { + springBootVersion = '2.6.2' +} + +dependencies { + implementation 'com.google.code.gson:gson:2.8.9' + implementation 'org.mifos:ph-ee-connector-common:1.8.1-SNAPSHOT' + implementation 'org.apache.camel.springboot:camel-spring-boot-starter:3.12.0' + implementation('org.springframework.boot:spring-boot-starter-web:2.6.2') + implementation "org.springframework.boot:spring-boot-starter-actuator:$springBootVersion" + implementation 'org.apache.camel:camel-endpointdsl:3.12.0' + implementation 'org.apache.camel:camel-jetty:3.12.0' + implementation 'org.apache.camel:camel-http:3.12.0' + implementation 'org.springframework:spring-web:5.3.15' + implementation 'org.apache.camel:camel-bean-validator:3.12.0' + implementation 'org.apache.camel:camel-undertow:3.12.0' + implementation 'org.apache.camel.springboot:camel-jackson-starter:3.12.0' + implementation 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.13.1' + implementation 'org.json:json:20211205' + implementation 'io.camunda:zeebe-client-java:8.1.1' + testImplementation 'org.springframework.boot:spring-boot-starter-test:2.6.2' + testImplementation 'org.springframework.boot:spring-boot-starter-test:2.6.2' + implementation 'javax.servlet:javax.servlet-api:3.1.0' + implementation 'commons-codec:commons-codec:1.15' + implementation 'commons-io:commons-io:2.11.0' + implementation 'io.springfox:springfox-swagger-ui:3.0.0' + implementation 'io.springfox:springfox-oas:3.0.0' + implementation 'com.github.joschi.jackson:jackson-datatype-threetenbp:2.6.4' + implementation "org.springdoc:springdoc-openapi-ui:1.6.11" + implementation 'org.projectlombok:lombok:1.18.22' + annotationProcessor 'org.projectlombok:lombok:1.18.24' + checkstyle 'com.puppycrawl.tools:checkstyle:10.9.3' + checkstyle 'com.github.sevntu-checkstyle:sevntu-checks:1.44.1' + implementation 'com.diffplug.gradle.spotless:spotless:2.4.1' + implementation 'com.diffplug.spotless:spotless-plugin-gradle:6.17.0' +} + +configure(this) { + // NOTE: order matters! + apply plugin: 'java' + apply plugin: 'idea' + apply plugin: 'eclipse' + apply plugin: 'checkstyle' + apply plugin: 'net.ltgt.errorprone' + configurations { + implementation.setCanBeResolved(true) + api.setCanBeResolved(true) + } + tasks.withType(JavaCompile) { + options.compilerArgs += [ + "-Xlint:unchecked", + "-Xlint:cast", + "-Xlint:auxiliaryclass", + "-Xlint:deprecation", + "-Xlint:dep-ann", + "-Xlint:divzero", + "-Xlint:empty", + "-Xlint:exports", + "-Xlint:fallthrough", + "-Xlint:finally", + "-Xlint:module", + "-Xlint:opens", + "-Xlint:options", + "-Xlint:overloads", + "-Xlint:overrides", + "-Xlint:path", + "-Xlint:processing", + "-Xlint:removal", + "-Xlint:requires-automatic", + "-Xlint:requires-transitive-automatic", + "-Xlint:try", + "-Xlint:varargs", + "-Xlint:preview", + "-Xlint:static", + // -Werror needs to be disabled because EclipseLink's static weaving doesn't generate warning-free code + // and during an IntelliJ recompilation, it fails + //"-Werror", + "-Xmaxwarns", + 1500, + "-Xmaxerrs", + 1500 + ] + options.deprecation = true + } + // Configuration for the spotless plugin + // https://github.com/diffplug/spotless/tree/main/plugin-gradle + spotless { + java { + targetExclude '**/build/**', '**/bin/**', '**/out/**', '**/gsmastub/**' + importOrder() //sort imports alphabetically + removeUnusedImports() + eclipse().configFile "$rootDir/ph-ee-connector-crm/config/crm-formatter.xml" + endWithNewline() + trimTrailingWhitespace() + // Enforce style modifier order + custom 'Modifier ordering', { + def modifierRanking = [ + public : 1, + protected : 2, + private : 3, + abstract : 4, + default : 5, + static : 6, + final : 7, + transient : 8, + volatile : 9, + synchronized: 10, + native : 11, + strictfp : 12] + // Find any instance of multiple modifiers. Lead with a non-word character to avoid + // accidental matching against for instance, "an alternative default value" + it.replaceAll(/\W(?:public |protected |private |abstract |default |static |final |transient |volatile |synchronized |native |strictfp ){2,}/, { + // Do not replace the leading non-word character. Identify the modifiers + it.replaceAll(/(?:public |protected |private |abstract |default |static |final |transient |volatile |synchronized |native |strictfp ){2,}/, { + // Sort the modifiers according to the ranking above + it.split().sort({ modifierRanking[it] }).join(' ') + ' ' + } + ) + } + ) + } + } + lineEndings 'UNIX' + } + // If we are running Gradle within Eclipse to enhance classes, + // set the classes directory to point to Eclipse's default build directory + if (project.hasProperty('env') && project.getProperty('env') == 'eclipse') { + sourceSets.main.java.outputDir = file("$projectDir/bin/main") + } + // Configuration for the Checkstyle plugin + // https://docs.gradle.org/current/userguide/checkstyle_plugin.html + dependencies { + checkstyle 'com.puppycrawl.tools:checkstyle:10.3.1' + checkstyle 'com.github.sevntu-checkstyle:sevntu-checks:1.42.0' + } + // Configuration for the errorprone plugin + // https://github.com/tbroyer/gradle-errorprone-plugin + dependencies { + errorprone "com.google.errorprone:error_prone_core:2.20.0" + } + + tasks.withType(JavaCompile) { + options.errorprone { + enabled = project.gradle.startParameter.taskNames.contains('build') || project.gradle.startParameter.taskNames.contains('check') + disableWarningsInGeneratedCode = true + excludedPaths = ".*/build/.*" + disable( + // TODO Remove disabled checks from this list, by fixing remaining usages + "UnusedVariable", + "TypeParameterUnusedInFormals", + "EmptyBlockTag", + "MissingSummary", + "InvalidParam", + "ReturnFromVoid", + "AlmostJavadoc", + "InvalidBlockTag", + "JavaUtilDate", // TODO FINERACT-1298 + "ReturnValueIgnored", + "DirectInvocationOnMock", + "CanIgnoreReturnValueSuggester", + "SameNameButDifferent", // Until errorprone recognizes Lombok + "MultiVariableDeclaration", // Until errorprone recognizes Lombok + "UnnecessaryDefaultInEnumSwitch" // FINERACT-1911 + ) + error( + "DefaultCharset", + "RemoveUnusedImports", + "WaitNotInLoop", + "ThreeLetterTimeZoneID", + "VariableNameSameAsType", + "UnnecessaryParentheses", + "MultipleTopLevelClasses", + "MixedMutabilityReturnType", + "AssertEqualsArgumentOrderChecker", + "EmptySetMultibindingContributions", + "BigDecimalEquals", + "MixedArrayDimensions", + "PackageLocation", + "UseBinds", + "BadImport", + "IntLongMath", + "FloatCast", + "ReachabilityFenceUsage", + "StreamResourceLeak", + "TruthIncompatibleType", + "ByteBufferBackingArray", + "OrphanedFormatString", + "CatchAndPrintStackTrace", + "ObjectToString", + "StringSplitter", + "AssertThrowsMultipleStatements", + "BoxedPrimitiveConstructor", + "EmptyCatch", + "BoxedPrimitiveEquality", + "SynchronizeOnNonFinalField", + "WildcardImport", + "PrivateConstructorForNoninstantiableModule", + "ClassCanBeStatic", + "ClassNewInstance", + "UnnecessaryStaticImport", + "UnsafeFinalization", + "JavaTimeDefaultTimeZone", + "JodaPlusMinusLong", + "SwitchDefault", + "VarTypeName", + "ArgumentSelectionDefectChecker", + "CompareToZero", + "InjectOnConstructorOfAbstractClass", + "ImmutableEnumChecker", + "NarrowingCompoundAssignment", + "MissingCasesInEnumSwitch", + "ReferenceEquality", + "UndefinedEquals", + "UnescapedEntity", + "ModifyCollectionInEnhancedForLoop", + "NonCanonicalType", + "InvalidInlineTag", + "MutablePublicArray", + "StaticAssignmentInConstructor", + "ProtectedMembersInFinalClass", + "OperatorPrecedence", + "EqualsGetClass", + "EqualsUnsafeCast", + "DoubleBraceInitialization", + "UnusedNestedClass", + "UnusedMethod", + "ModifiedButNotUsed", + "InconsistentCapitalization", + "MissingOverride", + ) + } + } +} + + + + +group = 'org.mifos' +version = '1.0.0-SNAPSHOT' +sourceCompatibility = JavaVersion.VERSION_17 +targetCompatibility = JavaVersion.VERSION_17 + +test { + useJUnitPlatform() +} + +publishing { + publications { + maven(MavenPublication) { + from(components.java) + } + } +} + + +tasks.withType(JavaCompile) { + options.encoding = 'UTF-8' +} diff --git a/ph-ee-connector-crm/config/checkstyle/checkstyle.xml b/ph-ee-connector-crm/config/checkstyle/checkstyle.xml new file mode 100644 index 000000000..5183efef5 --- /dev/null +++ b/ph-ee-connector-crm/config/checkstyle/checkstyle.xml @@ -0,0 +1,266 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ph-ee-connector-crm/config/checkstyle/suppressions.xml b/ph-ee-connector-crm/config/checkstyle/suppressions.xml new file mode 100644 index 000000000..f4e5b54c3 --- /dev/null +++ b/ph-ee-connector-crm/config/checkstyle/suppressions.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + diff --git a/ph-ee-connector-crm/config/crm-cleanup.xml b/ph-ee-connector-crm/config/crm-cleanup.xml new file mode 100644 index 000000000..a6e3c5b99 --- /dev/null +++ b/ph-ee-connector-crm/config/crm-cleanup.xml @@ -0,0 +1,71 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ph-ee-connector-crm/config/crm-formatter.xml b/ph-ee-connector-crm/config/crm-formatter.xml new file mode 100644 index 000000000..b9922d974 --- /dev/null +++ b/ph-ee-connector-crm/config/crm-formatter.xml @@ -0,0 +1,366 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ph-ee-connector-crm/gradle/wrapper/gradle-wrapper.jar b/ph-ee-connector-crm/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 000000000..033e24c4c Binary files /dev/null and b/ph-ee-connector-crm/gradle/wrapper/gradle-wrapper.jar differ diff --git a/ph-ee-connector-crm/gradle/wrapper/gradle-wrapper.properties b/ph-ee-connector-crm/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 000000000..774fae876 --- /dev/null +++ b/ph-ee-connector-crm/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.1-bin.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/ph-ee-connector-crm/gradlew b/ph-ee-connector-crm/gradlew new file mode 100755 index 000000000..fcb6fca14 --- /dev/null +++ b/ph-ee-connector-crm/gradlew @@ -0,0 +1,248 @@ +#!/bin/sh + +# +# Copyright © 2015-2021 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/ph-ee-connector-crm/gradlew.bat b/ph-ee-connector-crm/gradlew.bat new file mode 100644 index 000000000..6689b85be --- /dev/null +++ b/ph-ee-connector-crm/gradlew.bat @@ -0,0 +1,92 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 0 goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/ph-ee-connector-crm/settings.gradle b/ph-ee-connector-crm/settings.gradle new file mode 100644 index 000000000..02c1b7172 --- /dev/null +++ b/ph-ee-connector-crm/settings.gradle @@ -0,0 +1 @@ +rootProject.name = 'ph-ee-connector-crm' diff --git a/ph-ee-connector-crm/src/main/java/org/mifos/connector/PheeConnectorCrmApplication.java b/ph-ee-connector-crm/src/main/java/org/mifos/connector/PheeConnectorCrmApplication.java new file mode 100644 index 000000000..753546435 --- /dev/null +++ b/ph-ee-connector-crm/src/main/java/org/mifos/connector/PheeConnectorCrmApplication.java @@ -0,0 +1,15 @@ +package org.mifos.connector; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.ComponentScan; + +@SpringBootApplication +@ComponentScan("org.mifos.connector.crm") +public class PheeConnectorCrmApplication { + + public static void main(String[] args) { + SpringApplication.run(PheeConnectorCrmApplication.class, args); + } + +} diff --git a/ph-ee-connector-crm/src/main/java/org/mifos/connector/crm/api/definition/BillInquiryApi.java b/ph-ee-connector-crm/src/main/java/org/mifos/connector/crm/api/definition/BillInquiryApi.java new file mode 100644 index 000000000..b36ca426b --- /dev/null +++ b/ph-ee-connector-crm/src/main/java/org/mifos/connector/crm/api/definition/BillInquiryApi.java @@ -0,0 +1,24 @@ +package org.mifos.connector.crm.api.definition; + +import static org.mifos.connector.crm.zeebe.ZeebeVariables.*; + +import com.fasterxml.jackson.core.JsonProcessingException; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import java.util.concurrent.ExecutionException; +import org.mifos.connector.crm.data.BillInquiryResponseDTO; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestHeader; +import org.springframework.web.bind.annotation.RequestParam; + +@Tag(name = "GOV") +public interface BillInquiryApi { + + @Operation(summary = "Bill Fetch API from PBB to Bill Agg") + @GetMapping("/bills/{billId}") + BillInquiryResponseDTO billInquiry(@RequestHeader(value = PLATFORM_TENANT) String tenantId, + @RequestHeader(value = CLIENTCORRELATIONID) String correlationId, @RequestHeader(value = PAYER_FSP) String payerFspId, + @PathVariable(value = BILL_ID) String billId, @RequestParam(value = FIELDS, defaultValue = "inquiry") String field) + throws ExecutionException, InterruptedException, JsonProcessingException; +} diff --git a/ph-ee-connector-crm/src/main/java/org/mifos/connector/crm/api/definition/BillPaymentsApi.java b/ph-ee-connector-crm/src/main/java/org/mifos/connector/crm/api/definition/BillPaymentsApi.java new file mode 100644 index 000000000..e9f80a217 --- /dev/null +++ b/ph-ee-connector-crm/src/main/java/org/mifos/connector/crm/api/definition/BillPaymentsApi.java @@ -0,0 +1,21 @@ +package org.mifos.connector.crm.api.definition; + +import static org.mifos.connector.crm.zeebe.ZeebeVariables.*; + +import com.fasterxml.jackson.core.JsonProcessingException; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import java.util.concurrent.ExecutionException; +import org.mifos.connector.crm.data.BillPaymentsReqDTO; +import org.mifos.connector.crm.data.BillPaymentsResponseDTO; +import org.springframework.web.bind.annotation.*; + +@Tag(name = "GOV") +public interface BillPaymentsApi { + + @Operation(summary = "Bill Payments API from Payer FSP to PBB") + @PostMapping("/paymentNotifications") + BillPaymentsResponseDTO billPayments(@RequestHeader(value = PLATFORM_TENANT) String tenantId, + @RequestHeader(value = CLIENTCORRELATIONID) String correlationId, @RequestHeader(value = PAYER_FSP) String payerFspId, + @RequestBody BillPaymentsReqDTO body) throws ExecutionException, InterruptedException, JsonProcessingException; +} diff --git a/ph-ee-connector-crm/src/main/java/org/mifos/connector/crm/api/definition/BillRtpRespApi.java b/ph-ee-connector-crm/src/main/java/org/mifos/connector/crm/api/definition/BillRtpRespApi.java new file mode 100644 index 000000000..cdeb7af93 --- /dev/null +++ b/ph-ee-connector-crm/src/main/java/org/mifos/connector/crm/api/definition/BillRtpRespApi.java @@ -0,0 +1,25 @@ +package org.mifos.connector.crm.api.definition; + +import static org.mifos.connector.crm.zeebe.ZeebeVariables.CLIENTCORRELATIONID; +import static org.mifos.connector.crm.zeebe.ZeebeVariables.PLATFORM_TENANT; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.parameters.RequestBody; +import io.swagger.v3.oas.annotations.tags.Tag; +import java.util.concurrent.ExecutionException; +import org.mifos.connector.crm.data.BillRTPReqDTO; +import org.mifos.connector.crm.data.ResponseDTO; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestHeader; +import org.springframework.web.bind.annotation.RequestParam; + +@Tag(name = "GOV") +public interface BillRtpRespApi { + + @Operation(summary = "Bill RTP Resp API from PBB to Bill Agg") + @PostMapping("/billTransferRequests") + ResponseEntity billRTPResp(@RequestHeader(value = PLATFORM_TENANT) String tenantId, + @RequestHeader(value = CLIENTCORRELATIONID) String correlationId, @RequestParam(value = "X-Biller-Id") String billerId, + @RequestBody BillRTPReqDTO billRTPReqDTO) throws ExecutionException, InterruptedException; +} diff --git a/ph-ee-connector-crm/src/main/java/org/mifos/connector/crm/api/implementation/BillInquiryController.java b/ph-ee-connector-crm/src/main/java/org/mifos/connector/crm/api/implementation/BillInquiryController.java new file mode 100644 index 000000000..abb2962f6 --- /dev/null +++ b/ph-ee-connector-crm/src/main/java/org/mifos/connector/crm/api/implementation/BillInquiryController.java @@ -0,0 +1,35 @@ +package org.mifos.connector.crm.api.implementation; + +import static org.mifos.connector.crm.zeebe.ZeebeVariables.*; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import java.util.concurrent.ExecutionException; +import org.apache.camel.Exchange; +import org.apache.camel.ProducerTemplate; +import org.mifos.connector.crm.api.definition.BillInquiryApi; +import org.mifos.connector.crm.data.BillInquiryResponseDTO; +import org.mifos.connector.crm.utils.Headers; +import org.mifos.connector.crm.utils.SpringWrapperUtil; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.RestController; + +@RestController +public class BillInquiryController implements BillInquiryApi { + + @Autowired + private ProducerTemplate producerTemplate; + + @Autowired + ObjectMapper objectMapper; + + @Override + public BillInquiryResponseDTO billInquiry(String tenantId, String correlationId, String payerFspId, String billId, String field) + throws ExecutionException, InterruptedException, JsonProcessingException { + Headers headers = new Headers.HeaderBuilder().addHeader(PLATFORM_TENANT, tenantId).addHeader(CLIENTCORRELATIONID, correlationId) + .addHeader(PAYER_FSP, payerFspId).addHeader(BILL_ID, billId).addHeader(FIELDS, field).build(); + Exchange exchange = SpringWrapperUtil.getDefaultWrappedExchange(producerTemplate.getCamelContext(), headers, null); + producerTemplate.send("direct:bill-inquiry", exchange); + return exchange.getIn().getBody(BillInquiryResponseDTO.class); + } +} diff --git a/ph-ee-connector-crm/src/main/java/org/mifos/connector/crm/api/implementation/BillPaymentsController.java b/ph-ee-connector-crm/src/main/java/org/mifos/connector/crm/api/implementation/BillPaymentsController.java new file mode 100644 index 000000000..7312c067a --- /dev/null +++ b/ph-ee-connector-crm/src/main/java/org/mifos/connector/crm/api/implementation/BillPaymentsController.java @@ -0,0 +1,37 @@ +package org.mifos.connector.crm.api.implementation; + +import static org.mifos.connector.crm.zeebe.ZeebeVariables.*; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import java.util.concurrent.ExecutionException; +import org.apache.camel.Exchange; +import org.apache.camel.ProducerTemplate; +import org.mifos.connector.crm.api.definition.BillPaymentsApi; +import org.mifos.connector.crm.data.BillPaymentsReqDTO; +import org.mifos.connector.crm.data.BillPaymentsResponseDTO; +import org.mifos.connector.crm.utils.Headers; +import org.mifos.connector.crm.utils.SpringWrapperUtil; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.RestController; + +@RestController +public class BillPaymentsController implements BillPaymentsApi { + + @Autowired + private ProducerTemplate producerTemplate; + + @Autowired + ObjectMapper objectMapper; + + @Override + public BillPaymentsResponseDTO billPayments(String tenantId, String correlationId, String payerFspId, BillPaymentsReqDTO requestBody) + throws ExecutionException, InterruptedException, JsonProcessingException { + Headers headers = new Headers.HeaderBuilder().addHeader(PLATFORM_TENANT, tenantId).addHeader(CLIENTCORRELATIONID, correlationId) + .addHeader(PAYER_FSP, payerFspId).build(); + Exchange exchange = SpringWrapperUtil.getDefaultWrappedExchange(producerTemplate.getCamelContext(), headers, + objectMapper.writeValueAsString(requestBody)); + producerTemplate.send("direct:bill-payments", exchange); + return exchange.getIn().getBody(BillPaymentsResponseDTO.class); + } +} diff --git a/ph-ee-connector-crm/src/main/java/org/mifos/connector/crm/data/Bill.java b/ph-ee-connector-crm/src/main/java/org/mifos/connector/crm/data/Bill.java new file mode 100644 index 000000000..e31a3569b --- /dev/null +++ b/ph-ee-connector-crm/src/main/java/org/mifos/connector/crm/data/Bill.java @@ -0,0 +1,79 @@ +package org.mifos.connector.crm.data; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import org.springframework.stereotype.Component; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +@Component +public class Bill { + + private String billerId; + private String billerName; + private String billStatus; + private String dueDate; + private String amountonDueDate; + + @Override + public String toString() { + return "Bill{" + "billerId='" + billerId + '\'' + ", billerName='" + billerName + '\'' + ", billStatus='" + billStatus + '\'' + + ", dueDate='" + dueDate + '\'' + ", amountonDueDate='" + amountonDueDate + '\'' + ", amountAfterDueDate='" + + amountAfterDueDate + '\'' + '}'; + } + + private String amountAfterDueDate; + + public String getBillerId() { + return billerId; + } + + public void setBillerId(String billerId) { + this.billerId = billerId; + } + + public String getBillerName() { + return billerName; + } + + public void setBillerName(String billerName) { + this.billerName = billerName; + } + + public String getBillStatus() { + return billStatus; + } + + public void setBillStatus(String billStatus) { + this.billStatus = billStatus; + } + + public String getDueDate() { + return dueDate; + } + + public void setDueDate(String dueDate) { + this.dueDate = dueDate; + } + + public String getAmountonDueDate() { + return amountonDueDate; + } + + public void setAmountonDueDate(String amountonDueDate) { + this.amountonDueDate = amountonDueDate; + } + + public String getAmountAfterDueDate() { + return amountAfterDueDate; + } + + public void setAmountAfterDueDate(String amountAfterDueDate) { + this.amountAfterDueDate = amountAfterDueDate; + } + +} diff --git a/ph-ee-connector-crm/src/main/java/org/mifos/connector/crm/data/BillInquiryResponseDTO.java b/ph-ee-connector-crm/src/main/java/org/mifos/connector/crm/data/BillInquiryResponseDTO.java new file mode 100644 index 000000000..c65714e38 --- /dev/null +++ b/ph-ee-connector-crm/src/main/java/org/mifos/connector/crm/data/BillInquiryResponseDTO.java @@ -0,0 +1,74 @@ +package org.mifos.connector.crm.data; + +import java.io.Serializable; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import org.springframework.stereotype.Component; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor + +/* + * Sample response { “code”: “00”, “reason”: “Bill Inquiry Successful” “clientCorrelationId”: “915251236706”, “billId”: + * “123456789101112”, “billDetails”: [ “billerId”: “1232211”, “billerName”: “Govt. Entity”, “billStatus”: “Unpaid”, + * “dueDate”: “04/17/23” “amountonDueDate”: “2550”, “amountAfterDueDate”: “2570”,} } + */ +@Component +public class BillInquiryResponseDTO implements Serializable { + + private String code; + private String reason; + private String clientCorrelationId; + private String billId; + private Bill billDetails; + + public String getCode() { + return code; + } + + public void setCode(String code) { + this.code = code; + } + + public String getReason() { + return reason; + } + + public void setReason(String reason) { + this.reason = reason; + } + + public String getClientCorrelationId() { + return clientCorrelationId; + } + + public void setClientCorrelationId(String clientCorrelationId) { + this.clientCorrelationId = clientCorrelationId; + } + + public String getBillId() { + return billId; + } + + public void setBillId(String billId) { + this.billId = billId; + } + + public Bill getBillDetails() { + return billDetails; + } + + public void setBillDetails(Bill billDetails) { + this.billDetails = billDetails; + } + + @Override + public String toString() { + return "BillInquiryResponseDTO{" + "code='" + code + '\'' + ", reason='" + reason + '\'' + ", clientCorrelationId='" + + clientCorrelationId + '\'' + ", billId='" + billId + '\'' + ", billDetails=" + billDetails + '}'; + } +} diff --git a/ph-ee-connector-crm/src/main/java/org/mifos/connector/crm/data/BillPaymentsReqDTO.java b/ph-ee-connector-crm/src/main/java/org/mifos/connector/crm/data/BillPaymentsReqDTO.java new file mode 100644 index 000000000..436784abb --- /dev/null +++ b/ph-ee-connector-crm/src/main/java/org/mifos/connector/crm/data/BillPaymentsReqDTO.java @@ -0,0 +1,60 @@ +package org.mifos.connector.crm.data; + +import java.io.Serializable; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import org.springframework.stereotype.Component; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +@Component +public class BillPaymentsReqDTO implements Serializable { + + private String clientCorrelationId; + private String billInquiryRequestId; + private String billId; + private String paymentReferenceID; + + @Override + public String toString() { + return "BillPaymentsReqDTO{" + "clientCorrelationId='" + clientCorrelationId + '\'' + ", billInquiryRequestId='" + + billInquiryRequestId + '\'' + ", billId='" + billId + '\'' + ", paymentReferenceID='" + paymentReferenceID + '\'' + '}'; + } + + public String getClientCorrelationId() { + return clientCorrelationId; + } + + public void setClientCorrelationId(String clientCorrelationId) { + this.clientCorrelationId = clientCorrelationId; + } + + public String getBillInquiryRequestId() { + return billInquiryRequestId; + } + + public void setBillInquiryRequestId(String billInquiryRequestId) { + this.billInquiryRequestId = billInquiryRequestId; + } + + public String getBillId() { + return billId; + } + + public void setBillId(String billId) { + this.billId = billId; + } + + public String getPaymentReferenceID() { + return paymentReferenceID; + } + + public void setPaymentReferenceID(String paymentReferenceID) { + this.paymentReferenceID = paymentReferenceID; + } + +} diff --git a/ph-ee-connector-crm/src/main/java/org/mifos/connector/crm/data/BillPaymentsResponseDTO.java b/ph-ee-connector-crm/src/main/java/org/mifos/connector/crm/data/BillPaymentsResponseDTO.java new file mode 100644 index 000000000..36dfed7e7 --- /dev/null +++ b/ph-ee-connector-crm/src/main/java/org/mifos/connector/crm/data/BillPaymentsResponseDTO.java @@ -0,0 +1,84 @@ +package org.mifos.connector.crm.data; + +import java.io.Serializable; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import org.springframework.stereotype.Component; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor + +/* + * Sample response { "RequestID": "915251236706", “code”: “00” “reason”: “Transaction Successful” "billId”: + * “123456789101112”, “status”: “ACK” } + * + */ +@Component +public class BillPaymentsResponseDTO implements Serializable { + + private String code; + private String reason; + private String requestID; + private String billId; + private String paymentReferenceID; + private String status; + + public String getRequestID() { + return requestID; + } + + public void setRequestID(String requestID) { + this.requestID = requestID; + } + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } + + @Override + public String toString() { + return "BillPaymentsResponseDTO{" + "code='" + code + '\'' + ", reason='" + reason + '\'' + ", requestID='" + requestID + '\'' + + ", billId='" + billId + '\'' + ", paymentReferenceID='" + paymentReferenceID + '\'' + ", status='" + status + '\'' + '}'; + } + + public String getPaymentReferenceID() { + return paymentReferenceID; + } + + public void setPaymentReferenceID(String paymentReferenceID) { + this.paymentReferenceID = paymentReferenceID; + } + + public String getCode() { + return code; + } + + public void setCode(String code) { + this.code = code; + } + + public String getReason() { + return reason; + } + + public void setReason(String reason) { + this.reason = reason; + } + + public String getBillId() { + return billId; + } + + public void setBillId(String billId) { + this.billId = billId; + } + +} diff --git a/ph-ee-connector-crm/src/main/java/org/mifos/connector/crm/data/BillRTPReqDTO.java b/ph-ee-connector-crm/src/main/java/org/mifos/connector/crm/data/BillRTPReqDTO.java new file mode 100644 index 000000000..7186ebf02 --- /dev/null +++ b/ph-ee-connector-crm/src/main/java/org/mifos/connector/crm/data/BillRTPReqDTO.java @@ -0,0 +1,22 @@ +package org.mifos.connector.crm.data; + +import java.io.Serializable; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import org.springframework.stereotype.Component; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +@Component +public class BillRTPReqDTO implements Serializable { + + private String billRequestId; + private String billId; + private String status; + private String rejectionReason; + +} diff --git a/ph-ee-connector-crm/src/main/java/org/mifos/connector/crm/data/ResponseDTO.java b/ph-ee-connector-crm/src/main/java/org/mifos/connector/crm/data/ResponseDTO.java new file mode 100644 index 000000000..f934ae126 --- /dev/null +++ b/ph-ee-connector-crm/src/main/java/org/mifos/connector/crm/data/ResponseDTO.java @@ -0,0 +1,20 @@ +package org.mifos.connector.crm.data; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import org.springframework.stereotype.Component; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +@Component +public class ResponseDTO { + + private String ResponseCode; + private String ResponseDescription; + private String RequestID; + +} diff --git a/ph-ee-connector-crm/src/main/java/org/mifos/connector/crm/routes/BillInquiryRouteBuilder.java b/ph-ee-connector-crm/src/main/java/org/mifos/connector/crm/routes/BillInquiryRouteBuilder.java new file mode 100644 index 000000000..d4bf63f02 --- /dev/null +++ b/ph-ee-connector-crm/src/main/java/org/mifos/connector/crm/routes/BillInquiryRouteBuilder.java @@ -0,0 +1,101 @@ +package org.mifos.connector.crm.routes; + +import static org.mifos.connector.crm.utils.BillPayEnum.*; +import static org.mifos.connector.crm.zeebe.ZeebeVariables.*; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.apache.camel.Exchange; +import org.mifos.connector.common.camel.ErrorHandlerRouteBuilder; +import org.mifos.connector.crm.data.Bill; +import org.mifos.connector.crm.data.BillInquiryResponseDTO; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +@Component +public class BillInquiryRouteBuilder extends ErrorHandlerRouteBuilder { + + @Value("${billPay.billIdInvalidId}") + private String billIdInvalidId; + + @Value("${billPay.billIdEmptyId}") + private String billIdEmptyId; + + private Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Autowired + BillInquiryResponseDTO billInquiryResponseDTO; + + @Autowired + private Bill billDetails; + + @Override + public void configure() { + + from("direct:bill-inquiry").routeId("bill-inquiry").log("Received request for bill inquiry") + .setHeader(Exchange.HTTP_RESPONSE_CODE, constant(200)).process(exchange -> { + logger.debug("Bill Inquiry Id: {}" , exchange.getIn().getHeader(BILL_ID).toString()); + BillInquiryResponseDTO billInquiryResponseDTO; + String billId = exchange.getIn().getHeader(BILL_ID).toString(); + String billerID = exchange.getProperty(BILLER_ID).toString(); + String billerName = exchange.getProperty(BILLER_NAME).toString(); + if(billId.equals(billIdInvalidId)){ + logger.info("Bill Id is Invalid"); + billInquiryResponseDTO = setResponseBodyForInvalidBill( + exchange.getIn().getHeader(CLIENTCORRELATIONID).toString()); + exchange.setProperty(BILL_FETCH_FAILED, true); + exchange.setProperty(ERROR_INFORMATION,"Bill Fetch failed: Invalid Bill Id"); + } + else if(billId.equals(billIdEmptyId)){ + logger.info("Bill Id is Empty"); + billInquiryResponseDTO = setResponseBodyForEmptyBill( + exchange.getIn().getHeader(CLIENTCORRELATIONID).toString()); + exchange.setProperty(BILL_FETCH_FAILED, true); + exchange.setProperty(ERROR_INFORMATION,"Bill Fetch failed: Empty bill ID"); + } + else { + billInquiryResponseDTO = setResponseBody( + exchange.getIn().getHeader(CLIENTCORRELATIONID).toString(), billId, billerID, billerName); + exchange.setProperty(BILL_FETCH_FAILED, false); + } + exchange.setProperty(BILL_INQUIRY_RESPONSE, billInquiryResponseDTO); + exchange.setProperty(AMOUNT,billInquiryResponseDTO.getBillDetails().getAmountonDueDate()); + ObjectMapper objectMapper = new ObjectMapper(); + String jsonString = objectMapper.writeValueAsString(billInquiryResponseDTO); + exchange.getIn().setBody(jsonString); + logger.debug("Bill Inquiry Response: {}", jsonString); + }); + } + + private BillInquiryResponseDTO setResponseBody(String clientCorrelationId, String billId, String billerID, String billerName) { + + billDetails.setBillerId(billerID); + billDetails.setBillerName(billerName); + billDetails.setAmountonDueDate("1000"); + billDetails.setAmountAfterDueDate("1100"); + billDetails.setDueDate("2021-07-01"); + billDetails.setBillStatus("PAID"); + billInquiryResponseDTO.setBillDetails(billDetails); + billInquiryResponseDTO.setBillId(billId); + billInquiryResponseDTO.setCode(SUCCESS_RESPONSE_CODE.getValue()); + billInquiryResponseDTO.setReason(SUCCESS_RESPONSE_MESSAGE.getValue()); + billInquiryResponseDTO.setClientCorrelationId(clientCorrelationId); + return billInquiryResponseDTO; + } + private BillInquiryResponseDTO setResponseBodyForInvalidBill(String clientCorrelationId) { + billInquiryResponseDTO.setCode(FAILED_RESPONSE_CODE.getValue()); + billInquiryResponseDTO.setReason("Invalid Bill ID"); + billInquiryResponseDTO.setClientCorrelationId(clientCorrelationId); + return billInquiryResponseDTO; + } + private BillInquiryResponseDTO setResponseBodyForEmptyBill(String clientCorrelationId) { + billInquiryResponseDTO.setCode(FAILED_RESPONSE_CODE.getValue()); + billInquiryResponseDTO.setReason("Empty Bill ID"); + billInquiryResponseDTO.setClientCorrelationId(clientCorrelationId); + return billInquiryResponseDTO; + } + + +} diff --git a/ph-ee-connector-crm/src/main/java/org/mifos/connector/crm/routes/BillPayRouteBuilder.java b/ph-ee-connector-crm/src/main/java/org/mifos/connector/crm/routes/BillPayRouteBuilder.java new file mode 100644 index 000000000..1fd859392 --- /dev/null +++ b/ph-ee-connector-crm/src/main/java/org/mifos/connector/crm/routes/BillPayRouteBuilder.java @@ -0,0 +1,96 @@ +package org.mifos.connector.crm.routes; + +import static org.mifos.connector.crm.utils.BillPayEnum.*; +import static org.mifos.connector.crm.zeebe.ZeebeVariables.*; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.apache.camel.Exchange; +import org.apache.camel.model.dataformat.JsonLibrary; +import org.mifos.connector.common.camel.ErrorHandlerRouteBuilder; +import org.mifos.connector.crm.data.BillPaymentsReqDTO; +import org.mifos.connector.crm.data.BillPaymentsResponseDTO; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +@Component +public class BillPayRouteBuilder extends ErrorHandlerRouteBuilder { + + private Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Value("${billPay.billAlreadyPaidId}") + private String billAlreadyPaidId; + + @Value("${billPay.billPayTimeoutId}") + private String billPayTimeoutId; + @Autowired + BillPaymentsResponseDTO billPaymentsResponseDTO; + + @Override + public void configure() { + + from("direct:bill-payments").routeId("bill-payments").log("Received request for bill payments").unmarshal() + .json(JsonLibrary.Jackson, BillPaymentsReqDTO.class).setHeader(Exchange.HTTP_RESPONSE_CODE, constant(200)) + .process(exchange -> { + BillPaymentsResponseDTO response; + logger.debug("Bill Payments Request: {}" ,exchange.getIn().getBody(BillPaymentsReqDTO.class)); + if(exchange.getIn().getBody(BillPaymentsReqDTO.class).getBillId().equals(billAlreadyPaidId)){ + response = + setResponseBodyForBillPaid(exchange.getIn().getBody(BillPaymentsReqDTO.class)); + } + else if(exchange.getIn().getBody(BillPaymentsReqDTO.class).getBillId().equals(billPayTimeoutId)){ + Thread.sleep(15000); + response = + setResponseBodyForBillPayTimeout(exchange.getIn().getBody(BillPaymentsReqDTO.class)); + } + else { + response = + setResponseBodyForSuccess(exchange.getIn().getBody(BillPaymentsReqDTO.class)); + } + exchange.setProperty("billPayFailed", false); + exchange.setProperty(BILL_PAY_RESPONSE, response); + exchange.setProperty("reason", billPaymentsResponseDTO.getReason()); + exchange.setProperty("code", billPaymentsResponseDTO.getCode()); + exchange.setProperty("status", billPaymentsResponseDTO.getStatus()); + ObjectMapper objectMapper = new ObjectMapper(); + String jsonString = objectMapper.writeValueAsString(response); + exchange.getIn().setBody(jsonString); + logger.debug("Bill Payments Response: {}", response); + }); + + } + + private BillPaymentsResponseDTO setResponseBodyForSuccess(BillPaymentsReqDTO billPaymentsReqDTO) { + + billPaymentsResponseDTO.setBillId(billPaymentsReqDTO.getBillId()); + billPaymentsResponseDTO.setCode(SUCCESS_RESPONSE_CODE.getValue()); + billPaymentsResponseDTO.setReason(SUCCESS_RESPONSE_MESSAGE.getValue()); + billPaymentsResponseDTO.setStatus(SUCCESS_STATUS.getValue()); + billPaymentsResponseDTO.setRequestID(billPaymentsReqDTO.getBillInquiryRequestId()); + billPaymentsResponseDTO.setPaymentReferenceID(billPaymentsReqDTO.getPaymentReferenceID()); + return billPaymentsResponseDTO; + } + private BillPaymentsResponseDTO setResponseBodyForBillPaid(BillPaymentsReqDTO billPaymentsReqDTO) { + + billPaymentsResponseDTO.setBillId(billPaymentsReqDTO.getBillId()); + billPaymentsResponseDTO.setCode(FAILED_RESPONSE_CODE.getValue()); + billPaymentsResponseDTO.setReason(FAILED_DUPLICATE_PAYMENT_MESSAGE.getValue()); + billPaymentsResponseDTO.setStatus(FAILED_STATUS.getValue()); + billPaymentsResponseDTO.setRequestID(billPaymentsReqDTO.getBillInquiryRequestId()); + billPaymentsResponseDTO.setPaymentReferenceID(billPaymentsReqDTO.getPaymentReferenceID()); + return billPaymentsResponseDTO; + } + private BillPaymentsResponseDTO setResponseBodyForBillPayTimeout(BillPaymentsReqDTO billPaymentsReqDTO) { + + billPaymentsResponseDTO.setBillId(billPaymentsReqDTO.getBillId()); + billPaymentsResponseDTO.setCode(FAILED_RESPONSE_CODE.getValue()); + billPaymentsResponseDTO.setReason(FAILED_TIMEOUT_MESSAGE.getValue()); + billPaymentsResponseDTO.setStatus(FAILED_STATUS.getValue()); + billPaymentsResponseDTO.setRequestID(billPaymentsReqDTO.getBillInquiryRequestId()); + billPaymentsResponseDTO.setPaymentReferenceID(billPaymentsReqDTO.getPaymentReferenceID()); + return billPaymentsResponseDTO; + } + +} diff --git a/ph-ee-connector-crm/src/main/java/org/mifos/connector/crm/routes/BillRTPRespRouteBuilder.java b/ph-ee-connector-crm/src/main/java/org/mifos/connector/crm/routes/BillRTPRespRouteBuilder.java new file mode 100644 index 000000000..212ddee5e --- /dev/null +++ b/ph-ee-connector-crm/src/main/java/org/mifos/connector/crm/routes/BillRTPRespRouteBuilder.java @@ -0,0 +1,48 @@ +package org.mifos.connector.crm.routes; + +import static org.mifos.connector.crm.utils.BillPayEnum.SUCCESS_RESPONSE_CODE; +import static org.mifos.connector.crm.utils.BillPayEnum.SUCCESS_RESPONSE_MESSAGE; +import static org.mifos.connector.crm.zeebe.ZeebeVariables.CLIENTCORRELATIONID; + +import org.apache.camel.Exchange; +import org.json.JSONObject; +import org.mifos.connector.common.camel.ErrorHandlerRouteBuilder; +import org.mifos.connector.crm.data.ResponseDTO; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component +public class BillRTPRespRouteBuilder extends ErrorHandlerRouteBuilder { + + private Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Autowired + ResponseDTO responseDTO; + + @Override + public void configure() { + + from("direct:bill-rtp-resp").routeId("bill-rtp-resp").log("Sending response for bill rtp request") + .setHeader(Exchange.HTTP_RESPONSE_CODE, constant(200)).setBody(exchange -> { + JSONObject response = setResponseBody(exchange.getProperty(CLIENTCORRELATIONID).toString()); + exchange.setProperty("response", response); + return response; + }); + + from("direct:aync-response").routeId("aync-response").log("Setting response for request for bill inquiry") + .setHeader(Exchange.HTTP_RESPONSE_CODE, constant(202)).setBody(constant("Request Processing")); + } + + private JSONObject setResponseBody(String clientCorrelationId) { + + JSONObject response = new JSONObject(); + responseDTO.setResponseCode(SUCCESS_RESPONSE_CODE.toString()); + responseDTO.setResponseDescription(SUCCESS_RESPONSE_MESSAGE.toString()); + responseDTO.setRequestID(clientCorrelationId); + response.put("BillPaymentsResponse", responseDTO); + return response; + } + +} diff --git a/ph-ee-connector-crm/src/main/java/org/mifos/connector/crm/service/BillPaymentsService.java b/ph-ee-connector-crm/src/main/java/org/mifos/connector/crm/service/BillPaymentsService.java new file mode 100644 index 000000000..e4710a3e6 --- /dev/null +++ b/ph-ee-connector-crm/src/main/java/org/mifos/connector/crm/service/BillPaymentsService.java @@ -0,0 +1,27 @@ +package org.mifos.connector.crm.service; + +import org.mifos.connector.crm.data.BillPaymentsReqDTO; +import org.mifos.connector.crm.data.BillPaymentsResponseDTO; +import org.mifos.connector.crm.utils.BillPayEnum; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +@Service +public class BillPaymentsService { + + @Autowired + private BillPaymentsResponseDTO billPaymentsResponseDTO; + + String transactionId; + + public BillPaymentsResponseDTO billPayments(String tenantId, String correlationId, String payerFspId, BillPaymentsReqDTO body) { + + billPaymentsResponseDTO.setBillId(body.getBillId()); + billPaymentsResponseDTO.setCode(BillPayEnum.SUCCESS_RESPONSE_CODE.toString()); + billPaymentsResponseDTO.setReason(BillPayEnum.SUCCESS_RESPONSE_MESSAGE.toString()); + billPaymentsResponseDTO.setStatus(BillPayEnum.SUCCESS_STATUS.toString()); + billPaymentsResponseDTO.setRequestID(correlationId); + return billPaymentsResponseDTO; + } + +} diff --git a/ph-ee-connector-crm/src/main/java/org/mifos/connector/crm/utils/BillPayEnum.java b/ph-ee-connector-crm/src/main/java/org/mifos/connector/crm/utils/BillPayEnum.java new file mode 100644 index 000000000..cff7bf290 --- /dev/null +++ b/ph-ee-connector-crm/src/main/java/org/mifos/connector/crm/utils/BillPayEnum.java @@ -0,0 +1,18 @@ +package org.mifos.connector.crm.utils; + +public enum BillPayEnum { + + SUCCESS_RESPONSE_CODE("00"), FAILED_RESPONSE_CODE("01"), SUCCESS_STATUS("ACK"), SUCCESS_RESPONSE_MESSAGE( + "TRANSACTION SUCCESSFUL"), FAILED_TIMEOUT_MESSAGE("Bill Payment Failed: Bill Paid After Timeout"), + FAILED_STATUS("RJC"),FAILED_DUPLICATE_PAYMENT_MESSAGE("Bill Payment Failed: Bill Already Paid"); + + private final String value; + + BillPayEnum(String value) { + this.value = value; + } + + public String getValue() { + return this.value; + } +} diff --git a/ph-ee-connector-crm/src/main/java/org/mifos/connector/crm/utils/Headers.java b/ph-ee-connector-crm/src/main/java/org/mifos/connector/crm/utils/Headers.java new file mode 100644 index 000000000..1ba6a15b9 --- /dev/null +++ b/ph-ee-connector-crm/src/main/java/org/mifos/connector/crm/utils/Headers.java @@ -0,0 +1,45 @@ +package org.mifos.connector.crm.utils; + +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +public final class Headers { + + private Map headers; + + private Headers() {} + + private void setHeaders(Map headers) { + this.headers = headers; + } + + public Map getHeaders() { + return headers; + } + + public Set getHeadersKey() { + return this.headers.keySet(); + } + + public Object get(String key) { + return this.headers.get(key); + } + + public static class HeaderBuilder { + + private Map headers = new HashMap<>(); + + public HeaderBuilder addHeader(String key, Object value) { + headers.put(key, value); + return this; + } + + public Headers build() { + Headers headersClassInstance = new Headers(); + headersClassInstance.setHeaders(this.headers); + + return headersClassInstance; + } + } +} diff --git a/ph-ee-connector-crm/src/main/java/org/mifos/connector/crm/utils/SpringWrapperUtil.java b/ph-ee-connector-crm/src/main/java/org/mifos/connector/crm/utils/SpringWrapperUtil.java new file mode 100644 index 000000000..42e8d4ea4 --- /dev/null +++ b/ph-ee-connector-crm/src/main/java/org/mifos/connector/crm/utils/SpringWrapperUtil.java @@ -0,0 +1,30 @@ +package org.mifos.connector.crm.utils; + +import org.apache.camel.CamelContext; +import org.apache.camel.Exchange; +import org.apache.camel.support.DefaultExchange; + +public final class SpringWrapperUtil { + + private SpringWrapperUtil() {} + + public static Exchange getDefaultWrappedExchange(CamelContext camelContext, Headers headers, String body) { + Exchange exchange = new DefaultExchange(camelContext); + + // Setting headers + for (String headerKey : headers.getHeadersKey()) { + exchange.getIn().setHeader(headerKey, headers.get(headerKey)); + } + + // Setting body if available + if (body != null) { + try { + exchange.getIn().setBody((String) body); + } catch (Exception e) { + exchange.getIn().setBody(body); + + } + } + return exchange; + } +} diff --git a/ph-ee-connector-crm/src/main/java/org/mifos/connector/crm/zeebe/ZeebeClientConfiguration.java b/ph-ee-connector-crm/src/main/java/org/mifos/connector/crm/zeebe/ZeebeClientConfiguration.java new file mode 100644 index 000000000..7e239bdbe --- /dev/null +++ b/ph-ee-connector-crm/src/main/java/org/mifos/connector/crm/zeebe/ZeebeClientConfiguration.java @@ -0,0 +1,24 @@ +package org.mifos.connector.crm.zeebe; + +import io.camunda.zeebe.client.ZeebeClient; +import java.time.Duration; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class ZeebeClientConfiguration { + + @Value("${zeebe.broker.contactpoint}") + private String zeebeBrokerContactpoint; + + @Value("${zeebe.client.max-execution-threads}") + private int zeebeClientMaxThreads; + + @Bean + public ZeebeClient setup() { + return ZeebeClient.newClientBuilder().gatewayAddress(zeebeBrokerContactpoint).usePlaintext() + .defaultJobPollInterval(Duration.ofMillis(1)).defaultJobWorkerMaxJobsActive(2000) + .numJobWorkerExecutionThreads(zeebeClientMaxThreads).build(); + } +} diff --git a/ph-ee-connector-crm/src/main/java/org/mifos/connector/crm/zeebe/ZeebeVariables.java b/ph-ee-connector-crm/src/main/java/org/mifos/connector/crm/zeebe/ZeebeVariables.java new file mode 100644 index 000000000..a26ac64e4 --- /dev/null +++ b/ph-ee-connector-crm/src/main/java/org/mifos/connector/crm/zeebe/ZeebeVariables.java @@ -0,0 +1,41 @@ +package org.mifos.connector.crm.zeebe; + +public class ZeebeVariables { + + private ZeebeVariables() {} + + public static final String ACCOUNT = "account"; + public static final String CHANNEL_REQUEST = "channelRequest"; + public static final String ERROR_INFORMATION = "errorInformation"; + public static final String ERROR_DESCRIPTION = "errorDescription"; + public static final String IS_AUTHORISATION_REQUIRED = "isAuthorisationRequired"; + public static final String IS_RTP_REQUEST = "isRtpRequest"; + public static final String ORIGIN_DATE = "originDate"; + public static final String PARTY_ID = "partyId"; + public static final String PARTY_ID_TYPE = "partyIdType"; + public static final String TENANT_ID = "tenantId"; + public static final String PLATFORM_TENANT = "Platform-TenantId"; + public static final String PAYMENTS_NOTIFICATION_RESPONSE = "billPaymentsResponse"; + public static final String BILL_PAYMENTS_REQ = "billPaymentsReq"; + + public static final String TRANSACTION_ID = "transactionId"; + public static final String TRANSACTION_TYPE = "transactionType"; + public static final String CLIENTCORRELATIONID = "X-CorrelationID"; + public static final String CALLBACK_URL = "X-CallbackURL"; + public static final String PAYER_FSP = "X-PayerFSP-Id"; + public static final String BILL_ID = "billId"; + public static final String FIELDS = "fields"; + public static final String BILLER_ID = "billerId"; + public static final String BILLER_NAME = "billerName"; + public static final String BILLER_TYPE = "billerType"; + public static final String BILLER_ACCOUNT = "billerAccount"; + public static final String BILLER_FETCH_FAILED = "billerFetchFailed"; + public static final String BILLER_DETAILS = "billerDetails"; + public static final String BILL_INQUIRY_RESPONSE = "billInquiryResponse"; + public static final String BILL_FETCH_FAILED = "billFetchFailed"; + public static final String BILL_PAY_RESPONSE = "billPayResponse"; + public static final String BILL_PAY_FAILED = "billPayFailed"; + + public static final String AMOUNT = "amount"; + +} diff --git a/ph-ee-connector-crm/src/main/java/org/mifos/connector/crm/zeebe/ZeebeWorkers.java b/ph-ee-connector-crm/src/main/java/org/mifos/connector/crm/zeebe/ZeebeWorkers.java new file mode 100644 index 000000000..7198cc842 --- /dev/null +++ b/ph-ee-connector-crm/src/main/java/org/mifos/connector/crm/zeebe/ZeebeWorkers.java @@ -0,0 +1,158 @@ +package org.mifos.connector.crm.zeebe; + +import static org.mifos.connector.crm.zeebe.ZeebeVariables.*; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.google.gson.Gson; +import io.camunda.zeebe.client.ZeebeClient; +import io.camunda.zeebe.client.api.response.ActivatedJob; +import java.util.Map; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; +import javax.annotation.PostConstruct; +import org.apache.camel.CamelContext; +import org.apache.camel.Exchange; +import org.apache.camel.ProducerTemplate; +import org.json.JSONObject; +import org.mifos.connector.crm.data.BillPaymentsReqDTO; +import org.mifos.connector.crm.utils.Headers; +import org.mifos.connector.crm.utils.SpringWrapperUtil; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +@Component +public class ZeebeWorkers { + + private Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Autowired + private ZeebeClient zeebeClient; + + @Autowired + private ProducerTemplate producerTemplate; + + @Autowired + private CamelContext camelContext; + + @Autowired + private ObjectMapper objectMapper; + + @Value("${zeebe.client.evenly-allocated-max-jobs}") + private int workerMaxJobs; + + @Value("${status.billReqAcceptedId}") + private String billReqAcceptedId; + + @Value("${status.billTimeout}") + private int billTimeout; + + + private static final ScheduledExecutorService scheduledThreadPoolExecutor = Executors.newScheduledThreadPool(10); + + + @PostConstruct + public void setupWorkers() { + + // fetch bill details worker for sync mock api with response + zeebeClient.newWorker().jobType("fetch-bill").handler((client, job) -> { + logger.info("Job '{}' started from process '{}' with key {}", job.getType(), job.getBpmnProcessId(), job.getKey()); + logWorkerDetails(job); + Map variables = job.getVariablesAsMap(); + Headers headers = new Headers.HeaderBuilder().addHeader(PLATFORM_TENANT, variables.get(TENANT_ID).toString()) + .addHeader(CLIENTCORRELATIONID, variables.get(CLIENTCORRELATIONID).toString()) + .addHeader(PAYER_FSP, variables.get("payerFspId").toString()).addHeader(BILL_ID, variables.get(BILL_ID).toString()) + .build(); + Exchange exchange = SpringWrapperUtil.getDefaultWrappedExchange(producerTemplate.getCamelContext(), headers, null); + exchange.setProperty(BILLER_ID, variables.get(BILLER_ID).toString()); + exchange.setProperty(BILLER_NAME, variables.get(BILLER_NAME).toString()); + producerTemplate.send("direct:bill-inquiry", exchange); + variables.put(BILL_INQUIRY_RESPONSE, exchange.getProperty(BILL_INQUIRY_RESPONSE)); + variables.put(BILL_FETCH_FAILED, exchange.getProperty(BILL_FETCH_FAILED)); + variables.put(AMOUNT,exchange.getProperty(AMOUNT)); + zeebeClient.newCompleteCommand(job.getKey()).variables(variables).send(); + logger.debug("Zeebe variable {}", job.getVariablesAsMap()); + }).name("fetch-bill").maxJobsActive(workerMaxJobs).open(); + + // pay bill status worker for sync mock api with response + zeebeClient.newWorker().jobType("billPay").handler((client, job) -> { + logger.info("Job '{}' started from process '{}' with key {}", job.getType(), job.getBpmnProcessId(), job.getKey()); + logWorkerDetails(job); + Map variables = job.getVariablesAsMap(); + if(variables.get(BILL_ID).equals(billReqAcceptedId)){ + pauseExec();} + Headers headers = new Headers.HeaderBuilder().addHeader(PLATFORM_TENANT, variables.get(TENANT_ID).toString()) + .addHeader(CLIENTCORRELATIONID, variables.get(CLIENTCORRELATIONID).toString()) + .addHeader(PAYER_FSP, variables.get("payerFspId").toString()).build(); + Gson gson = new Gson(); + BillPaymentsReqDTO requestBody = gson.fromJson((variables.get(BILL_PAYMENTS_REQ).toString()), BillPaymentsReqDTO.class); + Exchange exchange = SpringWrapperUtil.getDefaultWrappedExchange(producerTemplate.getCamelContext(), headers, + objectMapper.writeValueAsString(requestBody)); + producerTemplate.send("direct:bill-payments", exchange); + variables.put(BILL_PAY_RESPONSE, exchange.getProperty(BILL_PAY_RESPONSE)); + variables.put("code", exchange.getProperty("code")); + variables.put("status", exchange.getProperty("status")); + variables.put("reason", exchange.getProperty("reason")); + variables.put("state", "ACCEPTED"); + variables.put(BILL_PAY_FAILED, exchange.getProperty(BILL_PAY_FAILED)); + zeebeClient.newCompleteCommand(job.getKey()).variables(variables).send(); + logger.debug("Zeebe variable {}", job.getVariablesAsMap()); + }).name("billPay").maxJobsActive(workerMaxJobs).open(); + + zeebeClient.newWorker().jobType("billRtpAck").handler((client, job) -> { + logger.info("Job '{}' started from process '{}' with key {}", job.getType(), job.getBpmnProcessId(), job.getKey()); + logWorkerDetails(job); + Map variables = job.getVariablesAsMap(); + Headers headers = new Headers.HeaderBuilder().addHeader("X-Platform-TenantId", variables.get(TENANT_ID).toString()) + .addHeader(CLIENTCORRELATIONID, variables.get(CLIENTCORRELATIONID).toString()).build(); + Exchange exchange = SpringWrapperUtil.getDefaultWrappedExchange(producerTemplate.getCamelContext(), headers, null); + // check before implementing + producerTemplate.send("direct:send-ack", exchange); + zeebeClient.newCompleteCommand(job.getKey()).variables(variables).send(); + logger.debug("Zeebe variable {}", job.getVariablesAsMap()); + }).name("billRtpAck").maxJobsActive(workerMaxJobs).open(); + + // billRTPResp + zeebeClient.newWorker().jobType("billRTPResp").handler((client, job) -> { + logger.info("Job '{}' started from process '{}' with key {}", job.getType(), job.getBpmnProcessId(), job.getKey()); + logWorkerDetails(job); + Map variables = job.getVariablesAsMap(); + Headers headers = new Headers.HeaderBuilder().addHeader("X-Platform-TenantId", variables.get(TENANT_ID).toString()) + .addHeader(CLIENTCORRELATIONID, variables.get(CLIENTCORRELATIONID).toString()).build(); + Exchange exchange = SpringWrapperUtil.getDefaultWrappedExchange(producerTemplate.getCamelContext(), headers, null); + producerTemplate.send("direct:bill-rtp-resp", exchange); + variables.put("billRTPResponse", exchange.getIn().getBody(String.class)); + zeebeClient.newCompleteCommand(job.getKey()).variables(variables).send(); + logger.debug("Zeebe variable {}", job.getVariablesAsMap()); + }).name("billRTPResp").maxJobsActive(workerMaxJobs).open(); + + } + + private void pauseExec() { + try { + logger.info("Pausing execution for capturing intermediary status "); + scheduledThreadPoolExecutor.schedule(() -> { + }, billTimeout, TimeUnit.SECONDS).get(); + } catch (Exception e) { + throw new RuntimeException(); + } + logger.info("Resuming execution post pause"); + } + + + private void logWorkerDetails(ActivatedJob job) { + JSONObject jsonJob = new JSONObject(); + jsonJob.put("bpmnProcessId", job.getBpmnProcessId()); + jsonJob.put("elementInstanceKey", job.getElementInstanceKey()); + jsonJob.put("jobKey", job.getKey()); + jsonJob.put("jobType", job.getType()); + jsonJob.put("workflowElementId", job.getElementId()); + jsonJob.put("workflowDefinitionVersion", job.getProcessDefinitionVersion()); + jsonJob.put("workflowKey", job.getProcessDefinitionKey()); + jsonJob.put("workflowInstanceKey", job.getProcessInstanceKey()); + logger.info("Job started: {}", jsonJob.toString(4)); + } +} diff --git a/ph-ee-connector-crm/src/main/resources/application.yml b/ph-ee-connector-crm/src/main/resources/application.yml new file mode 100644 index 000000000..725d7a3bf --- /dev/null +++ b/ph-ee-connector-crm/src/main/resources/application.yml @@ -0,0 +1,38 @@ +server: + port: 8080 + +logging: + level: + ROOT: INFO + +callback_enabled: true + + +zeebe: + client: + max-execution-threads: 100 + number-of-workers: 5 + evenly-allocated-max-jobs: "#{${zeebe.client.max-execution-threads} / ${zeebe.client.number-of-workers}}" + broker: + contactpoint: "localhost:26500" + +billPay: + billAlreadyPaidId : "003" + billIdInvalidId : "002" + billIdEmptyId : "00" + billPayTimeoutId : "005" + +management: + endpoint: + health: + enabled: true + probes: + enabled: true + liveness: + enabled: true + readiness: + enabled: true + +status: + billReqAcceptedId: "123" + billTimeout: 3 diff --git a/ph-ee-connector-gsma-mm/.DS_Store b/ph-ee-connector-gsma-mm/.DS_Store new file mode 100644 index 000000000..17e3188c6 Binary files /dev/null and b/ph-ee-connector-gsma-mm/.DS_Store differ diff --git a/ph-ee-connector-gsma-mm/.circleci/config.yml b/ph-ee-connector-gsma-mm/.circleci/config.yml new file mode 100644 index 000000000..9b33fff08 --- /dev/null +++ b/ph-ee-connector-gsma-mm/.circleci/config.yml @@ -0,0 +1,100 @@ +version: 2.1 +executors: + docker-executor: + docker: + - image: circleci/openjdk:17-buster-node-browsers-legacy + +jobs: + build_and_push_tag_image: + executor: docker-executor + environment: + JVM_OPTS: -Xmx512m + TERM: dumb + GITHUB_TOKEN: ${GITHUB_TOKEN} # Add the GitHub token as an environment variable + + steps: + - checkout + - setup_remote_docker: + version: 20.10.14 + - run: + name: Build and Push Docker tag Image + command: | + # Set environment variables + IMAGE_TAG=$CIRCLE_TAG + + # Check if the Docker image with the same tag already exists in Docker Hub + if curl -s -f -u "$DOCKERHUB_USERNAME":"$DOCKERHUB_PASSWORD" "https://hub.docker.com/v2/repositories/fynarfin/ph-ee-connector-gsma/tags/$IMAGE_TAG" > /dev/null; then + echo "Skipping the build and push as the tag $IMAGE_TAG already exists in Docker Hub." + exit 0 + fi + + # Build and tag the Docker image + ./gradlew bootJar + docker build -t "fynarfin/ph-ee-connector-gsma:$IMAGE_TAG" . + + # Push the Docker image to Docker Hub + docker login -u "$DOCKERHUB_USERNAME" -p "$DOCKERHUB_PASSWORD" + docker push "fynarfin/ph-ee-connector-gsma:$IMAGE_TAG" + + # when: always # The job will be executed even if there's no match for the tag filter + + build_and_push_latest_image: + executor: docker-executor + environment: + JVM_OPTS: -Xmx512m + TERM: dumb + + steps: + - checkout + # Install Docker to build and push the image + - setup_remote_docker: + version: 20.10.14 + + # Build the Docker image + - run: + name: Build Docker image + command: | + ./gradlew checkstyleMain + ./gradlew checkstyleTest + ./gradlew clean bootJar + docker build -t fynarfin/ph-ee-connector-gsma:latest . + if [ "$CIRCLE_BRANCH" != "develop" ]; then + PR_NUMBER=$(basename $CIRCLE_PULL_REQUEST) + PR_TITLE=$(curl -sSL "https://api.github.com/repos/fynarfin/$CIRCLE_PR_REPONAME/pulls/$PR_NUMBER" | jq -r '.title') + JIRA_STORY=$(echo $PR_TITLE | cut -d "[" -f2 | cut -d "]" -f1 | tr '[A-Z]' '[a-z]') + if [ -z "$JIRA_STORY" ]; then echo "Invalid PR title" && exit 1; else echo "Ticket NO: $JIRA_STORY"; fi + docker image tag fynarfin/ph-ee-connector-gsma:latest fynarfin/ph-ee-connector-gsma:$JIRA_STORY + fi + + # Log in to DockerHub using environment variables + - run: + name: Login to DockerHub + command: echo "${DOCKERHUB_PASSWORD}" | docker login -u "${DOCKERHUB_USERNAME}" --password-stdin + + # Push the Docker image to DockerHub + - run: + name: Push Docker image to DockerHub + command: | + if [ "$CIRCLE_BRANCH" = "develop" ]; then + docker push fynarfin/ph-ee-connector-gsma:latest + fi + if [ "$CIRCLE_BRANCH" != "develop" ]; then + PR_NUMBER=$(basename $CIRCLE_PULL_REQUEST) + PR_TITLE=$(curl -sSL "https://api.github.com/repos/fynarfin/$CIRCLE_PR_REPONAME/pulls/$PR_NUMBER" | jq -r '.title') + JIRA_STORY=$(echo $PR_TITLE | cut -d "[" -f2 | cut -d "]" -f1 | tr '[A-Z]' '[a-z]') + docker push fynarfin/ph-ee-connector-gsma:${JIRA_STORY} + fi + +workflows: + version: 2 + build-and-push: + jobs: + - build_and_push_tag_image: + filters: + tags: + only: /^v\d+\.\d+\.\d+$/ # Match tags in the format v1.2.3 + context: + - DOCKER + - build_and_push_latest_image: + context: + - DOCKER diff --git a/ph-ee-connector-gsma-mm/.github/pull_request_template.md b/ph-ee-connector-gsma-mm/.github/pull_request_template.md new file mode 100644 index 000000000..98a182a2e --- /dev/null +++ b/ph-ee-connector-gsma-mm/.github/pull_request_template.md @@ -0,0 +1,22 @@ +## Description + +* PR title should have jira ticket enclosed in `[]`.
+Format: ``` [jira_ticket] description```
+ex: [phee-123] PR title. +* Add a link to the Jira ticket. +* Describe the changes made and why they were made. + +## Checklist + +Please make sure these boxes are checked before submitting your pull request - thanks! +- [ ] Followed the PR title naming convention mentioned above. + +- [ ] Design related bullet points or design document link related to this PR added in the description above. + +- [ ] Updated corresponding Postman Collection or Api documentation for the changes in this PR. + +- [ ] Created/updated unit or integration tests for verifying the changes made. + +- [ ] Added required Swagger annotation and update API documentation with details of any API changes if applicable + +- [ ] Followed the naming conventions as given in https://docs.google.com/document/d/1Q4vaMSzrTxxh9TS0RILuNkSkYCxotuYk1Xe0CMIkkCU/edit?usp=sharing diff --git a/ph-ee-connector-gsma-mm/.github/workflows/test.yml b/ph-ee-connector-gsma-mm/.github/workflows/test.yml new file mode 100644 index 000000000..24232ebb3 --- /dev/null +++ b/ph-ee-connector-gsma-mm/.github/workflows/test.yml @@ -0,0 +1,10 @@ +name: Test +on: [push, pull_request] +jobs: + Assemble: + runs-on: ubuntu-latest + steps: + - name: Check out repository code + uses: actions/checkout@v2 + - name: Assemble project + run: ./gradlew clean build diff --git a/ph-ee-connector-gsma-mm/.gitignore b/ph-ee-connector-gsma-mm/.gitignore new file mode 100644 index 000000000..4095171b5 --- /dev/null +++ b/ph-ee-connector-gsma-mm/.gitignore @@ -0,0 +1,26 @@ +### Build files ### +target/ +src/main/java/org/mifos/connector/common +.gradle +build/ +!gradle/wrapper/gradle-wrapper.jar + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr + +### VS Code ### +.vscode/ + +*.orig \ No newline at end of file diff --git a/ph-ee-connector-gsma-mm/Dockerfile b/ph-ee-connector-gsma-mm/Dockerfile new file mode 100644 index 000000000..ef5e55d24 --- /dev/null +++ b/ph-ee-connector-gsma-mm/Dockerfile @@ -0,0 +1,4 @@ +FROM openjdk:17 + +COPY build/libs/*.jar . +CMD java -jar *.jar diff --git a/ph-ee-connector-gsma-mm/LICENSE b/ph-ee-connector-gsma-mm/LICENSE new file mode 100644 index 000000000..261eeb9e9 --- /dev/null +++ b/ph-ee-connector-gsma-mm/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/ph-ee-connector-gsma-mm/README.md b/ph-ee-connector-gsma-mm/README.md new file mode 100644 index 000000000..f4f9adb12 --- /dev/null +++ b/ph-ee-connector-gsma-mm/README.md @@ -0,0 +1,3 @@ +# ph-ee-connector-gsma + +#Auto-Trigger diff --git a/ph-ee-connector-gsma-mm/bpmns/bulk_processor.bpmn b/ph-ee-connector-gsma-mm/bpmns/bulk_processor.bpmn new file mode 100644 index 000000000..bc0df7101 --- /dev/null +++ b/ph-ee-connector-gsma-mm/bpmns/bulk_processor.bpmn @@ -0,0 +1,47 @@ + + + + + Flow_1sq9wn7 + + + Flow_1to020f + + + + + + + + Flow_1sq9wn7 + Flow_1to020f + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ph-ee-connector-gsma-mm/bpmns/debit-party-process-DFSPID.bpmn b/ph-ee-connector-gsma-mm/bpmns/debit-party-process-DFSPID.bpmn new file mode 100644 index 000000000..96833b80b --- /dev/null +++ b/ph-ee-connector-gsma-mm/bpmns/debit-party-process-DFSPID.bpmn @@ -0,0 +1,319 @@ + + + + + Flow_1iz4su9 + + + Flow_1khpy8b + + + + + + + Flow_0drcaub + Flow_0r7t1vh + Flow_0fq2w8b + + + Flow_0fq2w8b + Flow_0z3yk8q + + + Flow_16b1s15 + + PT60S + + + + Flow_16b1s15 + Flow_0drcaub + Flow_177y51s + + + =payeeAccountStatusRetry < 3 + + + + Flow_0z3yk8q + Flow_1rd2qbu + Flow_06fadz1 + + + + + + + + Flow_1g9y30t + Flow_1khpy8b + + + Flow_1rbhwaj + + + =partyLookupFailed = true + + + Flow_1rd8f1u + + + + + + + + + Flow_177y51s + Flow_1rd8f1u + + + + + + + Flow_1rd2qbu + Flow_0vpl387 + Flow_1rbhwaj + + + + + + Flow_06fadz1 + Flow_1ojxhgg + + + Flow_1ojxhgg + Flow_0vpl387 + Flow_053zh7e + + + + + + + Flow_053zh7e + Flow_11ks5lq + + + Flow_11ks5lq + Flow_0ygr2i6 + Flow_1g9y30t + + + + =transferPrepareFailed = true + + + =transferCreateFailed = true + + + + + + + Flow_0ygr2i6 + Flow_02nd84o + + + Flow_02nd84o + + + + + + + Flow_1iz4su9 + Flow_0r7t1vh + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ph-ee-connector-gsma-mm/bpmns/gsma-bill-payment.bpmn b/ph-ee-connector-gsma-mm/bpmns/gsma-bill-payment.bpmn new file mode 100644 index 000000000..82d5b387d --- /dev/null +++ b/ph-ee-connector-gsma-mm/bpmns/gsma-bill-payment.bpmn @@ -0,0 +1,409 @@ + + + + + Flow_0tk2ifu + + + Flow_1xmvmed + + + + + + Flow_1eb232y + Flow_09uoau8 + + + Flow_09uoau8 + Flow_17xcyxt + Flow_0xr934y + + + Flow_1bqhdy1 + Flow_10lx4kv + Flow_0d9tmm4 + + + + + + Flow_10rvrb2 + Flow_1bqhdy1 + + + Flow_0d9tmm4 + Flow_11r1axh + Flow_1i00n59 + + + + + + Flow_160tmjo + Flow_1xmvmed + + + Flow_1mdj95p + Flow_1bqfmi7 + Flow_1rjo4c4 + + + Flow_0zhx7zw + + + Flow_1etcf1u + + + + + + Flow_1rjo4c4 + Flow_1etcf1u + + + + + + Flow_17xcyxt + Flow_0uh3hk9 + Flow_0d2lx0j + Flow_0zhx7zw + + + + + + Flow_0xr934y + Flow_16ajdal + + + Flow_16ajdal + Flow_10rvrb2 + Flow_0uh3hk9 + + + + + + Flow_11r1axh + Flow_1rp6lna + + + Flow_1rp6lna + Flow_160tmjo + Flow_0e0628v + + + + + + Flow_1i00n59 + Flow_10c5opy + + + + + + Flow_0e0628v + Flow_05ijvs7 + Flow_0zkx4io + + + Flow_0zkx4io + + + Flow_10c5opy + Flow_0d2lx0j + Flow_05ijvs7 + + + + + + Flow_0tk2ifu + Flow_1eb232y + + + Flow_1mdj95p + + PT60S + + + + + + + + =billStatusError = true + + + + + + =paymentTransferRetry < 3 + + + + + =transactionFailed = true + + + + + + + + =transferPrepareFailed = true + + + + + + =transferCreateFailed = true + + + + =transferReleaseFailed = true + + + + + + + Flow_1bqfmi7 + Flow_10lx4kv + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ph-ee-connector-gsma-mm/bpmns/gsma-inttransfer-payer.bpmn b/ph-ee-connector-gsma-mm/bpmns/gsma-inttransfer-payer.bpmn new file mode 100644 index 000000000..2a33b35ce --- /dev/null +++ b/ph-ee-connector-gsma-mm/bpmns/gsma-inttransfer-payer.bpmn @@ -0,0 +1,592 @@ + + + + + Flow_0hymeub + + + Flow_14zk5zf + + + + + + Flow_1lnunl7 + Flow_08ry6kb + Flow_1l37gfy + + + Flow_1l37gfy + Flow_0tpdj7v + + + Flow_0eo8qz6 + Flow_1lnunl7 + Flow_0zw1ae7 + + + Flow_0tpdj7v + Flow_0mkf71e + Flow_1ugc26m + + + Flow_1mmeifz + Flow_1xdeqyv + Flow_1nhcqs5 + + + + + + Flow_0spn1nz + Flow_1mmeifz + + + Flow_1nhcqs5 + Flow_1i8dcbu + Flow_16358wv + + + + + + Flow_1hd7asg + Flow_14zk5zf + + + Flow_15t0wnt + Flow_1jj70lx + Flow_0j4cgfu + + + Flow_1bnldtz + + + Flow_1gacwmh + + + + + + Flow_0zw1ae7 + Flow_0j4cgfu + Flow_0vj8tsx + Flow_1gacwmh + + + + + + Flow_0mkf71e + Flow_1qe4zz1 + Flow_0e9435i + Flow_17k1e4j + Flow_1bnldtz + + + + + + Flow_1rg60pi + Flow_0e92dsh + + + Flow_0e92dsh + Flow_0spn1nz + Flow_1qe4zz1 + + + + + + Flow_1i8dcbu + Flow_08moqcp + + + Flow_08moqcp + Flow_1hd7asg + Flow_090t7bu + + + + + + Flow_16358wv + Flow_0uscqbi + + + + + + Flow_090t7bu + Flow_0prbs2c + Flow_0osg66n + + + Flow_0osg66n + + + Flow_0uscqbi + Flow_0e9435i + Flow_0prbs2c + + + + + + Flow_0hymeub + Flow_08ry6kb + + + Flow_0eo8qz6 + + PT60S + + + + Flow_15t0wnt + + PT60S + + + + + + =payeeAccountStatusRetry < 3 + + + + + + + + =partyLookupFailed = true + + + + + + =paymentTransferRetry < 3 + + + + + =transactionFailed = true + + + + + + + + =transferPrepareFailed = true + + + + + + =transferCreateFailed = true + + + + =transferReleaseFailed = true + + + + + + + + Flow_1ugc26m + Flow_1pohph2 + Flow_19zmt8a + + + Flow_19zmt8a + Flow_0okvk4r + + + Flow_06ojh3o + + PT60S + + + + Flow_06ojh3o + Flow_0vj8tsx + Flow_1pohph2 + + + + + =quoteRetryCount < 3 + + + Flow_0okvk4r + Flow_17k1e4j + Flow_1b65dfh + + + =gsmaQuoteFailed = true + + + + + + + + + Flow_1b65dfh + Flow_1rg60pi + + + + + + Flow_1jj70lx + Flow_1xdeqyv + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ph-ee-connector-gsma-mm/bpmns/gsma-link-based-transfer.bpmn b/ph-ee-connector-gsma-mm/bpmns/gsma-link-based-transfer.bpmn new file mode 100644 index 000000000..22d731582 --- /dev/null +++ b/ph-ee-connector-gsma-mm/bpmns/gsma-link-based-transfer.bpmn @@ -0,0 +1,560 @@ + + + + + Flow_1v217se + + + Flow_1051pnn + + + + + + Flow_18gj14i + Flow_0wbgbny + Flow_1yf0wh8 + + + Flow_1yf0wh8 + Flow_0qjn5ay + + + Flow_0p2feb1 + Flow_18gj14i + Flow_01ivm2n + + + Flow_0qjn5ay + Flow_0qfg7ma + Flow_0zr3bxl + + + Flow_1v7vwto + Flow_1282nka + Flow_165lzj4 + + + + + + Flow_1nohbyk + Flow_1v7vwto + + + Flow_165lzj4 + Flow_0scb2p0 + Flow_1ieoorm + + + + + + Flow_0yn2pcx + Flow_1051pnn + + + Flow_1tkyo8r + Flow_0uh8wz8 + Flow_1kacb4n + + + Flow_1tbs7kd + + + Flow_1p3v3zi + + + + + + Flow_01ivm2n + Flow_1kacb4n + Flow_1yy9jqc + Flow_1p3v3zi + + + + + + Flow_0qfg7ma + Flow_18o5655 + Flow_0zk5cvc + Flow_11l9zbd + Flow_1tbs7kd + + + + + + Flow_0hfbu8w + Flow_07bmth7 + + + Flow_07bmth7 + Flow_1nohbyk + Flow_18o5655 + + + + + + Flow_0scb2p0 + Flow_0eziyaa + + + Flow_0eziyaa + Flow_0yn2pcx + Flow_05h76w0 + + + + + + Flow_1ieoorm + Flow_1lf3yyw + + + + + + Flow_05h76w0 + Flow_0baupe0 + Flow_0x9t7lb + + + Flow_0x9t7lb + + + Flow_1lf3yyw + Flow_0zk5cvc + Flow_0baupe0 + + + + + + Flow_1v217se + Flow_0wbgbny + + + Flow_1tkyo8r + + PT60S + + + + + + =payeeAccountStatusRetry < 3 + + + + + + + + =partyLookupFailed = true + + + + + + =paymentTransferRetry < 3 + + + + + =transactionFailed = true + + + + + + + + =transferPrepareFailed = true + + + + + + =transferCreateFailed = true + + + + =transferReleaseFailed = true + + + + + Flow_1ksdq93 + Flow_0hfbu8w + Flow_11l9zbd + + + + + =linkCreationFailed = true + + + Flow_12o082h + Flow_1ksdq93 + + + + + + Flow_0zr3bxl + Flow_1qz445y + Flow_12o082h + + + Flow_1y4b8dl + + PT60S + + + + Flow_0p2feb1 + + PT60S + + + + + Flow_1y4b8dl + Flow_1yy9jqc + Flow_1qz445y + + + + =linkCreationRetryCount < 3 + + + + + + Flow_0uh8wz8 + Flow_1282nka + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ph-ee-connector-gsma-mm/bpmns/gsma-p2p-wo-local-quote.bpmn b/ph-ee-connector-gsma-mm/bpmns/gsma-p2p-wo-local-quote.bpmn new file mode 100644 index 000000000..66805950a --- /dev/null +++ b/ph-ee-connector-gsma-mm/bpmns/gsma-p2p-wo-local-quote.bpmn @@ -0,0 +1,471 @@ + + + + + Flow_1iz4su9 + + + Flow_1khpy8b + + + + + + + Flow_0drcaub + Flow_0r7t1vh + Flow_0fq2w8b + + + Flow_0fq2w8b + Flow_0z3yk8q + + + Flow_16b1s15 + + PT60S + + + + Flow_16b1s15 + Flow_0drcaub + Flow_177y51s + + + =payeeAccountStatusRetry < 3 + + + + Flow_0z3yk8q + Flow_1rd2qbu + Flow_06fadz1 + + + + Flow_0vfzj5k + Flow_1oiw1si + Flow_1yuhu0t + + + + + + Flow_0s5yx0e + Flow_0vfzj5k + + + + + + Flow_1yuhu0t + Flow_04sgr67 + Flow_11fn478 + + + + + + + Flow_1g9y30t + Flow_1khpy8b + + + Flow_126dexs + + PT60S + + + + Flow_126dexs + Flow_150jms5 + Flow_1lf6hxg + + + + =paymentTransferRetry < 3 + + + Flow_1rbhwaj + + + =partyLookupFailed = true + + + =transactionFailed = true + + + Flow_1rd8f1u + + + + + + + + + + Flow_177y51s + Flow_1lf6hxg + Flow_1rd8f1u + + + + + + + Flow_1rd2qbu + Flow_0vpl387 + Flow_0o49cl4 + Flow_1rbhwaj + + + + + + Flow_06fadz1 + Flow_1ojxhgg + + + Flow_1ojxhgg + Flow_0vpl387 + Flow_0s5yx0e + + + + + + + Flow_04sgr67 + Flow_11ks5lq + + + Flow_11ks5lq + Flow_0ygr2i6 + Flow_1g9y30t + + + + =transferPrepareFailed = true + + + =transferCreateFailed = true + + + + + + + + Flow_11fn478 + Flow_03o1q44 + + + + + + Flow_1kzho50 + Flow_0ygr2i6 + Flow_02nd84o + + + Flow_02nd84o + + + + Flow_03o1q44 + Flow_1kzho50 + Flow_0o49cl4 + + + + =transferReleaseFailed = true + + + + + + + Flow_1iz4su9 + Flow_0r7t1vh + + + + + + + + Flow_150jms5 + Flow_1oiw1si + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ph-ee-connector-gsma-mm/bpmns/gsma-p2p.bpmn b/ph-ee-connector-gsma-mm/bpmns/gsma-p2p.bpmn new file mode 100644 index 000000000..cd5d9d079 --- /dev/null +++ b/ph-ee-connector-gsma-mm/bpmns/gsma-p2p.bpmn @@ -0,0 +1,491 @@ + + + + + Flow_1iz4su9 + + + Flow_1khpy8b + + + + + + + Flow_0drcaub + Flow_0r7t1vh + Flow_0fq2w8b + + + Flow_0fq2w8b + Flow_0z3yk8q + + + Flow_16b1s15 + + PT60S + + + + Flow_16b1s15 + Flow_0drcaub + Flow_177y51s + + + =payeeAccountStatusRetry < 3 + + + + Flow_0z3yk8q + Flow_1sh7v1m + Flow_1rd2qbu + + + + + Flow_0vfzj5k + Flow_1yuhu0t + + + + + + Flow_150jms5 + Flow_0s5yx0e + Flow_0vfzj5k + + + + + + Flow_1yuhu0t + Flow_04sgr67 + Flow_11fn478 + + + + + + + Flow_1g9y30t + Flow_1khpy8b + + + Flow_126dexs + + PT60S + + + + Flow_126dexs + Flow_150jms5 + Flow_1lf6hxg + + + + =paymentTransferRetry < 3 + + + Flow_1rbhwaj + + + =partyLookupFailed = true + + + =transactionFailed = true + + + Flow_1rd8f1u + + + + + + + + + + Flow_177y51s + Flow_1lf6hxg + Flow_1rd8f1u + + + + + + + Flow_1rd2qbu + Flow_192jsmu + Flow_0vpl387 + Flow_0o49cl4 + Flow_1rbhwaj + + + + + + Flow_1sh7v1m + Flow_1orxtvv + + + Flow_1orxtvv + Flow_192jsmu + Flow_0fw3ncg + + + =localQuoteFailed = true + + + + + + + + Flow_0fw3ncg + Flow_1ojxhgg + + + Flow_1ojxhgg + Flow_0vpl387 + Flow_0s5yx0e + + + + + + + Flow_04sgr67 + Flow_11ks5lq + + + Flow_11ks5lq + Flow_0ygr2i6 + Flow_1g9y30t + + + + =transferPrepareFailed = true + + + =transferCreateFailed = true + + + + + + + + Flow_11fn478 + Flow_03o1q44 + + + + + + Flow_1kzho50 + Flow_0ygr2i6 + Flow_02nd84o + + + Flow_02nd84o + + + + Flow_03o1q44 + Flow_1kzho50 + Flow_0o49cl4 + + + + =transferReleaseFailed = true + + + + + + + Flow_1iz4su9 + Flow_0r7t1vh + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ph-ee-connector-gsma-mm/bpmns/gsma-payee-process.bpmn b/ph-ee-connector-gsma-mm/bpmns/gsma-payee-process.bpmn new file mode 100644 index 000000000..52263ee92 --- /dev/null +++ b/ph-ee-connector-gsma-mm/bpmns/gsma-payee-process.bpmn @@ -0,0 +1,288 @@ + + + + + Flow_1jp0uac + + + + + + Flow_1jp0uac + Flow_1qylaeu + + + Flow_1eioo1e + + + Flow_0l4vst0 + Flow_0bb479o + Flow_0whzjay + Flow_1rwwmqg + + + Flow_0bb479o + Flow_0qf8vno + + + + Flow_1rwwmqg + Flow_1idno0h + + PT60S + + + + + + + Flow_0i2fojt + Flow_1eioo1e + + + Flow_1qylaeu + Flow_0l4vst0 + Flow_0kma2kd + + + + + + Flow_0qf8vno + Flow_16vrj0s + + + Flow_0kp58m6 + + + Flow_16vrj0s + Flow_1no09i2 + Flow_0i2fojt + + + Flow_0whzjay + Flow_0rtotew + + + + Flow_1idno0h + + + Flow_0rtotew + + + Flow_0kma2kd + + + + + + + + + + + + =quoteFailed = true + + + + =transferCreateFailed = true + + + + + + + + Flow_1no09i2 + Flow_0kp58m6 + + + + + + add timeout dynamically for transfer and rtp? + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ph-ee-connector-gsma-mm/bpmns/gsma-payee-transfer.bpmn b/ph-ee-connector-gsma-mm/bpmns/gsma-payee-transfer.bpmn new file mode 100644 index 000000000..8e8b02e4a --- /dev/null +++ b/ph-ee-connector-gsma-mm/bpmns/gsma-payee-transfer.bpmn @@ -0,0 +1,383 @@ + + + + + Flow_0ao1g7c + + + Flow_1v5iuvx + Flow_07p7x6s + + + Flow_07zv7t5 + Flow_0ajk81k + + + Flow_07p7x6s + Flow_0tb55c7 + Flow_00vfw5y + + + + + + Flow_0ajk81k + Flow_00vfw5y + Flow_0zwb6ut + Flow_1fsohe8 + Flow_02o8xzy + Flow_05ept57 + Flow_1a97ey7 + + + Flow_1a97ey7 + + + + + + Flow_0tb55c7 + Flow_0zoteng + Flow_0za0l9f + + + Flow_0za0l9f + Flow_070pc0z + + + Flow_1kgnsb8 + Flow_0zwb6ut + Flow_0zoteng + + + Flow_0jr8i67 + + + Flow_070pc0z + Flow_1fsohe8 + Flow_05fdird + + + + + + Flow_1jmde75 + Flow_0jr8i67 + + + Flow_1todusq + Flow_02o8xzy + Flow_1jmde75 + Flow_1wy69jw + + + Flow_07zv7t5 + + PT60S + + + + Flow_1kgnsb8 + + PT60S + + + + + + + + =partyLookupFailed = true + + + + =transactionRequestFailed = true + + + =transactionState != "ACCEPTED" + + + + + =transactionRequestRetryCount < 3 + + + + + + + + =isAuthorisationRequired and (transactionRequestFailed = true or transActionState = "REJECTED") + + + + + + Flow_0ao1g7c + Flow_1v5iuvx + + + + + Flow_0rvu1jq + Flow_05fdird + Flow_1todusq + + + Flow_1vji14u + Flow_1wy69jw + Flow_0rvu1jq + Flow_05ept57 + + + Flow_1vji14u + + PT60S + + + + =isAuthorisationRequired = true and authRetriesLeftCount < authRetriesLeft + + + + + + Starts GSMA peer to peer transfer flow from payer side + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ph-ee-connector-gsma-mm/bpmns/international-remittance-payee-process-DFSPID.bpmn b/ph-ee-connector-gsma-mm/bpmns/international-remittance-payee-process-DFSPID.bpmn new file mode 100644 index 000000000..87c7b67a4 --- /dev/null +++ b/ph-ee-connector-gsma-mm/bpmns/international-remittance-payee-process-DFSPID.bpmn @@ -0,0 +1,77 @@ + + + + + Flow_1oh4r14 + + + + + + Flow_1oh4r14 + Flow_15u0t1f + + + Flow_0dl6v3u + + + + + Flow_15u0t1f + Flow_0dl6v3u + Flow_1ybr1l5 + + + + =transferCreateFailed = true + + + Flow_1ybr1l5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ph-ee-connector-gsma-mm/bpmns/international-remittance-payer-process-DFSPID.bpmn b/ph-ee-connector-gsma-mm/bpmns/international-remittance-payer-process-DFSPID.bpmn new file mode 100644 index 000000000..6282216e1 --- /dev/null +++ b/ph-ee-connector-gsma-mm/bpmns/international-remittance-payer-process-DFSPID.bpmn @@ -0,0 +1,467 @@ + + + + + Flow_1iz4su9 + + + Flow_1khpy8b + + + + + + + Flow_0drcaub + Flow_0r7t1vh + Flow_0fq2w8b + + + Flow_0fq2w8b + Flow_0z3yk8q + + + Flow_16b1s15 + + PT60S + + + + Flow_16b1s15 + Flow_0drcaub + Flow_177y51s + + + =payeeAccountStatusRetry < 3 + + + + Flow_0z3yk8q + Flow_1rd2qbu + Flow_06fadz1 + + + + Flow_0vfzj5k + Flow_1oiw1si + Flow_1yuhu0t + + + + + + Flow_0s5yx0e + Flow_0vfzj5k + + + + + + Flow_1yuhu0t + Flow_04sgr67 + Flow_11fn478 + + + + + + + Flow_1g9y30t + Flow_1khpy8b + + + Flow_126dexs + + PT60S + + + + Flow_126dexs + Flow_150jms5 + Flow_1lf6hxg + + + + =paymentTransferRetry < 3 + + + Flow_1rbhwaj + + + =partyLookupFailed = true + + + =transactionFailed = true + + + Flow_1rd8f1u + + + + + + + + + + Flow_177y51s + Flow_1lf6hxg + Flow_1rd8f1u + + + + + + + Flow_1rd2qbu + Flow_0vpl387 + Flow_0o49cl4 + Flow_1rbhwaj + + + + + + Flow_06fadz1 + Flow_1ojxhgg + + + Flow_1ojxhgg + Flow_0vpl387 + Flow_0s5yx0e + + + + + + + Flow_04sgr67 + Flow_11ks5lq + + + Flow_11ks5lq + Flow_0ygr2i6 + Flow_1g9y30t + + + + =transferPrepareFailed = true + + + =transferCreateFailed = true + + + + + + + + Flow_11fn478 + Flow_03o1q44 + + + + + + Flow_1kzho50 + Flow_0ygr2i6 + Flow_02nd84o + + + Flow_02nd84o + + + + Flow_03o1q44 + Flow_1kzho50 + Flow_0o49cl4 + + + + =transferReleaseFailed = true + + + + + + + Flow_1iz4su9 + Flow_0r7t1vh + + + + + + + + Flow_150jms5 + Flow_1oiw1si + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ph-ee-connector-gsma-mm/build.gradle b/ph-ee-connector-gsma-mm/build.gradle new file mode 100644 index 000000000..a01c40a2a --- /dev/null +++ b/ph-ee-connector-gsma-mm/build.gradle @@ -0,0 +1,191 @@ +/* + * This file was generated by the Gradle 'init' task. + */ + +plugins { + id 'java' + id 'maven-publish' + id 'org.springframework.boot' version '2.6.2' + id 'eclipse' + id 'checkstyle' + id 'com.diffplug.spotless' version '6.19.0' +} + +repositories { + // mavenLocal() + maven { + url = uri('https://repo.maven.apache.org/maven2') + } + + maven { + url = uri('https://jfrog.sandbox.fynarfin.io/artifactory/fyn-libs-snapshot') + } +} + +apply plugin:'com.diffplug.spotless' +spotless { + format 'misc', { + target '**/*.md', '**/*.properties', '**/.gitignore', '**/.openapi-generator-ignore', '**/*.yml', '**/*.xml', '**/**.json', '**/*.sql' + targetExclude '**/build/**', '**/bin/**', '**/.settings/**', '**/.idea/**', '**/.gradle/**', '**/gradlew.bat', '**/licenses/**', '**/banner.txt', '.vscode/**' + indentWithSpaces(4) + endWithNewline() + trimTrailingWhitespace() + } + + groovyGradle { + target '*.gradle', '**/*.gradle' + targetExclude '**/build/**' + greclipse() + indentWithSpaces(4) + endWithNewline() + trimTrailingWhitespace() + } + + lineEndings 'UNIX' +} + +ext { + springBootVersion = '2.6.2' +} + +dependencies { + implementation 'org.mifos:ph-ee-connector-common:1.0.0-SNAPSHOT' + implementation 'org.apache.camel.springboot:camel-spring-boot-starter:3.12.0' + implementation 'org.apache.camel:camel-endpointdsl:3.4.0' + implementation 'org.apache.camel:camel-jetty:3.4.0' + implementation 'org.apache.camel:camel-undertow:3.4.0' + implementation 'org.apache.camel:camel-http:3.4.0' + implementation 'org.apache.camel.springboot:camel-jackson-starter:3.12.0' + implementation 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.10.1' + implementation 'org.json:json:20190722' + implementation 'io.camunda:zeebe-client-java:1.1.0' + implementation 'com.auth0:java-jwt:3.10.2' + testImplementation 'org.springframework.boot:spring-boot-starter-test:2.6.2' + testImplementation 'org.junit.jupiter:junit-jupiter-api:5.6.0' + testImplementation 'org.junit.jupiter:junit-jupiter-engine:5.6.0' + checkstyle 'com.puppycrawl.tools:checkstyle:10.9.3' + checkstyle 'com.github.sevntu-checkstyle:sevntu-checks:1.44.1' + implementation 'com.diffplug.gradle.spotless:spotless:2.4.1' + implementation 'com.diffplug.spotless:spotless-plugin-gradle:6.17.0' + implementation 'org.springframework.boot:spring-boot-starter:2.5.2' + implementation 'org.springframework.boot:spring-boot-starter-web:2.5.2' + implementation "org.springframework.boot:spring-boot-starter-actuator:$springBootVersion" +} +configure(this) { + // NOTE: order matters! + apply plugin: 'java' + apply plugin: 'idea' + apply plugin: 'eclipse' + apply plugin: 'checkstyle' + configurations { + implementation.setCanBeResolved(true) + api.setCanBeResolved(true) + } + tasks.withType(JavaCompile) { + options.compilerArgs += [ + "-Xlint:unchecked", + "-Xlint:cast", + "-Xlint:auxiliaryclass", + "-Xlint:deprecation", + "-Xlint:dep-ann", + "-Xlint:divzero", + "-Xlint:empty", + "-Xlint:exports", + "-Xlint:fallthrough", + "-Xlint:finally", + "-Xlint:module", + "-Xlint:opens", + "-Xlint:options", + "-Xlint:overloads", + "-Xlint:overrides", + "-Xlint:path", + "-Xlint:processing", + "-Xlint:removal", + "-Xlint:requires-automatic", + "-Xlint:requires-transitive-automatic", + "-Xlint:try", + "-Xlint:varargs", + "-Xlint:preview", + "-Xlint:static", + // -Werror needs to be disabled because EclipseLink's static weaving doesn't generate warning-free code + // and during an IntelliJ recompilation, it fails + //"-Werror", + "-Xmaxwarns", + 1500, + "-Xmaxerrs", + 1500 + ] + options.deprecation = true + } + // Configuration for the spotless plugin + // https://github.com/diffplug/spotless/tree/main/plugin-gradle + spotless { + java { + targetExclude '**/build/**', '**/bin/**', '**/out/**' + importOrder() //sort imports alphabetically + removeUnusedImports() + eclipse().configFile "$rootDir/ph-ee-connector-gsma-mm/config/gsma-formatter.xml" + endWithNewline() + trimTrailingWhitespace() + // Enforce style modifier order + custom 'Modifier ordering', { + def modifierRanking = [ + public : 1, + protected : 2, + private : 3, + abstract : 4, + default : 5, + static : 6, + final : 7, + transient : 8, + volatile : 9, + synchronized: 10, + native : 11, + strictfp : 12] + // Find any instance of multiple modifiers. Lead with a non-word character to avoid + // accidental matching against for instance, "an alternative default value" + it.replaceAll(/\W(?:public |protected |private |abstract |default |static |final |transient |volatile |synchronized |native |strictfp ){2,}/, { + // Do not replace the leading non-word character. Identify the modifiers + it.replaceAll(/(?:public |protected |private |abstract |default |static |final |transient |volatile |synchronized |native |strictfp ){2,}/, { + // Sort the modifiers according to the ranking above + it.split().sort({ modifierRanking[it] }).join(' ') + ' ' + } + ) + } + ) + } + } + lineEndings 'UNIX' + } + // If we are running Gradle within Eclipse to enhance classes, + // set the classes directory to point to Eclipse's default build directory + if (project.hasProperty('env') && project.getProperty('env') == 'eclipse') { + sourceSets.main.java.outputDir = file("$projectDir/bin/main") + } + // Configuration for the Checkstyle plugin + // https://docs.gradle.org/current/userguide/checkstyle_plugin.html + dependencies { + checkstyle 'com.puppycrawl.tools:checkstyle:10.3.1' + checkstyle 'com.github.sevntu-checkstyle:sevntu-checks:1.42.0' + } +} +group = 'org.mifos' +version = '1.0.0-SNAPSHOT' +sourceCompatibility = '17' +targetCompatibility = '17' + +test { + useJUnitPlatform() +} + +publishing { + publications { + maven(MavenPublication) { + from(components.java) + } + } +} + +tasks.withType(JavaCompile) { + options.encoding = 'UTF-8' +} diff --git a/ph-ee-connector-gsma-mm/config/checkstyle/checkstyle.xml b/ph-ee-connector-gsma-mm/config/checkstyle/checkstyle.xml new file mode 100644 index 000000000..5183efef5 --- /dev/null +++ b/ph-ee-connector-gsma-mm/config/checkstyle/checkstyle.xml @@ -0,0 +1,266 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ph-ee-connector-gsma-mm/config/checkstyle/suppressions.xml b/ph-ee-connector-gsma-mm/config/checkstyle/suppressions.xml new file mode 100644 index 000000000..f4e5b54c3 --- /dev/null +++ b/ph-ee-connector-gsma-mm/config/checkstyle/suppressions.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + diff --git a/ph-ee-connector-gsma-mm/config/gsma-cleanup.xml b/ph-ee-connector-gsma-mm/config/gsma-cleanup.xml new file mode 100644 index 000000000..0042addbb --- /dev/null +++ b/ph-ee-connector-gsma-mm/config/gsma-cleanup.xml @@ -0,0 +1,71 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ph-ee-connector-gsma-mm/config/gsma-formatter.xml b/ph-ee-connector-gsma-mm/config/gsma-formatter.xml new file mode 100644 index 000000000..07085327a --- /dev/null +++ b/ph-ee-connector-gsma-mm/config/gsma-formatter.xml @@ -0,0 +1,366 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ph-ee-connector-gsma-mm/gradle/wrapper/gradle-wrapper.jar b/ph-ee-connector-gsma-mm/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 000000000..41d9927a4 Binary files /dev/null and b/ph-ee-connector-gsma-mm/gradle/wrapper/gradle-wrapper.jar differ diff --git a/ph-ee-connector-gsma-mm/gradle/wrapper/gradle-wrapper.properties b/ph-ee-connector-gsma-mm/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 000000000..e750102e0 --- /dev/null +++ b/ph-ee-connector-gsma-mm/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-7.3-bin.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/ph-ee-connector-gsma-mm/gradlew b/ph-ee-connector-gsma-mm/gradlew new file mode 100755 index 000000000..1b6c78733 --- /dev/null +++ b/ph-ee-connector-gsma-mm/gradlew @@ -0,0 +1,234 @@ +#!/bin/sh + +# +# Copyright © 2015-2021 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit + +APP_NAME="Gradle" +APP_BASE_NAME=${0##*/} + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/ph-ee-connector-gsma-mm/gradlew.bat b/ph-ee-connector-gsma-mm/gradlew.bat new file mode 100644 index 000000000..ac1b06f93 --- /dev/null +++ b/ph-ee-connector-gsma-mm/gradlew.bat @@ -0,0 +1,89 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/ph-ee-connector-gsma-mm/settings.gradle b/ph-ee-connector-gsma-mm/settings.gradle new file mode 100644 index 000000000..4094f6ed1 --- /dev/null +++ b/ph-ee-connector-gsma-mm/settings.gradle @@ -0,0 +1,5 @@ +/* + * This file was generated by the Gradle 'init' task. + */ + +rootProject.name = 'ph-ee-connector-gsma' diff --git a/ph-ee-connector-gsma-mm/src/.DS_Store b/ph-ee-connector-gsma-mm/src/.DS_Store new file mode 100644 index 000000000..225e59f13 Binary files /dev/null and b/ph-ee-connector-gsma-mm/src/.DS_Store differ diff --git a/ph-ee-connector-gsma-mm/src/main/java/org/mifos/connector/GsmaConnectorApplication.java b/ph-ee-connector-gsma-mm/src/main/java/org/mifos/connector/GsmaConnectorApplication.java new file mode 100644 index 000000000..c910bbe79 --- /dev/null +++ b/ph-ee-connector-gsma-mm/src/main/java/org/mifos/connector/GsmaConnectorApplication.java @@ -0,0 +1,34 @@ +package org.mifos.connector; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; +import org.apache.camel.Processor; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.Bean; + +@SpringBootApplication +public class GsmaConnectorApplication { + + public static void main(String[] args) { + SpringApplication.run(GsmaConnectorApplication.class, args); + } + + @Bean + public ObjectMapper objectMapper() { + ObjectMapper objectMapper = new ObjectMapper(); + objectMapper.registerModule(new JavaTimeModule()); + objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false); + return objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL) + .configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true) + .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + } + + @Bean + public Processor pojoToString(ObjectMapper objectMapper) { + return exchange -> exchange.getIn().setBody(objectMapper.writeValueAsString(exchange.getIn().getBody())); + } +} diff --git a/ph-ee-connector-gsma-mm/src/main/java/org/mifos/connector/gsma/HealthCheck.java b/ph-ee-connector-gsma-mm/src/main/java/org/mifos/connector/gsma/HealthCheck.java new file mode 100644 index 000000000..942756ab9 --- /dev/null +++ b/ph-ee-connector-gsma-mm/src/main/java/org/mifos/connector/gsma/HealthCheck.java @@ -0,0 +1,32 @@ +package org.mifos.connector.gsma; + +import org.apache.camel.Exchange; +import org.apache.camel.LoggingLevel; +import org.apache.camel.builder.RouteBuilder; +import org.mifos.connector.gsma.auth.AccessTokenStore; +import org.mifos.connector.gsma.zeebe.ZeebeProcessStarter; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component +public class HealthCheck extends RouteBuilder { + + @Autowired + public ZeebeProcessStarter zeebeProcessStarter; + + @Autowired + public AccessTokenStore accessTokenStore; + + private static final Logger logger = LoggerFactory.getLogger(ZeebeProcessStarter.class); + + @Override + public void configure() throws Exception { + from("rest:GET:/").setHeader(Exchange.HTTP_RESPONSE_CODE, constant(200)).setBody(constant("GET Good")); + + from("rest:POST:/").log(LoggingLevel.INFO, "POST Body: ${body}").setHeader(Exchange.HTTP_RESPONSE_CODE, constant(200)) + .setBody(constant("All Post Good")); + + } +} diff --git a/ph-ee-connector-gsma-mm/src/main/java/org/mifos/connector/gsma/account/AccountResponseProcessor.java b/ph-ee-connector-gsma-mm/src/main/java/org/mifos/connector/gsma/account/AccountResponseProcessor.java new file mode 100644 index 000000000..097bc5646 --- /dev/null +++ b/ph-ee-connector-gsma-mm/src/main/java/org/mifos/connector/gsma/account/AccountResponseProcessor.java @@ -0,0 +1,51 @@ +package org.mifos.connector.gsma.account; + +import static org.mifos.connector.gsma.camel.config.CamelProperties.CORRELATION_ID; +import static org.mifos.connector.gsma.camel.config.CamelProperties.ERROR_INFORMATION; +import static org.mifos.connector.gsma.zeebe.ZeebeExpressionVariables.PARTY_LOOKUP_FAILED; +import static org.mifos.connector.gsma.zeebe.ZeebeMessages.ACCOUNT_STATUS; + +import io.camunda.zeebe.client.ZeebeClient; +import java.time.Duration; +import java.util.HashMap; +import java.util.Map; +import org.apache.camel.Exchange; +import org.apache.camel.Processor; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +@Component +public class AccountResponseProcessor implements Processor { + + @Autowired + private ZeebeClient zeebeClient; + + private Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Value("${zeebe.client.ttl}") + private int timeToLive; + + @Override + public void process(Exchange exchange) { + + Map variables = new HashMap<>(); + + Object isPayeePartyLookupFailed = exchange.getProperty(PARTY_LOOKUP_FAILED); + if (isPayeePartyLookupFailed != null && (boolean) isPayeePartyLookupFailed) { + variables.put(ERROR_INFORMATION, exchange.getIn().getBody(String.class)); + variables.put(PARTY_LOOKUP_FAILED, true); + } else { + // TODO: Consult and Add partyLookupFspId + variables.put(PARTY_LOOKUP_FAILED, false); + } + + logger.info("Publishing account status message variables: " + variables); + + zeebeClient.newPublishMessageCommand().messageName(ACCOUNT_STATUS) + .correlationKey(exchange.getProperty(CORRELATION_ID, String.class)).timeToLive(Duration.ofMillis(timeToLive)) + .variables(variables).send().join(); + } +} diff --git a/ph-ee-connector-gsma-mm/src/main/java/org/mifos/connector/gsma/account/AccountRoutes.java b/ph-ee-connector-gsma-mm/src/main/java/org/mifos/connector/gsma/account/AccountRoutes.java new file mode 100644 index 000000000..0148db391 --- /dev/null +++ b/ph-ee-connector-gsma-mm/src/main/java/org/mifos/connector/gsma/account/AccountRoutes.java @@ -0,0 +1,182 @@ +package org.mifos.connector.gsma.account; + +import static org.mifos.connector.gsma.camel.config.CamelProperties.ACCESS_TOKEN; +import static org.mifos.connector.gsma.camel.config.CamelProperties.ACCOUNT_ACTION; +import static org.mifos.connector.gsma.camel.config.CamelProperties.ACCOUNT_RESPONSE; +import static org.mifos.connector.gsma.camel.config.CamelProperties.IDENTIFIER; +import static org.mifos.connector.gsma.camel.config.CamelProperties.IDENTIFIER_TYPE; +import static org.mifos.connector.gsma.camel.config.CamelProperties.IS_API_CALL; +import static org.mifos.connector.gsma.zeebe.ZeebeExpressionVariables.PARTY_LOOKUP_FAILED; + +import com.fasterxml.jackson.databind.ObjectMapper; +import java.time.ZoneOffset; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; +import org.apache.camel.Exchange; +import org.apache.camel.LoggingLevel; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.model.dataformat.JsonLibrary; +import org.mifos.connector.common.gsma.dto.AccountBalanceResponseDTO; +import org.mifos.connector.common.gsma.dto.AccountNameResponseDTO; +import org.mifos.connector.common.gsma.dto.ErrorDTO; +import org.mifos.connector.gsma.auth.AccessTokenStore; +import org.mifos.connector.gsma.zeebe.ZeebeProcessStarter; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +@Component +@SuppressWarnings("checkstyle:whitespaceafter") +public class AccountRoutes extends RouteBuilder { + + @Autowired + private ZeebeProcessStarter zeebeProcessStarter; + + @Autowired + private ObjectMapper objectMapper; + + @Autowired + private AccessTokenStore accessTokenStore; + + @Value("${gsma.api.host}") + private String baseURL; + + @Value("${gsma.api.account}") + private String account; + + @Autowired + private AccountResponseProcessor accountResponseProcessor; + + private Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Override + public void configure() throws Exception { + + /** + * Error handling route + */ + from("direct:account-error").id("account-error").unmarshal().json(JsonLibrary.Jackson, ErrorDTO.class).process(exchange -> { + logger.error(exchange.getIn().getBody(ErrorDTO.class).toString()); + }).setProperty(PARTY_LOOKUP_FAILED, constant(true)).process(accountResponseProcessor); + + /** + * Route when account API call was successful + */ + from("direct:account-success").id("account-success").choice() + .when(exchange -> exchange.getProperty(ACCOUNT_ACTION, String.class).equals("status")) + .log(LoggingLevel.INFO, "Routing to account status handler").to("direct:account-status-handler") + .when(exchange -> exchange.getProperty(ACCOUNT_ACTION, String.class).equals("balance")) + .log(LoggingLevel.INFO, "Routing to account balance handler").to("direct:account-balance-handler") + .when(exchange -> exchange.getProperty(ACCOUNT_ACTION, String.class).equals("accountname")) + .log(LoggingLevel.INFO, "Routing to account name handler").to("direct:account-name-handler").otherwise() + .log(LoggingLevel.INFO, "No routing specified for this type of action.").endChoice(); + + /** + * Account balance response handler + */ + from("direct:account-balance-handler").id("account-balance-handler").unmarshal() + .json(JsonLibrary.Jackson, AccountBalanceResponseDTO.class).process(exchange -> { + exchange.setProperty(ACCOUNT_RESPONSE, exchange.getIn().getBody(AccountBalanceResponseDTO.class).getCurrentBalance()); + // TODO: Add extra processing as per use case + }); + + /** + * Account status response handler + */ + from("direct:account-status-handler").id("account-status-handler") + // .unmarshal().json(JsonLibrary.Jackson, AccountStatusResponseDTO.class) + .log(LoggingLevel.INFO, "Inside account status handler").setProperty(PARTY_LOOKUP_FAILED, constant(false)) + .process(accountResponseProcessor); + + /** + * Account name response handler + */ + from("direct:account-name-handler").id("account-name-handler").unmarshal().json(JsonLibrary.Jackson, AccountNameResponseDTO.class) + .process(exchange -> { + exchange.setProperty(ACCOUNT_RESPONSE, exchange.getIn().getBody(AccountNameResponseDTO.class).getName().getFullName()); + // TODO: Add extra processing as per use case + }); + + /** + * Route to call GSMA account status API + */ + from("direct:get-account-details").id("get-account-details").removeHeader("*").setHeader(Exchange.HTTP_METHOD, constant("GET")) + .setHeader("X-Date", simple(ZonedDateTime.now(ZoneOffset.UTC).format(DateTimeFormatter.ISO_INSTANT))) + .setHeader("Authorization", simple("Bearer ${exchangeProperty." + ACCESS_TOKEN + "}")) + .toD(baseURL + account + "/${exchangeProperty." + IDENTIFIER_TYPE + "}/${exchangeProperty." + IDENTIFIER + + "}/${exchangeProperty." + ACCOUNT_ACTION + "}?bridgeEndpoint=true&throwExceptionOnFailure=false"); // Bad + // URL + + /** + * Base route for accounts TODO: Add support for multiple identifier lookup + */ + from("direct:account-route").id("account-route") + .log(LoggingLevel.INFO, "Getting ${exchangeProperty." + ACCOUNT_ACTION + "} for Identifier") + // .to("direct:get-access-token") //Get rid of this + // .process(exchange -> exchange.setProperty(ACCESS_TOKEN, accessTokenStore.getAccessToken())) + .log(LoggingLevel.INFO, "Got access token, moving on to API call.") + // .to("direct:get-account-details") // Bad API call + .log(LoggingLevel.INFO, "Completed ${exchangeProperty." + ACCOUNT_ACTION + "} ${body}").choice() + .when(exchange -> exchange.getProperty(IS_API_CALL, String.class).equals("true")) + .log(LoggingLevel.INFO, "Setting off API response").otherwise().choice() + .when(header("CamelHttpResponseCode").isEqualTo("200")).to("direct:account-success").otherwise() + .to("direct:account-success") // Changing to test, OG: "direct:account-error" + .endChoice().endChoice(); + + /** + * Method to get account status + */ + from("rest:GET:/account/status/{identifier_type}/{identifier}").log(LoggingLevel.INFO, "Getting Account Status") + .process(exchange -> { + exchange.setProperty(IDENTIFIER_TYPE, exchange.getIn().getHeader("identifier_type")); + exchange.setProperty(IDENTIFIER, exchange.getIn().getHeader("identifier")); + exchange.setProperty(IS_API_CALL, "true"); + exchange.setProperty(ACCOUNT_ACTION, "status"); + }).to("direct:account-route"); + + /** + * Method to get account name + */ + from("rest:GET:/account/name/{identifier_type}/{identifier}").log(LoggingLevel.INFO, "Getting Account Name").process(exchange -> { + exchange.setProperty(IDENTIFIER_TYPE, exchange.getIn().getHeader("identifier_type")); + exchange.setProperty(IDENTIFIER, exchange.getIn().getHeader("identifier")); + exchange.setProperty(IS_API_CALL, "true"); + exchange.setProperty(ACCOUNT_ACTION, "accountname"); + }).to("direct:account-route"); + + /** + * Method to get account balance + */ + from("rest:GET:/account/balance/{identifier_type}/{identifier}").log(LoggingLevel.INFO, "Getting Account Balance") + .process(exchange -> { + exchange.setProperty(IDENTIFIER_TYPE, exchange.getIn().getHeader("identifier_type")); + exchange.setProperty(IDENTIFIER, exchange.getIn().getHeader("identifier")); + exchange.setProperty(IS_API_CALL, "true"); + exchange.setProperty(ACCOUNT_ACTION, "balance"); + }).to("direct:account-route"); + + /** + * Method to get account statement + */ + from("rest:GET:/account/statements/{identifier_type}/{identifier}").log(LoggingLevel.INFO, "Getting Account Statements") + .process(exchange -> { + exchange.setProperty(IDENTIFIER_TYPE, exchange.getIn().getHeader("identifier_type")); + exchange.setProperty(IDENTIFIER, exchange.getIn().getHeader("identifier")); + exchange.setProperty(IS_API_CALL, "true"); + exchange.setProperty(ACCOUNT_ACTION, "statemententries"); + }).to("direct:account-route"); + + /** + * Method to get account transactions + */ + from("rest:GET:/account/transactions/{identifier_type}/{identifier}").log(LoggingLevel.INFO, "Getting Account Transactions") + .process(exchange -> { + exchange.setProperty(IDENTIFIER_TYPE, exchange.getIn().getHeader("identifier_type")); + exchange.setProperty(IDENTIFIER, exchange.getIn().getHeader("identifier")); + exchange.setProperty(IS_API_CALL, "true"); + exchange.setProperty(ACCOUNT_ACTION, "transactions"); + }).to("direct:account-route"); + } +} diff --git a/ph-ee-connector-gsma-mm/src/main/java/org/mifos/connector/gsma/account/AccountWorkers.java b/ph-ee-connector-gsma-mm/src/main/java/org/mifos/connector/gsma/account/AccountWorkers.java new file mode 100644 index 000000000..7f585f7ca --- /dev/null +++ b/ph-ee-connector-gsma-mm/src/main/java/org/mifos/connector/gsma/account/AccountWorkers.java @@ -0,0 +1,76 @@ +package org.mifos.connector.gsma.account; + +import static org.mifos.connector.gsma.camel.config.CamelProperties.ACCOUNT_ACTION; +import static org.mifos.connector.gsma.camel.config.CamelProperties.CHANNEL_REQUEST; +import static org.mifos.connector.gsma.camel.config.CamelProperties.CORRELATION_ID; +import static org.mifos.connector.gsma.camel.config.CamelProperties.IDENTIFIER; +import static org.mifos.connector.gsma.camel.config.CamelProperties.IDENTIFIER_TYPE; +import static org.mifos.connector.gsma.camel.config.CamelProperties.IS_API_CALL; +import static org.mifos.connector.gsma.camel.config.CamelProperties.IS_RTP_REQUEST; +import static org.mifos.connector.gsma.zeebe.ZeebeExpressionVariables.PAYEE_LOOKUP_RETRY_COUNT; + +import com.fasterxml.jackson.databind.ObjectMapper; +import io.camunda.zeebe.client.ZeebeClient; +import java.util.Map; +import javax.annotation.PostConstruct; +import org.apache.camel.CamelContext; +import org.apache.camel.Exchange; +import org.apache.camel.ProducerTemplate; +import org.apache.camel.support.DefaultExchange; +import org.mifos.connector.common.channel.dto.TransactionChannelRequestDTO; +import org.mifos.connector.common.mojaloop.dto.PartyIdInfo; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +@Component +public class AccountWorkers { + + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Autowired + private ProducerTemplate producerTemplate; + + @Autowired + private CamelContext camelContext; + + @Autowired + private ZeebeClient zeebeClient; + + @Value("${zeebe.client.evenly-allocated-max-jobs}") + private int workerMaxJobs; + + @Autowired + private ObjectMapper objectMapper; + + @PostConstruct + public void setupWorkers() { + + zeebeClient.newWorker().jobType("checkAccountStatus").handler((client, job) -> { + logger.info("Job '{}' started from process '{}' with key {}", job.getType(), job.getBpmnProcessId(), job.getKey()); + Map variables = job.getVariablesAsMap(); + variables.put(PAYEE_LOOKUP_RETRY_COUNT, 1 + (Integer) variables.getOrDefault(PAYEE_LOOKUP_RETRY_COUNT, -1)); + + Exchange exchange = new DefaultExchange(camelContext); + exchange.setProperty(CORRELATION_ID, variables.get("transactionId")); + exchange.setProperty(CHANNEL_REQUEST, variables.get("channelRequest")); + exchange.setProperty(ACCOUNT_ACTION, "status"); + exchange.setProperty(IS_RTP_REQUEST, variables.get(IS_RTP_REQUEST)); + TransactionChannelRequestDTO channelRequest = objectMapper.readValue(exchange.getProperty(CHANNEL_REQUEST, String.class), + TransactionChannelRequestDTO.class); + PartyIdInfo requestedParty = exchange.getProperty(IS_RTP_REQUEST, Boolean.class) ? channelRequest.getPayer().getPartyIdInfo() + : channelRequest.getPayee().getPartyIdInfo(); + logger.info("Payee Tenant ID: {}", variables.get("payeeTenantId")); + exchange.setProperty(IDENTIFIER_TYPE, requestedParty.getPartyIdType().toString().toLowerCase()); + exchange.setProperty(IDENTIFIER, requestedParty.getPartyIdentifier()); + + exchange.setProperty(IS_API_CALL, "false"); + + producerTemplate.send("direct:account-route", exchange); + client.newCompleteCommand(job.getKey()).variables(variables).send().join(); + }).name("checkAccountStatus").maxJobsActive(workerMaxJobs).open(); + + } +} diff --git a/ph-ee-connector-gsma-mm/src/main/java/org/mifos/connector/gsma/account/AuthorizationCodeRoutes.java b/ph-ee-connector-gsma-mm/src/main/java/org/mifos/connector/gsma/account/AuthorizationCodeRoutes.java new file mode 100644 index 000000000..4abe14edd --- /dev/null +++ b/ph-ee-connector-gsma-mm/src/main/java/org/mifos/connector/gsma/account/AuthorizationCodeRoutes.java @@ -0,0 +1,83 @@ +package org.mifos.connector.gsma.account; + +import static org.mifos.connector.gsma.camel.config.CamelProperties.ACCESS_TOKEN; +import static org.mifos.connector.gsma.camel.config.CamelProperties.ACCOUNT_ACTION; +import static org.mifos.connector.gsma.camel.config.CamelProperties.IDENTIFIER; +import static org.mifos.connector.gsma.camel.config.CamelProperties.IDENTIFIER_TYPE; +import static org.mifos.connector.gsma.camel.config.CamelProperties.IS_API_CALL; + +import com.fasterxml.jackson.databind.ObjectMapper; +import java.time.ZoneOffset; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; +import org.apache.camel.Exchange; +import org.apache.camel.LoggingLevel; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.model.dataformat.JsonLibrary; +import org.mifos.connector.common.gsma.dto.AuthorizationCodeDTO; +import org.mifos.connector.gsma.auth.AccessTokenStore; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +@Component +public class AuthorizationCodeRoutes extends RouteBuilder { + + @Autowired + private ObjectMapper objectMapper; + + @Autowired + private AccessTokenStore accessTokenStore; + + @Value("${gsma.api.host}") + private String baseURL; + + @Value("${gsma.api.account}") + private String account; + + private Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Override + public void configure() throws Exception { + + /** + * BAse route for Authorization Code + */ + from("direct:authorization-code-route").id("authorization-code-route") + .log(LoggingLevel.INFO, "Getting ${exchangeProperty." + ACCOUNT_ACTION + "} for Identifier").to("direct:get-access-token") + .process(exchange -> exchange.setProperty(ACCESS_TOKEN, accessTokenStore.getAccessToken())) + .log(LoggingLevel.INFO, "Got access token, moving on to API call.").process(exchange -> { + AuthorizationCodeDTO authorizationCodeDTO = new AuthorizationCodeDTO(); + authorizationCodeDTO.setRequestDate(ZonedDateTime.now(ZoneOffset.UTC).format(DateTimeFormatter.ISO_INSTANT)); + + exchange.getIn().setBody(authorizationCodeDTO); + }).to("direct:get-authorization-code").choice().when(header("CamelHttpResponseCode").isEqualTo("201")) + .log(LoggingLevel.INFO, "Successful in creating authorization object: ${body}").process(exchange -> { + AuthorizationCodeDTO authorizationCodeResponse = objectMapper.readValue(exchange.getIn().getBody(String.class), + AuthorizationCodeDTO.class); + exchange.getIn().setBody(authorizationCodeResponse.getAuthorisationCode()); + }).otherwise().log(LoggingLevel.INFO, "Error in getting Authorization Code").endChoice(); + + /** + * POST call to GSMA + */ + from("direct:get-authorization-code").id("get-authorization-code").log(LoggingLevel.INFO, "Fetching authorization code") + .removeHeader("*").setHeader(Exchange.HTTP_METHOD, constant("POST")) + .setHeader("X-Date", simple(ZonedDateTime.now(ZoneOffset.UTC).format(DateTimeFormatter.ISO_INSTANT))) + .setHeader("Authorization", simple("Bearer ${exchangeProperty." + ACCESS_TOKEN + "}")).marshal().json(JsonLibrary.Jackson) + .toD(baseURL + account + "/${exchangeProperty." + IDENTIFIER_TYPE + "}/${exchangeProperty." + IDENTIFIER + + "}/authorisationcodes?bridgeEndpoint=true&throwExceptionOnFailure=false"); + + /** + * API to get Authorization Code + */ + from("rest:GET:/account/authcode/{identifier_type}/{identifier}").log(LoggingLevel.INFO, "Getting Authorization Code") + .process(exchange -> { + exchange.setProperty(IDENTIFIER_TYPE, exchange.getIn().getHeader("identifier_type")); + exchange.setProperty(IDENTIFIER, exchange.getIn().getHeader("identifier")); + exchange.setProperty(IS_API_CALL, "true"); + }).to("direct:authorization-code-route"); + } +} diff --git a/ph-ee-connector-gsma-mm/src/main/java/org/mifos/connector/gsma/account/BillsRoute.java b/ph-ee-connector-gsma-mm/src/main/java/org/mifos/connector/gsma/account/BillsRoute.java new file mode 100644 index 000000000..1592f7fa2 --- /dev/null +++ b/ph-ee-connector-gsma-mm/src/main/java/org/mifos/connector/gsma/account/BillsRoute.java @@ -0,0 +1,187 @@ +package org.mifos.connector.gsma.account; + +import static org.mifos.connector.gsma.camel.config.CamelProperties.ACCESS_TOKEN; +import static org.mifos.connector.gsma.camel.config.CamelProperties.BILLS; +import static org.mifos.connector.gsma.camel.config.CamelProperties.BILLS_ACTION; +import static org.mifos.connector.gsma.camel.config.CamelProperties.BILLS_CALL_FAILED; +import static org.mifos.connector.gsma.camel.config.CamelProperties.BILLS_REQUEST_BODY; +import static org.mifos.connector.gsma.camel.config.CamelProperties.BILL_COMPANIES; +import static org.mifos.connector.gsma.camel.config.CamelProperties.BILL_REFERENCE; +import static org.mifos.connector.gsma.camel.config.CamelProperties.CORRELATION_ID; +import static org.mifos.connector.gsma.camel.config.CamelProperties.ERROR_INFORMATION; +import static org.mifos.connector.gsma.camel.config.CamelProperties.IDENTIFIER; +import static org.mifos.connector.gsma.camel.config.CamelProperties.IDENTIFIER_TYPE; +import static org.mifos.connector.gsma.camel.config.CamelProperties.TRANSACTION_ID; +import static org.mifos.connector.gsma.zeebe.ZeebeExpressionVariables.TRANSACTION_FAILED; + +import com.fasterxml.jackson.databind.ObjectMapper; +import java.time.ZoneOffset; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; +import java.util.UUID; +import org.apache.camel.Exchange; +import org.apache.camel.LoggingLevel; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.model.dataformat.JsonLibrary; +import org.mifos.connector.common.channel.dto.TransactionChannelRequestDTO; +import org.mifos.connector.common.gsma.dto.BillPaymentDTO; +import org.mifos.connector.common.gsma.dto.ErrorDTO; +import org.mifos.connector.common.gsma.dto.RequestStateDTO; +import org.mifos.connector.gsma.auth.AccessTokenStore; +import org.mifos.connector.gsma.transfer.CorrelationIDStore; +import org.mifos.connector.gsma.transfer.TransferResponseProcessor; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +@Component +public class BillsRoute extends RouteBuilder { + + @Autowired + private CorrelationIDStore correlationIDStore; + + @Autowired + private ObjectMapper objectMapper; + + @Autowired + private AccessTokenStore accessTokenStore; + + @Value("${gsma.api.host}") + private String baseURL; + + @Value("${gsma.api.account}") + private String account; + + @Value("${camel.host}") + private String hostURL; + + @Autowired + private TransferResponseProcessor transferResponseProcessor; + + private Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Override + public void configure() throws Exception { + + /** + * Starter route for all bills actions + */ + from("direct:bills-route-base").id("bills-route-base") + .log(LoggingLevel.INFO, "Starting bills ${exchangeProperty." + BILLS_ACTION + "} for Identifier") + .to("direct:get-access-token").process(exchange -> exchange.setProperty(ACCESS_TOKEN, accessTokenStore.getAccessToken())) + .log(LoggingLevel.INFO, "Got access token, moving on to API call.").choice() + .when(exchange -> exchange.getProperty(BILLS_ACTION, String.class).equals("companies")).to("direct:get-bills-companies") + .log(LoggingLevel.INFO, "Bill Companies API response: ${body}").choice() + .when(header("CamelHttpResponseCode").isEqualTo("200")).process(exchange -> { + exchange.setProperty(BILLS_CALL_FAILED, false); + exchange.setProperty(BILL_COMPANIES, exchange.getIn().getBody(String.class)); + }).otherwise().to("direct:bills-error-handler").endChoice() + .when(exchange -> exchange.getProperty(BILLS_ACTION, String.class).equals("bills")).to("direct:get-bills") + .log(LoggingLevel.INFO, "Bills API response: ${body}").choice().when(header("CamelHttpResponseCode").isEqualTo("200")) + .process(exchange -> { + exchange.setProperty(BILLS_CALL_FAILED, false); + exchange.setProperty(BILLS, exchange.getIn().getBody(String.class)); + }).otherwise().to("direct:bills-error-handler").endChoice() + .when(exchange -> exchange.getProperty(BILLS_ACTION, String.class).equals("payment")).to("direct:bills-payment") + .log(LoggingLevel.INFO, "Transaction API response: ${body}").to("direct:transaction-response-handler").otherwise() + .log(LoggingLevel.INFO, "No suitable bill action found").end(); + + /** + * Bills error handler + */ + from("direct:bills-error-handler").id("bills-error-handler").log(LoggingLevel.INFO, "Error in bills request").unmarshal() + .json(JsonLibrary.Jackson, ErrorDTO.class).process(exchange -> { + exchange.setProperty(BILLS_CALL_FAILED, true); + exchange.setProperty(ERROR_INFORMATION, exchange.getIn().getBody(ErrorDTO.class).toString()); + }); + + /** + * API call to get bill companies for an account + */ + from("direct:get-bills-companies").id("get-bills-companies").removeHeader("*").setHeader(Exchange.HTTP_METHOD, constant("GET")) + .setHeader("X-Date", simple(ZonedDateTime.now(ZoneOffset.UTC).format(DateTimeFormatter.ISO_INSTANT))) + .setHeader("Authorization", simple("Bearer ${exchangeProperty." + ACCESS_TOKEN + "}")) + .toD(baseURL + account + "/${exchangeProperty." + IDENTIFIER_TYPE + "}/${exchangeProperty." + IDENTIFIER + "}" + + "/billcompanies" + "?bridgeEndpoint=true&throwExceptionOnFailure=false"); + + /** + * API call to get bills for an account + */ + from("direct:get-bills").id("get-bills").removeHeader("*").setHeader(Exchange.HTTP_METHOD, constant("GET")) + .setHeader("X-Date", simple(ZonedDateTime.now(ZoneOffset.UTC).format(DateTimeFormatter.ISO_INSTANT))) + .setHeader("Authorization", simple("Bearer ${exchangeProperty." + ACCESS_TOKEN + "}")) + .toD(baseURL + account + "/${exchangeProperty." + IDENTIFIER_TYPE + "}/${exchangeProperty." + IDENTIFIER + "}" + "/bills" + + "?bridgeEndpoint=true&throwExceptionOnFailure=false"); + + /** + * API call to initiate payment for bill + */ + from("direct:bills-payment").id("bills-payment").removeHeader("*").setHeader(Exchange.HTTP_METHOD, constant("POST")) + .setHeader("X-Date", simple(ZonedDateTime.now(ZoneOffset.UTC).format(DateTimeFormatter.ISO_INSTANT))) + .setHeader("Authorization", simple("Bearer ${exchangeProperty." + ACCESS_TOKEN + "}")) + .setHeader("X-Callback-URL", simple(hostURL + "/bills/payment/callback")) + .setHeader("X-CorrelationID", simple("${exchangeProperty." + CORRELATION_ID + "}")) + .setHeader("Content-Type", constant("application/json")).setBody(exchange -> exchange.getProperty(BILLS_REQUEST_BODY)) + .marshal().json(JsonLibrary.Jackson).log(LoggingLevel.INFO, "Links Request Body: ${body}") + .toD(baseURL + account + "/${exchangeProperty." + IDENTIFIER_TYPE + "}/${exchangeProperty." + IDENTIFIER + + "}/bills/${exchangeProperty." + BILL_REFERENCE + "}/payments?bridgeEndpoint=true&throwExceptionOnFailure=false"); + + /** + * Callback for bill payment + */ + from("rest:PUT:/bills/payment/callback").log(LoggingLevel.INFO, "Callback body ${body}").unmarshal() + .json(JsonLibrary.Jackson, RequestStateDTO.class).process(exchange -> { + String serverUUID = exchange.getIn().getBody(RequestStateDTO.class).getServerCorrelationId(); + exchange.setProperty(TRANSACTION_ID, correlationIDStore.getClientCorrelation(serverUUID)); + }).choice().when(exchange -> exchange.getIn().getBody(RequestStateDTO.class).getStatus().equals("completed")) + .setProperty(TRANSACTION_FAILED, constant(false)).otherwise() + .process(exchange -> exchange.setProperty(ERROR_INFORMATION, + exchange.getIn().getBody(RequestStateDTO.class).getError().getErrorDescription())) + .setProperty(TRANSACTION_FAILED, constant(true)).end().process(transferResponseProcessor); + + /** + * API to initiate bill payment + */ + from("rest:POST:/bills/payment").log(LoggingLevel.INFO, "Got bill payment POST request").process(exchange -> { + + exchange.setProperty(BILLS_ACTION, "payment"); + + TransactionChannelRequestDTO channelRequest = objectMapper.readValue(exchange.getIn().getBody(String.class), + TransactionChannelRequestDTO.class); + exchange.setProperty(BILL_REFERENCE, channelRequest.getPayee().getPartyIdInfo().getPartyIdentifier()); + exchange.setProperty(IDENTIFIER_TYPE, channelRequest.getPayer().getPartyIdInfo().getPartyIdType()); + exchange.setProperty(IDENTIFIER, channelRequest.getPayer().getPartyIdInfo().getPartyIdentifier()); + + BillPaymentDTO paymentDTO = new BillPaymentDTO(); + + paymentDTO.setAmountPaid(channelRequest.getAmount().getAmount()); + paymentDTO.setCurrency(channelRequest.getAmount().getCurrency()); + + exchange.setProperty(BILLS_REQUEST_BODY, paymentDTO); + exchange.setProperty(CORRELATION_ID, UUID.randomUUID()); + }).to("direct:bills-route-base"); + + /** + * API to get bills for an account + */ + from("rest:GET:/account/bills/{identifier_type}/{identifier}").log(LoggingLevel.INFO, "Getting Account Bills").process(exchange -> { + exchange.setProperty(IDENTIFIER_TYPE, exchange.getIn().getHeader("identifier_type")); + exchange.setProperty(IDENTIFIER, exchange.getIn().getHeader("identifier")); + exchange.setProperty(BILLS_ACTION, "bills"); + }).to("direct:bills-route-base").setBody(exchange -> exchange.getProperty(BILLS, String.class)); + + /** + * API to get bill companies associated with an account + */ + from("rest:GET:/account/billcompanies/{identifier_type}/{identifier}").log(LoggingLevel.INFO, "Getting Account Status") + .process(exchange -> { + exchange.setProperty(IDENTIFIER_TYPE, exchange.getIn().getHeader("identifier_type")); + exchange.setProperty(IDENTIFIER, exchange.getIn().getHeader("identifier")); + exchange.setProperty(BILLS_ACTION, "companies"); + }).to("direct:bills-route-base").setBody(exchange -> exchange.getProperty(BILL_COMPANIES, String.class)); + + } + +} diff --git a/ph-ee-connector-gsma-mm/src/main/java/org/mifos/connector/gsma/account/BillsWorkers.java b/ph-ee-connector-gsma-mm/src/main/java/org/mifos/connector/gsma/account/BillsWorkers.java new file mode 100644 index 000000000..6134a06e8 --- /dev/null +++ b/ph-ee-connector-gsma-mm/src/main/java/org/mifos/connector/gsma/account/BillsWorkers.java @@ -0,0 +1,127 @@ +package org.mifos.connector.gsma.account; + +import static org.mifos.connector.gsma.camel.config.CamelProperties.BILLS; +import static org.mifos.connector.gsma.camel.config.CamelProperties.BILLS_ACTION; +import static org.mifos.connector.gsma.camel.config.CamelProperties.BILLS_CALL_FAILED; +import static org.mifos.connector.gsma.camel.config.CamelProperties.BILLS_REQUEST_BODY; +import static org.mifos.connector.gsma.camel.config.CamelProperties.BILL_REFERENCE; +import static org.mifos.connector.gsma.camel.config.CamelProperties.CHANNEL_REQUEST; +import static org.mifos.connector.gsma.camel.config.CamelProperties.CORRELATION_ID; +import static org.mifos.connector.gsma.camel.config.CamelProperties.ERROR_INFORMATION; +import static org.mifos.connector.gsma.camel.config.CamelProperties.IDENTIFIER; +import static org.mifos.connector.gsma.camel.config.CamelProperties.IDENTIFIER_TYPE; +import static org.mifos.connector.gsma.zeebe.ZeebeExpressionVariables.BILLS_STATUS_ERROR; + +import com.fasterxml.jackson.databind.ObjectMapper; +import io.camunda.zeebe.client.ZeebeClient; +import java.util.Map; +import javax.annotation.PostConstruct; +import org.apache.camel.CamelContext; +import org.apache.camel.Exchange; +import org.apache.camel.ProducerTemplate; +import org.apache.camel.support.DefaultExchange; +import org.mifos.connector.common.channel.dto.TransactionChannelRequestDTO; +import org.mifos.connector.common.gsma.dto.Bill; +import org.mifos.connector.common.gsma.dto.BillPaymentDTO; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +@Component +public class BillsWorkers { + + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Autowired + private ZeebeClient zeebeClient; + + @Autowired + private ProducerTemplate producerTemplate; + + @Autowired + private CamelContext camelContext; + + @Autowired + private ObjectMapper objectMapper; + + @Value("${zeebe.client.evenly-allocated-max-jobs}") + private int workerMaxJobs; + + @PostConstruct + public void setupWorkers() { + + zeebeClient.newWorker().jobType("billsPayment").handler((client, job) -> { + logger.info("Job '{}' started from process '{}' with key {}", job.getType(), job.getBpmnProcessId(), job.getKey()); + Map variables = job.getVariablesAsMap(); + + Exchange exchange = new DefaultExchange(camelContext); + exchange.setProperty(CORRELATION_ID, variables.get("transactionId")); + exchange.setProperty(CHANNEL_REQUEST, variables.get("channelRequest")); + + exchange.setProperty(BILLS_ACTION, "payment"); + + TransactionChannelRequestDTO channelRequest = objectMapper.readValue(exchange.getProperty(CHANNEL_REQUEST, String.class), + TransactionChannelRequestDTO.class); + exchange.setProperty(BILL_REFERENCE, channelRequest.getPayee().getPartyIdInfo().getPartyIdentifier()); + exchange.setProperty(IDENTIFIER_TYPE, channelRequest.getPayer().getPartyIdInfo().getPartyIdType()); + exchange.setProperty(IDENTIFIER, channelRequest.getPayer().getPartyIdInfo().getPartyIdentifier()); + + BillPaymentDTO paymentDTO = new BillPaymentDTO(); + + paymentDTO.setAmountPaid(channelRequest.getAmount().getAmount()); + paymentDTO.setCurrency(channelRequest.getAmount().getCurrency()); + + exchange.setProperty(BILLS_REQUEST_BODY, paymentDTO); + + producerTemplate.send("direct:bills-route-base", exchange); + + client.newCompleteCommand(job.getKey()).variables(variables).send().join(); + }).name("billsPayment").maxJobsActive(workerMaxJobs).open(); + + zeebeClient.newWorker().jobType("validateBill").handler((client, job) -> { + logger.info("Job '{}' started from process '{}' with key {}", job.getType(), job.getBpmnProcessId(), job.getKey()); + Map variables = job.getVariablesAsMap(); + + Exchange exchange = new DefaultExchange(camelContext); + exchange.setProperty(CORRELATION_ID, variables.get("transactionId")); + exchange.setProperty(CHANNEL_REQUEST, variables.get("channelRequest")); + + exchange.setProperty(BILLS_ACTION, "bills"); + + TransactionChannelRequestDTO channelRequest = objectMapper.readValue(exchange.getProperty(CHANNEL_REQUEST, String.class), + TransactionChannelRequestDTO.class); + exchange.setProperty(BILL_REFERENCE, channelRequest.getPayee().getPartyIdInfo().getPartyIdentifier()); + exchange.setProperty(IDENTIFIER_TYPE, channelRequest.getPayer().getPartyIdInfo().getPartyIdType()); + exchange.setProperty(IDENTIFIER, channelRequest.getPayer().getPartyIdInfo().getPartyIdentifier()); + + producerTemplate.send("direct:bills-route-base", exchange); + + if (!exchange.getProperty(BILLS_CALL_FAILED, Boolean.class)) { + Bill[] bills = objectMapper.readValue(exchange.getProperty(BILLS, String.class), Bill[].class); + boolean billPresent = false; + + for (Bill bill : bills) { + if (bill.getBillReference().equals(exchange.getProperty(BILL_REFERENCE))) { + billPresent = true; + break; + } + } + + if (billPresent) { + variables.put(BILLS_STATUS_ERROR, false); + } else { + variables.put(BILLS_STATUS_ERROR, true); + variables.put(ERROR_INFORMATION, "Bill Reference not present in account."); + } + } else { + variables.put(BILLS_STATUS_ERROR, true); + variables.put(ERROR_INFORMATION, exchange.getProperty(ERROR_INFORMATION, String.class)); + } + + client.newCompleteCommand(job.getKey()).variables(variables).send().join(); + }).name("validateBill").maxJobsActive(workerMaxJobs).open(); + } + +} diff --git a/ph-ee-connector-gsma-mm/src/main/java/org/mifos/connector/gsma/account/DebitMandateRoute.java b/ph-ee-connector-gsma-mm/src/main/java/org/mifos/connector/gsma/account/DebitMandateRoute.java new file mode 100644 index 000000000..0ea426dd5 --- /dev/null +++ b/ph-ee-connector-gsma-mm/src/main/java/org/mifos/connector/gsma/account/DebitMandateRoute.java @@ -0,0 +1,105 @@ +package org.mifos.connector.gsma.account; + +import static org.mifos.connector.gsma.camel.config.CamelProperties.ACCESS_TOKEN; +import static org.mifos.connector.gsma.camel.config.CamelProperties.DEBIT_MANDATE_BODY; +import static org.mifos.connector.gsma.camel.config.CamelProperties.ERROR_INFORMATION; +import static org.mifos.connector.gsma.camel.config.CamelProperties.IDENTIFIER; +import static org.mifos.connector.gsma.camel.config.CamelProperties.IDENTIFIER_TYPE; +import static org.mifos.connector.gsma.camel.config.CamelProperties.MANDATE_CREATE_FAILED; +import static org.mifos.connector.gsma.camel.config.CamelProperties.MANDATE_REFERENCE; + +import com.fasterxml.jackson.databind.ObjectMapper; +import java.time.ZoneOffset; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; +import org.apache.camel.Exchange; +import org.apache.camel.LoggingLevel; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.model.dataformat.JsonLibrary; +import org.mifos.connector.common.channel.dto.TransactionChannelRequestDTO; +import org.mifos.connector.common.gsma.dto.DebitMandateDTO; +import org.mifos.connector.common.gsma.dto.ErrorDTO; +import org.mifos.connector.gsma.auth.AccessTokenStore; +import org.mifos.connector.gsma.transfer.CorrelationIDStore; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +@Component +public class DebitMandateRoute extends RouteBuilder { + + @Autowired + private ObjectMapper objectMapper; + + @Autowired + private AccessTokenStore accessTokenStore; + + @Autowired + private CorrelationIDStore correlationIDStore; + + @Value("${gsma.api.host}") + private String baseURL; + + @Value("${gsma.api.account}") + private String account; + + private Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Override + public void configure() throws Exception { + + /** + * Base Route for debit mandate + */ + from("direct:debit-mandate-base").id("debit-mandate-base").log(LoggingLevel.INFO, "Debit Mandate route started") + .to("direct:get-access-token").process(exchange -> exchange.setProperty(ACCESS_TOKEN, accessTokenStore.getAccessToken())) + .log(LoggingLevel.INFO, "Got access token, moving on.") + // TODO: Create request body + .to("direct:create-debit-mandate").log(LoggingLevel.INFO, "Debit Mandate Response: ${body}").choice() + .when(header("CamelHttpResponseCode").isEqualTo("201")).log(LoggingLevel.INFO, "Mandate creation request successful") + .unmarshal().json(JsonLibrary.Jackson, DebitMandateDTO.class).process(exchange -> { + exchange.setProperty(MANDATE_CREATE_FAILED, false); + exchange.setProperty(MANDATE_REFERENCE, exchange.getIn().getBody(DebitMandateDTO.class).getMandateReference()); + }).otherwise().log(LoggingLevel.INFO, "Mandate creation failed").unmarshal().json(JsonLibrary.Jackson, ErrorDTO.class) + .process(exchange -> { + exchange.setProperty(MANDATE_CREATE_FAILED, true); + exchange.setProperty(ERROR_INFORMATION, exchange.getIn().getBody(ErrorDTO.class).getErrorCode()); + }).endChoice(); + + /** + * Calling API for debit mandate + */ + from("direct:create-debit-mandate").id("create-debit-mandate").removeHeader("*").setHeader(Exchange.HTTP_METHOD, constant("POST")) + .setHeader("X-Date", simple(ZonedDateTime.now(ZoneOffset.UTC).format(DateTimeFormatter.ISO_INSTANT))) + .setHeader("Authorization", simple("Bearer ${exchangeProperty." + ACCESS_TOKEN + "}")) + .setHeader("Content-Type", constant("application/json")).setBody(exchange -> exchange.getProperty(DEBIT_MANDATE_BODY)) + .marshal().json(JsonLibrary.Jackson).log(LoggingLevel.INFO, "Debit Mandate Request Body: ${body}") + .toD(baseURL + account + "/${exchangeProperty." + IDENTIFIER_TYPE + "}/${exchangeProperty." + IDENTIFIER + + "}/debitmandates?bridgeEndpoint=true&throwExceptionOnFailure=false"); + + /** + * API to create debit mandate + */ + from("rest:POST:/account/debitmandate/{identifier_type}/{identifier}").log(LoggingLevel.INFO, "Creating Debit Mandate") + .process(exchange -> { + exchange.setProperty(IDENTIFIER_TYPE, exchange.getIn().getHeader("identifier_type")); + exchange.setProperty(IDENTIFIER, exchange.getIn().getHeader("identifier")); + + TransactionChannelRequestDTO channelRequest = objectMapper.readValue(exchange.getIn().getBody(String.class), + TransactionChannelRequestDTO.class); + + DebitMandateDTO debitMandateRequest = new DebitMandateDTO(); + + debitMandateRequest.setRequestDate(ZonedDateTime.now(ZoneOffset.UTC).format(DateTimeFormatter.ISO_INSTANT)); + debitMandateRequest.setStartDate(ZonedDateTime.now(ZoneOffset.UTC).format(DateTimeFormatter.ISO_INSTANT)); + debitMandateRequest.setAmountLimit(channelRequest.getAmount().getAmount()); + debitMandateRequest.setCurrency(channelRequest.getAmount().getCurrency()); + debitMandateRequest.setNumberOfPayments(10); + + exchange.setProperty(DEBIT_MANDATE_BODY, debitMandateRequest); + }).to("direct:debit-mandate-base").setBody(simple("${exchangeProperty." + MANDATE_REFERENCE + "}")); + + } +} diff --git a/ph-ee-connector-gsma-mm/src/main/java/org/mifos/connector/gsma/account/DebitMandateWorkers.java b/ph-ee-connector-gsma-mm/src/main/java/org/mifos/connector/gsma/account/DebitMandateWorkers.java new file mode 100644 index 000000000..ce86db64b --- /dev/null +++ b/ph-ee-connector-gsma-mm/src/main/java/org/mifos/connector/gsma/account/DebitMandateWorkers.java @@ -0,0 +1,92 @@ +package org.mifos.connector.gsma.account; + +import static org.mifos.connector.gsma.camel.config.CamelProperties.CHANNEL_REQUEST; +import static org.mifos.connector.gsma.camel.config.CamelProperties.DEBIT_MANDATE_BODY; +import static org.mifos.connector.gsma.camel.config.CamelProperties.ERROR_INFORMATION; +import static org.mifos.connector.gsma.camel.config.CamelProperties.IDENTIFIER; +import static org.mifos.connector.gsma.camel.config.CamelProperties.IDENTIFIER_TYPE; +import static org.mifos.connector.gsma.camel.config.CamelProperties.MANDATE_CREATE_FAILED; +import static org.mifos.connector.gsma.camel.config.CamelProperties.MANDATE_REFERENCE; +import static org.mifos.connector.gsma.zeebe.ZeebeExpressionVariables.NUMBER_OF_PAYMENTS; + +import com.fasterxml.jackson.databind.ObjectMapper; +import io.camunda.zeebe.client.ZeebeClient; +import java.time.ZoneOffset; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; +import java.util.Map; +import javax.annotation.PostConstruct; +import org.apache.camel.CamelContext; +import org.apache.camel.Exchange; +import org.apache.camel.ProducerTemplate; +import org.apache.camel.support.DefaultExchange; +import org.mifos.connector.common.channel.dto.TransactionChannelRequestDTO; +import org.mifos.connector.common.gsma.dto.DebitMandateDTO; +import org.mifos.connector.common.mojaloop.dto.PartyIdInfo; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +@Component +public class DebitMandateWorkers { + + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Autowired + private ProducerTemplate producerTemplate; + + @Autowired + private CamelContext camelContext; + + @Autowired + private ZeebeClient zeebeClient; + + @Value("${zeebe.client.evenly-allocated-max-jobs}") + private int workerMaxJobs; + + @Autowired + private ObjectMapper objectMapper; + + @PostConstruct + public void setupWorkers() { + + zeebeClient.newWorker().jobType("createDebitMandate").handler((client, job) -> { + logger.info("Job '{}' started from process '{}' with key {}", job.getType(), job.getBpmnProcessId(), job.getKey()); + Map variables = job.getVariablesAsMap(); + + Exchange exchange = new DefaultExchange(camelContext); + exchange.setProperty(CHANNEL_REQUEST, variables.get("channelRequest")); + + TransactionChannelRequestDTO channelRequest = objectMapper.readValue(exchange.getProperty(CHANNEL_REQUEST, String.class), + TransactionChannelRequestDTO.class); + PartyIdInfo payerParty = channelRequest.getPayer().getPartyIdInfo(); + exchange.setProperty(IDENTIFIER_TYPE, payerParty.getPartyIdType().toString().toLowerCase()); + exchange.setProperty(IDENTIFIER, payerParty.getPartyIdentifier()); + + DebitMandateDTO debitMandateRequest = new DebitMandateDTO(); + + debitMandateRequest.setRequestDate(ZonedDateTime.now(ZoneOffset.UTC).format(DateTimeFormatter.ISO_INSTANT)); + debitMandateRequest.setStartDate(ZonedDateTime.now(ZoneOffset.UTC).format(DateTimeFormatter.ISO_INSTANT)); + debitMandateRequest.setAmountLimit(channelRequest.getAmount().getAmount()); + debitMandateRequest.setCurrency(channelRequest.getAmount().getCurrency()); + debitMandateRequest.setNumberOfPayments((Integer) variables.getOrDefault(NUMBER_OF_PAYMENTS, 10)); + + exchange.setProperty(DEBIT_MANDATE_BODY, debitMandateRequest); + + producerTemplate.send("direct:debit-mandate-base", exchange); + + variables.put(MANDATE_CREATE_FAILED, exchange.getProperty(MANDATE_CREATE_FAILED, Boolean.class)); + + if (exchange.getProperty(MANDATE_CREATE_FAILED, Boolean.class)) { + variables.put(ERROR_INFORMATION, exchange.getProperty(ERROR_INFORMATION, String.class)); + } else { + variables.put(MANDATE_REFERENCE, exchange.getProperty(MANDATE_REFERENCE, String.class)); + } + + client.newCompleteCommand(job.getKey()).variables(variables).send().join(); + }).name("createDebitMandate").maxJobsActive(workerMaxJobs).open(); + + } +} diff --git a/ph-ee-connector-gsma-mm/src/main/java/org/mifos/connector/gsma/account/LinksResponseProcessor.java b/ph-ee-connector-gsma-mm/src/main/java/org/mifos/connector/gsma/account/LinksResponseProcessor.java new file mode 100644 index 000000000..ce454ff25 --- /dev/null +++ b/ph-ee-connector-gsma-mm/src/main/java/org/mifos/connector/gsma/account/LinksResponseProcessor.java @@ -0,0 +1,57 @@ +package org.mifos.connector.gsma.account; + +import static org.mifos.connector.gsma.camel.config.CamelProperties.CORRELATION_ID; +import static org.mifos.connector.gsma.camel.config.CamelProperties.ERROR_INFORMATION; +import static org.mifos.connector.gsma.camel.config.CamelProperties.LINK_REFERENCE; +import static org.mifos.connector.gsma.zeebe.ZeebeExpressionVariables.LINK_CREATE_FAILED; +import static org.mifos.connector.gsma.zeebe.ZeebeMessages.LINK_RESPONSE; + +import io.camunda.zeebe.client.ZeebeClient; +import java.time.Duration; +import java.util.HashMap; +import java.util.Map; +import org.apache.camel.Exchange; +import org.apache.camel.Processor; +import org.mifos.connector.gsma.transfer.CorrelationIDStore; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +@Component +public class LinksResponseProcessor implements Processor { + + @Autowired + private ZeebeClient zeebeClient; + + @Autowired + private CorrelationIDStore correlationIDStore; + + private Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Value("${zeebe.client.ttl}") + private int timeToLive; + + @Override + public void process(Exchange exchange) throws Exception { + + Map variables = new HashMap<>(); + + Object didLinkCreateFail = exchange.getProperty(LINK_CREATE_FAILED); + if (didLinkCreateFail != null && (boolean) didLinkCreateFail) { + variables.put(ERROR_INFORMATION, exchange.getProperty(ERROR_INFORMATION, String.class)); + variables.put(LINK_CREATE_FAILED, true); + } else { + variables.put(LINK_REFERENCE, exchange.getProperty(LINK_REFERENCE, String.class)); + variables.put(LINK_CREATE_FAILED, false); + } + + String transactionID = correlationIDStore.getClientCorrelation(exchange.getProperty(CORRELATION_ID, String.class)); + + logger.info("Publishing link response message variables: " + variables); + + zeebeClient.newPublishMessageCommand().messageName(LINK_RESPONSE).correlationKey(transactionID) + .timeToLive(Duration.ofMillis(timeToLive)).variables(variables).send().join(); + } +} diff --git a/ph-ee-connector-gsma-mm/src/main/java/org/mifos/connector/gsma/account/LinksRoute.java b/ph-ee-connector-gsma-mm/src/main/java/org/mifos/connector/gsma/account/LinksRoute.java new file mode 100644 index 000000000..892b61d92 --- /dev/null +++ b/ph-ee-connector-gsma-mm/src/main/java/org/mifos/connector/gsma/account/LinksRoute.java @@ -0,0 +1,165 @@ +package org.mifos.connector.gsma.account; + +import static org.mifos.connector.gsma.camel.config.CamelProperties.ACCESS_TOKEN; +import static org.mifos.connector.gsma.camel.config.CamelProperties.ACCOUNT_ACTION; +import static org.mifos.connector.gsma.camel.config.CamelProperties.CHANNEL_REQUEST; +import static org.mifos.connector.gsma.camel.config.CamelProperties.CORRELATION_ID; +import static org.mifos.connector.gsma.camel.config.CamelProperties.ERROR_INFORMATION; +import static org.mifos.connector.gsma.camel.config.CamelProperties.IDENTIFIER; +import static org.mifos.connector.gsma.camel.config.CamelProperties.IDENTIFIER_TYPE; +import static org.mifos.connector.gsma.camel.config.CamelProperties.IS_RTP_REQUEST; +import static org.mifos.connector.gsma.camel.config.CamelProperties.LINKS_REQUEST_BODY; +import static org.mifos.connector.gsma.camel.config.CamelProperties.LINK_REFERENCE; +import static org.mifos.connector.gsma.camel.config.CamelProperties.RESPONSE_OBJECT; +import static org.mifos.connector.gsma.camel.config.CamelProperties.RESPONSE_OBJECT_AVAILABLE; +import static org.mifos.connector.gsma.camel.config.CamelProperties.RESPONSE_OBJECT_TYPE; +import static org.mifos.connector.gsma.zeebe.ZeebeExpressionVariables.LINK_CREATE_FAILED; + +import com.fasterxml.jackson.databind.ObjectMapper; +import java.time.ZoneOffset; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; +import java.util.UUID; +import org.apache.camel.Exchange; +import org.apache.camel.LoggingLevel; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.model.dataformat.JsonLibrary; +import org.mifos.connector.common.channel.dto.TransactionChannelRequestDTO; +import org.mifos.connector.common.gsma.dto.ErrorDTO; +import org.mifos.connector.common.gsma.dto.GsmaParty; +import org.mifos.connector.common.gsma.dto.LinksDTO; +import org.mifos.connector.common.gsma.dto.RequestStateDTO; +import org.mifos.connector.common.mojaloop.dto.PartyIdInfo; +import org.mifos.connector.gsma.auth.AccessTokenStore; +import org.mifos.connector.gsma.transfer.CorrelationIDStore; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +@Component +public class LinksRoute extends RouteBuilder { + + @Autowired + private ObjectMapper objectMapper; + + @Autowired + private AccessTokenStore accessTokenStore; + + @Autowired + private CorrelationIDStore correlationIDStore; + + @Autowired + private LinksResponseProcessor linksResponseProcessor; + + @Value("${gsma.api.host}") + private String baseURL; + + @Value("${camel.host}") + private String hostURL; + + @Value("${gsma.api.account}") + private String account; + + private Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Override + public void configure() throws Exception { + + /** + * Base route to create link + */ + from("direct:links-route").id("links-route") + .log(LoggingLevel.INFO, "Creating ${exchangeProperty." + ACCOUNT_ACTION + "} for Identifier").to("direct:get-access-token") + .process(exchange -> exchange.setProperty(ACCESS_TOKEN, accessTokenStore.getAccessToken())) + .log(LoggingLevel.INFO, "Got access token, moving on to API call.").to("direct:create-link-async") + .log(LoggingLevel.INFO, "Transaction API response: ${body}").choice().when(header("CamelHttpResponseCode").isEqualTo("202")) + .log(LoggingLevel.INFO, "Link request successful").unmarshal().json(JsonLibrary.Jackson, RequestStateDTO.class) + .process(exchange -> { + correlationIDStore.addMapping(exchange.getIn().getBody(RequestStateDTO.class).getServerCorrelationId(), + exchange.getProperty(CORRELATION_ID, String.class)); + logger.info("Saved correlationId mapping"); + }).otherwise().log(LoggingLevel.ERROR, "Link request unsuccessful").unmarshal().json(JsonLibrary.Jackson, ErrorDTO.class) + .process(exchange -> { + exchange.setProperty(LINK_CREATE_FAILED, true); + exchange.setProperty(ERROR_INFORMATION, exchange.getIn().getBody(ErrorDTO.class).getErrorDescription()); + }).process(linksResponseProcessor).endChoice(); + + /** + * Async call to Links API + */ + from("direct:create-link-async").id("create-link-async").removeHeader("*").setHeader(Exchange.HTTP_METHOD, constant("POST")) + .setHeader("X-Date", simple(ZonedDateTime.now(ZoneOffset.UTC).format(DateTimeFormatter.ISO_INSTANT))) + .setHeader("Authorization", simple("Bearer ${exchangeProperty." + ACCESS_TOKEN + "}")) + .setHeader("X-Callback-URL", simple(hostURL + "/links/callback")) + .setHeader("X-CorrelationID", simple("${exchangeProperty." + CORRELATION_ID + "}")) + .setHeader("Content-Type", constant("application/json")).setBody(exchange -> exchange.getProperty(LINKS_REQUEST_BODY)) + .marshal().json(JsonLibrary.Jackson).log(LoggingLevel.INFO, "Links Request Body: ${body}") + .toD(baseURL + account + "/${exchangeProperty." + IDENTIFIER_TYPE + "}/${exchangeProperty." + IDENTIFIER + + "}/links?bridgeEndpoint=true&throwExceptionOnFailure=false"); + + /** + * Sync call to Links API + */ + from("direct:create-link").id("create-link").removeHeader("*").setHeader(Exchange.HTTP_METHOD, constant("POST")) + .setHeader("X-Date", simple(ZonedDateTime.now(ZoneOffset.UTC).format(DateTimeFormatter.ISO_INSTANT))) + .setHeader("Authorization", simple("Bearer ${exchangeProperty." + ACCESS_TOKEN + "}")) + .setHeader("Content-Type", constant("application/json")).setBody(exchange -> exchange.getProperty(LINKS_REQUEST_BODY)) + .marshal().json(JsonLibrary.Jackson).log(LoggingLevel.INFO, "Links Request Body: ${body}") + .toD(baseURL + account + "/${exchangeProperty." + IDENTIFIER_TYPE + "}/${exchangeProperty." + IDENTIFIER + + "}/links?bridgeEndpoint=true&throwExceptionOnFailure=false"); + + /** + * Links API callback + */ + from("rest:PUT:/links/callback").log(LoggingLevel.INFO, "Callback body ${body}").unmarshal() + .json(JsonLibrary.Jackson, RequestStateDTO.class).process(exchange -> { + String serverUUID = exchange.getIn().getBody(RequestStateDTO.class).getServerCorrelationId(); + exchange.setProperty(CORRELATION_ID, correlationIDStore.getClientCorrelation(serverUUID)); + }).choice().when(exchange -> exchange.getIn().getBody(RequestStateDTO.class).getStatus().equals("completed")) + .setProperty(LINK_CREATE_FAILED, constant(false)).setProperty(RESPONSE_OBJECT_TYPE, constant("links")) + .to("direct:response-route").choice().when(exchange -> exchange.getProperty(RESPONSE_OBJECT_AVAILABLE, Boolean.class)) + .process(exchange -> { + String linkref = exchange.getProperty(RESPONSE_OBJECT, LinksDTO.class).getLinkReference(); + exchange.setProperty(LINK_REFERENCE, linkref); + }).log(LoggingLevel.INFO, "Link reference is: ${exchangeProperty." + LINK_REFERENCE + "}").otherwise() + .setProperty(ERROR_INFORMATION, simple("Error in getting link reference.")).setProperty(LINK_CREATE_FAILED, constant(true)) + .endChoice().otherwise() + .process(exchange -> exchange.setProperty(ERROR_INFORMATION, + exchange.getIn().getBody(RequestStateDTO.class).getError().getErrorDescription())) + .setProperty(LINK_CREATE_FAILED, constant(true)).end().process(linksResponseProcessor); + + /** + * API to start base route + */ + from("rest:POST:/links").log(LoggingLevel.INFO, "Got Links POST request").process(exchange -> { + exchange.setProperty(CHANNEL_REQUEST, exchange.getIn().getBody()); + exchange.setProperty(CORRELATION_ID, UUID.randomUUID()); + exchange.setProperty(IS_RTP_REQUEST, false); + + TransactionChannelRequestDTO channelRequest = objectMapper.readValue(exchange.getProperty(CHANNEL_REQUEST, String.class), + TransactionChannelRequestDTO.class); + GsmaParty party = new GsmaParty(); + LinksDTO linksDTO = new LinksDTO(); + + PartyIdInfo sourceParty = exchange.getProperty(IS_RTP_REQUEST, Boolean.class) ? channelRequest.getPayer().getPartyIdInfo() + : channelRequest.getPayee().getPartyIdInfo(); + PartyIdInfo destinationParty = exchange.getProperty(IS_RTP_REQUEST, Boolean.class) ? channelRequest.getPayee().getPartyIdInfo() + : channelRequest.getPayer().getPartyIdInfo(); + + party.setKey(sourceParty.getPartyIdType().toString().toLowerCase()); + party.setValue(sourceParty.getPartyIdentifier()); + + GsmaParty[] sourceAccounts = new GsmaParty[] { party }; + linksDTO.setStatus("active"); + linksDTO.setMode("both"); + linksDTO.setSourceAccountIdentifiers(sourceAccounts); + + exchange.setProperty(LINKS_REQUEST_BODY, linksDTO); + exchange.setProperty(IDENTIFIER_TYPE, destinationParty.getPartyIdType().toString().toLowerCase()); + exchange.setProperty(IDENTIFIER, destinationParty.getPartyIdentifier()); + }).to("direct:links-route"); + + } +} diff --git a/ph-ee-connector-gsma-mm/src/main/java/org/mifos/connector/gsma/account/LinksWorkers.java b/ph-ee-connector-gsma-mm/src/main/java/org/mifos/connector/gsma/account/LinksWorkers.java new file mode 100644 index 000000000..fbf802756 --- /dev/null +++ b/ph-ee-connector-gsma-mm/src/main/java/org/mifos/connector/gsma/account/LinksWorkers.java @@ -0,0 +1,101 @@ +package org.mifos.connector.gsma.account; + +import static org.mifos.connector.gsma.camel.config.CamelProperties.CHANNEL_REQUEST; +import static org.mifos.connector.gsma.camel.config.CamelProperties.CORRELATION_ID; +import static org.mifos.connector.gsma.camel.config.CamelProperties.IDENTIFIER; +import static org.mifos.connector.gsma.camel.config.CamelProperties.IDENTIFIER_TYPE; +import static org.mifos.connector.gsma.camel.config.CamelProperties.IS_RTP_REQUEST; +import static org.mifos.connector.gsma.camel.config.CamelProperties.LINKS_REQUEST_BODY; +import static org.mifos.connector.gsma.camel.config.CamelProperties.TRANSACTION_CORRELATION_ID; +import static org.mifos.connector.gsma.zeebe.ZeebeExpressionVariables.LINK_CREATION_COUNT; + +import com.fasterxml.jackson.databind.ObjectMapper; +import io.camunda.zeebe.client.ZeebeClient; +import java.util.Map; +import java.util.UUID; +import javax.annotation.PostConstruct; +import org.apache.camel.CamelContext; +import org.apache.camel.Exchange; +import org.apache.camel.ProducerTemplate; +import org.apache.camel.support.DefaultExchange; +import org.mifos.connector.common.channel.dto.TransactionChannelRequestDTO; +import org.mifos.connector.common.gsma.dto.GsmaParty; +import org.mifos.connector.common.gsma.dto.LinksDTO; +import org.mifos.connector.common.mojaloop.dto.PartyIdInfo; +import org.mifos.connector.gsma.transfer.CorrelationIDStore; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +@Component +public class LinksWorkers { + + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Autowired + private ProducerTemplate producerTemplate; + + @Autowired + private CamelContext camelContext; + + @Autowired + private ZeebeClient zeebeClient; + + @Value("${zeebe.client.evenly-allocated-max-jobs}") + private int workerMaxJobs; + + @Autowired + private ObjectMapper objectMapper; + + @Autowired + private CorrelationIDStore correlationIDStore; + + @PostConstruct + public void setupWorkers() { + + zeebeClient.newWorker().jobType("createAccountLink").handler((client, job) -> { + logger.info("Job '{}' started from process '{}' with key {}", job.getType(), job.getBpmnProcessId(), job.getKey()); + Map variables = job.getVariablesAsMap(); + variables.put(LINK_CREATION_COUNT, 1 + (Integer) variables.getOrDefault(LINK_CREATION_COUNT, -1)); + + Exchange exchange = new DefaultExchange(camelContext); + exchange.setProperty(CORRELATION_ID, UUID.randomUUID()); + exchange.setProperty(TRANSACTION_CORRELATION_ID, variables.get("transactionId")); + exchange.setProperty(CHANNEL_REQUEST, variables.get("channelRequest")); + exchange.setProperty(IS_RTP_REQUEST, variables.get(IS_RTP_REQUEST)); + + correlationIDStore.addMapping(exchange.getProperty(CORRELATION_ID, String.class), + exchange.getProperty(TRANSACTION_CORRELATION_ID, String.class)); + + TransactionChannelRequestDTO channelRequest = objectMapper.readValue(exchange.getProperty(CHANNEL_REQUEST, String.class), + TransactionChannelRequestDTO.class); + GsmaParty party = new GsmaParty(); + LinksDTO linksDTO = new LinksDTO(); + + PartyIdInfo sourceParty = exchange.getProperty(IS_RTP_REQUEST, Boolean.class) ? channelRequest.getPayer().getPartyIdInfo() + : channelRequest.getPayee().getPartyIdInfo(); + PartyIdInfo destinationParty = exchange.getProperty(IS_RTP_REQUEST, Boolean.class) ? channelRequest.getPayee().getPartyIdInfo() + : channelRequest.getPayer().getPartyIdInfo(); + + party.setKey(sourceParty.getPartyIdType().toString().toLowerCase()); + party.setValue(sourceParty.getPartyIdentifier()); + + GsmaParty[] sourceAccounts = new GsmaParty[] { party }; + linksDTO.setStatus("active"); + linksDTO.setMode("both"); + linksDTO.setSourceAccountIdentifiers(sourceAccounts); + + exchange.setProperty(LINKS_REQUEST_BODY, linksDTO); + + exchange.setProperty(IDENTIFIER_TYPE, destinationParty.getPartyIdType().toString().toLowerCase()); + exchange.setProperty(IDENTIFIER, destinationParty.getPartyIdentifier()); + + producerTemplate.send("direct:links-route", exchange); + + client.newCompleteCommand(job.getKey()).variables(variables).send().join(); + }).name("createAccountLink").maxJobsActive(workerMaxJobs).open(); + + } +} diff --git a/ph-ee-connector-gsma-mm/src/main/java/org/mifos/connector/gsma/auth/AccessTokenStore.java b/ph-ee-connector-gsma-mm/src/main/java/org/mifos/connector/gsma/auth/AccessTokenStore.java new file mode 100644 index 000000000..c30a83d28 --- /dev/null +++ b/ph-ee-connector-gsma-mm/src/main/java/org/mifos/connector/gsma/auth/AccessTokenStore.java @@ -0,0 +1,44 @@ +package org.mifos.connector.gsma.auth; + +import java.time.LocalDateTime; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; + +@Component +public class AccessTokenStore { + + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + public String accessToken; + public LocalDateTime expiresOn; + + public AccessTokenStore() { + this.expiresOn = LocalDateTime.now(); + logger.info("ACCESS TOKEN STORE CREATED!"); + } + + public String getAccessToken() { + return accessToken; + } + + public void setAccessToken(String accessToken) { + this.accessToken = accessToken; + } + + public LocalDateTime getExpiresOn() { + return expiresOn; + } + + public void setExpiresOn(int expires_in) { + this.expiresOn = LocalDateTime.now().plusSeconds(expires_in); + } + + public boolean isValid(LocalDateTime dateTime) { + if (dateTime.isBefore(expiresOn)) { + return true; + } else { + return false; + } + } + +} diff --git a/ph-ee-connector-gsma-mm/src/main/java/org/mifos/connector/gsma/auth/AuthProcessor.java b/ph-ee-connector-gsma-mm/src/main/java/org/mifos/connector/gsma/auth/AuthProcessor.java new file mode 100644 index 000000000..b1337634a --- /dev/null +++ b/ph-ee-connector-gsma-mm/src/main/java/org/mifos/connector/gsma/auth/AuthProcessor.java @@ -0,0 +1,16 @@ +package org.mifos.connector.gsma.auth; + +import org.apache.camel.Exchange; +import org.apache.camel.Processor; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class AuthProcessor implements Processor { + + private Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Override + public void process(Exchange exchange) throws Exception { + + } +} diff --git a/ph-ee-connector-gsma-mm/src/main/java/org/mifos/connector/gsma/auth/AuthRoutes.java b/ph-ee-connector-gsma-mm/src/main/java/org/mifos/connector/gsma/auth/AuthRoutes.java new file mode 100644 index 000000000..8ef9ecbe4 --- /dev/null +++ b/ph-ee-connector-gsma-mm/src/main/java/org/mifos/connector/gsma/auth/AuthRoutes.java @@ -0,0 +1,90 @@ +package org.mifos.connector.gsma.auth; + +import java.io.UnsupportedEncodingException; +import java.time.LocalDateTime; +import java.util.Base64; +import org.apache.camel.Exchange; +import org.apache.camel.LoggingLevel; +import org.apache.camel.Processor; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.model.dataformat.JsonLibrary; +import org.mifos.connector.common.gsma.dto.AccessTokenDTO; +import org.mifos.connector.common.gsma.dto.AuthErrorDTO; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +@Component +public class AuthRoutes extends RouteBuilder { + + @Value("${gsma.auth.host}") + private String authUrl; + + @Value("${gsma.auth.client-key}") + private String clientKey; + + @Value("${gsma.auth.client-secret}") + private String clientSecret; + + @Autowired + private AccessTokenStore accessTokenStore; + + private Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Override + public void configure() { + + /** + * Error handling route + */ + from("direct:access-token-error").id("access-token-error").unmarshal().json(JsonLibrary.Jackson, AuthErrorDTO.class) + .process(exchange -> { + logger.error(exchange.getIn().getBody(AuthErrorDTO.class).getErrorMessage()); + // TODO: Improve Error Handling + }); + + /** + * Save Access Token to AccessTokenStore + */ + from("direct:access-token-save").id("access-token-save").unmarshal().json(JsonLibrary.Jackson, AccessTokenDTO.class) + .process(new Processor() { + + @Override + public void process(Exchange exchange) throws Exception { + accessTokenStore.setAccessToken(exchange.getIn().getBody(AccessTokenDTO.class).getAccess_token()); + accessTokenStore.setExpiresOn(exchange.getIn().getBody(AccessTokenDTO.class).getExpires_in()); + logger.info("Saved Access Token: " + accessTokenStore.getAccessToken()); + } + }); + + /** + * Fetch Access Token from GSMA API + */ + from("direct:access-token-fetch").id("access-token-fetch").log(LoggingLevel.INFO, "Fetching access token") + .setHeader(Exchange.HTTP_METHOD, constant("POST")) + .setHeader("Authorization", simple("Basic " + createAuthHeader(clientKey, clientSecret))) + .setHeader("Content-Type", constant("application/x-www-form-urlencoded")).removeHeader(Exchange.HTTP_PATH) + .setBody(simple("grant_type=client_credentials")).toD(authUrl + "?bridgeEndpoint=true"); + + /** + * Access Token check validity and return value + */ + from("direct:get-access-token").id("get-access-token").choice().when(exchange -> accessTokenStore.isValid(LocalDateTime.now())) + .log("Access token valid. Continuing.").otherwise().log("Access token expired or not present") + .to("direct:access-token-fetch").choice().when(header("CamelHttpResponseCode").isEqualTo("200")) + .log("Access Token Fetch Successful").to("direct:access-token-save").otherwise().log("Access Token Fetch Unsuccessful") + .to("direct:access-token-error"); + } + + private String createAuthHeader(String key, String secret) { + String encodedAuth = null; + try { + encodedAuth = Base64.getEncoder().encodeToString((key + ":" + secret).getBytes("utf-8")); + } catch (UnsupportedEncodingException e) { + logger.debug(e.getMessage()); + } + return encodedAuth; + } +} diff --git a/ph-ee-connector-gsma-mm/src/main/java/org/mifos/connector/gsma/auth/AuthWorkers.java b/ph-ee-connector-gsma-mm/src/main/java/org/mifos/connector/gsma/auth/AuthWorkers.java new file mode 100644 index 000000000..8686b0a09 --- /dev/null +++ b/ph-ee-connector-gsma-mm/src/main/java/org/mifos/connector/gsma/auth/AuthWorkers.java @@ -0,0 +1,3 @@ +package org.mifos.connector.gsma.auth; + +public class AuthWorkers {} diff --git a/ph-ee-connector-gsma-mm/src/main/java/org/mifos/connector/gsma/camel/config/CamelContextConfig.java b/ph-ee-connector-gsma-mm/src/main/java/org/mifos/connector/gsma/camel/config/CamelContextConfig.java new file mode 100644 index 000000000..4b16917a3 --- /dev/null +++ b/ph-ee-connector-gsma-mm/src/main/java/org/mifos/connector/gsma/camel/config/CamelContextConfig.java @@ -0,0 +1,58 @@ +package org.mifos.connector.gsma.camel.config; + +import java.util.HashMap; +import org.apache.camel.CamelContext; +import org.apache.camel.component.http.HttpComponent; +import org.apache.camel.spi.RestConfiguration; +import org.apache.camel.spring.boot.CamelContextConfiguration; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class CamelContextConfig { + + @Value("${camel.server-port}") + private int serverPort; + + @Value("${camel.disable-ssl}") + private boolean disableSSL; + + @Autowired + private HttpClientConfigurerTrustAllCACerts httpClientConfigurerTrustAllCACerts; + + @Bean + CamelContextConfiguration contextConfiguration() { + return new CamelContextConfiguration() { + + @Override + public void beforeApplicationStart(CamelContext camelContext) { + camelContext.setTracing(false); + camelContext.setMessageHistory(false); + camelContext.setStreamCaching(true); + camelContext.disableJMX(); + + if (disableSSL) { + HttpComponent httpComponent = camelContext.getComponent("https", HttpComponent.class); + httpComponent.setHttpClientConfigurer(httpClientConfigurerTrustAllCACerts); + } + + RestConfiguration rest = new RestConfiguration(); + camelContext.setRestConfiguration(rest); + rest.setComponent("undertow"); + rest.setProducerComponent("undertow"); + rest.setPort(serverPort); + rest.setBindingMode(RestConfiguration.RestBindingMode.json); + rest.setDataFormatProperties(new HashMap<>()); + rest.getDataFormatProperties().put("prettyPrint", "true"); + rest.setScheme("http"); + } + + @Override + public void afterApplicationStart(CamelContext camelContext) { + // empty + } + }; + } +} diff --git a/ph-ee-connector-gsma-mm/src/main/java/org/mifos/connector/gsma/camel/config/CamelProperties.java b/ph-ee-connector-gsma-mm/src/main/java/org/mifos/connector/gsma/camel/config/CamelProperties.java new file mode 100644 index 000000000..655f0d4ad --- /dev/null +++ b/ph-ee-connector-gsma-mm/src/main/java/org/mifos/connector/gsma/camel/config/CamelProperties.java @@ -0,0 +1,64 @@ +package org.mifos.connector.gsma.camel.config; + +/** + * Central Definition of all the Camel Exchange Properties + */ +public final class CamelProperties { + + private CamelProperties() {} + + public static final String ORIGIN_DATE = "originDate"; + public static final String AUTH_HOST = "authUrl"; + public static final String CLIENT_KEY = "clientKey"; + public static final String CLIENT_SECRET = "clientSecret"; + public static final String ACCESS_TOKEN = "accessToken"; + public static final String IDENTIFIER_TYPE = "identifier_type"; + public static final String IDENTIFIER = "identifier"; + public static final String ACCOUNT_RESPONSE = "accountResponse"; + public static final String ACCOUNT_ACTION = "actionAction"; + public static final String CORRELATION_ID = "correlationId"; + public static final String TRANSACTION_BODY = "transactionBody"; + public static final String TRANSACTION_TYPE = "transactionType"; + public static final String ERROR_INFORMATION = "errorInformation"; + public static final String TRANSACTION_ID = "transactionId"; + public static final String CHANNEL_REQUEST = "channelRequest"; + public static final String IS_RTP_REQUEST = "isRtpRequest"; + public static final String SERVER_CORRELATION = "isRtpRequest"; + public static final String TRANSACTION_STATUS = "transactionStatus"; + public static final String STATUS_AVAILABLE = "statusAvailable"; + public static final String RESPONSE_OBJECT_LINK = "responseObjectLink"; + public static final String RESPONSE_OBJECT = "responseObject"; + public static final String RESPONSE_OBJECT_AVAILABLE = "responseObjectAvailable"; + public static final String TRANSACTION_OBJECT_AVAILABLE = "transactionObjectAvailable"; + public static final String TRANSACTION_OBJECT = "transactionObject"; + public static final String IS_API_CALL = "isAPICall"; + public static final String GSMA_AUTHORIZATION_CODE = "gsmaAuthorizationCode"; + public static final String LINKS_REQUEST_BODY = "linksRequestBody"; + public static final String LINK_REFERENCE = "linkReference"; + public static final String RESPONSE_OBJECT_TYPE = "responseObjectType"; + public static final String TRANSACTION_CORRELATION_ID = "transactionCorrelationId"; + public static final String TRANSACTION_REFERENCE = "transactionReference"; + public static final String DEBIT_MANDATE_BODY = "debitMandateBody"; + public static final String MANDATE_REFERENCE = "mandateReference"; + public static final String MANDATE_CREATE_FAILED = "mandateCreateFailed"; + public static final String BILLS_ACTION = "billsAction"; + public static final String BILLS_CALL_FAILED = "billsCallFailed"; + public static final String BILL_COMPANIES = "billCompanies"; + public static final String BILLS = "bills"; + public static final String BILLS_REQUEST_BODY = "billsRequestBody"; + public static final String BILL_REFERENCE = "billReference"; + public static final String QUOTE_ID = "quoteId"; + public static final String QUOTE_REFERENCE = "quoteReference"; + public static final String GSMA_QUOTE_FAILED = "gsmaQuoteFailed"; + public static final String QUOTE_RESPONSE = "quoteResponse"; + public static final String QUOTE_REQUEST_BODY = "quoteRequestBody"; + public static final String GSMA_CHANNEL_REQUEST = "gsmaChannelRequest"; + public static final String RECEIVING_TENANT = "receivingTenant"; + public static final String RECEIVING_AMOUNT = "receivingAmount"; + public static final String RECEIVING_CURRENCY = "receivingCurrency"; + public static final String SENDER_AMOUNT = "senderAmount"; + public static final String SENDER_CURRENCY = "senderCurrency"; + public static final String CURRENCY_PAIR = "currencyPair"; + public static final String CURRENCY_PAIR_RATE = "currencyPairRate"; + +} diff --git a/ph-ee-connector-gsma-mm/src/main/java/org/mifos/connector/gsma/camel/config/HttpClientConfigurerTrustAllCACerts.java b/ph-ee-connector-gsma-mm/src/main/java/org/mifos/connector/gsma/camel/config/HttpClientConfigurerTrustAllCACerts.java new file mode 100644 index 000000000..c311fdb6e --- /dev/null +++ b/ph-ee-connector-gsma-mm/src/main/java/org/mifos/connector/gsma/camel/config/HttpClientConfigurerTrustAllCACerts.java @@ -0,0 +1,66 @@ +package org.mifos.connector.gsma.camel.config; + +import java.security.KeyManagementException; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; +import javax.net.ssl.HostnameVerifier; +import javax.net.ssl.SSLContext; +import org.apache.camel.component.http.HttpClientConfigurer; +import org.apache.http.config.Registry; +import org.apache.http.config.RegistryBuilder; +import org.apache.http.conn.socket.ConnectionSocketFactory; +import org.apache.http.conn.socket.PlainConnectionSocketFactory; +import org.apache.http.conn.ssl.SSLConnectionSocketFactory; +import org.apache.http.conn.ssl.TrustStrategy; +import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; +import org.apache.http.ssl.SSLContextBuilder; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; + +@Component +public class HttpClientConfigurerTrustAllCACerts implements HttpClientConfigurer { + + public Logger logger = LoggerFactory.getLogger(this.getClass()); + + public HttpClientConfigurerTrustAllCACerts() {} + + @Override + public void configureHttpClient(HttpClientBuilder clientBuilder) { + // setup a Trust Strategy that allows all certificates. + // + SSLContext sslContext = null; + try { + sslContext = new SSLContextBuilder().loadTrustMaterial(null, new TrustStrategy() { + + public boolean isTrusted(X509Certificate[] arg0, String arg1) throws CertificateException { + return true; + } + }).build(); + } catch (KeyManagementException | NoSuchAlgorithmException | KeyStoreException e) { + logger.debug(e.getMessage()); + } + clientBuilder.setSslcontext(sslContext); + + // don't check Hostnames, either. + // -- use SSLConnectionSocketFactory.getDefaultHostnameVerifier(), if you don't want to weaken + HostnameVerifier hostnameVerifier = SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER; + + // here's the special part: + // -- need to create an SSL Socket Factory, to use our weakened "trust strategy"; + // -- and create a Registry, to register it. + // + SSLConnectionSocketFactory sslSocketFactory = new SSLConnectionSocketFactory(sslContext, hostnameVerifier); + Registry socketFactoryRegistry = RegistryBuilder.create() + .register("http", PlainConnectionSocketFactory.getSocketFactory()).register("https", sslSocketFactory).build(); + + // now, we create connection-manager using our Registry. + // -- allows multi-threaded use + PoolingHttpClientConnectionManager connMgr = new PoolingHttpClientConnectionManager(socketFactoryRegistry); + clientBuilder.setConnectionManager(connMgr); + } + +} diff --git a/ph-ee-connector-gsma-mm/src/main/java/org/mifos/connector/gsma/response/TransactionResponseRoute.java b/ph-ee-connector-gsma-mm/src/main/java/org/mifos/connector/gsma/response/TransactionResponseRoute.java new file mode 100644 index 000000000..2311cbd88 --- /dev/null +++ b/ph-ee-connector-gsma-mm/src/main/java/org/mifos/connector/gsma/response/TransactionResponseRoute.java @@ -0,0 +1,99 @@ +package org.mifos.connector.gsma.response; + +import static org.mifos.connector.gsma.camel.config.CamelProperties.ACCESS_TOKEN; +import static org.mifos.connector.gsma.camel.config.CamelProperties.CORRELATION_ID; +import static org.mifos.connector.gsma.camel.config.CamelProperties.RESPONSE_OBJECT; +import static org.mifos.connector.gsma.camel.config.CamelProperties.RESPONSE_OBJECT_AVAILABLE; +import static org.mifos.connector.gsma.camel.config.CamelProperties.RESPONSE_OBJECT_LINK; +import static org.mifos.connector.gsma.camel.config.CamelProperties.RESPONSE_OBJECT_TYPE; + +import java.time.ZoneOffset; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; +import org.apache.camel.Exchange; +import org.apache.camel.LoggingLevel; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.model.dataformat.JsonLibrary; +import org.mifos.connector.common.gsma.dto.GSMATransaction; +import org.mifos.connector.common.gsma.dto.LinksDTO; +import org.mifos.connector.common.gsma.dto.ResponseLinkDTO; +import org.mifos.connector.gsma.auth.AccessTokenStore; +import org.mifos.connector.gsma.transfer.CorrelationIDStore; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +@Component +public class TransactionResponseRoute extends RouteBuilder { + + @Autowired + private AccessTokenStore accessTokenStore; + + @Autowired + private CorrelationIDStore correlationIDStore; + + @Value("${gsma.api.host}") + private String baseURL; + + private Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Override + public void configure() throws Exception { + + /** + * Base route for transaction response + */ + from("direct:response-route").id("response-route").log(LoggingLevel.INFO, "Transaction Response route started") + .to("direct:get-access-token").process(exchange -> exchange.setProperty(ACCESS_TOKEN, accessTokenStore.getAccessToken())) + .log(LoggingLevel.INFO, "Got access token, moving on.").to("direct:get-response-link") + .log(LoggingLevel.INFO, "Transaction Response Link: ${body}").choice() + .when(header("CamelHttpResponseCode").isEqualTo("200")).unmarshal().json(JsonLibrary.Jackson, ResponseLinkDTO.class) + .process(exchange -> exchange.setProperty(RESPONSE_OBJECT_LINK, exchange.getIn().getBody(ResponseLinkDTO.class).getLink())) + .marshal().json(JsonLibrary.Jackson).log(LoggingLevel.INFO, "Moving to get Transaction Object").to("direct:get-link-object") + .log(LoggingLevel.INFO, "Transaction Link Object Response: ${body}").choice() + .when(header("CamelHttpResponseCode").isEqualTo("200")).setProperty(RESPONSE_OBJECT_AVAILABLE, constant(true)) + .to("direct:link-object-success").otherwise().log(LoggingLevel.INFO, "Error in getting Transaction Object") + .to("direct:transaction-response-error").endChoice().otherwise() + .log(LoggingLevel.INFO, "Error in getting Transaction Response Link").to("direct:transaction-response-error").endChoice(); + + /** + * Route to unmarshall different objects on success + */ + from("direct:link-object-success").id("link-object-success").choice() + .when(exchange -> exchange.getProperty(RESPONSE_OBJECT_TYPE, String.class).equals("links")) + .log(LoggingLevel.INFO, "Unmarshalling Links Object").unmarshal().json(JsonLibrary.Jackson, LinksDTO.class) + .process(exchange -> { + exchange.setProperty(RESPONSE_OBJECT, exchange.getIn().getBody(LinksDTO.class)); + }).when(exchange -> exchange.getProperty(RESPONSE_OBJECT_TYPE, String.class).equals("transaction")) + .log(LoggingLevel.INFO, "Unmarshalling Transaction Object").unmarshal().json(JsonLibrary.Jackson, GSMATransaction.class) + .process(exchange -> { + exchange.setProperty(RESPONSE_OBJECT, exchange.getIn().getBody(GSMATransaction.class)); + }).otherwise().log(LoggingLevel.INFO, "Unknown Response Object Type: ${exchangeProperty." + RESPONSE_OBJECT_TYPE + "}") + .endChoice(); + + /** + * Route to get Transaction Response Link API + */ + from("direct:get-response-link").id("get-response-link").removeHeader("*").setHeader(Exchange.HTTP_METHOD, constant("GET")) + .setHeader("X-Date", simple(ZonedDateTime.now(ZoneOffset.UTC).format(DateTimeFormatter.ISO_INSTANT))) + .setHeader("Authorization", simple("Bearer ${exchangeProperty." + ACCESS_TOKEN + "}")).toD(baseURL + "/responses" + + "/${exchangeProperty." + CORRELATION_ID + "}" + "?bridgeEndpoint=true&throwExceptionOnFailure=false"); + + /** + * Route to get Transaction Object + */ + from("direct:get-link-object").id("get-link-object").removeHeader("*").setHeader(Exchange.HTTP_METHOD, constant("GET")) + .setHeader("X-Date", simple(ZonedDateTime.now(ZoneOffset.UTC).format(DateTimeFormatter.ISO_INSTANT))) + .setHeader("Authorization", simple("Bearer ${exchangeProperty." + ACCESS_TOKEN + "}")) + .toD(baseURL + "/${exchangeProperty." + RESPONSE_OBJECT_LINK + "}" + "?bridgeEndpoint=true&throwExceptionOnFailure=false"); + + /** + * Error Handler Route for Transaction Response TODO: Improve based on use cases + */ + from("direct:transaction-response-error").id("transaction-response-error") + .log(LoggingLevel.INFO, "Error in getting Transaction Response").setProperty(RESPONSE_OBJECT_AVAILABLE, constant(false)); + + } +} diff --git a/ph-ee-connector-gsma-mm/src/main/java/org/mifos/connector/gsma/response/TransactionResponseWorker.java b/ph-ee-connector-gsma-mm/src/main/java/org/mifos/connector/gsma/response/TransactionResponseWorker.java new file mode 100644 index 000000000..6cdfb7d52 --- /dev/null +++ b/ph-ee-connector-gsma-mm/src/main/java/org/mifos/connector/gsma/response/TransactionResponseWorker.java @@ -0,0 +1,63 @@ +package org.mifos.connector.gsma.response; + +import static org.mifos.connector.gsma.camel.config.CamelProperties.CORRELATION_ID; +import static org.mifos.connector.gsma.camel.config.CamelProperties.RESPONSE_OBJECT; +import static org.mifos.connector.gsma.camel.config.CamelProperties.RESPONSE_OBJECT_AVAILABLE; +import static org.mifos.connector.gsma.camel.config.CamelProperties.RESPONSE_OBJECT_TYPE; +import static org.mifos.connector.gsma.camel.config.CamelProperties.TRANSACTION_OBJECT; +import static org.mifos.connector.gsma.camel.config.CamelProperties.TRANSACTION_OBJECT_AVAILABLE; + +import io.camunda.zeebe.client.ZeebeClient; +import java.util.Map; +import javax.annotation.PostConstruct; +import org.apache.camel.CamelContext; +import org.apache.camel.Exchange; +import org.apache.camel.ProducerTemplate; +import org.apache.camel.support.DefaultExchange; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +@Component +public class TransactionResponseWorker { + + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Autowired + private ProducerTemplate producerTemplate; + + @Autowired + private CamelContext camelContext; + + @Autowired + private ZeebeClient zeebeClient; + + @Value("${zeebe.client.evenly-allocated-max-jobs}") + private int workerMaxJobs; + + @PostConstruct + public void setupWorkers() { + + zeebeClient.newWorker().jobType("transactionResponse").handler((client, job) -> { + logger.info("Job '{}' started from process '{}' with key {}", job.getType(), job.getBpmnProcessId(), job.getKey()); + Map variables = job.getVariablesAsMap(); + + Exchange exchange = new DefaultExchange(camelContext); + exchange.setProperty(CORRELATION_ID, variables.get("transactionId")); + exchange.setProperty(RESPONSE_OBJECT_TYPE, "transaction"); + + producerTemplate.send("direct:response-route", exchange); + + variables.put(TRANSACTION_OBJECT_AVAILABLE, exchange.getProperty(RESPONSE_OBJECT_AVAILABLE, Boolean.class)); + if (exchange.getProperty(RESPONSE_OBJECT_AVAILABLE, Boolean.class)) { + variables.put(TRANSACTION_OBJECT, exchange.getProperty(RESPONSE_OBJECT, String.class)); + } + + client.newCompleteCommand(job.getKey()).variables(variables).send().join(); + }).name("transactionResponse").maxJobsActive(workerMaxJobs).open(); + + } + +} diff --git a/ph-ee-connector-gsma-mm/src/main/java/org/mifos/connector/gsma/state/TransactionStateProcessor.java b/ph-ee-connector-gsma-mm/src/main/java/org/mifos/connector/gsma/state/TransactionStateProcessor.java new file mode 100644 index 000000000..2dc74d169 --- /dev/null +++ b/ph-ee-connector-gsma-mm/src/main/java/org/mifos/connector/gsma/state/TransactionStateProcessor.java @@ -0,0 +1,19 @@ +package org.mifos.connector.gsma.state; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.apache.camel.Exchange; +import org.apache.camel.Processor; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component +public class TransactionStateProcessor implements Processor { + + @Autowired + private ObjectMapper objectMapper; + + @Override + public void process(Exchange exchange) throws Exception { + + } +} diff --git a/ph-ee-connector-gsma-mm/src/main/java/org/mifos/connector/gsma/state/TransactionStateRoute.java b/ph-ee-connector-gsma-mm/src/main/java/org/mifos/connector/gsma/state/TransactionStateRoute.java new file mode 100644 index 000000000..277eda1e5 --- /dev/null +++ b/ph-ee-connector-gsma-mm/src/main/java/org/mifos/connector/gsma/state/TransactionStateRoute.java @@ -0,0 +1,125 @@ +package org.mifos.connector.gsma.state; + +import static org.mifos.connector.gsma.camel.config.CamelProperties.ACCESS_TOKEN; +import static org.mifos.connector.gsma.camel.config.CamelProperties.CORRELATION_ID; +import static org.mifos.connector.gsma.camel.config.CamelProperties.ERROR_INFORMATION; +import static org.mifos.connector.gsma.camel.config.CamelProperties.RECEIVING_TENANT; +import static org.mifos.connector.gsma.camel.config.CamelProperties.SERVER_CORRELATION; +import static org.mifos.connector.gsma.camel.config.CamelProperties.STATUS_AVAILABLE; +import static org.mifos.connector.gsma.camel.config.CamelProperties.TRANSACTION_STATUS; +import static org.mifos.connector.gsma.zeebe.ZeebeExpressionVariables.TRANSACTION_FAILED; + +import java.time.ZoneOffset; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; +import java.util.stream.Stream; +import org.apache.camel.Exchange; +import org.apache.camel.LoggingLevel; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.model.dataformat.JsonLibrary; +import org.mifos.connector.common.gsma.dto.ErrorDTO; +import org.mifos.connector.common.gsma.dto.RequestStateDTO; +import org.mifos.connector.gsma.auth.AccessTokenStore; +import org.mifos.connector.gsma.transfer.CorrelationIDStore; +import org.mifos.connector.gsma.transfer.TransferResponseProcessor; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +@Component +public class TransactionStateRoute extends RouteBuilder { + + @Autowired + private AccessTokenStore accessTokenStore; + + @Autowired + private CorrelationIDStore correlationIDStore; + + @Autowired + private TransferResponseProcessor transferResponseProcessor; + + @Value("${gsma.api.host}") + private String baseURL; + + @Value("${gsma.api.channel}") + private String channelURL; + + private Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Override + public void configure() throws Exception { + + /** + * Route to check state and assign flags + */ + from("direct:transaction-state-check").id("transaction-state-check").to("direct:transaction-state").process(exchange -> { + if (exchange.getProperty(STATUS_AVAILABLE, Boolean.class)) { + if (exchange.getProperty(TRANSACTION_STATUS, String.class).equals("failed")) { + exchange.setProperty(ERROR_INFORMATION, + exchange.getIn().getBody(RequestStateDTO.class).getError().getErrorDescription()); + exchange.setProperty(TRANSACTION_FAILED, true); + } else if (exchange.getProperty(TRANSACTION_STATUS, String.class).equals("completed")) { + exchange.setProperty(TRANSACTION_FAILED, false); + } + } else { + exchange.setProperty(TRANSACTION_FAILED, true); + } + }).process(transferResponseProcessor); + + /** + * Base Route for Transaction State + */ + from("direct:transaction-state").id("transaction-state").log(LoggingLevel.INFO, "Transaction State route started") + // .to("direct:get-access-token") + // .process(exchange -> exchange.setProperty(ACCESS_TOKEN, accessTokenStore.getAccessToken())) + // .log(LoggingLevel.INFO, "Got access token, moving on.") + .choice() + .when(exchange -> correlationIDStore.isClientCorrelationPresent(exchange.getProperty(CORRELATION_ID, String.class))) + .log(LoggingLevel.INFO, "Getting Server Correlation ID").process(exchange -> { + Stream serverCorrelations = correlationIDStore + .getServerCorrelations(exchange.getProperty(CORRELATION_ID, String.class)); + String serverCorrelationID = serverCorrelations.findFirst().get(); + exchange.setProperty(SERVER_CORRELATION, serverCorrelationID); + logger.info("Server CorrelationID: " + serverCorrelationID); + }).to("direct:get-transaction-state-channel").log(LoggingLevel.INFO, "Transaction State API response: ${body}").choice() + .when(header("CamelHttpResponseCode").isEqualTo("200")).to("direct:transaction-state-success").otherwise() + .log(LoggingLevel.INFO, "Transaction State Request Unsuccessful").to("direct:transaction-state-error").endChoice() + .otherwise().log(LoggingLevel.INFO, "No Server Correlation found for Client").to("direct:transaction-state-error") + .endChoice(); + + /** + * Route to call Transaction State API + */ + from("direct:get-transaction-state").id("get-transaction-state").removeHeader("*").setHeader(Exchange.HTTP_METHOD, constant("GET")) + .setHeader("X-Date", simple(ZonedDateTime.now(ZoneOffset.UTC).format(DateTimeFormatter.ISO_INSTANT))) + .setHeader("Authorization", simple("Bearer ${exchangeProperty." + ACCESS_TOKEN + "}")).toD(baseURL + "/requeststates" + + "/${exchangeProperty." + SERVER_CORRELATION + "}" + "?bridgeEndpoint=true&throwExceptionOnFailure=false"); + + from("direct:get-transaction-state-channel").id("get-transaction-state-channel").removeHeader("*") + .setHeader(Exchange.HTTP_METHOD, constant("GET")) + .setHeader("Platform-TenantId", simple("${exchangeProperty." + RECEIVING_TENANT + "}")) + .toD(channelURL + "/channel/requeststates" + "/${exchangeProperty." + SERVER_CORRELATION + "}" + + "?bridgeEndpoint=true&throwExceptionOnFailure=false"); + + /** + * Error route handler TODO: Improve based on use cases + */ + from("direct:transaction-state-error").id("transaction-state-error").log(LoggingLevel.INFO, "Error in getting Transaction State") + .unmarshal().json(JsonLibrary.Jackson, ErrorDTO.class).process(exchange -> { + exchange.setProperty(STATUS_AVAILABLE, false); + exchange.setProperty(ERROR_INFORMATION, exchange.getIn().getBody(ErrorDTO.class).getErrorDescription()); + }); + /** + * Success route handler + */ + from("direct:transaction-state-success").id("transaction-state-success") + .log(LoggingLevel.INFO, "Transaction State request successful").unmarshal().json(JsonLibrary.Jackson, RequestStateDTO.class) + .process(exchange -> { + String status = exchange.getIn().getBody(RequestStateDTO.class).getStatus(); + exchange.setProperty(TRANSACTION_STATUS, status); + exchange.setProperty(STATUS_AVAILABLE, true); + }); + } +} diff --git a/ph-ee-connector-gsma-mm/src/main/java/org/mifos/connector/gsma/state/TransactionStateWorker.java b/ph-ee-connector-gsma-mm/src/main/java/org/mifos/connector/gsma/state/TransactionStateWorker.java new file mode 100644 index 000000000..cae493630 --- /dev/null +++ b/ph-ee-connector-gsma-mm/src/main/java/org/mifos/connector/gsma/state/TransactionStateWorker.java @@ -0,0 +1,71 @@ +package org.mifos.connector.gsma.state; + +import static org.mifos.connector.gsma.camel.config.CamelProperties.CORRELATION_ID; +import static org.mifos.connector.gsma.camel.config.CamelProperties.RECEIVING_TENANT; +import static org.mifos.connector.gsma.camel.config.CamelProperties.STATUS_AVAILABLE; +import static org.mifos.connector.gsma.camel.config.CamelProperties.TRANSACTION_ID; +import static org.mifos.connector.gsma.camel.config.CamelProperties.TRANSACTION_STATUS; +import static org.mifos.connector.gsma.zeebe.ZeebeExpressionVariables.TRANSFER_RETRY_COUNT; + +import com.fasterxml.jackson.databind.ObjectMapper; +import io.camunda.zeebe.client.ZeebeClient; +import java.util.Map; +import javax.annotation.PostConstruct; +import org.apache.camel.CamelContext; +import org.apache.camel.Exchange; +import org.apache.camel.ProducerTemplate; +import org.apache.camel.support.DefaultExchange; +import org.mifos.connector.common.gsma.dto.GSMATransaction; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +@Component +public class TransactionStateWorker { + + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Autowired + private ObjectMapper objectMapper; + + @Autowired + private ProducerTemplate producerTemplate; + + @Autowired + private CamelContext camelContext; + + @Autowired + private ZeebeClient zeebeClient; + + @Value("${zeebe.client.evenly-allocated-max-jobs}") + private int workerMaxJobs; + + @PostConstruct + public void setupWorkers() { + + zeebeClient.newWorker().jobType("transactionState").handler((client, job) -> { + logger.info("Job '{}' started from process '{}' with key {}", job.getType(), job.getBpmnProcessId(), job.getKey()); + Map variables = job.getVariablesAsMap(); + variables.put(TRANSFER_RETRY_COUNT, 1 + (Integer) variables.getOrDefault(TRANSFER_RETRY_COUNT, 0)); + GSMATransaction gsmaChannelRequest = objectMapper.readValue((String) variables.get("gsmaChannelRequest"), + GSMATransaction.class); + + Exchange exchange = new DefaultExchange(camelContext); + exchange.setProperty(CORRELATION_ID, variables.get("transactionId")); + exchange.setProperty(TRANSACTION_ID, variables.get("transactionId")); + exchange.setProperty(RECEIVING_TENANT, gsmaChannelRequest.getReceivingLei()); + + producerTemplate.send("direct:transaction-state-check", exchange); + + variables.put(STATUS_AVAILABLE, exchange.getProperty(STATUS_AVAILABLE, Boolean.class)); + if (exchange.getProperty(STATUS_AVAILABLE, Boolean.class)) { + variables.put(TRANSACTION_STATUS, exchange.getProperty(TRANSACTION_STATUS, String.class)); + } + + client.newCompleteCommand(job.getKey()).variables(variables).send().join(); + }).name("transactionState").maxJobsActive(workerMaxJobs).open(); + + } +} diff --git a/ph-ee-connector-gsma-mm/src/main/java/org/mifos/connector/gsma/transfer/CorrelationIDStore.java b/ph-ee-connector-gsma-mm/src/main/java/org/mifos/connector/gsma/transfer/CorrelationIDStore.java new file mode 100644 index 000000000..5d4df9448 --- /dev/null +++ b/ph-ee-connector-gsma-mm/src/main/java/org/mifos/connector/gsma/transfer/CorrelationIDStore.java @@ -0,0 +1,36 @@ +package org.mifos.connector.gsma.transfer; + +import java.util.HashMap; +import java.util.Map; +import java.util.stream.Stream; +import org.springframework.stereotype.Component; + +@Component +public class CorrelationIDStore { + + HashMap correlation = new HashMap<>(); + + public HashMap getCorrelation() { + return correlation; + } + + public void setCorrelation(HashMap correlation) { + this.correlation = correlation; + } + + public void addMapping(String serverCorrelation, String clientCorrelation) { + correlation.put(serverCorrelation, clientCorrelation); + } + + public String getClientCorrelation(String serverCorrelation) { + return correlation.get(serverCorrelation); + } + + public Stream getServerCorrelations(String clientCorrelation) { + return correlation.entrySet().stream().filter(entry -> clientCorrelation.equals(entry.getValue())).map(Map.Entry::getKey); + } + + public boolean isClientCorrelationPresent(String clientCorrelation) { + return correlation.containsValue(clientCorrelation); + } +} diff --git a/ph-ee-connector-gsma-mm/src/main/java/org/mifos/connector/gsma/transfer/DataTransformer.java b/ph-ee-connector-gsma-mm/src/main/java/org/mifos/connector/gsma/transfer/DataTransformer.java new file mode 100644 index 000000000..93dbc432b --- /dev/null +++ b/ph-ee-connector-gsma-mm/src/main/java/org/mifos/connector/gsma/transfer/DataTransformer.java @@ -0,0 +1,16 @@ +package org.mifos.connector.gsma.transfer; + +import org.mifos.connector.common.channel.dto.TransactionChannelRequestDTO; +import org.mifos.connector.common.gsma.dto.QuotesDTO; +import org.springframework.stereotype.Component; + +@Component +public class DataTransformer { + + public QuotesDTO getQuoteRequestBody(TransactionChannelRequestDTO channelRequest) { + QuotesDTO quote = new QuotesDTO(); + + return quote; + } + +} diff --git a/ph-ee-connector-gsma-mm/src/main/java/org/mifos/connector/gsma/transfer/QuoteResponseProcessor.java b/ph-ee-connector-gsma-mm/src/main/java/org/mifos/connector/gsma/transfer/QuoteResponseProcessor.java new file mode 100644 index 000000000..1336cdd9a --- /dev/null +++ b/ph-ee-connector-gsma-mm/src/main/java/org/mifos/connector/gsma/transfer/QuoteResponseProcessor.java @@ -0,0 +1,57 @@ +package org.mifos.connector.gsma.transfer; + +import static org.mifos.connector.gsma.camel.config.CamelProperties.ERROR_INFORMATION; +import static org.mifos.connector.gsma.camel.config.CamelProperties.GSMA_QUOTE_FAILED; +import static org.mifos.connector.gsma.camel.config.CamelProperties.QUOTE_ID; +import static org.mifos.connector.gsma.camel.config.CamelProperties.QUOTE_REFERENCE; +import static org.mifos.connector.gsma.camel.config.CamelProperties.TRANSACTION_ID; +import static org.mifos.connector.gsma.zeebe.ZeebeMessages.GSMA_QUOTE_RESPONSE; + +import io.camunda.zeebe.client.ZeebeClient; +import java.time.Duration; +import java.util.HashMap; +import java.util.Map; +import org.apache.camel.Exchange; +import org.apache.camel.Processor; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +@Component +public class QuoteResponseProcessor implements Processor { + + @Autowired + private ZeebeClient zeebeClient; + + private Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Value("${zeebe.client.ttl}") + private int timeToLive; + + @Override + public void process(Exchange exchange) { + + Map variables = new HashMap<>(); + + Object hasTransferFailed = exchange.getProperty(GSMA_QUOTE_FAILED); + + if (hasTransferFailed != null && (boolean) hasTransferFailed) { + variables.put(GSMA_QUOTE_FAILED, true); + variables.put(ERROR_INFORMATION, exchange.getIn().getBody(String.class)); + } else { + variables.put(QUOTE_ID, exchange.getProperty(QUOTE_ID)); + variables.put(QUOTE_REFERENCE, exchange.getProperty(QUOTE_REFERENCE)); + variables.put(GSMA_QUOTE_FAILED, false); + } + + logger.info("Publishing quote message variables: " + variables); + + zeebeClient.newPublishMessageCommand().messageName(GSMA_QUOTE_RESPONSE) + .correlationKey(exchange.getProperty(TRANSACTION_ID, String.class)).timeToLive(Duration.ofMillis(timeToLive)) + .variables(variables).send().join(); + + } + +} diff --git a/ph-ee-connector-gsma-mm/src/main/java/org/mifos/connector/gsma/transfer/QuotesRoute.java b/ph-ee-connector-gsma-mm/src/main/java/org/mifos/connector/gsma/transfer/QuotesRoute.java new file mode 100644 index 000000000..7ab993a8d --- /dev/null +++ b/ph-ee-connector-gsma-mm/src/main/java/org/mifos/connector/gsma/transfer/QuotesRoute.java @@ -0,0 +1,92 @@ +package org.mifos.connector.gsma.transfer; + +import static org.mifos.connector.gsma.camel.config.CamelProperties.ACCESS_TOKEN; +import static org.mifos.connector.gsma.camel.config.CamelProperties.ERROR_INFORMATION; +import static org.mifos.connector.gsma.camel.config.CamelProperties.GSMA_CHANNEL_REQUEST; +import static org.mifos.connector.gsma.camel.config.CamelProperties.GSMA_QUOTE_FAILED; +import static org.mifos.connector.gsma.camel.config.CamelProperties.QUOTE_ID; +import static org.mifos.connector.gsma.camel.config.CamelProperties.QUOTE_REFERENCE; +import static org.mifos.connector.gsma.camel.config.CamelProperties.QUOTE_REQUEST_BODY; +import static org.mifos.connector.gsma.camel.config.CamelProperties.QUOTE_RESPONSE; + +import com.fasterxml.jackson.databind.ObjectMapper; +import java.time.ZoneOffset; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; +import org.apache.camel.Exchange; +import org.apache.camel.LoggingLevel; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.model.dataformat.JsonLibrary; +import org.mifos.connector.common.gsma.dto.ErrorDTO; +import org.mifos.connector.common.gsma.dto.GSMATransaction; +import org.mifos.connector.common.gsma.dto.QuotesDTO; +import org.mifos.connector.gsma.auth.AccessTokenStore; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +@Component +public class QuotesRoute extends RouteBuilder { + + @Autowired + private ObjectMapper objectMapper; + + @Autowired + private AccessTokenStore accessTokenStore; + + @Autowired + private DataTransformer dataTransformer; + + @Value("${gsma.api.host}") + private String baseURL; + + @Value("${camel.host}") + private String hostURL; + + @Autowired + private QuoteResponseProcessor quoteResponseProcessor; + + private Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Override + public void configure() { + + from("direct:quote-route-base").id("quote-route-base").log(LoggingLevel.INFO, "Transfer route started") + .to("direct:get-access-token").process(exchange -> exchange.setProperty(ACCESS_TOKEN, accessTokenStore.getAccessToken())) + .log(LoggingLevel.INFO, "Got access token, moving on").process(exchange -> { + QuotesDTO gsmaQuoteRequestBody = new QuotesDTO(); + GSMATransaction gsmaChannelRequestBody = objectMapper + .readValue(exchange.getProperty(GSMA_CHANNEL_REQUEST, String.class), GSMATransaction.class); + + gsmaQuoteRequestBody.setRequestDate(ZonedDateTime.now(ZoneOffset.UTC).format(DateTimeFormatter.ISO_INSTANT)); + gsmaQuoteRequestBody.setCreditParty(gsmaChannelRequestBody.getCreditParty()); + gsmaQuoteRequestBody.setDebitParty(gsmaChannelRequestBody.getDebitParty()); + gsmaQuoteRequestBody.setRequestAmount(gsmaChannelRequestBody.getAmount()); + gsmaQuoteRequestBody.setRequestCurrency(gsmaChannelRequestBody.getCurrency()); + gsmaQuoteRequestBody.setSenderKyc(gsmaChannelRequestBody.getSenderKyc()); + gsmaQuoteRequestBody.setType("inttransfer"); + + exchange.setProperty(QUOTE_REQUEST_BODY, gsmaQuoteRequestBody); + }).log(LoggingLevel.INFO, "Moving on to API call").to("direct:get-quote") + .log(LoggingLevel.INFO, "Quote API response: ${body}").setProperty(QUOTE_RESPONSE, simple("${body}")).choice() + .when(header("CamelHttpResponseCode").isEqualTo("201")).log(LoggingLevel.INFO, "Quote request successful").unmarshal() + .json(JsonLibrary.Jackson, QuotesDTO.class).setProperty(GSMA_QUOTE_FAILED, constant(false)).process(exchange -> { + exchange.setProperty(QUOTE_ID, exchange.getIn().getBody(QuotesDTO.class).getQuotes()[0].getQuoteId()); + exchange.setProperty(QUOTE_REFERENCE, exchange.getIn().getBody(QuotesDTO.class).getQuotationReference()); + }).otherwise().log(LoggingLevel.ERROR, "Quote request unsuccessful").unmarshal().json(JsonLibrary.Jackson, ErrorDTO.class) + .process(exchange -> { + exchange.setProperty(ERROR_INFORMATION, exchange.getIn().getBody(ErrorDTO.class).getErrorCode()); + }).setProperty(GSMA_QUOTE_FAILED, constant(true)).end().process(quoteResponseProcessor); + + from("direct:get-quote").id("get-quote").removeHeader("*").setHeader(Exchange.HTTP_METHOD, constant("POST")) + .setHeader("X-Date", simple(ZonedDateTime.now(ZoneOffset.UTC).format(DateTimeFormatter.ISO_INSTANT))) + .setHeader("Authorization", simple("Bearer ${exchangeProperty." + ACCESS_TOKEN + "}")) + .setHeader("Content-Type", constant("application/json")).setBody(exchange -> exchange.getProperty(QUOTE_REQUEST_BODY)) + .marshal().json(JsonLibrary.Jackson).log(LoggingLevel.INFO, "Quote Request Body: ${body}") + .toD(baseURL + "/quotations" + "?bridgeEndpoint=true&throwExceptionOnFailure=false"); + + } + +} diff --git a/ph-ee-connector-gsma-mm/src/main/java/org/mifos/connector/gsma/transfer/QuotesWorkers.java b/ph-ee-connector-gsma-mm/src/main/java/org/mifos/connector/gsma/transfer/QuotesWorkers.java new file mode 100644 index 000000000..dea39aacb --- /dev/null +++ b/ph-ee-connector-gsma-mm/src/main/java/org/mifos/connector/gsma/transfer/QuotesWorkers.java @@ -0,0 +1,58 @@ +package org.mifos.connector.gsma.transfer; + +import static org.mifos.connector.gsma.camel.config.CamelProperties.CHANNEL_REQUEST; +import static org.mifos.connector.gsma.camel.config.CamelProperties.GSMA_CHANNEL_REQUEST; +import static org.mifos.connector.gsma.camel.config.CamelProperties.TRANSACTION_ID; +import static org.mifos.connector.gsma.zeebe.ZeebeExpressionVariables.QUOTE_RETRY_COUNT; + +import io.camunda.zeebe.client.ZeebeClient; +import java.util.Map; +import javax.annotation.PostConstruct; +import org.apache.camel.CamelContext; +import org.apache.camel.Exchange; +import org.apache.camel.ProducerTemplate; +import org.apache.camel.support.DefaultExchange; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +@Component +public class QuotesWorkers { + + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Autowired + private ZeebeClient zeebeClient; + + @Autowired + private ProducerTemplate producerTemplate; + + @Autowired + private CamelContext camelContext; + + @Value("${zeebe.client.evenly-allocated-max-jobs}") + private int workerMaxJobs; + + @PostConstruct + public void setupWorkers() { + + zeebeClient.newWorker().jobType("quote-gsma-payer").handler((client, job) -> { + logger.info("Job '{}' started from process '{}' with key {}", job.getType(), job.getBpmnProcessId(), job.getKey()); + Map variables = job.getVariablesAsMap(); + variables.put(QUOTE_RETRY_COUNT, 1 + (Integer) variables.getOrDefault(QUOTE_RETRY_COUNT, -1)); + + Exchange exchange = new DefaultExchange(camelContext); + exchange.setProperty(TRANSACTION_ID, variables.get("transactionId")); + exchange.setProperty(CHANNEL_REQUEST, variables.get("channelRequest")); + exchange.setProperty(GSMA_CHANNEL_REQUEST, variables.get("gsmaChannelRequest")); + + producerTemplate.send("direct:quote-route-base", exchange); + + client.newCompleteCommand(job.getKey()).variables(variables).send().join(); + }).name("quote-gsma-payer").maxJobsActive(workerMaxJobs).open(); + + } + +} diff --git a/ph-ee-connector-gsma-mm/src/main/java/org/mifos/connector/gsma/transfer/ReversalRoute.java b/ph-ee-connector-gsma-mm/src/main/java/org/mifos/connector/gsma/transfer/ReversalRoute.java new file mode 100644 index 000000000..d30774d32 --- /dev/null +++ b/ph-ee-connector-gsma-mm/src/main/java/org/mifos/connector/gsma/transfer/ReversalRoute.java @@ -0,0 +1,87 @@ +package org.mifos.connector.gsma.transfer; + +import static org.mifos.connector.gsma.camel.config.CamelProperties.ACCESS_TOKEN; +import static org.mifos.connector.gsma.camel.config.CamelProperties.CORRELATION_ID; +import static org.mifos.connector.gsma.camel.config.CamelProperties.RESPONSE_OBJECT; +import static org.mifos.connector.gsma.camel.config.CamelProperties.RESPONSE_OBJECT_AVAILABLE; +import static org.mifos.connector.gsma.camel.config.CamelProperties.RESPONSE_OBJECT_TYPE; +import static org.mifos.connector.gsma.camel.config.CamelProperties.TRANSACTION_BODY; +import static org.mifos.connector.gsma.camel.config.CamelProperties.TRANSACTION_REFERENCE; + +import com.fasterxml.jackson.databind.ObjectMapper; +import java.time.ZoneOffset; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; +import org.apache.camel.Exchange; +import org.apache.camel.LoggingLevel; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.model.dataformat.JsonLibrary; +import org.mifos.connector.common.gsma.dto.GSMATransaction; +import org.mifos.connector.gsma.auth.AccessTokenStore; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +@Component +public class ReversalRoute extends RouteBuilder { + + @Autowired + private ObjectMapper objectMapper; + + @Autowired + private AccessTokenStore accessTokenStore; + + @Value("${gsma.api.host}") + private String baseURL; + + @Autowired + private CorrelationIDStore correlationIDStore; + + private Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Override + public void configure() throws Exception { + + /** + * Reversal Starter with client correlation ID + */ + from("direct:reversal-starter").id("reversal-starter").setProperty(RESPONSE_OBJECT_TYPE, constant("transaction")) + .to("direct:response-route").choice().when(exchange -> exchange.getProperty(RESPONSE_OBJECT_AVAILABLE, Boolean.class)) + .process(exchange -> exchange.setProperty(TRANSACTION_REFERENCE, + exchange.getProperty(RESPONSE_OBJECT, GSMATransaction.class).getTransactionReference())) + .to("direct:reversal-base-route").otherwise().log("Failed to get transaction reference"); + + /** + * Base route for reversal with transaction reference + */ + from("direct:reversal-base-route").id("reversal-base-route").log(LoggingLevel.INFO, "Reversal route started") + .to("direct:get-access-token").process(exchange -> exchange.setProperty(ACCESS_TOKEN, accessTokenStore.getAccessToken())) + .log(LoggingLevel.INFO, "Got access token, moving on to get transaction reference").process(exchange -> { + GSMATransaction reversalBody = new GSMATransaction(); + reversalBody.setType("reversal"); + exchange.setProperty(TRANSACTION_BODY, reversalBody); + }).to("direct:commit-reversal").log(LoggingLevel.INFO, "Reversal Response: ${body}").choice() + .when(header("CamelHttpResponseCode").isEqualTo("201")).log(LoggingLevel.INFO, "Reversal successful").otherwise() + .log(LoggingLevel.INFO, "Reversal transaction failed").endChoice(); + + /** + * Call GSMA APIs to commit reversal + */ + from("direct:commit-reversal").removeHeader("*").setHeader(Exchange.HTTP_METHOD, constant("POST")) + .setHeader("X-Date", simple(ZonedDateTime.now(ZoneOffset.UTC).format(DateTimeFormatter.ISO_INSTANT))) + .setHeader("Authorization", simple("Bearer ${exchangeProperty." + ACCESS_TOKEN + "}")) + .setHeader("Content-Type", constant("application/json")).setBody(exchange -> exchange.getProperty(TRANSACTION_BODY)) + .marshal().json(JsonLibrary.Jackson).log(LoggingLevel.INFO, "Transaction Request Body: ${body}") + .toD(baseURL + "/transactions" + "/${exchangeProperty." + TRANSACTION_REFERENCE + "}" + "/reversals" + + "?bridgeEndpoint=true&throwExceptionOnFailure=false"); + + /** + * API to start reversal + */ + from("rest:GET:/transaction/reverse/{correlation}").log(LoggingLevel.INFO, "Transaction Reverse API").process(exchange -> { + exchange.setProperty(CORRELATION_ID, exchange.getIn().getHeader("correlation")); + }).to("direct:reversal-starter"); + } +} diff --git a/ph-ee-connector-gsma-mm/src/main/java/org/mifos/connector/gsma/transfer/TransferResponseProcessor.java b/ph-ee-connector-gsma-mm/src/main/java/org/mifos/connector/gsma/transfer/TransferResponseProcessor.java new file mode 100644 index 000000000..97ee75f75 --- /dev/null +++ b/ph-ee-connector-gsma-mm/src/main/java/org/mifos/connector/gsma/transfer/TransferResponseProcessor.java @@ -0,0 +1,58 @@ +package org.mifos.connector.gsma.transfer; + +import static org.mifos.connector.gsma.camel.config.CamelProperties.ERROR_INFORMATION; +import static org.mifos.connector.gsma.camel.config.CamelProperties.TRANSACTION_ID; +import static org.mifos.connector.gsma.zeebe.ZeebeExpressionVariables.TRANSACTION_FAILED; +import static org.mifos.connector.gsma.zeebe.ZeebeExpressionVariables.TRANSFER_STATE; +import static org.mifos.connector.gsma.zeebe.ZeebeMessages.TRANSFER_MESSAGE; +import static org.mifos.connector.gsma.zeebe.ZeebeMessages.TRANSFER_RESPONSE; + +import io.camunda.zeebe.client.ZeebeClient; +import java.time.Duration; +import java.util.HashMap; +import java.util.Map; +import org.apache.camel.Exchange; +import org.apache.camel.Processor; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +@Component +public class TransferResponseProcessor implements Processor { + + @Autowired + private ZeebeClient zeebeClient; + + private Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Value("${zeebe.client.ttl}") + private int timeToLive; + + @Override + public void process(Exchange exchange) { + + Map variables = new HashMap<>(); + + Object hasTransferFailed = exchange.getProperty(TRANSACTION_FAILED); + + if (hasTransferFailed != null && (boolean) hasTransferFailed) { + variables.put(TRANSACTION_FAILED, true); + variables.put(ERROR_INFORMATION, exchange.getIn().getBody(String.class)); + } else { + variables.put(TRANSFER_STATE, "COMMITTED"); + variables.put(TRANSACTION_FAILED, false); + + zeebeClient.newPublishMessageCommand().messageName(TRANSFER_MESSAGE) + .correlationKey(exchange.getProperty(TRANSACTION_ID, String.class)).variables(variables).send().join(); + } + + logger.info("Publishing transaction message variables: " + variables); + + zeebeClient.newPublishMessageCommand().messageName(TRANSFER_RESPONSE) + .correlationKey(exchange.getProperty(TRANSACTION_ID, String.class)).timeToLive(Duration.ofMillis(timeToLive)) + .variables(variables).send().join(); + + } +} diff --git a/ph-ee-connector-gsma-mm/src/main/java/org/mifos/connector/gsma/transfer/TransferRoutes.java b/ph-ee-connector-gsma-mm/src/main/java/org/mifos/connector/gsma/transfer/TransferRoutes.java new file mode 100644 index 000000000..96d75db8d --- /dev/null +++ b/ph-ee-connector-gsma-mm/src/main/java/org/mifos/connector/gsma/transfer/TransferRoutes.java @@ -0,0 +1,116 @@ +package org.mifos.connector.gsma.transfer; + +import static org.mifos.connector.gsma.camel.config.CamelProperties.ACCESS_TOKEN; +import static org.mifos.connector.gsma.camel.config.CamelProperties.CORRELATION_ID; +import static org.mifos.connector.gsma.camel.config.CamelProperties.GSMA_CHANNEL_REQUEST; +import static org.mifos.connector.gsma.camel.config.CamelProperties.TRANSACTION_ID; +import static org.mifos.connector.gsma.camel.config.CamelProperties.TRANSACTION_TYPE; +import static org.mifos.connector.gsma.zeebe.ZeebeExpressionVariables.TRANSACTION_FAILED; + +import com.fasterxml.jackson.databind.ObjectMapper; +import java.time.ZoneOffset; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; +import org.apache.camel.Exchange; +import org.apache.camel.LoggingLevel; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.model.dataformat.JsonLibrary; +import org.mifos.connector.common.gsma.dto.RequestStateDTO; +import org.mifos.connector.gsma.auth.AccessTokenStore; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +@Component +public class TransferRoutes extends RouteBuilder { + + @Autowired + private TransferResponseProcessor transferResponseProcessor; + + @Autowired + private TransformRequestData transformRequestData; + + @Autowired + private ObjectMapper objectMapper; + + @Autowired + private AccessTokenStore accessTokenStore; + + @Value("${gsma.api.host}") + private String baseURL; + + @Value("${camel.host}") + private String hostURL; + + @Value("${gsma.api.channel}") + private String channelURL; + + @Autowired + private CorrelationIDStore correlationIDStore; + + private Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Override + public void configure() { + + /** + * Base route for transactions + */ + from("direct:transfer-route").id("transfer-route").log(LoggingLevel.INFO, "Transfer route started") + // .to("direct:get-access-token") + // .process(exchange -> exchange.setProperty(ACCESS_TOKEN, accessTokenStore.getAccessToken())) + // .log(LoggingLevel.INFO, "Got access token, moving on") + .log(LoggingLevel.INFO, "Moving on to API call").to("direct:send-request-to-payee-route") + .log(LoggingLevel.INFO, "Status: ${header.CamelHttpResponseCode}") + .log(LoggingLevel.INFO, "Transaction API response: ${body}").to("direct:transaction-response-handler"); + + /** + * Route to handle async API responses + */ + from("direct:transaction-response-handler").id("transaction-response-handler").choice() + .when(header("CamelHttpResponseCode").isEqualTo("200")).log(LoggingLevel.INFO, "Transaction request successful").unmarshal() + .json(JsonLibrary.Jackson, RequestStateDTO.class).process(exchange -> { + correlationIDStore.addMapping(exchange.getIn().getBody(RequestStateDTO.class).getServerCorrelationId(), + exchange.getProperty(CORRELATION_ID, String.class)); + logger.info("Saved correlationId mapping"); + }).otherwise().log(LoggingLevel.ERROR, "Transaction request unsuccessful").process(exchange -> { + exchange.setProperty(TRANSACTION_ID, exchange.getProperty(CORRELATION_ID)); // TODO: Improve this + }).setProperty(TRANSACTION_FAILED, constant(true)).process(transferResponseProcessor); + + /** + * Calls GSMA API to commit transaction + */ + from("direct:commit-transaction").removeHeader("*").setHeader(Exchange.HTTP_METHOD, constant("POST")) + .setHeader("X-Date", simple(ZonedDateTime.now(ZoneOffset.UTC).format(DateTimeFormatter.ISO_INSTANT))) + .setHeader("Authorization", simple("Bearer ${exchangeProperty." + ACCESS_TOKEN + "}")) + .setHeader("X-Callback-URL", simple(hostURL + "/transfer/callback")) + .setHeader("X-CorrelationID", simple("${exchangeProperty." + CORRELATION_ID + "}")) + .setHeader("Content-Type", constant("application/json")).setBody(exchange -> exchange.getProperty(GSMA_CHANNEL_REQUEST)) + .log(LoggingLevel.INFO, "Transaction Request Body: ${body}").toD(baseURL + "/transactions/type" + "/${exchangeProperty." + + TRANSACTION_TYPE + "}" + "?bridgeEndpoint=true&throwExceptionOnFailure=false"); + + /** + * Callback for transaction + */ + from("rest:PUT:/transfer/callback").log(LoggingLevel.INFO, "Callback body ${body}").unmarshal() + .json(JsonLibrary.Jackson, RequestStateDTO.class).process(exchange -> { + String serverUUID = exchange.getIn().getBody(RequestStateDTO.class).getServerCorrelationId(); + exchange.setProperty(TRANSACTION_ID, correlationIDStore.getClientCorrelation(serverUUID)); + }).choice().when(exchange -> exchange.getIn().getBody(RequestStateDTO.class).getStatus().equals("completed")) + .setProperty(TRANSACTION_FAILED, constant(false)).otherwise().setProperty(TRANSACTION_FAILED, constant(true)).end() + .process(transferResponseProcessor); + + from("direct:send-request-to-payee-route").removeHeader("*").setHeader(Exchange.HTTP_METHOD, constant("POST")) + // .setHeader("Platform-TenantId", simple("${exchangeProperty."+ RECEIVING_TENANT +"}")) + .setHeader("Content-Type", constant("application/json")).process(exchange -> { + exchange.getIn().setHeader("Platform-TenantId", exchange.getProperty("payeeTenantId")); + logger.info("Tenant ID: {}", exchange.getProperty("payeeTenantId")); + }).setBody(exchange -> exchange.getProperty(GSMA_CHANNEL_REQUEST)) + .log(LoggingLevel.INFO, "Transaction Request Body: ${body}") + .toD(channelURL + "/channel/gsma/deposit" + "?bridgeEndpoint=true&throwExceptionOnFailure=false") + .log(LoggingLevel.INFO, "Channel API called, response: ${body}"); + + } +} diff --git a/ph-ee-connector-gsma-mm/src/main/java/org/mifos/connector/gsma/transfer/TransferWorkers.java b/ph-ee-connector-gsma-mm/src/main/java/org/mifos/connector/gsma/transfer/TransferWorkers.java new file mode 100644 index 000000000..6363761b4 --- /dev/null +++ b/ph-ee-connector-gsma-mm/src/main/java/org/mifos/connector/gsma/transfer/TransferWorkers.java @@ -0,0 +1,151 @@ +package org.mifos.connector.gsma.transfer; + +import static org.mifos.connector.gsma.camel.config.CamelProperties.CHANNEL_REQUEST; +import static org.mifos.connector.gsma.camel.config.CamelProperties.CORRELATION_ID; +import static org.mifos.connector.gsma.camel.config.CamelProperties.CURRENCY_PAIR; +import static org.mifos.connector.gsma.camel.config.CamelProperties.CURRENCY_PAIR_RATE; +import static org.mifos.connector.gsma.camel.config.CamelProperties.GSMA_AUTHORIZATION_CODE; +import static org.mifos.connector.gsma.camel.config.CamelProperties.GSMA_CHANNEL_REQUEST; +import static org.mifos.connector.gsma.camel.config.CamelProperties.IS_RTP_REQUEST; +import static org.mifos.connector.gsma.camel.config.CamelProperties.QUOTE_ID; +import static org.mifos.connector.gsma.camel.config.CamelProperties.QUOTE_REFERENCE; +import static org.mifos.connector.gsma.camel.config.CamelProperties.RECEIVING_AMOUNT; +import static org.mifos.connector.gsma.camel.config.CamelProperties.RECEIVING_CURRENCY; +import static org.mifos.connector.gsma.camel.config.CamelProperties.RECEIVING_TENANT; +import static org.mifos.connector.gsma.camel.config.CamelProperties.SENDER_AMOUNT; +import static org.mifos.connector.gsma.camel.config.CamelProperties.SENDER_CURRENCY; +import static org.mifos.connector.gsma.camel.config.CamelProperties.TRANSACTION_TYPE; +import static org.mifos.connector.gsma.zeebe.ZeebeExpressionVariables.TRANSACTION_FAILED; +import static org.mifos.connector.gsma.zeebe.ZeebeExpressionVariables.TRANSFER_RETRY_COUNT; +import static org.mifos.connector.gsma.zeebe.ZeebeMessages.TRANSFER_RESPONSE; + +import com.fasterxml.jackson.databind.ObjectMapper; +import io.camunda.zeebe.client.ZeebeClient; +import java.time.Duration; +import java.util.Map; +import javax.annotation.PostConstruct; +import org.apache.camel.CamelContext; +import org.apache.camel.Exchange; +import org.apache.camel.ProducerTemplate; +import org.apache.camel.support.DefaultExchange; +import org.mifos.connector.common.gsma.dto.GSMATransaction; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +@Component +public class TransferWorkers { + + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Autowired + private ObjectMapper objectMapper; + + @Autowired + private ZeebeClient zeebeClient; + + @Autowired + private ProducerTemplate producerTemplate; + + @Autowired + private CamelContext camelContext; + + @Value("${zeebe.client.evenly-allocated-max-jobs}") + private int workerMaxJobs; + + @PostConstruct + public void setupWorkers() { + + zeebeClient.newWorker().jobType("initiateTransfer").handler((client, job) -> { + logger.info("Job '{}' started from process '{}' with key {}", job.getType(), job.getBpmnProcessId(), job.getKey()); + Map variables = job.getVariablesAsMap(); + variables.put(TRANSFER_RETRY_COUNT, -1); + + Exchange exchange = new DefaultExchange(camelContext); + exchange.setProperty(CORRELATION_ID, variables.get("transactionId")); + exchange.setProperty(CHANNEL_REQUEST, variables.get("channelRequest")); + exchange.setProperty(GSMA_CHANNEL_REQUEST, variables.get("gsmaChannelRequest")); + exchange.setProperty(IS_RTP_REQUEST, variables.get(IS_RTP_REQUEST)); + exchange.setProperty(TRANSACTION_TYPE, variables.get(TRANSACTION_TYPE)); + exchange.setProperty(RECEIVING_TENANT, variables.get("tenantId")); + exchange.setProperty("payeeTenantId", variables.get("payeeTenantId")); + exchange.setProperty(GSMA_AUTHORIZATION_CODE, variables.get(GSMA_AUTHORIZATION_CODE)); + logger.info("Payee Tenant ID: {}", variables.get("payeeTenantId")); + producerTemplate.send("direct:transfer-route", exchange); + variables.put(TRANSACTION_FAILED, false); + // added to pass the transaction request api not found error + variables.put("payeeTenantId", exchange.getProperty("payeeTenantId")); + zeebeClient.newPublishMessageCommand().messageName(TRANSFER_RESPONSE) + .correlationKey(exchange.getProperty(CORRELATION_ID, String.class)).timeToLive(Duration.ofMillis(30000)) + .variables(variables).send(); + client.newCompleteCommand(job.getKey()).variables(variables).send().join(); + }).name("initiateTransfer").maxJobsActive(workerMaxJobs).open(); + + zeebeClient.newWorker().jobType("initiateIntTransfer").handler((client, job) -> { + logger.info("Job '{}' started from process '{}' with key {}", job.getType(), job.getBpmnProcessId(), job.getKey()); + Map variables = job.getVariablesAsMap(); + variables.put(TRANSFER_RETRY_COUNT, -1); + Exchange exchange = new DefaultExchange(camelContext); + exchange.setProperty(CORRELATION_ID, variables.get("transactionId")); + exchange.setProperty(CHANNEL_REQUEST, variables.get("channelRequest")); + exchange.setProperty(TRANSACTION_TYPE, variables.get(TRANSACTION_TYPE)); + exchange.setProperty(QUOTE_ID, variables.get(QUOTE_ID)); + exchange.setProperty(QUOTE_REFERENCE, variables.get(QUOTE_REFERENCE)); + exchange.setProperty("payeeTenantId", variables.get("payeeTenantId")); + + GSMATransaction gsmaTransaction = objectMapper.readValue((String) variables.get("gsmaChannelRequest"), GSMATransaction.class); + gsmaTransaction.getInternationalTransferInformation().setQuoteId((String) variables.get(QUOTE_ID)); + gsmaTransaction.getInternationalTransferInformation().setQuotationReference((String) variables.get(QUOTE_REFERENCE)); + + exchange.setProperty(GSMA_CHANNEL_REQUEST, gsmaTransaction); + + producerTemplate.send("direct:transfer-route", exchange); + variables.put("payeeTenantId", exchange.getProperty("payeeTenantId")); + client.newCompleteCommand(job.getKey()).variables(variables).send().join(); + }).name("initiateIntTransfer").maxJobsActive(workerMaxJobs).open(); + + zeebeClient.newWorker().jobType("initiatePayeeDeposit").handler((client, job) -> { + logger.info("Job '{}' started from process '{}' with key {}", job.getType(), job.getBpmnProcessId(), job.getKey()); + + Map variables = job.getVariablesAsMap(); + GSMATransaction gsmaChannelRequest = objectMapper.readValue((String) variables.get("gsmaChannelRequest"), + GSMATransaction.class); + GSMATransaction gsmaPayeeRequest = new GSMATransaction(); + variables.put(TRANSFER_RETRY_COUNT, -1); + // Do currency converted values instead of original values + String convertedAmount = gsmaChannelRequest.getInternationalTransferInformation().getReceivingAmount(); + String convertedCurrency = gsmaChannelRequest.getInternationalTransferInformation().getReceivingCurrency(); + + gsmaPayeeRequest.setDescriptionText( + "Original Amount = " + gsmaChannelRequest.getAmount() + ", currency = " + gsmaChannelRequest.getCurrency() + + ":::: Converted Amount = " + convertedAmount + ", currency = " + convertedCurrency); + logger.info(gsmaPayeeRequest.getDescriptionText()); + gsmaPayeeRequest.setAmount(convertedAmount); + gsmaPayeeRequest.setCurrency(convertedCurrency); + gsmaPayeeRequest.setRequestingOrganisationTransactionReference(variables.get("transactionId").toString()); + gsmaPayeeRequest.setCreditParty(gsmaChannelRequest.getCreditParty()); + gsmaPayeeRequest.setDebitParty(gsmaChannelRequest.getDebitParty()); + gsmaPayeeRequest.setReceivingLei(gsmaChannelRequest.getReceivingLei()); + gsmaPayeeRequest.setRequestingLei(gsmaChannelRequest.getRequestingLei()); + gsmaPayeeRequest.setType("transfer"); + + Exchange exchange = new DefaultExchange(camelContext); + exchange.setProperty(GSMA_CHANNEL_REQUEST, gsmaPayeeRequest); + exchange.setProperty(RECEIVING_TENANT, gsmaChannelRequest.getReceivingLei()); + exchange.setProperty(CORRELATION_ID, variables.get("transactionId")); + + variables.put(RECEIVING_AMOUNT, convertedAmount); + variables.put(RECEIVING_CURRENCY, convertedCurrency); + variables.put(SENDER_AMOUNT, gsmaChannelRequest.getAmount()); + variables.put(SENDER_CURRENCY, gsmaChannelRequest.getCurrency()); + variables.put(CURRENCY_PAIR, gsmaChannelRequest.getInternationalTransferInformation().getCurrencyPair()); + variables.put(CURRENCY_PAIR_RATE, gsmaChannelRequest.getInternationalTransferInformation().getCurrencyPairRate()); + + producerTemplate.send("direct:transfer-route", exchange); + + client.newCompleteCommand(job.getKey()).variables(variables).send().join(); + }).name("initiatePayeeDeposit").maxJobsActive(workerMaxJobs).open(); + } +} diff --git a/ph-ee-connector-gsma-mm/src/main/java/org/mifos/connector/gsma/transfer/TransformRequestData.java b/ph-ee-connector-gsma-mm/src/main/java/org/mifos/connector/gsma/transfer/TransformRequestData.java new file mode 100644 index 000000000..ad1c9f3fe --- /dev/null +++ b/ph-ee-connector-gsma-mm/src/main/java/org/mifos/connector/gsma/transfer/TransformRequestData.java @@ -0,0 +1,55 @@ +package org.mifos.connector.gsma.transfer; + +import static org.mifos.connector.gsma.camel.config.CamelProperties.CHANNEL_REQUEST; +import static org.mifos.connector.gsma.camel.config.CamelProperties.GSMA_AUTHORIZATION_CODE; +import static org.mifos.connector.gsma.camel.config.CamelProperties.TRANSACTION_BODY; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.apache.camel.Exchange; +import org.apache.camel.Processor; +import org.mifos.connector.common.channel.dto.TransactionChannelRequestDTO; +import org.mifos.connector.common.gsma.dto.GSMATransaction; +import org.mifos.connector.common.gsma.dto.GsmaParty; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component +public class TransformRequestData implements Processor { + + @Autowired + private ObjectMapper objectMapper; + + @Override + public void process(Exchange exchange) throws Exception { + + TransactionChannelRequestDTO channelRequest = objectMapper.readValue(exchange.getProperty(CHANNEL_REQUEST, String.class), + TransactionChannelRequestDTO.class); + GSMATransaction gsmaTransaction = new GSMATransaction(); + + GsmaParty msisdnCreditParty = new GsmaParty(); + msisdnCreditParty.setKey(channelRequest.getPayee().getPartyIdInfo().getPartyIdType().toString().toLowerCase()); + msisdnCreditParty.setValue(channelRequest.getPayee().getPartyIdInfo().getPartyIdentifier()); + + GsmaParty[] creditParty = new GsmaParty[] { msisdnCreditParty }; + + GsmaParty msisdnDebitParty = new GsmaParty(); + msisdnDebitParty.setKey(channelRequest.getPayer().getPartyIdInfo().getPartyIdType().toString().toLowerCase()); + msisdnDebitParty.setValue(channelRequest.getPayer().getPartyIdInfo().getPartyIdentifier()); + + GsmaParty[] debitParty = new GsmaParty[] { msisdnDebitParty }; + + String amount = channelRequest.getAmount().getAmount(); + String currency = channelRequest.getAmount().getCurrency(); + + if (exchange.getProperty(GSMA_AUTHORIZATION_CODE, String.class) != null) { + gsmaTransaction.setOneTimeCode(exchange.getProperty(GSMA_AUTHORIZATION_CODE, String.class)); + } + + gsmaTransaction.setAmount(amount); + gsmaTransaction.setCurrency(currency); + gsmaTransaction.setCreditParty(creditParty); + gsmaTransaction.setDebitParty(debitParty); + + exchange.setProperty(TRANSACTION_BODY, gsmaTransaction); + } +} diff --git a/ph-ee-connector-gsma-mm/src/main/java/org/mifos/connector/gsma/util/GsmaUtil.java b/ph-ee-connector-gsma-mm/src/main/java/org/mifos/connector/gsma/util/GsmaUtil.java new file mode 100644 index 000000000..3965c5d72 --- /dev/null +++ b/ph-ee-connector-gsma-mm/src/main/java/org/mifos/connector/gsma/util/GsmaUtil.java @@ -0,0 +1,12 @@ +package org.mifos.connector.gsma.util; + +import org.apache.camel.Exchange; +import org.springframework.stereotype.Component; + +@Component +public class GsmaUtil { + + public void sampleUtil(Exchange exchange) { + + } +} diff --git a/ph-ee-connector-gsma-mm/src/main/java/org/mifos/connector/gsma/zeebe/ZeebeClientConfiguration.java b/ph-ee-connector-gsma-mm/src/main/java/org/mifos/connector/gsma/zeebe/ZeebeClientConfiguration.java new file mode 100644 index 000000000..c5d5d1c14 --- /dev/null +++ b/ph-ee-connector-gsma-mm/src/main/java/org/mifos/connector/gsma/zeebe/ZeebeClientConfiguration.java @@ -0,0 +1,22 @@ +package org.mifos.connector.gsma.zeebe; + +import io.camunda.zeebe.client.ZeebeClient; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class ZeebeClientConfiguration { + + @Value("${zeebe.broker.contactpoint}") + private String zeebeBrokerContactpoint; + + @Value("${zeebe.client.max-execution-threads}") + private int zeebeClientMaxThreads; + + @Bean + public ZeebeClient setup() { + return ZeebeClient.newClientBuilder().gatewayAddress(zeebeBrokerContactpoint).usePlaintext() + .numJobWorkerExecutionThreads(zeebeClientMaxThreads).build(); + } +} diff --git a/ph-ee-connector-gsma-mm/src/main/java/org/mifos/connector/gsma/zeebe/ZeebeExpressionVariables.java b/ph-ee-connector-gsma-mm/src/main/java/org/mifos/connector/gsma/zeebe/ZeebeExpressionVariables.java new file mode 100644 index 000000000..edf285caf --- /dev/null +++ b/ph-ee-connector-gsma-mm/src/main/java/org/mifos/connector/gsma/zeebe/ZeebeExpressionVariables.java @@ -0,0 +1,19 @@ +package org.mifos.connector.gsma.zeebe; + +public final class ZeebeExpressionVariables { + + public static final String SAMPLE_EXPRESSION_SUCCESS = "sampleExpressionSuccess"; + public static final String PARTY_LOOKUP_FAILED = "partyLookupFailed"; + public static final String PAYEE_LOOKUP_RETRY_COUNT = "payeeAccountStatusRetry"; + public static final String TRANSFER_RETRY_COUNT = "paymentTransferRetry"; + public static final String TRANSACTION_FAILED = "transactionFailed"; + public static final String TRANSFER_STATE = "transferState"; + public static final String LINK_CREATE_FAILED = "linkCreationFailed"; + public static final String LINK_CREATION_COUNT = "linkCreationRetryCount"; + public static final String NUMBER_OF_PAYMENTS = "numberOfPayments"; + public static final String BILLS_STATUS_ERROR = "billStatusError"; + public static final String QUOTE_RETRY_COUNT = "quoteRetryCount"; + + private ZeebeExpressionVariables() {} + +} diff --git a/ph-ee-connector-gsma-mm/src/main/java/org/mifos/connector/gsma/zeebe/ZeebeMessages.java b/ph-ee-connector-gsma-mm/src/main/java/org/mifos/connector/gsma/zeebe/ZeebeMessages.java new file mode 100644 index 000000000..12d75945f --- /dev/null +++ b/ph-ee-connector-gsma-mm/src/main/java/org/mifos/connector/gsma/zeebe/ZeebeMessages.java @@ -0,0 +1,14 @@ +package org.mifos.connector.gsma.zeebe; + +public final class ZeebeMessages { + + public static final String SAMPLE_MESSAGE = "sample_message"; + public static final String ACCOUNT_STATUS = "accountStatus"; + public static final String TRANSFER_RESPONSE = "transferResponse"; + public static final String LINK_RESPONSE = "linkResponse"; + public static final String GSMA_QUOTE_RESPONSE = "gsmaQuoteResponse"; + public static final String TRANSFER_MESSAGE = "transfer-message"; + + private ZeebeMessages() {} + +} diff --git a/ph-ee-connector-gsma-mm/src/main/java/org/mifos/connector/gsma/zeebe/ZeebeProcessStarter.java b/ph-ee-connector-gsma-mm/src/main/java/org/mifos/connector/gsma/zeebe/ZeebeProcessStarter.java new file mode 100644 index 000000000..6df60d03e --- /dev/null +++ b/ph-ee-connector-gsma-mm/src/main/java/org/mifos/connector/gsma/zeebe/ZeebeProcessStarter.java @@ -0,0 +1,50 @@ +package org.mifos.connector.gsma.zeebe; + +import io.camunda.zeebe.client.ZeebeClient; +import java.util.HashMap; +import java.util.Map; +import org.apache.camel.Exchange; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component +public class ZeebeProcessStarter { + + private static final Logger logger = LoggerFactory.getLogger(ZeebeProcessStarter.class); + + @Autowired + private ZeebeClient zeebeClient; + + public static void zeebeVariablesToCamelHeaders(Map variables, Exchange exchange, String... names) { + for (String name : names) { + Object value = variables.get(name); + if (value == null) { + logger.error("failed to find Zeebe variable name {}", name); + } + exchange.getIn().setHeader(name, value); + } + } + + public static void camelHeadersToZeebeVariables(Exchange exchange, Map variables, String... names) { + for (String name : names) { + String header = exchange.getIn().getHeader(name, String.class); + if (header == null) { + logger.error("failed to find Camel Exchange header {}", name); + } + variables.put(name, header); + } + } + + public void startZeebeWorkflow(String workflowId, Map extraVariables) { + Map variables = new HashMap<>(); + variables.putAll(extraVariables); + // TODO: Add extra variables if required. Such as origin date. + + zeebeClient.newCreateInstanceCommand().bpmnProcessId(workflowId).latestVersion() // .version(1) + .variables(variables).send().join(); + + logger.info("zeebee workflow instance from process {} started", workflowId); + } +} diff --git a/ph-ee-connector-gsma-mm/src/main/java/org/mifos/connector/gsma/zeebe/ZeebeVariables.java b/ph-ee-connector-gsma-mm/src/main/java/org/mifos/connector/gsma/zeebe/ZeebeVariables.java new file mode 100644 index 000000000..dbec0f11c --- /dev/null +++ b/ph-ee-connector-gsma-mm/src/main/java/org/mifos/connector/gsma/zeebe/ZeebeVariables.java @@ -0,0 +1,9 @@ +package org.mifos.connector.gsma.zeebe; + +public final class ZeebeVariables { + + private ZeebeVariables() {} + + public static final String QUOTE_SWITCH_RESULT = "quoteSwitchRequest"; + +} diff --git a/ph-ee-connector-gsma-mm/src/main/java/org/mifos/connector/gsma/zeebe/ZeebeeWorkers.java b/ph-ee-connector-gsma-mm/src/main/java/org/mifos/connector/gsma/zeebe/ZeebeeWorkers.java new file mode 100644 index 000000000..5d7bb4b1b --- /dev/null +++ b/ph-ee-connector-gsma-mm/src/main/java/org/mifos/connector/gsma/zeebe/ZeebeeWorkers.java @@ -0,0 +1,81 @@ +package org.mifos.connector.gsma.zeebe; + +import static org.mifos.connector.gsma.zeebe.ZeebeVariables.QUOTE_SWITCH_RESULT; + +import com.fasterxml.jackson.databind.ObjectMapper; +import io.camunda.zeebe.client.ZeebeClient; +import java.util.Map; +import javax.annotation.PostConstruct; +import org.mifos.connector.common.channel.dto.TransactionChannelRequestDTO; +import org.mifos.connector.common.mojaloop.dto.QuoteSwitchRequestDTO; +import org.mifos.connector.common.mojaloop.type.AmountType; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +@Component +public class ZeebeeWorkers { + + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Autowired + private ZeebeClient zeebeClient; + + @Autowired + private ZeebeProcessStarter zeebeProcessStarter; + + @Autowired + private ObjectMapper objectMapper; + + @Value("${zeebe.client.evenly-allocated-max-jobs}") + private int workerMaxJobs; + + @PostConstruct + public void setupWorkers() { + + zeebeClient.newWorker().jobType("payeeProcess").handler((client, job) -> { + logger.info("Job '{}' started from process '{}' with key {}", job.getType(), job.getBpmnProcessId(), job.getKey()); + + Map variables = job.getVariablesAsMap(); + TransactionChannelRequestDTO channelRequest = objectMapper.readValue((String) variables.get("channelRequest"), + TransactionChannelRequestDTO.class); + + QuoteSwitchRequestDTO quoteRequest = new QuoteSwitchRequestDTO(); + quoteRequest.setAmount(channelRequest.getAmount()); + quoteRequest.setPayee(channelRequest.getPayee()); + quoteRequest.setPayer(channelRequest.getPayer()); + quoteRequest.setAmountType(AmountType.SEND); + + variables.put(QUOTE_SWITCH_RESULT, quoteRequest); + zeebeProcessStarter.startZeebeWorkflow("gsma_payee_process", variables); + + client.newCompleteCommand(job.getKey()).send().join(); + }).name("payeeProcess").maxJobsActive(workerMaxJobs).open(); + + zeebeClient.newWorker().jobType("testerWorker").handler((client, job) -> { + logger.info("Job '{}' started from process '{}' with key {}", job.getType(), job.getBpmnProcessId(), job.getKey()); + client.newCompleteCommand(job.getKey()).send().join(); + }).name("testerWorker").maxJobsActive(workerMaxJobs).open(); + + zeebeClient.newWorker().jobType("sendTimeoutChannel").handler((client, job) -> { + logger.info("Job '{}' started from process '{}' with key {}", job.getType(), job.getBpmnProcessId(), job.getKey()); + logger.info("TRANSACTION TIMEOUT"); + client.newCompleteCommand(job.getKey()).send().join(); + }).name("sendTimeoutChannel").maxJobsActive(workerMaxJobs).open(); + + zeebeClient.newWorker().jobType("sendFailureChannel").handler((client, job) -> { + logger.info("Job '{}' started from process '{}' with key {}", job.getType(), job.getBpmnProcessId(), job.getKey()); + logger.info("TRANSACTION FAILED"); + client.newCompleteCommand(job.getKey()).send().join(); + }).name("sendFailureChannel").maxJobsActive(workerMaxJobs).open(); + + zeebeClient.newWorker().jobType("sendConfirmationChannel").handler((client, job) -> { + logger.info("Job '{}' started from process '{}' with key {}", job.getType(), job.getBpmnProcessId(), job.getKey()); + logger.info("TRANSACTION WAS SUCCESSFUL."); + client.newCompleteCommand(job.getKey()).send().join(); + }).name("sendConfirmationChannel").maxJobsActive(workerMaxJobs).open(); + + } +} diff --git a/ph-ee-connector-gsma-mm/src/main/resources/application.yml b/ph-ee-connector-gsma-mm/src/main/resources/application.yml new file mode 100644 index 000000000..5ec120f4f --- /dev/null +++ b/ph-ee-connector-gsma-mm/src/main/resources/application.yml @@ -0,0 +1,49 @@ +camel: + server-port: ${PORT:5000} + disable-ssl: true + host: "https://webhook.site/0d1bcf85-f42a-462e-809f-b1d4dca2a0cc" # Host URL for callback + springboot: + main-run-controller: true + dataformat: + json-jackson: + auto-discover-object-mapper: true + +bpmn: + flows: + some-flow: "SomeFlow-DFSPID" + +zeebe: + client: + max-execution-threads: 100 + number-of-workers: 8 + evenly-allocated-max-jobs: "#{${zeebe.client.max-execution-threads} / ${zeebe.client.number-of-workers}}" + ttl: 30000 + broker: + contactpoint: "127.0.0.1:26500" + +gsma: + auth: + host: https://sandbox.mobilemoneyapi.io/v1/oauth/accesstoken + client-key: bBvcGtIhyfAPNTMwuvACLyVrzcaTsyXR + client-secret: PAL6ekftxxg02O58 + api: + host: https://sandbox.mobilemoneyapi.io/oauth/simulator/v1.1/mm + account: /accounts + channel: https://ph-ee-connector-channel:8443 + +dfspids: "DFSPID" + + +management: +# server: +# port: 5000 + endpoint: + health: + enabled: true + probes: + enabled: true + liveness: + enabled: true + readiness: + enabled: true +# show-details: always diff --git a/ph-ee-connector-gsma-mm/src/main/resources/logback.xml b/ph-ee-connector-gsma-mm/src/main/resources/logback.xml new file mode 100644 index 000000000..adf11dd65 --- /dev/null +++ b/ph-ee-connector-gsma-mm/src/main/resources/logback.xml @@ -0,0 +1,24 @@ + + + + + + + + + ${CONSOLE_LOG_PATTERN} + utf8 + + + + + + + + + + + + + diff --git a/ph-ee-connector-gsma-mm/src/test/java/org/mifos/connector/gsma/TestUtil.java b/ph-ee-connector-gsma-mm/src/test/java/org/mifos/connector/gsma/TestUtil.java new file mode 100644 index 000000000..c0df8da32 --- /dev/null +++ b/ph-ee-connector-gsma-mm/src/test/java/org/mifos/connector/gsma/TestUtil.java @@ -0,0 +1,16 @@ +package org.mifos.connector.gsma; + +import java.util.UUID; +import org.junit.jupiter.api.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class TestUtil { + + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Test + public void test1() { + logger.info("{}", UUID.randomUUID().toString()); + } +} diff --git a/ph-ee-connector-mock-payment-schema/.circleci/config.yml b/ph-ee-connector-mock-payment-schema/.circleci/config.yml new file mode 100644 index 000000000..5d596e686 --- /dev/null +++ b/ph-ee-connector-mock-payment-schema/.circleci/config.yml @@ -0,0 +1,97 @@ +version: 2.1 +executors: + docker-executor: + docker: + - image: circleci/openjdk:17-buster-node-browsers-legacy + +jobs: + build_and_push_tag_image: + executor: docker-executor + environment: + JVM_OPTS: -Xmx512m + TERM: dumb + GITHUB_TOKEN: ${GITHUB_TOKEN} # Add the GitHub token as an environment variable + + steps: + - checkout + - setup_remote_docker: + version: 20.10.14 + - run: + name: Build and Push Docker tag Image + command: | + # Set environment variables + IMAGE_TAG=$CIRCLE_TAG + + # Check if the Docker image with the same tag already exists in Docker Hub + if curl -s -f -u "$DOCKERHUB_USERNAME":"$DOCKERHUB_PASSWORD" "https://hub.docker.com/v2/repositories/fynarfin/ph-ee-connector-mock-payment-schema/tags/$IMAGE_TAG" > /dev/null; then + echo "Skipping the build and push as the tag $IMAGE_TAG already exists in Docker Hub." + exit 0 + fi + + # Build and tag the Docker image + ./gradlew bootJar + docker build -t "fynarfin/ph-ee-connector-mock-payment-schema:$IMAGE_TAG" . + + # Push the Docker image to Docker Hub + docker login -u "$DOCKERHUB_USERNAME" -p "$DOCKERHUB_PASSWORD" + docker push "fynarfin/ph-ee-connector-mock-payment-schema:$IMAGE_TAG" + + # when: always # The job will be executed even if there's no match for the tag filter + + build_and_push_latest_image: + executor: docker-executor + environment: + JVM_OPTS: -Xmx512m + TERM: dumb + + steps: + - checkout + # Install Docker to build and push the image + - setup_remote_docker: + version: 20.10.14 + + # Build the Docker image + - run: + name: Build Docker image + command: | + ./gradlew bootJar + docker build -t fynarfin/ph-ee-connector-mock-payment-schema:latest . + if [ "$CIRCLE_BRANCH" != "develop" ]; then + PR_NUMBER=$(basename $CIRCLE_PULL_REQUEST) + PR_TITLE=$(curl -sSL "https://api.github.com/repos/fynarfin/$CIRCLE_PR_REPONAME/pulls/$PR_NUMBER" | jq -r '.title') + JIRA_STORY=$(echo $PR_TITLE | cut -d "[" -f2 | cut -d "]" -f1 | tr '[A-Z]' '[a-z]') + if [ -z "$JIRA_STORY" ]; then echo "Invalid PR title" && exit 1; else echo "Ticket NO: $JIRA_STORY"; fi + docker image tag fynarfin/$CIRCLE_PR_REPONAME:latest fynarfin/$CIRCLE_PR_REPONAME:$JIRA_STORY + fi + # Log in to DockerHub using environment variables + - run: + name: Login to DockerHub + command: echo "${DOCKERHUB_PASSWORD}" | docker login -u "${DOCKERHUB_USERNAME}" --password-stdin + + # Push the Docker image to DockerHub + - run: + name: Push Docker image to DockerHub + command: | + if [ "$CIRCLE_BRANCH" = "develop" ]; then + docker push fynarfin/ph-ee-connector-mock-payment-schema:latest + fi + if [ "$CIRCLE_BRANCH" != "develop" ]; then + PR_NUMBER=$(basename $CIRCLE_PULL_REQUEST) + PR_TITLE=$(curl -sSL "https://api.github.com/repos/fynarfin/$CIRCLE_PR_REPONAME/pulls/$PR_NUMBER" | jq -r '.title') + JIRA_STORY=$(echo $PR_TITLE | cut -d "[" -f2 | cut -d "]" -f1 | tr '[A-Z]' '[a-z]') + docker push fynarfin/$CIRCLE_PR_REPONAME:${JIRA_STORY} + fi + +workflows: + version: 2 + build-and-push: + jobs: + - build_and_push_tag_image: + filters: + tags: + only: /^v\d+\.\d+\.\d+$/ # Match tags in the format v1.2.3 + context: + - DOCKER + - build_and_push_latest_image: + context: + - DOCKER diff --git a/ph-ee-connector-mock-payment-schema/.github/pull_request_template.md b/ph-ee-connector-mock-payment-schema/.github/pull_request_template.md new file mode 100644 index 000000000..bcf84d8d0 --- /dev/null +++ b/ph-ee-connector-mock-payment-schema/.github/pull_request_template.md @@ -0,0 +1,22 @@ +## Description + +* PR title should have jira ticket enclosed in `[]`.
+Format: ``` [jira_ticket] description```
+ex: [phee-123] PR title. +* Add a link to the Jira ticket. +* Describe the changes made and why they were made. + +## Checklist + +Please make sure these boxes are checked before submitting your pull request - thanks! +- [ ] Followed the PR title naming convention mentioned above. + +- [ ] Design related bullet points or design document link related to this PR added in the description above. + +- [ ] Updated corresponding Postman Collection or Api documentation for the changes in this PR. + +- [ ] Created/updated unit or integration tests for verifying the changes made. + +- [ ] Added required Swagger annotation and update API documentation with details of any API changes if applicable + +- [ ] Followed the naming conventions as given in https://docs.google.com/document/d/1Q4vaMSzrTxxh9TS0RILuNkSkYCxotuYk1Xe0CMIkkCU/edit?usp=sharing diff --git a/ph-ee-connector-mock-payment-schema/.gitignore b/ph-ee-connector-mock-payment-schema/.gitignore new file mode 100644 index 000000000..c2065bc26 --- /dev/null +++ b/ph-ee-connector-mock-payment-schema/.gitignore @@ -0,0 +1,37 @@ +HELP.md +.gradle +build/ +!gradle/wrapper/gradle-wrapper.jar +!**/src/main/**/build/ +!**/src/test/**/build/ + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache +bin/ +!**/src/main/**/bin/ +!**/src/test/**/bin/ + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr +out/ +!**/src/main/**/out/ +!**/src/test/**/out/ + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ + +### VS Code ### +.vscode/ diff --git a/ph-ee-connector-mock-payment-schema/Dockerfile b/ph-ee-connector-mock-payment-schema/Dockerfile new file mode 100644 index 000000000..d7b682aec --- /dev/null +++ b/ph-ee-connector-mock-payment-schema/Dockerfile @@ -0,0 +1,5 @@ +FROM openjdk:17-bullseye +EXPOSE 5000 + +COPY build/libs/*.jar . +CMD java -jar *.jar diff --git a/ph-ee-connector-mock-payment-schema/README.md b/ph-ee-connector-mock-payment-schema/README.md new file mode 100644 index 000000000..da96ae90d --- /dev/null +++ b/ph-ee-connector-mock-payment-schema/README.md @@ -0,0 +1,13 @@ +Mock Payement Scehma Connector for Payment Transfers + +## Checkstyle +Use below command to execute the checkstyle test. +```shell +./gradlew checkstyleMain +``` + +## Spotless +Use below command to execute the spotless apply. +```shell +./gradlew spotlessApply +``` diff --git a/ph-ee-connector-mock-payment-schema/build.gradle b/ph-ee-connector-mock-payment-schema/build.gradle new file mode 100644 index 000000000..a4fbbfb6a --- /dev/null +++ b/ph-ee-connector-mock-payment-schema/build.gradle @@ -0,0 +1,336 @@ +/* + * This file was generated by the Gradle 'init' task. + */ + +plugins { + id 'java' + id 'maven-publish' + id 'eclipse' + id 'org.springframework.boot' version '2.5.5' + id 'io.spring.dependency-management' version '1.1.0' + id 'checkstyle' + id 'com.diffplug.spotless' version '6.19.0' + id "org.springdoc.openapi-gradle-plugin" version "1.6.0" + id 'net.ltgt.errorprone' version '3.1.0' +} + +repositories { + // mavenLocal() + maven { + url = uri('https://repo.maven.apache.org/maven2') + } + maven { + url "https://jfrog.sandbox.fynarfin.io/artifactory/fyn-libs-snapshot" + } + + maven { + url = uri('https://jfrog.sandbox.fynarfin.io/artifactory/fyn-libs-snapshot') + } +} + +apply plugin:'com.diffplug.spotless' +spotless { + format 'misc', { + target '**/*.md', '**/*.properties', '**/.gitignore', '**/.openapi-generator-ignore', '**/*.yml', '**/*.xml', '**/**.json', '**/*.sql' + targetExclude '**/build/**', '**/bin/**', '**/.settings/**', '**/.idea/**', '**/.gradle/**', '**/gradlew.bat', '**/licenses/**', '**/banner.txt', '.vscode/**' + indentWithSpaces(4) + endWithNewline() + trimTrailingWhitespace() + } + + groovyGradle { + target '*.gradle', '**/*.gradle' + targetExclude '**/build/**' + greclipse() + indentWithSpaces(4) + endWithNewline() + trimTrailingWhitespace() + } + + lineEndings 'UNIX' +} + +ext { + springBootVersion = '2.6.2' +} + +dependencies { + implementation 'com.google.code.gson:gson:2.8.9' + implementation 'org.json:json:20210307' + implementation 'org.mifos:ph-ee-connector-common:1.4.1-SNAPSHOT' + implementation 'org.springframework.boot:spring-boot-starter:2.5.2' + implementation 'org.springframework.boot:spring-boot-starter-web:2.5.2' + implementation "org.springframework.boot:spring-boot-starter-actuator:$springBootVersion" + implementation 'org.springframework:spring-web:5.3.19' + implementation 'com.amazonaws:aws-java-sdk:1.11.486' + implementation 'com.azure:azure-storage-blob:12.12.0' + implementation ('io.camunda:zeebe-client-java:8.1.23') + implementation 'com.fasterxml.jackson.dataformat:jackson-dataformat-csv:2.12.0' + implementation 'org.springframework.kafka:spring-kafka:2.9.2' + compileOnly 'org.projectlombok:lombok:1.18.24' + annotationProcessor 'org.projectlombok:lombok:1.18.24' + checkstyle 'com.puppycrawl.tools:checkstyle:10.9.3' + checkstyle 'com.github.sevntu-checkstyle:sevntu-checks:1.44.1' + implementation 'com.diffplug.gradle.spotless:spotless:2.4.1' + implementation 'com.diffplug.spotless:spotless-plugin-gradle:6.17.0' + implementation 'io.rest-assured:rest-assured:4.4.0' + testImplementation 'io.cucumber:cucumber-junit:7.8.1' + testImplementation 'io.cucumber:cucumber-spring:7.8.1' + testImplementation 'io.cucumber:cucumber-java:7.8.1' + testImplementation 'org.springframework.boot:spring-boot-starter-test:2.5.4' + testImplementation "com.google.truth:truth:1.1.3" + testImplementation 'com.google.code.gson:gson:2.9.0' + implementation "org.springdoc:springdoc-openapi-ui:1.6.11" +} + +configure(this) { + // NOTE: order matters! + apply plugin: 'java' + apply plugin: 'idea' + apply plugin: 'eclipse' + apply plugin: 'checkstyle' + apply plugin: 'net.ltgt.errorprone' + configurations { + implementation.setCanBeResolved(true) + api.setCanBeResolved(true) + } + tasks.withType(JavaCompile) { + options.compilerArgs += [ + "-Xlint:unchecked", + "-Xlint:cast", + "-Xlint:auxiliaryclass", + "-Xlint:deprecation", + "-Xlint:dep-ann", + "-Xlint:divzero", + "-Xlint:empty", + "-Xlint:exports", + "-Xlint:fallthrough", + "-Xlint:finally", + "-Xlint:module", + "-Xlint:opens", + "-Xlint:options", + "-Xlint:overloads", + "-Xlint:overrides", + "-Xlint:path", + "-Xlint:processing", + "-Xlint:removal", + "-Xlint:requires-automatic", + "-Xlint:requires-transitive-automatic", + "-Xlint:try", + "-Xlint:varargs", + "-Xlint:preview", + "-Xlint:static", + // -Werror needs to be disabled because EclipseLink's static weaving doesn't generate warning-free code + // and during an IntelliJ recompilation, it fails + //"-Werror", + "-Xmaxwarns", + 1500, + "-Xmaxerrs", + 1500 + ] + options.deprecation = true + } + // Configuration for the spotless plugin + // https://github.com/diffplug/spotless/tree/main/plugin-gradle + spotless { + java { + targetExclude '**/build/**', '**/bin/**', '**/out/**' + importOrder() //sort imports alphabetically + removeUnusedImports() + eclipse().configFile "$rootDir/ph-ee-connector-mock-payment-schema/config/mock-formatter.xml" + endWithNewline() + trimTrailingWhitespace() + // Enforce style modifier order + custom 'Modifier ordering', { + def modifierRanking = [ + public : 1, + protected : 2, + private : 3, + abstract : 4, + default : 5, + static : 6, + final : 7, + transient : 8, + volatile : 9, + synchronized: 10, + native : 11, + strictfp : 12] + // Find any instance of multiple modifiers. Lead with a non-word character to avoid + // accidental matching against for instance, "an alternative default value" + it.replaceAll(/\W(?:public |protected |private |abstract |default |static |final |transient |volatile |synchronized |native |strictfp ){2,}/, { + // Do not replace the leading non-word character. Identify the modifiers + it.replaceAll(/(?:public |protected |private |abstract |default |static |final |transient |volatile |synchronized |native |strictfp ){2,}/, { + // Sort the modifiers according to the ranking above + it.split().sort({ modifierRanking[it] }).join(' ') + ' ' + } + ) + } + ) + } + } + lineEndings 'UNIX' + } + // If we are running Gradle within Eclipse to enhance classes, + // set the classes directory to point to Eclipse's default build directory + if (project.hasProperty('env') && project.getProperty('env') == 'eclipse') { + sourceSets.main.java.outputDir = file("$projectDir/bin/main") + } + // Configuration for the Checkstyle plugin + // https://docs.gradle.org/current/userguide/checkstyle_plugin.html + dependencies { + checkstyle 'com.puppycrawl.tools:checkstyle:10.3.1' + checkstyle 'com.github.sevntu-checkstyle:sevntu-checks:1.42.0' + } + // Configuration for the errorprone plugin + // https://github.com/tbroyer/gradle-errorprone-plugin + dependencies { + errorprone "com.google.errorprone:error_prone_core:2.20.0" + } + + tasks.withType(JavaCompile) { + options.errorprone { + enabled = project.gradle.startParameter.taskNames.contains('build') || project.gradle.startParameter.taskNames.contains('check') + disableWarningsInGeneratedCode = true + excludedPaths = ".*/build/.*" + disable( + // TODO Remove disabled checks from this list, by fixing remaining usages + "UnusedVariable", + "TypeParameterUnusedInFormals", + "EmptyBlockTag", + "MissingSummary", + "InvalidParam", + "ReturnFromVoid", + "AlmostJavadoc", + "InvalidBlockTag", + "JavaUtilDate", // TODO FINERACT-1298 + "ReturnValueIgnored", + "DirectInvocationOnMock", + "CanIgnoreReturnValueSuggester", + "SameNameButDifferent", // Until errorprone recognizes Lombok + "MultiVariableDeclaration", // Until errorprone recognizes Lombok + "UnnecessaryDefaultInEnumSwitch" // FINERACT-1911 + ) + error( + "DefaultCharset", + "RemoveUnusedImports", + "WaitNotInLoop", + "ThreeLetterTimeZoneID", + "VariableNameSameAsType", + "UnnecessaryParentheses", + "MultipleTopLevelClasses", + "MixedMutabilityReturnType", + "AssertEqualsArgumentOrderChecker", + "EmptySetMultibindingContributions", + "BigDecimalEquals", + "MixedArrayDimensions", + "PackageLocation", + "UseBinds", + "BadImport", + "IntLongMath", + "FloatCast", + "ReachabilityFenceUsage", + "StreamResourceLeak", + "TruthIncompatibleType", + "ByteBufferBackingArray", + "OrphanedFormatString", + "CatchAndPrintStackTrace", + "ObjectToString", + "StringSplitter", + "AssertThrowsMultipleStatements", + "BoxedPrimitiveConstructor", + "EmptyCatch", + "BoxedPrimitiveEquality", + "SynchronizeOnNonFinalField", + "WildcardImport", + "PrivateConstructorForNoninstantiableModule", + "ClassCanBeStatic", + "ClassNewInstance", + "UnnecessaryStaticImport", + "UnsafeFinalization", + "JavaTimeDefaultTimeZone", + "JodaPlusMinusLong", + "SwitchDefault", + "VarTypeName", + "ArgumentSelectionDefectChecker", + "CompareToZero", + "InjectOnConstructorOfAbstractClass", + "ImmutableEnumChecker", + "NarrowingCompoundAssignment", + "MissingCasesInEnumSwitch", + "ReferenceEquality", + "UndefinedEquals", + "UnescapedEntity", + "ModifyCollectionInEnhancedForLoop", + "NonCanonicalType", + "InvalidInlineTag", + "MutablePublicArray", + "StaticAssignmentInConstructor", + "ProtectedMembersInFinalClass", + "OperatorPrecedence", + "EqualsGetClass", + "EqualsUnsafeCast", + "DoubleBraceInitialization", + "UnusedNestedClass", + "UnusedMethod", + "ModifiedButNotUsed", + "InconsistentCapitalization", + "MissingOverride", + ) + } + } +} +group = 'org.mifos' +version = '0.0.1-SNAPSHOT' +description = 'ph-ee-processor-bulk' +sourceCompatibility = JavaVersion.VERSION_17 + +publishing { + publications { + maven(MavenPublication) { + from(components.java) + } + } +} + +tasks.withType(JavaCompile) { + options.encoding = 'UTF-8' +} + +tasks.named('test') { + useJUnitPlatform() +} + + +configurations { + cucumberRuntime { + extendsFrom testImplementation + } +} + + +task cucumberCli() { + dependsOn assemble, testClasses + doLast { + javaexec { + main = "io.cucumber.core.cli.Main" + classpath = configurations.cucumberRuntime + sourceSets.main.output + sourceSets.test.output + args = [ + '--plugin', + 'pretty', + '--plugin', + 'html:target/cucumber-report.html', + '--glue', + 'org.mifos.processor.cucumber', + 'src/test/java/resources' + ] + } + } +} + +openApi { + apiDocsUrl.set("http://localhost:8080/v3/api-docs") + outputDir.set(file("src/main/java/docs")) + outputFileName.set("swagger.yaml") +} +task bootRun() { +} diff --git a/ph-ee-connector-mock-payment-schema/config/checkstyle/checkstyle.xml b/ph-ee-connector-mock-payment-schema/config/checkstyle/checkstyle.xml new file mode 100644 index 000000000..b9350ad75 --- /dev/null +++ b/ph-ee-connector-mock-payment-schema/config/checkstyle/checkstyle.xml @@ -0,0 +1,240 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ph-ee-connector-mock-payment-schema/config/checkstyle/suppressions.xml b/ph-ee-connector-mock-payment-schema/config/checkstyle/suppressions.xml new file mode 100644 index 000000000..f4e5b54c3 --- /dev/null +++ b/ph-ee-connector-mock-payment-schema/config/checkstyle/suppressions.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + diff --git a/ph-ee-connector-mock-payment-schema/config/mock-cleanup.xml b/ph-ee-connector-mock-payment-schema/config/mock-cleanup.xml new file mode 100644 index 000000000..8c3cb1c13 --- /dev/null +++ b/ph-ee-connector-mock-payment-schema/config/mock-cleanup.xml @@ -0,0 +1,71 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ph-ee-connector-mock-payment-schema/config/mock-formatter.xml b/ph-ee-connector-mock-payment-schema/config/mock-formatter.xml new file mode 100644 index 000000000..8633a10b4 --- /dev/null +++ b/ph-ee-connector-mock-payment-schema/config/mock-formatter.xml @@ -0,0 +1,366 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ph-ee-connector-mock-payment-schema/gradle/wrapper/gradle-wrapper.jar b/ph-ee-connector-mock-payment-schema/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 000000000..7454180f2 Binary files /dev/null and b/ph-ee-connector-mock-payment-schema/gradle/wrapper/gradle-wrapper.jar differ diff --git a/ph-ee-connector-mock-payment-schema/gradle/wrapper/gradle-wrapper.properties b/ph-ee-connector-mock-payment-schema/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 000000000..ffed3a254 --- /dev/null +++ b/ph-ee-connector-mock-payment-schema/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-bin.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/ph-ee-connector-mock-payment-schema/gradlew b/ph-ee-connector-mock-payment-schema/gradlew new file mode 100755 index 000000000..1b6c78733 --- /dev/null +++ b/ph-ee-connector-mock-payment-schema/gradlew @@ -0,0 +1,234 @@ +#!/bin/sh + +# +# Copyright © 2015-2021 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit + +APP_NAME="Gradle" +APP_BASE_NAME=${0##*/} + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/ph-ee-connector-mock-payment-schema/gradlew.bat b/ph-ee-connector-mock-payment-schema/gradlew.bat new file mode 100644 index 000000000..ac1b06f93 --- /dev/null +++ b/ph-ee-connector-mock-payment-schema/gradlew.bat @@ -0,0 +1,89 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/ph-ee-connector-mock-payment-schema/settings.gradle b/ph-ee-connector-mock-payment-schema/settings.gradle new file mode 100644 index 000000000..cf8bbe0b0 --- /dev/null +++ b/ph-ee-connector-mock-payment-schema/settings.gradle @@ -0,0 +1 @@ +rootProject.name = 'ph-ee-connector-mockPaymentSchema' diff --git a/ph-ee-connector-mock-payment-schema/src/main/java/org/mifos/connector/mockpaymentschema/MockPaymentSchemaApplication.java b/ph-ee-connector-mock-payment-schema/src/main/java/org/mifos/connector/mockpaymentschema/MockPaymentSchemaApplication.java new file mode 100644 index 000000000..9491b41a9 --- /dev/null +++ b/ph-ee-connector-mock-payment-schema/src/main/java/org/mifos/connector/mockpaymentschema/MockPaymentSchemaApplication.java @@ -0,0 +1,16 @@ +package org.mifos.connector.mockpaymentschema; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.ComponentScan; + +@SpringBootApplication +@ComponentScan("org.mifos.connector.mockpaymentschema") +@SuppressWarnings("checkstyle:HideUtilityClassConstructor") +public class MockPaymentSchemaApplication { + + public static void main(String[] args) { + SpringApplication.run(MockPaymentSchemaApplication.class, args); + } + +} diff --git a/ph-ee-connector-mock-payment-schema/src/main/java/org/mifos/connector/mockpaymentschema/api/BatchApi.java b/ph-ee-connector-mock-payment-schema/src/main/java/org/mifos/connector/mockpaymentschema/api/BatchApi.java new file mode 100644 index 000000000..bca163e5e --- /dev/null +++ b/ph-ee-connector-mock-payment-schema/src/main/java/org/mifos/connector/mockpaymentschema/api/BatchApi.java @@ -0,0 +1,59 @@ +package org.mifos.connector.mockpaymentschema.api; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.mifos.connector.mockpaymentschema.schema.AuthorizationRequest; +import org.mifos.connector.mockpaymentschema.schema.BatchDTO; +import org.mifos.connector.mockpaymentschema.schema.BatchDetailResponse; +import org.mifos.connector.mockpaymentschema.service.BatchService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestHeader; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +@RestController +public class BatchApi { + + @Autowired + private BatchService batchService; + + protected Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Tag(name = "GOV") + @Operation(summary = "Batch Auth-z API") + @PostMapping("/batches/{batchId}") + public ResponseEntity getAuthorization(@PathVariable String batchId, + @RequestHeader("X-Client-Correlation-ID") String clientCorrelationId, @RequestBody AuthorizationRequest authorizationRequest, + @RequestParam(value = "command") String command, @RequestHeader(value = "X-CallbackURL") String callbackURL) { + if (!"authorize".equals(command)) { + return new ResponseEntity<>(HttpStatus.BAD_REQUEST); + } + try { + batchService.getAuthorization(batchId, clientCorrelationId, authorizationRequest, callbackURL); + } catch (Exception e) { + logger.error(e.toString()); + return new ResponseEntity<>(HttpStatus.BAD_REQUEST); + } + return new ResponseEntity<>(HttpStatus.ACCEPTED); + } + + @GetMapping(value = "/batches/{batchId}/summary", produces = MediaType.APPLICATION_JSON_VALUE) + public BatchDTO batchSummary(@PathVariable String batchId) { + return batchService.getBatchSummary(batchId); + } + + @GetMapping(value = "/batches/{batchId}/detail", produces = MediaType.APPLICATION_JSON_VALUE) + public BatchDetailResponse batchDetail(@PathVariable String batchId, @RequestParam(value = "pageNo", defaultValue = "0") Integer pageNo, + @RequestParam(value = "pageSize", defaultValue = "10") Integer pageSize) { + return batchService.getBatchDetails(batchId, pageNo, pageSize); + } +} diff --git a/ph-ee-connector-mock-payment-schema/src/main/java/org/mifos/connector/mockpaymentschema/camel/config/Client.java b/ph-ee-connector-mock-payment-schema/src/main/java/org/mifos/connector/mockpaymentschema/camel/config/Client.java new file mode 100644 index 000000000..635be0e72 --- /dev/null +++ b/ph-ee-connector-mock-payment-schema/src/main/java/org/mifos/connector/mockpaymentschema/camel/config/Client.java @@ -0,0 +1,34 @@ +package org.mifos.connector.mockpaymentschema.camel.config; + +public class Client { + + private String tenant; + private String clientId; + private String clientSecret; + + public Client() {} + + public String getTenant() { + return tenant; + } + + public void setTenant(String tenant) { + this.tenant = tenant; + } + + public String getClientId() { + return clientId; + } + + public void setClientId(String clientId) { + this.clientId = clientId; + } + + public String getClientSecret() { + return clientSecret; + } + + public void setClientSecret(String clientSecret) { + this.clientSecret = clientSecret; + } +} diff --git a/ph-ee-connector-mock-payment-schema/src/main/java/org/mifos/connector/mockpaymentschema/camel/config/ClientProperties.java b/ph-ee-connector-mock-payment-schema/src/main/java/org/mifos/connector/mockpaymentschema/camel/config/ClientProperties.java new file mode 100644 index 000000000..d11b32f2b --- /dev/null +++ b/ph-ee-connector-mock-payment-schema/src/main/java/org/mifos/connector/mockpaymentschema/camel/config/ClientProperties.java @@ -0,0 +1,28 @@ +package org.mifos.connector.mockpaymentschema.camel.config; + +import java.util.ArrayList; +import java.util.List; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +@Component +@ConfigurationProperties(prefix = "identity.channel") +public class ClientProperties { + + private List clients = new ArrayList<>(); + + public ClientProperties() {} + + public List getClients() { + return clients; + } + + public void setClients(List clients) { + this.clients = clients; + } + + public Client getClient(String tenant) { + return getClients().stream().filter(t -> t.getTenant().equals(tenant)).findFirst() + .orElseThrow(() -> new RuntimeException("Client for tenant: " + tenant + ", not configuerd!")); + } +} diff --git a/ph-ee-connector-mock-payment-schema/src/main/java/org/mifos/connector/mockpaymentschema/config/AsyncConfiguration.java b/ph-ee-connector-mock-payment-schema/src/main/java/org/mifos/connector/mockpaymentschema/config/AsyncConfiguration.java new file mode 100644 index 000000000..f62a413e3 --- /dev/null +++ b/ph-ee-connector-mock-payment-schema/src/main/java/org/mifos/connector/mockpaymentschema/config/AsyncConfiguration.java @@ -0,0 +1,33 @@ +package org.mifos.connector.mockpaymentschema.config; + +import java.util.concurrent.Executor; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.scheduling.annotation.EnableAsync; +import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; + +@Configuration +@EnableAsync +public class AsyncConfiguration { + + @Value("${async.core_pool_size}") + public Integer corePoolSize; + + @Value("${async.max_pool_size}") + public Integer maxPoolSize; + + @Value("${async.queue_capacity}") + public Integer queueCapacity; + + @Bean(name = "asyncExecutor") + public Executor asyncExecutor() { + ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); + executor.setCorePoolSize(corePoolSize); + executor.setMaxPoolSize(maxPoolSize); + executor.setQueueCapacity(queueCapacity); + executor.setThreadNamePrefix("AsyncThread-"); + executor.initialize(); + return executor; + } +} diff --git a/ph-ee-connector-mock-payment-schema/src/main/java/org/mifos/connector/mockpaymentschema/schema/AuthorizationRequest.java b/ph-ee-connector-mock-payment-schema/src/main/java/org/mifos/connector/mockpaymentschema/schema/AuthorizationRequest.java new file mode 100644 index 000000000..317a64114 --- /dev/null +++ b/ph-ee-connector-mock-payment-schema/src/main/java/org/mifos/connector/mockpaymentschema/schema/AuthorizationRequest.java @@ -0,0 +1,22 @@ +package org.mifos.connector.mockpaymentschema.schema; + +import java.math.BigDecimal; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +public class AuthorizationRequest { + + private String batchId; + + private String payerIdentifier; + + private String currency; + + private BigDecimal amount; +} diff --git a/ph-ee-connector-mock-payment-schema/src/main/java/org/mifos/connector/mockpaymentschema/schema/AuthorizationResponse.java b/ph-ee-connector-mock-payment-schema/src/main/java/org/mifos/connector/mockpaymentschema/schema/AuthorizationResponse.java new file mode 100644 index 000000000..aedc60712 --- /dev/null +++ b/ph-ee-connector-mock-payment-schema/src/main/java/org/mifos/connector/mockpaymentschema/schema/AuthorizationResponse.java @@ -0,0 +1,19 @@ +package org.mifos.connector.mockpaymentschema.schema; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +public class AuthorizationResponse { + + private String clientCorrelationId; + + private String status; + + private String reason; +} diff --git a/ph-ee-connector-mock-payment-schema/src/main/java/org/mifos/connector/mockpaymentschema/schema/BatchDTO.java b/ph-ee-connector-mock-payment-schema/src/main/java/org/mifos/connector/mockpaymentschema/schema/BatchDTO.java new file mode 100644 index 000000000..ca5e590e1 --- /dev/null +++ b/ph-ee-connector-mock-payment-schema/src/main/java/org/mifos/connector/mockpaymentschema/schema/BatchDTO.java @@ -0,0 +1,50 @@ +package org.mifos.connector.mockpaymentschema.schema; + +import java.math.BigDecimal; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +public class BatchDTO { + + private String batchId; + + private String requestId; + + private Long total; + + private Long ongoing; + + private Long failed; + + private Long successful; + + private BigDecimal totalAmount; + + private BigDecimal successfulAmount; + + private BigDecimal pendingAmount; + + private BigDecimal failedAmount; + + private String file; + + private String notes; + + private String createdAt; + + private String status; + + private String modes; + + private String purpose; + + private String failPercentage; + + private String successPercentage; +} diff --git a/ph-ee-connector-mock-payment-schema/src/main/java/org/mifos/connector/mockpaymentschema/schema/BatchDetailResponse.java b/ph-ee-connector-mock-payment-schema/src/main/java/org/mifos/connector/mockpaymentschema/schema/BatchDetailResponse.java new file mode 100644 index 000000000..8de1cb932 --- /dev/null +++ b/ph-ee-connector-mock-payment-schema/src/main/java/org/mifos/connector/mockpaymentschema/schema/BatchDetailResponse.java @@ -0,0 +1,37 @@ +package org.mifos.connector.mockpaymentschema.schema; + +import java.util.List; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +public class BatchDetailResponse { + + private List content; + + private org.mifos.connector.mockpaymentschema.schema.PageableDTO pageable; + + private Long totalPages; + + private Long totalElements; + + private boolean last; + + private boolean first; + + private org.mifos.connector.mockpaymentschema.schema.SortDTO sort; + + private Long numberOfElements; + + private Long size; + + private Long number; + + private boolean empty; + +} diff --git a/ph-ee-connector-mock-payment-schema/src/main/java/org/mifos/connector/mockpaymentschema/schema/PageableDTO.java b/ph-ee-connector-mock-payment-schema/src/main/java/org/mifos/connector/mockpaymentschema/schema/PageableDTO.java new file mode 100644 index 000000000..b7eeafc82 --- /dev/null +++ b/ph-ee-connector-mock-payment-schema/src/main/java/org/mifos/connector/mockpaymentschema/schema/PageableDTO.java @@ -0,0 +1,25 @@ +package org.mifos.connector.mockpaymentschema.schema; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +public class PageableDTO { + + private org.mifos.connector.mockpaymentschema.schema.SortDTO sort; + + private Long pageSize; + + private Long pageNumber; + + private Long offset; + + private boolean unpaged; + + private boolean paged; +} diff --git a/ph-ee-connector-mock-payment-schema/src/main/java/org/mifos/connector/mockpaymentschema/schema/SortDTO.java b/ph-ee-connector-mock-payment-schema/src/main/java/org/mifos/connector/mockpaymentschema/schema/SortDTO.java new file mode 100644 index 000000000..9f4826c4c --- /dev/null +++ b/ph-ee-connector-mock-payment-schema/src/main/java/org/mifos/connector/mockpaymentschema/schema/SortDTO.java @@ -0,0 +1,19 @@ +package org.mifos.connector.mockpaymentschema.schema; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +public class SortDTO { + + private boolean sorted; + + private boolean unsorted; + + private boolean empty; +} diff --git a/ph-ee-connector-mock-payment-schema/src/main/java/org/mifos/connector/mockpaymentschema/schema/Transfer.java b/ph-ee-connector-mock-payment-schema/src/main/java/org/mifos/connector/mockpaymentschema/schema/Transfer.java new file mode 100644 index 000000000..808d87abb --- /dev/null +++ b/ph-ee-connector-mock-payment-schema/src/main/java/org/mifos/connector/mockpaymentschema/schema/Transfer.java @@ -0,0 +1,70 @@ +package org.mifos.connector.mockpaymentschema.schema; + +import java.math.BigDecimal; +import java.util.Date; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +public class Transfer { + + private String id; + + private Long workflowInstanceKey; + + private String transactionId; + + private Date startedAt; + private Date completedAt; + + private TransferStatus status; + + private String statusDetail; + + private String payeeDfspId; + + private String payeePartyId; + + private String payeePartyIdType; + + private BigDecimal payeeFee; + + private String payeeFeeCurrency; + + private String payeeQuoteCode; + + private String payerDfspId; + + private String payerPartyId; + + private String payerPartyIdType; + + private BigDecimal payerFee; + + private String payerFeeCurrency; + + private String payerQuoteCode; + + private BigDecimal amount; + + private String currency; + + private String direction; + + private String errorInformation; + + private String batchId; + + private String clientCorrelationId; + + public Transfer(Long workflowInstanceKey) { + this.workflowInstanceKey = workflowInstanceKey; + this.status = TransferStatus.IN_PROGRESS; + } + +} diff --git a/ph-ee-connector-mock-payment-schema/src/main/java/org/mifos/connector/mockpaymentschema/schema/TransferStatus.java b/ph-ee-connector-mock-payment-schema/src/main/java/org/mifos/connector/mockpaymentschema/schema/TransferStatus.java new file mode 100644 index 000000000..41e84baf8 --- /dev/null +++ b/ph-ee-connector-mock-payment-schema/src/main/java/org/mifos/connector/mockpaymentschema/schema/TransferStatus.java @@ -0,0 +1,5 @@ +package org.mifos.connector.mockpaymentschema.schema; + +public enum TransferStatus { + COMPLETED, FAILED, IN_PROGRESS, UNKNOWN +} diff --git a/ph-ee-connector-mock-payment-schema/src/main/java/org/mifos/connector/mockpaymentschema/service/BatchService.java b/ph-ee-connector-mock-payment-schema/src/main/java/org/mifos/connector/mockpaymentschema/service/BatchService.java new file mode 100644 index 000000000..6295a16de --- /dev/null +++ b/ph-ee-connector-mock-payment-schema/src/main/java/org/mifos/connector/mockpaymentschema/service/BatchService.java @@ -0,0 +1,124 @@ +package org.mifos.connector.mockpaymentschema.service; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.UUID; +import java.util.concurrent.ThreadLocalRandom; +import org.mifos.connector.mockpaymentschema.schema.AuthorizationRequest; +import org.mifos.connector.mockpaymentschema.schema.AuthorizationResponse; +import org.mifos.connector.mockpaymentschema.schema.BatchDTO; +import org.mifos.connector.mockpaymentschema.schema.BatchDetailResponse; +import org.mifos.connector.mockpaymentschema.schema.Transfer; +import org.mifos.connector.mockpaymentschema.schema.TransferStatus; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Service; + +@Service +public class BatchService { + + @Value("${threshold.amount}") + private String thresholdAmount; + + @Autowired + private org.mifos.connector.mockpaymentschema.service.SendCallbackService sendCallbackService; + + protected Logger logger = LoggerFactory.getLogger(this.getClass()); + + private String payerPartyId = "835322416"; + + private String payeePartyId = "27713803912"; + + private int successTxnCount = 9; + + @Async("asyncExecutor") + public void getAuthorization(String batchId, String clientCorrelationId, AuthorizationRequest authRequest, String callbackUrl) { + AuthorizationResponse response = new AuthorizationResponse(); + + if (authRequest.getAmount().compareTo(BigDecimal.valueOf(Long.valueOf(thresholdAmount))) >= 0) { + response.setStatus("N"); + response.setClientCorrelationId(clientCorrelationId); + response.setReason("Error getting authorization for the request"); + } else { + response.setClientCorrelationId(clientCorrelationId); + response.setStatus("Y"); + } + try { + logger.info("Sending callback: {}", callbackUrl); + sendCallbackService.sendCallback(new ObjectMapper().writeValueAsString(response), callbackUrl); + } catch (JsonProcessingException e) { + logger.error(e.toString()); + } + } + + public BatchDTO getBatchSummary(String batchId) { + return successfulBatchSummaryResponse(batchId); + } + + public BatchDetailResponse getBatchDetails(String batchId, int pageNo, int pageSize) { + List transactions = getTransactions(batchId); + int toIndex = pageNo * pageSize; + int fromIndex = toIndex - pageSize; + toIndex = Math.min(toIndex, transactions.size()); + BatchDetailResponse batchDetailResponse = new BatchDetailResponse(); + batchDetailResponse.setContent(transactions.subList(fromIndex, toIndex)); + return batchDetailResponse; + } + + private BatchDTO successfulBatchSummaryResponse(String batchId) { + Long total = 10L; + Long ongoing = 1L; + Long failed = 1L; + Long successful = 8L; + BigDecimal totalAmount = BigDecimal.valueOf(100); + BigDecimal ongoingAmount = BigDecimal.valueOf(0); + BigDecimal failedAmount = BigDecimal.valueOf(10); + BigDecimal successfulAmount = BigDecimal.valueOf(90); + String status = "Pending"; + String successPercentage = "90"; + String failedPercentage = "10"; + + return new BatchDTO(batchId, null, total, ongoing, failed, successful, totalAmount, successfulAmount, ongoingAmount, failedAmount, + null, null, null, status, null, null, failedPercentage, successPercentage); + } + + private List getTransactions(String batchId) { + List transactionList = new ArrayList<>(); + + for (int index = 0; index < 10; index++) { + Transfer transfer; + + if (successTxnCount > 0) { + transfer = getSingleTransaction(index, ThreadLocalRandom.current().nextLong(), UUID.randomUUID().toString(), + TransferStatus.COMPLETED, batchId); + } else { + transfer = getSingleTransaction(index, ThreadLocalRandom.current().nextLong(), UUID.randomUUID().toString(), + TransferStatus.IN_PROGRESS, batchId); + } + transactionList.add(transfer); + } + return transactionList; + } + + private Transfer getSingleTransaction(int index, Long workflowInstanceKey, String requestId, TransferStatus status, String batchId) { + String id = String.valueOf(index); + Date startedAt = new Date(1685536200000L); + Date completedAt = new Date(1685536268000L); + String payerPartyIdType = "MSISDN"; + String payeePartyIdType = "MSISDN"; + BigDecimal amount = BigDecimal.valueOf(10); + String currency = "USD"; + String direction = "OUTGOING"; + + return new Transfer(id, workflowInstanceKey, requestId, startedAt, completedAt, status, null, null, payeePartyId, payeePartyIdType, + null, null, null, null, payerPartyId, payerPartyIdType, null, null, null, amount, currency, direction, null, batchId, null); + } + +} diff --git a/ph-ee-connector-mock-payment-schema/src/main/java/org/mifos/connector/mockpaymentschema/service/SendCallbackService.java b/ph-ee-connector-mock-payment-schema/src/main/java/org/mifos/connector/mockpaymentschema/service/SendCallbackService.java new file mode 100644 index 000000000..bc2b1cda9 --- /dev/null +++ b/ph-ee-connector-mock-payment-schema/src/main/java/org/mifos/connector/mockpaymentschema/service/SendCallbackService.java @@ -0,0 +1,17 @@ +package org.mifos.connector.mockpaymentschema.service; + +import io.restassured.RestAssured; +import io.restassured.builder.RequestSpecBuilder; +import io.restassured.http.ContentType; +import io.restassured.specification.RequestSpecification; +import org.springframework.stereotype.Service; + +@Service +public class SendCallbackService { + + public void sendCallback(String body, String callbackURL) { + RequestSpecification requestSpec = new RequestSpecBuilder().build(); + requestSpec.relaxedHTTPSValidation(); + RestAssured.given(requestSpec).baseUri(callbackURL).contentType(ContentType.JSON).body(body).when().post(); + } +} diff --git a/ph-ee-connector-mock-payment-schema/src/main/java/org/mifos/connector/mockpaymentschema/zeebe/ZeebeClientConfiguration.java b/ph-ee-connector-mock-payment-schema/src/main/java/org/mifos/connector/mockpaymentschema/zeebe/ZeebeClientConfiguration.java new file mode 100644 index 000000000..0f7051285 --- /dev/null +++ b/ph-ee-connector-mock-payment-schema/src/main/java/org/mifos/connector/mockpaymentschema/zeebe/ZeebeClientConfiguration.java @@ -0,0 +1,29 @@ +package org.mifos.connector.mockpaymentschema.zeebe; + +import io.camunda.zeebe.client.ZeebeClient; +import java.time.Duration; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +@ConditionalOnExpression("${zeebe.enabled:true}") +public class ZeebeClientConfiguration { + + @Value("${zeebe.broker.contactpoint}") + private String zeebeBrokerContactpoint; + + @Value("${zeebe.client.max-execution-threads}") + private int zeebeClientMaxThreads; + + @Value("${zeebe.client.poll-interval}") + private int zeebeClientPollInterval; + + @Bean + public ZeebeClient setup() { + return ZeebeClient.newClientBuilder().gatewayAddress(zeebeBrokerContactpoint).usePlaintext() + .defaultJobPollInterval(Duration.ofMillis(zeebeClientPollInterval)).defaultJobWorkerMaxJobsActive(2000) + .numJobWorkerExecutionThreads(zeebeClientMaxThreads).build(); + } +} diff --git a/ph-ee-connector-mock-payment-schema/src/main/java/org/mifos/connector/mockpaymentschema/zeebe/ZeebeUtil.java b/ph-ee-connector-mock-payment-schema/src/main/java/org/mifos/connector/mockpaymentschema/zeebe/ZeebeUtil.java new file mode 100644 index 000000000..0ec74a928 --- /dev/null +++ b/ph-ee-connector-mock-payment-schema/src/main/java/org/mifos/connector/mockpaymentschema/zeebe/ZeebeUtil.java @@ -0,0 +1,14 @@ +package org.mifos.connector.mockpaymentschema.zeebe; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public final class ZeebeUtil { + + private ZeebeUtil() {} + + private static Logger logger = LoggerFactory.getLogger(ZeebeUtil.class); + private static ObjectMapper objectMapper = new ObjectMapper(); + +} diff --git a/ph-ee-connector-mock-payment-schema/src/main/java/org/mifos/connector/mockpaymentschema/zeebe/ZeebeVariables.java b/ph-ee-connector-mock-payment-schema/src/main/java/org/mifos/connector/mockpaymentschema/zeebe/ZeebeVariables.java new file mode 100644 index 000000000..ed338b23b --- /dev/null +++ b/ph-ee-connector-mock-payment-schema/src/main/java/org/mifos/connector/mockpaymentschema/zeebe/ZeebeVariables.java @@ -0,0 +1,55 @@ +package org.mifos.connector.mockpaymentschema.zeebe; + +import java.util.HashMap; +import java.util.Map; +import org.mifos.connector.common.ams.dto.TransferActionType; + +public final class ZeebeVariables { + + public static final Map ACTION_FAILURE_MAP = new HashMap<>(); + + public static final String ACCOUNT = "account"; + public static final String ACCOUNT_CURRENCY = "accountCurrency"; + public static final String ACCOUNT_ID = "accountId"; + public static final String CHANNEL_REQUEST = "channelRequest"; + public static final String ERROR_INFORMATION = "errorInformation"; + public static final String EXTERNAL_ACCOUNT_ID = "externalAccountId"; + public static final String INTEROP_REGISTRATION_FAILED = "interopRegistrationFailed"; + public static final String LOCAL_QUOTE_FAILED = "localQuoteFailed"; + public static final String LOCAL_QUOTE_RESPONSE = "localQuoteResponse"; + public static final String PARTY_ID = "partyId"; + public static final String PARTY_ID_TYPE = "partyIdType"; + public static final String PAYEE_PARTY_RESPONSE = "payeePartyResponse"; + public static final String QUOTE_FAILED = "quoteFailed"; + public static final String QUOTE_SWITCH_REQUEST = "quoteSwitchRequest"; + public static final String QUOTE_SWITCH_REQUEST_AMOUNT = "quoteSwitchRequestAmount"; + public static final String TENANT_ID = "tenantId"; + public static final String BOOK_TRANSACTION_ID = "bookTransactionId"; + public static final String TRANSACTION_ID = "transactionId"; + public static final String TRANSFER_CODE = "transferCode"; + public static final String TRANSFER_CREATE_FAILED = "transferCreateFailed"; + public static final String TRANSFER_PREPARE_FAILED = "transferPrepareFailed"; + public static final String TRANSFER_RELEASE_FAILED = "transferReleaseFailed"; + public static final String TRANSFER_RESPONSE_PREFIX = "transferResponse"; + + public static final String PARTY_LOOKUP_FAILED = "partyLookupFailed"; + + public static final String TRANSFER_SETTLEMENT_FAILED = "transferSettlementFailed"; + public static final String PAYEE_LOOKUP_RETRY_COUNT = "payeeAccountStatusRetry"; + public static final String TRANSFER_RETRY_COUNT = "paymentTransferRetry"; + public static final String TRANSACTION_FAILED = "transactionFailed"; + public static final String TRANSFER_STATE = "transferState"; + public static final String LINK_CREATE_FAILED = "linkCreationFailed"; + public static final String LINK_CREATION_COUNT = "linkCreationRetryCount"; + public static final String NUMBER_OF_PAYMENTS = "numberOfPayments"; + public static final String BILLS_STATUS_ERROR = "billStatusError"; + public static final String QUOTE_RETRY_COUNT = "quoteRetryCount"; + + static { + ACTION_FAILURE_MAP.put(TransferActionType.PREPARE.name(), TRANSFER_PREPARE_FAILED); + ACTION_FAILURE_MAP.put(TransferActionType.CREATE.name(), TRANSFER_CREATE_FAILED); + ACTION_FAILURE_MAP.put(TransferActionType.RELEASE.name(), TRANSFER_RELEASE_FAILED); + } + + private ZeebeVariables() {} +} diff --git a/ph-ee-connector-mock-payment-schema/src/main/java/org/mifos/connector/mockpaymentschema/zeebe/ZeebeeWorkers.java b/ph-ee-connector-mock-payment-schema/src/main/java/org/mifos/connector/mockpaymentschema/zeebe/ZeebeeWorkers.java new file mode 100644 index 000000000..9375e9a5b --- /dev/null +++ b/ph-ee-connector-mock-payment-schema/src/main/java/org/mifos/connector/mockpaymentschema/zeebe/ZeebeeWorkers.java @@ -0,0 +1,223 @@ +package org.mifos.connector.mockpaymentschema.zeebe; + +import static org.mifos.connector.mockpaymentschema.zeebe.ZeebeVariables.PARTY_LOOKUP_FAILED; +import static org.mifos.connector.mockpaymentschema.zeebe.ZeebeVariables.TRANSACTION_FAILED; +import static org.mifos.connector.mockpaymentschema.zeebe.ZeebeVariables.TRANSACTION_ID; +import static org.mifos.connector.mockpaymentschema.zeebe.ZeebeVariables.TRANSFER_CODE; +import static org.mifos.connector.mockpaymentschema.zeebe.ZeebeVariables.TRANSFER_CREATE_FAILED; +import static org.mifos.connector.mockpaymentschema.zeebe.ZeebeVariables.TRANSFER_PREPARE_FAILED; +import static org.mifos.connector.mockpaymentschema.zeebe.ZeebeVariables.TRANSFER_RELEASE_FAILED; +import static org.mifos.connector.mockpaymentschema.zeebe.ZeebeVariables.TRANSFER_SETTLEMENT_FAILED; + +import io.camunda.zeebe.client.ZeebeClient; +import io.camunda.zeebe.client.api.response.ActivatedJob; +import java.time.Duration; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; +import javax.annotation.PostConstruct; +import org.json.JSONObject; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +@Component +@SuppressWarnings("FutureReturnValueIgnored") +public class ZeebeeWorkers { + + public static final String WORKER_PARTY_LOOKUP_LOCAL = "party-lookup-local-"; + public static final String WORKER_PAYEE_COMMIT_TRANSFER = "payee-commit-transfer-"; + public static final String WORKER_PAYEE_QUOTE = "payee-quote-"; + public static final String WORKER_PAYER_LOCAL_QUOTE = "payer-local-quote-"; + public static final String WORKER_INTEROP_PARTY_REGISTRATION = "interop-party-registration-"; + public static final String WORKER_PAYEE_DEPOSIT_TRANSFER = "payee-deposit-transfer-"; + + private Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Autowired(required = false) + private ZeebeClient zeebeClient; + + @Value("${ams.local.enabled:false}") + private boolean isAmsLocalEnabled; + + @Value("#{'${dfspids}'.split(',')}") + private List dfspids; + + @Value("${zeebe.client.evenly-allocated-max-jobs}") + private int workerMaxJobs; + + @Value("${mockFailure.percentage}") + private int mockFailurePercentage; + + @PostConstruct + public void setupWorkers() { + zeebeClient.newWorker().jobType("mockPayerBlockFunds").handler((client, job) -> { + logger.info("Job '{}' started from process '{}' with key {}", job.getType(), job.getBpmnProcessId(), job.getKey()); + logWorkerDetails(job); + if (isAmsLocalEnabled) { + Map variables = job.getVariablesAsMap(); + variables = setSuccessOrFailure("block", variables); + variables.put(TRANSFER_CREATE_FAILED, false); + variables.put("payeeTenantId", job.getVariablesAsMap().get("payeeTenantId")); + variables.put(TRANSFER_CODE, "000"); + zeebeClient.newCompleteCommand(job.getKey()).variables(variables).send(); + logger.info("Zeebe variable {}", job.getVariablesAsMap()); + } else { + Map variables = new HashMap<>(); + variables.put(TRANSFER_PREPARE_FAILED, false); + zeebeClient.newCompleteCommand(job.getKey()).variables(variables).send(); + } + }).name("mockPayerBlockFunds").maxJobsActive(workerMaxJobs).open(); + + zeebeClient.newWorker().jobType("mockBookFunds").handler((client, job) -> { + logWorkerDetails(job); + if (isAmsLocalEnabled) { + Map variables = new HashMap<>(); + variables = setSuccessOrFailure("book", variables); + variables.put(TRANSFER_CREATE_FAILED, false); + variables.put("payeeTenantId", job.getVariablesAsMap().get("payeeTenantId")); + variables.put(TRANSFER_CODE, "000"); + zeebeClient.newCompleteCommand(job.getKey()).variables(variables).send(); + logger.info("Zeebe variable {}", job.getVariablesAsMap()); + } else { + Map variables = new HashMap<>(); + variables.put("transferCreateFailed", false); + zeebeClient.newCompleteCommand(job.getKey()).variables(variables).send(); + } + }).name("mockBookFunds").maxJobsActive(workerMaxJobs).open(); + + zeebeClient.newWorker().jobType("mockReleaseBlock").handler((client, job) -> { + logWorkerDetails(job); + if (isAmsLocalEnabled) { + Map variables = job.getVariablesAsMap(); + variables = setSuccessOrFailure("release", variables); + variables.put(TRANSFER_CREATE_FAILED, false); + variables.put("transferReleaseFailed", false); + variables.put("payeeTenantId", job.getVariablesAsMap().get("payeeTenantId")); + variables.put(TRANSFER_CODE, "000"); + zeebeClient.newCompleteCommand(job.getKey()).variables(variables).send(); + + logger.info("Zeebe variable {}", job.getVariablesAsMap()); + } else { + Map variables = new HashMap<>(); + variables.put("transferReleaseFailed", false); + zeebeClient.newCompleteCommand(job.getKey()).variables(variables).send(); + } + }).name("mockReleaseBlock").maxJobsActive(workerMaxJobs).open(); + + zeebeClient.newWorker().jobType("mockPayeeLookup").handler((client, job) -> { + logger.info("Job '{}' started from process '{}' with key {}", job.getType(), job.getBpmnProcessId(), job.getKey()); + Map variables = job.getVariablesAsMap(); + client.newCompleteCommand(job.getKey()).variables(variables).send().join(); + }).name("mockPayeeLookup").maxJobsActive(workerMaxJobs).open(); + + zeebeClient.newWorker().jobType("mockPayeeAccountStatus").handler((client, job) -> { + logger.info("Job '{}' started from process '{}' with key {}", job.getType(), job.getBpmnProcessId(), job.getKey()); + Map variables = job.getVariablesAsMap(); + variables = setSuccessOrFailure("payeeLookup", variables); + client.newCompleteCommand(job.getKey()).variables(variables).send().join(); + }).name("mockPayeeAccountStatus").maxJobsActive(workerMaxJobs).open(); + + zeebeClient.newWorker().jobType("mockInitiateTransfer").handler((client, job) -> { + logger.info("Job '{}' started from process '{}' with key {}", job.getType(), job.getBpmnProcessId(), job.getKey()); + Map variables = job.getVariablesAsMap(); + variables = setSuccessOrFailure("transaction", variables); + variables.put("externalId", UUID.randomUUID()); + // added to pass the transaction request api not found error + logger.debug("{} {}", variables.get(TRANSACTION_FAILED), variables.get(TRANSACTION_ID)); + + zeebeClient.newPublishMessageCommand().messageName("mockTransferResponse") + .correlationKey((String) variables.get(TRANSACTION_ID)).timeToLive(Duration.ofMillis(30000)).send().join(); + client.newCompleteCommand(job.getKey()).variables(variables).send().join(); + }).name("mockInitiateTransfer").maxJobsActive(workerMaxJobs).open(); + + zeebeClient.newWorker().jobType("getMockStatus").handler((client, job) -> { + logger.debug("Job '{}' started from process '{}' with key {}", job.getType(), job.getBpmnProcessId(), job.getKey()); + Map variables = job.getVariablesAsMap(); + variables = setSuccessOrFailure("transaction", variables); + // added to pass the transaction request api not found error + zeebeClient.newPublishMessageCommand().messageName("mockTransferResponse") + .correlationKey(variables.get(TRANSACTION_ID).toString()).timeToLive(Duration.ofMillis(30000)).variables(variables) + .send(); + client.newCompleteCommand(job.getKey()).variables(variables).send().join(); + }).name("getMockStatus").maxJobsActive(workerMaxJobs).open(); + + zeebeClient.newWorker().jobType("transfer-validation-ams").handler((client, job) -> { + logger.info("Job '{}' started from process '{}' with key {}", job.getType(), job.getBpmnProcessId(), job.getKey()); + Map variables; + variables = job.getVariablesAsMap(); + variables.put(PARTY_LOOKUP_FAILED, false); + zeebeClient.newCompleteCommand(job.getKey()).variables(variables).send().join(); + }).name("transfer-validation-ams").maxJobsActive(workerMaxJobs).open(); + + zeebeClient.newWorker().jobType("transfer-clearing-ams").handler((client, job) -> { + logger.info("Job '{}' started from process '{}' with key {}", job.getType(), job.getBpmnProcessId(), job.getKey()); + Map variables; + variables = job.getVariablesAsMap(); + variables.put(TRANSFER_SETTLEMENT_FAILED, false); + zeebeClient.newCompleteCommand(job.getKey()).variables(variables).send().join(); + }).name("transfer-clearing-ams").maxJobsActive(workerMaxJobs).open(); + + } + + private Map setSuccessOrFailure(String scenario, Map variables) { + int successProbability = (int) (Math.random() * 100); + logger.info("Success probability {}", successProbability); + switch (scenario) { + case "block": + if (successProbability > 0 && successProbability <= mockFailurePercentage) { + variables.put(TRANSFER_PREPARE_FAILED, true); + } else { + variables.put(TRANSFER_PREPARE_FAILED, false); + } + break; + case "book": + if (successProbability > 0 && successProbability <= mockFailurePercentage) { + variables.put(TRANSFER_CREATE_FAILED, true); + } else { + variables.put(TRANSFER_CREATE_FAILED, false); + } + break; + case "release": + if (successProbability > 0 && successProbability <= mockFailurePercentage) { + variables.put(TRANSFER_RELEASE_FAILED, true); + } else { + variables.put(TRANSFER_RELEASE_FAILED, false); + } + break; + case "payeeLookup": + if (successProbability > 0 && successProbability <= mockFailurePercentage) { + variables.put(PARTY_LOOKUP_FAILED, true); + } else { + variables.put(PARTY_LOOKUP_FAILED, false); + } + break; + case "transaction": + if (successProbability > 0 && successProbability <= mockFailurePercentage) { + variables.put(TRANSACTION_FAILED, true); + } else { + variables.put(TRANSACTION_FAILED, false); + } + break; + + } + return variables; + } + + private void logWorkerDetails(ActivatedJob job) { + JSONObject jsonJob = new JSONObject(); + jsonJob.put("bpmnProcessId", job.getBpmnProcessId()); + jsonJob.put("elementInstanceKey", job.getElementInstanceKey()); + jsonJob.put("jobKey", job.getKey()); + jsonJob.put("jobType", job.getType()); + jsonJob.put("workflowElementId", job.getElementId()); + jsonJob.put("workflowDefinitionVersion", job.getProcessDefinitionVersion()); + jsonJob.put("workflowKey", job.getProcessDefinitionKey()); + jsonJob.put("workflowInstanceKey", job.getProcessInstanceKey()); + logger.info("Job started: {}", jsonJob.toString(4)); + } + +} diff --git a/ph-ee-connector-mock-payment-schema/src/main/resources/application.yml b/ph-ee-connector-mock-payment-schema/src/main/resources/application.yml new file mode 100644 index 000000000..3e85667bd --- /dev/null +++ b/ph-ee-connector-mock-payment-schema/src/main/resources/application.yml @@ -0,0 +1,53 @@ +camel: + server-port: 5000 + springboot: + main-run-controller: true + dataformat: + json-jackson: + auto-discover-object-mapper: true + +dfspids: "DFSPIDS" + +server: + port: 8080 + +zeebe: + client: + max-execution-threads: 50 + evenly-allocated-max-jobs: 1000 + poll-interval: 10 + # max-execution-threads: 100 + # number-of-workers: 8 + # evenly-allocated-max-jobs: "#{${zeebe.client.max-execution-threads} / ${zeebe.client.number-of-workers}}" + broker: + contactpoint: "127.0.0.1:26500" + +ams: + local: + server-cert-check: false + enabled: true + +mockFailure: + percentage: 50 + +logging: + level: + root: INFO + +async: + core_pool_size: 10 + max_pool_size: 10 + queue_capacity: 100 + +threshold: + amount: 20000 + +management: + endpoint: + health: + probes: + enabled: true + liveness: + enabled: true + readiness: + enabled: true diff --git a/ph-ee-connector-mojaloop-java/.circleci/config.yml b/ph-ee-connector-mojaloop-java/.circleci/config.yml new file mode 100644 index 000000000..32bd0ae58 --- /dev/null +++ b/ph-ee-connector-mojaloop-java/.circleci/config.yml @@ -0,0 +1,99 @@ +version: 2.1 +executors: + docker-executor: + docker: + - image: circleci/openjdk:17-buster-node-browsers-legacy + +jobs: + build_and_push_tag_image: + executor: docker-executor + environment: + JVM_OPTS: -Xmx512m + TERM: dumb + GITHUB_TOKEN: ${GITHUB_TOKEN} # Add the GitHub token as an environment variable + + steps: + - checkout + - setup_remote_docker: + version: 20.10.14 + - run: + name: Build and Push Docker tag Image + command: | + # Set environment variables + IMAGE_TAG=$CIRCLE_TAG + + # Check if the Docker image with the same tag already exists in Docker Hub + if curl -s -f -u "$DOCKERHUB_USERNAME":"$DOCKERHUB_PASSWORD" "https://hub.docker.com/v2/repositories/fynarfin/ph-ee-connector-mojaloop/tags/$IMAGE_TAG" > /dev/null; then + echo "Skipping the build and push as the tag $IMAGE_TAG already exists in Docker Hub." + exit 0 + fi + + # Build and tag the Docker image + ./gradlew bootJar + docker build -t "fynarfin/ph-ee-connector-mojaloop:$IMAGE_TAG" . + + # Push the Docker image to Docker Hub + docker login -u "$DOCKERHUB_USERNAME" -p "$DOCKERHUB_PASSWORD" + docker push "fynarfin/ph-ee-connector-mojaloop:$IMAGE_TAG" + + # when: always # The job will be executed even if there's no match for the tag filter + + build_and_push_latest_image: + executor: docker-executor + environment: + JVM_OPTS: -Xmx512m + TERM: dumb + + steps: + - checkout + # Install Docker to build and push the image + - setup_remote_docker: + version: 20.10.14 + + # Build the Docker image + - run: + name: Build Docker image + command: | + ./gradlew bootJar + docker build -t fynarfin/ph-ee-connector-mojaloop:latest . + if [ "$CIRCLE_BRANCH" != "develop" ]; then + PR_NUMBER=$(basename $CIRCLE_PULL_REQUEST) + PR_TITLE=$(curl -sSL "https://api.github.com/repos/fynarfin/$CIRCLE_PR_REPONAME/pulls/$PR_NUMBER" | jq -r '.title') + JIRA_STORY=$(echo $PR_TITLE | cut -d "[" -f2 | cut -d "]" -f1 | tr '[A-Z]' '[a-z]') + if [ -z "$JIRA_STORY" ]; then echo "Invalid PR title" && exit 1; else echo "Ticket NO: $JIRA_STORY"; fi + docker image tag fynarfin/ph-ee-connector-mojaloop:latest fynarfin/ph-ee-connector-mojaloop:$JIRA_STORY + fi + + # Log in to DockerHub using environment variables + - run: + name: Login to DockerHub + command: echo "${DOCKERHUB_PASSWORD}" | docker login -u "${DOCKERHUB_USERNAME}" --password-stdin + + # Push the Docker image to DockerHub + - run: + name: Push Docker image to DockerHub + command: | + if [ "$CIRCLE_BRANCH" = "develop" ]; then + docker push fynarfin/ph-ee-connector-mojaloop:latest + fi + if [ "$CIRCLE_BRANCH" != "develop" ]; then + PR_NUMBER=$(basename $CIRCLE_PULL_REQUEST) + PR_TITLE=$(curl -sSL "https://api.github.com/repos/fynarfin/$CIRCLE_PR_REPONAME/pulls/$PR_NUMBER" | jq -r '.title') + JIRA_STORY=$(echo $PR_TITLE | cut -d "[" -f2 | cut -d "]" -f1 | tr '[A-Z]' '[a-z]') + docker push fynarfin/ph-ee-connector-mojaloop:${JIRA_STORY} + fi + +workflows: + version: 2 + build-and-push: + jobs: + - build_and_push_tag_image: + filters: + tags: + only: /^v\d+\.\d+\.\d+$/ # Match tags in the format v1.2.3 + context: + - DOCKER + - build_and_push_latest_image: + context: + - DOCKER + diff --git a/ph-ee-connector-mojaloop-java/.github/ISSUE_TEMPLATE/DMP_2024.yml b/ph-ee-connector-mojaloop-java/.github/ISSUE_TEMPLATE/DMP_2024.yml new file mode 100644 index 000000000..f729c7318 --- /dev/null +++ b/ph-ee-connector-mojaloop-java/.github/ISSUE_TEMPLATE/DMP_2024.yml @@ -0,0 +1,264 @@ +name: DMP 2024 Project Template +description: List a new project for Dedicated Mentoring Program (DMP) 2024 +title: "[DMP 2024]: " +labels: ["DMP 2024"] +body: + - type: textarea + id: ticket-description + validations: + required: true + attributes: + label: Ticket Contents + value: | + ## Description + [Provide a brief description of the feature, including why it is needed and what it will accomplish.] + + - type: textarea + id: ticket-goals + validations: + required: true + attributes: + label: Goals & Mid-Point Milestone + description: List the goals of the feature. Please add the goals that must be achieved by Mid-point check-in i.e 1.5 months into the coding period. + value: | + ## Goals + - [ ] [Goal 1] + - [ ] [Goal 2] + - [ ] [Goal 3] + - [ ] [Goal 4] + - [ ] [Goals Achieved By Mid-point Milestone] + + - type: textarea + id: ticket-setup + attributes: + label: Setup/Installation + description: Please list or link setup or installation guide (if any) + + - type: textarea + id: ticket-expected-outcome + attributes: + label: Expected Outcome + description: Describe in detail what the final product or result should look like and how it should behave. + + - type: textarea + id: ticket-acceptance-criteria + attributes: + label: Acceptance Criteria + description: List the acceptance criteria for this feature. + + - type: textarea + id: ticket-implementation-details + validations: + required: true + attributes: + label: Implementation Details + description: List any technical details about the proposed implementation, including any specific technologies that will be used. + + - type: textarea + id: ticket-mockups + attributes: + label: Mockups/Wireframes + description: Include links to any visual aids, mockups, wireframes, or diagrams that help illustrate what the final product should look like. This is not always necessary, but can be very helpful in many cases. + + - type: input + id: ticket-product + attributes: + label: Product Name + placeholder: Enter Product Name + validations: + required: true + + - type: dropdown + id: ticket-organisation + attributes: + label: Organisation Name + description: Enter Organisation Name + multiple: false + options: + - Bandhu + - Belongg + - Blockster Global (CREDBEL) + - Civis + - Dhwani + - Dhiway + - EGov + - EkShop Marketplace + - FIDE + - If Me + - Key Education Foundation + - Norwegian Meteorological Institute + - Planet Read + - Project Second Chance + - Reap Benefit + - SamagraX + - ShikshaLokam + - Tech4Dev + - Tekdi + - The Mifos Initiative + - Tibil + - Ushahidi + - Arghyam + - Piramal Swasthya Management Research Institute + - Belongg AI + validations: + required: true + + - type: dropdown + id: ticket-governance-domain + attributes: + label: Domain + options: + - ⁠Healthcare + - ⁠Education + - Financial Inclusion + - ⁠Livelihoods + - ⁠Skilling + - ⁠Learning & Development + - ⁠Agriculture + - ⁠Service Delivery + - Open Source Library + - Water + validations: + required: true + + + - type: dropdown + id: ticket-technical-skills-required + attributes: + label: Tech Skills Needed + description: Select the technologies needed for this ticket (use Ctrl or Command to select multiple) + multiple: true + options: + - .NET + - Angular + - Artificial Intelligence + - ASP.NET + - AWS + - Babel + - Bootstrap + - C# + - Chart.js + - CI/CD + - Computer Vision + - CORS + - cURL + - Cypress + - D3.js + - Database + - Debugging + - Design + - DevOps + - Django + - Docker + - Electron + - ESLint + - Express.js + - Feature + - Flask + - Go + - GraphQL + - HTML + - Ionic + - Jest + - Java + - JavaScript + - Jenkins + - JWT + - Kubernetes + - Laravel + - Machine Learning + - Maintenance + - Markdown + - Material-UI + - Microservices + - MongoDB + - Mobile + - Mockups + - Mocha + - Natural Language Processing + - NestJS + - Node.js + - NUnit + - OAuth + - Performance Improvement + - Prettier + - Python + - Question + - React + - React Native + - Redux + - RESTful APIs + - Ruby + - Ruby on Rails + - Rust + - Scala + - Security + - Selenium + - SEO + - Serverless + - Solidity + - Spring Boot + - SQL + - Swagger + - Tailwind CSS + - Test + - Testing Library + - Three.js + - TypeScript + - UI/UX/Design + - Virtual Reality + - Vue.js + - WebSockets + - Webpack + - Other + validations: + required: true + + - type: textarea + id: ticket-mentors + attributes: + label: Mentor(s) + description: Please tag relevant mentors for the ticket + validations: + required: true + + - type: dropdown + id: ticket-category + attributes: + label: Category + description: Choose the categories that best describe your ticket + multiple: true + options: + - API + - Analytics + - Accessibility + - Backend + - Breaking Change + - Beginner Friendly + - Configuration + - CI/CD + - Database + - Data Science + - Deprecation + - Documentation + - Delpoyment + - Frontend + - Internationalization + - Localization + - Machine Learning + - Maintenance + - Mobile + - Performance Improvement + - Question + - Refactoring + - Research + - Needs Reproduction + - SEO + - Security + - Testing + - AI + - Other + validations: + required: true + + diff --git a/ph-ee-connector-mojaloop-java/.github/pull_request_template.md b/ph-ee-connector-mojaloop-java/.github/pull_request_template.md new file mode 100644 index 000000000..98a182a2e --- /dev/null +++ b/ph-ee-connector-mojaloop-java/.github/pull_request_template.md @@ -0,0 +1,22 @@ +## Description + +* PR title should have jira ticket enclosed in `[]`.
+Format: ``` [jira_ticket] description```
+ex: [phee-123] PR title. +* Add a link to the Jira ticket. +* Describe the changes made and why they were made. + +## Checklist + +Please make sure these boxes are checked before submitting your pull request - thanks! +- [ ] Followed the PR title naming convention mentioned above. + +- [ ] Design related bullet points or design document link related to this PR added in the description above. + +- [ ] Updated corresponding Postman Collection or Api documentation for the changes in this PR. + +- [ ] Created/updated unit or integration tests for verifying the changes made. + +- [ ] Added required Swagger annotation and update API documentation with details of any API changes if applicable + +- [ ] Followed the naming conventions as given in https://docs.google.com/document/d/1Q4vaMSzrTxxh9TS0RILuNkSkYCxotuYk1Xe0CMIkkCU/edit?usp=sharing diff --git a/ph-ee-connector-mojaloop-java/.gitignore b/ph-ee-connector-mojaloop-java/.gitignore new file mode 100644 index 000000000..da0226431 --- /dev/null +++ b/ph-ee-connector-mojaloop-java/.gitignore @@ -0,0 +1,34 @@ +target/ +HELP.md +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/**/target/ +!**/src/test/**/target/ +.gradle +build/ +!gradle/wrapper/gradle-wrapper.jar +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +.DS_Store +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ + +### VS Code ### +.vscode/ diff --git a/ph-ee-connector-mojaloop-java/Dockerfile b/ph-ee-connector-mojaloop-java/Dockerfile new file mode 100644 index 000000000..4f25df9d7 --- /dev/null +++ b/ph-ee-connector-mojaloop-java/Dockerfile @@ -0,0 +1,6 @@ +FROM openjdk:17 +EXPOSE 5000 + +COPY build/libs/*.jar . +CMD java -jar *.jar + diff --git a/ph-ee-connector-mojaloop-java/Jenkinsfile b/ph-ee-connector-mojaloop-java/Jenkinsfile new file mode 100644 index 000000000..9efc46793 --- /dev/null +++ b/ph-ee-connector-mojaloop-java/Jenkinsfile @@ -0,0 +1,17 @@ +pipeline { + agent any + stages { + stage('build') { + steps { + sh 'mvn --version' + sh 'mvn -U clean package' + } + } + stage('docker') { + steps { + sh 'docker build . -t paymenthubee.azurecr.io/phee/connector-mojaloop-java' + sh 'docker push paymenthubee.azurecr.io/phee/connector-mojaloop-java' + } + } + } +} \ No newline at end of file diff --git a/ph-ee-connector-mojaloop-java/LICENSE b/ph-ee-connector-mojaloop-java/LICENSE new file mode 100644 index 000000000..a612ad981 --- /dev/null +++ b/ph-ee-connector-mojaloop-java/LICENSE @@ -0,0 +1,373 @@ +Mozilla Public License Version 2.0 +================================== + +1. Definitions +-------------- + +1.1. "Contributor" + means each individual or legal entity that creates, contributes to + the creation of, or owns Covered Software. + +1.2. "Contributor Version" + means the combination of the Contributions of others (if any) used + by a Contributor and that particular Contributor's Contribution. + +1.3. "Contribution" + means Covered Software of a particular Contributor. + +1.4. "Covered Software" + means Source Code Form to which the initial Contributor has attached + the notice in Exhibit A, the Executable Form of such Source Code + Form, and Modifications of such Source Code Form, in each case + including portions thereof. + +1.5. "Incompatible With Secondary Licenses" + means + + (a) that the initial Contributor has attached the notice described + in Exhibit B to the Covered Software; or + + (b) that the Covered Software was made available under the terms of + version 1.1 or earlier of the License, but not also under the + terms of a Secondary License. + +1.6. "Executable Form" + means any form of the work other than Source Code Form. + +1.7. "Larger Work" + means a work that combines Covered Software with other material, in + a separate file or files, that is not Covered Software. + +1.8. "License" + means this document. + +1.9. "Licensable" + means having the right to grant, to the maximum extent possible, + whether at the time of the initial grant or subsequently, any and + all of the rights conveyed by this License. + +1.10. "Modifications" + means any of the following: + + (a) any file in Source Code Form that results from an addition to, + deletion from, or modification of the contents of Covered + Software; or + + (b) any new file in Source Code Form that contains any Covered + Software. + +1.11. "Patent Claims" of a Contributor + means any patent claim(s), including without limitation, method, + process, and apparatus claims, in any patent Licensable by such + Contributor that would be infringed, but for the grant of the + License, by the making, using, selling, offering for sale, having + made, import, or transfer of either its Contributions or its + Contributor Version. + +1.12. "Secondary License" + means either the GNU General Public License, Version 2.0, the GNU + Lesser General Public License, Version 2.1, the GNU Affero General + Public License, Version 3.0, or any later versions of those + licenses. + +1.13. "Source Code Form" + means the form of the work preferred for making modifications. + +1.14. "You" (or "Your") + means an individual or a legal entity exercising rights under this + License. For legal entities, "You" includes any entity that + controls, is controlled by, or is under common control with You. For + purposes of this definition, "control" means (a) the power, direct + or indirect, to cause the direction or management of such entity, + whether by contract or otherwise, or (b) ownership of more than + fifty percent (50%) of the outstanding shares or beneficial + ownership of such entity. + +2. License Grants and Conditions +-------------------------------- + +2.1. Grants + +Each Contributor hereby grants You a world-wide, royalty-free, +non-exclusive license: + +(a) under intellectual property rights (other than patent or trademark) + Licensable by such Contributor to use, reproduce, make available, + modify, display, perform, distribute, and otherwise exploit its + Contributions, either on an unmodified basis, with Modifications, or + as part of a Larger Work; and + +(b) under Patent Claims of such Contributor to make, use, sell, offer + for sale, have made, import, and otherwise transfer either its + Contributions or its Contributor Version. + +2.2. Effective Date + +The licenses granted in Section 2.1 with respect to any Contribution +become effective for each Contribution on the date the Contributor first +distributes such Contribution. + +2.3. Limitations on Grant Scope + +The licenses granted in this Section 2 are the only rights granted under +this License. No additional rights or licenses will be implied from the +distribution or licensing of Covered Software under this License. +Notwithstanding Section 2.1(b) above, no patent license is granted by a +Contributor: + +(a) for any code that a Contributor has removed from Covered Software; + or + +(b) for infringements caused by: (i) Your and any other third party's + modifications of Covered Software, or (ii) the combination of its + Contributions with other software (except as part of its Contributor + Version); or + +(c) under Patent Claims infringed by Covered Software in the absence of + its Contributions. + +This License does not grant any rights in the trademarks, service marks, +or logos of any Contributor (except as may be necessary to comply with +the notice requirements in Section 3.4). + +2.4. Subsequent Licenses + +No Contributor makes additional grants as a result of Your choice to +distribute the Covered Software under a subsequent version of this +License (see Section 10.2) or under the terms of a Secondary License (if +permitted under the terms of Section 3.3). + +2.5. Representation + +Each Contributor represents that the Contributor believes its +Contributions are its original creation(s) or it has sufficient rights +to grant the rights to its Contributions conveyed by this License. + +2.6. Fair Use + +This License is not intended to limit any rights You have under +applicable copyright doctrines of fair use, fair dealing, or other +equivalents. + +2.7. Conditions + +Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted +in Section 2.1. + +3. Responsibilities +------------------- + +3.1. Distribution of Source Form + +All distribution of Covered Software in Source Code Form, including any +Modifications that You create or to which You contribute, must be under +the terms of this License. You must inform recipients that the Source +Code Form of the Covered Software is governed by the terms of this +License, and how they can obtain a copy of this License. You may not +attempt to alter or restrict the recipients' rights in the Source Code +Form. + +3.2. Distribution of Executable Form + +If You distribute Covered Software in Executable Form then: + +(a) such Covered Software must also be made available in Source Code + Form, as described in Section 3.1, and You must inform recipients of + the Executable Form how they can obtain a copy of such Source Code + Form by reasonable means in a timely manner, at a charge no more + than the cost of distribution to the recipient; and + +(b) You may distribute such Executable Form under the terms of this + License, or sublicense it under different terms, provided that the + license for the Executable Form does not attempt to limit or alter + the recipients' rights in the Source Code Form under this License. + +3.3. Distribution of a Larger Work + +You may create and distribute a Larger Work under terms of Your choice, +provided that You also comply with the requirements of this License for +the Covered Software. If the Larger Work is a combination of Covered +Software with a work governed by one or more Secondary Licenses, and the +Covered Software is not Incompatible With Secondary Licenses, this +License permits You to additionally distribute such Covered Software +under the terms of such Secondary License(s), so that the recipient of +the Larger Work may, at their option, further distribute the Covered +Software under the terms of either this License or such Secondary +License(s). + +3.4. Notices + +You may not remove or alter the substance of any license notices +(including copyright notices, patent notices, disclaimers of warranty, +or limitations of liability) contained within the Source Code Form of +the Covered Software, except that You may alter any license notices to +the extent required to remedy known factual inaccuracies. + +3.5. Application of Additional Terms + +You may choose to offer, and to charge a fee for, warranty, support, +indemnity or liability obligations to one or more recipients of Covered +Software. However, You may do so only on Your own behalf, and not on +behalf of any Contributor. You must make it absolutely clear that any +such warranty, support, indemnity, or liability obligation is offered by +You alone, and You hereby agree to indemnify every Contributor for any +liability incurred by such Contributor as a result of warranty, support, +indemnity or liability terms You offer. You may include additional +disclaimers of warranty and limitations of liability specific to any +jurisdiction. + +4. Inability to Comply Due to Statute or Regulation +--------------------------------------------------- + +If it is impossible for You to comply with any of the terms of this +License with respect to some or all of the Covered Software due to +statute, judicial order, or regulation then You must: (a) comply with +the terms of this License to the maximum extent possible; and (b) +describe the limitations and the code they affect. Such description must +be placed in a text file included with all distributions of the Covered +Software under this License. Except to the extent prohibited by statute +or regulation, such description must be sufficiently detailed for a +recipient of ordinary skill to be able to understand it. + +5. Termination +-------------- + +5.1. The rights granted under this License will terminate automatically +if You fail to comply with any of its terms. However, if You become +compliant, then the rights granted under this License from a particular +Contributor are reinstated (a) provisionally, unless and until such +Contributor explicitly and finally terminates Your grants, and (b) on an +ongoing basis, if such Contributor fails to notify You of the +non-compliance by some reasonable means prior to 60 days after You have +come back into compliance. Moreover, Your grants from a particular +Contributor are reinstated on an ongoing basis if such Contributor +notifies You of the non-compliance by some reasonable means, this is the +first time You have received notice of non-compliance with this License +from such Contributor, and You become compliant prior to 30 days after +Your receipt of the notice. + +5.2. If You initiate litigation against any entity by asserting a patent +infringement claim (excluding declaratory judgment actions, +counter-claims, and cross-claims) alleging that a Contributor Version +directly or indirectly infringes any patent, then the rights granted to +You by any and all Contributors for the Covered Software under Section +2.1 of this License shall terminate. + +5.3. In the event of termination under Sections 5.1 or 5.2 above, all +end user license agreements (excluding distributors and resellers) which +have been validly granted by You or Your distributors under this License +prior to termination shall survive termination. + +************************************************************************ +* * +* 6. Disclaimer of Warranty * +* ------------------------- * +* * +* Covered Software is provided under this License on an "as is" * +* basis, without warranty of any kind, either expressed, implied, or * +* statutory, including, without limitation, warranties that the * +* Covered Software is free of defects, merchantable, fit for a * +* particular purpose or non-infringing. The entire risk as to the * +* quality and performance of the Covered Software is with You. * +* Should any Covered Software prove defective in any respect, You * +* (not any Contributor) assume the cost of any necessary servicing, * +* repair, or correction. This disclaimer of warranty constitutes an * +* essential part of this License. No use of any Covered Software is * +* authorized under this License except under this disclaimer. * +* * +************************************************************************ + +************************************************************************ +* * +* 7. Limitation of Liability * +* -------------------------- * +* * +* Under no circumstances and under no legal theory, whether tort * +* (including negligence), contract, or otherwise, shall any * +* Contributor, or anyone who distributes Covered Software as * +* permitted above, be liable to You for any direct, indirect, * +* special, incidental, or consequential damages of any character * +* including, without limitation, damages for lost profits, loss of * +* goodwill, work stoppage, computer failure or malfunction, or any * +* and all other commercial damages or losses, even if such party * +* shall have been informed of the possibility of such damages. This * +* limitation of liability shall not apply to liability for death or * +* personal injury resulting from such party's negligence to the * +* extent applicable law prohibits such limitation. Some * +* jurisdictions do not allow the exclusion or limitation of * +* incidental or consequential damages, so this exclusion and * +* limitation may not apply to You. * +* * +************************************************************************ + +8. Litigation +------------- + +Any litigation relating to this License may be brought only in the +courts of a jurisdiction where the defendant maintains its principal +place of business and such litigation shall be governed by laws of that +jurisdiction, without reference to its conflict-of-law provisions. +Nothing in this Section shall prevent a party's ability to bring +cross-claims or counter-claims. + +9. Miscellaneous +---------------- + +This License represents the complete agreement concerning the subject +matter hereof. If any provision of this License is held to be +unenforceable, such provision shall be reformed only to the extent +necessary to make it enforceable. Any law or regulation which provides +that the language of a contract shall be construed against the drafter +shall not be used to construe this License against a Contributor. + +10. Versions of the License +--------------------------- + +10.1. New Versions + +Mozilla Foundation is the license steward. Except as provided in Section +10.3, no one other than the license steward has the right to modify or +publish new versions of this License. Each version will be given a +distinguishing version number. + +10.2. Effect of New Versions + +You may distribute the Covered Software under the terms of the version +of the License under which You originally received the Covered Software, +or under the terms of any subsequent version published by the license +steward. + +10.3. Modified Versions + +If you create software not governed by this License, and you want to +create a new license for such software, you may create and use a +modified version of this License if you rename the license and remove +any references to the name of the license steward (except to note that +such modified license differs from this License). + +10.4. Distributing Source Code Form that is Incompatible With Secondary +Licenses + +If You choose to distribute Source Code Form that is Incompatible With +Secondary Licenses under the terms of this version of the License, the +notice described in Exhibit B of this License must be attached. + +Exhibit A - Source Code Form License Notice +------------------------------------------- + + This Source Code Form is subject to the terms of the Mozilla Public + License, v. 2.0. If a copy of the MPL was not distributed with this + file, You can obtain one at http://mozilla.org/MPL/2.0/. + +If it is not possible or desirable to put the notice in a particular +file, then You may include the notice in a location (such as a LICENSE +file in a relevant directory) where a recipient would be likely to look +for such a notice. + +You may add additional accurate notices of copyright ownership. + +Exhibit B - "Incompatible With Secondary Licenses" Notice +--------------------------------------------------------- + + This Source Code Form is "Incompatible With Secondary Licenses", as + defined by the Mozilla Public License, v. 2.0. diff --git a/ph-ee-connector-mojaloop-java/README.md b/ph-ee-connector-mojaloop-java/README.md new file mode 100644 index 000000000..b0200384b --- /dev/null +++ b/ph-ee-connector-mojaloop-java/README.md @@ -0,0 +1,15 @@ +# payment-hub-ee +Payment Hub Enterprise Edition middleware for integration to real-time payment systems. + +# Zeebe worker api mapping + +BPMN|Worker|Route|Endpoint|HTTP METHOD +--|--|--|--|-- +party-registration-DFSPID.bpmn |party-registration-oracle |direct:get-dfsp-from-oracle |/oracle/participants/{PARTY_ID_TYPE}/${PARTY_ID}?host={oracle-host} |GET +party-registration-DFSPID.bpmn |party-registration-oracle |direct:remove-party-identifier-from-dfsp-in-oracle |/oracle/participants/{PARTY_ID_TYPE}/${PARTY_ID}?host={oracle-host} |DELETE +party-registration-DFSPID.bpmn |party-registration-oracle |direct:add-party-identifier-to-dfsp-in-oracle |/oracle/participants/{PARTY_ID_TYPE}/${PARTY_ID}?host={oracle-host} |POST +payer-fund-transfer-DFSPID.bpmn |party-lookup-request |direct:send-party-lookup |/parties/{PARTY_ID_TYPE}/{PARTY_ID}?host={als-host} |GET +payer-fund-transfer-DFSPID.bpmn |party-lookup |rest:PUT:/switch/parties/MSISDN/{partyId} |call zeebe message task |- +payer-fund-transfer-DFSPID.bpmn |quote |direct:send-quote |/quotes?host={quotes-host} |POST +payer-fund-transfer-DFSPID.bpmn |quote-callback |rest:PUT:/switch/quotes/{QUOTE_ID} |call zeebe message task |- +payer-fund-transfer-DFSPID.bpmn |quote-error |rest:PUT:/switch/quotes/{QUOTE_ID}/error |call zeebe message task |- diff --git a/ph-ee-connector-mojaloop-java/build.gradle b/ph-ee-connector-mojaloop-java/build.gradle new file mode 100644 index 000000000..be6434a0d --- /dev/null +++ b/ph-ee-connector-mojaloop-java/build.gradle @@ -0,0 +1,79 @@ +/* + * This file was generated by the Gradle 'init' task. + * + * This project uses @Incubating APIs which are subject to change. + */ + +plugins { + id 'java' + id 'maven-publish' + id 'org.springframework.boot' version '2.7.3' +} +apply plugin: 'java' +apply plugin: 'io.spring.dependency-management' + +repositories { + mavenLocal() + maven { + url = uri('https://repo.maven.apache.org/maven2/') + } + maven { + url = uri('https://jfrog.sandbox.fynarfin.io/artifactory/fyn-libs-snapshot') + } + mavenCentral() +} + +ext { + camelVersion = '3.18.1' + zeebClientVersion = '8.1.23' + springBootVersion = '2.7.3' +} + +configurations.all { + resolutionStrategy { + force 'com.fasterxml.jackson.core:jackson-databind:2.4.6' + } +} + +dependencies { + implementation 'org.mifos:ph-ee-connector-common:1.2.2-SNAPSHOT' + implementation 'org.mifos:interop-ilp-conditions:1.7.1-SNAPSHOT' + implementation "org.apache.camel.springboot:camel-spring-boot-starter:$camelVersion" + implementation "org.apache.camel:camel-undertow:$camelVersion" + implementation 'org.apache.camel.springboot:camel-jackson-starter:3.16.0' + implementation 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.7.9' + implementation "org.apache.camel:camel-http:$camelVersion" + implementation "org.apache.camel:camel-endpointdsl:$camelVersion" + implementation "org.apache.camel:camel-jetty:$camelVersion" + implementation("io.camunda:zeebe-client-java:$zeebClientVersion") + testImplementation 'org.springframework.boot:spring-boot-starter-test' + testImplementation 'org.junit.jupiter:junit-jupiter-api:5.9.0' + testImplementation 'org.junit.jupiter:junit-jupiter-engine:5.9.0' + implementation 'org.json:json:20210307' + compileOnly 'org.projectlombok:lombok:1.18.24' + annotationProcessor 'org.projectlombok:lombok:1.18.24' + implementation "org.springframework.boot:spring-boot-starter:$springBootVersion" + implementation "org.springframework.boot:spring-boot-starter-web:$springBootVersion" + implementation "org.springframework.boot:spring-boot-starter-actuator:$springBootVersion" +} + +group = 'org.mifos' +version = '1.0.0-SNAPSHOT' +description = 'ph-ee-connector-mojaloop-java' +java.sourceCompatibility = "17" + +publishing { + publications { + maven(MavenPublication) { + from(components.java) + } + } +} + +tasks.withType(JavaCompile) { + options.encoding = 'UTF-8' +} + +test { + useJUnitPlatform() +} diff --git a/ph-ee-connector-mojaloop-java/gradle/wrapper/gradle-wrapper.jar b/ph-ee-connector-mojaloop-java/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 000000000..41d9927a4 Binary files /dev/null and b/ph-ee-connector-mojaloop-java/gradle/wrapper/gradle-wrapper.jar differ diff --git a/ph-ee-connector-mojaloop-java/gradle/wrapper/gradle-wrapper.properties b/ph-ee-connector-mojaloop-java/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 000000000..e750102e0 --- /dev/null +++ b/ph-ee-connector-mojaloop-java/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-7.3-bin.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/ph-ee-connector-mojaloop-java/gradlew b/ph-ee-connector-mojaloop-java/gradlew new file mode 100755 index 000000000..1b6c78733 --- /dev/null +++ b/ph-ee-connector-mojaloop-java/gradlew @@ -0,0 +1,234 @@ +#!/bin/sh + +# +# Copyright © 2015-2021 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit + +APP_NAME="Gradle" +APP_BASE_NAME=${0##*/} + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/ph-ee-connector-mojaloop-java/gradlew.bat b/ph-ee-connector-mojaloop-java/gradlew.bat new file mode 100644 index 000000000..ac1b06f93 --- /dev/null +++ b/ph-ee-connector-mojaloop-java/gradlew.bat @@ -0,0 +1,89 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/ph-ee-connector-mojaloop-java/settings.gradle b/ph-ee-connector-mojaloop-java/settings.gradle new file mode 100644 index 000000000..fbfb83ba2 --- /dev/null +++ b/ph-ee-connector-mojaloop-java/settings.gradle @@ -0,0 +1,7 @@ +/* + * This file was generated by the Gradle 'init' task. + * + * This project uses @Incubating APIs which are subject to change. + */ + +rootProject.name = 'ph-ee-connector-mojaloop-java' diff --git a/ph-ee-connector-mojaloop-java/src/main/java/org/mifos/connector/MojaloopConnectorApplication.java b/ph-ee-connector-mojaloop-java/src/main/java/org/mifos/connector/MojaloopConnectorApplication.java new file mode 100644 index 000000000..33b72a0ff --- /dev/null +++ b/ph-ee-connector-mojaloop-java/src/main/java/org/mifos/connector/MojaloopConnectorApplication.java @@ -0,0 +1,68 @@ +package org.mifos.connector; + +import com.fasterxml.jackson.annotation.JsonAutoDetect; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; +import org.apache.camel.Processor; +import org.mifos.connector.mojaloop.camel.config.CustomHeaderFilterStrategy; +import org.mifos.connector.mojaloop.properties.PartyProperties; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Bean; +import javax.annotation.PostConstruct; +import static org.mifos.connector.mojaloop.camel.config.CamelProperties.CUSTOM_HEADER_FILTER_STRATEGY; + +@SpringBootApplication +@EnableConfigurationProperties(PartyProperties.class) +public class MojaloopConnectorApplication { + + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Value("${mojaloop.perf-mode}") + private boolean mojaPerfMode; + + public static void main(String[] args) { + SpringApplication.run(MojaloopConnectorApplication.class, args); + } + + @PostConstruct + public void setup() { + if(mojaPerfMode) { + logger.info("----- PERF mode is turned on, no AMS and ZEEBE is running! -----"); + } + } + + @Bean + public ObjectMapper objectMapper() { + ObjectMapper objectMapper = new ObjectMapper(); + objectMapper.registerModule(new JavaTimeModule()); + objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false); + objectMapper.setVisibilityChecker( + objectMapper.getSerializationConfig() + .getDefaultVisibilityChecker() + .withFieldVisibility(JsonAutoDetect.Visibility.ANY) + .withGetterVisibility(JsonAutoDetect.Visibility.NONE) + ); + return objectMapper + .setSerializationInclusion(JsonInclude.Include.NON_NULL) + .configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true) + .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + } + + @Bean + public Processor pojoToString(ObjectMapper objectMapper) { + return exchange -> exchange.getIn().setBody(objectMapper.writeValueAsString(exchange.getIn().getBody())); + } + + @Bean(CUSTOM_HEADER_FILTER_STRATEGY) + public CustomHeaderFilterStrategy headerFilterStrategy() { + return new CustomHeaderFilterStrategy(); + } +} diff --git a/ph-ee-connector-mojaloop-java/src/main/java/org/mifos/connector/mojaloop/HealthCheck.java b/ph-ee-connector-mojaloop-java/src/main/java/org/mifos/connector/mojaloop/HealthCheck.java new file mode 100644 index 000000000..48d9e60e4 --- /dev/null +++ b/ph-ee-connector-mojaloop-java/src/main/java/org/mifos/connector/mojaloop/HealthCheck.java @@ -0,0 +1,16 @@ +package org.mifos.connector.mojaloop; + +import org.apache.camel.Exchange; +import org.apache.camel.builder.RouteBuilder; +import org.springframework.stereotype.Component; + +@Component +public class HealthCheck extends RouteBuilder { + + @Override + public void configure() { + from("rest:GET:/") + .setHeader(Exchange.HTTP_RESPONSE_CODE, constant(200)) + .setBody(constant("")); + } +} diff --git a/ph-ee-connector-mojaloop-java/src/main/java/org/mifos/connector/mojaloop/camel/ExternalApiCallRoute.java b/ph-ee-connector-mojaloop-java/src/main/java/org/mifos/connector/mojaloop/camel/ExternalApiCallRoute.java new file mode 100644 index 000000000..875943a57 --- /dev/null +++ b/ph-ee-connector-mojaloop-java/src/main/java/org/mifos/connector/mojaloop/camel/ExternalApiCallRoute.java @@ -0,0 +1,31 @@ +package org.mifos.connector.mojaloop.camel; + +import org.apache.camel.LoggingLevel; +import org.apache.camel.builder.RouteBuilder; +import org.springframework.stereotype.Component; + +import static org.mifos.connector.mojaloop.camel.config.CamelProperties.*; + +@Component +public class ExternalApiCallRoute extends RouteBuilder { + + @Override + public void configure() { + from("direct:external-api-call") + .id("external-api-call") + .log(LoggingLevel.DEBUG,"######## API CALL -> Calling an external api") + .process(exchange -> { + // remove the trailing "/" from endpoint + String endpoint = exchange.getProperty(ENDPOINT, String.class); + if (endpoint.startsWith("/")) { exchange.setProperty(ENDPOINT, endpoint.substring(1)); } + }) + .log(LoggingLevel.DEBUG,"Host: ${exchangeProperty." + HOST + "}") + .log(LoggingLevel.DEBUG,"Endpoint: ${exchangeProperty." + ENDPOINT + "}") + .log(LoggingLevel.DEBUG,"Headers: ${headers}") + .log(LoggingLevel.DEBUG,"Request Body: ${body}") + .toD("${exchangeProperty." + HOST + "}/${exchangeProperty." + ENDPOINT + "}" + + "?bridgeEndpoint=true" + "&throwExceptionOnFailure=false" + + "&headerFilterStrategy=#" + CUSTOM_HEADER_FILTER_STRATEGY) + .log(LoggingLevel.DEBUG,"Response body: ${body}"); + } +} diff --git a/ph-ee-connector-mojaloop-java/src/main/java/org/mifos/connector/mojaloop/camel/UnmarshlingRoute.java b/ph-ee-connector-mojaloop-java/src/main/java/org/mifos/connector/mojaloop/camel/UnmarshlingRoute.java new file mode 100644 index 000000000..c5a2250b3 --- /dev/null +++ b/ph-ee-connector-mojaloop-java/src/main/java/org/mifos/connector/mojaloop/camel/UnmarshlingRoute.java @@ -0,0 +1,37 @@ +package org.mifos.connector.mojaloop.camel; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.apache.camel.builder.RouteBuilder; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import static org.mifos.connector.mojaloop.camel.config.CamelProperties.CLASS_TYPE; + +@Component +public class UnmarshlingRoute extends RouteBuilder { + + private Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Autowired + private ObjectMapper objectMapper; + + @Override + public void configure() { + + from("direct:body-unmarshling") + .id("body-unmarshling") + .process(exchange -> { + try { + Class type = (Class) exchange.getProperty(CLASS_TYPE); + String bdy = exchange.getIn().getBody(String.class); + exchange.getIn().setBody(objectMapper.readValue(bdy, type)); + logger.debug("Converted dto: {}", exchange.getIn().getBody()); + } catch (Exception e) { + logger.error("Error while unmarshling body: {}", e.getMessage()); + } + }); + + } +} diff --git a/ph-ee-connector-mojaloop-java/src/main/java/org/mifos/connector/mojaloop/camel/config/CamelContextConfig.java b/ph-ee-connector-mojaloop-java/src/main/java/org/mifos/connector/mojaloop/camel/config/CamelContextConfig.java new file mode 100644 index 000000000..13fe09d13 --- /dev/null +++ b/ph-ee-connector-mojaloop-java/src/main/java/org/mifos/connector/mojaloop/camel/config/CamelContextConfig.java @@ -0,0 +1,41 @@ +package org.mifos.connector.mojaloop.camel.config; + +import org.apache.camel.CamelContext; +import org.apache.camel.spi.RestConfiguration; +import org.apache.camel.spring.boot.CamelContextConfiguration; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import java.util.HashMap; +import java.util.Map; + +@Configuration +public class CamelContextConfig { + + @Value("${camel.server-port}") + private int serverPort; + + @Bean + CamelContextConfiguration contextConfiguration() { + return new CamelContextConfiguration() { + @Override + public void beforeApplicationStart(CamelContext camelContext) { + camelContext.disableJMX(); + + RestConfiguration rest = new RestConfiguration(); + rest.setComponent("undertow"); + rest.setProducerComponent("undertow"); + rest.setPort(serverPort); + rest.setBindingMode(RestConfiguration.RestBindingMode.json); + rest.setScheme("http"); + camelContext.setRestConfiguration(rest); + } + + @Override + public void afterApplicationStart(CamelContext camelContext) { + // empty + } + }; + } +} diff --git a/ph-ee-connector-mojaloop-java/src/main/java/org/mifos/connector/mojaloop/camel/config/CamelProperties.java b/ph-ee-connector-mojaloop-java/src/main/java/org/mifos/connector/mojaloop/camel/config/CamelProperties.java new file mode 100644 index 000000000..29a509294 --- /dev/null +++ b/ph-ee-connector-mojaloop-java/src/main/java/org/mifos/connector/mojaloop/camel/config/CamelProperties.java @@ -0,0 +1,34 @@ +package org.mifos.connector.mojaloop.camel.config; + +public class CamelProperties { + + private CamelProperties() {} + + public static final String AUTH_TYPE = "authType"; + public static final String CACHED_TRANSACTION_ID = "cachedTransactionId"; + public static final String PARTY_EXISTS = "partyExists"; + + public static final String HOST = "externalApiCallHost"; + public static final String ENDPOINT = "externalApiCallEndpoint"; + + public static final String CUSTOM_HEADER_FILTER_STRATEGY = "customHeaderFilterStrategy"; + + public static final String CLASS_TYPE = "classType"; + + public static final String HEADER_CONTENT_TYPE = "Content-Type"; + + public static final String HEADER_ACCEPT = "Accept"; + + public static final String HEADER_HOST = "Host"; + + public static final String HEADER_DATE = "Date"; + + public static final String HEADER_TRACEPARENT = "traceparent"; + + public static final String HEADER_TRACESTATE = "tracestate"; + + public static final String HEADER_VALUE_TYPE_JSON = "application/json"; + + + +} diff --git a/ph-ee-connector-mojaloop-java/src/main/java/org/mifos/connector/mojaloop/camel/config/CustomHeaderFilterStrategy.java b/ph-ee-connector-mojaloop-java/src/main/java/org/mifos/connector/mojaloop/camel/config/CustomHeaderFilterStrategy.java new file mode 100644 index 000000000..4b908edd8 --- /dev/null +++ b/ph-ee-connector-mojaloop-java/src/main/java/org/mifos/connector/mojaloop/camel/config/CustomHeaderFilterStrategy.java @@ -0,0 +1,26 @@ +package org.mifos.connector.mojaloop.camel.config; + +import org.apache.camel.support.DefaultHeaderFilterStrategy; + +public class CustomHeaderFilterStrategy extends DefaultHeaderFilterStrategy { + + public CustomHeaderFilterStrategy() { + initialize(); + } + + protected void initialize() { + getOutFilter().add("content-length"); + getOutFilter().add("host"); + getOutFilter().add("cache-control"); + getOutFilter().add("connection"); + getOutFilter().add("pragma"); + getOutFilter().add("trailer"); + getOutFilter().add("transfer-encoding"); + getOutFilter().add("upgrade"); + getOutFilter().add("via"); + getOutFilter().add("warning"); + setLowerCase(true); + setOutFilterStartsWith(CAMEL_FILTER_STARTS_WITH); + setInFilterStartsWith(CAMEL_FILTER_STARTS_WITH); + } +} diff --git a/ph-ee-connector-mojaloop-java/src/main/java/org/mifos/connector/mojaloop/camel/trace/AddTraceHeaderProcessor.java b/ph-ee-connector-mojaloop-java/src/main/java/org/mifos/connector/mojaloop/camel/trace/AddTraceHeaderProcessor.java new file mode 100644 index 000000000..a81d79160 --- /dev/null +++ b/ph-ee-connector-mojaloop-java/src/main/java/org/mifos/connector/mojaloop/camel/trace/AddTraceHeaderProcessor.java @@ -0,0 +1,38 @@ +package org.mifos.connector.mojaloop.camel.trace; + + +import org.apache.camel.Exchange; +import org.apache.camel.Processor; +import org.mifos.connector.common.util.ContextUtil; +import org.springframework.stereotype.Component; + +import java.util.Base64; + +import static org.mifos.connector.mojaloop.camel.config.CamelProperties.*; +import static org.mifos.connector.mojaloop.zeebe.ZeebeVariables.ORIGIN_DATE; +import static org.mifos.connector.mojaloop.zeebe.ZeebeVariables.TRANSACTION_ID; + +@Component +public class AddTraceHeaderProcessor implements Processor { + + /** + * Adds Date and traceparent headers for every outgoing request to mojaloop. + * Date: https://tools.ietf.org/html/rfc7231#section-7.1.1.1 + * traceparent: https://w3c.github.io/trace-context/ + * format: "version"-"trace-id"-"parent-id"-"trace-flags"' + *

+ * Mojaloop does not support correlatinId at every async request-response in a common way so we are using this 'traceparent' header + */ + @Override + public void process(Exchange exchange) { + String transactionId = exchange.getProperty(TRANSACTION_ID, String.class); + String transactionIdTrimed = transactionId.replace("-", ""); + String transactionIdKey = transactionIdTrimed.substring(0, 16); + String traceParent = String.join("-", "00", transactionIdTrimed, transactionIdKey, "01"); + + exchange.getIn().setHeader(HEADER_TRACEPARENT, traceParent); + exchange.getIn().setHeader(HEADER_TRACESTATE, "ph=" + Base64.getEncoder().encodeToString(transactionIdKey.getBytes())); + exchange.getIn().setHeader(HEADER_DATE, + ContextUtil.formatToDateHeader(exchange.getProperty(ORIGIN_DATE, Long.class))); + } +} diff --git a/ph-ee-connector-mojaloop-java/src/main/java/org/mifos/connector/mojaloop/camel/trace/GetCachedTransactionIdProcessor.java b/ph-ee-connector-mojaloop-java/src/main/java/org/mifos/connector/mojaloop/camel/trace/GetCachedTransactionIdProcessor.java new file mode 100644 index 000000000..7f9f01f76 --- /dev/null +++ b/ph-ee-connector-mojaloop-java/src/main/java/org/mifos/connector/mojaloop/camel/trace/GetCachedTransactionIdProcessor.java @@ -0,0 +1,43 @@ +package org.mifos.connector.mojaloop.camel.trace; + +import org.apache.camel.Exchange; +import org.apache.camel.Processor; +import org.mifos.connector.mojaloop.camel.config.CamelProperties; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; + +import java.math.BigInteger; +import java.util.UUID; + +import static org.mifos.connector.mojaloop.camel.config.CamelProperties.HEADER_TRACEPARENT; + +@Component +public class GetCachedTransactionIdProcessor implements Processor { + + private Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Override + public void process(Exchange exchange) { + String transactionIdKey = null; + String traceparent = exchange.getIn().getHeader(HEADER_TRACEPARENT, String.class); + logger.debug("trace parent header: {}", traceparent); + + String transactionId = resolveTransactionIdFromTraceparent(traceparent); + + logger.debug("resolved parent {} to transactionId {}", traceparent, transactionId); + exchange.setProperty(CamelProperties.CACHED_TRANSACTION_ID, transactionId); + + if (transactionId == null) { + logger.error("FATAL: failed to resolve transactionIdKey {} in local TransactionCache, stopping route now", transactionIdKey); + exchange.setRouteStop(true); + } + } + + public static String resolveTransactionIdFromTraceparent(String traceparent) { + String parts = traceparent.split("-")[1]; + Long most = new BigInteger(parts.substring(0, 16), 16).longValue(); + Long least = new BigInteger(parts.substring(16, 32), 16).longValue(); + return new UUID(most, least).toString(); + } +} diff --git a/ph-ee-connector-mojaloop-java/src/main/java/org/mifos/connector/mojaloop/ilp/CodecContextFactory.java b/ph-ee-connector-mojaloop-java/src/main/java/org/mifos/connector/mojaloop/ilp/CodecContextFactory.java new file mode 100644 index 000000000..b533db29f --- /dev/null +++ b/ph-ee-connector-mojaloop-java/src/main/java/org/mifos/connector/mojaloop/ilp/CodecContextFactory.java @@ -0,0 +1,63 @@ +package org.mifos.connector.mojaloop.ilp; + +/* + * This Source Code Form is subject to the terms of the Mozilla + * Public License, v. 2.0. If a copy of the MPL was not distributed + * with this file, You can obtain one at + * + * https://mozilla.org/MPL/2.0/. + */ + + +import org.interledger.Condition; +import org.interledger.InterledgerAddress; +import org.interledger.codecs.CodecContext; +import org.interledger.codecs.oer.*; +import org.interledger.codecs.oer.ilp.ConditionOerCodec; +import org.interledger.codecs.oer.ilp.InterledgerAddressOerCodec; +import org.interledger.codecs.oer.ilp.InterledgerPacketTypeOerCodec; +import org.interledger.codecs.oer.ilp.InterledgerPaymentOerCodec; +import org.interledger.codecs.oer.ilqp.*; +import org.interledger.codecs.oer.ipr.InterledgerPaymentRequestOerCodec; +import org.interledger.codecs.packettypes.InterledgerPacketType; +import org.interledger.codecs.psk.PskMessageBinaryCodec; +import org.interledger.ilp.InterledgerPayment; +import org.interledger.ilqp.*; +import org.interledger.ipr.InterledgerPaymentRequest; +import org.interledger.psk.PskMessage; + +public class CodecContextFactory { + + public static CodecContext interledger() { + return (new CodecContext()) + .register(OerUint8Codec.OerUint8.class, new OerUint8Codec()) + .register(OerUint32Codec.OerUint32.class, new OerUint32Codec()) + .register(OerUint64Codec.OerUint64.class, new OerUint64Codec()) + .register(OerUint256Codec.OerUint256.class, new OerUint256Codec()) + .register(OerLengthPrefixCodec.OerLengthPrefix.class, new OerLengthPrefixCodec()) + .register(OerIA5StringCodec.OerIA5String.class, new OerIA5StringCodec()) + .register(OerOctetStringCodec.OerOctetString.class, new OerOctetStringCodec()) + .register(OerGeneralizedTimeCodec.OerGeneralizedTime.class, new OerGeneralizedTimeCodec()) + .register(InterledgerAddress.class, new InterledgerAddressOerCodec()) + .register(InterledgerPacketType.class, new InterledgerPacketTypeOerCodec()) + .register(org.interledger.ilp.InterledgerPayment.class, new org.interledger.codecs.oer.ilp.InterledgerPaymentOerCodec()) + .register(InterledgerPaymentRequest.class, new InterledgerPaymentRequestOerCodec()) + .register(Condition.class, new ConditionOerCodec()) + .register(QuoteByDestinationAmountRequest.class, new QuoteByDestinationAmountRequestOerCodec()) + .register(QuoteByDestinationAmountResponse.class, new QuoteByDestinationAmountResponseOerCodec()) + .register(QuoteBySourceAmountRequest.class, new QuoteBySourceAmountRequestOerCodec()) + .register(QuoteBySourceAmountResponse.class, new QuoteBySourceAmountResponseOerCodec()) + .register(QuoteLiquidityRequest.class, new QuoteLiquidityRequestOerCodec()) + .register(QuoteLiquidityResponse.class, new QuoteLiquidityResponseOerCodec()) + .register(PskMessage.class, new PskMessageBinaryCodec()) + .register(InterledgerPayment.class, new InterledgerPaymentOerCodec()); + } + + public static CodecContext interledgerJson() { + throw new RuntimeException("Not yet implemented!"); + } + + public static CodecContext interledgerProtobuf() { + throw new RuntimeException("Not yet implemented!"); + } +} diff --git a/ph-ee-connector-mojaloop-java/src/main/java/org/mifos/connector/mojaloop/ilp/Ilp.java b/ph-ee-connector-mojaloop-java/src/main/java/org/mifos/connector/mojaloop/ilp/Ilp.java new file mode 100644 index 000000000..899ad0c2a --- /dev/null +++ b/ph-ee-connector-mojaloop-java/src/main/java/org/mifos/connector/mojaloop/ilp/Ilp.java @@ -0,0 +1,59 @@ +package org.mifos.connector.mojaloop.ilp; + +import com.ilp.conditions.models.pdp.Transaction; + +public class Ilp { + + private final String packet; // mandatory + private final String condition; // mandatory + private final String fulfilment; // optional + private final Transaction transaction; // mandatory + + public Ilp(String packet, String condition, String fulfilment, Transaction transaction) { + this.packet = packet; + this.condition = condition; + this.fulfilment = fulfilment; + this.transaction = transaction; + } + + public Ilp(String packet, String condition, Transaction transaction) { + this(packet, condition, null, transaction); + } + + public String getPacket() { + return packet; + } + + public String getCondition() { + return condition; + } + + public String getFulfilment() { + return fulfilment; + } + + public Transaction getTransaction() { + return transaction; + } + + void update(Ilp oIlp) { + if (oIlp == null) + return; + if (!packet.equals(oIlp.getPacket())) + throw new RuntimeException("Ilp packet is not valid " + packet + " vs." + oIlp.getPacket()); + if (!condition.equals(oIlp.getCondition())) + throw new RuntimeException("Ilp condition is not valid " + packet + " vs." + oIlp.getPacket()); + if (fulfilment != null && oIlp.getFulfilment() != null && !fulfilment.equals(oIlp.getFulfilment())) + throw new RuntimeException("Ilp fulfilment is not valid " + fulfilment + " vs." + oIlp.getFulfilment()); + + } + + @Override + public String toString() { + return "Ilp{" + + "packet:'" + packet + '\'' + + ", condition:'" + condition + '\'' + + ", fulfilment:'" + fulfilment + '\'' + + '}'; + } +} diff --git a/ph-ee-connector-mojaloop-java/src/main/java/org/mifos/connector/mojaloop/ilp/IlpBuilder.java b/ph-ee-connector-mojaloop-java/src/main/java/org/mifos/connector/mojaloop/ilp/IlpBuilder.java new file mode 100644 index 000000000..63426e8fb --- /dev/null +++ b/ph-ee-connector-mojaloop-java/src/main/java/org/mifos/connector/mojaloop/ilp/IlpBuilder.java @@ -0,0 +1,79 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla + * Public License, v. 2.0. If a copy of the MPL was not distributed + * with this file, You can obtain one at + * + * https://mozilla.org/MPL/2.0/. + */ +package org.mifos.connector.mojaloop.ilp; + +import com.ilp.conditions.models.pdp.Money; +import com.ilp.conditions.models.pdp.PartyIdInfo; +import com.ilp.conditions.models.pdp.Transaction; +import org.mifos.connector.common.util.ContextUtil; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; +import java.io.IOException; +import java.math.BigDecimal; + +@Component +public class IlpBuilder { + + private static final String ILP_ADDRESS_TEMPLATE = "g.tz.%s.%s.%s"; + + @Autowired + private IlpConditionHandlerImpl ilpConditionHandlerImpl; + + @Value("${connector.ilp-secret}") + private String conectorIlpSecret; + + public Ilp build(String transactionId, String quoteId, BigDecimal transactionAmount, String currency, Party payer, + Party payee, BigDecimal transferAmount) throws IOException { + Transaction transaction = mapToTransaction(transactionId, quoteId, transactionAmount, currency, payer, payee); + return build(transaction, transferAmount); + } + + public Ilp build(Transaction transaction, BigDecimal amount) throws IOException { + String ilpAddress = buildIlpAddress(transaction); + String ilpPacket = ilpConditionHandlerImpl.getILPPacket(ilpAddress, ContextUtil.formatAmount(amount), transaction); + String ilpCondition = ilpConditionHandlerImpl.generateCondition(ilpPacket, conectorIlpSecret.getBytes()); + String fulfillment = ilpConditionHandlerImpl.generateFulfillment(ilpPacket, conectorIlpSecret.getBytes()); + + return new Ilp(ilpPacket, ilpCondition, fulfillment, transaction); + } + + public Ilp parse(String packet, String condition) { + return new Ilp(packet, condition, ilpConditionHandlerImpl.getTransactionFromIlpPacket(packet)); + } + + public boolean isValidPacketAgainstCondition(String packet, String condition) { + return ilpConditionHandlerImpl.generateCondition(packet, conectorIlpSecret.getBytes()).equals(condition); + } + + public String buildIlpAddress(Transaction transaction) { + PartyIdInfo partyIdInfo = transaction.getPayee().getPartyIdInfo(); + return String.format(ILP_ADDRESS_TEMPLATE, partyIdInfo.getFspId(), partyIdInfo.getPartyIdType(), partyIdInfo.getPartyIdentifier()); + } + + private Transaction mapToTransaction(String transactionId, String quoteId, BigDecimal transactionAmount, String currency, + Party payer, Party payee) { + Money money = new Money(); + money.setAmount(ContextUtil.formatAmount(transactionAmount)); + money.setCurrency(currency); + + return mapToTransaction(transactionId, quoteId, money, payer, payee); + } + + private Transaction mapToTransaction(String transactionId, String quoteId, Money transactionAmount, Party payer, Party payee) { + Transaction transaction = new Transaction(); + + transaction.setTransactionId(transactionId); + transaction.setQuoteId(quoteId); + transaction.setAmount(transactionAmount); + transaction.setPayer(payer.getIlpParty()); + transaction.setPayee(payee.getIlpParty()); + + return transaction; + } +} diff --git a/ph-ee-connector-mojaloop-java/src/main/java/org/mifos/connector/mojaloop/ilp/IlpConditionHandlerImpl.java b/ph-ee-connector-mojaloop-java/src/main/java/org/mifos/connector/mojaloop/ilp/IlpConditionHandlerImpl.java new file mode 100644 index 000000000..372835894 --- /dev/null +++ b/ph-ee-connector-mojaloop-java/src/main/java/org/mifos/connector/mojaloop/ilp/IlpConditionHandlerImpl.java @@ -0,0 +1,97 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla + * Public License, v. 2.0. If a copy of the MPL was not distributed + * with this file, You can obtain one at + * + * https://mozilla.org/MPL/2.0/. + */ +package org.mifos.connector.mojaloop.ilp; + +import com.fasterxml.jackson.annotation.JsonInclude.Include; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.ilp.conditions.models.pdp.Transaction; +import org.interledger.Condition; +import org.interledger.Fulfillment; +import org.interledger.InterledgerAddress; +import org.interledger.codecs.CodecContext; +import org.interledger.ilp.InterledgerPayment; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import javax.crypto.Mac; +import javax.crypto.spec.SecretKeySpec; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.util.Base64; +import static java.util.Base64.getUrlDecoder; + +@Component +public class IlpConditionHandlerImpl { + + private final Logger logger = LoggerFactory.getLogger(getClass()); + + @Autowired + private ObjectMapper mapper; + + public String getILPPacket(String ilpAddress, String amount, Transaction transaction) throws IOException { + InterledgerAddress address = InterledgerAddress.builder().value(ilpAddress).build(); + InterledgerPayment.Builder paymentBuilder = InterledgerPayment.builder(); + paymentBuilder.destinationAccount(address); + paymentBuilder.destinationAmount(Long.valueOf(amount)); + mapper.setSerializationInclusion(Include.NON_NULL); + String notificationJson = mapper.writeValueAsString(transaction); + byte[] serializedTransaction = Base64.getUrlEncoder().encode(notificationJson.getBytes()); + paymentBuilder.data(serializedTransaction); + CodecContext context = CodecContextFactory.interledger(); + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + context.write(InterledgerPayment.class, paymentBuilder.build(), outputStream); + return Base64.getUrlEncoder().encodeToString(outputStream.toByteArray()); + } + + public Transaction getTransactionFromIlpPacket(String ilpPacket) { + try { + ByteArrayInputStream inputStream = new ByteArrayInputStream(getUrlDecoder().decode(ilpPacket)); + CodecContext context = CodecContextFactory.interledger(); + InterledgerPayment ip = context.read(InterledgerPayment.class, inputStream); + byte[] decodedTxn = getUrlDecoder().decode(ip.getData()); + return mapper.readValue(decodedTxn, Transaction.class); + } catch (Exception ex) { + logger.error("Error when extract transaction from ilp packet!", ex); + return null; + } + } + + public String generateFulfillment(String ilpPacket, byte[] secret) { + byte[] bFulfillment = this.getFulfillmentBytes(ilpPacket, secret); + return Base64.getUrlEncoder().withoutPadding().encodeToString(bFulfillment); + } + + public String generateCondition(String ilpPacket, byte[] secret) { + byte[] bFulfillment = this.getFulfillmentBytes(ilpPacket, secret); + Fulfillment fulfillment = Fulfillment.builder().preimage(bFulfillment).build(); + return Base64.getUrlEncoder().withoutPadding().encodeToString(fulfillment.getCondition().getHash()); + } + + public boolean validateFulfillmentAgainstCondition(String strFulfillment, String strCondition) { + byte[] bFulfillment = getUrlDecoder().decode(strFulfillment); + Fulfillment fulfillment = Fulfillment.of(bFulfillment); + byte[] bCondition = getUrlDecoder().decode(strCondition); + Condition condition = Condition.of(bCondition); + return fulfillment.validate(condition); + } + + private byte[] getFulfillmentBytes(String ilpPacket, byte[] secret) { + try { + String HMAC_ALGORITHM = "HmacSHA256"; + Mac mac = Mac.getInstance(HMAC_ALGORITHM); + mac.init(new SecretKeySpec(secret, HMAC_ALGORITHM)); + return mac.doFinal(ilpPacket.getBytes()); + } catch (NoSuchAlgorithmException | IllegalStateException | InvalidKeyException var5) { + throw new RuntimeException("Error getting HMAC", var5); + } + } +} diff --git a/ph-ee-connector-mojaloop-java/src/main/java/org/mifos/connector/mojaloop/ilp/Party.java b/ph-ee-connector-mojaloop-java/src/main/java/org/mifos/connector/mojaloop/ilp/Party.java new file mode 100644 index 000000000..69ef20df2 --- /dev/null +++ b/ph-ee-connector-mojaloop-java/src/main/java/org/mifos/connector/mojaloop/ilp/Party.java @@ -0,0 +1,101 @@ +package org.mifos.connector.mojaloop.ilp; + +/* + * This Source Code Form is subject to the terms of the Mozilla + * Public License, v. 2.0. If a copy of the MPL was not distributed + * with this file, You can obtain one at + * + * https://mozilla.org/MPL/2.0/. + */ + +import com.ilp.conditions.models.pdp.PartyComplexName; +import com.ilp.conditions.models.pdp.PartyPersonalInfo; +import org.mifos.connector.common.mojaloop.dto.ComplexName; +import org.mifos.connector.common.mojaloop.dto.PartyIdInfo; +import org.mifos.connector.common.mojaloop.dto.PersonalInfo; +import org.wildfly.common.annotation.NotNull; + +import java.beans.Transient; + +public class Party { + + @NotNull + private PartyIdInfo partyIdInfo; // mandatory + private String merchantClassificationCode ; // optional + private String name; // optional + private PersonalInfo personalInfo; // optional + + Party() { + } + + public Party(PartyIdInfo partyIdInfo, String merchantClassificationCode, String name, PersonalInfo personalInfo) { + this.partyIdInfo = partyIdInfo; + this.merchantClassificationCode = merchantClassificationCode; + this.name = name; + this.personalInfo = personalInfo; + } + + public Party(PartyIdInfo partyIdInfo) { + this(partyIdInfo, null, null, null); + } + + public PartyIdInfo getPartyIdInfo() { + return partyIdInfo; + } + + public void setPartyIdInfo(PartyIdInfo partyIdInfo) { + this.partyIdInfo = partyIdInfo; + } + + public String getMerchantClassificationCode() { + return merchantClassificationCode; + } + + public void setMerchantClassificationCode(String merchantClassificationCode) { + this.merchantClassificationCode = merchantClassificationCode; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public PersonalInfo getPersonalInfo() { + return personalInfo; + } + + public void setPersonalInfo(PersonalInfo personalInfo) { + this.personalInfo = personalInfo; + } + + @Transient + public com.ilp.conditions.models.pdp.Party getIlpParty() { + com.ilp.conditions.models.pdp.Party ilpParty = new com.ilp.conditions.models.pdp.Party(); + ilpParty.setMerchantClassificationCode(merchantClassificationCode); + ilpParty.setName(name); + + com.ilp.conditions.models.pdp.PartyIdInfo ilpPartyIdInfo = new com.ilp.conditions.models.pdp.PartyIdInfo(); + ilpPartyIdInfo.setFspId(partyIdInfo.getFspId()); + ilpPartyIdInfo.setPartyIdentifier(partyIdInfo.getPartyIdentifier()); + ilpPartyIdInfo.setPartyIdType(partyIdInfo.getPartyIdType().name()); + ilpPartyIdInfo.setPartySubIdOrType(partyIdInfo.getPartySubIdOrType()); + ilpParty.setPartyIdInfo(ilpPartyIdInfo); + + if (personalInfo != null) { + PartyPersonalInfo ilpPersonalInfo = new PartyPersonalInfo(); + ilpPersonalInfo.setDateOfBirth(personalInfo.getDateOfBirth()); + PartyComplexName payerComplexName = new PartyComplexName(); + ComplexName complexName = personalInfo.getComplexName(); + payerComplexName.setFirstName(complexName.getFirstName()); + payerComplexName.setLastName(complexName.getLastName()); + payerComplexName.setMiddleName(complexName.getMiddleName()); + ilpPersonalInfo.setComplexName(payerComplexName); + ilpParty.setPersonalInfo(ilpPersonalInfo); + } + + return ilpParty; + } +} diff --git a/ph-ee-connector-mojaloop-java/src/main/java/org/mifos/connector/mojaloop/model/QuoteCallbackDTO.java b/ph-ee-connector-mojaloop-java/src/main/java/org/mifos/connector/mojaloop/model/QuoteCallbackDTO.java new file mode 100644 index 000000000..501520490 --- /dev/null +++ b/ph-ee-connector-mojaloop-java/src/main/java/org/mifos/connector/mojaloop/model/QuoteCallbackDTO.java @@ -0,0 +1,17 @@ +package org.mifos.connector.mojaloop.model; + +import lombok.Getter; +import lombok.Setter; +import org.mifos.connector.common.mojaloop.dto.MoneyData; + +@Getter +@Setter +public class QuoteCallbackDTO { + + private MoneyData transferAmount; + private MoneyData payeeFspFee; + private MoneyData payeeFspCommission; + private String expiration; + private String ilpPacket; + private String condition; +} diff --git a/ph-ee-connector-mojaloop-java/src/main/java/org/mifos/connector/mojaloop/party/OracleRoutes.java b/ph-ee-connector-mojaloop-java/src/main/java/org/mifos/connector/mojaloop/party/OracleRoutes.java new file mode 100644 index 000000000..82bdaece1 --- /dev/null +++ b/ph-ee-connector-mojaloop-java/src/main/java/org/mifos/connector/mojaloop/party/OracleRoutes.java @@ -0,0 +1,93 @@ +package org.mifos.connector.mojaloop.party; + +import org.apache.camel.Exchange; +import org.apache.camel.LoggingLevel; +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; +import org.mifos.connector.common.camel.ErrorHandlerRouteBuilder; +import org.mifos.connector.mojaloop.properties.PartyProperties; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import static org.mifos.connector.mojaloop.camel.config.CamelProperties.*; +import static org.mifos.connector.mojaloop.zeebe.ZeebeVariables.ACCOUNT_CURRENCY; +import static org.mifos.connector.mojaloop.zeebe.ZeebeVariables.PARTY_ID; +import static org.mifos.connector.mojaloop.zeebe.ZeebeVariables.PARTY_ID_TYPE; +import static org.mifos.connector.mojaloop.zeebe.ZeebeVariables.TENANT_ID; + +@Component +public class OracleRoutes extends ErrorHandlerRouteBuilder { + + @Autowired + private PartyProperties partyProperties; + + public OracleRoutes() { + super.configure(); + } + + @Override + public void configure() { + // @formatter:off + from("direct:register-party-identifier-in-oracle") + .log(LoggingLevel.DEBUG, "######## registering party identifier ${exchangeProperty." + PARTY_ID + "} with type ${exchangeProperty." + PARTY_ID_TYPE + "} in oracle") + .id("register-party-identifier-in-oracle") + .to("direct:get-dfsp-from-oracle") + .choice() + .when(e -> e.getProperty(PARTY_EXISTS, Boolean.class)) + .to("direct:remove-party-identifier-from-dfsp-in-oracle") + .to("direct:add-party-identifier-to-dfsp-in-oracle") + .endChoice() + .otherwise() + .to("direct:add-party-identifier-to-dfsp-in-oracle") + .endChoice() + .end(); + // @formatter:on + + from("direct:get-dfsp-from-oracle") + .id("get-dfsp-from-oracle") + .removeHeaders("*") + .setHeader(Exchange.HTTP_METHOD, constant("GET")) + .setProperty(HOST, simple("{{switch.oracle-host}}")) + .setProperty(ENDPOINT, constant("oracle/participants/${exchangeProperty." + + PARTY_ID_TYPE + "}/${exchangeProperty." + PARTY_ID + "}")) + .to("direct:external-api-call") + .log(LoggingLevel.DEBUG, "get-dfsp-from-oracle response ${body}") + .process(e -> { + try { + e.setProperty(PARTY_EXISTS, !new JSONArray(e.getIn().getBody(String.class)).isEmpty()); + } catch (JSONException ex) { // non exist and existing response format are different from oracle + e.setProperty(PARTY_EXISTS, true); + } + }); + + from("direct:add-party-identifier-to-dfsp-in-oracle") + .id("add-party-identifier-to-dfsp-in-oracle") + .removeHeaders("*") + .process(e -> { + String fspId = partyProperties.getPartyByTenant(e.getProperty(TENANT_ID, String.class)).getFspId(); + JSONObject request = new JSONObject(); + request.put("fspId", fspId); + request.put("currency", e.getProperty(ACCOUNT_CURRENCY, String.class)); + e.getIn().setBody(request.toString()); + e.getIn().setHeader(HEADER_CONTENT_TYPE, HEADER_VALUE_TYPE_JSON); + e.getIn().setHeader(HEADER_ACCEPT, HEADER_VALUE_TYPE_JSON); + }) + .setHeader(Exchange.HTTP_METHOD, constant("POST")) + .setProperty(HOST, simple("{{switch.oracle-host}}")) + .setProperty(ENDPOINT, constant("oracle/participants/${exchangeProperty." + PARTY_ID_TYPE + + "}/${exchangeProperty." + PARTY_ID + "}")) + .to("direct:external-api-call") + .log(LoggingLevel.DEBUG, "add-party-identifier-to-dfsp-in-oracle response ${body}"); + + from("direct:remove-party-identifier-from-dfsp-in-oracle") + .id("remove-party-to-dfsp-in-oracle") + .removeHeaders("*") + .setHeader(Exchange.HTTP_METHOD, constant("DELETE")) + .setProperty(HOST, simple("{{switch.oracle-host}}")) + .setProperty(ENDPOINT, constant("oracle/participants/${exchangeProperty." + + PARTY_ID_TYPE + "}/${exchangeProperty." + PARTY_ID + "}")) + .to("direct:external-api-call") + .log(LoggingLevel.DEBUG, "remove-party-identifier-from-dfsp-in-oracle response ${body}"); + } +} diff --git a/ph-ee-connector-mojaloop-java/src/main/java/org/mifos/connector/mojaloop/party/PartiesResponseProcessor.java b/ph-ee-connector-mojaloop-java/src/main/java/org/mifos/connector/mojaloop/party/PartiesResponseProcessor.java new file mode 100644 index 000000000..f14495d55 --- /dev/null +++ b/ph-ee-connector-mojaloop-java/src/main/java/org/mifos/connector/mojaloop/party/PartiesResponseProcessor.java @@ -0,0 +1,55 @@ +package org.mifos.connector.mojaloop.party; + +import io.camunda.zeebe.client.ZeebeClient; +import org.apache.camel.Exchange; +import org.apache.camel.Processor; +import org.mifos.connector.common.mojaloop.dto.PartySwitchResponseDTO; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.time.Duration; +import java.util.HashMap; +import java.util.Map; + +import static org.mifos.connector.mojaloop.camel.config.CamelProperties.CACHED_TRANSACTION_ID; +import static org.mifos.connector.mojaloop.zeebe.ZeebeVariables.ERROR_INFORMATION; +import static org.mifos.connector.mojaloop.zeebe.ZeebeVariables.PARTY_LOOKUP_FSP_ID; +import static org.mifos.connector.mojaloop.zeebe.ZeebeVariables.PARTY_LOOKUP_FAILED; +import static org.mifos.connector.mojaloop.zeebe.ZeebeMessages.PARTY_LOOKUP; + +@Component +public class PartiesResponseProcessor implements Processor { + + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Autowired(required = false) + private ZeebeClient zeebeClient; + + @Override + public void process(Exchange exchange) { + Map variables = new HashMap<>(); + Object isPayeePartyLookupFailed = exchange.getProperty(PARTY_LOOKUP_FAILED); + String error = exchange.getIn().getBody(String.class); + if (isPayeePartyLookupFailed != null && (boolean) isPayeePartyLookupFailed) { + variables.put(ERROR_INFORMATION, error); + variables.put(PARTY_LOOKUP_FAILED, true); + } else { + PartySwitchResponseDTO response = exchange.getIn().getBody(PartySwitchResponseDTO.class); + variables.put(PARTY_LOOKUP_FSP_ID, response.getParty().getPartyIdInfo().getFspId()); + variables.put(PARTY_LOOKUP_FAILED, false); + } + + if(zeebeClient != null) { + zeebeClient.newPublishMessageCommand() + .messageName(PARTY_LOOKUP) + .correlationKey(exchange.getProperty(CACHED_TRANSACTION_ID, String.class)) + .timeToLive(Duration.ofMillis(30000)) + .variables(variables) + .send(); + } else { + logger.error("Mojaloop party request failed: {}", error); + } + } +} diff --git a/ph-ee-connector-mojaloop-java/src/main/java/org/mifos/connector/mojaloop/party/PartyLookupRoutes.java b/ph-ee-connector-mojaloop-java/src/main/java/org/mifos/connector/mojaloop/party/PartyLookupRoutes.java new file mode 100644 index 000000000..f5e3d6d63 --- /dev/null +++ b/ph-ee-connector-mojaloop-java/src/main/java/org/mifos/connector/mojaloop/party/PartyLookupRoutes.java @@ -0,0 +1,200 @@ +package org.mifos.connector.mojaloop.party; + + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.apache.camel.Exchange; +import org.apache.camel.LoggingLevel; +import org.apache.camel.Processor; +import org.mifos.connector.common.camel.ErrorHandlerRouteBuilder; +import org.mifos.connector.common.channel.dto.TransactionChannelRequestDTO; +import org.mifos.connector.common.mojaloop.dto.Party; +import org.mifos.connector.common.mojaloop.dto.PartyIdInfo; +import org.mifos.connector.common.mojaloop.dto.PartySwitchResponseDTO; +import org.mifos.connector.common.mojaloop.type.IdentifierType; +import org.mifos.connector.mojaloop.camel.trace.AddTraceHeaderProcessor; +import org.mifos.connector.mojaloop.camel.trace.GetCachedTransactionIdProcessor; +import org.mifos.connector.mojaloop.properties.PartyProperties; +import org.mifos.connector.mojaloop.util.MojaloopUtil; +import org.mifos.connector.mojaloop.zeebe.ZeebeProcessStarter; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; +import static org.mifos.connector.common.ams.dto.InteropIdentifierType.MSISDN; +import static org.mifos.connector.common.mojaloop.type.MojaloopHeaders.FSPIOP_DESTINATION; +import static org.mifos.connector.common.mojaloop.type.MojaloopHeaders.FSPIOP_SOURCE; +import static org.mifos.connector.mojaloop.camel.config.CamelProperties.*; +import static org.mifos.connector.mojaloop.zeebe.ZeebeVariables.*; + +@Component +public class PartyLookupRoutes extends ErrorHandlerRouteBuilder { + + @Value("${bpmn.flows.party-lookup}") + private String partyLookupFlow; + + @Value("${mojaloop.perf-mode}") + private boolean mojaPerfMode; + + @Value("${mojaloop.perf-resp-delay}") + private int mojaPerfRespDelay; + + @Value("${switch.als-host}") + private String alsHost; + + @Autowired + private Processor pojoToString; + + @Autowired + private ZeebeProcessStarter zeebeProcessStarter; + + @Autowired + private PartyProperties partyProperties; + + @Autowired + private ObjectMapper objectMapper; + + @Autowired + private MojaloopUtil mojaloopUtil; + + @Autowired + private AddTraceHeaderProcessor addTraceHeaderProcessor; + + @Autowired + private GetCachedTransactionIdProcessor getCachedTransactionIdProcessor; + + @Autowired + private PartiesResponseProcessor partiesResponseProcessor; + + public PartyLookupRoutes() { + super.configure(); + } + + @Override + public void configure() { + //@formatter:off + from("rest:GET:/switch/parties/{" + PARTY_ID_TYPE + "}/{" + PARTY_ID + "}") + .log(LoggingLevel.DEBUG, "## SWITCH -> PAYER/PAYEE inbound GET parties - STEP 2") + .choice() + .when(e -> mojaPerfMode) + .wireTap("direct:send-delayed-party-dummy-response") + .endChoice() + .otherwise() + .process(e -> { + String host = e.getIn().getHeader("Host", String.class).split(":")[0]; + log.debug("HOST: {}", host); + log.debug("Headers: {}", e.getIn().getHeaders()); + String payeeFsp = e.getIn().getHeader(FSPIOP_DESTINATION.headerName(), String.class); + log.debug("Payeefsp: {}", payeeFsp); + log.debug("PARTIES: {}", objectMapper.writeValueAsString(partyProperties.getParties())); + String tenantId = partyProperties.getPartyByDomainAndFspId(host, payeeFsp).getTenantId(); + log.debug("PAYEE TENANT: {}", tenantId); + zeebeProcessStarter.startZeebeWorkflow(partyLookupFlow.replace("{tenant}", tenantId), + variables -> { + variables.put(HEADER_DATE, e.getIn().getHeader(HEADER_DATE)); + variables.put(HEADER_TRACEPARENT, e.getIn().getHeader(HEADER_TRACEPARENT)); + variables.put(FSPIOP_SOURCE.headerName(), e.getIn().getHeader(FSPIOP_SOURCE.headerName())); + variables.put(PAYEE_TENANT_ID, partyProperties.getPartyByDfsp(payeeFsp).getTenantId()); + variables.put(PARTY_ID_TYPE, e.getIn().getHeader(PARTY_ID_TYPE)); + variables.put(PARTY_ID, e.getIn().getHeader(PARTY_ID)); + variables.put(TENANT_ID, tenantId); + if(e.getIn().getHeader("X-Lookup-Callback-Url")!=null) { + variables.put("X-Lookup-Callback-Url", e.getIn().getHeader("X-Lookup-Callback-Url")); + } + else { + variables.put("X-Lookup-Callback-Url", alsHost); + } + }); + } + ) + .endChoice() + .end() + .setBody(constant(null)) + .setHeader(Exchange.HTTP_RESPONSE_CODE, constant(202)); + //@formatter:on + + from("rest:PUT:/switch/parties/" + MSISDN + "/{partyId}") + .setProperty(CLASS_TYPE, constant(PartySwitchResponseDTO.class)) + .to("direct:body-unmarshling") + .process(getCachedTransactionIdProcessor) + .to("direct:parties-step4"); + + from("direct:parties-step4") + .log(LoggingLevel.DEBUG, "######## SWITCH -> PAYER - response for parties request - STEP 4") + .process(partiesResponseProcessor) + .setBody(constant(null)) + .setHeader(Exchange.HTTP_RESPONSE_CODE, constant(200)); + + from("rest:PUT:/switch/parties/" + MSISDN + "/{partyId}/error") + .log(LoggingLevel.ERROR, "######## SWITCH -> PAYER - parties error") + .process(getCachedTransactionIdProcessor) + .setProperty(PARTY_LOOKUP_FAILED, constant(true)) + .process(partiesResponseProcessor) + .setBody(constant(null)) + .setHeader(Exchange.HTTP_RESPONSE_CODE, constant(200)); + + from("direct:send-delayed-party-dummy-response") + .delay(mojaPerfRespDelay) + .process(e -> { + String host = e.getIn().getHeader("Host", String.class).split(":")[0]; + + Party party = new Party( // only return fspId from configuration + new PartyIdInfo(IdentifierType.valueOf(e.getIn().getHeader(PARTY_ID_TYPE, String.class)), + e.getIn().getHeader(PARTY_ID, String.class), + null, + partyProperties.getPartyByDomainAndFspId(host, null).getFspId()), + null, + null, + null); + e.setProperty(PAYEE_PARTY_RESPONSE, objectMapper.writeValueAsString(party)); + }) + .to("direct:send-parties-response"); + + from("direct:send-parties-response") + .log(LoggingLevel.DEBUG, "######## PAYEE -> SWITCH - party lookup response - STEP 3") + .id("send-parties-response") + .process(exchange -> { + Party party = objectMapper.readValue(exchange.getProperty(PAYEE_PARTY_RESPONSE, String.class), Party.class); + + exchange.setProperty(PARTY_ID, party.getPartyIdInfo().getPartyIdentifier()); + exchange.setProperty(PARTY_ID_TYPE, party.getPartyIdInfo().getPartyIdType().name()); + exchange.getIn().setBody(new PartySwitchResponseDTO(party)); + mojaloopUtil.setPartyHeadersResponse(exchange); + }) + .process(pojoToString) + .log(LoggingLevel.DEBUG, "Party response from payee: ${body}") + .setHeader(Exchange.HTTP_METHOD, constant("PUT")) + .setProperty(ENDPOINT, simple("/parties/${exchangeProperty." + PARTY_ID_TYPE + "}/${exchangeProperty." + PARTY_ID + "}")) + .to("direct:external-api-call"); + + from("direct:send-parties-error-response") + .log(LoggingLevel.DEBUG, "######## PAYEE -> SWITCH - party lookup error response - STEP 3") + .id("send-parties-error-response") + .process(exchange -> { + exchange.getIn().setBody(exchange.getProperty(ERROR_INFORMATION)); + mojaloopUtil.setPartyHeadersResponse(exchange); + }) + .setHeader(Exchange.HTTP_METHOD, constant("PUT")) + .setProperty(HOST, simple("{{switch.als-host}}")) + .setProperty(ENDPOINT, simple("/parties/${exchangeProperty." + PARTY_ID_TYPE + "}/${exchangeProperty." + PARTY_ID + "}/error")) + .to("direct:external-api-call"); + + from("direct:send-party-lookup") + .id("send-party-lookup") + .log(LoggingLevel.DEBUG, "######## PAYER -> SWITCH - party lookup request - STEP 1") + .process(e -> { + TransactionChannelRequestDTO channelRequest = objectMapper.readValue(e.getProperty(CHANNEL_REQUEST, String.class), TransactionChannelRequestDTO.class); + PartyIdInfo requestedParty = e.getProperty(IS_RTP_REQUEST, Boolean.class) ? channelRequest.getPayer().getPartyIdInfo() : channelRequest.getPayee().getPartyIdInfo(); + e.setProperty(PARTY_ID_TYPE, requestedParty.getPartyIdType()); + e.setProperty(PARTY_ID, requestedParty.getPartyIdentifier()); + e.getIn().setHeader(FSPIOP_SOURCE.headerName(), partyProperties.getPartyByTenant(e.getProperty(TENANT_ID, String.class)).getFspId()); + + mojaloopUtil.setPartyHeadersRequest(e); + }) + .process(addTraceHeaderProcessor) + .setHeader(Exchange.HTTP_METHOD, constant("GET")) + .process(e -> log.info("Mojaloop headers : {}", e.getIn().getHeaders())) + .setProperty(HOST, simple("{{switch.als-host}}")) + .setProperty(ENDPOINT, simple("/parties/${exchangeProperty." + PARTY_ID_TYPE + "}/${exchangeProperty." + PARTY_ID + "}")) + .to("direct:external-api-call") + .log(LoggingLevel.DEBUG,"Response body: ${body}"); + } +} diff --git a/ph-ee-connector-mojaloop-java/src/main/java/org/mifos/connector/mojaloop/party/PartyLookupWorkers.java b/ph-ee-connector-mojaloop-java/src/main/java/org/mifos/connector/mojaloop/party/PartyLookupWorkers.java new file mode 100644 index 000000000..a1f2aa91a --- /dev/null +++ b/ph-ee-connector-mojaloop-java/src/main/java/org/mifos/connector/mojaloop/party/PartyLookupWorkers.java @@ -0,0 +1,186 @@ +package org.mifos.connector.mojaloop.party; + +import com.fasterxml.jackson.databind.ObjectMapper; +import io.camunda.zeebe.client.ZeebeClient; +import org.apache.camel.CamelContext; +import org.apache.camel.Exchange; +import org.apache.camel.ProducerTemplate; +import org.apache.camel.support.DefaultExchange; +import org.mifos.connector.common.mojaloop.dto.Party; +import org.mifos.connector.common.mojaloop.dto.PartyIdInfo; +import org.mifos.connector.common.mojaloop.dto.PartySwitchResponseDTO; +import org.mifos.connector.mojaloop.properties.PartyProperties; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; +import org.springframework.stereotype.Component; +import javax.annotation.PostConstruct; +import java.util.List; +import java.util.Map; +import static org.mifos.connector.common.mojaloop.type.IdentifierType.MSISDN; +import static org.mifos.connector.common.mojaloop.type.MojaloopHeaders.FSPIOP_SOURCE; +import static org.mifos.connector.mojaloop.camel.config.CamelProperties.*; +import static org.mifos.connector.mojaloop.zeebe.ZeebeProcessStarter.zeebeVariablesToCamelHeaders; +import static org.mifos.connector.mojaloop.zeebe.ZeebeVariables.ACCOUNT_CURRENCY; +import static org.mifos.connector.mojaloop.zeebe.ZeebeVariables.CHANNEL_REQUEST; +import static org.mifos.connector.mojaloop.zeebe.ZeebeVariables.ERROR_INFORMATION; +import static org.mifos.connector.mojaloop.zeebe.ZeebeVariables.INITIATOR_FSP_ID; +import static org.mifos.connector.mojaloop.zeebe.ZeebeVariables.IS_RTP_REQUEST; +import static org.mifos.connector.mojaloop.zeebe.ZeebeVariables.ORIGIN_DATE; +import static org.mifos.connector.mojaloop.zeebe.ZeebeVariables.PARTY_ID; +import static org.mifos.connector.mojaloop.zeebe.ZeebeVariables.PARTY_ID_TYPE; +import static org.mifos.connector.mojaloop.zeebe.ZeebeVariables.PARTY_LOOKUP_RETRY_COUNT; +import static org.mifos.connector.mojaloop.zeebe.ZeebeVariables.PAYEE_PARTY_RESPONSE; +import static org.mifos.connector.mojaloop.zeebe.ZeebeVariables.TENANT_ID; +import static org.mifos.connector.mojaloop.zeebe.ZeebeVariables.TRANSACTION_ID; +import static org.mifos.connector.mojaloop.zeebe.ZeebeeWorkers.WORKER_PARTY_LOOKUP_LOCAL_RESPONSE; +import static org.mifos.connector.mojaloop.zeebe.ZeebeeWorkers.WORKER_PARTY_LOOKUP_REQUEST; +import static org.mifos.connector.mojaloop.zeebe.ZeebeeWorkers.WORKER_PARTY_REGISTRATION_ORACLE; + +@Component +@ConditionalOnExpression("!${mojaloop.perf-mode:false}") +public class PartyLookupWorkers { + + private Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Autowired + private ZeebeClient zeebeClient; + + @Autowired + private ProducerTemplate producerTemplate; + + @Autowired + private CamelContext camelContext; + + @Autowired + private PartyProperties partyProperties; + + @Autowired + private ObjectMapper objectMapper; + + @Value("#{'${dfspids}'.split(',')}") + private List dfspids; + + @Value("${zeebe.client.evenly-allocated-max-jobs}") + private int workerMaxJobs; + + @Value("${mojaloop.enabled}") + private boolean isMojaloopEnabled; + + @PostConstruct + public void setupWorkers() { + for (String dfspId : dfspids) { + logger.info("## generating " + WORKER_PARTY_LOOKUP_REQUEST + "{} zeebe worker", dfspId); + zeebeClient.newWorker() + .jobType(WORKER_PARTY_LOOKUP_REQUEST + dfspId) + .handler((client, job) -> { + logger.info("Job '{}' started from process '{}' with key {}", job.getType(), job.getBpmnProcessId(), job.getKey()); + Map existingVariables = job.getVariablesAsMap(); + existingVariables.put(PARTY_LOOKUP_RETRY_COUNT, 1 + (Integer) existingVariables.getOrDefault(PARTY_LOOKUP_RETRY_COUNT, -1)); + + boolean isTransactionRequest = (boolean) existingVariables.get(IS_RTP_REQUEST); + String tenantId = (String) existingVariables.get(TENANT_ID); + Object channelRequest = existingVariables.get(CHANNEL_REQUEST); + // only saved for operations to identify workflow + if (existingVariables.get(INITIATOR_FSP_ID) == null) { +// TransactionChannelRequestDTO channelRequestObject = objectMapper.readValue((String) channelRequest, TransactionChannelRequestDTO.class); +// PartyIdInfo initiatorParty = isTransactionRequest ? channelRequestObject.getPayee().getPartyIdInfo() : channelRequestObject.getPayer().getPartyIdInfo(); + String initiatorFspId = partyProperties.getPartyByTenant(tenantId).getFspId(); + existingVariables.put(INITIATOR_FSP_ID, initiatorFspId); + } + + Exchange exchange = new DefaultExchange(camelContext); + if (isMojaloopEnabled) { + exchange.setProperty(TRANSACTION_ID, existingVariables.get(TRANSACTION_ID)); + exchange.setProperty(CHANNEL_REQUEST, channelRequest); + exchange.setProperty(ORIGIN_DATE, existingVariables.get(ORIGIN_DATE)); + exchange.setProperty(IS_RTP_REQUEST, isTransactionRequest); + exchange.setProperty(TENANT_ID, tenantId); + producerTemplate.send("direct:send-party-lookup", exchange); + } else { + PartyIdInfo partyIdInfo = new PartyIdInfo(MSISDN, "27710305999", null, "in03tn05"); + Party party = new Party(partyIdInfo, null, null, null); + PartySwitchResponseDTO response = new PartySwitchResponseDTO(party); + exchange.getIn().setBody(response); + exchange.setProperty(CACHED_TRANSACTION_ID, existingVariables.get(TRANSACTION_ID)); + producerTemplate.send("direct:parties-step4", exchange); + } + + client.newCompleteCommand(job.getKey()) + .variables(existingVariables) + .send() + ; + }) + .name(WORKER_PARTY_LOOKUP_REQUEST + dfspId) + .maxJobsActive(workerMaxJobs) + .open(); + + logger.info("## generating " + WORKER_PARTY_LOOKUP_LOCAL_RESPONSE + "{} zeebe worker", dfspId); + zeebeClient.newWorker() + .jobType(WORKER_PARTY_LOOKUP_LOCAL_RESPONSE + dfspId) + .handler((client, job) -> { + logger.info("Job '{}' started from process '{}' with key {}", job.getType(), job.getBpmnProcessId(), job.getKey()); + Map existingVariables = job.getVariablesAsMap(); + + Exchange exchange = new DefaultExchange(camelContext); + Object errorInformation = existingVariables.get(ERROR_INFORMATION); + + zeebeVariablesToCamelHeaders(existingVariables, exchange, + FSPIOP_SOURCE.headerName(), + HEADER_TRACEPARENT, + HEADER_DATE + ); + + if (errorInformation != null) { + + exchange.setProperty(ERROR_INFORMATION, errorInformation); + exchange.setProperty(PARTY_ID_TYPE, existingVariables.get(PARTY_ID_TYPE)); + exchange.setProperty(PARTY_ID, existingVariables.get(PARTY_ID)); + + logger.debug("Error info: {}", objectMapper.writeValueAsString(errorInformation)); + logger.debug("Zeebe variables: {}", existingVariables); + producerTemplate.send("direct:send-parties-error-response", exchange); + } else { + + exchange.setProperty(PAYEE_PARTY_RESPONSE, existingVariables.get(PAYEE_PARTY_RESPONSE)); + exchange.setProperty(HOST, existingVariables.get("X-Lookup-Callback-Url")); + + producerTemplate.send("direct:send-parties-response", exchange); + } + + client.newCompleteCommand(job.getKey()) + .send() + ; + }) + .name(WORKER_PARTY_LOOKUP_LOCAL_RESPONSE + dfspId) + .maxJobsActive(workerMaxJobs) + .open(); + + logger.info("## generating " + WORKER_PARTY_REGISTRATION_ORACLE + "{} zeebe worker", dfspId); + zeebeClient.newWorker() + .jobType(WORKER_PARTY_REGISTRATION_ORACLE + dfspId) + .handler((client, job) -> { + logger.info("Job '{}' started from process '{}' with key {}", job.getType(), job.getBpmnProcessId(), job.getKey()); + Map existingVariables = job.getVariablesAsMap(); + + Exchange exchange = new DefaultExchange(camelContext); + exchange.setProperty(PARTY_ID_TYPE, existingVariables.get(PARTY_ID_TYPE)); + exchange.setProperty(PARTY_ID, existingVariables.get(PARTY_ID)); + exchange.setProperty(TENANT_ID, existingVariables.get(TENANT_ID)); + exchange.setProperty(ACCOUNT_CURRENCY, existingVariables.get(ACCOUNT_CURRENCY)); + producerTemplate.send("direct:register-party-identifier-in-oracle", exchange); + + client.newCompleteCommand(job.getKey()) + .send() + ; + + logger.info("Job '{}' completed from process '{}' with key {}", job.getType(), job.getBpmnProcessId(), job.getKey()); + }) + .name(WORKER_PARTY_REGISTRATION_ORACLE + dfspId) + .maxJobsActive(workerMaxJobs) + .open(); + } + } +} diff --git a/ph-ee-connector-mojaloop-java/src/main/java/org/mifos/connector/mojaloop/properties/Party.java b/ph-ee-connector-mojaloop-java/src/main/java/org/mifos/connector/mojaloop/properties/Party.java new file mode 100644 index 000000000..a1dcff1aa --- /dev/null +++ b/ph-ee-connector-mojaloop-java/src/main/java/org/mifos/connector/mojaloop/properties/Party.java @@ -0,0 +1,33 @@ +package org.mifos.connector.mojaloop.properties; + +public class Party { + + private String tenantId, fspId, domain; + + public Party() { + } + + public String getTenantId() { + return tenantId; + } + + public void setTenantId(String tenantId) { + this.tenantId = tenantId; + } + + public String getFspId() { + return fspId; + } + + public void setFspId(String fspId) { + this.fspId = fspId; + } + + public String getDomain() { + return domain; + } + + public void setDomain(String domain) { + this.domain = domain; + } +} diff --git a/ph-ee-connector-mojaloop-java/src/main/java/org/mifos/connector/mojaloop/properties/PartyProperties.java b/ph-ee-connector-mojaloop-java/src/main/java/org/mifos/connector/mojaloop/properties/PartyProperties.java new file mode 100644 index 000000000..f80cae3e3 --- /dev/null +++ b/ph-ee-connector-mojaloop-java/src/main/java/org/mifos/connector/mojaloop/properties/PartyProperties.java @@ -0,0 +1,55 @@ +package org.mifos.connector.mojaloop.properties; + +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.List; + +@Component +@ConfigurationProperties +public class PartyProperties { + + private List parties = new ArrayList<>(); + + public PartyProperties() { + } + + public List getParties() { + return parties; + } + + public void setParties(List parties) { + this.parties = parties; + } + + public Party getPartyByDfsp(String dfsp) { + return getParties().stream() + .filter(t -> t.getFspId().equals(dfsp)) + .findFirst() + .orElseThrow(() -> new RuntimeException("Party with dfspId: " + dfsp + ", not configured!")); + } + + public Party getPartyByTenant(String tenant) { + return getParties().stream() + .filter(t -> t.getTenantId().equals(tenant)) + .findFirst() + .orElseThrow(() -> new RuntimeException("Party with tenant: " + tenant + ", not configured!")); + } + + public Party getPartyByDomainAndFspId(String domain, String fspId) { + List filteredParties = getParties().stream() + .filter(t -> t.getDomain().equals(domain)) + .toList(); + if (fspId == null || fspId.isEmpty() || filteredParties.size() == 1) { + return filteredParties.stream() + .findFirst() + .orElseThrow(() -> new RuntimeException("Party with domain: " + domain + ", not configured!")); + } + + return filteredParties.stream() + .filter(t -> t.getFspId().equals(fspId)) + .findFirst() + .orElseThrow(() -> new RuntimeException("Party with domain: " + domain + " and payeeFsp: " + fspId + ", not configured!")); + } +} diff --git a/ph-ee-connector-mojaloop-java/src/main/java/org/mifos/connector/mojaloop/quote/QuoteResponseProcessor.java b/ph-ee-connector-mojaloop-java/src/main/java/org/mifos/connector/mojaloop/quote/QuoteResponseProcessor.java new file mode 100644 index 000000000..dd0fe93a6 --- /dev/null +++ b/ph-ee-connector-mojaloop-java/src/main/java/org/mifos/connector/mojaloop/quote/QuoteResponseProcessor.java @@ -0,0 +1,77 @@ +package org.mifos.connector.mojaloop.quote; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import io.camunda.zeebe.client.ZeebeClient; +import org.apache.camel.Exchange; +import org.apache.camel.Processor; +import org.mifos.connector.mojaloop.ilp.IlpBuilder; +import org.mifos.connector.mojaloop.model.QuoteCallbackDTO; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; +import java.time.Duration; +import java.util.HashMap; +import java.util.Map; +import static org.mifos.connector.mojaloop.zeebe.ZeebeMessages.QUOTE_CALLBACK; +import static org.mifos.connector.mojaloop.zeebe.ZeebeMessages.QUOTE_ERROR; +import static org.mifos.connector.mojaloop.zeebe.ZeebeVariables.ERROR_INFORMATION; +import static org.mifos.connector.mojaloop.zeebe.ZeebeVariables.PAYEE_QUOTE_RESPONSE; +import static org.mifos.connector.mojaloop.zeebe.ZeebeVariables.QUOTE_FAILED; +import static org.mifos.connector.mojaloop.zeebe.ZeebeVariables.QUOTE_ID; + +@Component +public class QuoteResponseProcessor implements Processor { + + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Autowired(required = false) + private ZeebeClient zeebeClient; + + @Autowired + private IlpBuilder ilpBuilder; + + @Autowired + private ObjectMapper objectMapper; + + @Value("${mojaloop.enabled}") + private boolean isMojaloopEnabled; + + @Override + public void process(Exchange exchange) throws JsonProcessingException { + Map variables = new HashMap<>(); + + String messageName; + String error = exchange.getIn().getBody(String.class); + if (exchange.getProperty(QUOTE_FAILED, false, Boolean.class)) { + messageName = QUOTE_ERROR; + variables.put(ERROR_INFORMATION, error); + variables.put(QUOTE_FAILED, true); + } else { + QuoteCallbackDTO response = exchange.getIn().getBody(QuoteCallbackDTO.class); + logger.debug("ILP PACKET: {}", response.getIlpPacket()); + logger.debug("CONDITION: {}", response.getCondition()); + messageName = QUOTE_CALLBACK; + variables.put(PAYEE_QUOTE_RESPONSE, objectMapper.writeValueAsString(response)); + if (isMojaloopEnabled && !ilpBuilder.isValidPacketAgainstCondition(response.getIlpPacket(), response.getCondition())) { + logger.error("Invalid ILP packet for quote: {}", exchange.getIn().getHeader(QUOTE_ID)); + variables.put(QUOTE_FAILED, true); + } else { + variables.put(QUOTE_FAILED, false); + } + } + + if(zeebeClient != null) { + zeebeClient.newPublishMessageCommand() + .messageName(messageName) + .correlationKey(exchange.getIn().getHeader(QUOTE_ID, String.class)) + .timeToLive(Duration.ofMillis(30000)) + .variables(variables) + .send(); + } else { + logger.error("Mojaloop quote request failed: {}", error); + } + } +} diff --git a/ph-ee-connector-mojaloop-java/src/main/java/org/mifos/connector/mojaloop/quote/QuoteRoutes.java b/ph-ee-connector-mojaloop-java/src/main/java/org/mifos/connector/mojaloop/quote/QuoteRoutes.java new file mode 100644 index 000000000..40d635c27 --- /dev/null +++ b/ph-ee-connector-mojaloop-java/src/main/java/org/mifos/connector/mojaloop/quote/QuoteRoutes.java @@ -0,0 +1,319 @@ +package org.mifos.connector.mojaloop.quote; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.apache.camel.Exchange; +import org.apache.camel.LoggingLevel; +import org.apache.camel.Processor; +import org.mifos.connector.common.ams.dto.QuoteFspResponseDTO; +import org.mifos.connector.common.camel.ErrorHandlerRouteBuilder; +import org.mifos.connector.common.channel.dto.TransactionChannelRequestDTO; +import org.mifos.connector.common.mojaloop.dto.Extension; +import org.mifos.connector.common.mojaloop.dto.ExtensionList; +import org.mifos.connector.common.mojaloop.dto.FspMoneyData; +import org.mifos.connector.common.mojaloop.dto.MoneyData; +import org.mifos.connector.common.mojaloop.dto.Party; +import org.mifos.connector.common.mojaloop.dto.PartyIdInfo; +import org.mifos.connector.common.mojaloop.dto.QuoteSwitchRequestDTO; +import org.mifos.connector.common.mojaloop.dto.QuoteSwitchResponseDTO; +import org.mifos.connector.common.mojaloop.dto.TransactionType; +import org.mifos.connector.common.mojaloop.type.AmountType; +import org.mifos.connector.mojaloop.camel.trace.AddTraceHeaderProcessor; +import org.mifos.connector.mojaloop.ilp.Ilp; +import org.mifos.connector.mojaloop.ilp.IlpBuilder; +import org.mifos.connector.mojaloop.model.QuoteCallbackDTO; +import org.mifos.connector.mojaloop.properties.PartyProperties; +import org.mifos.connector.mojaloop.util.MojaloopUtil; +import org.mifos.connector.mojaloop.zeebe.ZeebeProcessStarter; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; +import java.math.BigDecimal; +import java.time.LocalDateTime; +import static java.math.BigDecimal.ZERO; +import static org.mifos.connector.common.mojaloop.type.MojaloopHeaders.FSPIOP_DESTINATION; +import static org.mifos.connector.common.mojaloop.type.MojaloopHeaders.FSPIOP_SOURCE; +import static org.mifos.connector.mojaloop.camel.config.CamelProperties.*; +import static org.mifos.connector.mojaloop.zeebe.ZeebeVariables.*; + +@Component +public class QuoteRoutes extends ErrorHandlerRouteBuilder { + private Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Value("${mojaloop.perf-mode}") + private boolean mojaPerfMode; + + @Value("${mojaloop.perf-resp-delay}") + private int mojaPerfRespDelay; + + @Value("${bpmn.flows.quote}") + private String quoteFlow; + + @Value("${switch.quotes-host}") + private String quoteHost; + + @Autowired + private IlpBuilder ilpBuilder; + + @Autowired + private Processor pojoToString; + + @Autowired + private ObjectMapper objectMapper; + + @Autowired + private ZeebeProcessStarter zeebeProcessStarter; + + @Autowired + private AddTraceHeaderProcessor addTraceHeaderProcessor; + + @Autowired + private PartyProperties partyProperties; + + @Autowired + private MojaloopUtil mojaloopUtil; + + @Autowired + private QuoteResponseProcessor quoteResponseProcessor; + + public QuoteRoutes() { + super.configure(); + } + + @Override + public void configure() { + from("rest:POST:/switch/quotes") + .log(LoggingLevel.DEBUG, "######## SWITCH -> PAYEE - forward quote request - STEP 2") + .setProperty(QUOTE_SWITCH_REQUEST, bodyAs(String.class)) + .choice() // @formatter:off + .when(e -> mojaPerfMode) + .wireTap("direct:send-delayed-quote-dummy-response") + .endChoice() + .otherwise() + //.unmarshal().json(JsonLibrary.Jackson, QuoteSwitchRequestDTO.class) + .setProperty(CLASS_TYPE, constant(QuoteSwitchRequestDTO.class)) + .to("direct:body-unmarshling") + .process(exchange -> { // @formatter:on + QuoteSwitchRequestDTO request = exchange.getIn().getBody(QuoteSwitchRequestDTO.class); + PartyIdInfo payee = request.getPayee().getPartyIdInfo(); + String tenantId = partyProperties.getPartyByDfsp(payee.getFspId()).getTenantId(); + + zeebeProcessStarter.startZeebeWorkflow(quoteFlow.replace("{tenant}", tenantId), + variables -> { + variables.put("initiator", request.getTransactionType().getInitiator()); + variables.put("initiatorType", request.getTransactionType().getInitiatorType()); + variables.put("scenario", request.getTransactionType().getScenario()); + variables.put("amount", new FspMoneyData(request.getAmount().getAmountDecimal(), request.getAmount().getCurrency())); + variables.put("transactionId", request.getTransactionId()); + variables.put("transferCode", request.getTransactionRequestId()); // TODO is that right? + + ExtensionList extensionList = request.getExtensionList(); + String note = extensionList == null ? "" : extensionList.getExtension().stream() + .filter(e -> "comment".equals(e.getKey())) + .findFirst() + .map(Extension::getValue) + .orElse(""); + variables.put("note", note); + + variables.put(QUOTE_ID, request.getQuoteId()); + variables.put(FSPIOP_SOURCE.headerName(), payee.getFspId()); + variables.put(FSPIOP_DESTINATION.headerName(), request.getPayer().getPartyIdInfo().getFspId()); + variables.put(TRANSACTION_ID, request.getTransactionId()); + variables.put(QUOTE_SWITCH_REQUEST, exchange.getProperty(QUOTE_SWITCH_REQUEST)); + variables.put(QUOTE_SWITCH_REQUEST_AMOUNT, request.getAmount()); + variables.put(TENANT_ID, tenantId); + if(exchange.getIn().getHeader("X-Quote-Callback-Url")!=null) { + variables.put("X-Quote-Callback-Url", exchange.getIn().getHeader("X-Quote-Callback-Url")); + } + else { + variables.put("X-Quote-Callback-Url", quoteHost); + } + + ZeebeProcessStarter.camelHeadersToZeebeVariables(exchange, variables, + HEADER_DATE, + HEADER_TRACEPARENT + ); + }); + } + ) + .endChoice() + .end() + .setBody(constant(null)) + .setHeader(Exchange.HTTP_RESPONSE_CODE, constant(202)); + + from("direct:send-delayed-quote-dummy-response") + .delay(mojaPerfRespDelay) + .process(exchange -> { + String currency = "TZS"; + FspMoneyData fspFee = new FspMoneyData(ZERO, currency); + FspMoneyData fspCommission = new FspMoneyData(ZERO, currency); + + QuoteFspResponseDTO response = new QuoteFspResponseDTO(); + response.setFspFee(fspFee); + response.setFspCommission(fspCommission); + + exchange.getIn().setHeader(LOCAL_QUOTE_RESPONSE, objectMapper.writeValueAsString(response)); + }) + .to("direct:send-quote-to-switch"); + + + from("rest:PUT:/switch/quotes/{" + QUOTE_ID + "}") + .setProperty(CLASS_TYPE, constant(QuoteCallbackDTO.class)) + .to("direct:body-unmarshling") + .process(exchange -> logger.debug("Received callback: {}", objectMapper.writeValueAsString(exchange.getIn().getBody(QuoteCallbackDTO.class)))) + .to("direct:quotes-step4"); + + from("direct:quotes-step4") + .log(LoggingLevel.DEBUG, "######## SWITCH -> PAYER - response for quote request - STEP 4") + .process(quoteResponseProcessor) + .setBody(constant(null)) + .setHeader(Exchange.HTTP_RESPONSE_CODE, constant(200)); + + from("rest:PUT:/switch/quotes/{" + QUOTE_ID + "}/error") + .log(LoggingLevel.ERROR, "######## SWITCH -> PAYER - quote error") + .log(LoggingLevel.DEBUG,"Body: ${body}") + .setProperty(QUOTE_FAILED, constant(true)) + .process(quoteResponseProcessor) + .setBody(constant(null)) + .setHeader(Exchange.HTTP_RESPONSE_CODE, constant(200)); + + from("direct:send-quote-error-to-switch") + .id("send-quote-error-to-switch") + //.unmarshal().json(JsonLibrary.Jackson, QuoteSwitchRequestDTO.class) + .setProperty(CLASS_TYPE, constant(QuoteSwitchRequestDTO.class)) + .to("direct:body-unmarshling") + .process(e -> { + QuoteSwitchRequestDTO request = e.getIn().getBody(QuoteSwitchRequestDTO.class); + mojaloopUtil.setQuoteHeadersResponse(e, request); + e.getIn().setBody(e.getProperty(ERROR_INFORMATION)); + e.setProperty(QUOTE_ID, request.getQuoteId()); + }) + .toD("rest:PUT:/quotes/${exchangeProperty." + QUOTE_ID + "}/error?host={{switch.quotes-host}}"); + + from("direct:send-quote-to-switch") + .id("send-quote-to-switch") + .log(LoggingLevel.DEBUG, "######## PAYEE -> SWITCH - response for quote request - STEP 3") + //.unmarshal().json(JsonLibrary.Jackson, QuoteSwitchRequestDTO.class) + .setProperty(CLASS_TYPE, constant(QuoteSwitchRequestDTO.class)) + .to("direct:body-unmarshling") + .process(exchange -> { + QuoteSwitchRequestDTO request = exchange.getIn().getBody(QuoteSwitchRequestDTO.class); + MoneyData requestAmount = request.getAmount(); + stripAmount(requestAmount); + + Ilp ilp = ilpBuilder.build(request.getTransactionId(), + request.getQuoteId(), + requestAmount.getAmountDecimal(), + requestAmount.getCurrency(), + objectMapper.readValue(objectMapper.writeValueAsString(request.getPayer()), + org.mifos.connector.mojaloop.ilp.Party.class), + objectMapper.readValue(objectMapper.writeValueAsString(request.getPayee()), + org.mifos.connector.mojaloop.ilp.Party.class), + requestAmount.getAmountDecimal()); + + String localQuoteResponseString = exchange.getIn().getHeader(LOCAL_QUOTE_RESPONSE, String.class); + logger.debug("## parsing local quote response string: {}", localQuoteResponseString); + logger.debug("ILP object: {}", objectMapper.writeValueAsString(ilp)); + QuoteFspResponseDTO localQuoteResponse = objectMapper.readValue(localQuoteResponseString, QuoteFspResponseDTO.class); + FspMoneyData fspFee = localQuoteResponse.getFspFee(); + FspMoneyData fspCommission = localQuoteResponse.getFspCommission(); + + // amount format: ^([0]|([1-9][0-9]{0,17}))([.][0-9]{0,3}[1-9])?$ + BigDecimal fspFeeAmount = (fspFee != null ? fspFee.getAmount() : ZERO).stripTrailingZeros(); + String fspFeeCurrency = fspFee != null ? fspFee.getCurrency() : requestAmount.getCurrency(); + BigDecimal fspCommissionAmount = (fspCommission != null ? fspCommission.getAmount() : ZERO).stripTrailingZeros(); + String fspCommissionCurrency = fspCommission != null ? fspCommission.getCurrency() : requestAmount.getCurrency(); + + QuoteSwitchResponseDTO response = new QuoteSwitchResponseDTO( + requestAmount, + new MoneyData(requestAmount.getAmountDecimal().subtract(fspFeeAmount).subtract(fspCommissionAmount).stripTrailingZeros().toPlainString(), + requestAmount.getCurrency()), + new MoneyData(fspFeeAmount.compareTo(ZERO) == 0 ? "0" : fspFeeAmount.toPlainString(), fspFeeCurrency), + new MoneyData(fspCommissionAmount.compareTo(ZERO) == 0 ? "0" : fspCommissionAmount.toPlainString(), fspCommissionCurrency), + LocalDateTime.now().plusHours(1), + null, + ilp.getPacket(), + ilp.getCondition(), + request.getExtensionList()); + + exchange.getIn().setBody(response); + exchange.setProperty(QUOTE_ID, request.getQuoteId()); + + mojaloopUtil.setQuoteHeadersResponse(exchange, request); + }) + .process(pojoToString) + .log(LoggingLevel.DEBUG, "Quote response from payee: ${body}") + .setHeader(Exchange.HTTP_METHOD, constant("PUT")) + .setProperty(ENDPOINT, simple("/quotes/${exchangeProperty." + QUOTE_ID + "}")) + .to("direct:external-api-call"); + + from("direct:send-quote") + .id("send-quote") + .log(LoggingLevel.DEBUG, "######## PAYER -> SWITCH - quote request - STEP 1") + .process(exchange -> { + TransactionChannelRequestDTO channelRequest = objectMapper.readValue(exchange.getProperty(CHANNEL_REQUEST, String.class), TransactionChannelRequestDTO.class); + logger.debug("Channel request: {}", channelRequest); + TransactionType transactionType = new TransactionType(); + transactionType.setInitiator(channelRequest.getTransactionType().getInitiator()); + transactionType.setInitiatorType(channelRequest.getTransactionType().getInitiatorType()); + transactionType.setScenario(channelRequest.getTransactionType().getScenario()); + + PartyIdInfo payerParty = channelRequest.getPayer().getPartyIdInfo(); + String payerFspId = partyProperties.getPartyByTenant(exchange.getProperty(TENANT_ID, String.class)).getFspId(); + PartyIdInfo requestPayeePartyIdInfo = channelRequest.getPayee().getPartyIdInfo(); + String payeeFspId = partyProperties.getPartyByTenant(requestPayeePartyIdInfo.getFspId()).getFspId(); + Party payer = new Party( + new PartyIdInfo(payerParty.getPartyIdType(), + payerParty.getPartyIdentifier(), + null, + payerFspId), + null, + null, + null); + + + Party payee = new Party( + new PartyIdInfo(requestPayeePartyIdInfo.getPartyIdType(), + requestPayeePartyIdInfo.getPartyIdentifier(), + null, + payeeFspId), + null, + null, + null); + + MoneyData requestAmount = channelRequest.getAmount(); + logger.debug("Amount decimal: {}", channelRequest.getAmount().getAmountDecimal()); + stripAmount(requestAmount); + QuoteSwitchRequestDTO quoteRequest = new QuoteSwitchRequestDTO( + exchange.getProperty(TRANSACTION_ID, String.class), + null, // TODO previously sent transactionRequest, use this? + exchange.getProperty(QUOTE_ID, String.class), + payee, + payer, + AmountType.RECEIVE, + requestAmount, + null, + transactionType, + null, + null, // TODO should be used other then extensions for comment? + null, + channelRequest.getExtensionList()); + exchange.getIn().setBody(quoteRequest); + + exchange.setProperty(FSPIOP_SOURCE.headerName(), payerFspId); + exchange.setProperty(FSPIOP_DESTINATION.headerName(), exchange.getProperty(PARTY_LOOKUP_FSP_ID)); + mojaloopUtil.setQuoteHeadersRequest(exchange); + }) + .process(pojoToString) + .process(addTraceHeaderProcessor) + .setHeader(Exchange.HTTP_METHOD, constant("POST")) + .setProperty(HOST, simple("{{switch.quotes-host}}")) + .setProperty(ENDPOINT, constant("/quotes")) + .to("direct:external-api-call"); + } + + private void stripAmount(MoneyData requestAmount) { + requestAmount.setAmount(requestAmount.getAmountDecimal().stripTrailingZeros().toPlainString()); + } +} diff --git a/ph-ee-connector-mojaloop-java/src/main/java/org/mifos/connector/mojaloop/quote/QuoteWorkers.java b/ph-ee-connector-mojaloop-java/src/main/java/org/mifos/connector/mojaloop/quote/QuoteWorkers.java new file mode 100644 index 000000000..768a1603f --- /dev/null +++ b/ph-ee-connector-mojaloop-java/src/main/java/org/mifos/connector/mojaloop/quote/QuoteWorkers.java @@ -0,0 +1,161 @@ +package org.mifos.connector.mojaloop.quote; + +import com.fasterxml.jackson.databind.ObjectMapper; +import io.camunda.zeebe.client.ZeebeClient; +import org.apache.camel.CamelContext; +import org.apache.camel.Exchange; +import org.apache.camel.ProducerTemplate; +import org.apache.camel.support.DefaultExchange; +import org.mifos.connector.common.channel.dto.TransactionChannelRequestDTO; +import org.mifos.connector.common.mojaloop.dto.FspMoneyData; +import org.mifos.connector.common.mojaloop.dto.QuoteSwitchResponseDTO; +import org.mifos.connector.mojaloop.zeebe.ZeebeProcessStarter; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; +import org.springframework.stereotype.Component; +import javax.annotation.PostConstruct; +import java.math.BigDecimal; +import java.util.List; +import java.util.Map; +import java.util.UUID; +import static org.mifos.connector.common.mojaloop.type.MojaloopHeaders.FSPIOP_DESTINATION; +import static org.mifos.connector.common.mojaloop.type.MojaloopHeaders.FSPIOP_SOURCE; +import static org.mifos.connector.mojaloop.camel.config.CamelProperties.HEADER_DATE; +import static org.mifos.connector.mojaloop.camel.config.CamelProperties.HEADER_TRACEPARENT; +import static org.mifos.connector.mojaloop.camel.config.CamelProperties.HOST; +import static org.mifos.connector.mojaloop.zeebe.ZeebeVariables.CHANNEL_REQUEST; +import static org.mifos.connector.mojaloop.zeebe.ZeebeVariables.ERROR_INFORMATION; +import static org.mifos.connector.mojaloop.zeebe.ZeebeVariables.LOCAL_QUOTE_RESPONSE; +import static org.mifos.connector.mojaloop.zeebe.ZeebeVariables.ORIGIN_DATE; +import static org.mifos.connector.mojaloop.zeebe.ZeebeVariables.PARTY_LOOKUP_FSP_ID; +import static org.mifos.connector.mojaloop.zeebe.ZeebeVariables.QUOTE_ID; +import static org.mifos.connector.mojaloop.zeebe.ZeebeVariables.QUOTE_SWITCH_REQUEST; +import static org.mifos.connector.mojaloop.zeebe.ZeebeVariables.TENANT_ID; +import static org.mifos.connector.mojaloop.zeebe.ZeebeVariables.TIMEOUT_QUOTE_RETRY_COUNT; +import static org.mifos.connector.mojaloop.zeebe.ZeebeVariables.TRANSACTION_ID; +import static org.mifos.connector.mojaloop.zeebe.ZeebeeWorkers.WORKER_PAYEE_QUOTE_RESPONSE; +import static org.mifos.connector.mojaloop.zeebe.ZeebeeWorkers.WORKER_QUOTE; + +@Component +@ConditionalOnExpression("!${mojaloop.perf-mode:false}") +public class QuoteWorkers { + + private Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Autowired + private ZeebeClient zeebeClient; + + @Autowired + private ProducerTemplate producerTemplate; + + @Autowired + private CamelContext camelContext; + + @Value("#{'${dfspids}'.split(',')}") + private List dfspids; + + @Value("${zeebe.client.evenly-allocated-max-jobs}") + private int workerMaxJobs; + + @Value("${mojaloop.enabled}") + private boolean isMojaloopEnabled; + + @Autowired + private ObjectMapper objectMapper; + + @PostConstruct + public void setupWorkers() { + for (String dfspId : dfspids) { + logger.info("## generating " + WORKER_QUOTE + "{} zeebe worker", dfspId); + zeebeClient.newWorker() + .jobType(WORKER_QUOTE + dfspId) + .handler((client, job) -> { + logger.info("Job '{}' started from process '{}' with key {}", job.getType(), job.getBpmnProcessId(), job.getKey()); + + Map existingVariables = job.getVariablesAsMap(); + existingVariables.put(TIMEOUT_QUOTE_RETRY_COUNT, 1 + (Integer) existingVariables.getOrDefault(TIMEOUT_QUOTE_RETRY_COUNT, -1)); + Object quoteId = existingVariables.get(QUOTE_ID); + String transactionId = (String) existingVariables.get(TRANSACTION_ID); + if (quoteId == null) { + quoteId = UUID.randomUUID().toString(); + existingVariables.put(QUOTE_ID, quoteId); + } + + Exchange exchange = new DefaultExchange(camelContext); + if (isMojaloopEnabled) { + exchange.setProperty(TRANSACTION_ID, transactionId); + exchange.setProperty(CHANNEL_REQUEST, existingVariables.get(CHANNEL_REQUEST)); + exchange.setProperty(ORIGIN_DATE, existingVariables.get(ORIGIN_DATE)); + exchange.setProperty(PARTY_LOOKUP_FSP_ID, existingVariables.get(PARTY_LOOKUP_FSP_ID)); + exchange.setProperty(TENANT_ID, existingVariables.get(TENANT_ID)); + exchange.setProperty(QUOTE_ID, quoteId); + producerTemplate.send("direct:send-quote", exchange); + } else { + TransactionChannelRequestDTO channelRequest = objectMapper.readValue((String) existingVariables.get(CHANNEL_REQUEST), TransactionChannelRequestDTO.class); + QuoteSwitchResponseDTO response = new QuoteSwitchResponseDTO(); + response.setTransferAmount(channelRequest.getAmount()); + response.setPayeeFspFee(new FspMoneyData(BigDecimal.ZERO, channelRequest.getAmount().getCurrency()).toMoneyData()); + response.setPayeeFspCommission(new FspMoneyData(BigDecimal.ZERO, channelRequest.getAmount().getCurrency()).toMoneyData()); + response.setExpiration("never"); + response.setIlpPacket("ilp"); + response.setCondition("condition"); + + exchange.getIn().setBody(response); + exchange.getIn().setHeader(QUOTE_ID, quoteId); + producerTemplate.send("direct:quotes-step4", exchange); + } + + client.newCompleteCommand(job.getKey()) + .variables(existingVariables) + .send() + ; + }) + .name(WORKER_QUOTE + dfspId) + .maxJobsActive(workerMaxJobs) + .open(); + + logger.info("## generating " + WORKER_PAYEE_QUOTE_RESPONSE + "{} zeebe worker", dfspId); + zeebeClient.newWorker() + .jobType(WORKER_PAYEE_QUOTE_RESPONSE + dfspId) + .handler((client, job) -> { + logger.info("Job '{}' started from process '{}' with key {}", job.getType(), job.getBpmnProcessId(), job.getKey()); + Map existingVariables = job.getVariablesAsMap(); + + Exchange exchange = new DefaultExchange(camelContext); + exchange.getIn().setBody(existingVariables.get(QUOTE_SWITCH_REQUEST)); + Object errorInformation = existingVariables.get(ERROR_INFORMATION); + if (errorInformation != null) { + ZeebeProcessStarter.zeebeVariablesToCamelHeaders(existingVariables, exchange, + FSPIOP_SOURCE.headerName(), + FSPIOP_DESTINATION.headerName(), + HEADER_DATE, + HEADER_TRACEPARENT + ); + + exchange.setProperty(ERROR_INFORMATION, errorInformation); + producerTemplate.send("direct:send-quote-error-to-switch", exchange); + } else { + ZeebeProcessStarter.zeebeVariablesToCamelHeaders(existingVariables, exchange, + FSPIOP_SOURCE.headerName(), + FSPIOP_DESTINATION.headerName(), + HEADER_DATE, + HEADER_TRACEPARENT, + LOCAL_QUOTE_RESPONSE + ); + exchange.setProperty(HOST, existingVariables.get("X-Quote-Callback-Url")); + + producerTemplate.send("direct:send-quote-to-switch", exchange); + } + client.newCompleteCommand(job.getKey()) + .send() + ; + }) + .name(WORKER_PAYEE_QUOTE_RESPONSE + dfspId) + .maxJobsActive(workerMaxJobs) + .open(); + } + } +} diff --git a/ph-ee-connector-mojaloop-java/src/main/java/org/mifos/connector/mojaloop/transactionrequest/TransactionResponseProcessor.java b/ph-ee-connector-mojaloop-java/src/main/java/org/mifos/connector/mojaloop/transactionrequest/TransactionResponseProcessor.java new file mode 100644 index 000000000..78bc9bfc9 --- /dev/null +++ b/ph-ee-connector-mojaloop-java/src/main/java/org/mifos/connector/mojaloop/transactionrequest/TransactionResponseProcessor.java @@ -0,0 +1,62 @@ +package org.mifos.connector.mojaloop.transactionrequest; + +import com.fasterxml.jackson.databind.ObjectMapper; +import io.camunda.zeebe.client.ZeebeClient; +import org.apache.camel.Exchange; +import org.apache.camel.Processor; +import org.mifos.connector.common.mojaloop.dto.TransactionRequestSwitchResponseDTO; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.time.Duration; +import java.util.HashMap; +import java.util.Map; + +import static org.mifos.connector.mojaloop.zeebe.ZeebeVariables.ERROR_INFORMATION; +import static org.mifos.connector.mojaloop.zeebe.ZeebeVariables.TRANSACTION_ID; +import static org.mifos.connector.mojaloop.zeebe.ZeebeVariables.TRANSACTION_REQUEST_RESPONSE; +import static org.mifos.connector.mojaloop.zeebe.ZeebeVariables.TRANSACTION_REQUEST_FAILED; +import static org.mifos.connector.mojaloop.zeebe.ZeebeVariables.TRANSACTION_STATE; +import static org.mifos.connector.mojaloop.zeebe.ZeebeMessages.TRANSACTION_REQUEST; + +@Component +public class TransactionResponseProcessor implements Processor { + + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Autowired(required = false) + private ZeebeClient zeebeClient; + + @Autowired + private ObjectMapper objectMapper; + + @Override + public void process(Exchange exchange) throws Exception { + Map variables = new HashMap<>(); + Object isTransactionRequestFailed = exchange.getProperty(TRANSACTION_REQUEST_FAILED); + String error = exchange.getIn().getBody(String.class); + + if (isTransactionRequestFailed != null && (boolean)isTransactionRequestFailed) { + variables.put(ERROR_INFORMATION, error); + variables.put(TRANSACTION_REQUEST_FAILED, true); + } else { + TransactionRequestSwitchResponseDTO response = exchange.getIn().getBody(TransactionRequestSwitchResponseDTO.class); + variables.put(TRANSACTION_REQUEST_RESPONSE, objectMapper.writeValueAsString(response)); + variables.put(TRANSACTION_REQUEST_FAILED, false); + variables.put(TRANSACTION_STATE, response.getTransactionRequestState().name()); // TODO prepare for pending state? + } + + if(zeebeClient != null) { + zeebeClient.newPublishMessageCommand() + .messageName(TRANSACTION_REQUEST) + .correlationKey(exchange.getIn().getHeader(TRANSACTION_ID, String.class)) + .timeToLive(Duration.ofMillis(30000)) + .variables(variables) + .send(); + } else { + logger.error("Mojaloop transactionRequest request failed: {}", error); + } + } +} diff --git a/ph-ee-connector-mojaloop-java/src/main/java/org/mifos/connector/mojaloop/transactionrequest/TransactionRoutes.java b/ph-ee-connector-mojaloop-java/src/main/java/org/mifos/connector/mojaloop/transactionrequest/TransactionRoutes.java new file mode 100644 index 000000000..02487fc5d --- /dev/null +++ b/ph-ee-connector-mojaloop-java/src/main/java/org/mifos/connector/mojaloop/transactionrequest/TransactionRoutes.java @@ -0,0 +1,221 @@ +package org.mifos.connector.mojaloop.transactionrequest; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.apache.camel.Exchange; +import org.apache.camel.LoggingLevel; +import org.apache.camel.Processor; +import org.apache.camel.model.dataformat.JsonLibrary; +import org.mifos.connector.common.camel.ErrorHandlerRouteBuilder; +import org.mifos.connector.common.channel.dto.TransactionChannelRequestDTO; +import org.mifos.connector.common.mojaloop.dto.Party; +import org.mifos.connector.common.mojaloop.dto.PartyIdInfo; +import org.mifos.connector.common.mojaloop.dto.TransactionRequestSwitchRequestDTO; +import org.mifos.connector.common.mojaloop.dto.TransactionRequestSwitchResponseDTO; +import org.mifos.connector.common.mojaloop.dto.TransactionType; +import org.mifos.connector.common.mojaloop.type.AuthenticationType; +import org.mifos.connector.common.mojaloop.type.InitiatorType; +import org.mifos.connector.common.mojaloop.type.Scenario; +import org.mifos.connector.common.mojaloop.type.TransactionRequestState; +import org.mifos.connector.common.mojaloop.type.TransactionRole; +import org.mifos.connector.mojaloop.camel.trace.AddTraceHeaderProcessor; +import org.mifos.connector.mojaloop.camel.trace.GetCachedTransactionIdProcessor; +import org.mifos.connector.mojaloop.properties.PartyProperties; +import org.mifos.connector.mojaloop.util.MojaloopUtil; +import org.mifos.connector.mojaloop.zeebe.ZeebeProcessStarter; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +import static org.mifos.connector.common.mojaloop.type.MojaloopHeaders.FSPIOP_DESTINATION; +import static org.mifos.connector.common.mojaloop.type.MojaloopHeaders.FSPIOP_SOURCE; +import static org.mifos.connector.mojaloop.camel.config.CamelProperties.*; +import static org.mifos.connector.mojaloop.zeebe.ZeebeVariables.CHANNEL_REQUEST; +import static org.mifos.connector.mojaloop.zeebe.ZeebeVariables.INITIATOR_FSP_ID; +import static org.mifos.connector.mojaloop.zeebe.ZeebeVariables.PARTY_LOOKUP_FSP_ID; +import static org.mifos.connector.mojaloop.zeebe.ZeebeVariables.TENANT_ID; +import static org.mifos.connector.mojaloop.zeebe.ZeebeVariables.TRANSACTION_ID; +import static org.mifos.connector.mojaloop.zeebe.ZeebeVariables.TRANSACTION_REQUEST; +import static org.mifos.connector.mojaloop.zeebe.ZeebeVariables.IS_AUTHORISATION_REQUIRED; +import static org.mifos.connector.mojaloop.zeebe.ZeebeVariables.TRANSACTION_REQUEST_FAILED; +import static org.mifos.connector.mojaloop.zeebe.ZeebeVariables.TRANSACTION_STATE; + +@Component +public class TransactionRoutes extends ErrorHandlerRouteBuilder { + + private Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Value("${bpmn.flows.transaction-request}") + private String transactionRequestFlow; + + @Autowired + private ObjectMapper objectMapper; + + @Autowired + private PartyProperties partyProperties; + + @Autowired + private MojaloopUtil mojaloopUtil; + + @Autowired + private Processor pojoToString; + + @Autowired + private AddTraceHeaderProcessor addTraceHeaderProcessor; + + @Autowired + private GetCachedTransactionIdProcessor getCachedTransactionIdProcessor; + + @Autowired + private ZeebeProcessStarter zeebeProcessStarter; + + @Autowired + private TransactionResponseProcessor transactionResponseProcessor; + + public TransactionRoutes() { + super.configure(); + } + + @Override + public void configure() { + from("rest:POST:/switch/transactionRequests") + .setProperty(TRANSACTION_REQUEST, bodyAs(String.class)) + .unmarshal().json(JsonLibrary.Jackson, TransactionRequestSwitchRequestDTO.class) + .log(LoggingLevel.DEBUG, "######## SWITCH -> PAYER - incoming transactionRequest ${body.transactionRequestId} - STEP 2") + .process(exchange -> { + TransactionRequestSwitchRequestDTO transactionRequest = exchange.getIn().getBody(TransactionRequestSwitchRequestDTO.class); + PartyIdInfo payer = transactionRequest.getPayer(); + org.mifos.connector.mojaloop.properties.Party payerParty = partyProperties.getPartyByDfsp(payer.getFspId()); + zeebeProcessStarter.startZeebeWorkflow(transactionRequestFlow.replace("{tenant}", payerParty.getTenantId()), + variables -> { + try { + variables.put(TRANSACTION_ID, transactionRequest.getTransactionRequestId()); + variables.put(TRANSACTION_REQUEST, exchange.getProperty(TRANSACTION_REQUEST)); + variables.put(PARTY_LOOKUP_FSP_ID, transactionRequest.getPayee().getPartyIdInfo().getFspId()); + variables.put(IS_AUTHORISATION_REQUIRED, transactionRequest.getAuthenticationType() != null); + variables.put(INITIATOR_FSP_ID, payerParty.getFspId()); + variables.put(TENANT_ID, payerParty.getTenantId()); + + TransactionChannelRequestDTO channelRequest = new TransactionChannelRequestDTO(); + channelRequest.setPayer(new Party(payer)); + channelRequest.setPayee(transactionRequest.getPayee()); + TransactionType transactionType = new TransactionType(); + transactionType.setInitiator(TransactionRole.PAYER); + transactionType.setScenario(Scenario.PAYMENT); + transactionType.setInitiatorType(InitiatorType.CONSUMER); + channelRequest.setTransactionType(transactionType); + channelRequest.setAmount(transactionRequest.getAmount()); + variables.put(CHANNEL_REQUEST, objectMapper.writeValueAsString(channelRequest)); + variables.put(TRANSACTION_STATE, TransactionRequestState.RECEIVED.name()); + + ZeebeProcessStarter.camelHeadersToZeebeVariables(exchange, variables, + HEADER_DATE, + HEADER_TRACEPARENT + ); + } catch (Exception e) { + logger.error("Error when creating channelRequest for payer local quote!", e); + } + }); + } + ) + .setBody(constant(null)) + .setHeader(Exchange.HTTP_RESPONSE_CODE, constant(202)); + + from("rest:PUT:/switch/transactionRequests/{" + TRANSACTION_ID + "}") + .log(LoggingLevel.DEBUG, "######## SWITCH -> PAYEE - response for transactionRequest ${header." + TRANSACTION_ID + "} - STEP 4") + .unmarshal().json(JsonLibrary.Jackson, TransactionRequestSwitchResponseDTO.class) + .process(transactionResponseProcessor) + .setBody(constant(null)) + .setHeader(Exchange.HTTP_RESPONSE_CODE, constant(200)); + + from("rest:PUT:/switch/transactionRequests/{" + TRANSACTION_ID + "}/error") + .log(LoggingLevel.DEBUG, "######## SWITCH error with transactionRequest ${header." + TRANSACTION_ID + "}") + .setProperty(TRANSACTION_REQUEST_FAILED, constant(true)) + .process(transactionResponseProcessor) + .setBody(constant(null)) + .setHeader(Exchange.HTTP_RESPONSE_CODE, constant(200)); + + from("direct:send-transaction-request") + .id("send-transaction-request") + .log(LoggingLevel.DEBUG, "######## PAYEE -> SWITCH - transactionRequest request ${exchangeProperty." + TRANSACTION_ID + "} - STEP 1") + .process(e -> { + TransactionChannelRequestDTO channelRequest = objectMapper.readValue(e.getProperty(CHANNEL_REQUEST, String.class), TransactionChannelRequestDTO.class); + PartyIdInfo payeeParty = channelRequest.getPayee().getPartyIdInfo(); + String payeeFspId = partyProperties.getPartyByTenant(e.getProperty(TENANT_ID, String.class)).getFspId(); + payeeParty.setFspId(payeeFspId); + e.setProperty(FSPIOP_SOURCE.headerName(), payeeFspId); + + PartyIdInfo payerParty = channelRequest.getPayer().getPartyIdInfo(); + String payerFspId = e.getProperty(PARTY_LOOKUP_FSP_ID, String.class); + payerParty.setFspId(payerFspId); + e.setProperty(FSPIOP_DESTINATION.headerName(), payerFspId); + + TransactionRequestSwitchRequestDTO tr = new TransactionRequestSwitchRequestDTO(); + tr.setTransactionRequestId(e.getProperty(TRANSACTION_ID, String.class)); + tr.setPayee(new Party(payeeParty, null, null, null)); + tr.setPayer(payerParty); + tr.setAmount(channelRequest.getAmount()); + tr.setTransactionType(channelRequest.getTransactionType()); + tr.setExtensionList(channelRequest.getExtensionList()); + String authType = e.getProperty(AUTH_TYPE, String.class); + if (!"NONE".equals(authType)) { + tr.setAuthenticationType(AuthenticationType.valueOf(authType)); + } + + e.getIn().setBody(tr); + + mojaloopUtil.setTransactionRequestHeadersRequest(e); + }) + .process(pojoToString) + .log(LoggingLevel.DEBUG, "Transaction request from payee: ${body}") + .process(addTraceHeaderProcessor) + .toD("rest:POST:/transactionRequests?host={{switch.transactions-host}}"); + + from("direct:send-transaction-state") + .log(LoggingLevel.DEBUG, "######## PAYER -> SWITCH - transactionState response ${exchangeProperty." + TRANSACTION_ID + "} - STEP 3") + .process(e -> { + TransactionRequestSwitchResponseDTO response = new TransactionRequestSwitchResponseDTO(); + response.setTransactionId(e.getProperty(TRANSACTION_ID, String.class)); + response.setTransactionRequestState(TransactionRequestState.valueOf(e.getProperty(TRANSACTION_STATE, String.class))); + + e.getIn().setBody(response); + mojaloopUtil.setTransactionRequestHeadersResponse(e); + }) + .process(pojoToString) + .log(LoggingLevel.DEBUG, "Transaction request response from payer: ${body}") + .toD("rest:PUT:/transactionRequests/${exchangeProperty." + TRANSACTION_ID + "}?host={{switch.transactions-host}}"); + + // --- Authorizations endpoints --- + from("direct:send-payer-authorisation") + .log(LoggingLevel.DEBUG, "######## PAYER -> SWITCH - authorizations request - STEP 1") + .process(e -> { + }) + .toD("rest:GET:/authorizations/${exchangeProperty." + TRANSACTION_ID + "}?host={{switch.transactions-host}}"); + + from("rest:GET:/switch/authorizations/{" + TRANSACTION_ID + "}") + .log(LoggingLevel.DEBUG, "######## SWITCH -> PAYEE - authorizations request - STEP 2") + .process(e -> { + }); + + from("direct:send-payee-authorisation-response") + .log(LoggingLevel.DEBUG, "######## PAYEE -> SWITCH - authorizations request - STEP 3") + .process(e -> { + }) + .toD("rest:PUT:/authorizations/${exchangeProperty." + TRANSACTION_ID + "}?host={{switch.transactions-host}}"); + + from("rest:PUT:/switch/authorizations/{" + TRANSACTION_ID + "}") + .log(LoggingLevel.DEBUG, "######## SWITCH -> PAYER - response for authorizations - STEP 4") + .process(e -> { + }) + .setBody(constant(null)) + .setHeader(Exchange.HTTP_RESPONSE_CODE, constant(200)); + + from("rest:PUT:/switch/authorizations/{" + TRANSACTION_ID + "}/error") + .log(LoggingLevel.DEBUG, "######## SWITCH error with authorizations") + .process(e -> { + }) + .setBody(constant(null)) + .setHeader(Exchange.HTTP_RESPONSE_CODE, constant(200)); + } +} diff --git a/ph-ee-connector-mojaloop-java/src/main/java/org/mifos/connector/mojaloop/transactionrequest/TransactionWorkers.java b/ph-ee-connector-mojaloop-java/src/main/java/org/mifos/connector/mojaloop/transactionrequest/TransactionWorkers.java new file mode 100644 index 000000000..7534c721a --- /dev/null +++ b/ph-ee-connector-mojaloop-java/src/main/java/org/mifos/connector/mojaloop/transactionrequest/TransactionWorkers.java @@ -0,0 +1,168 @@ +package org.mifos.connector.mojaloop.transactionrequest; + +import com.fasterxml.jackson.databind.ObjectMapper; +import io.camunda.zeebe.client.ZeebeClient; +import org.apache.camel.CamelContext; +import org.apache.camel.Exchange; +import org.apache.camel.ProducerTemplate; +import org.apache.camel.support.DefaultExchange; +import org.mifos.connector.common.channel.dto.TransactionChannelRequestDTO; +import org.mifos.connector.mojaloop.zeebe.ZeebeProcessStarter; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; +import org.springframework.stereotype.Component; + +import javax.annotation.PostConstruct; +import java.util.List; +import java.util.Map; + +import static org.mifos.connector.common.mojaloop.type.MojaloopHeaders.FSPIOP_DESTINATION; +import static org.mifos.connector.common.mojaloop.type.MojaloopHeaders.FSPIOP_SOURCE; +import static org.mifos.connector.mojaloop.camel.config.CamelProperties.*; +import static org.mifos.connector.mojaloop.zeebe.ZeebeVariables.CHANNEL_REQUEST; +import static org.mifos.connector.mojaloop.zeebe.ZeebeVariables.ORIGIN_DATE; +import static org.mifos.connector.mojaloop.zeebe.ZeebeVariables.PARTY_LOOKUP_FSP_ID; +import static org.mifos.connector.mojaloop.zeebe.ZeebeVariables.TENANT_ID; +import static org.mifos.connector.mojaloop.zeebe.ZeebeVariables.TRANSACTION_ID; +import static org.mifos.connector.mojaloop.zeebe.ZeebeVariables.AUTH_RETRIES_LEFT_COUNT; +import static org.mifos.connector.mojaloop.zeebe.ZeebeVariables.PAYER_CONFIRMATION_RETRY_COUNT; +import static org.mifos.connector.mojaloop.zeebe.ZeebeVariables.TRANSACTION_REQUEST_RETRY_COUNT; +import static org.mifos.connector.mojaloop.zeebe.ZeebeVariables.TRANSACTION_STATE; +import static org.mifos.connector.mojaloop.zeebe.ZeebeeWorkers.WORKER_SEND_AUTH_CONFIRMATION; +import static org.mifos.connector.mojaloop.zeebe.ZeebeeWorkers.WORKER_SEND_AUTH_RESPONSE; +import static org.mifos.connector.mojaloop.zeebe.ZeebeeWorkers.WORKER_SEND_TRANSACTION_STATE_RESPONSE; +import static org.mifos.connector.mojaloop.zeebe.ZeebeeWorkers.WORKER_TRANSACTION_REQUEST; + +@Component +@ConditionalOnExpression("!${mojaloop.perf-mode:false}") +public class TransactionWorkers { + + private Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Autowired + private ZeebeClient zeebeClient; + + @Autowired + private ProducerTemplate producerTemplate; + + @Autowired + private CamelContext camelContext; + + @Autowired + private ObjectMapper objectMapper; + + @Value("#{'${dfspids}'.split(',')}") + private List dfspids; + + @Value("${zeebe.client.evenly-allocated-max-jobs}") + private int workerMaxJobs; + + @PostConstruct + public void setupWorkers() { + for (String dfspId : dfspids) { + logger.info("## generating " + WORKER_TRANSACTION_REQUEST + "{} zeebe worker", dfspId); + zeebeClient.newWorker() + .jobType(WORKER_TRANSACTION_REQUEST + dfspId) + .handler((client, job) -> { + logger.info("Job '{}' started from process '{}' with key {}", job.getType(), job.getBpmnProcessId(), job.getKey()); + Map existingVariables = job.getVariablesAsMap(); + existingVariables.put(TRANSACTION_REQUEST_RETRY_COUNT, 1 + (Integer) existingVariables.getOrDefault(TRANSACTION_REQUEST_RETRY_COUNT, -1)); + + Exchange exchange = new DefaultExchange(camelContext); + exchange.setProperty(TRANSACTION_ID, existingVariables.get(TRANSACTION_ID)); + exchange.setProperty(PARTY_LOOKUP_FSP_ID, existingVariables.get(PARTY_LOOKUP_FSP_ID)); + exchange.setProperty(CHANNEL_REQUEST, existingVariables.get(CHANNEL_REQUEST)); + exchange.setProperty(ORIGIN_DATE, existingVariables.get(ORIGIN_DATE)); + exchange.setProperty(AUTH_TYPE, existingVariables.get(AUTH_TYPE)); + exchange.setProperty(TENANT_ID, existingVariables.get(TENANT_ID)); + producerTemplate.send("direct:send-transaction-request", exchange); + + client.newCompleteCommand(job.getKey()) + .variables(existingVariables) + .send() + ; + }) + .name(WORKER_TRANSACTION_REQUEST + dfspId) + .maxJobsActive(workerMaxJobs) + .open(); + + logger.info("## generating " + WORKER_SEND_AUTH_CONFIRMATION + "{} zeebe worker", dfspId); + zeebeClient.newWorker() + .jobType(WORKER_SEND_AUTH_CONFIRMATION + dfspId) + .handler((client, job) -> { + logger.info("Job '{}' started from process '{}' with key {}", job.getType(), job.getBpmnProcessId(), job.getKey()); + Map existingVariables = job.getVariablesAsMap(); + +// Exchange exchange = new DefaultExchange(camelContext); +// exchange.setProperty(TRANSACTION_ID, existingVariables.get(TRANSACTION_ID)); +// +// producerTemplate.send("", exchange); + + client.newCompleteCommand(job.getKey()) + .send() + ; + }) + .name(WORKER_SEND_AUTH_CONFIRMATION + dfspId) + .maxJobsActive(workerMaxJobs) + .open(); + + logger.info("## generating " + WORKER_SEND_AUTH_RESPONSE + "{} zeebe worker", dfspId); + zeebeClient.newWorker() + .jobType(WORKER_SEND_AUTH_RESPONSE + dfspId) + .handler((client, job) -> { + logger.info("Job '{}' started from process '{}' with key {}", job.getType(), job.getBpmnProcessId(), job.getKey()); + Map existingVariables = job.getVariablesAsMap(); + existingVariables.put(PAYER_CONFIRMATION_RETRY_COUNT, 1 + (Integer) existingVariables.getOrDefault(PAYER_CONFIRMATION_RETRY_COUNT, -1)); + existingVariables.put(AUTH_RETRIES_LEFT_COUNT, 1 + (Integer) existingVariables.getOrDefault(AUTH_RETRIES_LEFT_COUNT, -1)); + +// Exchange exchange = new DefaultExchange(camelContext); +// exchange.setProperty(TRANSACTION_ID, existingVariables.get(TRANSACTION_ID)); +// producerTemplate.send("", exchange); + + client.newCompleteCommand(job.getKey()) + .variables(existingVariables) + .send() + ; + }) + .name(WORKER_SEND_AUTH_RESPONSE + dfspId) + .maxJobsActive(workerMaxJobs) + .open(); + + logger.info("## generating " + WORKER_SEND_TRANSACTION_STATE_RESPONSE + "{} zeebe worker", dfspId); + zeebeClient.newWorker() + .jobType(WORKER_SEND_TRANSACTION_STATE_RESPONSE + dfspId) + .handler((client, job) -> { + logger.info("Job '{}' started from process '{}' with key {}", job.getType(), job.getBpmnProcessId(), job.getKey()); + Map existingVariables = job.getVariablesAsMap(); + TransactionChannelRequestDTO channelRequest = objectMapper.readValue((String) existingVariables.get(CHANNEL_REQUEST), TransactionChannelRequestDTO.class); + + Exchange exchange = new DefaultExchange(camelContext); + exchange.setProperty(TRANSACTION_ID, existingVariables.get(TRANSACTION_ID)); + exchange.setProperty(TRANSACTION_STATE, existingVariables.get(TRANSACTION_STATE)); + exchange.setProperty(FSPIOP_SOURCE.headerName(), channelRequest.getPayer().getPartyIdInfo().getFspId()); + exchange.setProperty(FSPIOP_DESTINATION.headerName(), channelRequest.getPayee().getPartyIdInfo().getFspId()); + + ZeebeProcessStarter.zeebeVariablesToCamelHeaders(existingVariables, exchange, + HEADER_DATE, + HEADER_TRACEPARENT + ); + + producerTemplate.send("direct:send-transaction-state", exchange); + + client.newCompleteCommand(job.getKey()) + .send() + ; + }) + .name(WORKER_SEND_TRANSACTION_STATE_RESPONSE + dfspId) + .maxJobsActive(workerMaxJobs) + .open(); + + + } + } + + +} diff --git a/ph-ee-connector-mojaloop-java/src/main/java/org/mifos/connector/mojaloop/transfer/TransferResponseProcessor.java b/ph-ee-connector-mojaloop-java/src/main/java/org/mifos/connector/mojaloop/transfer/TransferResponseProcessor.java new file mode 100644 index 000000000..af9e1fe9c --- /dev/null +++ b/ph-ee-connector-mojaloop-java/src/main/java/org/mifos/connector/mojaloop/transfer/TransferResponseProcessor.java @@ -0,0 +1,53 @@ +package org.mifos.connector.mojaloop.transfer; + +import io.camunda.zeebe.client.ZeebeClient; +import org.apache.camel.Exchange; +import org.apache.camel.Processor; +import org.mifos.connector.common.mojaloop.dto.TransferSwitchResponseDTO; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import java.time.Duration; +import java.util.HashMap; +import java.util.Map; +import static org.mifos.connector.mojaloop.camel.config.CamelProperties.CACHED_TRANSACTION_ID; +import static org.mifos.connector.mojaloop.zeebe.ZeebeVariables.ERROR_INFORMATION; +import static org.mifos.connector.mojaloop.zeebe.ZeebeVariables.TRANSFER_FAILED; +import static org.mifos.connector.mojaloop.zeebe.ZeebeVariables.TRANSFER_STATE; +import static org.mifos.connector.mojaloop.zeebe.ZeebeMessages.TRANSFER_RESPONSE; + + +@Component +public class TransferResponseProcessor implements Processor { + + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Autowired(required = false) + private ZeebeClient zeebeClient; + + @Override + public void process(Exchange exchange) { + Map variables = new HashMap<>(); + Object isPayeeTransferFailed = exchange.getProperty(TRANSFER_FAILED); + String error = exchange.getIn().getBody(String.class); + if (isPayeeTransferFailed != null && (boolean)isPayeeTransferFailed) { + variables.put(ERROR_INFORMATION, error); + variables.put(TRANSFER_FAILED, true); + } else { + variables.put(TRANSFER_STATE, exchange.getIn().getBody(TransferSwitchResponseDTO.class).getTransferState().name()); + variables.put(TRANSFER_FAILED, false); + } + + if(zeebeClient != null) { + zeebeClient.newPublishMessageCommand() + .messageName(TRANSFER_RESPONSE) + .correlationKey(exchange.getProperty(CACHED_TRANSACTION_ID, String.class)) + .timeToLive(Duration.ofMillis(30000)) + .variables(variables) + .send(); + } else { + logger.error("Mojaloop transfer request failed: {}", error); + } + } +} diff --git a/ph-ee-connector-mojaloop-java/src/main/java/org/mifos/connector/mojaloop/transfer/TransferRoutes.java b/ph-ee-connector-mojaloop-java/src/main/java/org/mifos/connector/mojaloop/transfer/TransferRoutes.java new file mode 100644 index 000000000..be0609e07 --- /dev/null +++ b/ph-ee-connector-mojaloop-java/src/main/java/org/mifos/connector/mojaloop/transfer/TransferRoutes.java @@ -0,0 +1,218 @@ +package org.mifos.connector.mojaloop.transfer; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.ilp.conditions.models.pdp.Transaction; +import io.camunda.zeebe.client.ZeebeClient; +import org.apache.camel.Exchange; +import org.apache.camel.LoggingLevel; +import org.apache.camel.Processor; +import org.mifos.connector.common.camel.ErrorHandlerRouteBuilder; +import org.mifos.connector.common.channel.dto.TransactionChannelRequestDTO; +import org.mifos.connector.common.mojaloop.dto.*; +import org.mifos.connector.common.mojaloop.type.TransferState; +import org.mifos.connector.common.util.ContextUtil; +import org.mifos.connector.mojaloop.camel.trace.AddTraceHeaderProcessor; +import org.mifos.connector.mojaloop.camel.trace.GetCachedTransactionIdProcessor; +import org.mifos.connector.mojaloop.ilp.Ilp; +import org.mifos.connector.mojaloop.ilp.IlpBuilder; +import org.mifos.connector.mojaloop.util.MojaloopUtil; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; +import java.util.HashMap; +import java.util.Map; +import static org.mifos.connector.common.mojaloop.type.MojaloopHeaders.FSPIOP_DESTINATION; +import static org.mifos.connector.common.mojaloop.type.MojaloopHeaders.FSPIOP_SOURCE; +import static org.mifos.connector.mojaloop.camel.config.CamelProperties.*; +import static org.mifos.connector.mojaloop.zeebe.ZeebeMessages.TRANSFER_MESSAGE; +import static org.mifos.connector.mojaloop.zeebe.ZeebeVariables.CHANNEL_REQUEST; +import static org.mifos.connector.mojaloop.zeebe.ZeebeVariables.ERROR_INFORMATION; +import static org.mifos.connector.mojaloop.zeebe.ZeebeVariables.SWITCH_TRANSFER_REQUEST; +import static org.mifos.connector.mojaloop.zeebe.ZeebeVariables.TRANSACTION_ID; +import static org.mifos.connector.mojaloop.zeebe.ZeebeVariables.TRANSFER_FAILED; + +@Component +public class TransferRoutes extends ErrorHandlerRouteBuilder { + + @Value("${mojaloop.perf-mode}") + private boolean mojaPerfMode; + + @Value("${mojaloop.perf-resp-delay}") + private int mojaPerfRespDelay; + + @Value("${switch.transfers-host}") + private String transferHost; + + @Autowired + private IlpBuilder ilpBuilder; + + @Autowired + private Processor pojoToString; + + @Autowired(required = false) + private ZeebeClient zeebeClient; + + @Autowired + private MojaloopUtil mojaloopUtil; + + @Autowired + private ObjectMapper objectMapper; + + @Autowired + private AddTraceHeaderProcessor addTraceHeaderProcessor; + + @Autowired + private GetCachedTransactionIdProcessor getCachedTransactionIdProcessor; + + @Autowired + private TransferResponseProcessor transferResponseProcessor; + + public TransferRoutes() { + super.configure(); + } + + @Override + public void configure() { + //@formatter:off + from("rest:POST:/switch/transfers") + .setProperty(SWITCH_TRANSFER_REQUEST, bodyAs(String.class)) + .setProperty(CLASS_TYPE, constant(TransferSwitchRequestDTO.class)) + .to("direct:body-unmarshling") + .choice() + .when(e -> mojaPerfMode) + .wireTap("direct:send-delayed-transfer-dummy-response") + .endChoice() + .otherwise() + .process(exchange -> { + TransferSwitchRequestDTO request = exchange.getIn().getBody(TransferSwitchRequestDTO.class); + Ilp ilp = ilpBuilder.parse(request.getIlpPacket(), request.getCondition()); + + Map variables = new HashMap<>(); + variables.put(SWITCH_TRANSFER_REQUEST, exchange.getProperty(SWITCH_TRANSFER_REQUEST)); + String transactionId = ilp.getTransaction().getTransactionId(); + exchange.setProperty(TRANSACTION_ID, transactionId); + variables.put(TRANSACTION_ID, transactionId); + variables.put(FSPIOP_SOURCE.headerName(), request.getPayeeFsp()); + variables.put(FSPIOP_DESTINATION.headerName(), request.getPayerFsp()); + variables.put(HEADER_DATE, exchange.getIn().getHeader(HEADER_DATE)); + variables.put(HEADER_TRACEPARENT, exchange.getIn().getHeader(HEADER_TRACEPARENT)); + if(exchange.getIn().getHeader("X-Transfer-Callback-Url")!=null) { + variables.put("X-Transfer-Callback-Url", exchange.getIn().getHeader("X-Transfer-Callback-Url")); + } + else { + variables.put("X-Transfer-Callback-Url", transferHost); + } + + zeebeClient.newPublishMessageCommand() + .messageName(TRANSFER_MESSAGE) + .correlationKey(transactionId) + .variables(variables) + .send() + ; + }) + .endChoice() + .end() + .log(LoggingLevel.DEBUG, "######## SWITCH -> PAYEE - forward transfer request ${exchangeProperty."+TRANSACTION_ID+"} - STEP 2") + .setBody(constant(null)) + .setHeader(Exchange.HTTP_RESPONSE_CODE, constant(202)); + //@formatter:on + + from("rest:PUT:/switch/transfers/{"+TRANSACTION_ID+"}") + .setProperty(CLASS_TYPE, constant(TransferSwitchResponseDTO.class)) + .to("direct:body-unmarshling") + .process(getCachedTransactionIdProcessor) + .to("direct:transfers-step4"); + + from("direct:transfers-step4") + .log(LoggingLevel.DEBUG, "######## SWITCH -> PAYER - response for transfer request ${header."+TRANSACTION_ID+"} - STEP 4") + .process(transferResponseProcessor) + .setBody(constant(null)) + .setHeader(Exchange.HTTP_RESPONSE_CODE, constant(200)); + + from("rest:PUT:/switch/transfers/{"+TRANSACTION_ID+"}/error") + .log(LoggingLevel.ERROR, "######## SWITCH -> PAYER - transfer error ${header."+TRANSACTION_ID+"}") + .process(getCachedTransactionIdProcessor) + .setProperty(TRANSFER_FAILED, constant(true)) + .process(transferResponseProcessor) + .setBody(constant(null)) + .setHeader(Exchange.HTTP_RESPONSE_CODE, constant(200)); + + from("direct:send-transfer-error-to-switch") + .id("send-transfer-error-to-switch") + .setProperty(CLASS_TYPE, constant(TransferSwitchRequestDTO.class)) + .to("direct:body-unmarshling") + .process(e -> { + TransferSwitchRequestDTO request = e.getIn().getBody(TransferSwitchRequestDTO.class); + mojaloopUtil.setTransferHeadersResponse(e, ilpBuilder.parse(request.getIlpPacket(), request.getCondition()).getTransaction()); + e.getIn().setBody(e.getProperty(ERROR_INFORMATION)); + }) + .setHeader(Exchange.HTTP_METHOD, constant("PUT")) + .setProperty(HOST, simple("{{switch.transfers-host}}")) + .setProperty(ENDPOINT, simple("transfers/${exchangeProperty."+TRANSACTION_ID+"}/error")) + .to("direct:external-api-call"); + + from("direct:send-delayed-transfer-dummy-response") + .delay(mojaPerfRespDelay) + .process(e -> { + TransferSwitchRequestDTO transactionRequest = e.getIn().getBody(TransferSwitchRequestDTO.class); + Ilp ilp = ilpBuilder.parse(transactionRequest.getIlpPacket(), transactionRequest.getCondition()); + e.setProperty(TRANSACTION_ID, ilp.getTransaction().getTransactionId()); + e.getIn().setBody(objectMapper.writeValueAsString(transactionRequest)); + }) + .to("direct:send-transfer-to-switch"); + + from("direct:send-transfer-to-switch") + .log(LoggingLevel.DEBUG, "######## PAYEE -> SWITCH - transfer response ${exchangeProperty."+TRANSACTION_ID+"} - STEP 3") + .setProperty(CLASS_TYPE, constant(TransferSwitchRequestDTO.class)) + .to("direct:body-unmarshling") + .process(exchange -> { + TransferSwitchRequestDTO request = exchange.getIn().getBody(TransferSwitchRequestDTO.class); + Ilp ilp = ilpBuilder.parse(request.getIlpPacket(), request.getCondition()); + + TransferSwitchResponseDTO response = new TransferSwitchResponseDTO( + ilp.getFulfilment(), + ContextUtil.parseMojaDate(exchange.getIn().getHeader(HEADER_DATE, String.class)), // there is a validation at fulfiltransfer: completedTimestamp.getTime() > now.getTime() + maxCallbackTimeLagDilation(200ms by default) + TransferState.COMMITTED, + null); + + exchange.getIn().setBody(response); + mojaloopUtil.setTransferHeadersResponse(exchange, ilp.getTransaction()); + }) + .process(pojoToString) + .log(LoggingLevel.DEBUG, "Transfer response from payee: ${body}") + .setHeader(Exchange.HTTP_METHOD, constant("PUT")) + .setProperty(ENDPOINT, simple("transfers/${exchangeProperty." + TRANSACTION_ID + "}")) + .to("direct:external-api-call"); + + from("direct:send-transfer") + .id("send-transfer") + .log(LoggingLevel.DEBUG, "######## PAYER -> SWITCH - transfer request ${exchangeProperty."+TRANSACTION_ID+"} - STEP 1") + .setProperty(CLASS_TYPE, constant(QuoteSwitchResponseDTO.class)) + .to("direct:body-unmarshling") + .process(exchange -> { + QuoteSwitchResponseDTO quoteResponse = exchange.getIn().getBody(QuoteSwitchResponseDTO.class); + Ilp ilp = ilpBuilder.parse(quoteResponse.getIlpPacket(), quoteResponse.getCondition()); + + Transaction transaction = ilp.getTransaction(); + TransferSwitchRequestDTO request = new TransferSwitchRequestDTO( + transaction.getTransactionId(), + transaction.getPayer().getPartyIdInfo().getFspId(), + transaction.getPayee().getPartyIdInfo().getFspId(), + new MoneyData(transaction.getAmount().getAmount(), transaction.getAmount().getCurrency()), + ilp.getPacket(), + ilp.getCondition(), + ContextUtil.parseDate(quoteResponse.getExpiration()).plusHours(1), + objectMapper.readValue(exchange.getProperty(CHANNEL_REQUEST, String.class), TransactionChannelRequestDTO.class).getExtensionList()); + + exchange.getIn().setBody(request); + mojaloopUtil.setTransferHeadersRequest(exchange, transaction); + }) + .process(pojoToString) + .process(addTraceHeaderProcessor) + .log(LoggingLevel.DEBUG, "Transfer body: ${body}") + .setHeader(Exchange.HTTP_METHOD, constant("POST")) + .setProperty(HOST, simple("{{switch.transfers-host}}")) + .setProperty(ENDPOINT, constant("/transfers")) + .to("direct:external-api-call"); + } +} diff --git a/ph-ee-connector-mojaloop-java/src/main/java/org/mifos/connector/mojaloop/transfer/TransferWorkers.java b/ph-ee-connector-mojaloop-java/src/main/java/org/mifos/connector/mojaloop/transfer/TransferWorkers.java new file mode 100644 index 000000000..53ea790b2 --- /dev/null +++ b/ph-ee-connector-mojaloop-java/src/main/java/org/mifos/connector/mojaloop/transfer/TransferWorkers.java @@ -0,0 +1,131 @@ +package org.mifos.connector.mojaloop.transfer; + +import io.camunda.zeebe.client.ZeebeClient; +import org.apache.camel.CamelContext; +import org.apache.camel.Exchange; +import org.apache.camel.ProducerTemplate; +import org.apache.camel.support.DefaultExchange; +import org.mifos.connector.common.mojaloop.dto.TransferSwitchResponseDTO; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; +import org.springframework.stereotype.Component; +import javax.annotation.PostConstruct; +import java.util.List; +import java.util.Map; +import static org.mifos.connector.common.mojaloop.type.TransferState.COMMITTED; +import static org.mifos.connector.mojaloop.camel.config.CamelProperties.*; +import static org.mifos.connector.mojaloop.zeebe.ZeebeProcessStarter.zeebeVariablesToCamelHeaders; +import static org.mifos.connector.mojaloop.zeebe.ZeebeVariables.CHANNEL_REQUEST; +import static org.mifos.connector.mojaloop.zeebe.ZeebeVariables.ERROR_INFORMATION; +import static org.mifos.connector.mojaloop.zeebe.ZeebeVariables.ORIGIN_DATE; +import static org.mifos.connector.mojaloop.zeebe.ZeebeVariables.PAYEE_QUOTE_RESPONSE; +import static org.mifos.connector.mojaloop.zeebe.ZeebeVariables.SWITCH_TRANSFER_REQUEST; +import static org.mifos.connector.mojaloop.zeebe.ZeebeVariables.TIMEOUT_TRANSFER_RETRY_COUNT; +import static org.mifos.connector.mojaloop.zeebe.ZeebeVariables.TRANSACTION_ID; +import static org.mifos.connector.mojaloop.zeebe.ZeebeeWorkers.WORKER_PAYEE_TRANSFER_RESPONSE; +import static org.mifos.connector.mojaloop.zeebe.ZeebeeWorkers.WORKER_SEND_TRANSFER_REQUEST; + +@Component +@ConditionalOnExpression("!${mojaloop.perf-mode:false}") +public class TransferWorkers { + + private Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Autowired + private ZeebeClient zeebeClient; + + @Autowired + private ProducerTemplate producerTemplate; + + @Autowired + private CamelContext camelContext; + + @Value("#{'${dfspids}'.split(',')}") + private List dfspids; + + @Value("${zeebe.client.evenly-allocated-max-jobs}") + private int workerMaxJobs; + + @Value("${mojaloop.enabled}") + private boolean isMojaloopEnabled; + + @PostConstruct + public void setupWorkers() { + for (String dfspid : dfspids) { + logger.info("## generating " + WORKER_PAYEE_TRANSFER_RESPONSE + "{} zeebe worker", dfspid); + zeebeClient.newWorker() + .jobType(WORKER_PAYEE_TRANSFER_RESPONSE + dfspid) + .handler((client, job) -> { + logger.info("Job '{}' started from process '{}' with key {}", job.getType(), job.getBpmnProcessId(), job.getKey()); + Map existingVariables = job.getVariablesAsMap(); + + Exchange exchange = new DefaultExchange(camelContext); + exchange.getIn().setBody(existingVariables.get(SWITCH_TRANSFER_REQUEST)); + Object errorInformation = existingVariables.get(ERROR_INFORMATION); + if (errorInformation != null) { + zeebeVariablesToCamelHeaders(existingVariables, exchange, + HEADER_DATE, + HEADER_TRACEPARENT + ); + + exchange.setProperty(ERROR_INFORMATION, errorInformation); + exchange.setProperty(TRANSACTION_ID, existingVariables.get(TRANSACTION_ID)); + producerTemplate.send("direct:send-transfer-error-to-switch", exchange); + } else { + zeebeVariablesToCamelHeaders(existingVariables, exchange, + HEADER_DATE, + HEADER_TRACEPARENT + ); + + exchange.setProperty(TRANSACTION_ID, existingVariables.get(TRANSACTION_ID)); + exchange.setProperty(HOST, existingVariables.get("X-Transfer-Callback-Url")); + producerTemplate.send("direct:send-transfer-to-switch", exchange); + } + client.newCompleteCommand(job.getKey()) + .send() + ; + }) + .name(WORKER_PAYEE_TRANSFER_RESPONSE + dfspid) + .maxJobsActive(workerMaxJobs) + .open(); + + logger.info("## generating " + WORKER_SEND_TRANSFER_REQUEST + "{} zeebe worker", dfspid); + zeebeClient.newWorker() + .jobType(WORKER_SEND_TRANSFER_REQUEST + dfspid) + .handler((client, job) -> { + logger.info("Job '{}' started from process '{}' with key {}", job.getType(), job.getBpmnProcessId(), job.getKey()); + Map variables = job.getVariablesAsMap(); + variables.put(TIMEOUT_TRANSFER_RETRY_COUNT, 1 + (Integer) variables.getOrDefault(TIMEOUT_TRANSFER_RETRY_COUNT, -1)); + + Exchange exchange = new DefaultExchange(camelContext); + Object transactionId = variables.get(TRANSACTION_ID); + if(isMojaloopEnabled) { + exchange.setProperty(TRANSACTION_ID, transactionId); + exchange.setProperty(ORIGIN_DATE, variables.get(ORIGIN_DATE)); + exchange.setProperty(CHANNEL_REQUEST, variables.get(CHANNEL_REQUEST)); + exchange.getIn().setBody(variables.get(PAYEE_QUOTE_RESPONSE)); + logger.debug("PAYEE QUOTE RESPONSE ZEEBE VARIABLE: {}", variables.get(PAYEE_QUOTE_RESPONSE)); + producerTemplate.send("direct:send-transfer", exchange); + } else { + TransferSwitchResponseDTO response = new TransferSwitchResponseDTO(); + response.setTransferState(COMMITTED); + exchange.getIn().setBody(response); + exchange.getIn().setHeader(TRANSACTION_ID, transactionId); + exchange.setProperty(CACHED_TRANSACTION_ID, transactionId); + producerTemplate.send("direct:transfers-step4", exchange); + } + + client.newCompleteCommand(job.getKey()) + .variables(variables) + .send() + ; + }) + .name(WORKER_SEND_TRANSFER_REQUEST + dfspid) + .maxJobsActive(workerMaxJobs) + .open(); + } + } +} diff --git a/ph-ee-connector-mojaloop-java/src/main/java/org/mifos/connector/mojaloop/util/MojaloopUtil.java b/ph-ee-connector-mojaloop-java/src/main/java/org/mifos/connector/mojaloop/util/MojaloopUtil.java new file mode 100644 index 000000000..e04a86018 --- /dev/null +++ b/ph-ee-connector-mojaloop-java/src/main/java/org/mifos/connector/mojaloop/util/MojaloopUtil.java @@ -0,0 +1,132 @@ +package org.mifos.connector.mojaloop.util; + +import com.ilp.conditions.models.pdp.Transaction; +import org.apache.camel.Exchange; +import org.mifos.connector.common.mojaloop.dto.QuoteSwitchRequestDTO; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; +import java.util.HashMap; +import java.util.Map; +import static org.mifos.connector.common.mojaloop.type.InteroperabilityType.PARTIES_ACCEPT_TYPE; +import static org.mifos.connector.common.mojaloop.type.InteroperabilityType.PARTIES_CONTENT_TYPE; +import static org.mifos.connector.common.mojaloop.type.InteroperabilityType.QUOTES_ACCEPT_TYPE; +import static org.mifos.connector.common.mojaloop.type.InteroperabilityType.QUOTES_CONTENT_TYPE; +import static org.mifos.connector.common.mojaloop.type.InteroperabilityType.TRANSACTIONS_ACCEPT_TYPE; +import static org.mifos.connector.common.mojaloop.type.InteroperabilityType.TRANSACTIONS_CONTENT_TYPE; +import static org.mifos.connector.common.mojaloop.type.InteroperabilityType.TRANSFERS_ACCEPT_TYPE; +import static org.mifos.connector.common.mojaloop.type.InteroperabilityType.TRANSFERS_CONTENT_TYPE; +import static org.mifos.connector.common.mojaloop.type.MojaloopHeaders.FSPIOP_DESTINATION; +import static org.mifos.connector.common.mojaloop.type.MojaloopHeaders.FSPIOP_SOURCE; +import static org.mifos.connector.mojaloop.camel.config.CamelProperties.*; + +@Component +public class MojaloopUtil { + + @Value("${switch.account-lookup-service}") + private String accountLookupService; + + @Value("${switch.quote-service}") + private String switchQuoteService; + + @Value("${switch.transfer-service}") + private String transferService; + + @Value("${switch.transaction-request-service}") + private String transactionRequestService; + + public void setPartyHeadersResponse(Exchange exchange) { + Map headers = new HashMap<>(); + headers.put(FSPIOP_SOURCE.headerName(), exchange.getIn().getHeader(FSPIOP_SOURCE.headerName())); + headers.put(FSPIOP_DESTINATION.headerName(), exchange.getIn().getHeader(FSPIOP_SOURCE.headerName())); + headers.put(HEADER_CONTENT_TYPE, PARTIES_CONTENT_TYPE.headerValue()); + headers.put(HEADER_ACCEPT, PARTIES_ACCEPT_TYPE.headerValue()); + headers.put(HEADER_HOST, accountLookupService); + setResponseTraceHeaders(exchange, headers); + finalizeHeaders(exchange, headers); + } + + public void setPartyHeadersRequest(Exchange exchange) { + Map headers = new HashMap<>(); + headers.put(FSPIOP_SOURCE.headerName(), exchange.getIn().getHeader(FSPIOP_SOURCE.headerName())); + headers.put(HEADER_CONTENT_TYPE, PARTIES_CONTENT_TYPE.headerValue()); + headers.put(HEADER_ACCEPT, PARTIES_ACCEPT_TYPE.headerValue()); + headers.put(HEADER_HOST, accountLookupService); + finalizeHeaders(exchange, headers); + } + + public void setQuoteHeadersResponse(Exchange e, QuoteSwitchRequestDTO request) { + Map headers = new HashMap<>(); + headers.put(FSPIOP_SOURCE.headerName(), request.getPayee().getPartyIdInfo().getFspId()); + headers.put(FSPIOP_DESTINATION.headerName(), request.getPayer().getPartyIdInfo().getFspId()); + headers.put(HEADER_CONTENT_TYPE, QUOTES_CONTENT_TYPE.headerValue()); + headers.put(HEADER_HOST, switchQuoteService); + setResponseTraceHeaders(e, headers); + finalizeHeaders(e, headers); + } + + public void setQuoteHeadersRequest(Exchange e) { + Map headers = new HashMap<>(); + headers.put(FSPIOP_SOURCE.headerName(), e.getProperty(FSPIOP_SOURCE.headerName())); + headers.put(FSPIOP_DESTINATION.headerName(), e.getProperty(FSPIOP_DESTINATION.headerName())); + headers.put(HEADER_CONTENT_TYPE, QUOTES_CONTENT_TYPE.headerValue()); + headers.put(HEADER_ACCEPT, QUOTES_ACCEPT_TYPE.headerValue()); + headers.put(HEADER_HOST, switchQuoteService); + finalizeHeaders(e, headers); + } + + public void setTransferHeadersResponse(Exchange e, Transaction transaction) { + Map headers = new HashMap<>(); + headers.put(FSPIOP_SOURCE.headerName(), transaction.getPayee().getPartyIdInfo().getFspId()); + headers.put(FSPIOP_DESTINATION.headerName(), transaction.getPayer().getPartyIdInfo().getFspId()); + headers.put(HEADER_CONTENT_TYPE, TRANSFERS_CONTENT_TYPE.headerValue()); + headers.put(HEADER_ACCEPT, TRANSFERS_ACCEPT_TYPE.headerValue()); + headers.put(HEADER_HOST, transferService); + setResponseTraceHeaders(e, headers); + finalizeHeaders(e, headers); + } + + public void setTransferHeadersRequest(Exchange e, Transaction transaction) { + Map headers = new HashMap<>(); + headers.put(FSPIOP_SOURCE.headerName(), transaction.getPayer().getPartyIdInfo().getFspId()); + headers.put(FSPIOP_DESTINATION.headerName(), transaction.getPayee().getPartyIdInfo().getFspId()); + headers.put(HEADER_CONTENT_TYPE, TRANSFERS_CONTENT_TYPE.headerValue()); + headers.put(HEADER_ACCEPT, TRANSFERS_ACCEPT_TYPE.headerValue()); + headers.put(HEADER_HOST, transferService); + finalizeHeaders(e, headers); + } + + public void setTransactionRequestHeadersResponse(Exchange e) { + Map headers = new HashMap<>(); + headers.put(FSPIOP_SOURCE.headerName(), e.getProperty(FSPIOP_SOURCE.headerName())); + headers.put(FSPIOP_DESTINATION.headerName(), e.getProperty(FSPIOP_DESTINATION.headerName())); + headers.put(HEADER_CONTENT_TYPE, TRANSACTIONS_CONTENT_TYPE.headerValue()); + headers.put(HEADER_ACCEPT, TRANSACTIONS_ACCEPT_TYPE.headerValue()); + headers.put(HEADER_HOST, transactionRequestService); + setResponseTraceHeaders(e, headers); + finalizeHeaders(e, headers); + } + + public void setTransactionRequestHeadersRequest(Exchange e) { + Map headers = new HashMap<>(); + headers.put(FSPIOP_SOURCE.headerName(), e.getProperty(FSPIOP_SOURCE.headerName())); + headers.put(FSPIOP_DESTINATION.headerName(), e.getProperty(FSPIOP_DESTINATION.headerName())); + headers.put(HEADER_CONTENT_TYPE, TRANSACTIONS_CONTENT_TYPE.headerValue()); + headers.put(HEADER_ACCEPT, TRANSACTIONS_ACCEPT_TYPE.headerValue()); + headers.put(HEADER_HOST, transactionRequestService); + finalizeHeaders(e, headers); + } + + private void finalizeHeaders(Exchange e, Map headers) { + e.getIn().removeHeaders("*"); + e.getIn().setHeaders(headers); + } + + private void setResponseTraceHeaders(Exchange exchange, Map headers) { + headers.put(HEADER_DATE, exchange.getIn().getHeader(HEADER_DATE)); + headers.put(HEADER_TRACEPARENT, exchange.getIn().getHeader(HEADER_TRACEPARENT)); + Object tracestate = exchange.getIn().getHeader(HEADER_TRACESTATE); + if (tracestate != null) { + headers.put(HEADER_TRACESTATE, tracestate); + } + } +} diff --git a/ph-ee-connector-mojaloop-java/src/main/java/org/mifos/connector/mojaloop/zeebe/ZeebeClientConfiguration.java b/ph-ee-connector-mojaloop-java/src/main/java/org/mifos/connector/mojaloop/zeebe/ZeebeClientConfiguration.java new file mode 100644 index 000000000..9dffbce4e --- /dev/null +++ b/ph-ee-connector-mojaloop-java/src/main/java/org/mifos/connector/mojaloop/zeebe/ZeebeClientConfiguration.java @@ -0,0 +1,34 @@ +package org.mifos.connector.mojaloop.zeebe; + +import io.camunda.zeebe.client.ZeebeClient; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import java.time.Duration; + +@Configuration +@ConditionalOnExpression("!${mojaloop.perf-mode:false}") +public class ZeebeClientConfiguration { + + @Value("${zeebe.broker.contactpoint}") + private String zeebeBrokerContactpoint; + + @Value("${zeebe.client.max-execution-threads}") + private int zeebeClientMaxThreads; + + @Value("${zeebe.client.poll-interval}") + private int zeebeClientPollInterval; + + @Bean + public ZeebeClient setup() { + return ZeebeClient.newClientBuilder() + .gatewayAddress(zeebeBrokerContactpoint) + .usePlaintext() + .defaultJobPollInterval(Duration.ofMillis(zeebeClientPollInterval)) + .defaultJobWorkerMaxJobsActive(2000) + .numJobWorkerExecutionThreads(zeebeClientMaxThreads) + .build(); + } +} diff --git a/ph-ee-connector-mojaloop-java/src/main/java/org/mifos/connector/mojaloop/zeebe/ZeebeMessages.java b/ph-ee-connector-mojaloop-java/src/main/java/org/mifos/connector/mojaloop/zeebe/ZeebeMessages.java new file mode 100644 index 000000000..6c55d17d8 --- /dev/null +++ b/ph-ee-connector-mojaloop-java/src/main/java/org/mifos/connector/mojaloop/zeebe/ZeebeMessages.java @@ -0,0 +1,19 @@ +package org.mifos.connector.mojaloop.zeebe; + +public class ZeebeMessages { + + private ZeebeMessages() {} + + public static final String ACCEPT_QUOTE = "accept-quote"; + public static final String AUTHORISATION_REQUEST = "authorisation-request"; + public static final String PARTY_LOOKUP = "party-lookup"; + public static final String PAYER_AUTH_CONFIRMATION = "payer-auth-confirmation"; + public static final String PAYER_AUTH_RESPONSE = "payer-auth-response"; + public static final String PAYER_CONFIRMATION = "payer-confirmation"; + public static final String QUOTE_CALLBACK = "quote-callback"; + public static final String QUOTE_ERROR = "quote-error"; + public static final String TRANSFER_MESSAGE = "transfer-message"; + public static final String TRANSFER_RESPONSE = "transfer-response"; + public static final String TRANSACTION_REQUEST = "transaction-request"; + +} diff --git a/ph-ee-connector-mojaloop-java/src/main/java/org/mifos/connector/mojaloop/zeebe/ZeebeProcessStarter.java b/ph-ee-connector-mojaloop-java/src/main/java/org/mifos/connector/mojaloop/zeebe/ZeebeProcessStarter.java new file mode 100644 index 000000000..29146a225 --- /dev/null +++ b/ph-ee-connector-mojaloop-java/src/main/java/org/mifos/connector/mojaloop/zeebe/ZeebeProcessStarter.java @@ -0,0 +1,58 @@ +package org.mifos.connector.mojaloop.zeebe; + +import io.camunda.zeebe.client.ZeebeClient; +import io.camunda.zeebe.client.api.response.ProcessInstanceEvent; +import org.apache.camel.Exchange; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import java.time.Instant; +import java.util.HashMap; +import java.util.Map; +import java.util.function.Consumer; + +@Component +public class ZeebeProcessStarter { + + private static Logger logger = LoggerFactory.getLogger(ZeebeProcessStarter.class); + + @Autowired(required = false) + private ZeebeClient zeebeClient; + + public void startZeebeWorkflow(String workflowId, Consumer> variablesLambda) { + Map variables = new HashMap<>(); + variables.put(ZeebeVariables.ORIGIN_DATE, Instant.now().toEpochMilli()); + variablesLambda.accept(variables); + + + + ProcessInstanceEvent instance = zeebeClient.newCreateInstanceCommand() + .bpmnProcessId(workflowId) + .latestVersion() + .variables(variables) + .send().join(); + + logger.info("zeebee workflow instance from process {} started with key {}", workflowId, instance.getProcessInstanceKey()); + } + + public static void zeebeVariablesToCamelHeaders(Map variables, Exchange exchange, String... names) { + for (String name : names) { + Object value = variables.get(name); + if (value == null) { + logger.error("failed to find Zeebe variable name {}", name); + } + exchange.getIn().setHeader(name, value); + } + } + + public static void camelHeadersToZeebeVariables(Exchange exchange, Map variables, String... names) { + for (String name : names) { + String header = exchange.getIn().getHeader(name, String.class); + if (header == null) { + logger.error("failed to find Camel Exchange header {}", name); + } + variables.put(name, header); + } + } +} diff --git a/ph-ee-connector-mojaloop-java/src/main/java/org/mifos/connector/mojaloop/zeebe/ZeebeVariables.java b/ph-ee-connector-mojaloop-java/src/main/java/org/mifos/connector/mojaloop/zeebe/ZeebeVariables.java new file mode 100644 index 000000000..358c4a5cf --- /dev/null +++ b/ph-ee-connector-mojaloop-java/src/main/java/org/mifos/connector/mojaloop/zeebe/ZeebeVariables.java @@ -0,0 +1,45 @@ +package org.mifos.connector.mojaloop.zeebe; + +public class ZeebeVariables { + + private ZeebeVariables() {} + + public static final String ACCOUNT_CURRENCY = "accountCurrency"; + public static final String AUTH_RETRIES_LEFT_COUNT = "authRetriesLeftCount"; + public static final String AUTH_VALIDATION_SUCCESS = "authValidationSuccess"; + public static final String CHANNEL_REQUEST = "channelRequest"; + public static final String ERROR_INFORMATION = "errorInformation"; + public static final String INITIATOR_FSP_ID = "initiatorFspId"; + public static final String IS_AUTHORISATION_REQUIRED = "isAuthorisationRequired"; + public static final String IS_RTP_REQUEST = "isRtpRequest"; + public static final String LOCAL_QUOTE_RESPONSE = "localQuoteResponse"; + public static final String ORIGIN_DATE = "originDate"; + public static final String PARTY_ID = "partyId"; + public static final String PARTY_ID_TYPE = "partyIdType"; + public static final String PARTY_LOOKUP_FAILED = "partyLookupFailed"; + public static final String PARTY_LOOKUP_FSP_ID = "partyLookupFspId"; + public static final String PARTY_LOOKUP_RETRY_COUNT = "partyLookupRetryCount"; + public static final String PAYEE_PARTY_RESPONSE = "payeePartyResponse"; + public static final String PAYEE_QUOTE_RESPONSE = "payeeQuoteResponse"; + public static final String PAYER_AUTHORISATION_RETRY_COUNT = "payerAuthorisationRetryCount"; + public static final String PAYER_CONFIRMATION_RETRY_COUNT = "payerConfirmationRetryCount"; + public static final String PAYER_CONFIRMED = "payerConfirmed"; + public static final String QUOTE_ID = "quoteId"; + public static final String QUOTE_FAILED = "quoteFailed"; + public static final String QUOTE_SWITCH_REQUEST = "quoteSwitchRequest"; + public static final String QUOTE_SWITCH_REQUEST_AMOUNT = "quoteSwitchRequestAmount"; + public static final String SWITCH_TRANSFER_REQUEST = "switchTransferRequest"; + public static final String TENANT_ID = "tenantId"; + public static final String TIMEOUT_QUOTE_RETRY_COUNT = "quoteRetryCount"; + public static final String TIMEOUT_TRANSFER_RETRY_COUNT = "transferRetryCount"; + public static final String TRANSACTION_ID = "transactionId"; + public static final String TRANSACTION_REQUEST = "transactionRequest"; + public static final String TRANSACTION_REQUEST_FAILED = "transactionRequestFailed"; + public static final String TRANSACTION_REQUEST_RESPONSE = "transactionRequestResponse"; + public static final String TRANSACTION_REQUEST_RETRY_COUNT = "transactionRequestRetryCount"; + public static final String TRANSACTION_STATE = "transactionState"; + public static final String TRANSFER_FAILED = "transferFailed"; + public static final String TRANSFER_STATE = "transferState"; + public static final String PAYEE_TENANT_ID = "payeeTenantId"; + +} diff --git a/ph-ee-connector-mojaloop-java/src/main/java/org/mifos/connector/mojaloop/zeebe/ZeebeeWorkers.java b/ph-ee-connector-mojaloop-java/src/main/java/org/mifos/connector/mojaloop/zeebe/ZeebeeWorkers.java new file mode 100644 index 000000000..7713f77a7 --- /dev/null +++ b/ph-ee-connector-mojaloop-java/src/main/java/org/mifos/connector/mojaloop/zeebe/ZeebeeWorkers.java @@ -0,0 +1,130 @@ +package org.mifos.connector.mojaloop.zeebe; + +import io.camunda.zeebe.client.ZeebeClient; +import org.mifos.connector.common.mojaloop.type.TransactionRequestState; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; +import org.springframework.stereotype.Component; +import javax.annotation.PostConstruct; +import java.time.Duration; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import static org.mifos.connector.mojaloop.zeebe.ZeebeVariables.TRANSACTION_ID; +import static org.mifos.connector.mojaloop.zeebe.ZeebeVariables.AUTH_VALIDATION_SUCCESS; +import static org.mifos.connector.mojaloop.zeebe.ZeebeVariables.PAYER_CONFIRMED; +import static org.mifos.connector.mojaloop.zeebe.ZeebeVariables.TRANSACTION_STATE; +import static org.mifos.connector.mojaloop.zeebe.ZeebeMessages.ACCEPT_QUOTE; + + +@Component +@ConditionalOnExpression("!${mojaloop.perf-mode:false}") +public class ZeebeeWorkers { + + public static final String WORKER_GENERATE_OTP = "generate-otp-"; + public static final String WORKER_PARTY_LOOKUP_REQUEST = "party-lookup-request-"; + public static final String WORKER_PARTY_LOOKUP_LOCAL_RESPONSE = "party-lookup-local-response-"; + public static final String WORKER_PAYEE_QUOTE_RESPONSE = "payee-quote-response-"; + public static final String WORKER_PAYER_REQUEST_CONFIRM = "payer-request-confirm-"; + public static final String WORKER_PAYEE_TRANSFER_RESPONSE = "payee-transfer-response-"; + public static final String WORKER_QUOTE = "quote-"; + public static final String WORKER_SEND_AUTH_CONFIRMATION = "send-auth-confirmation-"; + public static final String WORKER_SEND_AUTH_RESPONSE = "send-auth-response-"; + public static final String WORKER_SEND_TRANSACTION_STATE_RESPONSE = "send-transaction-state-response-"; + public static final String WORKER_SEND_TRANSFER_REQUEST = "send-transfer-request-"; + public static final String WORKER_TRANSACTION_REQUEST = "transaction-request-"; + public static final String WORKER_VALIDATE_OTP_AUTH_REPONSE = "validate-otp-auth-reponse-"; + public static final String WORKER_SEND_PAYER_AUTHORISATION = "send-payer-authorisation-"; + public static final String WORKER_PARTY_REGISTRATION_ORACLE = "party-registration-oracle-"; + + private Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Autowired + private ZeebeClient zeebeClient; + + @Value("#{'${dfspids}'.split(',')}") + private List dfspids; + + @Value("${zeebe.client.evenly-allocated-max-jobs}") + private int workerMaxJobs; + + @PostConstruct + public void setupWorkers() { + // TODO move this worker + for (String dfspid : dfspids) { + logger.info("## generating " + WORKER_PAYER_REQUEST_CONFIRM + "{} zeebe worker", dfspid); + zeebeClient.newWorker() + .jobType(WORKER_PAYER_REQUEST_CONFIRM + dfspid) + .handler((client, job) -> { + logger.info("Job '{}' started from process '{}' with key {}", job.getType(), job.getBpmnProcessId(), job.getKey()); + Map variables = new HashMap<>(); + variables.put(PAYER_CONFIRMED, true); + // TODO these should be somewhere else + variables.put(AUTH_VALIDATION_SUCCESS, true); + variables.put(TRANSACTION_STATE, TransactionRequestState.ACCEPTED.name()); + + // TODO sum local and payee quote and send to customer + + zeebeClient.newPublishMessageCommand() + .messageName(ACCEPT_QUOTE) + .correlationKey((String) job.getVariablesAsMap().get(TRANSACTION_ID)) + .timeToLive(Duration.ofMillis(30000)) + .send() + ; + + client.newCompleteCommand(job.getKey()) + .variables(variables) + .send() + ; + }) + .name(WORKER_PAYER_REQUEST_CONFIRM + dfspid) + .maxJobsActive(workerMaxJobs) + .open(); + + logger.info("## generating " + WORKER_GENERATE_OTP + "{} zeebe worker", dfspid); + zeebeClient.newWorker() + .jobType(WORKER_GENERATE_OTP + dfspid) + .handler((client, job) -> { + logger.info("Job '{}' started from process '{}' with key {}", job.getType(), job.getBpmnProcessId(), job.getKey()); + + client.newCompleteCommand(job.getKey()) + .send() + ; + }) + .name(WORKER_GENERATE_OTP + dfspid) + .maxJobsActive(workerMaxJobs) + .open(); + + logger.info("## generating " + WORKER_VALIDATE_OTP_AUTH_REPONSE + "{} zeebe worker", dfspid); + zeebeClient.newWorker() + .jobType(WORKER_VALIDATE_OTP_AUTH_REPONSE + dfspid) + .handler((client, job) -> { + logger.info("Job '{}' started from process '{}' with key {}", job.getType(), job.getBpmnProcessId(), job.getKey()); + + client.newCompleteCommand(job.getKey()) + .send() + ; + }) + .name(WORKER_VALIDATE_OTP_AUTH_REPONSE + dfspid) + .maxJobsActive(workerMaxJobs) + .open(); + + logger.info("## generating " + WORKER_SEND_PAYER_AUTHORISATION + "{} zeebe worker", dfspid); + zeebeClient.newWorker() + .jobType(WORKER_SEND_PAYER_AUTHORISATION + dfspid) + .handler((client, job) -> { + logger.info("Job '{}' started from process '{}' with key {}", job.getType(), job.getBpmnProcessId(), job.getKey()); + + client.newCompleteCommand(job.getKey()) + .send() + ; + }) + .name(WORKER_SEND_PAYER_AUTHORISATION + dfspid) + .maxJobsActive(workerMaxJobs) + .open(); + } + } +} diff --git a/ph-ee-connector-mojaloop-java/src/main/resources/application-bb.yml b/ph-ee-connector-mojaloop-java/src/main/resources/application-bb.yml new file mode 100644 index 000000000..55fc2bdf0 --- /dev/null +++ b/ph-ee-connector-mojaloop-java/src/main/resources/application-bb.yml @@ -0,0 +1,7 @@ +parties: + - tenantId: gorilla + fspId: payerfsp + domain: "" + - tenantId: lion + fspId: payeefsp + domain: "" diff --git a/ph-ee-connector-mojaloop-java/src/main/resources/application-large.yml b/ph-ee-connector-mojaloop-java/src/main/resources/application-large.yml new file mode 100644 index 000000000..062f9eab8 --- /dev/null +++ b/ph-ee-connector-mojaloop-java/src/main/resources/application-large.yml @@ -0,0 +1,7 @@ +parties: + - tenantId: tn01 + fspId: in01tn01 + domain: in01tn01.mifos.io + - tenantId: tn02 + fspId: in01tn02 + domain: in01tn02.mifos.io \ No newline at end of file diff --git a/ph-ee-connector-mojaloop-java/src/main/resources/application-med.yml b/ph-ee-connector-mojaloop-java/src/main/resources/application-med.yml new file mode 100644 index 000000000..0f5bd5f37 --- /dev/null +++ b/ph-ee-connector-mojaloop-java/src/main/resources/application-med.yml @@ -0,0 +1,7 @@ +parties: + - tenantId: tn05 + fspId: in03tn05 + domain: in03tn05.mifos.io + - tenantId: tn06 + fspId: in03tn06 + domain: in03tn06.mifos.io \ No newline at end of file diff --git a/ph-ee-connector-mojaloop-java/src/main/resources/application.yml b/ph-ee-connector-mojaloop-java/src/main/resources/application.yml new file mode 100644 index 000000000..0e95e33d5 --- /dev/null +++ b/ph-ee-connector-mojaloop-java/src/main/resources/application.yml @@ -0,0 +1,64 @@ +camel: + server-port: 5000 + springboot: + main-run-controller: true + dataformat: + json-jackson: + auto-discover-object-mapper: true + +bpmn: + flows: + party-lookup: "PayeePartyLookup-{tenant}" + quote: "PayeeQuoteTransfer-{tenant}" + transaction-request: "PayerTransactionRequest-{tenant}" + +zeebe: + client: + max-execution-threads: 50 + evenly-allocated-max-jobs: 1000 + poll-interval: 10 +# max-execution-threads: 100 +# number-of-workers: 15 +# evenly-allocated-max-jobs: "#{${zeebe.client.max-execution-threads} / ${zeebe.client.number-of-workers}}" + broker: + contactpoint: "ph-ee-zeebe:26500" + +connector: + ilp-secret: h4on38bsDjKiat2783gnklgafikmeuu5123kpobb7jm99 + + +mojaloop: + enabled: true + perf-mode: false + perf-resp-delay: 100 + +switch: + quotes-host: "" + quote-service: quoting-service.local + als-host: "" + account-lookup-service: account-lookup-service.local + transfers-host: "" + transfer-service: ml-api-adapter.local + transactions-host: "" + transaction-request-service: transaction-request-service.local + oracle-host: "" + +dfspids: "DFSPID" + +logging: + level: + root: ERROR + +server: + port: 8080 +management: + endpoint: + health: + enabled: true + probes: + enabled: true + liveness: + enabled: true + readiness: + enabled: true + diff --git a/ph-ee-connector-mojaloop-java/src/main/resources/logback.xml b/ph-ee-connector-mojaloop-java/src/main/resources/logback.xml new file mode 100644 index 000000000..46f13de80 --- /dev/null +++ b/ph-ee-connector-mojaloop-java/src/main/resources/logback.xml @@ -0,0 +1,24 @@ + + + + + + + + + ${CONSOLE_LOG_PATTERN} + utf8 + + + + + + + + + + + + + \ No newline at end of file diff --git a/ph-ee-connector-mojaloop-java/src/test/java/org/mifos/connector/mojaloop/IlpTestCase.java b/ph-ee-connector-mojaloop-java/src/test/java/org/mifos/connector/mojaloop/IlpTestCase.java new file mode 100644 index 000000000..63892d190 --- /dev/null +++ b/ph-ee-connector-mojaloop-java/src/test/java/org/mifos/connector/mojaloop/IlpTestCase.java @@ -0,0 +1,132 @@ +package org.mifos.connector.mojaloop; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.ilp.conditions.models.pdp.*; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.mifos.connector.mojaloop.ilp.IlpBuilder; +import org.mifos.connector.mojaloop.ilp.IlpConditionHandlerImpl; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.test.context.SpringBootTest; + +import java.io.IOException; + +/* + * ILP_PACKET = random + ilp address + base64(txnPayload) + * F -> HMCASHA256(ilpPacket, secret) + * C -> SHA256(F) + */ +@SpringBootTest +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +public class IlpTestCase { + + private Transaction transaction; + + private String ilpPacket; + + private String condition; + + private String fulfillment; + + private final Logger logger = LoggerFactory.getLogger(getClass()); + + @Autowired + public ObjectMapper objectMapper; + + @Autowired + public IlpBuilder ilpBuilder; + + @Autowired + public IlpConditionHandlerImpl ilpConditionHandler; + + @Value("${connector.ilp-secret}") + private String ilpSecret; + + @BeforeAll + public void init() { + mockTransaction(); + } + + @BeforeEach + public void generateIlpPacket() throws IOException { + String ilpAddress = ilpBuilder.buildIlpAddress(transaction); + this.ilpPacket = ilpConditionHandler.getILPPacket(ilpAddress, "100", + transaction); + } + + public void mockTransaction() { + transaction = new Transaction(){{ + setAmount(new Money(){{ + setAmount("100"); + setCurrency("USD"); + }}); + setPayer(new Party(){{ + setPartyIdInfo(new PartyIdInfo(){{ + setPartyIdType("MSISDN"); + setPartyIdentifier("123123123"); + }}); + }}); + setPayee(new Party(){{ + setPartyIdInfo(new PartyIdInfo(){{ + setPartyIdType("MSISDN"); + setPartyIdentifier("321321321"); + }}); + }}); + setTransactionType(new TransactionType(){{ + setScenario("TRANSFER"); + setInitiator("PAYER"); + setInitiatorType("CONSUMER"); + }}); + }}; + } + + // generate ILP + @Test + public void checkIfIlpPacketIsNotNull() { + logger.debug("ILP Packet: {}", this.ilpPacket); + assert !ilpPacket.isEmpty(); + } + + // check if secret is not null + @Test + public void secretNotNull() { + assert ilpSecret != null; + logger.debug("Secret: {}", ilpSecret); + } + + // get condition from ILP packet + @Test + public void getConditionFromIlpPacket() throws IOException { + String condition = ilpConditionHandler.generateCondition( + this.ilpPacket, ilpSecret.getBytes()); + logger.debug("Condition is {}", condition); + this.condition = condition; + assert !condition.isEmpty(); + } + + // get fulfillment from ILP packet + @Test + public void getFulfillmentFromIlpPacket() throws IOException { + String fulfillment = ilpConditionHandler.generateFulfillment( + this.ilpPacket, ilpSecret.getBytes()); + logger.debug("Fulfillment is {}", condition); + this.fulfillment = fulfillment; + assert !this.fulfillment.isEmpty(); + } + + // extract transaction from ilpPacket + @Test + public void extractTxnFromIlpPacket() throws IOException { + logger.debug("Using ilppacket: {}", this.ilpPacket); + Transaction transaction = ilpConditionHandler.getTransactionFromIlpPacket(this.ilpPacket); + assert transaction != null; + logger.debug("Transaction extracted: {}", objectMapper.writeValueAsString(transaction)); + } + + +} diff --git a/ph-ee-connector-mojaloop-java/src/test/java/org/mifos/connector/mojaloop/QuoteTest.java b/ph-ee-connector-mojaloop-java/src/test/java/org/mifos/connector/mojaloop/QuoteTest.java new file mode 100644 index 000000000..5503726ce --- /dev/null +++ b/ph-ee-connector-mojaloop-java/src/test/java/org/mifos/connector/mojaloop/QuoteTest.java @@ -0,0 +1,36 @@ +package org.mifos.connector.mojaloop; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.junit.jupiter.api.Test; +import org.mifos.connector.common.ams.dto.QuoteFspResponseDTO; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; + +import java.io.IOException; + +@SpringBootTest +public class QuoteTest { + + private Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Autowired + private ObjectMapper objectMapper; + + @Test + public void testLocalQuoteDeserialization() throws IOException { + String localQuoteResponseString = "{\"transactionCode\":\"cf1f9731-d248-4cc9-be4c-7937f2ed6c18\",\"quoteCode\":\"4c94ba50-3c6e-46b6-b1ae-1b89baa2b126\",\"state\":\"ACCEPTED\",\"fspFee\":{\"amount\":0,\"currency\":\"USD\"}}"; + QuoteFspResponseDTO localQuoteResponse = objectMapper.readValue(localQuoteResponseString, QuoteFspResponseDTO.class); + + logger.debug("local quote dto: {}", objectMapper.writeValueAsString(localQuoteResponse)); + } + + @Test + public void testDateDeser() throws IOException { + String json = "{}"; + QuoteFspResponseDTO testDto = objectMapper.readValue(json, QuoteFspResponseDTO.class); + + logger.debug("Test dto: {}", testDto); + } +} diff --git a/ph-ee-connector-mojaloop-java/src/test/java/org/mifos/connector/mojaloop/TestUtil.java b/ph-ee-connector-mojaloop-java/src/test/java/org/mifos/connector/mojaloop/TestUtil.java new file mode 100644 index 000000000..337ee26f5 --- /dev/null +++ b/ph-ee-connector-mojaloop-java/src/test/java/org/mifos/connector/mojaloop/TestUtil.java @@ -0,0 +1,13 @@ +package org.mifos.connector.mojaloop; + +import org.junit.jupiter.api.Test; + +import java.util.UUID; + +public class TestUtil { + + @Test + public void test1() { + System.out.println(UUID.randomUUID().toString()); + } +} diff --git a/ph-ee-connector-mojaloop-java/src/test/resources/moja-dto.txt b/ph-ee-connector-mojaloop-java/src/test/resources/moja-dto.txt new file mode 100644 index 000000000..03df8d25f --- /dev/null +++ b/ph-ee-connector-mojaloop-java/src/test/resources/moja-dto.txt @@ -0,0 +1,22 @@ +QuoteSwitchResponseDTO +{ + "transferAmount": { + "amount": "1", + "currency": "TZS" + }, + "payeeReceiveAmount": { + "amount": "1", + "currency": "TZS" + }, + "payeeFspFee": { + "amount": "0", + "currency": "TZS" + }, + "payeeFspCommission": { + "amount": "0", + "currency": "TZS" + }, + "expiration": "2020-07-14T10:04:54.946Z", + "ilpPacket": "AQExIGcudHouaW4wM3RuMDYuTVNJU0ROLjI3NzEwMzA2OTk5ggHQZXlKMGNtRnVjMkZqZEdsdmJrbGtJam9pT1RObE5qUTFOR1V0T1dJNU15MDBOREV6TFRrek16VXRaRGRpT1dVNU1EaGhNalE1SWl3aWNYVnZkR1ZKWkNJNkltTmhNR05pWmpFeExXSTNZemN0TkRCbU15MWhOalJqTFdJM01XTmlaamM1WVRneU9TSXNJbkJoZVdWbElqcDdJbkJoY25SNVNXUkpibVp2SWpwN0luQmhjblI1U1dSVWVYQmxJam9pVFZOSlUwUk9JaXdpY0dGeWRIbEpaR1Z1ZEdsbWFXVnlJam9pTWpjM01UQXpNRFk1T1RraUxDSm1jM0JKWkNJNkltbHVNRE4wYmpBMkluMTlMQ0p3WVhsbGNpSTZleUp3WVhKMGVVbGtTVzVtYnlJNmV5SndZWEowZVVsa1ZIbHdaU0k2SWsxVFNWTkVUaUlzSW5CaGNuUjVTV1JsYm5ScFptbGxjaUk2SWpJM056RXdNakF6T1RrNUlpd2labk53U1dRaU9pSnBiakF4ZEc0d01TSjlmU3dpWVcxdmRXNTBJanA3SW1OMWNuSmxibU41SWpvaVZGcFRJaXdpWVcxdmRXNTBJam9pTVNKOWZRPT0=", + "condition": "wgPeIZ5mZi4og_NsGO-hGskxburNXD4LbszRs3BxDIg" +} diff --git a/ph-ee-env-labs/.circleci/config.yml b/ph-ee-env-labs/.circleci/config.yml new file mode 100644 index 000000000..04c8544d0 --- /dev/null +++ b/ph-ee-env-labs/.circleci/config.yml @@ -0,0 +1,515 @@ +version: 2.1 +orbs: + slack: circleci/slack@4.12.5 + helm: circleci/helm@2.0.1 + aws-eks: circleci/aws-eks@2.2.0 + kubernetes: circleci/kubernetes@1.3 + fynarfin-orb: fynarfin/docker-image-availability-check-and-upgrade@1.0.2 +jobs: + build: + docker: + - image: cimg/python:3.10 + working_directory: ~/repo + environment: + TERM: dumb + steps: + - checkout + - run: rm -f helm/g2p-sandbox-fynarfin-SIT/Chart.lock helm/g2p-sandbox-fynarfin-SIT/requirements.lock helm/g2p-sandbox-fynarfin-SIT/charts/* + - helm/install-helm-client: + version: "v3.8.2" + # - run: "sed -i '12s/.*/version: 0.0.0/' helm/g2p-sandbox-fynarfin-SIT/Chart.yaml" + - run: + name: build-and-host-g2p-fynarfin-sit + environment: + JIRA_STORY: '' + JIRA_STORY_DIR: '' + command: | + if [ "$CIRCLE_BRANCH" != "develop" ]; then + PR_NUMBER=$(basename $CIRCLE_PULL_REQUEST) + PR_TITLE=$(curl -sSL "https://api.github.com/repos/fynarfin/$CIRCLE_PROJECT_REPONAME/pulls/$PR_NUMBER" | jq -r '.title') + JIRA_STORY=-$(echo $PR_TITLE | cut -d "[" -f2 | cut -d "]" -f1 | tr '[A-Z]' '[a-z]') + if [ -z "$JIRA_STORY" ]; then echo "Invalid PR title" && exit 1; else echo "Ticket NO: $JIRA_STORY" && JIRA_STORY_DIR=$(echo /jira-story-version); fi + echo Charts will save in https://fynarfin.io/images/fynarfin$JIRA_STORY_DIR + fi + CHART_URL="https://fynarfin.io/images/fynarfin$JIRA_STORY_DIR/ph-ee-g2psandbox-0.0.0$JIRA_STORY" + if curl --output /dev/null --silent --head --fail "$CHART_URL"; then + sed -i "11s@^ *repository:.*\$@ repository: $CHART_URL@" helm/g2p-sandbox-fynarfin-SIT/Chart.yaml + sed -i "12s@^ *version:.*\$@ version: 0.0.0$JIRA_STORY@" helm/g2p-sandbox-fynarfin-SIT/Chart.yaml + echo "chart used: < $CHART_URL >" + else + CHART_URL="https://fynarfin.io/images/fynarfin/ph-ee-g2psandbox-0.0.0" + echo "chart used: < $CHART_URL >" + fi + sed -i "6s/.*/version: 0.2.0$JIRA_STORY/" helm/g2p-sandbox-fynarfin-SIT/Chart.yaml + cat helm/g2p-sandbox-fynarfin-SIT/Chart.yaml + helm dep up helm/g2p-sandbox-fynarfin-SIT + helm package helm/g2p-sandbox-fynarfin-SIT + helm repo index . + echo "$CERT_FILE" | base64 --decode > b64encoded.pem + chmod 400 b64encoded.pem + ssh -i b64encoded.pem -o StrictHostKeyChecking=No ec2-user@13.233.68.128 sudo mkdir -p /apps/apache-tomcat-7.0.82/webapps/ROOT/images/fynarfin$JIRA_STORY_DIR/ph-ee-g2psandbox-fynarfin$JIRA_STORY + scp -o StrictHostKeyChecking=No -i b64encoded.pem index.yaml ph-ee-g2psandbox-fynarfin-0.2.0$JIRA_STORY.tgz ec2-user@13.233.68.128:~/ + ssh -i b64encoded.pem -o StrictHostKeyChecking=No ec2-user@13.233.68.128 sudo mv -t /apps/apache-tomcat-7.0.82/webapps/ROOT/images/fynarfin$JIRA_STORY_DIR/ph-ee-g2psandbox-fynarfin$JIRA_STORY index.yaml ph-ee-g2psandbox-fynarfin-0.2.0$JIRA_STORY.tgz + build-g2p-sandbox-ci-chart: + docker: + - image: cimg/python:3.10 + working_directory: ~/repo + environment: + TERM: dumb + steps: + - checkout + - run: rm -f helm/ph-ee-g2p-sandbox-ci/Chart.lock helm/ph-ee-g2p-sandbox-ci/requirements.lock helm/ph-ee-g2p-sandbox-ci/charts/* + - helm/install-helm-client: + version: "v3.8.2" + # - run: "sed -i '12s/.*/version: 0.0.0/' helm/ph-ee-g2p-sandbox-ci/Chart.yaml" + - run: + name: build-and-host-ph-ee-g2p-sandbox-ci + environment: + JIRA_STORY: '' + JIRA_STORY_DIR: '' + command: | + if [ "$CIRCLE_BRANCH" != "develop" ]; then + PR_NUMBER=$(basename $CIRCLE_PULL_REQUEST) + PR_TITLE=$(curl -sSL "https://api.github.com/repos/fynarfin/$CIRCLE_PROJECT_REPONAME/pulls/$PR_NUMBER" | jq -r '.title') + JIRA_STORY=-$(echo $PR_TITLE | cut -d "[" -f2 | cut -d "]" -f1 | tr '[A-Z]' '[a-z]') + if [ -z "$JIRA_STORY" ]; then echo "Invalid PR title" && exit 1; else echo "Ticket NO: $JIRA_STORY" && JIRA_STORY_DIR=$(echo /jira-story-version); fi + echo Charts will save in https://fynarfin.io/images$JIRA_STORY_DIR + fi + CHART_URL="https://fynarfin.io/images$JIRA_STORY_DIR/ph-ee-g2psandbox-0.0.0$JIRA_STORY" + if curl --output /dev/null --silent --head --fail "$CHART_URL"; then + sed -i "11s@^ *repository:.*\$@ repository: $CHART_URL@" helm/ph-ee-g2p-sandbox-ci/Chart.yaml + sed -i "12s@^ *version:.*\$@ version: 0.0.0$JIRA_STORY@" helm/ph-ee-g2p-sandbox-ci/Chart.yaml + echo "chart used: < $CHART_URL >" + else + CHART_URL="https://fynarfin.io/images/ph-ee-g2p-sandbox-ci-0.0.0" + echo "chart used: < $CHART_URL >" + fi + sed -i "6s/.*/version: 0.0.0$JIRA_STORY/" helm/ph-ee-g2p-sandbox-ci/Chart.yaml + cat helm/ph-ee-g2p-sandbox-ci/Chart.yaml + helm dep up helm/ph-ee-g2p-sandbox-ci + helm package helm/ph-ee-g2p-sandbox-ci + helm repo index . + echo "$CERT_FILE" | base64 --decode > b64encoded.pem + chmod 400 b64encoded.pem + ssh -i b64encoded.pem -o StrictHostKeyChecking=No ec2-user@13.233.68.128 sudo mkdir -p /apps/apache-tomcat-7.0.82/webapps/ROOT/images/fynarfin$JIRA_STORY_DIR/ph-ee-g2p-sandbox-ci$JIRA_STORY + scp -o StrictHostKeyChecking=No -i b64encoded.pem index.yaml ph-ee-g2p-sandbox-ci-0.0.0$JIRA_STORY.tgz ec2-user@13.233.68.128:~/ + ssh -i b64encoded.pem -o StrictHostKeyChecking=No ec2-user@13.233.68.128 sudo mv -t /apps/apache-tomcat-7.0.82/webapps/ROOT/images/fynarfin$JIRA_STORY_DIR/ph-ee-g2p-sandbox-ci$JIRA_STORY index.yaml ph-ee-g2p-sandbox-ci-0.0.0$JIRA_STORY.tgz + upgrade-g2psandbox-helm-chart: + docker: + - image: cimg/python:3.10 + environment: + TERM: dumb + steps: + - fynarfin-orb/docker-image-availability-check-and-upgrade: + namespace: paymenthub + chart-base-url: https://fynarfin.io/images/fynarfin + chart-name: ph-ee-g2psandbox-fynarfin + chart-version: 0.2.0 + # chart: "https://fynarfin.io/images/fynarfin/ph-ee-g2psandbox-fynarfin/ph-ee-g2psandbox-fynarfin-0.2.0.tgz" + release-name: g2p-sandbox + # add-repo: "https://fynarfin.io/images/fynarfin/ph-ee-g2psandbox-fynarfin" + cluster-name: "sit" + aws-region: "$REGION" + service-file-path: https://raw.githubusercontent.com/fynarfin/ph-ee-env-labs/develop/.circleci/services.txt + + host-g2-sandbox-security-fynarfin-chart: + docker: + - image: cimg/python:3.10 + working_directory: ~/repo + environment: + TERM: dumb + steps: + - checkout + - run: rm -f helm/g2p-sandbox-security-fynarfin-SIT/Chart.lock helm/g2p-sandbox-security-fynarfin-SIT/requirements.lock helm/g2p-sandbox-security-fynarfin-SIT/charts/* + - helm/install-helm-client: + version: "v3.8.2" + - run: + name: build-and-host-g2p-sandbox-security + environment: + JIRA_STORY: '' + JIRA_STORY_DIR: '' + command: | + if [ "$CIRCLE_BRANCH" != "develop" ]; then + PR_NUMBER=$(basename $CIRCLE_PULL_REQUEST) + PR_TITLE=$(curl -sSL "https://api.github.com/repos/fynarfin/$CIRCLE_PROJECT_REPONAME/pulls/$PR_NUMBER" | jq -r '.title') + JIRA_STORY=-$(echo $PR_TITLE | cut -d "[" -f2 | cut -d "]" -f1 | tr '[A-Z]' '[a-z]') + if [ -z "$JIRA_STORY" ]; then echo "Invalid PR title" && exit 1; else echo "Ticket NO: $JIRA_STORY" && JIRA_STORY_DIR=$(echo /jira-story-version); fi + fi + CHART_URL="https://fynarfin.io/images/fynarfin$JIRA_STORY_DIR/ph-ee-g2psandbox-security$JIRA_STORY" + if curl --output /dev/null --silent --head --fail "$CHART_URL"; then + sed -i "10s@^ *repository:.*\$@ repository: $CHART_URL@" helm/g2p-sandbox-security-fynarfin-SIT/Chart.yaml + sed -i "11s@^ *version:.*\$@ version: 0.0.0$JIRA_STORY@" helm/g2p-sandbox-security-fynarfin-SIT/Chart.yaml + echo "chart used: < $CHART_URL >" + else + CHART_URL="https://fynarfin.io/images/fynarfin/ph-ee-g2psandbox-security" + echo "chart used: < $CHART_URL >" + fi + sed -i "5s/.*/version: 0.0.0$JIRA_STORY/" helm/g2p-sandbox-security-fynarfin-SIT/Chart.yaml + cat helm/g2p-sandbox-security-fynarfin-SIT/Chart.yaml + # - run: "sed -i '4s/.*/version: 0.0.0-SNAPSHOT/' helm/g2p-sandbox-security/requirements.yaml" + # SED & replace dependency with 0.0.0 + helm dep up helm/g2p-sandbox-security-fynarfin-SIT + helm package helm/g2p-sandbox-security-fynarfin-SIT + helm repo index . + echo "$CERT_FILE" | base64 --decode > b64encoded.pem + chmod 400 b64encoded.pem + ssh -i b64encoded.pem -o StrictHostKeyChecking=No ec2-user@13.233.68.128 sudo mkdir -p /apps/apache-tomcat-7.0.82/webapps/ROOT/images/fynarfin$JIRA_STORY_DIR/ph-ee-g2psandbox-security-fynarfin$JIRA_STORY + scp -o StrictHostKeyChecking=No -i b64encoded.pem index.yaml ph-ee-g2psandbox-security-fynarfin-0.0.0$JIRA_STORY.tgz ec2-user@13.233.68.128:~/ + ssh -i b64encoded.pem -o StrictHostKeyChecking=No ec2-user@13.233.68.128 sudo mv -t /apps/apache-tomcat-7.0.82/webapps/ROOT/images/fynarfin$JIRA_STORY_DIR/ph-ee-g2psandbox-security-fynarfin$JIRA_STORY index.yaml ph-ee-g2psandbox-security-fynarfin-0.0.0$JIRA_STORY.tgz + upgrade-g2psandbox-security-helm-chart: + docker: + - image: cimg/python:3.10 + steps: + - aws-eks/update-kubeconfig-with-authenticator: + cluster-name: "sit" + aws-region: "$REGION" + - kubernetes/install-kubectl + - run: | + if ! kubectl get ns ph-infrastructure > /dev/null 2>&1; then + kubectl create namespace ph-infrastructure + fi + - fynarfin-orb/docker-image-availability-check-and-upgrade: + namespace: ph-infrastructure + chart-base-url: https://fynarfin.io/images/fynarfin + chart-name: ph-ee-g2psandbox-security-fynarfin + chart-version: 0.0.0 + # chart: "https://fynarfin.io/images/fynarfin/ph-ee-g2psandbox-security-fynarfin/ph-ee-g2psandbox-security-fynarfin-0.0.0.tgz" + # add-repo: "https://fynarfin.io/images/fynarfin/ph-ee-g2psandbox-security-fynarfin" + release-name: g2p-sandbox-security + cluster-name: "sit" + aws-region: "$REGION" + service-file-path: https://raw.githubusercontent.com/fynarfin/ph-ee-env-labs/develop/.circleci/services.txt + + host-dpga-compliance-barebone-chart: + docker: + - image: cimg/python:3.10 + working_directory: ~/repo + environment: + TERM: dumb + steps: + - checkout + - run: | + if [[ -n $(git show --name-only $CIRCLE_SHA1 | grep "^helm/dpga-compliance-barebone/") ]]; then + echo "Directory has changed. Running the job." + else + echo "Directory has not changed. Skipping the job." + circleci step halt + fi + - run: rm -f helm/dpga-compliance-barebone/Chart.lock helm/dpga-compliance-barebone/charts/* + - helm/install-helm-client: + version: "v3.8.2" + - run: + name: host-dpga-compliance-barebone-chart + environment: + JIRA_STORY: '' + JIRA_STORY_DIR: '' + command: | + if [ "$CIRCLE_BRANCH" != "develop" ]; then + PR_NUMBER=$(basename $CIRCLE_PULL_REQUEST) + PR_TITLE=$(curl -sSL "https://api.github.com/repos/fynarfin/$CIRCLE_PROJECT_REPONAME/pulls/$PR_NUMBER" | jq -r '.title') + JIRA_STORY=-$(echo $PR_TITLE | cut -d "[" -f2 | cut -d "]" -f1 | tr '[A-Z]' '[a-z]') + if [ -z "$JIRA_STORY" ]; then echo "Invalid PR title" && exit 1; else echo "Ticket NO: $JIRA_STORY" && JIRA_STORY_DIR=$(echo /jira-story-version); fi + fi + sed -i "6s/.*/version: 1.0.0$JIRA_STORY/" helm/dpga-compliance-barebone/Chart.yaml + cat helm/dpga-compliance-barebone/Chart.yaml + helm dep up helm/dpga-compliance-barebone + helm package helm/dpga-compliance-barebone + helm repo index . + echo "$CERT_FILE" | base64 --decode > b64encoded.pem + chmod 400 b64encoded.pem + ssh -i b64encoded.pem -o StrictHostKeyChecking=No ec2-user@13.233.68.128 sudo mkdir -p /apps/apache-tomcat-7.0.82/webapps/ROOT/images/fynarfin$JIRA_STORY_DIR/dpga-barebone$JIRA_STORY + scp -o StrictHostKeyChecking=No -i b64encoded.pem index.yaml dpga-barebone-1.0.0$JIRA_STORY.tgz ec2-user@13.233.68.128:~/ + ssh -i b64encoded.pem -o StrictHostKeyChecking=No ec2-user@13.233.68.128 sudo mv -t /apps/apache-tomcat-7.0.82/webapps/ROOT/images/fynarfin$JIRA_STORY_DIR/dpga-barebone$JIRA_STORY index.yaml dpga-barebone-1.0.0$JIRA_STORY.tgz + + upgrade-dpga-compliance-barebone-chart: + docker: + - image: cimg/python:3.10 + steps: + - checkout + - run: | + if [[ -n $(git show --name-only $CIRCLE_SHA1 | grep "^helm/dpga-compliance-barebone/") ]]; then + echo "Directory has changed. Running the job." + else + echo "Directory has not changed. Skipping the job." + circleci step halt + fi + - aws-eks/update-kubeconfig-with-authenticator: + cluster-name: "sit" + aws-region: "$REGION" + - kubernetes/install-kubectl + - run: | + if ! kubectl get ns paymenthub-dpg > /dev/null 2>&1; then + kubectl create namespace paymenthub-dpg + fi + - fynarfin-orb/docker-image-availability-check-and-upgrade: + namespace: paymenthub-dpg + chart-base-url: https://fynarfin.io/images/fynarfin + chart-name: dpga-barebone + chart-version: 1.0.0 + # chart: "https://fynarfin.io/images/fynarfin/dpga-barebone/dpga-barebone-1.0.0.tgz" + # add-repo: "https://fynarfin.io/images/fynarfin/dpga-barebone" + release-name: dpga-release + cluster-name: "sit" + aws-region: "$REGION" + service-file-path: https://raw.githubusercontent.com/fynarfin/ph-ee-env-labs/develop/.circleci/services.txt + + host-g2p-sandbox-fynarfin-demo-chart: + docker: + - image: cimg/python:3.10 + working_directory: ~/repo + environment: + TERM: dumb + steps: + - checkout + - run: | + if [[ -n $(git show --name-only $CIRCLE_SHA1 | grep "^helm/g2p-sandbox-fynarfin-demo/") ]]; then + echo "Directory has changed. Running the job." + else + echo "Directory has not changed. Skipping the job." + circleci step halt + fi + - run: rm -f helm/g2p-sandbox-fynarfin-demo/Chart.lock helm/g2p-sandbox-fynarfin-demo/charts/* + - helm/install-helm-client: + version: "v3.8.2" + - run: + name: host-g2p-sandbox-fynarfin-demo + environment: + JIRA_STORY: '' + JIRA_STORY_DIR: '' + command: | + if [ "$CIRCLE_BRANCH" != "develop" ]; then + PR_NUMBER=$(basename $CIRCLE_PULL_REQUEST) + PR_TITLE=$(curl -sSL "https://api.github.com/repos/fynarfin/$CIRCLE_PROJECT_REPONAME/pulls/$PR_NUMBER" | jq -r '.title') + JIRA_STORY=-$(echo $PR_TITLE | cut -d "[" -f2 | cut -d "]" -f1 | tr '[A-Z]' '[a-z]') + if [ -z "$JIRA_STORY" ]; then echo "Invalid PR title" && exit 1; else echo "Ticket NO: $JIRA_STORY" && JIRA_STORY_DIR=$(echo /jira-story-version); fi + fi + sed -i "6s/.*/version: 1.0.0$JIRA_STORY/" helm/g2p-sandbox-fynarfin-demo/Chart.yaml + cat helm/g2p-sandbox-fynarfin-demo/Chart.yaml + helm dep up helm/g2p-sandbox-fynarfin-demo + helm package helm/g2p-sandbox-fynarfin-demo + helm repo index . + echo "$CERT_FILE" | base64 --decode > b64encoded.pem + chmod 400 b64encoded.pem + ssh -i b64encoded.pem -o StrictHostKeyChecking=No ec2-user@13.233.68.128 sudo mkdir -p /apps/apache-tomcat-7.0.82/webapps/ROOT/images/fynarfin$JIRA_STORY_DIR/ph-ee-g2psandbox-fynarfin-demo$JIRA_STORY + scp -o StrictHostKeyChecking=No -i b64encoded.pem index.yaml ph-ee-g2psandbox-fynarfin-demo-1.0.0$JIRA_STORY.tgz ec2-user@13.233.68.128:~/ + ssh -i b64encoded.pem -o StrictHostKeyChecking=No ec2-user@13.233.68.128 sudo mv -t /apps/apache-tomcat-7.0.82/webapps/ROOT/images/fynarfin$JIRA_STORY_DIR/ph-ee-g2psandbox-fynarfin-demo$JIRA_STORY index.yaml ph-ee-g2psandbox-fynarfin-demo-1.0.0$JIRA_STORY.tgz + + upgrade-g2p-sandbox-fynarfin-demo-chart: + docker: + - image: cimg/python:3.10 + steps: + - checkout + - run: | + if [[ -n $(git show --name-only $CIRCLE_SHA1 | grep "^helm/g2p-sandbox-fynarfin-demo/") ]]; then + echo "Directory has changed. Running the job." + else + echo "Directory has not changed. Skipping the job." + circleci step halt + fi + - aws-eks/update-kubeconfig-with-authenticator: + cluster-name: "sit" + aws-region: "$REGION" + - kubernetes/install-kubectl + - run: | + if ! kubectl get ns paymenthub-demo > /dev/null 2>&1; then + kubectl create namespace paymenthub-demo + fi + - run: "kubectl delete clusterroles `kubectl get clusterroles |grep c-role|cut -d ' ' -f1` || echo ' ' " + - run: "kubectl delete clusterrolebinding `kubectl get clusterrolebinding |grep c-role|cut -d ' ' -f1` || echo ' ' " + - fynarfin-orb/docker-image-availability-check-and-upgrade: + namespace: paymenthub-demo + chart-base-url: https://fynarfin.io/images/fynarfin + chart-name: ph-ee-g2psandbox-fynarfin-demo + chart-version: 1.0.0 + release-name: g2p-sandbox-demo + cluster-name: "sit" + aws-region: "$REGION" + service-file-path: https://raw.githubusercontent.com/fynarfin/ph-ee-env-labs/develop/.circleci/services.txt + + deploying-bpmns-demo-namespace: + docker: + - image: 'cimg/base:2022.06' + steps: + - checkout + - run: | + if [[ -n $(git show --name-only $CIRCLE_SHA1 | grep "^helm/g2p-sandbox-fynarfin-demo/") ]]; then + echo "Directory has changed. Running the job." + else + echo "Directory has not changed. Skipping the job." + circleci step halt + fi + - run: git clone https://github.com/fynarfin/ph-ee-env-labs + - run: echo $AWS_PROFILE + - run: echo $AWS_DEFAULT_PROFILE + - run: | + #sleep 5 + #sudo apt install -y netcat + #until nc -vz https://zeebeops-demo.sandbox.fynarfin.io 443; do echo "Waiting for zeebe-ops service"; sleep 2; done; + - run: | + cd ph-ee-env-labs + sed -i 's/zeebeops/zeebeops-demo/g' orchestration/deployBpmn.sh + sh orchestration/deployBpmn.sh + + create-secret-paymenthub-demo-namespace: + docker: + - image: 'cimg/base:2022.06' + environment: + TERM: dumb + NAMESPACE: paymenthub-demo + steps: + - setup_remote_docker: + version: 20.10.14 + - kubernetes/install-kubectl + - run: git clone https://github.com/fynarfin/ph-ee-env-labs + - aws-eks/update-kubeconfig-with-authenticator: + cluster-name: "sit" + aws-region: "$REGION" + - run: | + cd ph-ee-env-labs + export ENV_NAMESPACE=$NAMESPACE + kubectl config use-context arn:aws:eks:$REGION:419830066942:cluster/sit + kubectl config get-contexts + cd helm/kibana-secret/ + make secrets || echo "kibana" already exists + + - run: | + cd ph-ee-env-labs + export ENV_NAMESPACE=$NAMESPACE + kubectl config use-context arn:aws:eks:$REGION:419830066942:cluster/sit + kubectl config get-contexts + cd helm/es-secret/ + make secrets || echo "elastic-certificates" already exists + + create-tls-secret-paymenthub-demo-namespace: + docker: + - image: 'cimg/base:2022.06' + environment: + TERM: dumb + NAMESPACE: paymenthub-demo + steps: + - setup_remote_docker: + version: 20.10.14 + - kubernetes/install-kubectl + - aws-eks/update-kubeconfig-with-authenticator: + cluster-name: "sit" + aws-region: "$REGION" + - run: | + echo "$KEY" | tr '#' '\n' > key.pem + echo "$SSL_BUNDLE" | tr '#' '\n' > ssl-bundle.crt + openssl x509 -in ssl-bundle.crt -text -noout + if kubectl get secret fyn-cert --namespace $NAMESPACE &> /dev/null; then + echo "Secret fyn-cert already exists. Skipping creation." + else + kubectl create secret tls fyn-cert --namespace $NAMESPACE --key=key.pem --cert=ssl-bundle.crt -o yaml + fi + + test-chart-gov: + docker: + - image: cimg/openjdk:17.0.0 + steps: + - run: git clone https://github.com/fynarfin/ph-ee-integration-test + - run: cd ph-ee-integration-test && ./gradlew test -Dcucumber.filter.tags="@gov" + - store_test_results: + path: ph-ee-integration-test/build/test-results/test/TEST-org.fynarfin.integrationtest.TestRunner.xml + test-chart-ams: + docker: + - image: cimg/openjdk:17.0.0 + steps: + - run: git clone https://github.com/fynarfin/ph-ee-integration-test + - run: cd ph-ee-integration-test && ./gradlew test -Dcucumber.filter.tags="@amsIntegration" + - store_test_results: + path: ph-ee-integration-test/build/test-results/test/TEST-org.fynarfin.integrationtest.TestRunner.xml + +workflows: + deploy: + jobs: + - build: + context: + - AWS + - Helm + - slack + - build-g2p-sandbox-ci-chart: + requires: + - build + context: + - AWS + - Helm + - slack + - host-g2-sandbox-security-fynarfin-chart: + requires: + - build-g2p-sandbox-ci-chart + context: + - AWS + - Helm + - slack + - upgrade-g2psandbox-helm-chart: + requires: + - build + - upgrade-g2psandbox-security-helm-chart + context: + - AWS + - Helm + - slack + - upgrade-g2psandbox-security-helm-chart: + requires: + - host-g2-sandbox-security-fynarfin-chart + context: + - AWS + - Helm + - slack + - host-dpga-compliance-barebone-chart: + context: + - AWS + - Helm + - slack + - upgrade-dpga-compliance-barebone-chart: + requires: + - host-dpga-compliance-barebone-chart + context: + - AWS + - Helm + - slack + - host-g2p-sandbox-fynarfin-demo-chart: + context: + - AWS + - Helm + - slack + - upgrade-g2p-sandbox-fynarfin-demo-chart: + requires: + - host-g2p-sandbox-fynarfin-demo-chart + context: + - AWS + - Helm + - slack + - deploying-bpmns-demo-namespace: + requires: + - upgrade-g2p-sandbox-fynarfin-demo-chart + context: + - AWS + - Helm + - slack + - create-secret-paymenthub-demo-namespace: + requires: + - deploying-bpmns-demo-namespace + context: + - AWS + - Helm + - slack + - Secrets + - create-tls-secret-paymenthub-demo-namespace: + requires: + - upgrade-g2p-sandbox-fynarfin-demo-chart + context: + - AWS + - Helm + - slack + - Secrets + - TLS + # - install-helm-chart: + # cluster-name: sit + # - delete-helm-release: + # cluster-name: sit + # requires: + # - install-helm-chart + + diff --git a/ph-ee-env-labs/.circleci/services.txt b/ph-ee-env-labs/.circleci/services.txt new file mode 100644 index 000000000..7bde5858e --- /dev/null +++ b/ph-ee-env-labs/.circleci/services.txt @@ -0,0 +1,22 @@ +ph-ee-g2psandbox.ph-ee-engine.community-app.image docker.io/fynarfin/community-app +ph-ee-g2psandbox.ph-ee-engine.ph_ee_connector_ams_mifos.image docker.io/fynarfin/ph-ee-connector-ams-mifos +ph-ee-g2psandbox.ph-ee-engine.connector_bulk.image docker.io/fynarfin/ph-ee-bulk-processor +ph-ee-g2psandbox.ph-ee-engine.importer_rdbms.image docker.io/fynarfin/ph-ee-importer-rdbms +ph-ee-g2psandbox.ph-ee-engine.channel.image docker.io/fynarfin/ph-ee-connector-channel +ph-ee-g2psandbox.ph-ee-engine.messagegateway.image docker.io/fynarfin/message-gateway +ph-ee-g2psandbox.ph-ee-engine.ph_ee_connector_gsma.image docker.io/fynarfin/ph-ee-connector-gsma +ph-ee-g2psandbox.ph-ee-engine.mockpayment.image docker.io/fynarfin/ph-ee-connector-mock-payment-schema +ph-ee-g2psandbox.ph-ee-engine.ph_ee_connector_mojaloop.image docker.io/fynarfin/ph-ee-connector-mojaloop +ph-ee-g2psandbox.ph-ee-engine.notifications.image docker.io/fynarfin/ph-ee-notifications +ph-ee-g2psandbox.account_mapper.image docker.io/fynarfin/ph-ee-identity-account-mapper +ph-ee-g2psandbox.ph-ee-engine.importer_es.image docker.io/fynarfin/ph-ee-importer-es +ph-ee-g2psandbox.ph-ee-engine.operations_app.image docker.io/fynarfin/ph-ee-operations-app +ph-ee-g2psandbox.ph-ee-engine.operations_web.image docker.io/fynarfin/ph-ee-operations-web +ph-ee-g2psandbox.ph-ee-engine.vouchers.image docker.io/fynarfin/ph-ee-vouchers +ph-ee-g2psandbox.ph-ee-engine.ph_ee_connector_slcb.image docker.io/fynarfin/ph-ee-connector-slcb +ph-ee-g2psandbox.ph-ee-engine.mpesa.image fynarfin/ph-ee-connector-mpesa +ph-ee-g2psandbox.ph-ee-engine.crm.image fynarfin/ph-ee-connector-crm +ph-ee-g2psandbox.ph-ee-engine.billPay.image fynarfin/ph-ee-bill-pay +ph-ee-g2psandbox.ph-ee-engine.connector.image fynarfin/ph-ee-connector-bulk +ph-ee-g2psandbox.ph-ee-engine.integration_test.image fynarfin/ph-ee-integration-test +ph-ee-g2psandbox.ph-ee-engine.zeebe_ops.image fynarfin/ph-ee-zeebe-ops \ No newline at end of file diff --git a/ph-ee-env-labs/.github/ISSUE_TEMPLATE/DMP_2024.yml b/ph-ee-env-labs/.github/ISSUE_TEMPLATE/DMP_2024.yml new file mode 100644 index 000000000..f729c7318 --- /dev/null +++ b/ph-ee-env-labs/.github/ISSUE_TEMPLATE/DMP_2024.yml @@ -0,0 +1,264 @@ +name: DMP 2024 Project Template +description: List a new project for Dedicated Mentoring Program (DMP) 2024 +title: "[DMP 2024]: " +labels: ["DMP 2024"] +body: + - type: textarea + id: ticket-description + validations: + required: true + attributes: + label: Ticket Contents + value: | + ## Description + [Provide a brief description of the feature, including why it is needed and what it will accomplish.] + + - type: textarea + id: ticket-goals + validations: + required: true + attributes: + label: Goals & Mid-Point Milestone + description: List the goals of the feature. Please add the goals that must be achieved by Mid-point check-in i.e 1.5 months into the coding period. + value: | + ## Goals + - [ ] [Goal 1] + - [ ] [Goal 2] + - [ ] [Goal 3] + - [ ] [Goal 4] + - [ ] [Goals Achieved By Mid-point Milestone] + + - type: textarea + id: ticket-setup + attributes: + label: Setup/Installation + description: Please list or link setup or installation guide (if any) + + - type: textarea + id: ticket-expected-outcome + attributes: + label: Expected Outcome + description: Describe in detail what the final product or result should look like and how it should behave. + + - type: textarea + id: ticket-acceptance-criteria + attributes: + label: Acceptance Criteria + description: List the acceptance criteria for this feature. + + - type: textarea + id: ticket-implementation-details + validations: + required: true + attributes: + label: Implementation Details + description: List any technical details about the proposed implementation, including any specific technologies that will be used. + + - type: textarea + id: ticket-mockups + attributes: + label: Mockups/Wireframes + description: Include links to any visual aids, mockups, wireframes, or diagrams that help illustrate what the final product should look like. This is not always necessary, but can be very helpful in many cases. + + - type: input + id: ticket-product + attributes: + label: Product Name + placeholder: Enter Product Name + validations: + required: true + + - type: dropdown + id: ticket-organisation + attributes: + label: Organisation Name + description: Enter Organisation Name + multiple: false + options: + - Bandhu + - Belongg + - Blockster Global (CREDBEL) + - Civis + - Dhwani + - Dhiway + - EGov + - EkShop Marketplace + - FIDE + - If Me + - Key Education Foundation + - Norwegian Meteorological Institute + - Planet Read + - Project Second Chance + - Reap Benefit + - SamagraX + - ShikshaLokam + - Tech4Dev + - Tekdi + - The Mifos Initiative + - Tibil + - Ushahidi + - Arghyam + - Piramal Swasthya Management Research Institute + - Belongg AI + validations: + required: true + + - type: dropdown + id: ticket-governance-domain + attributes: + label: Domain + options: + - ⁠Healthcare + - ⁠Education + - Financial Inclusion + - ⁠Livelihoods + - ⁠Skilling + - ⁠Learning & Development + - ⁠Agriculture + - ⁠Service Delivery + - Open Source Library + - Water + validations: + required: true + + + - type: dropdown + id: ticket-technical-skills-required + attributes: + label: Tech Skills Needed + description: Select the technologies needed for this ticket (use Ctrl or Command to select multiple) + multiple: true + options: + - .NET + - Angular + - Artificial Intelligence + - ASP.NET + - AWS + - Babel + - Bootstrap + - C# + - Chart.js + - CI/CD + - Computer Vision + - CORS + - cURL + - Cypress + - D3.js + - Database + - Debugging + - Design + - DevOps + - Django + - Docker + - Electron + - ESLint + - Express.js + - Feature + - Flask + - Go + - GraphQL + - HTML + - Ionic + - Jest + - Java + - JavaScript + - Jenkins + - JWT + - Kubernetes + - Laravel + - Machine Learning + - Maintenance + - Markdown + - Material-UI + - Microservices + - MongoDB + - Mobile + - Mockups + - Mocha + - Natural Language Processing + - NestJS + - Node.js + - NUnit + - OAuth + - Performance Improvement + - Prettier + - Python + - Question + - React + - React Native + - Redux + - RESTful APIs + - Ruby + - Ruby on Rails + - Rust + - Scala + - Security + - Selenium + - SEO + - Serverless + - Solidity + - Spring Boot + - SQL + - Swagger + - Tailwind CSS + - Test + - Testing Library + - Three.js + - TypeScript + - UI/UX/Design + - Virtual Reality + - Vue.js + - WebSockets + - Webpack + - Other + validations: + required: true + + - type: textarea + id: ticket-mentors + attributes: + label: Mentor(s) + description: Please tag relevant mentors for the ticket + validations: + required: true + + - type: dropdown + id: ticket-category + attributes: + label: Category + description: Choose the categories that best describe your ticket + multiple: true + options: + - API + - Analytics + - Accessibility + - Backend + - Breaking Change + - Beginner Friendly + - Configuration + - CI/CD + - Database + - Data Science + - Deprecation + - Documentation + - Delpoyment + - Frontend + - Internationalization + - Localization + - Machine Learning + - Maintenance + - Mobile + - Performance Improvement + - Question + - Refactoring + - Research + - Needs Reproduction + - SEO + - Security + - Testing + - AI + - Other + validations: + required: true + + diff --git a/ph-ee-env-labs/.github/pull_request_template.md b/ph-ee-env-labs/.github/pull_request_template.md new file mode 100644 index 000000000..8716e5451 --- /dev/null +++ b/ph-ee-env-labs/.github/pull_request_template.md @@ -0,0 +1,22 @@ +## Description + +* PR title should have jira ticket enclosed in `[]`.
+ Format: ``` [jira_ticket] description```
+ ex: [phee-123] PR title. +* Add a link to the Jira ticket. +* Describe the changes made and why they were made. + +## Checklist + +Please make sure these boxes are checked before submitting your pull request - thanks! +- [ ] Followed the PR title naming convention mentioned above. + +- [ ] Design-related bullet points or design document links related to this PR are added in the description above. + +- [ ] Updated corresponding Postman Collection or Api documentation for the changes in this PR. + +- [ ] Create/update unit or integration tests for verifying the changes made. + +- [ ] Add required Swagger annotation and update API documentation with details of any API changes if applicable + +- [ ] Followed the naming conventions as given in https://docs.google.com/document/d/1Q4vaMSzrTxxh9TS0RILuNkSkYCxotuYk1Xe0CMIkkCU/edit?usp=sharing diff --git a/ph-ee-env-labs/.gitignore b/ph-ee-env-labs/.gitignore new file mode 100644 index 000000000..ab6a1b043 --- /dev/null +++ b/ph-ee-env-labs/.gitignore @@ -0,0 +1,36 @@ +.DS_Store +*.class +*.jar +*.war +*.ear +.classpath +.project +.settings +.gradle +build +*.iml +*.ipr +*.iws +*.swp +*.DS_Store +.idea +.vscode +catalina.base_IS_UNDEFINED/ +keystore.jks +bin/ +.lock +fineract-provider/out/ +fineract-provider/config/swagger/config.json +fineract-provider/config/swagger/fineract-input.yaml +licenses +**/.asciidoctor/images/* +**/.asciidoctor/diagram/* +**/images/diag-*.svg +fineract-avro-schemas/out/ +fineract-client/out/ +fineract-provider/src/main/generated/ +integration-tests/out/ +module/dummy/starter/out/ +chart.lock +*.tgz +charts/ \ No newline at end of file diff --git a/ph-ee-env-labs/Collection/Collection OAF.postman_collection.json b/ph-ee-env-labs/Collection/Collection OAF.postman_collection.json new file mode 100644 index 000000000..e838ba9bd --- /dev/null +++ b/ph-ee-env-labs/Collection/Collection OAF.postman_collection.json @@ -0,0 +1,116 @@ +{ + "info": { + "_postman_id": "ca4a575d-03b8-4873-898d-8a7cf6e2e46e", + "name": "Collection OAF", + "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json" + }, + "item": [ + { + "name": "https://paymenthub.qa.oneacrefund.org/channel/channel/collection", + "request": { + "method": "POST", + "header": [ + { + "key": "Platform-TenantId", + "value": "oaf", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"payer\": [\n {\n \"key\": \"MSISDN\",\n \"value\": \"254708374149\"\n },\n {\n \"key\": \"ACCOUNTID\",\n \"value\": \"24450523\"\n }\n ],\n \"amount\": {\n \"amount\": \"1\",\n \"currency\": \"USD\"\n },\n \"transactionType\": {\n \"scenario\": \"MPESA\",\n \"subScenario\": \"BUYGOODS\",\n \"initiator\": \"PAYEE\",\n \"initiatorType\": \"BUSINESS\"\n }\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "https://paymenthub.qa.oneacrefund.org/channel/channel/collection", + "protocol": "https", + "host": [ + "paymenthub", + "qa", + "oneacrefund", + "org" + ], + "path": [ + "channel", + "channel", + "collection" + ] + }, + "description": "Cloud API" + }, + "response": [] + }, + { + "name": "http://0.0.0.0:5000/buygoods/callback", + "request": { + "method": "POST", + "header": [], + "url": { + "raw": "http://0.0.0.0:5000/buygoods/callback", + "protocol": "http", + "host": [ + "0", + "0", + "0", + "0" + ], + "port": "5000", + "path": [ + "buygoods", + "callback" + ] + } + }, + "response": [] + }, + { + "name": "http://0.0.0.0:5000/sms/callback", + "request": { + "method": "POST", + "header": [], + "url": { + "raw": "http://0.0.0.0:5000/sms/callback", + "protocol": "http", + "host": [ + "0", + "0", + "0", + "0" + ], + "port": "5000", + "path": [ + "sms", + "callback" + ] + }, + "description": "Callback from message gateway" + }, + "response": [] + }, + { + "name": "http:/localhost:9191/telerivet/report/", + "request": { + "method": "POST", + "header": [], + "url": { + "raw": "http:/localhost:9191/telerivet/report/", + "host": [ + "http" + ], + "port": "", + "path": [ + "localhost:9191", + "telerivet", + "report", + "" + ] + } + }, + "response": [] + } + ] +} \ No newline at end of file diff --git a/ph-ee-env-labs/Collection/Paybill APIs.postman_collection.json b/ph-ee-env-labs/Collection/Paybill APIs.postman_collection.json new file mode 100644 index 000000000..1ece514d3 --- /dev/null +++ b/ph-ee-env-labs/Collection/Paybill APIs.postman_collection.json @@ -0,0 +1,752 @@ +{ + "info": { + "_postman_id": "dfade4e2-596c-4a83-8d1a-8faed215a9f6", + "name": "Paybill APIs", + "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json", + "_exporter_id": "22669462" + }, + "item": [ + { + "name": "Validation", + "item": [ + { + "name": "MPESA-Connector Validiate Webhook", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 200\", function () {", + " pm.response.to.have.status(200);", + " pm.expect(pm.response.text).not.equal(null)", + "});", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"TransactionType\":\"Pay Bill\",\n \"TransID\":\"RKTQDM7W6S\",\n \"TransTime\":\"20191122063845\",\n \"TransAmount\":\"10\",\n \"BusinessShortCode\":\"24322607\",\n \"BillRefNumber\":\"24322607\",\n \"InvoiceNumber\":\"\",\n \"OrgAccountBalance\":\"49197.00\",\n \"ThirdPartyTransID\":\"\",\n \"MSISDN\":\"254797668592\",\n \"FirstName\":\"John\"\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{MpesaHostName}}/validation?amsName=paygops", + "host": [ + "{{MpesaHostName}}" + ], + "path": [ + "validation" + ], + "query": [ + { + "key": "amsName", + "value": "paygops" + } + ] + } + }, + "response": [ + { + "name": "MPESA-Connector Validiate Webhook", + "originalRequest": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"TransactionType\":\"Pay Bill\",\n \"TransID\":\"RKTQDM7W6S\",\n \"TransTime\":\"20191122063845\",\n \"TransAmount\":\"10\",\n \"BusinessShortCode\":\"24322607\",\n \"BillRefNumber\":\"24322607\",\n \"InvoiceNumber\":\"\",\n \"OrgAccountBalance\":\"49197.00\",\n \"ThirdPartyTransID\":\"\",\n \"MSISDN\":\"254797668592\",\n \"FirstName\":\"John\"\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "http://localhost:5000/validation?amsName=paygops", + "protocol": "http", + "host": [ + "localhost" + ], + "port": "5000", + "path": [ + "validation" + ], + "query": [ + { + "key": "amsName", + "value": "paygops" + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Accept", + "value": "*/*" + }, + { + "key": "Postman-Token", + "value": "13349c97-9169-4cb4-86d0-88f87c303d59" + }, + { + "key": "amsName", + "value": "paygops" + }, + { + "key": "CF-RAY", + "value": "75871274fd4d94c2-CCU" + }, + { + "key": "Accept-Encoding", + "value": "gzip,deflate" + }, + { + "key": "Server", + "value": "cloudflare" + }, + { + "key": "Report-To", + "value": "{\"endpoints\":[{\"url\":\"https:\\/\\/a.nel.cloudflare.com\\/report\\/v3?s=U739gismX5DI0NtG%2BmyGgq5yoGzkBNnpQwXIFtbea4z6BpbaBDXBXgWVnLOYDe%2B6iZ7VXv9Dq3PxW7sHyKP0r1UuGwpfZLe4T5DPaYCdBkwtAYaakdx1YxiwKyZlGUrW5jq15WteJ0nox%2BQ%3D\"}],\"group\":\"cf-nel\",\"max_age\":604800}" + }, + { + "key": "Date", + "value": "Tue, 11 Oct 2022 10:56:57 GMT" + }, + { + "key": "NEL", + "value": "{\"success_fraction\":0,\"report_to\":\"cf-nel\",\"max_age\":604800}" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "Authorization", + "value": "Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJTb2xhcmlzIE9mZmdyaWQiLCJleHAiOjE2ODAyNzcwNDcsImlhdCI6MTY0ODcyMDA5NSwic3ViIjo2MDUsInBlcm1pc3Npb25zIjpbIkRlbGV0ZURldmljZXMiLCJIYW5kbGVSZXZlcnNlZFBheW1lbnRzIiwiVmlld0Rhc2hib2FyZHMiLCJDaGFuZ2VQQVlHTW9kZURldmljZXMiLCJWaWV3R2xvYmFsRGFzaGJvYXJkcyIsIkVkaXRBY2NvdW50cyIsIk1hbmFnZUFsbEFjY291bnRzIiwiRm9yY2VQQVlHTW9kZURldmljZXMiLCJHb2dsYURhc2hib2FyZHMiLCJXaXRoTWVWaWV3U3RvY2siLCJEb3dubG9hZEdsb2JhbEFjY291bnRzIiwiRGVsZXRlUGhvbmVOdW1iZXJzIiwiTWFuYWdlQWNjb3VudHMiLCJXaXRoQ2xpZW50c1ZpZXdTdG9jayIsIkxpc3RQb3J0Zm9saW9zIiwiT3JwaGFuZWRWaWV3U3RvY2siLCJWaWV3UG9ydGZvbGlvcyIsIkVkaXRNYWRlVHJhbnNmZXJzIiwiRnJvbU9ycGhhbmVkTW92ZVN0b2NrIiwiUmVxdWVzdFRyYW5zZmVycyIsIkVkaXRQb3J0Zm9saW9zIiwiRGVsZXRlUG9ydGZvbGlvcyIsIkFwcHJvdmVUcmFuc2ZlcnMiLCJGcm9tV2l0aE1lTW92ZVN0b2NrIiwiQ3JlYXRlUG9ydGZvbGlvcyIsIkNvbmZpcm1UcmFuc2ZlcnMiLCJUb09ycGhhbmVkTW92ZVN0b2NrIiwiVG9XaXRoTWVNb3ZlU3RvY2siLCJWaWV3VHJhbnNmZXJzIiwiQXBwcm92ZUFkZE9ucyIsIlZpZXdTZXR0aW5nc0ludGVyZmFjZUFkbWluIiwiRGVsZXRlVHJhbnNmZXJzIiwiRWRpdFBsYW5uZWREZWxpdmVyeURhdGVMZWFkcyIsIkNyZWF0ZUFQSVRva2VuQWRtaW4iLCJWaWV3QmFkZ2VUcmFuc2ZlcnMiLCJDb25maWd1cmVNb2JpbGVBcHBTZXR0aW5nc0FkbWluIiwiU3luY0NvbXBsZXRlZENsaWVudHNNb2JpbGUiLCJWaWV3QWN0aXZpdHlMb2dBZG1pbiIsIlZpZXdFeHBlbnNlcyIsIkFkZEV4cGVuc2VzIiwiRXhwb3J0RGF0YUFkbWluIiwiRWRpdE9mZmVyUGFydGlhbGx5UGFpZExlYWRzIiwiRWRpdEV4cGVuc2VzIiwiRWRpdE9mZmVyQXdhaXRpbmdEZWxpdmVyeUxlYWRzIiwiRWRpdE93bkV4cGVuc2VzIiwiQ29uZmlndXJlQXV0b21hdGVkTWVzc2FnZXNBZG1pbiIsIlN5bmNMZWFkc01vYmlsZSIsIkNvbmZpZ3VyZVNhbGVzTWFuYWdlbWVudEFkbWluIiwiRWRpdE90aGVyc0V4cGVuc2VzIiwiUmVtb3ZlTGFzdFBob25lTnVtYmVycyIsIkNvbmZpZ3VyZVBheW1lbnRNYW5hZ2VtZW50QWRtaW4iLCJFZGl0QW1vdW50RXhwZW5zZXMiLCJEZWxldGVFeHBlbnNlcyIsIkNvbmZpZ3VyZUxvY2FsU2V0dGluZ3NBZG1pbiIsIkZpbGxDdXN0b21Gb3Jtc0NsaWVudHMiLCJBZGRWaWxsYWdlcyIsIkNvbmZpZ3VyZUdlbmVyYWxTZXR0aW5nc0FkbWluIiwiQWRkVG9Db250cmFjdEFkZE9ucyIsIkNvbmZpZ3VyZUxhbmd1YWdlU2V0dGluZ3NBZG1pbiIsIkVkaXRWaWxsYWdlcyIsIlN5bmNBY3RpdmF0aW9uQWN0aW9ucyIsIkVkaXRDdXN0b21TTVNBZG1pbiIsIkRlbGV0ZVZpbGxhZ2VzIiwiRmlsbEN1c3RvbUZvcm1zTGVhZHMiLCJWaWV3U2hvcHMiLCJDdXN0b21pemVQbGF0Zm9ybUFkbWluIiwiQWRkQ2x1c3RlcnMiLCJTZWVBbGxOb3RpZmljYXRpb25zQWRtaW4iLCJTZWVIdWJOb3RpZmljYXRpb25zQWRtaW4iLCJFZGl0Q2x1c3RlcnMiLCJWaWV3T2ZmZXJzIiwiVmlld0FjY291bnRzIiwiVmlld093blVzZXJzIiwiRWRpdFVzZXJzIiwiQWRkT2ZmZXJzIiwiRWRpdE9mZmVycyIsIkFkZFVzZXJzIiwiQWRkSHVicyIsIkVkaXRIdWJzIiwiVmlld0FkZG9uT2ZmZXJzIiwiQ3JlYXRlUm9sZXMiLCJEZWxldGVIdWJzIiwiQWRkQWRkb25PZmZlcnMiLCJBc3NpZ25Sb2xlcyIsIkFkZERldmljZXMiLCJFZGl0QWRkb25PZmZlcnMiLCJBZGRab25lcyIsIlZpZXdMb2dzIiwiVmlld0xlYWRHZW5lcmF0b3JzIiwiRWRpdFpvbmVzIiwiU2V0Q29tbWlzc2lvbkxlYWRzIiwiVmlld0ZhdWx0c0xvZ3MiLCJEZWxldGVab25lcyIsIlZpZXdVc2VycyIsIkFkZE1lc3NhZ2VzIiwiVmlld0xlYWRzIiwiQWRkUmVnaW9ucyIsIkFwcHJvdmVMZWFkcyIsIkFkZE1hbnVhbE1lc3NhZ2VzIiwiRWRpdFJlZ2lvbnMiLCJWaWV3QWxsTWVzc2FnZXMiLCJEZWxldGVSZWdpb25zIiwiVmlld01lc3NhZ2VzIiwiQWRkQ2xpZW50R3JvdXBzIiwiVmlld09ycGhhbmVkTWVzc2FnZXMiLCJFZGl0Q2xpZW50R3JvdXBzIiwiQWRkT3V0Z29pbmdNZXNzYWdlcyIsIkFkZExlYWRzIiwiRGVsZXRlQ2xpZW50R3JvdXBzIiwiVmlld0JhZGdlTGVhZHMiLCJBZGRBUElIb29rIiwiSW5TdG9ja1ZpZXdTdG9jayIsIldpdGhVc2Vyc1ZpZXdTdG9jayIsIkRlbGV0ZUFQSUhvb2siLCJGcm9tSW5TdG9ja01vdmVTdG9jayIsIlZpZXdGb3JtcyIsIkZyb21Vc2Vyc01vdmVTdG9jayIsIkFkZEZvcm1zIiwiVG9JblN0b2NrTW92ZVN0b2NrIiwiR2l2ZUNvbW1pc3Npb25Ub0xlYWRHZW5lcmF0b3JzIiwiRWRpdEZvcm1zIiwiRGVsZXRlRm9ybXMiLCJFZGl0Q2xpZW50cyIsIlRvVXNlcnNNb3ZlU3RvY2siLCJWaWV3SXNzdWVzIiwiQWRkSXNzdWVzIiwiRWRpdEludGVyYWN0aW9uc1NldHRpbmdzRm9ybXMiLCJDb25maWd1cmVPcGVyYXRpb25hbEVudGl0aWVzQWRtaW4iLCJWaWV3Q2xpZW50cyIsIkVkaXRJc3N1ZXMiLCJFZGl0Q2xpZW50TGVhZERhdGFTZXR0aW5nc0Zvcm1zIiwiQ29uZmlndXJlRGV2aWNlQVBJQWRtaW4iLCJNYWtlT25TdG9ja091dHNpZGVWaWV3QWN0aW9ucyIsIlZpZXdJbnRlcmFjdGlvbnMiLCJWaWV3QWN0aW9ucyIsIkFkZEludGVyYWN0aW9ucyIsIlN5bmNBbGxDcmVhdGVkTGVhZHNNb2JpbGUiLCJEb0NoYW5nZU9mZmVyQWN0aW9ucyIsIkVkaXRJbnRlcmFjdGlvbnMiLCJTeW5jQWxsR2VuZXJhdGVkTGVhZHNNb2JpbGUiLCJEZVJlZ2lzdGVyQWN0aW9ucyIsIkRlbGV0ZUludGVyYWN0aW9ucyIsIlN5bmNJbnN0YWxsZWRMYXN0MldlZWtzTGVhZHNNb2JpbGUiLCJWaWV3UGxhbm5pbmciLCJHaXZlRGlzY291bnRBY3Rpb25zIiwiU3luY0luc3RhbGxlZExhc3QyTW9udGhzTGVhZHNNb2JpbGUiLCJWaWV3Q3JlYXRlZExlYWRzIiwiR2l2ZURpc2NvdW50T3ZlcjJEYXlzQWN0aW9ucyIsIkFkZFBsYW5uaW5nIiwiU3luY0xlYWRHZW5lcmF0b3JzTW9iaWxlIiwiRWRpdFBsYW5uaW5nIiwiUmVnaXN0ZXJBY3Rpb25zIiwiTWVyZ2VMZWFkR2VuZXJhdG9ycyIsIlN5bmNDbGllbnRzTW9iaWxlIiwiRWRpdExlYWRzIiwiQ29sbGVjdENhc2hBY3Rpb25zIiwiRGVsZXRlUGxhbm5pbmciLCJTeW5jQWxsQ3JlYXRlZENsaWVudHNNb2JpbGUiLCJTd2FwRGV2aWNlQWN0aW9ucyIsIkVkaXRMZWFkR2VuZXJhdG9ycyIsIlZpZXdQYXltZW50cyIsIlN5bmNBbGxHZW5lcmF0ZWRDbGllbnRzTW9iaWxlIiwiVmlld09ycGhhbmVkUGF5bWVudHMiLCJHaXZlRGVsYXlBY3Rpb25zIiwiU3luY0ludGVyYWN0aW9uc01vYmlsZSIsIkFkZFBheW1lbnRzIiwiR2l2ZURlbGF5T3ZlcjJEYXlzQWN0aW9ucyIsIlN5bmNQbGFubmluZ01vYmlsZSIsIkFkZExlYWRHZW5lcmF0b3JzIiwiR2l2ZU5lZ2F0aXZlRGlzY291bnRUb0NvbXBsZXRlZEFjdGlvbnMiLCJBZGp1c3RCYWxhbmNlUGF5bWVudHMiLCJTeW5jRGV2aWNlc01vYmlsZSIsIkVkaXRXYWxsZXRQYXltZW50cyIsIk1hcmtDb250cmFjdERlZmF1bHRlZEFjdGlvbnMiLCJWaWV3UmV2ZXJzZWRQYXltZW50cyIsIlVuZG9Db250cmFjdERlZmF1bHRlZEFjdGlvbnMiLCJFZGl0SW5zdGFsbGVkTGVhZHMiLCJWaWV3QmFkZ2VJc3N1ZXMiLCJHaXZlVG9rZW5zT2ZmbGluZUFjdGlvbnMiLCJBZGRSZXZlcnNlZFBheW1lbnRzIl19.msQFoIe1htXINxp82s2K0jEXFBE_QMdd0U5LnQzVNa4" + }, + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Content-Length", + "value": "436" + }, + { + "key": "CF-Cache-Status", + "value": "DYNAMIC" + } + ], + "cookie": [], + "body": "{\n \"transaction_id\": \"RKTQDM7W6S\",\n \"amount\": \"1\",\n \"sender_name\": \"254797668592\",\n \"sender_phone_number\": \"+254797668592\",\n \"sent_datetime\": \"2022-10-11T10:56:57.265124Z\",\n \"memo\": \"24322607\",\n \"wallet_operator\": \"\",\n \"country\": \"\",\n \"currency\": \"KES\",\n \"warnings\": [],\n \"reconciled\": true,\n \"destinations\": [\n {\n \"destination_type\": \"contract_repayment\",\n \"destination\": \"C370015\"\n }\n ],\n \"destination_type\": \"contract_repayment\",\n \"destination\": \"C370015\"\n}" + } + ] + }, + { + "name": "Account Status", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 200\", function () {", + " pm.response.to.have.status(200);", + " pm.expect(pm.response.text).not.equal(null)", + "});", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"primaryIdentifier\": {\n \"key\": \"foundationalID\",\n \"value\": \"24322607\"\n },\n \"secondaryIdentifier\": {\n \"key\": \"MSISDN\",\n \"value\": \"254797668592\"\n },\n \"customData\": [\n {\n \"key\": \"transactionId\",\n \"value\": \"670d65bd-4efd-4a6c-ae2c-7fdaa8cb4d60\"\n },\n {\n \"key\": \"currency\",\n \"value\": \"KES\"\n },\n {\n \"key\": \"memo\",\n \"value\": \"24322607\"\n },\n {\n \"key\": \"wallet_name\",\n \"value\": \"254797668592\"\n }\n ]\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{ChannelHostName}}/accounts/validate/MSISDN/27710101999?amsName=paygops", + "host": [ + "{{ChannelHostName}}" + ], + "path": [ + "accounts", + "validate", + "MSISDN", + "27710101999" + ], + "query": [ + { + "key": "amsName", + "value": "paygops" + } + ] + } + }, + "response": [ + { + "name": "Account Status", + "originalRequest": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"primaryIdentifier\": {\n \"key\": \"foundationalID\",\n \"value\": \"24322607\"\n },\n \"secondaryIdentifier\": {\n \"key\": \"MSISDN\",\n \"value\": \"254797668592\"\n },\n \"customData\": [\n {\n \"key\": \"transactionId\",\n \"value\": \"670d65bd-4efd-4a6c-ae2c-7fdaa8cb4d60\"\n },\n {\n \"key\": \"currency\",\n \"value\": \"KES\"\n },\n {\n \"key\": \"memo\",\n \"value\": \"24322607\"\n },\n {\n \"key\": \"wallet_name\",\n \"value\": \"254797668592\"\n }\n ]\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "http://localhost:5001/accounts/validate/MSISDN/27710101999?amsName=paygops", + "protocol": "http", + "host": [ + "localhost" + ], + "port": "5001", + "path": [ + "accounts", + "validate", + "MSISDN", + "27710101999" + ], + "query": [ + { + "key": "amsName", + "value": "paygops" + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "CF-RAY", + "value": "758709c23f5f94c2-CCU" + }, + { + "key": "Accept-Encoding", + "value": "gzip,deflate" + }, + { + "key": "Server", + "value": "cloudflare" + }, + { + "key": "Report-To", + "value": "{\"endpoints\":[{\"url\":\"https:\\/\\/a.nel.cloudflare.com\\/report\\/v3?s=P4q5tTEWU4hyQUUUWS9P8r1cn1zkM%2Fiz48we7UWbflD36giC6%2FyTLto38tkB4kCSfpV4loID4lHbKPt1elsi6ABSjpepOrB6%2Fl15f%2Fvu0ladDb0YMNhcwI7IKRQ8QhEGaTBJkqVyyw4HlAs%3D\"}],\"group\":\"cf-nel\",\"max_age\":604800}" + }, + { + "key": "Date", + "value": "Tue, 11 Oct 2022 10:51:00 GMT" + }, + { + "key": "NEL", + "value": "{\"success_fraction\":0,\"report_to\":\"cf-nel\",\"max_age\":604800}" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "Authorization", + "value": "Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJTb2xhcmlzIE9mZmdyaWQiLCJleHAiOjE2ODAyNzcwNDcsImlhdCI6MTY0ODcyMDA5NSwic3ViIjo2MDUsInBlcm1pc3Npb25zIjpbIkRlbGV0ZURldmljZXMiLCJIYW5kbGVSZXZlcnNlZFBheW1lbnRzIiwiVmlld0Rhc2hib2FyZHMiLCJDaGFuZ2VQQVlHTW9kZURldmljZXMiLCJWaWV3R2xvYmFsRGFzaGJvYXJkcyIsIkVkaXRBY2NvdW50cyIsIk1hbmFnZUFsbEFjY291bnRzIiwiRm9yY2VQQVlHTW9kZURldmljZXMiLCJHb2dsYURhc2hib2FyZHMiLCJXaXRoTWVWaWV3U3RvY2siLCJEb3dubG9hZEdsb2JhbEFjY291bnRzIiwiRGVsZXRlUGhvbmVOdW1iZXJzIiwiTWFuYWdlQWNjb3VudHMiLCJXaXRoQ2xpZW50c1ZpZXdTdG9jayIsIkxpc3RQb3J0Zm9saW9zIiwiT3JwaGFuZWRWaWV3U3RvY2siLCJWaWV3UG9ydGZvbGlvcyIsIkVkaXRNYWRlVHJhbnNmZXJzIiwiRnJvbU9ycGhhbmVkTW92ZVN0b2NrIiwiUmVxdWVzdFRyYW5zZmVycyIsIkVkaXRQb3J0Zm9saW9zIiwiRGVsZXRlUG9ydGZvbGlvcyIsIkFwcHJvdmVUcmFuc2ZlcnMiLCJGcm9tV2l0aE1lTW92ZVN0b2NrIiwiQ3JlYXRlUG9ydGZvbGlvcyIsIkNvbmZpcm1UcmFuc2ZlcnMiLCJUb09ycGhhbmVkTW92ZVN0b2NrIiwiVG9XaXRoTWVNb3ZlU3RvY2siLCJWaWV3VHJhbnNmZXJzIiwiQXBwcm92ZUFkZE9ucyIsIlZpZXdTZXR0aW5nc0ludGVyZmFjZUFkbWluIiwiRGVsZXRlVHJhbnNmZXJzIiwiRWRpdFBsYW5uZWREZWxpdmVyeURhdGVMZWFkcyIsIkNyZWF0ZUFQSVRva2VuQWRtaW4iLCJWaWV3QmFkZ2VUcmFuc2ZlcnMiLCJDb25maWd1cmVNb2JpbGVBcHBTZXR0aW5nc0FkbWluIiwiU3luY0NvbXBsZXRlZENsaWVudHNNb2JpbGUiLCJWaWV3QWN0aXZpdHlMb2dBZG1pbiIsIlZpZXdFeHBlbnNlcyIsIkFkZEV4cGVuc2VzIiwiRXhwb3J0RGF0YUFkbWluIiwiRWRpdE9mZmVyUGFydGlhbGx5UGFpZExlYWRzIiwiRWRpdEV4cGVuc2VzIiwiRWRpdE9mZmVyQXdhaXRpbmdEZWxpdmVyeUxlYWRzIiwiRWRpdE93bkV4cGVuc2VzIiwiQ29uZmlndXJlQXV0b21hdGVkTWVzc2FnZXNBZG1pbiIsIlN5bmNMZWFkc01vYmlsZSIsIkNvbmZpZ3VyZVNhbGVzTWFuYWdlbWVudEFkbWluIiwiRWRpdE90aGVyc0V4cGVuc2VzIiwiUmVtb3ZlTGFzdFBob25lTnVtYmVycyIsIkNvbmZpZ3VyZVBheW1lbnRNYW5hZ2VtZW50QWRtaW4iLCJFZGl0QW1vdW50RXhwZW5zZXMiLCJEZWxldGVFeHBlbnNlcyIsIkNvbmZpZ3VyZUxvY2FsU2V0dGluZ3NBZG1pbiIsIkZpbGxDdXN0b21Gb3Jtc0NsaWVudHMiLCJBZGRWaWxsYWdlcyIsIkNvbmZpZ3VyZUdlbmVyYWxTZXR0aW5nc0FkbWluIiwiQWRkVG9Db250cmFjdEFkZE9ucyIsIkNvbmZpZ3VyZUxhbmd1YWdlU2V0dGluZ3NBZG1pbiIsIkVkaXRWaWxsYWdlcyIsIlN5bmNBY3RpdmF0aW9uQWN0aW9ucyIsIkVkaXRDdXN0b21TTVNBZG1pbiIsIkRlbGV0ZVZpbGxhZ2VzIiwiRmlsbEN1c3RvbUZvcm1zTGVhZHMiLCJWaWV3U2hvcHMiLCJDdXN0b21pemVQbGF0Zm9ybUFkbWluIiwiQWRkQ2x1c3RlcnMiLCJTZWVBbGxOb3RpZmljYXRpb25zQWRtaW4iLCJTZWVIdWJOb3RpZmljYXRpb25zQWRtaW4iLCJFZGl0Q2x1c3RlcnMiLCJWaWV3T2ZmZXJzIiwiVmlld0FjY291bnRzIiwiVmlld093blVzZXJzIiwiRWRpdFVzZXJzIiwiQWRkT2ZmZXJzIiwiRWRpdE9mZmVycyIsIkFkZFVzZXJzIiwiQWRkSHVicyIsIkVkaXRIdWJzIiwiVmlld0FkZG9uT2ZmZXJzIiwiQ3JlYXRlUm9sZXMiLCJEZWxldGVIdWJzIiwiQWRkQWRkb25PZmZlcnMiLCJBc3NpZ25Sb2xlcyIsIkFkZERldmljZXMiLCJFZGl0QWRkb25PZmZlcnMiLCJBZGRab25lcyIsIlZpZXdMb2dzIiwiVmlld0xlYWRHZW5lcmF0b3JzIiwiRWRpdFpvbmVzIiwiU2V0Q29tbWlzc2lvbkxlYWRzIiwiVmlld0ZhdWx0c0xvZ3MiLCJEZWxldGVab25lcyIsIlZpZXdVc2VycyIsIkFkZE1lc3NhZ2VzIiwiVmlld0xlYWRzIiwiQWRkUmVnaW9ucyIsIkFwcHJvdmVMZWFkcyIsIkFkZE1hbnVhbE1lc3NhZ2VzIiwiRWRpdFJlZ2lvbnMiLCJWaWV3QWxsTWVzc2FnZXMiLCJEZWxldGVSZWdpb25zIiwiVmlld01lc3NhZ2VzIiwiQWRkQ2xpZW50R3JvdXBzIiwiVmlld09ycGhhbmVkTWVzc2FnZXMiLCJFZGl0Q2xpZW50R3JvdXBzIiwiQWRkT3V0Z29pbmdNZXNzYWdlcyIsIkFkZExlYWRzIiwiRGVsZXRlQ2xpZW50R3JvdXBzIiwiVmlld0JhZGdlTGVhZHMiLCJBZGRBUElIb29rIiwiSW5TdG9ja1ZpZXdTdG9jayIsIldpdGhVc2Vyc1ZpZXdTdG9jayIsIkRlbGV0ZUFQSUhvb2siLCJGcm9tSW5TdG9ja01vdmVTdG9jayIsIlZpZXdGb3JtcyIsIkZyb21Vc2Vyc01vdmVTdG9jayIsIkFkZEZvcm1zIiwiVG9JblN0b2NrTW92ZVN0b2NrIiwiR2l2ZUNvbW1pc3Npb25Ub0xlYWRHZW5lcmF0b3JzIiwiRWRpdEZvcm1zIiwiRGVsZXRlRm9ybXMiLCJFZGl0Q2xpZW50cyIsIlRvVXNlcnNNb3ZlU3RvY2siLCJWaWV3SXNzdWVzIiwiQWRkSXNzdWVzIiwiRWRpdEludGVyYWN0aW9uc1NldHRpbmdzRm9ybXMiLCJDb25maWd1cmVPcGVyYXRpb25hbEVudGl0aWVzQWRtaW4iLCJWaWV3Q2xpZW50cyIsIkVkaXRJc3N1ZXMiLCJFZGl0Q2xpZW50TGVhZERhdGFTZXR0aW5nc0Zvcm1zIiwiQ29uZmlndXJlRGV2aWNlQVBJQWRtaW4iLCJNYWtlT25TdG9ja091dHNpZGVWaWV3QWN0aW9ucyIsIlZpZXdJbnRlcmFjdGlvbnMiLCJWaWV3QWN0aW9ucyIsIkFkZEludGVyYWN0aW9ucyIsIlN5bmNBbGxDcmVhdGVkTGVhZHNNb2JpbGUiLCJEb0NoYW5nZU9mZmVyQWN0aW9ucyIsIkVkaXRJbnRlcmFjdGlvbnMiLCJTeW5jQWxsR2VuZXJhdGVkTGVhZHNNb2JpbGUiLCJEZVJlZ2lzdGVyQWN0aW9ucyIsIkRlbGV0ZUludGVyYWN0aW9ucyIsIlN5bmNJbnN0YWxsZWRMYXN0MldlZWtzTGVhZHNNb2JpbGUiLCJWaWV3UGxhbm5pbmciLCJHaXZlRGlzY291bnRBY3Rpb25zIiwiU3luY0luc3RhbGxlZExhc3QyTW9udGhzTGVhZHNNb2JpbGUiLCJWaWV3Q3JlYXRlZExlYWRzIiwiR2l2ZURpc2NvdW50T3ZlcjJEYXlzQWN0aW9ucyIsIkFkZFBsYW5uaW5nIiwiU3luY0xlYWRHZW5lcmF0b3JzTW9iaWxlIiwiRWRpdFBsYW5uaW5nIiwiUmVnaXN0ZXJBY3Rpb25zIiwiTWVyZ2VMZWFkR2VuZXJhdG9ycyIsIlN5bmNDbGllbnRzTW9iaWxlIiwiRWRpdExlYWRzIiwiQ29sbGVjdENhc2hBY3Rpb25zIiwiRGVsZXRlUGxhbm5pbmciLCJTeW5jQWxsQ3JlYXRlZENsaWVudHNNb2JpbGUiLCJTd2FwRGV2aWNlQWN0aW9ucyIsIkVkaXRMZWFkR2VuZXJhdG9ycyIsIlZpZXdQYXltZW50cyIsIlN5bmNBbGxHZW5lcmF0ZWRDbGllbnRzTW9iaWxlIiwiVmlld09ycGhhbmVkUGF5bWVudHMiLCJHaXZlRGVsYXlBY3Rpb25zIiwiU3luY0ludGVyYWN0aW9uc01vYmlsZSIsIkFkZFBheW1lbnRzIiwiR2l2ZURlbGF5T3ZlcjJEYXlzQWN0aW9ucyIsIlN5bmNQbGFubmluZ01vYmlsZSIsIkFkZExlYWRHZW5lcmF0b3JzIiwiR2l2ZU5lZ2F0aXZlRGlzY291bnRUb0NvbXBsZXRlZEFjdGlvbnMiLCJBZGp1c3RCYWxhbmNlUGF5bWVudHMiLCJTeW5jRGV2aWNlc01vYmlsZSIsIkVkaXRXYWxsZXRQYXltZW50cyIsIk1hcmtDb250cmFjdERlZmF1bHRlZEFjdGlvbnMiLCJWaWV3UmV2ZXJzZWRQYXltZW50cyIsIlVuZG9Db250cmFjdERlZmF1bHRlZEFjdGlvbnMiLCJFZGl0SW5zdGFsbGVkTGVhZHMiLCJWaWV3QmFkZ2VJc3N1ZXMiLCJHaXZlVG9rZW5zT2ZmbGluZUFjdGlvbnMiLCJBZGRSZXZlcnNlZFBheW1lbnRzIl19.msQFoIe1htXINxp82s2K0jEXFBE_QMdd0U5LnQzVNa4" + }, + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Content-Length", + "value": "462" + }, + { + "key": "CF-Cache-Status", + "value": "DYNAMIC" + } + ], + "cookie": [], + "body": "{\n \"transaction_id\": \"670d65bd-4efd-4a6c-ae2c-7fdaa8cb4d60\",\n \"amount\": \"1\",\n \"sender_name\": \"254797668592\",\n \"sender_phone_number\": \"+254797668592\",\n \"sent_datetime\": \"2022-10-11T10:51:00.990116Z\",\n \"memo\": \"24322607\",\n \"wallet_operator\": \"\",\n \"country\": \"\",\n \"currency\": \"KES\",\n \"warnings\": [],\n \"reconciled\": true,\n \"destinations\": [\n {\n \"destination_type\": \"contract_repayment\",\n \"destination\": \"C370015\"\n }\n ],\n \"destination_type\": \"contract_repayment\",\n \"destination\": \"C370015\"\n}" + } + ] + }, + { + "name": "Paygops Connector Account Status", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 200\", function () {", + " pm.response.to.have.status(200);", + " pm.expect(pm.response.text).not.equal(null)", + "});", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"primaryIdentifier\": {\n \"key\": \"MSISDN\",\n \"value\": \"254797668592\"\n },\n \"secondaryIdentifier\": {\n \"key\": \"foundationalID\",\n \"value\": \"24322607\"\n },\n \"customData\": [\n {\n \"key\": \"transactionId\",\n \"value\": \"670d65bd-4efd-4a6c-ae2c-7fdaa8cb4d60\"\n },\n {\n \"key\": \"currency\",\n \"value\": \"KES\"\n },\n {\n \"key\": \"memo\",\n \"value\": \"24322607\"\n },\n {\n \"key\": \"wallet_name\",\n \"value\": \"254797668592\"\n }\n ]\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{PaygopsHostName}}/api/v1/paybill/validate/paygops", + "host": [ + "{{PaygopsHostName}}" + ], + "path": [ + "api", + "v1", + "paybill", + "validate", + "paygops" + ] + } + }, + "response": [ + { + "name": "Paygops Connector Account Status", + "originalRequest": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"primaryIdentifier\": {\n \"key\": \"MSISDN\",\n \"value\": \"254797668592\"\n },\n \"secondaryIdentifier\": {\n \"key\": \"foundationalID\",\n \"value\": \"24322607\"\n },\n \"customData\": [\n {\n \"key\": \"transactionId\",\n \"value\": \"670d65bd-4efd-4a6c-ae2c-7fdaa8cb4d60\"\n },\n {\n \"key\": \"currency\",\n \"value\": \"KES\"\n },\n {\n \"key\": \"memo\",\n \"value\": \"24322607\"\n },\n {\n \"key\": \"wallet_name\",\n \"value\": \"254797668592\"\n }\n ]\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "http://0.0.0.0:5002/api/v1/paybill/validate/paygops", + "protocol": "http", + "host": [ + "0", + "0", + "0", + "0" + ], + "port": "5002", + "path": [ + "api", + "v1", + "paybill", + "validate", + "paygops" + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Encoding", + "value": "br" + }, + { + "key": "Accept", + "value": "*/*" + }, + { + "key": "Postman-Token", + "value": "f97605a6-3ba6-45df-8a42-2ff9afd46dc0" + }, + { + "key": "CF-RAY", + "value": "757f82c0bde82e9e-SIN" + }, + { + "key": "Accept-Encoding", + "value": "gzip, deflate, br" + }, + { + "key": "Server", + "value": "cloudflare" + }, + { + "key": "Report-To", + "value": "{\"endpoints\":[{\"url\":\"https:\\/\\/a.nel.cloudflare.com\\/report\\/v3?s=tHxc5Mv4DCE3%2Fcrk2eJQ4hOPWBGy7j6pZql4rw8mRWpKdc0kSSa2%2Fi5Mn18o1RZRLaJCTzAaz3bBu5TLKDvMI85KCjPoiYrVkZRkuQCwCMxesYpAWu%2BHwJbgtURlbuUy39IayqMqcV%2FhByc%3D\"}],\"group\":\"cf-nel\",\"max_age\":604800}" + }, + { + "key": "Date", + "value": "Mon, 10 Oct 2022 12:55:30 GMT" + }, + { + "key": "NEL", + "value": "{\"success_fraction\":0,\"report_to\":\"cf-nel\",\"max_age\":604800}" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "Authorization", + "value": "Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJTb2xhcmlzIE9mZmdyaWQiLCJleHAiOjE2ODAyNzcwNDcsImlhdCI6MTY0ODcyMDA5NSwic3ViIjo2MDUsInBlcm1pc3Npb25zIjpbIkRlbGV0ZURldmljZXMiLCJIYW5kbGVSZXZlcnNlZFBheW1lbnRzIiwiVmlld0Rhc2hib2FyZHMiLCJDaGFuZ2VQQVlHTW9kZURldmljZXMiLCJWaWV3R2xvYmFsRGFzaGJvYXJkcyIsIkVkaXRBY2NvdW50cyIsIk1hbmFnZUFsbEFjY291bnRzIiwiRm9yY2VQQVlHTW9kZURldmljZXMiLCJHb2dsYURhc2hib2FyZHMiLCJXaXRoTWVWaWV3U3RvY2siLCJEb3dubG9hZEdsb2JhbEFjY291bnRzIiwiRGVsZXRlUGhvbmVOdW1iZXJzIiwiTWFuYWdlQWNjb3VudHMiLCJXaXRoQ2xpZW50c1ZpZXdTdG9jayIsIkxpc3RQb3J0Zm9saW9zIiwiT3JwaGFuZWRWaWV3U3RvY2siLCJWaWV3UG9ydGZvbGlvcyIsIkVkaXRNYWRlVHJhbnNmZXJzIiwiRnJvbU9ycGhhbmVkTW92ZVN0b2NrIiwiUmVxdWVzdFRyYW5zZmVycyIsIkVkaXRQb3J0Zm9saW9zIiwiRGVsZXRlUG9ydGZvbGlvcyIsIkFwcHJvdmVUcmFuc2ZlcnMiLCJGcm9tV2l0aE1lTW92ZVN0b2NrIiwiQ3JlYXRlUG9ydGZvbGlvcyIsIkNvbmZpcm1UcmFuc2ZlcnMiLCJUb09ycGhhbmVkTW92ZVN0b2NrIiwiVG9XaXRoTWVNb3ZlU3RvY2siLCJWaWV3VHJhbnNmZXJzIiwiQXBwcm92ZUFkZE9ucyIsIlZpZXdTZXR0aW5nc0ludGVyZmFjZUFkbWluIiwiRGVsZXRlVHJhbnNmZXJzIiwiRWRpdFBsYW5uZWREZWxpdmVyeURhdGVMZWFkcyIsIkNyZWF0ZUFQSVRva2VuQWRtaW4iLCJWaWV3QmFkZ2VUcmFuc2ZlcnMiLCJDb25maWd1cmVNb2JpbGVBcHBTZXR0aW5nc0FkbWluIiwiU3luY0NvbXBsZXRlZENsaWVudHNNb2JpbGUiLCJWaWV3QWN0aXZpdHlMb2dBZG1pbiIsIlZpZXdFeHBlbnNlcyIsIkFkZEV4cGVuc2VzIiwiRXhwb3J0RGF0YUFkbWluIiwiRWRpdE9mZmVyUGFydGlhbGx5UGFpZExlYWRzIiwiRWRpdEV4cGVuc2VzIiwiRWRpdE9mZmVyQXdhaXRpbmdEZWxpdmVyeUxlYWRzIiwiRWRpdE93bkV4cGVuc2VzIiwiQ29uZmlndXJlQXV0b21hdGVkTWVzc2FnZXNBZG1pbiIsIlN5bmNMZWFkc01vYmlsZSIsIkNvbmZpZ3VyZVNhbGVzTWFuYWdlbWVudEFkbWluIiwiRWRpdE90aGVyc0V4cGVuc2VzIiwiUmVtb3ZlTGFzdFBob25lTnVtYmVycyIsIkNvbmZpZ3VyZVBheW1lbnRNYW5hZ2VtZW50QWRtaW4iLCJFZGl0QW1vdW50RXhwZW5zZXMiLCJEZWxldGVFeHBlbnNlcyIsIkNvbmZpZ3VyZUxvY2FsU2V0dGluZ3NBZG1pbiIsIkZpbGxDdXN0b21Gb3Jtc0NsaWVudHMiLCJBZGRWaWxsYWdlcyIsIkNvbmZpZ3VyZUdlbmVyYWxTZXR0aW5nc0FkbWluIiwiQWRkVG9Db250cmFjdEFkZE9ucyIsIkNvbmZpZ3VyZUxhbmd1YWdlU2V0dGluZ3NBZG1pbiIsIkVkaXRWaWxsYWdlcyIsIlN5bmNBY3RpdmF0aW9uQWN0aW9ucyIsIkVkaXRDdXN0b21TTVNBZG1pbiIsIkRlbGV0ZVZpbGxhZ2VzIiwiRmlsbEN1c3RvbUZvcm1zTGVhZHMiLCJWaWV3U2hvcHMiLCJDdXN0b21pemVQbGF0Zm9ybUFkbWluIiwiQWRkQ2x1c3RlcnMiLCJTZWVBbGxOb3RpZmljYXRpb25zQWRtaW4iLCJTZWVIdWJOb3RpZmljYXRpb25zQWRtaW4iLCJFZGl0Q2x1c3RlcnMiLCJWaWV3T2ZmZXJzIiwiVmlld0FjY291bnRzIiwiVmlld093blVzZXJzIiwiRWRpdFVzZXJzIiwiQWRkT2ZmZXJzIiwiRWRpdE9mZmVycyIsIkFkZFVzZXJzIiwiQWRkSHVicyIsIkVkaXRIdWJzIiwiVmlld0FkZG9uT2ZmZXJzIiwiQ3JlYXRlUm9sZXMiLCJEZWxldGVIdWJzIiwiQWRkQWRkb25PZmZlcnMiLCJBc3NpZ25Sb2xlcyIsIkFkZERldmljZXMiLCJFZGl0QWRkb25PZmZlcnMiLCJBZGRab25lcyIsIlZpZXdMb2dzIiwiVmlld0xlYWRHZW5lcmF0b3JzIiwiRWRpdFpvbmVzIiwiU2V0Q29tbWlzc2lvbkxlYWRzIiwiVmlld0ZhdWx0c0xvZ3MiLCJEZWxldGVab25lcyIsIlZpZXdVc2VycyIsIkFkZE1lc3NhZ2VzIiwiVmlld0xlYWRzIiwiQWRkUmVnaW9ucyIsIkFwcHJvdmVMZWFkcyIsIkFkZE1hbnVhbE1lc3NhZ2VzIiwiRWRpdFJlZ2lvbnMiLCJWaWV3QWxsTWVzc2FnZXMiLCJEZWxldGVSZWdpb25zIiwiVmlld01lc3NhZ2VzIiwiQWRkQ2xpZW50R3JvdXBzIiwiVmlld09ycGhhbmVkTWVzc2FnZXMiLCJFZGl0Q2xpZW50R3JvdXBzIiwiQWRkT3V0Z29pbmdNZXNzYWdlcyIsIkFkZExlYWRzIiwiRGVsZXRlQ2xpZW50R3JvdXBzIiwiVmlld0JhZGdlTGVhZHMiLCJBZGRBUElIb29rIiwiSW5TdG9ja1ZpZXdTdG9jayIsIldpdGhVc2Vyc1ZpZXdTdG9jayIsIkRlbGV0ZUFQSUhvb2siLCJGcm9tSW5TdG9ja01vdmVTdG9jayIsIlZpZXdGb3JtcyIsIkZyb21Vc2Vyc01vdmVTdG9jayIsIkFkZEZvcm1zIiwiVG9JblN0b2NrTW92ZVN0b2NrIiwiR2l2ZUNvbW1pc3Npb25Ub0xlYWRHZW5lcmF0b3JzIiwiRWRpdEZvcm1zIiwiRGVsZXRlRm9ybXMiLCJFZGl0Q2xpZW50cyIsIlRvVXNlcnNNb3ZlU3RvY2siLCJWaWV3SXNzdWVzIiwiQWRkSXNzdWVzIiwiRWRpdEludGVyYWN0aW9uc1NldHRpbmdzRm9ybXMiLCJDb25maWd1cmVPcGVyYXRpb25hbEVudGl0aWVzQWRtaW4iLCJWaWV3Q2xpZW50cyIsIkVkaXRJc3N1ZXMiLCJFZGl0Q2xpZW50TGVhZERhdGFTZXR0aW5nc0Zvcm1zIiwiQ29uZmlndXJlRGV2aWNlQVBJQWRtaW4iLCJNYWtlT25TdG9ja091dHNpZGVWaWV3QWN0aW9ucyIsIlZpZXdJbnRlcmFjdGlvbnMiLCJWaWV3QWN0aW9ucyIsIkFkZEludGVyYWN0aW9ucyIsIlN5bmNBbGxDcmVhdGVkTGVhZHNNb2JpbGUiLCJEb0NoYW5nZU9mZmVyQWN0aW9ucyIsIkVkaXRJbnRlcmFjdGlvbnMiLCJTeW5jQWxsR2VuZXJhdGVkTGVhZHNNb2JpbGUiLCJEZVJlZ2lzdGVyQWN0aW9ucyIsIkRlbGV0ZUludGVyYWN0aW9ucyIsIlN5bmNJbnN0YWxsZWRMYXN0MldlZWtzTGVhZHNNb2JpbGUiLCJWaWV3UGxhbm5pbmciLCJHaXZlRGlzY291bnRBY3Rpb25zIiwiU3luY0luc3RhbGxlZExhc3QyTW9udGhzTGVhZHNNb2JpbGUiLCJWaWV3Q3JlYXRlZExlYWRzIiwiR2l2ZURpc2NvdW50T3ZlcjJEYXlzQWN0aW9ucyIsIkFkZFBsYW5uaW5nIiwiU3luY0xlYWRHZW5lcmF0b3JzTW9iaWxlIiwiRWRpdFBsYW5uaW5nIiwiUmVnaXN0ZXJBY3Rpb25zIiwiTWVyZ2VMZWFkR2VuZXJhdG9ycyIsIlN5bmNDbGllbnRzTW9iaWxlIiwiRWRpdExlYWRzIiwiQ29sbGVjdENhc2hBY3Rpb25zIiwiRGVsZXRlUGxhbm5pbmciLCJTeW5jQWxsQ3JlYXRlZENsaWVudHNNb2JpbGUiLCJTd2FwRGV2aWNlQWN0aW9ucyIsIkVkaXRMZWFkR2VuZXJhdG9ycyIsIlZpZXdQYXltZW50cyIsIlN5bmNBbGxHZW5lcmF0ZWRDbGllbnRzTW9iaWxlIiwiVmlld09ycGhhbmVkUGF5bWVudHMiLCJHaXZlRGVsYXlBY3Rpb25zIiwiU3luY0ludGVyYWN0aW9uc01vYmlsZSIsIkFkZFBheW1lbnRzIiwiR2l2ZURlbGF5T3ZlcjJEYXlzQWN0aW9ucyIsIlN5bmNQbGFubmluZ01vYmlsZSIsIkFkZExlYWRHZW5lcmF0b3JzIiwiR2l2ZU5lZ2F0aXZlRGlzY291bnRUb0NvbXBsZXRlZEFjdGlvbnMiLCJBZGp1c3RCYWxhbmNlUGF5bWVudHMiLCJTeW5jRGV2aWNlc01vYmlsZSIsIkVkaXRXYWxsZXRQYXltZW50cyIsIk1hcmtDb250cmFjdERlZmF1bHRlZEFjdGlvbnMiLCJWaWV3UmV2ZXJzZWRQYXltZW50cyIsIlVuZG9Db250cmFjdERlZmF1bHRlZEFjdGlvbnMiLCJFZGl0SW5zdGFsbGVkTGVhZHMiLCJWaWV3QmFkZ2VJc3N1ZXMiLCJHaXZlVG9rZW5zT2ZmbGluZUFjdGlvbnMiLCJBZGRSZXZlcnNlZFBheW1lbnRzIl19.msQFoIe1htXINxp82s2K0jEXFBE_QMdd0U5LnQzVNa4" + }, + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Content-Length", + "value": "267" + }, + { + "key": "CF-Cache-Status", + "value": "DYNAMIC" + } + ], + "cookie": [], + "body": "{\n \"transaction_id\": \"670d65bd-4efd-4a6c-ae2c-7fdaa8cb4d60\",\n \"amount\": \"1\",\n \"sender_name\": \"254797668592\",\n \"sender_phone_number\": \"+24322607\",\n \"sent_datetime\": \"2022-10-10T12:55:30.826429Z\",\n \"memo\": \"24322607\",\n \"wallet_operator\": \"\",\n \"country\": \"\",\n \"currency\": \"KES\",\n \"warnings\": [],\n \"reconciled\": true,\n \"destinations\": [\n {\n \"destination_type\": \"contract_repayment\",\n \"destination\": \"C370015\"\n }\n ],\n \"destination_type\": \"contract_repayment\",\n \"destination\": \"C370015\"\n}" + } + ] + } + ] + }, + { + "name": "Confirmation", + "item": [ + { + "name": "MPESA-Connector Confirmation Webhook", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 200\", function () {", + " pm.response.to.have.status(200);", + " pm.expect(pm.response.text).not.equal(null)", + "});", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"TransactionType\":\"Pay Bill\",\n \"TransID\":\"RKTQDM7W6S\",\n \"TransTime\":\"20191122063845\",\n \"TransAmount\":\"10\",\n \"BusinessShortCode\":\"600638\",\n \"BillRefNumber\":\"A123\",\n \"InvoiceNumber\":\"\",\n \"OrgAccountBalance\":\"49197.00\",\n \"ThirdPartyTransID\":\"\",\n \"MSISDN\":\"254797668592\",\n \"FirstName\":\"John\"\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{MPesaHostName}}/confirmation?amsName=paygops", + "host": [ + "{{MPesaHostName}}" + ], + "path": [ + "confirmation" + ], + "query": [ + { + "key": "amsName", + "value": "paygops" + } + ] + } + }, + "response": [ + { + "name": "MPESA-Connector Confirm", + "originalRequest": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"TransactionType\":\"Pay Bill\",\n \"TransID\":\"RKTQDM7W6S\",\n \"TransTime\":\"20191122063845\",\n \"TransAmount\":\"10\",\n \"BusinessShortCode\":\"600638\",\n \"BillRefNumber\":\"A123\",\n \"InvoiceNumber\":\"\",\n \"OrgAccountBalance\":\"49197.00\",\n \"ThirdPartyTransID\":\"\",\n \"MSISDN\":\"254797668592\",\n \"FirstName\":\"John\"\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "http://localhost:5000/confirmation?amsName=paygops", + "protocol": "http", + "host": [ + "localhost" + ], + "port": "5000", + "path": [ + "confirmation" + ], + "query": [ + { + "key": "amsName", + "value": "paygops" + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Accept", + "value": "*/*" + }, + { + "key": "Postman-Token", + "value": "eaf71f3f-8df9-438c-8c1e-83de61a14869" + }, + { + "key": "amsName", + "value": "paygops" + }, + { + "key": "CF-RAY", + "value": "75454b29fe9a7a30-PAT" + }, + { + "key": "Accept-Encoding", + "value": "gzip,deflate" + }, + { + "key": "Server", + "value": "cloudflare" + }, + { + "key": "Report-To", + "value": "{\"endpoints\":[{\"url\":\"https:\\/\\/a.nel.cloudflare.com\\/report\\/v3?s=yaiqIcUbSawf20xEQ%2BlJI0IS4uNQxbZu3ggoJn5ps1Y71V%2BUrFvQe7oYFBq9iGHMOdMZLKKoPLx08ACvP6HAwATCTK%2BXrW5%2BkhUTtjd5EKoe0SrMqQVBSLqY8ZAhO8EHlEVCCCgVk3sbn70%3D\"}],\"group\":\"cf-nel\",\"max_age\":604800}" + }, + { + "key": "Date", + "value": "Mon, 03 Oct 2022 11:21:19 GMT" + }, + { + "key": "NEL", + "value": "{\"success_fraction\":0,\"report_to\":\"cf-nel\",\"max_age\":604800}" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "Authorization", + "value": "Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJTb2xhcmlzIE9mZmdyaWQiLCJleHAiOjE2ODAyNzcwNDcsImlhdCI6MTY0ODcyMDA5NSwic3ViIjo2MDUsInBlcm1pc3Npb25zIjpbIkRlbGV0ZURldmljZXMiLCJIYW5kbGVSZXZlcnNlZFBheW1lbnRzIiwiVmlld0Rhc2hib2FyZHMiLCJDaGFuZ2VQQVlHTW9kZURldmljZXMiLCJWaWV3R2xvYmFsRGFzaGJvYXJkcyIsIkVkaXRBY2NvdW50cyIsIk1hbmFnZUFsbEFjY291bnRzIiwiRm9yY2VQQVlHTW9kZURldmljZXMiLCJHb2dsYURhc2hib2FyZHMiLCJXaXRoTWVWaWV3U3RvY2siLCJEb3dubG9hZEdsb2JhbEFjY291bnRzIiwiRGVsZXRlUGhvbmVOdW1iZXJzIiwiTWFuYWdlQWNjb3VudHMiLCJXaXRoQ2xpZW50c1ZpZXdTdG9jayIsIkxpc3RQb3J0Zm9saW9zIiwiT3JwaGFuZWRWaWV3U3RvY2siLCJWaWV3UG9ydGZvbGlvcyIsIkVkaXRNYWRlVHJhbnNmZXJzIiwiRnJvbU9ycGhhbmVkTW92ZVN0b2NrIiwiUmVxdWVzdFRyYW5zZmVycyIsIkVkaXRQb3J0Zm9saW9zIiwiRGVsZXRlUG9ydGZvbGlvcyIsIkFwcHJvdmVUcmFuc2ZlcnMiLCJGcm9tV2l0aE1lTW92ZVN0b2NrIiwiQ3JlYXRlUG9ydGZvbGlvcyIsIkNvbmZpcm1UcmFuc2ZlcnMiLCJUb09ycGhhbmVkTW92ZVN0b2NrIiwiVG9XaXRoTWVNb3ZlU3RvY2siLCJWaWV3VHJhbnNmZXJzIiwiQXBwcm92ZUFkZE9ucyIsIlZpZXdTZXR0aW5nc0ludGVyZmFjZUFkbWluIiwiRGVsZXRlVHJhbnNmZXJzIiwiRWRpdFBsYW5uZWREZWxpdmVyeURhdGVMZWFkcyIsIkNyZWF0ZUFQSVRva2VuQWRtaW4iLCJWaWV3QmFkZ2VUcmFuc2ZlcnMiLCJDb25maWd1cmVNb2JpbGVBcHBTZXR0aW5nc0FkbWluIiwiU3luY0NvbXBsZXRlZENsaWVudHNNb2JpbGUiLCJWaWV3QWN0aXZpdHlMb2dBZG1pbiIsIlZpZXdFeHBlbnNlcyIsIkFkZEV4cGVuc2VzIiwiRXhwb3J0RGF0YUFkbWluIiwiRWRpdE9mZmVyUGFydGlhbGx5UGFpZExlYWRzIiwiRWRpdEV4cGVuc2VzIiwiRWRpdE9mZmVyQXdhaXRpbmdEZWxpdmVyeUxlYWRzIiwiRWRpdE93bkV4cGVuc2VzIiwiQ29uZmlndXJlQXV0b21hdGVkTWVzc2FnZXNBZG1pbiIsIlN5bmNMZWFkc01vYmlsZSIsIkNvbmZpZ3VyZVNhbGVzTWFuYWdlbWVudEFkbWluIiwiRWRpdE90aGVyc0V4cGVuc2VzIiwiUmVtb3ZlTGFzdFBob25lTnVtYmVycyIsIkNvbmZpZ3VyZVBheW1lbnRNYW5hZ2VtZW50QWRtaW4iLCJFZGl0QW1vdW50RXhwZW5zZXMiLCJEZWxldGVFeHBlbnNlcyIsIkNvbmZpZ3VyZUxvY2FsU2V0dGluZ3NBZG1pbiIsIkZpbGxDdXN0b21Gb3Jtc0NsaWVudHMiLCJBZGRWaWxsYWdlcyIsIkNvbmZpZ3VyZUdlbmVyYWxTZXR0aW5nc0FkbWluIiwiQWRkVG9Db250cmFjdEFkZE9ucyIsIkNvbmZpZ3VyZUxhbmd1YWdlU2V0dGluZ3NBZG1pbiIsIkVkaXRWaWxsYWdlcyIsIlN5bmNBY3RpdmF0aW9uQWN0aW9ucyIsIkVkaXRDdXN0b21TTVNBZG1pbiIsIkRlbGV0ZVZpbGxhZ2VzIiwiRmlsbEN1c3RvbUZvcm1zTGVhZHMiLCJWaWV3U2hvcHMiLCJDdXN0b21pemVQbGF0Zm9ybUFkbWluIiwiQWRkQ2x1c3RlcnMiLCJTZWVBbGxOb3RpZmljYXRpb25zQWRtaW4iLCJTZWVIdWJOb3RpZmljYXRpb25zQWRtaW4iLCJFZGl0Q2x1c3RlcnMiLCJWaWV3T2ZmZXJzIiwiVmlld0FjY291bnRzIiwiVmlld093blVzZXJzIiwiRWRpdFVzZXJzIiwiQWRkT2ZmZXJzIiwiRWRpdE9mZmVycyIsIkFkZFVzZXJzIiwiQWRkSHVicyIsIkVkaXRIdWJzIiwiVmlld0FkZG9uT2ZmZXJzIiwiQ3JlYXRlUm9sZXMiLCJEZWxldGVIdWJzIiwiQWRkQWRkb25PZmZlcnMiLCJBc3NpZ25Sb2xlcyIsIkFkZERldmljZXMiLCJFZGl0QWRkb25PZmZlcnMiLCJBZGRab25lcyIsIlZpZXdMb2dzIiwiVmlld0xlYWRHZW5lcmF0b3JzIiwiRWRpdFpvbmVzIiwiU2V0Q29tbWlzc2lvbkxlYWRzIiwiVmlld0ZhdWx0c0xvZ3MiLCJEZWxldGVab25lcyIsIlZpZXdVc2VycyIsIkFkZE1lc3NhZ2VzIiwiVmlld0xlYWRzIiwiQWRkUmVnaW9ucyIsIkFwcHJvdmVMZWFkcyIsIkFkZE1hbnVhbE1lc3NhZ2VzIiwiRWRpdFJlZ2lvbnMiLCJWaWV3QWxsTWVzc2FnZXMiLCJEZWxldGVSZWdpb25zIiwiVmlld01lc3NhZ2VzIiwiQWRkQ2xpZW50R3JvdXBzIiwiVmlld09ycGhhbmVkTWVzc2FnZXMiLCJFZGl0Q2xpZW50R3JvdXBzIiwiQWRkT3V0Z29pbmdNZXNzYWdlcyIsIkFkZExlYWRzIiwiRGVsZXRlQ2xpZW50R3JvdXBzIiwiVmlld0JhZGdlTGVhZHMiLCJBZGRBUElIb29rIiwiSW5TdG9ja1ZpZXdTdG9jayIsIldpdGhVc2Vyc1ZpZXdTdG9jayIsIkRlbGV0ZUFQSUhvb2siLCJGcm9tSW5TdG9ja01vdmVTdG9jayIsIlZpZXdGb3JtcyIsIkZyb21Vc2Vyc01vdmVTdG9jayIsIkFkZEZvcm1zIiwiVG9JblN0b2NrTW92ZVN0b2NrIiwiR2l2ZUNvbW1pc3Npb25Ub0xlYWRHZW5lcmF0b3JzIiwiRWRpdEZvcm1zIiwiRGVsZXRlRm9ybXMiLCJFZGl0Q2xpZW50cyIsIlRvVXNlcnNNb3ZlU3RvY2siLCJWaWV3SXNzdWVzIiwiQWRkSXNzdWVzIiwiRWRpdEludGVyYWN0aW9uc1NldHRpbmdzRm9ybXMiLCJDb25maWd1cmVPcGVyYXRpb25hbEVudGl0aWVzQWRtaW4iLCJWaWV3Q2xpZW50cyIsIkVkaXRJc3N1ZXMiLCJFZGl0Q2xpZW50TGVhZERhdGFTZXR0aW5nc0Zvcm1zIiwiQ29uZmlndXJlRGV2aWNlQVBJQWRtaW4iLCJNYWtlT25TdG9ja091dHNpZGVWaWV3QWN0aW9ucyIsIlZpZXdJbnRlcmFjdGlvbnMiLCJWaWV3QWN0aW9ucyIsIkFkZEludGVyYWN0aW9ucyIsIlN5bmNBbGxDcmVhdGVkTGVhZHNNb2JpbGUiLCJEb0NoYW5nZU9mZmVyQWN0aW9ucyIsIkVkaXRJbnRlcmFjdGlvbnMiLCJTeW5jQWxsR2VuZXJhdGVkTGVhZHNNb2JpbGUiLCJEZVJlZ2lzdGVyQWN0aW9ucyIsIkRlbGV0ZUludGVyYWN0aW9ucyIsIlN5bmNJbnN0YWxsZWRMYXN0MldlZWtzTGVhZHNNb2JpbGUiLCJWaWV3UGxhbm5pbmciLCJHaXZlRGlzY291bnRBY3Rpb25zIiwiU3luY0luc3RhbGxlZExhc3QyTW9udGhzTGVhZHNNb2JpbGUiLCJWaWV3Q3JlYXRlZExlYWRzIiwiR2l2ZURpc2NvdW50T3ZlcjJEYXlzQWN0aW9ucyIsIkFkZFBsYW5uaW5nIiwiU3luY0xlYWRHZW5lcmF0b3JzTW9iaWxlIiwiRWRpdFBsYW5uaW5nIiwiUmVnaXN0ZXJBY3Rpb25zIiwiTWVyZ2VMZWFkR2VuZXJhdG9ycyIsIlN5bmNDbGllbnRzTW9iaWxlIiwiRWRpdExlYWRzIiwiQ29sbGVjdENhc2hBY3Rpb25zIiwiRGVsZXRlUGxhbm5pbmciLCJTeW5jQWxsQ3JlYXRlZENsaWVudHNNb2JpbGUiLCJTd2FwRGV2aWNlQWN0aW9ucyIsIkVkaXRMZWFkR2VuZXJhdG9ycyIsIlZpZXdQYXltZW50cyIsIlN5bmNBbGxHZW5lcmF0ZWRDbGllbnRzTW9iaWxlIiwiVmlld09ycGhhbmVkUGF5bWVudHMiLCJHaXZlRGVsYXlBY3Rpb25zIiwiU3luY0ludGVyYWN0aW9uc01vYmlsZSIsIkFkZFBheW1lbnRzIiwiR2l2ZURlbGF5T3ZlcjJEYXlzQWN0aW9ucyIsIlN5bmNQbGFubmluZ01vYmlsZSIsIkFkZExlYWRHZW5lcmF0b3JzIiwiR2l2ZU5lZ2F0aXZlRGlzY291bnRUb0NvbXBsZXRlZEFjdGlvbnMiLCJBZGp1c3RCYWxhbmNlUGF5bWVudHMiLCJTeW5jRGV2aWNlc01vYmlsZSIsIkVkaXRXYWxsZXRQYXltZW50cyIsIk1hcmtDb250cmFjdERlZmF1bHRlZEFjdGlvbnMiLCJWaWV3UmV2ZXJzZWRQYXltZW50cyIsIlVuZG9Db250cmFjdERlZmF1bHRlZEFjdGlvbnMiLCJFZGl0SW5zdGFsbGVkTGVhZHMiLCJWaWV3QmFkZ2VJc3N1ZXMiLCJHaXZlVG9rZW5zT2ZmbGluZUFjdGlvbnMiLCJBZGRSZXZlcnNlZFBheW1lbnRzIl19.msQFoIe1htXINxp82s2K0jEXFBE_QMdd0U5LnQzVNa4" + }, + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Content-Length", + "value": "393" + }, + { + "key": "CF-Cache-Status", + "value": "DYNAMIC" + } + ], + "cookie": [], + "body": "{\n \"transaction_id\": \"RKTQDM7W6S\",\n \"amount\": \"1.00\",\n \"wallet_name\": \"254797668592\",\n \"wallet_msisdn\": \"+254797668592\",\n \"sent_datetime\": \"2022-10-03T11:14:04.790513Z\",\n \"reception_datetime\": \"2022-10-03T11:14:04.796193Z\",\n \"memo\": \"A123\",\n \"wallet_operator\": \"\",\n \"country\": \"\",\n \"currency\": \"KES\",\n \"destinations\": [\n {\n \"destination_type\": \"balance\"\n }\n ],\n \"destination_type\": \"balance\",\n \"destination\": null\n}" + } + ] + }, + { + "name": "Paygops Connector Settlement", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 200\", function () {", + " pm.response.to.have.status(200);", + " pm.expect(pm.response.text).not.equal(null)", + "});", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"primaryIdentifier\": {\n \"key\": \"MSISDN\",\n \"value\": \"254797668592\"\n },\n \"secondaryIdentifier\": {\n \"key\": \"foundationalID\",\n \"value\": \"24322607\"\n },\n \"customData\": [\n {\n \"key\": \"transactionId\",\n \"value\": \"670d65bd-4efd-4a6c-ae2c-7fdaa8cb4d60\"\n },\n {\n \"key\": \"currency\",\n \"value\": \"KES\"\n },\n {\n \"key\": \"memo\",\n \"value\": \"24322607\"\n },\n {\n \"key\": \"wallet_name\",\n \"value\": \"254797668592\"\n }\n ]\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{PaygopsHostName}}/api/v1/paybill/confirm/paygops", + "host": [ + "{{PaygopsHostName}}" + ], + "path": [ + "api", + "v1", + "paybill", + "confirm", + "paygops" + ] + } + }, + "response": [ + { + "name": "Paygops Confirm", + "originalRequest": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"primaryIdentifier\": {\n \"key\": \"MSISDN\",\n \"value\": \"254797668592\"\n },\n \"secondaryIdentifier\": {\n \"key\": \"foundationalID\",\n \"value\": \"24322607\"\n },\n \"customData\": [\n {\n \"key\": \"transactionId\",\n \"value\": \"670d65bd-4efd-4a6c-ae2c-7fdaa8cb4d60\"\n },\n {\n \"key\": \"currency\",\n \"value\": \"KES\"\n },\n {\n \"key\": \"memo\",\n \"value\": \"24322607\"\n },\n {\n \"key\": \"wallet_name\",\n \"value\": \"254797668592\"\n }\n ]\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "http://0.0.0.0:5002/api/v1/paybill/confirm/paygops", + "protocol": "http", + "host": [ + "0", + "0", + "0", + "0" + ], + "port": "5002", + "path": [ + "api", + "v1", + "paybill", + "confirm", + "paygops" + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Encoding", + "value": "br" + }, + { + "key": "Accept", + "value": "*/*" + }, + { + "key": "Postman-Token", + "value": "5f8b5996-bca8-4bec-8c58-92cf23cca34f" + }, + { + "key": "CF-RAY", + "value": "754506cb68c92e8e-BOM" + }, + { + "key": "Accept-Encoding", + "value": "gzip, deflate, br" + }, + { + "key": "Server", + "value": "cloudflare" + }, + { + "key": "Report-To", + "value": "{\"endpoints\":[{\"url\":\"https:\\/\\/a.nel.cloudflare.com\\/report\\/v3?s=VdWXDm70hmcLXGwX1oiQo9a8Yebk9yLWTKW1nynBSrlGO4P0W3kVkXzKvfGS3ud%2Bes2aUb6Wj%2BAOVPOaXHXfu6xHCZMOE3MAkpA4Gb9%2BDsmWGXHnkVThxEXImV8GD8Zr0HPyDPBDioezaz0%3D\"}],\"group\":\"cf-nel\",\"max_age\":604800}" + }, + { + "key": "Date", + "value": "Mon, 03 Oct 2022 10:34:39 GMT" + }, + { + "key": "NEL", + "value": "{\"success_fraction\":0,\"report_to\":\"cf-nel\",\"max_age\":604800}" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "Authorization", + "value": "Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJTb2xhcmlzIE9mZmdyaWQiLCJleHAiOjE2ODAyNzcwNDcsImlhdCI6MTY0ODcyMDA5NSwic3ViIjo2MDUsInBlcm1pc3Npb25zIjpbIkRlbGV0ZURldmljZXMiLCJIYW5kbGVSZXZlcnNlZFBheW1lbnRzIiwiVmlld0Rhc2hib2FyZHMiLCJDaGFuZ2VQQVlHTW9kZURldmljZXMiLCJWaWV3R2xvYmFsRGFzaGJvYXJkcyIsIkVkaXRBY2NvdW50cyIsIk1hbmFnZUFsbEFjY291bnRzIiwiRm9yY2VQQVlHTW9kZURldmljZXMiLCJHb2dsYURhc2hib2FyZHMiLCJXaXRoTWVWaWV3U3RvY2siLCJEb3dubG9hZEdsb2JhbEFjY291bnRzIiwiRGVsZXRlUGhvbmVOdW1iZXJzIiwiTWFuYWdlQWNjb3VudHMiLCJXaXRoQ2xpZW50c1ZpZXdTdG9jayIsIkxpc3RQb3J0Zm9saW9zIiwiT3JwaGFuZWRWaWV3U3RvY2siLCJWaWV3UG9ydGZvbGlvcyIsIkVkaXRNYWRlVHJhbnNmZXJzIiwiRnJvbU9ycGhhbmVkTW92ZVN0b2NrIiwiUmVxdWVzdFRyYW5zZmVycyIsIkVkaXRQb3J0Zm9saW9zIiwiRGVsZXRlUG9ydGZvbGlvcyIsIkFwcHJvdmVUcmFuc2ZlcnMiLCJGcm9tV2l0aE1lTW92ZVN0b2NrIiwiQ3JlYXRlUG9ydGZvbGlvcyIsIkNvbmZpcm1UcmFuc2ZlcnMiLCJUb09ycGhhbmVkTW92ZVN0b2NrIiwiVG9XaXRoTWVNb3ZlU3RvY2siLCJWaWV3VHJhbnNmZXJzIiwiQXBwcm92ZUFkZE9ucyIsIlZpZXdTZXR0aW5nc0ludGVyZmFjZUFkbWluIiwiRGVsZXRlVHJhbnNmZXJzIiwiRWRpdFBsYW5uZWREZWxpdmVyeURhdGVMZWFkcyIsIkNyZWF0ZUFQSVRva2VuQWRtaW4iLCJWaWV3QmFkZ2VUcmFuc2ZlcnMiLCJDb25maWd1cmVNb2JpbGVBcHBTZXR0aW5nc0FkbWluIiwiU3luY0NvbXBsZXRlZENsaWVudHNNb2JpbGUiLCJWaWV3QWN0aXZpdHlMb2dBZG1pbiIsIlZpZXdFeHBlbnNlcyIsIkFkZEV4cGVuc2VzIiwiRXhwb3J0RGF0YUFkbWluIiwiRWRpdE9mZmVyUGFydGlhbGx5UGFpZExlYWRzIiwiRWRpdEV4cGVuc2VzIiwiRWRpdE9mZmVyQXdhaXRpbmdEZWxpdmVyeUxlYWRzIiwiRWRpdE93bkV4cGVuc2VzIiwiQ29uZmlndXJlQXV0b21hdGVkTWVzc2FnZXNBZG1pbiIsIlN5bmNMZWFkc01vYmlsZSIsIkNvbmZpZ3VyZVNhbGVzTWFuYWdlbWVudEFkbWluIiwiRWRpdE90aGVyc0V4cGVuc2VzIiwiUmVtb3ZlTGFzdFBob25lTnVtYmVycyIsIkNvbmZpZ3VyZVBheW1lbnRNYW5hZ2VtZW50QWRtaW4iLCJFZGl0QW1vdW50RXhwZW5zZXMiLCJEZWxldGVFeHBlbnNlcyIsIkNvbmZpZ3VyZUxvY2FsU2V0dGluZ3NBZG1pbiIsIkZpbGxDdXN0b21Gb3Jtc0NsaWVudHMiLCJBZGRWaWxsYWdlcyIsIkNvbmZpZ3VyZUdlbmVyYWxTZXR0aW5nc0FkbWluIiwiQWRkVG9Db250cmFjdEFkZE9ucyIsIkNvbmZpZ3VyZUxhbmd1YWdlU2V0dGluZ3NBZG1pbiIsIkVkaXRWaWxsYWdlcyIsIlN5bmNBY3RpdmF0aW9uQWN0aW9ucyIsIkVkaXRDdXN0b21TTVNBZG1pbiIsIkRlbGV0ZVZpbGxhZ2VzIiwiRmlsbEN1c3RvbUZvcm1zTGVhZHMiLCJWaWV3U2hvcHMiLCJDdXN0b21pemVQbGF0Zm9ybUFkbWluIiwiQWRkQ2x1c3RlcnMiLCJTZWVBbGxOb3RpZmljYXRpb25zQWRtaW4iLCJTZWVIdWJOb3RpZmljYXRpb25zQWRtaW4iLCJFZGl0Q2x1c3RlcnMiLCJWaWV3T2ZmZXJzIiwiVmlld0FjY291bnRzIiwiVmlld093blVzZXJzIiwiRWRpdFVzZXJzIiwiQWRkT2ZmZXJzIiwiRWRpdE9mZmVycyIsIkFkZFVzZXJzIiwiQWRkSHVicyIsIkVkaXRIdWJzIiwiVmlld0FkZG9uT2ZmZXJzIiwiQ3JlYXRlUm9sZXMiLCJEZWxldGVIdWJzIiwiQWRkQWRkb25PZmZlcnMiLCJBc3NpZ25Sb2xlcyIsIkFkZERldmljZXMiLCJFZGl0QWRkb25PZmZlcnMiLCJBZGRab25lcyIsIlZpZXdMb2dzIiwiVmlld0xlYWRHZW5lcmF0b3JzIiwiRWRpdFpvbmVzIiwiU2V0Q29tbWlzc2lvbkxlYWRzIiwiVmlld0ZhdWx0c0xvZ3MiLCJEZWxldGVab25lcyIsIlZpZXdVc2VycyIsIkFkZE1lc3NhZ2VzIiwiVmlld0xlYWRzIiwiQWRkUmVnaW9ucyIsIkFwcHJvdmVMZWFkcyIsIkFkZE1hbnVhbE1lc3NhZ2VzIiwiRWRpdFJlZ2lvbnMiLCJWaWV3QWxsTWVzc2FnZXMiLCJEZWxldGVSZWdpb25zIiwiVmlld01lc3NhZ2VzIiwiQWRkQ2xpZW50R3JvdXBzIiwiVmlld09ycGhhbmVkTWVzc2FnZXMiLCJFZGl0Q2xpZW50R3JvdXBzIiwiQWRkT3V0Z29pbmdNZXNzYWdlcyIsIkFkZExlYWRzIiwiRGVsZXRlQ2xpZW50R3JvdXBzIiwiVmlld0JhZGdlTGVhZHMiLCJBZGRBUElIb29rIiwiSW5TdG9ja1ZpZXdTdG9jayIsIldpdGhVc2Vyc1ZpZXdTdG9jayIsIkRlbGV0ZUFQSUhvb2siLCJGcm9tSW5TdG9ja01vdmVTdG9jayIsIlZpZXdGb3JtcyIsIkZyb21Vc2Vyc01vdmVTdG9jayIsIkFkZEZvcm1zIiwiVG9JblN0b2NrTW92ZVN0b2NrIiwiR2l2ZUNvbW1pc3Npb25Ub0xlYWRHZW5lcmF0b3JzIiwiRWRpdEZvcm1zIiwiRGVsZXRlRm9ybXMiLCJFZGl0Q2xpZW50cyIsIlRvVXNlcnNNb3ZlU3RvY2siLCJWaWV3SXNzdWVzIiwiQWRkSXNzdWVzIiwiRWRpdEludGVyYWN0aW9uc1NldHRpbmdzRm9ybXMiLCJDb25maWd1cmVPcGVyYXRpb25hbEVudGl0aWVzQWRtaW4iLCJWaWV3Q2xpZW50cyIsIkVkaXRJc3N1ZXMiLCJFZGl0Q2xpZW50TGVhZERhdGFTZXR0aW5nc0Zvcm1zIiwiQ29uZmlndXJlRGV2aWNlQVBJQWRtaW4iLCJNYWtlT25TdG9ja091dHNpZGVWaWV3QWN0aW9ucyIsIlZpZXdJbnRlcmFjdGlvbnMiLCJWaWV3QWN0aW9ucyIsIkFkZEludGVyYWN0aW9ucyIsIlN5bmNBbGxDcmVhdGVkTGVhZHNNb2JpbGUiLCJEb0NoYW5nZU9mZmVyQWN0aW9ucyIsIkVkaXRJbnRlcmFjdGlvbnMiLCJTeW5jQWxsR2VuZXJhdGVkTGVhZHNNb2JpbGUiLCJEZVJlZ2lzdGVyQWN0aW9ucyIsIkRlbGV0ZUludGVyYWN0aW9ucyIsIlN5bmNJbnN0YWxsZWRMYXN0MldlZWtzTGVhZHNNb2JpbGUiLCJWaWV3UGxhbm5pbmciLCJHaXZlRGlzY291bnRBY3Rpb25zIiwiU3luY0luc3RhbGxlZExhc3QyTW9udGhzTGVhZHNNb2JpbGUiLCJWaWV3Q3JlYXRlZExlYWRzIiwiR2l2ZURpc2NvdW50T3ZlcjJEYXlzQWN0aW9ucyIsIkFkZFBsYW5uaW5nIiwiU3luY0xlYWRHZW5lcmF0b3JzTW9iaWxlIiwiRWRpdFBsYW5uaW5nIiwiUmVnaXN0ZXJBY3Rpb25zIiwiTWVyZ2VMZWFkR2VuZXJhdG9ycyIsIlN5bmNDbGllbnRzTW9iaWxlIiwiRWRpdExlYWRzIiwiQ29sbGVjdENhc2hBY3Rpb25zIiwiRGVsZXRlUGxhbm5pbmciLCJTeW5jQWxsQ3JlYXRlZENsaWVudHNNb2JpbGUiLCJTd2FwRGV2aWNlQWN0aW9ucyIsIkVkaXRMZWFkR2VuZXJhdG9ycyIsIlZpZXdQYXltZW50cyIsIlN5bmNBbGxHZW5lcmF0ZWRDbGllbnRzTW9iaWxlIiwiVmlld09ycGhhbmVkUGF5bWVudHMiLCJHaXZlRGVsYXlBY3Rpb25zIiwiU3luY0ludGVyYWN0aW9uc01vYmlsZSIsIkFkZFBheW1lbnRzIiwiR2l2ZURlbGF5T3ZlcjJEYXlzQWN0aW9ucyIsIlN5bmNQbGFubmluZ01vYmlsZSIsIkFkZExlYWRHZW5lcmF0b3JzIiwiR2l2ZU5lZ2F0aXZlRGlzY291bnRUb0NvbXBsZXRlZEFjdGlvbnMiLCJBZGp1c3RCYWxhbmNlUGF5bWVudHMiLCJTeW5jRGV2aWNlc01vYmlsZSIsIkVkaXRXYWxsZXRQYXltZW50cyIsIk1hcmtDb250cmFjdERlZmF1bHRlZEFjdGlvbnMiLCJWaWV3UmV2ZXJzZWRQYXltZW50cyIsIlVuZG9Db250cmFjdERlZmF1bHRlZEFjdGlvbnMiLCJFZGl0SW5zdGFsbGVkTGVhZHMiLCJWaWV3QmFkZ2VJc3N1ZXMiLCJHaXZlVG9rZW5zT2ZmbGluZUFjdGlvbnMiLCJBZGRSZXZlcnNlZFBheW1lbnRzIl19.msQFoIe1htXINxp82s2K0jEXFBE_QMdd0U5LnQzVNa4" + }, + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Content-Length", + "value": "239" + }, + { + "key": "CF-Cache-Status", + "value": "DYNAMIC" + } + ], + "cookie": [], + "body": "{\n \"transaction_id\": \"670d65bd-4efd-4a6c-ae2c-7fdaa8cb4d60\",\n \"amount\": \"1.00\",\n \"wallet_name\": \"254797668592\",\n \"wallet_msisdn\": \"+254797668592\",\n \"sent_datetime\": \"2022-10-03T10:32:25.477716Z\",\n \"reception_datetime\": \"2022-10-03T10:32:25.482215Z\",\n \"memo\": \"24322607\",\n \"wallet_operator\": \"\",\n \"country\": \"\",\n \"currency\": \"KES\",\n \"destinations\": [\n {\n \"destination_type\": \"adjustment\"\n }\n ],\n \"destination_type\": \"adjustment\",\n \"destination\": null\n}" + } + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/ph-ee-env-labs/LICENSE b/ph-ee-env-labs/LICENSE new file mode 100644 index 000000000..a612ad981 --- /dev/null +++ b/ph-ee-env-labs/LICENSE @@ -0,0 +1,373 @@ +Mozilla Public License Version 2.0 +================================== + +1. Definitions +-------------- + +1.1. "Contributor" + means each individual or legal entity that creates, contributes to + the creation of, or owns Covered Software. + +1.2. "Contributor Version" + means the combination of the Contributions of others (if any) used + by a Contributor and that particular Contributor's Contribution. + +1.3. "Contribution" + means Covered Software of a particular Contributor. + +1.4. "Covered Software" + means Source Code Form to which the initial Contributor has attached + the notice in Exhibit A, the Executable Form of such Source Code + Form, and Modifications of such Source Code Form, in each case + including portions thereof. + +1.5. "Incompatible With Secondary Licenses" + means + + (a) that the initial Contributor has attached the notice described + in Exhibit B to the Covered Software; or + + (b) that the Covered Software was made available under the terms of + version 1.1 or earlier of the License, but not also under the + terms of a Secondary License. + +1.6. "Executable Form" + means any form of the work other than Source Code Form. + +1.7. "Larger Work" + means a work that combines Covered Software with other material, in + a separate file or files, that is not Covered Software. + +1.8. "License" + means this document. + +1.9. "Licensable" + means having the right to grant, to the maximum extent possible, + whether at the time of the initial grant or subsequently, any and + all of the rights conveyed by this License. + +1.10. "Modifications" + means any of the following: + + (a) any file in Source Code Form that results from an addition to, + deletion from, or modification of the contents of Covered + Software; or + + (b) any new file in Source Code Form that contains any Covered + Software. + +1.11. "Patent Claims" of a Contributor + means any patent claim(s), including without limitation, method, + process, and apparatus claims, in any patent Licensable by such + Contributor that would be infringed, but for the grant of the + License, by the making, using, selling, offering for sale, having + made, import, or transfer of either its Contributions or its + Contributor Version. + +1.12. "Secondary License" + means either the GNU General Public License, Version 2.0, the GNU + Lesser General Public License, Version 2.1, the GNU Affero General + Public License, Version 3.0, or any later versions of those + licenses. + +1.13. "Source Code Form" + means the form of the work preferred for making modifications. + +1.14. "You" (or "Your") + means an individual or a legal entity exercising rights under this + License. For legal entities, "You" includes any entity that + controls, is controlled by, or is under common control with You. For + purposes of this definition, "control" means (a) the power, direct + or indirect, to cause the direction or management of such entity, + whether by contract or otherwise, or (b) ownership of more than + fifty percent (50%) of the outstanding shares or beneficial + ownership of such entity. + +2. License Grants and Conditions +-------------------------------- + +2.1. Grants + +Each Contributor hereby grants You a world-wide, royalty-free, +non-exclusive license: + +(a) under intellectual property rights (other than patent or trademark) + Licensable by such Contributor to use, reproduce, make available, + modify, display, perform, distribute, and otherwise exploit its + Contributions, either on an unmodified basis, with Modifications, or + as part of a Larger Work; and + +(b) under Patent Claims of such Contributor to make, use, sell, offer + for sale, have made, import, and otherwise transfer either its + Contributions or its Contributor Version. + +2.2. Effective Date + +The licenses granted in Section 2.1 with respect to any Contribution +become effective for each Contribution on the date the Contributor first +distributes such Contribution. + +2.3. Limitations on Grant Scope + +The licenses granted in this Section 2 are the only rights granted under +this License. No additional rights or licenses will be implied from the +distribution or licensing of Covered Software under this License. +Notwithstanding Section 2.1(b) above, no patent license is granted by a +Contributor: + +(a) for any code that a Contributor has removed from Covered Software; + or + +(b) for infringements caused by: (i) Your and any other third party's + modifications of Covered Software, or (ii) the combination of its + Contributions with other software (except as part of its Contributor + Version); or + +(c) under Patent Claims infringed by Covered Software in the absence of + its Contributions. + +This License does not grant any rights in the trademarks, service marks, +or logos of any Contributor (except as may be necessary to comply with +the notice requirements in Section 3.4). + +2.4. Subsequent Licenses + +No Contributor makes additional grants as a result of Your choice to +distribute the Covered Software under a subsequent version of this +License (see Section 10.2) or under the terms of a Secondary License (if +permitted under the terms of Section 3.3). + +2.5. Representation + +Each Contributor represents that the Contributor believes its +Contributions are its original creation(s) or it has sufficient rights +to grant the rights to its Contributions conveyed by this License. + +2.6. Fair Use + +This License is not intended to limit any rights You have under +applicable copyright doctrines of fair use, fair dealing, or other +equivalents. + +2.7. Conditions + +Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted +in Section 2.1. + +3. Responsibilities +------------------- + +3.1. Distribution of Source Form + +All distribution of Covered Software in Source Code Form, including any +Modifications that You create or to which You contribute, must be under +the terms of this License. You must inform recipients that the Source +Code Form of the Covered Software is governed by the terms of this +License, and how they can obtain a copy of this License. You may not +attempt to alter or restrict the recipients' rights in the Source Code +Form. + +3.2. Distribution of Executable Form + +If You distribute Covered Software in Executable Form then: + +(a) such Covered Software must also be made available in Source Code + Form, as described in Section 3.1, and You must inform recipients of + the Executable Form how they can obtain a copy of such Source Code + Form by reasonable means in a timely manner, at a charge no more + than the cost of distribution to the recipient; and + +(b) You may distribute such Executable Form under the terms of this + License, or sublicense it under different terms, provided that the + license for the Executable Form does not attempt to limit or alter + the recipients' rights in the Source Code Form under this License. + +3.3. Distribution of a Larger Work + +You may create and distribute a Larger Work under terms of Your choice, +provided that You also comply with the requirements of this License for +the Covered Software. If the Larger Work is a combination of Covered +Software with a work governed by one or more Secondary Licenses, and the +Covered Software is not Incompatible With Secondary Licenses, this +License permits You to additionally distribute such Covered Software +under the terms of such Secondary License(s), so that the recipient of +the Larger Work may, at their option, further distribute the Covered +Software under the terms of either this License or such Secondary +License(s). + +3.4. Notices + +You may not remove or alter the substance of any license notices +(including copyright notices, patent notices, disclaimers of warranty, +or limitations of liability) contained within the Source Code Form of +the Covered Software, except that You may alter any license notices to +the extent required to remedy known factual inaccuracies. + +3.5. Application of Additional Terms + +You may choose to offer, and to charge a fee for, warranty, support, +indemnity or liability obligations to one or more recipients of Covered +Software. However, You may do so only on Your own behalf, and not on +behalf of any Contributor. You must make it absolutely clear that any +such warranty, support, indemnity, or liability obligation is offered by +You alone, and You hereby agree to indemnify every Contributor for any +liability incurred by such Contributor as a result of warranty, support, +indemnity or liability terms You offer. You may include additional +disclaimers of warranty and limitations of liability specific to any +jurisdiction. + +4. Inability to Comply Due to Statute or Regulation +--------------------------------------------------- + +If it is impossible for You to comply with any of the terms of this +License with respect to some or all of the Covered Software due to +statute, judicial order, or regulation then You must: (a) comply with +the terms of this License to the maximum extent possible; and (b) +describe the limitations and the code they affect. Such description must +be placed in a text file included with all distributions of the Covered +Software under this License. Except to the extent prohibited by statute +or regulation, such description must be sufficiently detailed for a +recipient of ordinary skill to be able to understand it. + +5. Termination +-------------- + +5.1. The rights granted under this License will terminate automatically +if You fail to comply with any of its terms. However, if You become +compliant, then the rights granted under this License from a particular +Contributor are reinstated (a) provisionally, unless and until such +Contributor explicitly and finally terminates Your grants, and (b) on an +ongoing basis, if such Contributor fails to notify You of the +non-compliance by some reasonable means prior to 60 days after You have +come back into compliance. Moreover, Your grants from a particular +Contributor are reinstated on an ongoing basis if such Contributor +notifies You of the non-compliance by some reasonable means, this is the +first time You have received notice of non-compliance with this License +from such Contributor, and You become compliant prior to 30 days after +Your receipt of the notice. + +5.2. If You initiate litigation against any entity by asserting a patent +infringement claim (excluding declaratory judgment actions, +counter-claims, and cross-claims) alleging that a Contributor Version +directly or indirectly infringes any patent, then the rights granted to +You by any and all Contributors for the Covered Software under Section +2.1 of this License shall terminate. + +5.3. In the event of termination under Sections 5.1 or 5.2 above, all +end user license agreements (excluding distributors and resellers) which +have been validly granted by You or Your distributors under this License +prior to termination shall survive termination. + +************************************************************************ +* * +* 6. Disclaimer of Warranty * +* ------------------------- * +* * +* Covered Software is provided under this License on an "as is" * +* basis, without warranty of any kind, either expressed, implied, or * +* statutory, including, without limitation, warranties that the * +* Covered Software is free of defects, merchantable, fit for a * +* particular purpose or non-infringing. The entire risk as to the * +* quality and performance of the Covered Software is with You. * +* Should any Covered Software prove defective in any respect, You * +* (not any Contributor) assume the cost of any necessary servicing, * +* repair, or correction. This disclaimer of warranty constitutes an * +* essential part of this License. No use of any Covered Software is * +* authorized under this License except under this disclaimer. * +* * +************************************************************************ + +************************************************************************ +* * +* 7. Limitation of Liability * +* -------------------------- * +* * +* Under no circumstances and under no legal theory, whether tort * +* (including negligence), contract, or otherwise, shall any * +* Contributor, or anyone who distributes Covered Software as * +* permitted above, be liable to You for any direct, indirect, * +* special, incidental, or consequential damages of any character * +* including, without limitation, damages for lost profits, loss of * +* goodwill, work stoppage, computer failure or malfunction, or any * +* and all other commercial damages or losses, even if such party * +* shall have been informed of the possibility of such damages. This * +* limitation of liability shall not apply to liability for death or * +* personal injury resulting from such party's negligence to the * +* extent applicable law prohibits such limitation. Some * +* jurisdictions do not allow the exclusion or limitation of * +* incidental or consequential damages, so this exclusion and * +* limitation may not apply to You. * +* * +************************************************************************ + +8. Litigation +------------- + +Any litigation relating to this License may be brought only in the +courts of a jurisdiction where the defendant maintains its principal +place of business and such litigation shall be governed by laws of that +jurisdiction, without reference to its conflict-of-law provisions. +Nothing in this Section shall prevent a party's ability to bring +cross-claims or counter-claims. + +9. Miscellaneous +---------------- + +This License represents the complete agreement concerning the subject +matter hereof. If any provision of this License is held to be +unenforceable, such provision shall be reformed only to the extent +necessary to make it enforceable. Any law or regulation which provides +that the language of a contract shall be construed against the drafter +shall not be used to construe this License against a Contributor. + +10. Versions of the License +--------------------------- + +10.1. New Versions + +Mozilla Foundation is the license steward. Except as provided in Section +10.3, no one other than the license steward has the right to modify or +publish new versions of this License. Each version will be given a +distinguishing version number. + +10.2. Effect of New Versions + +You may distribute the Covered Software under the terms of the version +of the License under which You originally received the Covered Software, +or under the terms of any subsequent version published by the license +steward. + +10.3. Modified Versions + +If you create software not governed by this License, and you want to +create a new license for such software, you may create and use a +modified version of this License if you rename the license and remove +any references to the name of the license steward (except to note that +such modified license differs from this License). + +10.4. Distributing Source Code Form that is Incompatible With Secondary +Licenses + +If You choose to distribute Source Code Form that is Incompatible With +Secondary Licenses under the terms of this version of the License, the +notice described in Exhibit B of this License must be attached. + +Exhibit A - Source Code Form License Notice +------------------------------------------- + + This Source Code Form is subject to the terms of the Mozilla Public + License, v. 2.0. If a copy of the MPL was not distributed with this + file, You can obtain one at http://mozilla.org/MPL/2.0/. + +If it is not possible or desirable to put the notice in a particular +file, then You may include the notice in a location (such as a LICENSE +file in a relevant directory) where a recipient would be likely to look +for such a notice. + +You may add additional accurate notices of copyright ownership. + +Exhibit B - "Incompatible With Secondary Licenses" Notice +--------------------------------------------------------- + + This Source Code Form is "Incompatible With Secondary Licenses", as + defined by the Mozilla Public License, v. 2.0. diff --git a/ph-ee-env-labs/README.md b/ph-ee-env-labs/README.md new file mode 100644 index 000000000..30327778a --- /dev/null +++ b/ph-ee-env-labs/README.md @@ -0,0 +1,16 @@ +# Payment-hub-ee +Payment Hub Enterprise Edition middleware for integration to real-time payment systems. + +ph-ee-connector-ams-mifos : [Link](https://hub.docker.com/layers/shanidkh/ph-ee/ph-ee-connector-ams-mifos/images/sha256-53cacd45e87d2e24e07143f73540e8aa40b31d9f52c6ee69ebffe7bd34bc8ca2?context=repo) + +ph-ee-connector-channel : [Link](https://hub.docker.com/layers/shanidkh/ph-ee/ph-ee-connector-channel/images/sha256-34e6c6af08822fb852ba7a178be5ebc246f9b0159da9b937b1245b8b91ac863f?context=repo) + +ph-ee-connector-mojaloop-java : [Link](https://hub.docker.com/layers/shanidkh/ph-ee/ph-ee-connector-mojaloop-java/images/sha256-5728e6cbf588fb566deeb95808e534b2269b2ced7177418fdb2739ecfe89d050?context=repo) + +ph-ee-importer-rdbms : [Link](https://hub.docker.com/layers/shanidkh/ph-ee/ph-ee-importer-rdbms/images/sha256-efc1244ae4ed62ab45a4cb2da834fcb617b45f8ad8c7162af2a5954aa5b773b4?context=repo) + +ph-ee-operations-app : [Link](https://hub.docker.com/layers/shanidkh/ph-ee/ph-ee-operations-app/images/sha256-025eec7cbe4ae5c7f9875efc11f75ab90704a6430c567829b15156de83a3698d?context=repo) + +To get the image : (sudo)docker pull reponame/tagname + + diff --git a/ph-ee-env-labs/data/barebone_sql/01_create_schemas_and_tenants.sql b/ph-ee-env-labs/data/barebone_sql/01_create_schemas_and_tenants.sql new file mode 100644 index 000000000..1bb192765 --- /dev/null +++ b/ph-ee-env-labs/data/barebone_sql/01_create_schemas_and_tenants.sql @@ -0,0 +1,31 @@ +-- create basic schemas +CREATE SCHEMA IF NOT EXISTS `fineract_tenants`; +CREATE SCHEMA IF NOT EXISTS `fineract_default`; + +-- add tenant schemas +CREATE SCHEMA IF NOT EXISTS `tn03`; +CREATE SCHEMA IF NOT EXISTS `tn04`; + +-- add tenant server connections +USE `fineract_tenants`; +SET @last_connection_id = -1; + +SELECT COALESCE(max(id), 1)+1 INTO @last_connection_id FROM tenant_server_connections; +INSERT INTO `tenant_server_connections` (`id`, `schema_name`, `schema_server`, `schema_server_port`, `schema_username`, `schema_password`, `auto_update`) VALUES +(@last_connection_id, 'tn03', 'fineractmysql-dev', '3306', 'root', 'skdcnwauicn2ucnaecasdsajdnizucawencascdca', 1); + +SELECT COALESCE(max(id), 1)+1 INTO @last_connection_id FROM tenant_server_connections; +INSERT INTO `tenant_server_connections` (`id`, `schema_name`, `schema_server`, `schema_server_port`, `schema_username`, `schema_password`, `auto_update`) VALUES +(@last_connection_id, 'tn04', 'fineractmysql-dev', '3306', 'root', 'skdcnwauicn2ucnaecasdsajdnizucawencascdca', 1); + +-- add tenants +USE `fineract_tenants`; +SET @last_tenant_id = -1; +SET @last_connection_id = -1; +SELECT COALESCE(max(id), 1)+1 INTO @last_tenant_id FROM tenants; +SELECT id INTO @last_connection_id FROM tenant_server_connections where schema_name = 'tn03'; +INSERT INTO `tenants` VALUES (@last_tenant_id,'tn03','Rhino','Africa/Bujumbura',NULL,NULL,NULL,NULL, @last_connection_id, @last_connection_id); + +SELECT COALESCE(max(id), 1)+1 INTO @last_tenant_id FROM tenants; +SELECT id INTO @last_connection_id FROM tenant_server_connections where schema_name = 'tn04'; +INSERT INTO `tenants` VALUES (@last_tenant_id,'tn04','Elephant','Africa/Bujumbura',NULL,NULL,NULL,NULL, @last_connection_id, @last_connection_id); \ No newline at end of file diff --git a/ph-ee-env-labs/data/barebone_sql/02_add_interop_data.sql b/ph-ee-env-labs/data/barebone_sql/02_add_interop_data.sql new file mode 100644 index 000000000..bd5fc61a0 --- /dev/null +++ b/ph-ee-env-labs/data/barebone_sql/02_add_interop_data.sql @@ -0,0 +1,228 @@ +-- STEP 1 add interop data +USE `tn03`; + +SET @last_saving_prod_id = -1; +SELECT COALESCE(max(id), 1) into @last_saving_prod_id from m_savings_product; + +SET @saving_prod_name = concat('Saving Product', @last_saving_prod_id); + +INSERT INTO `m_savings_product` +(`name`, `short_name`, `description`, `deposit_type_enum`, `currency_code`, `currency_digits`, + `currency_multiplesof`, `nominal_annual_interest_rate`, `interest_compounding_period_enum`, + `interest_posting_period_enum`, `interest_calculation_type_enum`, `interest_calculation_days_in_year_type_enum`, + `min_required_opening_balance`, `accounting_type`, `withdrawal_fee_amount`, `withdrawal_fee_type_enum`, + `withdrawal_fee_for_transfer`, `allow_overdraft`, `min_required_balance`, `enforce_min_required_balance`, + `min_balance_for_interest_calculation`, `withhold_tax`, `tax_group_id`, `is_dormancy_tracking_active`) +VALUES (@saving_prod_name, concat('SP', @last_saving_prod_id), 'Saving Product', 100, 'TZS', 2, NULL, 0.000000, 1, + 4, 1, 360, NULL, 2, NULL, NULL, 0, 0, 0.000000, 1, NULL, 0, NULL, 0); + +SET @saving_prod_id = -1; +SELECT id INTO @saving_prod_id FROM m_savings_product WHERE name = @saving_prod_name; + +SET @payment_type_id = -1; +SELECT id INTO @payment_type_id FROM m_payment_type WHERE value = 'Money Transfer'; + +SET @saving_gl_name = 'Interoperation Saving'; +INSERT INTO `acc_gl_account` (`name`, `parent_id`, `hierarchy`, `gl_code`, `disabled`, `manual_journal_entries_allowed`, `account_usage`, `classification_enum`, `description`) +VALUES (@saving_gl_name, NULL, NULL, 'Interop_Saving', 0, 1, 1, 1, 'Interoperation Saving Asset'); -- account_usage: DETAIL, classification_enum: ASSET + +INSERT INTO `acc_product_mapping` (`gl_account_id`, `product_id`, `product_type`, `payment_type`, `charge_id`, `financial_account_type`) +VALUES ((SELECT id FROM acc_gl_account WHERE name = @saving_gl_name), @saving_prod_id, 2, @payment_type_id, NULL, 1); -- product_type: SAVING, financial_account_type: ASSET + +SET @nostro_gl_name = 'Interoperation NOSTRO'; +INSERT INTO `acc_gl_account` (`name`, `parent_id`, `hierarchy`, `gl_code`, `disabled`, `manual_journal_entries_allowed`, `account_usage`, `classification_enum`, `description`) +VALUES (@nostro_gl_name, NULL, NULL, 'Interop_Nostro', 0, 0, 1, 2, 'Interoperation NOSTRO Liability'); -- account_usage: DETAIL, classification_enum: LIABILITY + +INSERT INTO `acc_product_mapping` (`gl_account_id`, `product_id`, `product_type`, `payment_type`, `charge_id`, `financial_account_type`) +VALUES ((SELECT id FROM acc_gl_account WHERE name = @nostro_gl_name), @saving_prod_id, 2, NULL, NULL, 2); -- product_type: SAVING, financial_account_type: LIABILITY + +SET @fee_gl_name = 'Interoperation Fee'; +INSERT INTO `acc_gl_account` (`name`, `parent_id`, `hierarchy`, `gl_code`, `disabled`, `manual_journal_entries_allowed`, `account_usage`, `classification_enum`, `description`) +VALUES (@fee_gl_name, NULL, NULL, 'Interop_Fee', 0, 0, 1, 4, 'Interoperation Fee Income'); -- account_usage: DETAIL, classification_enum: INCOME + +SET @fee_gl_id = -1; +SELECT id INTO @fee_gl_id FROM acc_gl_account WHERE name = @fee_gl_name; + +INSERT INTO `acc_product_mapping` (`gl_account_id`, `product_id`, `product_type`, `payment_type`, `charge_id`, `financial_account_type`) +VALUES (@fee_gl_id, @saving_prod_id, 2, NULL, NULL, 4); -- product_type: SAVING, financial_account_type: INCOME + +SET @charge_name = 'Interoperation Withdraw Fee'; +INSERT INTO `m_charge` +(`name`,`currency_code`,`charge_applies_to_enum`,`charge_time_enum`,`charge_calculation_enum`,`charge_payment_mode_enum`, + `amount`,`fee_on_day`,`fee_interval`,`fee_on_month`,`is_penalty`,`is_active`,`is_deleted`,`min_cap`,`max_cap`,`fee_frequency`, + `income_or_liability_account_id`,`tax_group_id`) +VALUES (@charge_name, 'TZS', 2, 5, 1, NULL, 1.000000, NULL, NULL, NULL, 0, 0, 0, NULL, NULL, NULL, @fee_gl_id, NULL); + +-- STEP 2 add tn03 + +SET @client_name = 'InteropCustomer'; +SET @saving_account_no = '9062b90de19b43989005'; +SET @saving_account_ext_id = '9062b90de19b43989005d9'; +SET @IBAN = 'IC11in02tn03' + @saving_account_ext_id; +SET @MSISDN = '27710203999'; + +INSERT INTO `m_client` (`account_no`, `external_id`, `status_enum`, `sub_status`, `activation_date`, `office_joining_date`, + `office_id`, `transfer_to_office_id`, `staff_id`, `firstname`, `middlename`, `lastname`, `fullname`, + `display_name`, `mobile_no`, `gender_cv_id`, `date_of_birth`, `image_id`, `closure_reason_cv_id`, + `closedon_date`, `updated_by`, `updated_on`, `submittedon_date`, `submittedon_userid`, `activatedon_userid`, + `closedon_userid`, `default_savings_product`, `default_savings_account`, `client_type_cv_id`, `client_classification_cv_id`, + `reject_reason_cv_id`, `rejectedon_date`, `rejectedon_userid`, `withdraw_reason_cv_id`, `withdrawn_on_date`, + `withdraw_on_userid`, `reactivated_on_date`, `reactivated_on_userid`, `legal_form_enum`, `reopened_on_date`, + `reopened_by_userid`) +VALUES (@saving_account_no, NULL, 300, NULL, ADDDATE(curdate(), -100), NULL, 1, NULL, NULL, NULL, NULL, NULL, + @client_name, @client_name, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ADDDATE(curdate(), -100), + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,NULL, NULL); + +SET @last_saving_prod_id = -1; +SELECT COALESCE(max(id), 1) into @last_saving_prod_id from m_savings_product; + +SET @saving_prod_name = concat('Saving Product', @last_saving_prod_id); +SET @saving_prod_id = -1; +SELECT id INTO @saving_prod_id FROM m_savings_product WHERE name = @saving_prod_name; + +SET @client_id = -1; +SELECT id INTO @client_id FROM m_client WHERE fullname = @client_name; + +INSERT INTO `m_savings_account` +(`account_no`, `external_id`, `client_id`, `group_id`, `product_id`, `field_officer_id`, `status_enum`, + `sub_status_enum`, `account_type_enum`, `deposit_type_enum`, `submittedon_date`, `submittedon_userid`, + `approvedon_date`, `approvedon_userid`, `activatedon_date`, `activatedon_userid`, + `currency_code`, `currency_digits`, `currency_multiplesof`, `nominal_annual_interest_rate`, + `interest_compounding_period_enum`, `interest_posting_period_enum`, `interest_calculation_type_enum`, + `interest_calculation_days_in_year_type_enum`, `min_required_opening_balance`, `withdrawal_fee_for_transfer`, + `allow_overdraft`, `account_balance_derived`, `min_required_balance`, `enforce_min_required_balance`, + `version`, `withhold_tax`) +VALUES (@saving_account_no, @saving_account_ext_id, @client_id, NULL, @saving_prod_id, NULL, 300, 0, 1, 100, ADDDATE(curdate(), -100), + NULL, ADDDATE(curdate(), -100), NULL, ADDDATE(curdate(), -100), NULL, 'TZS', 2, NULL, 1.000000, 1, 4, 1, -- 29. - 4 + 360, NULL, 1, 1, 100000000.000000, 0.000000, 1, 1, 0); + +SET @saving_acc_id = -1; +SELECT id INTO @saving_acc_id FROM m_savings_account WHERE account_no = @saving_account_no; + +INSERT INTO interop_identifier (id, account_id, type, a_value, sub_value_or_type, created_by, created_on, modified_by, modified_on) +VALUES (NULL, @saving_acc_id, 'IBAN', @IBAN, NULL, 'operator', CURDATE(), 'operator', + CURDATE()); +INSERT INTO interop_identifier (id, account_id, type, a_value, sub_value_or_type, created_by, created_on, modified_by, modified_on) +VALUES (NULL, @saving_acc_id, 'MSISDN', @MSISDN, NULL, 'operator', CURDATE(), 'operator', CURDATE()); + +SET @charge_name = 'Interoperation Withdraw Fee'; + +INSERT INTO `m_savings_account_charge` (`savings_account_id`, `charge_id`, `is_penalty`, `charge_time_enum`, `charge_calculation_enum`, + `amount`, `amount_outstanding_derived`,`is_paid_derived`, `waived`, `is_active`) +VALUES (@saving_acc_id, (SELECT id FROM m_charge WHERE name = @charge_name), 0, 5, 1, 1.000000, 0.000000, 0, 0, 1); + +-- STEP 3 add interop data +USE `tn04`; + +SET @last_saving_prod_id = -1; +SELECT COALESCE(max(id), 1) into @last_saving_prod_id from m_savings_product; + +SET @saving_prod_name = concat('Saving Product', @last_saving_prod_id); + +INSERT INTO `m_savings_product` +(`name`, `short_name`, `description`, `deposit_type_enum`, `currency_code`, `currency_digits`, + `currency_multiplesof`, `nominal_annual_interest_rate`, `interest_compounding_period_enum`, + `interest_posting_period_enum`, `interest_calculation_type_enum`, `interest_calculation_days_in_year_type_enum`, + `min_required_opening_balance`, `accounting_type`, `withdrawal_fee_amount`, `withdrawal_fee_type_enum`, + `withdrawal_fee_for_transfer`, `allow_overdraft`, `min_required_balance`, `enforce_min_required_balance`, + `min_balance_for_interest_calculation`, `withhold_tax`, `tax_group_id`, `is_dormancy_tracking_active`) +VALUES (@saving_prod_name, concat('SP', @last_saving_prod_id), 'Saving Product', 100, 'TZS', 2, NULL, 0.000000, 1, + 4, 1, 360, NULL, 2, NULL, NULL, 0, 0, 0.000000, 1, NULL, 0, NULL, 0); + +SET @saving_prod_id = -1; +SELECT id INTO @saving_prod_id FROM m_savings_product WHERE name = @saving_prod_name; + +SET @payment_type_id = -1; +SELECT id INTO @payment_type_id FROM m_payment_type WHERE value = 'Money Transfer'; + +SET @saving_gl_name = 'Interoperation Saving'; +INSERT INTO `acc_gl_account` (`name`, `parent_id`, `hierarchy`, `gl_code`, `disabled`, `manual_journal_entries_allowed`, `account_usage`, `classification_enum`, `description`) +VALUES (@saving_gl_name, NULL, NULL, 'Interop_Saving', 0, 1, 1, 1, 'Interoperation Saving Asset'); -- account_usage: DETAIL, classification_enum: ASSET + +INSERT INTO `acc_product_mapping` (`gl_account_id`, `product_id`, `product_type`, `payment_type`, `charge_id`, `financial_account_type`) +VALUES ((SELECT id FROM acc_gl_account WHERE name = @saving_gl_name), @saving_prod_id, 2, @payment_type_id, NULL, 1); -- product_type: SAVING, financial_account_type: ASSET + +SET @nostro_gl_name = 'Interoperation NOSTRO'; +INSERT INTO `acc_gl_account` (`name`, `parent_id`, `hierarchy`, `gl_code`, `disabled`, `manual_journal_entries_allowed`, `account_usage`, `classification_enum`, `description`) +VALUES (@nostro_gl_name, NULL, NULL, 'Interop_Nostro', 0, 0, 1, 2, 'Interoperation NOSTRO Liability'); -- account_usage: DETAIL, classification_enum: LIABILITY + +INSERT INTO `acc_product_mapping` (`gl_account_id`, `product_id`, `product_type`, `payment_type`, `charge_id`, `financial_account_type`) +VALUES ((SELECT id FROM acc_gl_account WHERE name = @nostro_gl_name), @saving_prod_id, 2, NULL, NULL, 2); -- product_type: SAVING, financial_account_type: LIABILITY + +SET @fee_gl_name = 'Interoperation Fee'; +INSERT INTO `acc_gl_account` (`name`, `parent_id`, `hierarchy`, `gl_code`, `disabled`, `manual_journal_entries_allowed`, `account_usage`, `classification_enum`, `description`) +VALUES (@fee_gl_name, NULL, NULL, 'Interop_Fee', 0, 0, 1, 4, 'Interoperation Fee Income'); -- account_usage: DETAIL, classification_enum: INCOME + +SET @fee_gl_id = -1; +SELECT id INTO @fee_gl_id FROM acc_gl_account WHERE name = @fee_gl_name; + +INSERT INTO `acc_product_mapping` (`gl_account_id`, `product_id`, `product_type`, `payment_type`, `charge_id`, `financial_account_type`) +VALUES (@fee_gl_id, @saving_prod_id, 2, NULL, NULL, 4); -- product_type: SAVING, financial_account_type: INCOME + +SET @charge_name = 'Interoperation Withdraw Fee'; +INSERT INTO `m_charge` +(`name`,`currency_code`,`charge_applies_to_enum`,`charge_time_enum`,`charge_calculation_enum`,`charge_payment_mode_enum`, + `amount`,`fee_on_day`,`fee_interval`,`fee_on_month`,`is_penalty`,`is_active`,`is_deleted`,`min_cap`,`max_cap`,`fee_frequency`, + `income_or_liability_account_id`,`tax_group_id`) +VALUES (@charge_name, 'TZS', 2, 5, 1, NULL, 1.000000, NULL, NULL, NULL, 0, 0, 0, NULL, NULL, NULL, @fee_gl_id, NULL); + +-- STEP 3 add tn04 + +SET @client_name = 'InteropMerchant'; +SET @saving_account_no = 'a6b6c10b2aaa4778ac2f'; +SET @saving_account_ext_id = 'a6b6c10b2aaa4778ac2fc9'; +SET @IBAN = 'IC11in02tn04' + @saving_account_ext_id; +SET @MSISDN = '27710204999'; + +INSERT INTO `m_client` (`account_no`, `external_id`, `status_enum`, `sub_status`, `activation_date`, `office_joining_date`, + `office_id`, `transfer_to_office_id`, `staff_id`, `firstname`, `middlename`, `lastname`, `fullname`, + `display_name`, `mobile_no`, `gender_cv_id`, `date_of_birth`, `image_id`, `closure_reason_cv_id`, + `closedon_date`, `updated_by`, `updated_on`, `submittedon_date`, `submittedon_userid`, `activatedon_userid`, + `closedon_userid`, `default_savings_product`, `default_savings_account`, `client_type_cv_id`, `client_classification_cv_id`, + `reject_reason_cv_id`, `rejectedon_date`, `rejectedon_userid`, `withdraw_reason_cv_id`, `withdrawn_on_date`, + `withdraw_on_userid`, `reactivated_on_date`, `reactivated_on_userid`, `legal_form_enum`, `reopened_on_date`, + `reopened_by_userid`) +VALUES (@saving_account_no, NULL, 300, NULL, ADDDATE(curdate(), -100), NULL, 1, NULL, NULL, NULL, NULL, NULL, + @client_name, @client_name, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ADDDATE(curdate(), -100), + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,NULL, NULL); + +-- saving product, account +SET @last_saving_prod_id = -1; +SELECT COALESCE(max(id), 1) into @last_saving_prod_id from m_savings_product; + + +SET @saving_prod_name = concat('Saving Product', @last_saving_prod_id); +SET @saving_prod_id = -1; +SELECT id INTO @saving_prod_id FROM m_savings_product WHERE name = @saving_prod_name; + +SET @client_id = -1; +SELECT id INTO @client_id FROM m_client WHERE fullname = @client_name; + +INSERT INTO `m_savings_account` +(`account_no`, `external_id`, `client_id`, `group_id`, `product_id`, `field_officer_id`, `status_enum`, + `sub_status_enum`, `account_type_enum`, `deposit_type_enum`, `submittedon_date`, `submittedon_userid`, + `approvedon_date`, `approvedon_userid`, `activatedon_date`, `activatedon_userid`, + `currency_code`, `currency_digits`, `currency_multiplesof`, `nominal_annual_interest_rate`, + `interest_compounding_period_enum`, `interest_posting_period_enum`, `interest_calculation_type_enum`, + `interest_calculation_days_in_year_type_enum`, `min_required_opening_balance`, `withdrawal_fee_for_transfer`, + `allow_overdraft`, `account_balance_derived`, `min_required_balance`, `enforce_min_required_balance`, + `version`, `withhold_tax`) +VALUES (@saving_account_no, @saving_account_ext_id, @client_id, NULL, @saving_prod_id, NULL, 300, 0, 1, 100, ADDDATE(curdate(), -100), + NULL, ADDDATE(curdate(), -100), NULL, ADDDATE(curdate(), -100), NULL, 'TZS', 2, NULL, 1.000000, 1, 4, 1, -- 29. - 4 + 360, NULL, 1, 1, 100000000.000000, 0.000000, 1, 1, 0); + +-- interop_identifier +SET @saving_acc_id = -1; +SELECT id INTO @saving_acc_id FROM m_savings_account WHERE account_no = @saving_account_no; + +INSERT INTO interop_identifier (id, account_id, type, a_value, sub_value_or_type, created_by, created_on, modified_by, modified_on) +VALUES (NULL, @saving_acc_id, 'IBAN', @IBAN, NULL, 'operator', CURDATE(), 'operator', + CURDATE()); +INSERT INTO interop_identifier (id, account_id, type, a_value, sub_value_or_type, created_by, created_on, modified_by, modified_on) +VALUES (NULL, @saving_acc_id, 'MSISDN', @MSISDN, NULL, 'operator', CURDATE(), 'operator', CURDATE()); + +SET @charge_name = 'Interoperation Withdraw Fee'; + +INSERT INTO `m_savings_account_charge` (`savings_account_id`, `charge_id`, `is_penalty`, `charge_time_enum`, `charge_calculation_enum`, + `amount`, `amount_outstanding_derived`,`is_paid_derived`, `waived`, `is_active`) +VALUES (@saving_acc_id, (SELECT id FROM m_charge WHERE name = @charge_name), 0, 5, 1, 1.000000, 0.000000, 0, 0, 1); \ No newline at end of file diff --git a/ph-ee-env-labs/data/barebone_sql/03_add_accounts.sql b/ph-ee-env-labs/data/barebone_sql/03_add_accounts.sql new file mode 100644 index 000000000..5e7e2900c --- /dev/null +++ b/ph-ee-env-labs/data/barebone_sql/03_add_accounts.sql @@ -0,0 +1,285 @@ +USE `tn03`; + +-- loan product +SET @last_product_id = 1; +SET @last_ext_id = -1; +SELECT COALESCE(max(external_id), 1) INTO @last_ext_id FROM m_product_loan; + + +INSERT INTO `m_product_loan` VALUES +(@last_product_id, 'TZS', 2, 1, 1, + NULL, NULL, NULL, NULL, concat('Interoperation Customer Product', @last_product_id),'Demo Interoperation Product', -- 6 + NULL, b'0', b'0', 1.000000, 1.000000, + 1.000000, 3, 1.000000, 0, + 1, 1, 1, 2, 1200, + NULL,NULL, NULL, NULL, NULL, + 1, 1, 3, @last_ext_id + 1, 0, + 0,0,ADDDATE(curdate(),-100),ADDDATE(curdate(),100), 0, 0, + NULL, NULL,NULL, 1, 30, + 0, 0, 0.00, 0, 1, + 0, 0, 0, null, b'0'); + +SET @product_id = -1; +SELECT id INTO @product_id FROM m_product_loan WHERE name = concat('Interoperation Customer Product', @last_product_id); + +-- charge, mapping +INSERT INTO `m_charge` VALUES ( + NULL, concat('Loan Withdraw Fee_', @product_id), 'TZS', 1, 2, + 1, 0, 1.000000, NULL, NULL, + NULL, 0, 1, 0, NULL, + NULL, NULL, NULL, NULL); + +INSERT INTO `m_product_loan_charge` VALUES + (@product_id, (SELECT id + FROM m_charge + WHERE name = concat('Loan Withdraw Fee_', @product_id))); + +-- gl_account, mappings +-- ASSET-1, LIABILITY-2, EQUITY-3, INCOME-4, EXPENSE-5 +SET @liab_acc_name = concat('Loan Payable Liability_', @product_id); +INSERT INTO `acc_gl_account` VALUES ( + NULL, @liab_acc_name, NULL, NULL, concat('0360009420', @product_id), + 0, 1, 1, 1, NULL, 'Loan Payable Liability'); + +INSERT INTO `acc_product_mapping` VALUES ( + NULL, + (SELECT id + FROM acc_gl_account + WHERE name = @liab_acc_name), + @product_id, + NULL, NULL, NULL, 2); + +SET @nostro_acc_name = concat('Loan NOSTRO_', @product_id); +INSERT INTO `acc_gl_account` VALUES ( + NULL, @nostro_acc_name, NULL, NULL, concat('0360009421', @product_id), + 0, 1, 1, 1, NULL, 'Loan NOSTRO'); + +INSERT INTO `acc_product_mapping` VALUES ( + NULL, + (SELECT id + FROM acc_gl_account + WHERE name = @nostro_acc_name), + @product_id, + NULL, NULL, NULL, 1); + +SET @cash_acc_name = concat('Loan Product Cash_', @product_id); +INSERT INTO `acc_gl_account` VALUES ( + NULL, @cash_acc_name, NULL, NULL, concat('0360009422', @product_id), + 0, 1, 1, 1, NULL, 'Loan Product Cash'); + +INSERT INTO `acc_product_mapping` VALUES ( + NULL, + (SELECT id + FROM acc_gl_account + WHERE name = @cash_acc_name), + @product_id, + NULL, NULL, NULL, 1); + +SET @expen_acc_name = concat('Loan Product Expenses_', @product_id); +INSERT INTO `acc_gl_account` VALUES ( + NULL, @expen_acc_name, NULL, NULL, concat('0360009423', @product_id), + 0, 1, 1, 1, NULL, 'Loan Product Expenses'); + +INSERT INTO `acc_product_mapping` VALUES ( + NULL, + (SELECT id + FROM acc_gl_account + WHERE name = @expen_acc_name), + @product_id, + NULL, NULL, NULL, 5); + +SET @accrue_acc_name = concat('Loan Product Accrue Liability_', @product_id); +INSERT INTO `acc_gl_account` VALUES ( + NULL, @accrue_acc_name, NULL, NULL, concat('0360009424', @product_id), + 0, 1, 1, 1, NULL, 'Loan Product Accrue Liability'); + +INSERT INTO `acc_product_mapping` VALUES ( + NULL, + (SELECT id + FROM acc_gl_account + WHERE name = @accrue_acc_name), + @product_id, + NULL, NULL, NULL, 2); + +SET @equ_acc_name = concat('Loan Product Equity_', @product_id); +INSERT INTO `acc_gl_account` VALUES ( + NULL, @equ_acc_name, NULL, NULL, concat('0360009425', @product_id), + 0, 1, 1, 1, NULL, 'Loan Product Equity'); + +INSERT INTO `acc_product_mapping` VALUES ( + NULL, + (SELECT id + FROM acc_gl_account + WHERE name = @equ_acc_name), + @product_id, + NULL, NULL, NULL, 3); + +SET @feer_acc_name = concat('Loan Product Fees Revenue_', @product_id); +INSERT INTO `acc_gl_account` VALUES ( + NULL, @feer_acc_name, NULL, NULL, concat('0360009426', @product_id), + 0, 1, 1, 1, NULL, 'Loan Product Fees Revenue'); + +INSERT INTO `acc_product_mapping` VALUES ( + NULL, + (SELECT id + FROM acc_gl_account + WHERE name = @feer_acc_name), + @product_id, + NULL, NULL, NULL, 4); + +SET @overd_acc_name = concat('Overdraft_', @product_id); +INSERT INTO `acc_gl_account` VALUES ( + 11, @overd_acc_name, NULL, NULL, concat('0360009427', @product_id), + 0, 1, 1, 1, NULL, 'Overdraft'); + +INSERT INTO `acc_product_mapping` VALUES ( + NULL, + (SELECT id + FROM acc_gl_account + WHERE name = @overd_acc_name), + @product_id, + NULL, 1, NULL, 11); + +-- TENANT 4 ###################### + +USE `tn04`; + +-- loan product +SET @last_product_id = 1; +SET @last_ext_id = -1; +SELECT COALESCE(max(external_id), 1) INTO @last_ext_id FROM m_product_loan; + + +INSERT INTO `m_product_loan` VALUES +(@last_product_id, 'TZS', 2, 1, 1, -- 5 + NULL, NULL, NULL, NULL, concat('Interoperation Customer Product', @last_product_id),'Demo Interoperation Product', -- 6 + NULL, b'0', b'0', 1.000000, 1.000000, -- 5 + 1.000000, 3, 1.000000, 0, -- 4 + 1, 1, 1, 2, 1200, -- number_of_repayments 5 + NULL,NULL, NULL, NULL, NULL, -- 5 + 1, 1, 3, @last_ext_id + 1, 0, -- 5 + 0,0,ADDDATE(curdate(),-100),ADDDATE(curdate(),100), 0, 0, -- dates 6 + NULL, NULL,NULL, 1, 30, -- 5 + 0, 0, 0.00, 0, 1, -- 5 + 0, 0, 0, null, b'0'); -- 5 + +SET @product_id = -1; +SELECT id INTO @product_id FROM m_product_loan WHERE name = concat('Interoperation Customer Product', @last_product_id); + +-- charge, mapping +INSERT INTO `m_charge` VALUES ( + NULL, concat('Loan Withdraw Fee_', @product_id), 'TZS', 1, 2, + 1, 0, 1.000000, NULL, NULL, + NULL, 0, 1, 0, NULL, + NULL, NULL, NULL, NULL); + +INSERT INTO `m_product_loan_charge` VALUES + (@product_id, (SELECT id + FROM m_charge + WHERE name = concat('Loan Withdraw Fee_', @product_id))); + +-- gl_account, mappings +-- ASSET-1, LIABILITY-2, EQUITY-3, INCOME-4, EXPENSE-5 +SET @liab_acc_name = concat('Loan Payable Liability_', @product_id); +INSERT INTO `acc_gl_account` VALUES ( + NULL, @liab_acc_name, NULL, NULL, concat('0360009420', @product_id), + 0, 1, 1, 1, NULL, 'Loan Payable Liability'); + +INSERT INTO `acc_product_mapping` VALUES ( + NULL, + (SELECT id + FROM acc_gl_account + WHERE name = @liab_acc_name), + @product_id, + NULL, NULL, NULL, 2); + +SET @nostro_acc_name = concat('Loan NOSTRO_', @product_id); +INSERT INTO `acc_gl_account` VALUES ( + NULL, @nostro_acc_name, NULL, NULL, concat('0360009421', @product_id), + 0, 1, 1, 1, NULL, 'Loan NOSTRO'); + +INSERT INTO `acc_product_mapping` VALUES ( + NULL, + (SELECT id + FROM acc_gl_account + WHERE name = @nostro_acc_name), + @product_id, + NULL, NULL, NULL, 1); + +SET @cash_acc_name = concat('Loan Product Cash_', @product_id); +INSERT INTO `acc_gl_account` VALUES ( + NULL, @cash_acc_name, NULL, NULL, concat('0360009422', @product_id), + 0, 1, 1, 1, NULL, 'Loan Product Cash'); + +INSERT INTO `acc_product_mapping` VALUES ( + NULL, + (SELECT id + FROM acc_gl_account + WHERE name = @cash_acc_name), + @product_id, + NULL, NULL, NULL, 1); + +SET @expen_acc_name = concat('Loan Product Expenses_', @product_id); +INSERT INTO `acc_gl_account` VALUES ( + NULL, @expen_acc_name, NULL, NULL, concat('0360009423', @product_id), + 0, 1, 1, 1, NULL, 'Loan Product Expenses'); + +INSERT INTO `acc_product_mapping` VALUES ( + NULL, + (SELECT id + FROM acc_gl_account + WHERE name = @expen_acc_name), + @product_id, + NULL, NULL, NULL, 5); + +SET @accrue_acc_name = concat('Loan Product Accrue Liability_', @product_id); +INSERT INTO `acc_gl_account` VALUES ( + NULL, @accrue_acc_name, NULL, NULL, concat('0360009424', @product_id), + 0, 1, 1, 1, NULL, 'Loan Product Accrue Liability'); + +INSERT INTO `acc_product_mapping` VALUES ( + NULL, + (SELECT id + FROM acc_gl_account + WHERE name = @accrue_acc_name), + @product_id, + NULL, NULL, NULL, 2); + +SET @equ_acc_name = concat('Loan Product Equity_', @product_id); +INSERT INTO `acc_gl_account` VALUES ( + NULL, @equ_acc_name, NULL, NULL, concat('0360009425', @product_id), + 0, 1, 1, 1, NULL, 'Loan Product Equity'); + +INSERT INTO `acc_product_mapping` VALUES ( + NULL, + (SELECT id + FROM acc_gl_account + WHERE name = @equ_acc_name), + @product_id, + NULL, NULL, NULL, 3); + +SET @feer_acc_name = concat('Loan Product Fees Revenue_', @product_id); +INSERT INTO `acc_gl_account` VALUES ( + NULL, @feer_acc_name, NULL, NULL, concat('0360009426', @product_id), + 0, 1, 1, 1, NULL, 'Loan Product Fees Revenue'); + +INSERT INTO `acc_product_mapping` VALUES ( + NULL, + (SELECT id + FROM acc_gl_account + WHERE name = @feer_acc_name), + @product_id, + NULL, NULL, NULL, 4); + +SET @overd_acc_name = concat('Overdraft_', @product_id); +INSERT INTO `acc_gl_account` VALUES ( + 11, @overd_acc_name, NULL, NULL, concat('0360009427', @product_id), + 0, 1, 1, 1, NULL, 'Overdraft'); + +INSERT INTO `acc_product_mapping` VALUES ( + NULL, + (SELECT id + FROM acc_gl_account + WHERE name = @overd_acc_name), + @product_id, + NULL, 1, NULL, 11); \ No newline at end of file diff --git a/ph-ee-env-labs/data/barebone_sql/docker-compose.yml b/ph-ee-env-labs/data/barebone_sql/docker-compose.yml new file mode 100644 index 000000000..52c80279f --- /dev/null +++ b/ph-ee-env-labs/data/barebone_sql/docker-compose.yml @@ -0,0 +1,26 @@ +version: '2' +services: + fineractmysql: + image: mysql:5.7 + restart: always + environment: + MYSQL_ROOT_PASSWORD: mysql + ports: + - "3306:3306" + + fineract-server: + image: paymenthubee.azurecr.io/fineract_fineract-server:1.2 + environment: + SPRING_PROFILES_ACTIVE: basicauth + JAVA_OPTS: '-agentlib:jdwp=transport=dt_socket,server=y,address=5006,suspend=n' + ports: + - 8443:8443 + - 5006:5006 + restart: always + depends_on: + - fineractmysql + + community-app: + image: paymenthubee.azurecr.io/fineract/community-app + ports: + - 9002:80 diff --git a/ph-ee-env-labs/data/medium_sql/01_create_schemas.sql b/ph-ee-env-labs/data/medium_sql/01_create_schemas.sql new file mode 100644 index 000000000..ec0cbafe4 --- /dev/null +++ b/ph-ee-env-labs/data/medium_sql/01_create_schemas.sql @@ -0,0 +1,5 @@ +-- STEP 1 create schemas +CREATE SCHEMA IF NOT EXISTS `mifosplatform-tenants`; +CREATE SCHEMA IF NOT EXISTS `mifostenant-default`; +CREATE SCHEMA IF NOT EXISTS `tn05`; +CREATE SCHEMA IF NOT EXISTS `tn06`; \ No newline at end of file diff --git a/ph-ee-env-labs/data/medium_sql/02_add_interop_data.sql b/ph-ee-env-labs/data/medium_sql/02_add_interop_data.sql new file mode 100644 index 000000000..2692cdbf1 --- /dev/null +++ b/ph-ee-env-labs/data/medium_sql/02_add_interop_data.sql @@ -0,0 +1,227 @@ +-- STEP 1 add interop data +USE `tn05`; + +SET @last_saving_prod_id = -1; +SELECT COALESCE(max(id), 1) into @last_saving_prod_id from m_savings_product; + +SET @saving_prod_name = concat('Saving Product', @last_saving_prod_id); + +INSERT INTO `m_savings_product` +(`name`, `short_name`, `description`, `deposit_type_enum`, `currency_code`, `currency_digits`, + `currency_multiplesof`, `nominal_annual_interest_rate`, `interest_compounding_period_enum`, + `interest_posting_period_enum`, `interest_calculation_type_enum`, `interest_calculation_days_in_year_type_enum`, + `min_required_opening_balance`, `accounting_type`, `withdrawal_fee_amount`, `withdrawal_fee_type_enum`, + `withdrawal_fee_for_transfer`, `allow_overdraft`, `min_required_balance`, `enforce_min_required_balance`, + `min_balance_for_interest_calculation`, `withhold_tax`, `tax_group_id`, `is_dormancy_tracking_active`) +VALUES (@saving_prod_name, concat('SP', @last_saving_prod_id), 'Saving Product', 100, 'TZS', 2, NULL, 0.000000, 1, + 4, 1, 360, NULL, 2, NULL, NULL, 0, 0, 0.000000, 1, NULL, 0, NULL, 0); + +SET @saving_prod_id = -1; +SELECT id INTO @saving_prod_id FROM m_savings_product WHERE name = @saving_prod_name; + +SET @payment_type_id = -1; +SELECT id INTO @payment_type_id FROM m_payment_type WHERE value = 'Money Transfer'; + +SET @saving_gl_name = 'Interoperation Saving'; +INSERT INTO `acc_gl_account` (`name`, `parent_id`, `hierarchy`, `gl_code`, `disabled`, `manual_journal_entries_allowed`, `account_usage`, `classification_enum`, `description`) +VALUES (@saving_gl_name, NULL, NULL, 'Interop_Saving', 0, 1, 1, 1, 'Interoperation Saving Asset'); -- account_usage: DETAIL, classification_enum: ASSET + +INSERT INTO `acc_product_mapping` (`gl_account_id`, `product_id`, `product_type`, `payment_type`, `charge_id`, `financial_account_type`) +VALUES ((SELECT id FROM acc_gl_account WHERE name = @saving_gl_name), @saving_prod_id, 2, @payment_type_id, NULL, 1); -- product_type: SAVING, financial_account_type: ASSET + +SET @nostro_gl_name = 'Interoperation NOSTRO'; +INSERT INTO `acc_gl_account` (`name`, `parent_id`, `hierarchy`, `gl_code`, `disabled`, `manual_journal_entries_allowed`, `account_usage`, `classification_enum`, `description`) +VALUES (@nostro_gl_name, NULL, NULL, 'Interop_Nostro', 0, 0, 1, 2, 'Interoperation NOSTRO Liability'); -- account_usage: DETAIL, classification_enum: LIABILITY + +INSERT INTO `acc_product_mapping` (`gl_account_id`, `product_id`, `product_type`, `payment_type`, `charge_id`, `financial_account_type`) +VALUES ((SELECT id FROM acc_gl_account WHERE name = @nostro_gl_name), @saving_prod_id, 2, NULL, NULL, 2); -- product_type: SAVING, financial_account_type: LIABILITY + +SET @fee_gl_name = 'Interoperation Fee'; +INSERT INTO `acc_gl_account` (`name`, `parent_id`, `hierarchy`, `gl_code`, `disabled`, `manual_journal_entries_allowed`, `account_usage`, `classification_enum`, `description`) +VALUES (@fee_gl_name, NULL, NULL, 'Interop_Fee', 0, 0, 1, 4, 'Interoperation Fee Income'); -- account_usage: DETAIL, classification_enum: INCOME + +SET @fee_gl_id = -1; +SELECT id INTO @fee_gl_id FROM acc_gl_account WHERE name = @fee_gl_name; + +INSERT INTO `acc_product_mapping` (`gl_account_id`, `product_id`, `product_type`, `payment_type`, `charge_id`, `financial_account_type`) +VALUES (@fee_gl_id, @saving_prod_id, 2, NULL, NULL, 4); -- product_type: SAVING, financial_account_type: INCOME + +SET @charge_name = 'Interoperation Withdraw Fee'; +INSERT INTO `m_charge` +(`name`,`currency_code`,`charge_applies_to_enum`,`charge_time_enum`,`charge_calculation_enum`,`charge_payment_mode_enum`, + `amount`,`fee_on_day`,`fee_interval`,`fee_on_month`,`is_penalty`,`is_active`,`is_deleted`,`min_cap`,`max_cap`,`fee_frequency`, + `income_or_liability_account_id`,`tax_group_id`) +VALUES (@charge_name, 'TZS', 2, 5, 1, NULL, 1.000000, NULL, NULL, NULL, 0, 0, 0, NULL, NULL, NULL, @fee_gl_id, NULL); + +-- STEP 2 add tn05 + +SET @client_name = 'InteropCustomer'; +SET @saving_account_no = '9062b90de19b43989005'; +SET @saving_account_ext_id = '9062b90de19b43989005d9'; +SET @IBAN = 'IC11in03tn05' + @saving_account_ext_id; +SET @MSISDN = '27710305999'; + +INSERT INTO `m_client` (`account_no`, `external_id`, `status_enum`, `sub_status`, `activation_date`, `office_joining_date`, + `office_id`, `transfer_to_office_id`, `staff_id`, `firstname`, `middlename`, `lastname`, `fullname`, + `display_name`, `mobile_no`, `gender_cv_id`, `date_of_birth`, `image_id`, `closure_reason_cv_id`, + `closedon_date`, `updated_by`, `updated_on`, `submittedon_date`, `submittedon_userid`, `activatedon_userid`, + `closedon_userid`, `default_savings_product`, `default_savings_account`, `client_type_cv_id`, `client_classification_cv_id`, + `reject_reason_cv_id`, `rejectedon_date`, `rejectedon_userid`, `withdraw_reason_cv_id`, `withdrawn_on_date`, + `withdraw_on_userid`, `reactivated_on_date`, `reactivated_on_userid`, `legal_form_enum`, `reopened_on_date`, + `reopened_by_userid`) +VALUES (@saving_account_no, NULL, 300, NULL, ADDDATE(curdate(), -100), NULL, 1, NULL, NULL, NULL, NULL, NULL, + @client_name, @client_name, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ADDDATE(curdate(), -100), + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,NULL, NULL); + +SET @last_saving_prod_id = -1; +SELECT COALESCE(max(id), 1) into @last_saving_prod_id from m_savings_product; + +SET @saving_prod_name = concat('Saving Product', @last_saving_prod_id); +SET @saving_prod_id = -1; +SELECT id INTO @saving_prod_id FROM m_savings_product WHERE name = @saving_prod_name; + +SET @client_id = -1; +SELECT id INTO @client_id FROM m_client WHERE fullname = @client_name; + +INSERT INTO `m_savings_account` +(`account_no`, `external_id`, `client_id`, `group_id`, `product_id`, `field_officer_id`, `status_enum`, + `sub_status_enum`, `account_type_enum`, `deposit_type_enum`, `submittedon_date`, `submittedon_userid`, + `approvedon_date`, `approvedon_userid`, `activatedon_date`, `activatedon_userid`, + `currency_code`, `currency_digits`, `currency_multiplesof`, `nominal_annual_interest_rate`, + `interest_compounding_period_enum`, `interest_posting_period_enum`, `interest_calculation_type_enum`, + `interest_calculation_days_in_year_type_enum`, `min_required_opening_balance`, `withdrawal_fee_for_transfer`, + `allow_overdraft`, `account_balance_derived`, `min_required_balance`, `enforce_min_required_balance`, + `version`, `withhold_tax`) +VALUES (@saving_account_no, @saving_account_ext_id, @client_id, NULL, @saving_prod_id, NULL, 300, 0, 1, 100, ADDDATE(curdate(), -100), + NULL, ADDDATE(curdate(), -100), NULL, ADDDATE(curdate(), -100), NULL, 'TZS', 2, NULL, 1.000000, 1, 4, 1, -- 29. - 4 + 360, NULL, 1, 1, 100000000.000000, 0.000000, 1, 1, 0); + +SET @saving_acc_id = -1; +SELECT id INTO @saving_acc_id FROM m_savings_account WHERE account_no = @saving_account_no; + +INSERT INTO interop_identifier (id, account_id, type, a_value, sub_value_or_type, created_by, created_on, modified_by, modified_on) +VALUES (NULL, @saving_acc_id, 'IBAN', @IBAN, NULL, 'operator', CURDATE(), 'operator', + CURDATE()); +INSERT INTO interop_identifier (id, account_id, type, a_value, sub_value_or_type, created_by, created_on, modified_by, modified_on) +VALUES (NULL, @saving_acc_id, 'MSISDN', @MSISDN, NULL, 'operator', CURDATE(), 'operator', CURDATE()); + +SET @charge_name = 'Interoperation Withdraw Fee'; + +INSERT INTO `m_savings_account_charge` (`savings_account_id`, `charge_id`, `is_penalty`, `charge_time_enum`, `charge_calculation_enum`, + `amount`, `amount_outstanding_derived`,`is_paid_derived`, `waived`, `is_active`) +VALUES (@saving_acc_id, (SELECT id FROM m_charge WHERE name = @charge_name), 0, 5, 1, 1.000000, 0.000000, 0, 0, 1); + +-- STEP 3 add interop data +USE `tn06`; + +SET @last_saving_prod_id = -1; +SELECT COALESCE(max(id), 1) into @last_saving_prod_id from m_savings_product; + +SET @saving_prod_name = concat('Saving Product', @last_saving_prod_id); + +INSERT INTO `m_savings_product` +(`name`, `short_name`, `description`, `deposit_type_enum`, `currency_code`, `currency_digits`, + `currency_multiplesof`, `nominal_annual_interest_rate`, `interest_compounding_period_enum`, + `interest_posting_period_enum`, `interest_calculation_type_enum`, `interest_calculation_days_in_year_type_enum`, + `min_required_opening_balance`, `accounting_type`, `withdrawal_fee_amount`, `withdrawal_fee_type_enum`, + `withdrawal_fee_for_transfer`, `allow_overdraft`, `min_required_balance`, `enforce_min_required_balance`, + `min_balance_for_interest_calculation`, `withhold_tax`, `tax_group_id`, `is_dormancy_tracking_active`) +VALUES (@saving_prod_name, concat('SP', @last_saving_prod_id), 'Saving Product', 100, 'TZS', 2, NULL, 0.000000, 1, + 4, 1, 360, NULL, 2, NULL, NULL, 0, 0, 0.000000, 1, NULL, 0, NULL, 0); + +SET @saving_prod_id = -1; +SELECT id INTO @saving_prod_id FROM m_savings_product WHERE name = @saving_prod_name; + +SET @payment_type_id = -1; +SELECT id INTO @payment_type_id FROM m_payment_type WHERE value = 'Money Transfer'; + +SET @saving_gl_name = 'Interoperation Saving'; +INSERT INTO `acc_gl_account` (`name`, `parent_id`, `hierarchy`, `gl_code`, `disabled`, `manual_journal_entries_allowed`, `account_usage`, `classification_enum`, `description`) +VALUES (@saving_gl_name, NULL, NULL, 'Interop_Saving', 0, 1, 1, 1, 'Interoperation Saving Asset'); -- account_usage: DETAIL, classification_enum: ASSET + +INSERT INTO `acc_product_mapping` (`gl_account_id`, `product_id`, `product_type`, `payment_type`, `charge_id`, `financial_account_type`) +VALUES ((SELECT id FROM acc_gl_account WHERE name = @saving_gl_name), @saving_prod_id, 2, @payment_type_id, NULL, 1); -- product_type: SAVING, financial_account_type: ASSET + +SET @nostro_gl_name = 'Interoperation NOSTRO'; +INSERT INTO `acc_gl_account` (`name`, `parent_id`, `hierarchy`, `gl_code`, `disabled`, `manual_journal_entries_allowed`, `account_usage`, `classification_enum`, `description`) +VALUES (@nostro_gl_name, NULL, NULL, 'Interop_Nostro', 0, 0, 1, 2, 'Interoperation NOSTRO Liability'); -- account_usage: DETAIL, classification_enum: LIABILITY + +INSERT INTO `acc_product_mapping` (`gl_account_id`, `product_id`, `product_type`, `payment_type`, `charge_id`, `financial_account_type`) +VALUES ((SELECT id FROM acc_gl_account WHERE name = @nostro_gl_name), @saving_prod_id, 2, NULL, NULL, 2); -- product_type: SAVING, financial_account_type: LIABILITY + +SET @fee_gl_name = 'Interoperation Fee'; +INSERT INTO `acc_gl_account` (`name`, `parent_id`, `hierarchy`, `gl_code`, `disabled`, `manual_journal_entries_allowed`, `account_usage`, `classification_enum`, `description`) +VALUES (@fee_gl_name, NULL, NULL, 'Interop_Fee', 0, 0, 1, 4, 'Interoperation Fee Income'); -- account_usage: DETAIL, classification_enum: INCOME + +SET @fee_gl_id = -1; +SELECT id INTO @fee_gl_id FROM acc_gl_account WHERE name = @fee_gl_name; + +INSERT INTO `acc_product_mapping` (`gl_account_id`, `product_id`, `product_type`, `payment_type`, `charge_id`, `financial_account_type`) +VALUES (@fee_gl_id, @saving_prod_id, 2, NULL, NULL, 4); -- product_type: SAVING, financial_account_type: INCOME + +SET @charge_name = 'Interoperation Withdraw Fee'; +INSERT INTO `m_charge` +(`name`,`currency_code`,`charge_applies_to_enum`,`charge_time_enum`,`charge_calculation_enum`,`charge_payment_mode_enum`, + `amount`,`fee_on_day`,`fee_interval`,`fee_on_month`,`is_penalty`,`is_active`,`is_deleted`,`min_cap`,`max_cap`,`fee_frequency`, + `income_or_liability_account_id`,`tax_group_id`) +VALUES (@charge_name, 'TZS', 2, 5, 1, NULL, 1.000000, NULL, NULL, NULL, 0, 0, 0, NULL, NULL, NULL, @fee_gl_id, NULL); + +-- STEP 3 add tn06 + +SET @client_name = 'InteropMerchant'; +SET @saving_account_no = 'a6b6c10b2aaa4778ac2f'; +SET @saving_account_ext_id = 'a6b6c10b2aaa4778ac2fc9'; +SET @IBAN = 'IC11in03tn06' + @saving_account_ext_id; +SET @MSISDN = '27710306999'; + +INSERT INTO `m_client` (`account_no`, `external_id`, `status_enum`, `sub_status`, `activation_date`, `office_joining_date`, + `office_id`, `transfer_to_office_id`, `staff_id`, `firstname`, `middlename`, `lastname`, `fullname`, + `display_name`, `mobile_no`, `gender_cv_id`, `date_of_birth`, `image_id`, `closure_reason_cv_id`, + `closedon_date`, `updated_by`, `updated_on`, `submittedon_date`, `submittedon_userid`, `activatedon_userid`, + `closedon_userid`, `default_savings_product`, `default_savings_account`, `client_type_cv_id`, `client_classification_cv_id`, + `reject_reason_cv_id`, `rejectedon_date`, `rejectedon_userid`, `withdraw_reason_cv_id`, `withdrawn_on_date`, + `withdraw_on_userid`, `reactivated_on_date`, `reactivated_on_userid`, `legal_form_enum`, `reopened_on_date`, + `reopened_by_userid`) +VALUES (@saving_account_no, NULL, 300, NULL, ADDDATE(curdate(), -100), NULL, 1, NULL, NULL, NULL, NULL, NULL, + @client_name, @client_name, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ADDDATE(curdate(), -100), + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,NULL, NULL); + +-- saving product, account +SET @last_saving_prod_id = -1; +SELECT COALESCE(max(id), 1) into @last_saving_prod_id from m_savings_product; + +SET @saving_prod_name = concat('Saving Product', @last_saving_prod_id); +SET @saving_prod_id = -1; +SELECT id INTO @saving_prod_id FROM m_savings_product WHERE name = @saving_prod_name; + +SET @client_id = -1; +SELECT id INTO @client_id FROM m_client WHERE fullname = @client_name; + +INSERT INTO `m_savings_account` +(`account_no`, `external_id`, `client_id`, `group_id`, `product_id`, `field_officer_id`, `status_enum`, + `sub_status_enum`, `account_type_enum`, `deposit_type_enum`, `submittedon_date`, `submittedon_userid`, + `approvedon_date`, `approvedon_userid`, `activatedon_date`, `activatedon_userid`, + `currency_code`, `currency_digits`, `currency_multiplesof`, `nominal_annual_interest_rate`, + `interest_compounding_period_enum`, `interest_posting_period_enum`, `interest_calculation_type_enum`, + `interest_calculation_days_in_year_type_enum`, `min_required_opening_balance`, `withdrawal_fee_for_transfer`, + `allow_overdraft`, `account_balance_derived`, `min_required_balance`, `enforce_min_required_balance`, + `version`, `withhold_tax`) +VALUES (@saving_account_no, @saving_account_ext_id, @client_id, NULL, @saving_prod_id, NULL, 300, 0, 1, 100, ADDDATE(curdate(), -100), + NULL, ADDDATE(curdate(), -100), NULL, ADDDATE(curdate(), -100), NULL, 'TZS', 2, NULL, 1.000000, 1, 4, 1, -- 29. - 4 + 360, NULL, 1, 1, 100000000.000000, 0.000000, 1, 1, 0); + +-- interop_identifier +SET @saving_acc_id = -1; +SELECT id INTO @saving_acc_id FROM m_savings_account WHERE account_no = @saving_account_no; + +INSERT INTO interop_identifier (id, account_id, type, a_value, sub_value_or_type, created_by, created_on, modified_by, modified_on) +VALUES (NULL, @saving_acc_id, 'IBAN', @IBAN, NULL, 'operator', CURDATE(), 'operator', + CURDATE()); +INSERT INTO interop_identifier (id, account_id, type, a_value, sub_value_or_type, created_by, created_on, modified_by, modified_on) +VALUES (NULL, @saving_acc_id, 'MSISDN', @MSISDN, NULL, 'operator', CURDATE(), 'operator', CURDATE()); + +SET @charge_name = 'Interoperation Withdraw Fee'; + +INSERT INTO `m_savings_account_charge` (`savings_account_id`, `charge_id`, `is_penalty`, `charge_time_enum`, `charge_calculation_enum`, + `amount`, `amount_outstanding_derived`,`is_paid_derived`, `waived`, `is_active`) +VALUES (@saving_acc_id, (SELECT id FROM m_charge WHERE name = @charge_name), 0, 5, 1, 1.000000, 0.000000, 0, 0, 1); \ No newline at end of file diff --git a/ph-ee-env-labs/data/medium_sql/03_add_accounts.sql b/ph-ee-env-labs/data/medium_sql/03_add_accounts.sql new file mode 100644 index 000000000..814a455ed --- /dev/null +++ b/ph-ee-env-labs/data/medium_sql/03_add_accounts.sql @@ -0,0 +1,286 @@ +-- TENANT 5 ###################### +USE `tn05`; + +-- loan product +SET @last_product_id = 1; +SET @last_ext_id = -1; +SELECT COALESCE(max(external_id), 1) INTO @last_ext_id FROM m_product_loan; + + +INSERT INTO `m_product_loan` VALUES +(@last_product_id, 'TZS', 2, 1, 1, + NULL, NULL, NULL, NULL, concat('Interoperation Customer Product', @last_product_id),'Demo Interoperation Product', -- 6 + NULL, b'0', b'0', 1.000000, 1.000000, + 1.000000, 3, 1.000000, 0, + 1, 1, 1, 2, 1200, + NULL,NULL, NULL, NULL, NULL, + 1, 1, 3, @last_ext_id + 1, 0, + 0,0,ADDDATE(curdate(),-100),ADDDATE(curdate(),100), 0, 0, + NULL, NULL,NULL, 1, 30, + 0, 0, 0.00, 0, 1, + 0, 0, 0, null, b'0'); + +SET @product_id = -1; +SELECT id INTO @product_id FROM m_product_loan WHERE name = concat('Interoperation Customer Product', @last_product_id); + +-- charge, mapping +INSERT INTO `m_charge` VALUES ( + NULL, concat('Loan Withdraw Fee_', @product_id), 'TZS', 1, 2, + 1, 0, 1.000000, NULL, NULL, + NULL, 0, 1, 0, NULL, + NULL, NULL, NULL, NULL); + +INSERT INTO `m_product_loan_charge` VALUES + (@product_id, (SELECT id + FROM m_charge + WHERE name = concat('Loan Withdraw Fee_', @product_id))); + +-- gl_account, mappings +-- ASSET-1, LIABILITY-2, EQUITY-3, INCOME-4, EXPENSE-5 +SET @liab_acc_name = concat('Loan Payable Liability_', @product_id); +INSERT INTO `acc_gl_account` VALUES ( + NULL, @liab_acc_name, NULL, NULL, concat('0360009420', @product_id), + 0, 1, 1, 1, NULL, 'Loan Payable Liability'); + +INSERT INTO `acc_product_mapping` VALUES ( + NULL, + (SELECT id + FROM acc_gl_account + WHERE name = @liab_acc_name), + @product_id, + NULL, NULL, NULL, 2); + +SET @nostro_acc_name = concat('Loan NOSTRO_', @product_id); +INSERT INTO `acc_gl_account` VALUES ( + NULL, @nostro_acc_name, NULL, NULL, concat('0360009421', @product_id), + 0, 1, 1, 1, NULL, 'Loan NOSTRO'); + +INSERT INTO `acc_product_mapping` VALUES ( + NULL, + (SELECT id + FROM acc_gl_account + WHERE name = @nostro_acc_name), + @product_id, + NULL, NULL, NULL, 1); + +SET @cash_acc_name = concat('Loan Product Cash_', @product_id); +INSERT INTO `acc_gl_account` VALUES ( + NULL, @cash_acc_name, NULL, NULL, concat('0360009422', @product_id), + 0, 1, 1, 1, NULL, 'Loan Product Cash'); + +INSERT INTO `acc_product_mapping` VALUES ( + NULL, + (SELECT id + FROM acc_gl_account + WHERE name = @cash_acc_name), + @product_id, + NULL, NULL, NULL, 1); + +SET @expen_acc_name = concat('Loan Product Expenses_', @product_id); +INSERT INTO `acc_gl_account` VALUES ( + NULL, @expen_acc_name, NULL, NULL, concat('0360009423', @product_id), + 0, 1, 1, 1, NULL, 'Loan Product Expenses'); + +INSERT INTO `acc_product_mapping` VALUES ( + NULL, + (SELECT id + FROM acc_gl_account + WHERE name = @expen_acc_name), + @product_id, + NULL, NULL, NULL, 5); + +SET @accrue_acc_name = concat('Loan Product Accrue Liability_', @product_id); +INSERT INTO `acc_gl_account` VALUES ( + NULL, @accrue_acc_name, NULL, NULL, concat('0360009424', @product_id), + 0, 1, 1, 1, NULL, 'Loan Product Accrue Liability'); + +INSERT INTO `acc_product_mapping` VALUES ( + NULL, + (SELECT id + FROM acc_gl_account + WHERE name = @accrue_acc_name), + @product_id, + NULL, NULL, NULL, 2); + +SET @equ_acc_name = concat('Loan Product Equity_', @product_id); +INSERT INTO `acc_gl_account` VALUES ( + NULL, @equ_acc_name, NULL, NULL, concat('0360009425', @product_id), + 0, 1, 1, 1, NULL, 'Loan Product Equity'); + +INSERT INTO `acc_product_mapping` VALUES ( + NULL, + (SELECT id + FROM acc_gl_account + WHERE name = @equ_acc_name), + @product_id, + NULL, NULL, NULL, 3); + +SET @feer_acc_name = concat('Loan Product Fees Revenue_', @product_id); +INSERT INTO `acc_gl_account` VALUES ( + NULL, @feer_acc_name, NULL, NULL, concat('0360009426', @product_id), + 0, 1, 1, 1, NULL, 'Loan Product Fees Revenue'); + +INSERT INTO `acc_product_mapping` VALUES ( + NULL, + (SELECT id + FROM acc_gl_account + WHERE name = @feer_acc_name), + @product_id, + NULL, NULL, NULL, 4); + +SET @overd_acc_name = concat('Overdraft_', @product_id); +INSERT INTO `acc_gl_account` VALUES ( + 11, @overd_acc_name, NULL, NULL, concat('0360009427', @product_id), + 0, 1, 1, 1, NULL, 'Overdraft'); + +INSERT INTO `acc_product_mapping` VALUES ( + NULL, + (SELECT id + FROM acc_gl_account + WHERE name = @overd_acc_name), + @product_id, + NULL, 1, NULL, 11); + +-- TENANT 6 ###################### + +USE `tn06`; + +-- loan product +SET @last_product_id = 1; +SET @last_ext_id = -1; +SELECT COALESCE(max(external_id), 1) INTO @last_ext_id FROM m_product_loan; + + +INSERT INTO `m_product_loan` VALUES +(@last_product_id, 'TZS', 2, 1, 1, -- 5 + NULL, NULL, NULL, NULL, concat('Interoperation Customer Product', @last_product_id),'Demo Interoperation Product', -- 6 + NULL, b'0', b'0', 1.000000, 1.000000, -- 5 + 1.000000, 3, 1.000000, 0, -- 4 + 1, 1, 1, 2, 1200, -- number_of_repayments 5 + NULL,NULL, NULL, NULL, NULL, -- 5 + 1, 1, 3, @last_ext_id + 1, 0, -- 5 + 0,0,ADDDATE(curdate(),-100),ADDDATE(curdate(),100), 0, 0, -- dates 6 + NULL, NULL,NULL, 1, 30, -- 5 + 0, 0, 0.00, 0, 1, -- 5 + 0, 0, 0, null, b'0'); -- 5 + +SET @product_id = -1; +SELECT id INTO @product_id FROM m_product_loan WHERE name = concat('Interoperation Customer Product', @last_product_id); + +-- charge, mapping +INSERT INTO `m_charge` VALUES ( + NULL, concat('Loan Withdraw Fee_', @product_id), 'TZS', 1, 2, + 1, 0, 1.000000, NULL, NULL, + NULL, 0, 1, 0, NULL, + NULL, NULL, NULL, NULL); + +INSERT INTO `m_product_loan_charge` VALUES + (@product_id, (SELECT id + FROM m_charge + WHERE name = concat('Loan Withdraw Fee_', @product_id))); + +-- gl_account, mappings +-- ASSET-1, LIABILITY-2, EQUITY-3, INCOME-4, EXPENSE-5 +SET @liab_acc_name = concat('Loan Payable Liability_', @product_id); +INSERT INTO `acc_gl_account` VALUES ( + NULL, @liab_acc_name, NULL, NULL, concat('0360009420', @product_id), + 0, 1, 1, 1, NULL, 'Loan Payable Liability'); + +INSERT INTO `acc_product_mapping` VALUES ( + NULL, + (SELECT id + FROM acc_gl_account + WHERE name = @liab_acc_name), + @product_id, + NULL, NULL, NULL, 2); + +SET @nostro_acc_name = concat('Loan NOSTRO_', @product_id); +INSERT INTO `acc_gl_account` VALUES ( + NULL, @nostro_acc_name, NULL, NULL, concat('0360009421', @product_id), + 0, 1, 1, 1, NULL, 'Loan NOSTRO'); + +INSERT INTO `acc_product_mapping` VALUES ( + NULL, + (SELECT id + FROM acc_gl_account + WHERE name = @nostro_acc_name), + @product_id, + NULL, NULL, NULL, 1); + +SET @cash_acc_name = concat('Loan Product Cash_', @product_id); +INSERT INTO `acc_gl_account` VALUES ( + NULL, @cash_acc_name, NULL, NULL, concat('0360009422', @product_id), + 0, 1, 1, 1, NULL, 'Loan Product Cash'); + +INSERT INTO `acc_product_mapping` VALUES ( + NULL, + (SELECT id + FROM acc_gl_account + WHERE name = @cash_acc_name), + @product_id, + NULL, NULL, NULL, 1); + +SET @expen_acc_name = concat('Loan Product Expenses_', @product_id); +INSERT INTO `acc_gl_account` VALUES ( + NULL, @expen_acc_name, NULL, NULL, concat('0360009423', @product_id), + 0, 1, 1, 1, NULL, 'Loan Product Expenses'); + +INSERT INTO `acc_product_mapping` VALUES ( + NULL, + (SELECT id + FROM acc_gl_account + WHERE name = @expen_acc_name), + @product_id, + NULL, NULL, NULL, 5); + +SET @accrue_acc_name = concat('Loan Product Accrue Liability_', @product_id); +INSERT INTO `acc_gl_account` VALUES ( + NULL, @accrue_acc_name, NULL, NULL, concat('0360009424', @product_id), + 0, 1, 1, 1, NULL, 'Loan Product Accrue Liability'); + +INSERT INTO `acc_product_mapping` VALUES ( + NULL, + (SELECT id + FROM acc_gl_account + WHERE name = @accrue_acc_name), + @product_id, + NULL, NULL, NULL, 2); + +SET @equ_acc_name = concat('Loan Product Equity_', @product_id); +INSERT INTO `acc_gl_account` VALUES ( + NULL, @equ_acc_name, NULL, NULL, concat('0360009425', @product_id), + 0, 1, 1, 1, NULL, 'Loan Product Equity'); + +INSERT INTO `acc_product_mapping` VALUES ( + NULL, + (SELECT id + FROM acc_gl_account + WHERE name = @equ_acc_name), + @product_id, + NULL, NULL, NULL, 3); + +SET @feer_acc_name = concat('Loan Product Fees Revenue_', @product_id); +INSERT INTO `acc_gl_account` VALUES ( + NULL, @feer_acc_name, NULL, NULL, concat('0360009426', @product_id), + 0, 1, 1, 1, NULL, 'Loan Product Fees Revenue'); + +INSERT INTO `acc_product_mapping` VALUES ( + NULL, + (SELECT id + FROM acc_gl_account + WHERE name = @feer_acc_name), + @product_id, + NULL, NULL, NULL, 4); + +SET @overd_acc_name = concat('Overdraft_', @product_id); +INSERT INTO `acc_gl_account` VALUES ( + 11, @overd_acc_name, NULL, NULL, concat('0360009427', @product_id), + 0, 1, 1, 1, NULL, 'Overdraft'); + +INSERT INTO `acc_product_mapping` VALUES ( + NULL, + (SELECT id + FROM acc_gl_account + WHERE name = @overd_acc_name), + @product_id, + NULL, 1, NULL, 11); \ No newline at end of file diff --git a/ph-ee-env-labs/data/medium_sql/docker-compose.yml b/ph-ee-env-labs/data/medium_sql/docker-compose.yml new file mode 100644 index 000000000..bd9427475 --- /dev/null +++ b/ph-ee-env-labs/data/medium_sql/docker-compose.yml @@ -0,0 +1,26 @@ +version: '2' +services: + fineractmysql: + image: mysql:5.7 + restart: always + environment: + MYSQL_ROOT_PASSWORD: mysql + ports: + - "3306:3306" + + fineract-server: + image: paymenthubee.azurecr.io/fineract_fineract-server:1.2_med + environment: + SPRING_PROFILES_ACTIVE: basicauth + JAVA_OPTS: '-agentlib:jdwp=transport=dt_socket,server=y,address=5006,suspend=n' + ports: + - 8443:8443 + - 5006:5006 + restart: always + depends_on: + - fineractmysql + + community-app: + image: paymenthubee.azurecr.io/fineract/community-app + ports: + - 9002:80 diff --git a/ph-ee-env-labs/helm/README.md b/ph-ee-env-labs/helm/README.md new file mode 100644 index 000000000..1f4952904 --- /dev/null +++ b/ph-ee-env-labs/helm/README.md @@ -0,0 +1 @@ +helm upgrade -f superset/values.yaml superset superset --install --create-namespace --namespace phee diff --git a/ph-ee-env-labs/helm/dpga-compliance-barebone/Chart.yaml b/ph-ee-env-labs/helm/dpga-compliance-barebone/Chart.yaml new file mode 100644 index 000000000..8fafb11b5 --- /dev/null +++ b/ph-ee-env-labs/helm/dpga-compliance-barebone/Chart.yaml @@ -0,0 +1,57 @@ +apiVersion: v2 +name: dpga-barebone +description: DPGA Barebone Edition + +type: application +version: 1.0.0 +appVersion: 1.0.0 + +dependencies: + - name: postgresql + version: 12.10.0 + repository: https://charts.bitnami.com/bitnami + condition: "postgresql.enabled" + + - name: elasticsearch + repository: http://helm.elastic.co + version: 7.17.3 + condition: "elasticsearch.enabled" + + - name: redis + version: 17.9.3 + repository: "https://charts.bitnami.com/bitnami" + condition: "redis.enabled" + + - name: dpga-channel + repository: "file://./dpga-connector-channel" + version: 1.0.0 + + - name: dpg-importer-rdbms + repository: "file://./ph-ee-dpg-importer-rdbms" + version: 1.0.0 + + - name: netflix-conductor + repository: "file://./netflix-conductor" + version: 0.0.1 + + - name: kafka + version: 25.3.1 + repository: "https://charts.bitnami.com/bitnami" + condition: "kafka.enabled" + + - name: mysql + version: 9.4.5 + repository: "https://charts.bitnami.com/bitnami" + alias: operationsmysql + condition: "operations.mysql.enabled" + + - name: operations_app + version: 1.0.0 + repository: "file://./operations-app" + condition: "operations_app.enabled" + + - name: operations_web + version: 1.0.0 + repository: "file://./operations-web" + condition: "operations_web.enabled" + diff --git a/ph-ee-env-labs/helm/dpga-compliance-barebone/config/application-bb.properties b/ph-ee-env-labs/helm/dpga-compliance-barebone/config/application-bb.properties new file mode 100644 index 000000000..343758f88 --- /dev/null +++ b/ph-ee-env-labs/helm/dpga-compliance-barebone/config/application-bb.properties @@ -0,0 +1,9 @@ +store.local.interop.host=https://rhino.mifos.g2pconnect.io +store.local.customer.host=https://rhino.mifos.g2pconnect.io +zeebe.broker.contactpoint=g2p-sandbox-zeebe-gateway:26500 + +security.oauth2.resource.jwt.key-uri=http://ops-bk.mifos.g2pconnect.io/oauth/token_key +rest.authorization.enabled=false +rest.authorization.host=http://ops-bk.mifos.g2pconnect.io + +dfspids=rhino, gorilla, lion diff --git a/ph-ee-env-labs/helm/dpga-compliance-barebone/config/application-fin12.properties b/ph-ee-env-labs/helm/dpga-compliance-barebone/config/application-fin12.properties new file mode 100644 index 000000000..82e7a2c79 --- /dev/null +++ b/ph-ee-env-labs/helm/dpga-compliance-barebone/config/application-fin12.properties @@ -0,0 +1,7 @@ +ams.localenabled=true +ph-ee-g2psandbox.ph-ee-engine.ph_ee_connector_ams_mifos.ams_local_interop_host="https://fynams.sandbox.fynarfin.io/" +ph-ee-g2psandbox.ph-ee-engine.ph_ee_connector_ams_mifos.ams_local_account_host="https://fynams.sandbox.fynarfin.io/" +ph-ee-g2psandbox.ph-ee-engine.ph_ee_connector_ams_mifos.ams_local_customer_host="https://fynams.sandbox.fynarfin.io/" +ph-ee-g2psandbox.ph-ee-engine.ph_ee_connector_ams_mifos.ams_local_auth_host="https://fynams.sandbox.fynarfin.io/" +ph-ee-g2psandbox.ph-ee-engine.ph_ee_connector_ams_mifos.ams_local_loan_host="https://fynams.sandbox.fynarfin.io/" +ph-ee-g2psandbox.ph-ee-engine.ph_ee_connector_ams_mifos.dfspids="rhino,gorilla" \ No newline at end of file diff --git a/ph-ee-env-labs/helm/dpga-compliance-barebone/config/application-tenants.properties b/ph-ee-env-labs/helm/dpga-compliance-barebone/config/application-tenants.properties new file mode 100644 index 000000000..07b08651e --- /dev/null +++ b/ph-ee-env-labs/helm/dpga-compliance-barebone/config/application-tenants.properties @@ -0,0 +1,8 @@ +bpmns.tenants[0].id= lion +bpmns.tenants[0].flows.payment-transfer= minimal_mock_fund_transfer_account_lookup-{dfspid} +bpmns.tenants[1].id= rhino +bpmns.tenants[1].flows.payment-transfer= minimal_mock_fund_transfer-{dfspid} +bpmns.tenants[1].flows.outbound-transfer-request= minimal_mock_transfer_request-{dfspid} +bpmns.tenants[2].id= gorilla +bpmns.tenants[2].flows.payment-transfer= PayerFundTransfer-{dfspid} +bpmns.tenants[2].flows.outbound-transfer-request= {ps}_flow_{ams}-{dfspid} \ No newline at end of file diff --git a/ph-ee-env-labs/helm/dpga-compliance-barebone/dpga-connector-channel/Chart.yaml b/ph-ee-env-labs/helm/dpga-compliance-barebone/dpga-connector-channel/Chart.yaml new file mode 100644 index 000000000..c6fe72956 --- /dev/null +++ b/ph-ee-env-labs/helm/dpga-compliance-barebone/dpga-connector-channel/Chart.yaml @@ -0,0 +1,5 @@ +apiVersion: v1 +description: dpga-connector-channel +name: dpga-channel +version: 1.0.0 +appVersion: "1.0.0" diff --git a/ph-ee-env-labs/helm/dpga-compliance-barebone/dpga-connector-channel/README.md b/ph-ee-env-labs/helm/dpga-compliance-barebone/dpga-connector-channel/README.md new file mode 100644 index 000000000..5ee0325b5 --- /dev/null +++ b/ph-ee-env-labs/helm/dpga-compliance-barebone/dpga-connector-channel/README.md @@ -0,0 +1,67 @@ +# channel + +![Version: 1.0.0](https://img.shields.io/badge/Version-1.0.0-informational?style=flat-square) ![AppVersion: 1.0.0](https://img.shields.io/badge/AppVersion-1.0.0-informational?style=flat-square) + +ph-ee-connector-channel + +## Values + +| Key | Type | Default | Description | +|-----|------|---------|-------------| +| DFSPIDS | string | `""` | | +| LOGGING_LEVEL_ROOT | string | `"INFO"` | | +| SPRING_PROFILES_ACTIVE | string | `"bb,tenants"` | | +| configmap.apiversion | string | `"v1"` | | +| deployment.annotations.deployTime | string | `"{{ .Values.deployTime }}"` | | +| deployment.apiVersion | string | `"apps/v1"` | | +| enabled | bool | `true` | | +| hostname | string | `"channel.sandbox.mifos.io"` | | +| image | string | `""` | | +| imagePullPolicy | string | `"Always"` | | +| imageTag | string | `"latest"` | | +| ingress.annotations."kubernetes.io/ingress.class" | string | `"nginx"` | | +| ingress.apiversion | string | `"networking.k8s.io/v1"` | | +| ingress.backend.service.name | string | `"ph-ee-connector-channel"` | | +| ingress.backend.service.port.number | int | `80` | | +| ingress.className | string | `"nginx"` | | +| ingress.enabled | bool | `true` | | +| ingress.path | string | `"/"` | | +| ingress.stub_backend.service.name | string | `"ph-ee-connector-channel"` | | +| ingress.stub_backend.service.port.number | int | `82` | | +| ingress.tls[0].hosts | string | `"notifications.sandbox.mifos.io"` | | +| ingress.tls[1].secretName | string | `"sandbox-secret"` | | +| limits.cpu | string | `"500m"` | | +| limits.memory | string | `"512M"` | | +| livenessProbe.httpGet.path | string | `"/actuator/health/liveness"` | | +| livenessProbe.httpGet.port | int | `8080` | | +| livenessProbe.initialDelaySeconds | int | `20` | | +| livenessProbe.periodSeconds | int | `30` | | +| notifications.NOTIFICATION_FAILURE_ENABLED | string | `"false"` | | +| notifications.NOTIFICATION_SUCCESS_ENABLED | string | `"false"` | | +| operations.authEnabled | bool | `false` | | +| operations.url | string | `"http://ops-bk.sandbox.mifos.io/api/v1"` | | +| readinessProbe.httpGet.path | string | `"/actuator/health/readiness"` | | +| readinessProbe.httpGet.port | int | `8080` | | +| readinessProbe.initialDelaySeconds | int | `20` | | +| readinessProbe.periodSeconds | int | `30` | | +| redis.host | string | `"127.0.0.1"` | | +| redis.idempotency.apiList | string | `"/channel/transfer,/channel/collection,/channel/gsma/transaction,/channel/transactionRequest"` | | +| redis.idempotency.enabled | bool | `true` | | +| redis.idempotency.keyFormat | string | `"clientCorrelationId_tenant_api"` | | +| redis.password | string | `""` | | +| redis.port | int | `6379` | | +| requests.cpu | string | `"100m"` | | +| requests.memory | string | `"256M"` | | +| secret.apiversion | string | `"v1"` | | +| service.apiversion | string | `"v1"` | | +| stub_hostname | string | `"channel-gsma.sandbox.mifos.io"` | | +| tenantPrimary.clientId | string | `"mifos"` | | +| tenantPrimary.clientSecret | string | `"password"` | | +| tenantPrimary.tenant | string | `"rhino"` | | +| tenantSecondary.clientId | string | `"mifos"` | | +| tenantSecondary.clientSecret | string | `"password"` | | +| tenantSecondary.tenant | string | `"gorilla"` | | +| wildcardhostname | string | `"channel.sandbox.mifos.io"` | | + +---------------------------------------------- +Autogenerated from chart metadata using [helm-docs v1.11.0](https://github.com/norwoodj/helm-docs/releases/v1.11.0) diff --git a/ph-ee-env-labs/helm/dpga-compliance-barebone/dpga-connector-channel/templates/deployment.yaml b/ph-ee-env-labs/helm/dpga-compliance-barebone/dpga-connector-channel/templates/deployment.yaml new file mode 100644 index 000000000..7c946e29f --- /dev/null +++ b/ph-ee-env-labs/helm/dpga-compliance-barebone/dpga-connector-channel/templates/deployment.yaml @@ -0,0 +1,32 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: dpga-connector-channel + labels: + app: dpga-connector-channel +spec: + replicas: 1 + selector: + matchLabels: + app: dpga-connector-channel + template: + metadata: + labels: + app: dpga-connector-channel + annotations: + kubernetes.io/ingress.class: "nginx" + nginx.ingress.kubernetes.io/backend-protocol: "HTTP" + spec: + containers: + - name: ph-ee-connector-channel + image: "{{ .Values.image }}" + ports: + - containerPort: 8081 + imagePullPolicy: "{{ .Values.imagePullPolicy }}" + resources: + limits: + memory: "{{ .Values.limits.memory }}" + cpu: "{{ .Values.limits.cpu }}" + requests: + memory: "{{ .Values.requests.memory }}" + cpu: "{{ .Values.requests.cpu }}" diff --git a/ph-ee-env-labs/helm/dpga-compliance-barebone/dpga-connector-channel/templates/ingress.yaml b/ph-ee-env-labs/helm/dpga-compliance-barebone/dpga-connector-channel/templates/ingress.yaml new file mode 100644 index 000000000..fba8448ad --- /dev/null +++ b/ph-ee-env-labs/helm/dpga-compliance-barebone/dpga-connector-channel/templates/ingress.yaml @@ -0,0 +1,22 @@ +{{- if .Values.ingress.enabled }} +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: dpga-connector-channel +{{- with .Values.ingress.annotations }} + annotations: +{{ toYaml . | indent 4 }} +{{- end }} +spec: + rules: + - host: "{{ .Values.ingress.hostname }}" + http: + paths: + - path: "{{ .Values.ingress.path }}" + pathType: Prefix + backend: + service: + name: dpga-connector-channel + port: + number: 80 +{{- end }} diff --git a/ph-ee-env-labs/helm/dpga-compliance-barebone/dpga-connector-channel/templates/service.yaml b/ph-ee-env-labs/helm/dpga-compliance-barebone/dpga-connector-channel/templates/service.yaml new file mode 100644 index 000000000..842ddf226 --- /dev/null +++ b/ph-ee-env-labs/helm/dpga-compliance-barebone/dpga-connector-channel/templates/service.yaml @@ -0,0 +1,18 @@ +{{- if .Values.enabled -}} +apiVersion: {{ .Values.service.apiversion }} +kind: Service +metadata: + labels: + app: dpga-connector-channel + name: dpga-connector-channel +spec: + ports: + - name: port + port: 80 + protocol: TCP + targetPort: 8081 + selector: + app: dpga-connector-channel + sessionAffinity: None + type: ClusterIP +{{- end }} \ No newline at end of file diff --git a/ph-ee-env-labs/helm/dpga-compliance-barebone/dpga-connector-channel/values.yaml b/ph-ee-env-labs/helm/dpga-compliance-barebone/dpga-connector-channel/values.yaml new file mode 100644 index 000000000..181bb64a0 --- /dev/null +++ b/ph-ee-env-labs/helm/dpga-compliance-barebone/dpga-connector-channel/values.yaml @@ -0,0 +1,44 @@ +service: + apiversion: "v1" + +secret: + apiversion: "v1" + +configmap: + apiversion: "v1" + +enabled: true +image: "419830066942.dkr.ecr.ap-south-1.amazonaws.com/dpga-connector-channel:latest" +imageTag: latest +imagePullPolicy: "Always" +SPRING_PROFILES_ACTIVE: "application" +#LOGGING_LEVEL_ROOT: "INFO" +DFSPIDS: "lion,gorilla,rhino" +limits: + cpu: "500m" + memory: "512M" +requests: + cpu: "100m" + memory: "256M" +livenessProbe: + httpGet: + path: /actuator/health/liveness + port: 8443 + initialDelaySeconds: 20 + periodSeconds: 30 +readinessProbe: + httpGet: + path: /actuator/health/readiness + port: 8443 + initialDelaySeconds: 20 + periodSeconds: 30 +## Enabling this will publicly expose your channel instance. +## Only enable this if you have security enabled on your cluster +ingress: + enabled: true + hostname: "dpga-connector-chanel.sandbox.fynarfin.io" + path: "/" + wildcardhostname: "*.sandbox.fynarfin.io" + annotations: + kubernetes.io/ingress.class: "nginx" + nginx.ingress.kubernetes.io/backend-protocol: "HTTP" diff --git a/ph-ee-env-labs/helm/dpga-compliance-barebone/netflix-conductor/Chart.yaml b/ph-ee-env-labs/helm/dpga-compliance-barebone/netflix-conductor/Chart.yaml new file mode 100644 index 000000000..7056db4a4 --- /dev/null +++ b/ph-ee-env-labs/helm/dpga-compliance-barebone/netflix-conductor/Chart.yaml @@ -0,0 +1,6 @@ +name: netflix-conductor +description: A generated Helm Chart for docker-compose from Skippbox Kompose +version: 0.0.1 +apiVersion: v2 +keywords: + - netflix-conductor \ No newline at end of file diff --git a/ph-ee-env-labs/helm/dpga-compliance-barebone/netflix-conductor/README.md b/ph-ee-env-labs/helm/dpga-compliance-barebone/netflix-conductor/README.md new file mode 100644 index 000000000..1e7cd3f04 --- /dev/null +++ b/ph-ee-env-labs/helm/dpga-compliance-barebone/netflix-conductor/README.md @@ -0,0 +1 @@ +Basic Helm Chart for Netflix Conductor diff --git a/ph-ee-env-labs/helm/dpga-compliance-barebone/netflix-conductor/templates/conductor-server-deployment.yaml b/ph-ee-env-labs/helm/dpga-compliance-barebone/netflix-conductor/templates/conductor-server-deployment.yaml new file mode 100644 index 000000000..00438db4a --- /dev/null +++ b/ph-ee-env-labs/helm/dpga-compliance-barebone/netflix-conductor/templates/conductor-server-deployment.yaml @@ -0,0 +1,133 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: conductor-server + namespace: paymenthub-dpg + labels: + app: conductor-server +spec: + replicas: 1 + selector: + matchLabels: + app: conductor-server + template: + metadata: + labels: + app: conductor-server + spec: + containers: + - env: + - name: CONFIG_PROP + value: config-postgres.properties + image: anover/conductor:server + imagePullPolicy: Always + name: conductor-server + ports: + - containerPort: 8080 + hostPort: 8080 + volumeMounts: + - name: db-config + mountPath: /app/config/config-postgres.properties + subPath: config-postgres.properties + livenessProbe: + httpGet: + path: /actuator/health/liveness + port: 8080 + scheme: HTTP + initialDelaySeconds: 20 + periodSeconds: 30 + readinessProbe: + httpGet: + path: /actuator/health/readiness + port: 8080 + scheme: HTTP + initialDelaySeconds: 20 + periodSeconds: 30 + volumes: + - name: db-config + configMap: + name: server-db-config +--- +kind: ConfigMap +apiVersion: v1 +metadata: + name: server-db-config + namespace: paymenthub-dpg +data: + config-postgres.properties: | + # Servers. + conductor.grpc-server.enabled=false + + # Database persistence type. + conductor.db.type=postgres + conductor.queue.type=postgres + + spring.datasource.url=jdbc:postgresql://postgres:5432/conductor + spring.datasource.username=conductor + spring.datasource.password=conductor + + # Hikari pool sizes are -1 by default and prevent startup + spring.datasource.hikari.maximum-pool-size=10 + spring.datasource.hikari.minimum-idle=2 + + # Elastic search instance indexing is enabled. + conductor.indexing.enabled=true + + # Transport address to elasticsearch + conductor.elasticsearch.url=http://es:9200 + + # Name of the elasticsearch cluster + conductor.elasticsearch.indexName=conductor + + conductor.elasticsearch.clusterHealthColor=yellow + + conductor.workflow-status-listener.type=custom + conductor.task-status-listener.type=custom + + spring.kafka.bootstrap-servers=kafka:9092 + + # Load sample kitchen sink workflow + # loadSample=true +--- +apiVersion: v1 +kind: Service +metadata: + name: conductor-server + namespace: paymenthub-dpg +spec: + selector: + app: conductor-server + type: ClusterIP + ports: + - name: http + protocol: TCP + port: 8080 + targetPort: 8080 +--- + +{{- if .Values.conductorserver.ingress.enabled }} +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: conductor-server + annotations: +{{- if .Values.conductorserver.ingress.annotations }} +{{ toYaml .Values.conductorserver.ingress.annotations | indent 4 }} +{{- end }} +spec: + rules: + - host: "{{ .Values.conductorserver.ingress.hostname }}" + http: + paths: + - path: "{{ .Values.conductorserver.ingress.path }}" + pathType: Prefix + backend: + service: + name: conductor-server + port: + number: 8080 +# tls: +# - hosts: +# - "{{ .Values.conductorserver.ingress.wildcardhostname }}" +# secretName: "{{ .Values.tls }}" +{{- end }} \ No newline at end of file diff --git a/ph-ee-env-labs/helm/dpga-compliance-barebone/netflix-conductor/templates/conductor-ui-deployment.yaml b/ph-ee-env-labs/helm/dpga-compliance-barebone/netflix-conductor/templates/conductor-ui-deployment.yaml new file mode 100644 index 000000000..d50328bc4 --- /dev/null +++ b/ph-ee-env-labs/helm/dpga-compliance-barebone/netflix-conductor/templates/conductor-ui-deployment.yaml @@ -0,0 +1,67 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: conductor-ui + namespace: paymenthub-dpg +spec: + replicas: 1 + selector: + matchLabels: + app: conductor-ui + template: + metadata: + labels: + app: conductor-ui + spec: + containers: + - env: + - name: WF_SERVER + value: "http://conductor-server.paymenthub-dpg.svc.cluster.local:8080/" + image: anover/conductor:ui + imagePullPolicy: Always + name: conductor-ui + ports: + - containerPort: 5000 + hostPort: 5000 +--- +apiVersion: v1 +kind: Service +metadata: + name: conductor-ui + namespace: paymenthub-dpg +spec: + ports: + - port: 80 + targetPort: 5000 + protocol: TCP + type: NodePort + selector: + app: conductor-ui +--- + +{{- if .Values.conductorui.ingress.enabled }} +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: conductor-ui + annotations: +{{- if .Values.conductorui.ingress.annotations }} +{{ toYaml .Values.conductorui.ingress.annotations | indent 4 }} +{{- end }} +spec: + rules: + - host: "{{ .Values.conductorui.ingress.hostname }}" + http: + paths: + - path: "{{ .Values.conductorui.ingress.path }}" + pathType: Prefix + backend: + service: + name: conductor-ui + port: + number: 80 + tls: + - hosts: + - "{{ .Values.conductorui.ingress.wildcardhostname }}" + secretName: "{{ .Values.tls }}" +{{- end }} diff --git a/ph-ee-env-labs/helm/dpga-compliance-barebone/netflix-conductor/values.yaml b/ph-ee-env-labs/helm/dpga-compliance-barebone/netflix-conductor/values.yaml new file mode 100644 index 000000000..1b212c4a9 --- /dev/null +++ b/ph-ee-env-labs/helm/dpga-compliance-barebone/netflix-conductor/values.yaml @@ -0,0 +1,95 @@ +ingress: + enabled: true + +elasticsearch: + enabled: true + replicas: 1 + protocol: http + fullnameOverride: "es" + clusterName: "elasticsearch" + minimumMasterNodes: 1 + esConfig: + elasticsearch.yml: | + xpack.security.enabled: false + transport.host: 0.0.0.0 +# extraEnvs: +# - name: ES_JAVA_OPTS +# value: "-Xms512m -Xmx1024m" + config: + transport.host: 0.0.0.0 + discovery.type: single-node + xpack.security.enabled: "false" + healthCheckPath: / + healthCheckPort: 9200 + persistence: + enabled: true + resources: + requests: + cpu: "100m" + memory: "1024M" + limits: + cpu: "1000m" + memory: "1024M" + volumeClaimTemplate: + accessModes: [ "ReadWriteOnce" ] + storageClassName: "gp2" + resources: + requests: + storage: 10Gi + + +redis: + enabled: true + fullnameOverride: "rs" + replica: + replicaCount: 0 + usePassword: false + auth: + enabled: false + +global: + postgresql: + auth: + postgresPassword: "conductor" + username: "conductor" + password: "conductor" + +postgresql: + enabled: true + fullnameOverride: "postgres" + postgresUser: conductor + postgresPassword: conductor + persistence: + enabled: true + primary: + initdb: + scripts: + setup.sql: |- + CREATE DATABASE conductor; + GRANT ALL PRIVILEGES ON `conductor`.* TO 'conductor'; + GRANT ALL ON *.* TO 'root'@'%'; + +networks: + internal: {} + +tls: "" + +conductorui: + ingress: + enabled: true + hostname: "conductor-ui.sandbox.fynarfin.io" + path: "/" + wildcardhostname: "*.sandbox.fynarfin.io" + annotations: + kubernetes.io/ingress.class: "nginx" + nginx.ingress.kubernetes.io/backend-protocol: "HTTP" + +conductorserver: + ingress: + enabled: true + hostname: "conductor-server.sandbox.fynarfin.io" + path: "/" + wildcardhostname: "*.sandbox.fynarfin.io" + annotations: + kubernetes.io/ingress.class: "nginx" + nginx.ingress.kubernetes.io/backend-protocol: "HTTP" \ No newline at end of file diff --git a/ph-ee-env-labs/helm/dpga-compliance-barebone/operations-app/Chart.yaml b/ph-ee-env-labs/helm/dpga-compliance-barebone/operations-app/Chart.yaml new file mode 100644 index 000000000..c6edb4134 --- /dev/null +++ b/ph-ee-env-labs/helm/dpga-compliance-barebone/operations-app/Chart.yaml @@ -0,0 +1,5 @@ +apiVersion: v1 +description: ph-ee-operations-app +name: operations_app +version: 1.0.0 +appVersion: "1.0.0" \ No newline at end of file diff --git a/ph-ee-env-labs/helm/dpga-compliance-barebone/operations-app/README.md b/ph-ee-env-labs/helm/dpga-compliance-barebone/operations-app/README.md new file mode 100644 index 000000000..e931e10c4 --- /dev/null +++ b/ph-ee-env-labs/helm/dpga-compliance-barebone/operations-app/README.md @@ -0,0 +1,48 @@ +# operations_app + +![Version: 1.0.0](https://img.shields.io/badge/Version-1.0.0-informational?style=flat-square) ![AppVersion: 1.0.0](https://img.shields.io/badge/AppVersion-1.0.0-informational?style=flat-square) + +ph-ee-operations-app + +## Values + +| Key | Type | Default | Description | +|-----|------|---------|-------------| +| SPRING_PROFILES_ACTIVE | string | `""` | | +| configmap.apiversion | string | `"v1"` | | +| deployment.annotations.deployTime | string | `"{{ .Values.deployTime }}"` | | +| deployment.apiVersion | string | `"apps/v1"` | | +| enabled | bool | `true` | | +| hostname | string | `"ops-bk.sandbox.mifos.io"` | | +| image | string | `""` | | +| imageTag | string | `""` | | +| ingress.annotations."kubernetes.io/ingress.class" | string | `"nginx"` | | +| ingress.annotations."nginx.ingress.kubernetes.io/configuration-snippet" | string | `"more_set_headers \"Access-Control-Allow-Origin: *\";\nmore_set_headers \"Platform-TenantId: *\";\n"` | | +| ingress.annotations."nginx.ingress.kubernetes.io/cors-allow-credentials" | string | `"true"` | | +| ingress.annotations."nginx.ingress.kubernetes.io/cors-allow-headers" | string | `"DNT,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization,Platform-TenantId"` | | +| ingress.annotations."nginx.ingress.kubernetes.io/cors-allow-methods" | string | `"PUT, GET, POST, OPTIONS, DELETE, PATCH"` | | +| ingress.annotations."nginx.ingress.kubernetes.io/enable-cors" | string | `"true"` | | +| ingress.apiversion | string | `"networking.k8s.io/v1"` | | +| ingress.backend.service.name | string | `"ph-ee-operations-app"` | | +| ingress.backend.service.port.number | int | `80` | | +| ingress.className | string | `"kong"` | | +| ingress.enabled | bool | `true` | | +| ingress.path | string | `"/"` | | +| ingress.tls[0].hosts | string | `"ops-bk.sandbox.mifos.io"` | | +| ingress.tls[1].secretName | string | `"sandbox-secret"` | | +| limits.cpu | string | `"500m"` | | +| limits.memory | string | `"512M"` | | +| requests.cpu | string | `"100m"` | | +| requests.memory | string | `"256M"` | | +| secret.apiversion | string | `"v1"` | | +| secret.datasource.host | string | `"operationsmysql"` | | +| secret.datasource.password | string | `"password"` | | +| secret.datasource.port | int | `3306` | | +| secret.datasource.schema | string | `"tenants"` | | +| secret.datasource.username | string | `"mifos"` | | +| service.apiversion | string | `"v1"` | | +| tenants | string | `""` | | +| wildcardhostname | string | `"ops-bk.sandbox.mifos.io"` | | + +---------------------------------------------- +Autogenerated from chart metadata using [helm-docs v1.11.0](https://github.com/norwoodj/helm-docs/releases/v1.11.0) diff --git a/ph-ee-env-labs/helm/dpga-compliance-barebone/operations-app/templates/deployment.yaml b/ph-ee-env-labs/helm/dpga-compliance-barebone/operations-app/templates/deployment.yaml new file mode 100644 index 000000000..a9ea5d398 --- /dev/null +++ b/ph-ee-env-labs/helm/dpga-compliance-barebone/operations-app/templates/deployment.yaml @@ -0,0 +1,87 @@ +{{- if .Values.enabled -}} + +apiVersion: apps/v1 +kind: Deployment +metadata: + name: ph-ee-operations-app + labels: + app: ph-ee-operations-app +spec: + replicas: {{ .Values.replicas }} + selector: + matchLabels: + app: ph-ee-operations-app + template: + metadata: + labels: + app: ph-ee-operations-app + annotations: +{{- if .Values.deployment.annotations }} +{{ toYaml .Values.deployment.annotations | indent 8 }} +{{- end }} + spec: + containers: + - name: ph-ee-operations-app + image: "{{ .Values.image }}" + imagePullPolicy: "{{ .Values.global.imagePullPolicy }}" + ports: + - containerPort: 5000 + readinessProbe: + httpGet: + path: /oauth/token_key + port: 5000 + periodSeconds: 30 + timeoutSeconds: 5 + resources: + limits: + memory: "{{ .Values.limits.memory }}" + cpu: "{{ .Values.limits.cpu }}" + requests: + memory: "{{ .Values.requests.memory }}" + cpu: "{{ .Values.requests.cpu }}" + env: + - name: "FINERACT_DATASOURCE_CORE_USERNAME" + value: "{{ .Values.datasource.username }}" + - name: "FINERACT_DATASOURCE_CORE_PASSWORD" + valueFrom: + secretKeyRef: + name: "operations-app-secret" + key: "database-password" + - name: "FINERACT_DATASOURCE_CORE_HOST" + value: "{{ .Values.datasource.host }}" + - name: "FINERACT_DATASOURCE_CORE_PORT" + value: "{{ .Values.datasource.port }}" + - name: "FINERACT_DATASOURCE_CORE_SCHEMA" + value: "{{ .Values.datasource.schema }}" + - name: "SPRING_PROFILES_ACTIVE" + value: "{{ .Values.global.SPRING_PROFILES_ACTIVE }}" + - name: "TOKEN_CLIENT_CHANNEL_SECRET" + value: "{{ .Values.token_client_channel_secret }}" + - name: "TENANTS" + value: "{{ .Values.global.tenants }}" + - name: "LOGGING_LEVEL_ROOT" + value: "{{ .Values.global.LOGGING_LEVEL_ROOT }}" + - name: "LOGGING_PATTERN_CONSOLE" + value: "{{ .Values.global.LOGGING_PATTERN_CONSOLE }}" +{{- if .Values.extraEnvs | default .Values.deployment.extraEnvs }} +{{ toYaml ( .Values.extraEnvs | default .Values.deployment.extraEnvs ) | indent 10 }} +{{- end }} + envFrom: {{ toYaml ( .Values.envFrom | default .Values.deployment.envFrom ) | nindent 12 }} + securityContext: {{ toYaml ( .Values.podSecurityContext | default .Values.deployment.securityContext ) | nindent 12 }} + + volumeMounts: + - name: ph-ee-config + mountPath: "/config" + initContainers: + - name: wait-db + image: jwilder/dockerize + imagePullPolicy: IfNotPresent + args: + - -timeout=120s + - -wait + - tcp://{{ .Values.secret.datasource.host }}:3306 + volumes: + - name: ph-ee-config + configMap: + name: ph-ee-config +{{- end }} \ No newline at end of file diff --git a/ph-ee-env-labs/helm/dpga-compliance-barebone/operations-app/templates/ingress.yaml b/ph-ee-env-labs/helm/dpga-compliance-barebone/operations-app/templates/ingress.yaml new file mode 100644 index 000000000..db9ba7319 --- /dev/null +++ b/ph-ee-env-labs/helm/dpga-compliance-barebone/operations-app/templates/ingress.yaml @@ -0,0 +1,49 @@ +{{- if .Values.ingress.enabled -}} +{{- $pathtype := .Values.ingress.pathtype -}} +{{- $ingressPath := .Values.ingress.path -}} +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: ph-ee-dpg-operations-app + labels: + app: {{ .Chart.Name }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +{{- with .Values.ingress.annotations }} + annotations: +{{ toYaml . | indent 4 }} +{{- end }} +spec: + {{- if .Values.ingress.className }} + ingressClassName: {{ .Values.ingress.className | quote }} + {{- end }} +{{- if .Values.ingress.tls }} + tls: + {{- if .ingressPath }} + {{- range .Values.ingress.tls }} + - hosts: + {{- range .hosts }} + - {{ . }} + {{- end }} + secretName: {{ .secretName }} + {{- end }} +{{- else }} +{{ toYaml .Values.ingress.tls | indent 4 }} + {{- end }} +{{- end}} + rules: + {{- range .Values.ingress.hosts }} + - host: {{ .host }} + http: + paths: + {{- range .paths }} + - path: {{ .path }} + pathType: {{ $pathtype }} + backend: + service: + name: {{ .backend.service.name}} + port: + number: {{ .backend.service.port.number}} + {{- end }} + {{- end }} + {{- end }} diff --git a/ph-ee-env-labs/helm/dpga-compliance-barebone/operations-app/templates/secret.yaml b/ph-ee-env-labs/helm/dpga-compliance-barebone/operations-app/templates/secret.yaml new file mode 100644 index 000000000..6d2f1932c --- /dev/null +++ b/ph-ee-env-labs/helm/dpga-compliance-barebone/operations-app/templates/secret.yaml @@ -0,0 +1,9 @@ +{{- if .Values.enabled -}} +apiVersion: {{ .Values.secret.apiversion }} +kind: Secret +metadata: + name: operations-app-secret +type: Opaque +data: + database-password: {{ .Values.datasource.password | b64enc }} +{{- end }} \ No newline at end of file diff --git a/ph-ee-env-labs/helm/dpga-compliance-barebone/operations-app/templates/service.yaml b/ph-ee-env-labs/helm/dpga-compliance-barebone/operations-app/templates/service.yaml new file mode 100644 index 000000000..60fcc7fb4 --- /dev/null +++ b/ph-ee-env-labs/helm/dpga-compliance-barebone/operations-app/templates/service.yaml @@ -0,0 +1,18 @@ +{{- if .Values.enabled -}} +apiVersion: {{ .Values.service.apiversion }} +kind: Service +metadata: + labels: + app: ph-ee-operations-app + name: ph-ee-operations-app +spec: + ports: + - name: port + port: 80 + protocol: TCP + targetPort: 5000 + selector: + app: ph-ee-operations-app + sessionAffinity: None + type: ClusterIP +{{- end }} \ No newline at end of file diff --git a/ph-ee-env-labs/helm/dpga-compliance-barebone/operations-app/values.yaml b/ph-ee-env-labs/helm/dpga-compliance-barebone/operations-app/values.yaml new file mode 100644 index 000000000..20e98a776 --- /dev/null +++ b/ph-ee-env-labs/helm/dpga-compliance-barebone/operations-app/values.yaml @@ -0,0 +1,44 @@ +service: + apiversion: "v1" + +configmap: + apiversion: "v1" + +enabled: true +image: "" +imageTag: "" +SPRING_PROFILES_ACTIVE: "" +tenants: "" +secret: + apiversion: "v1" + datasource: + username: "mifos" + password: "password" + host: "operationsmysql" + port: 3306 + schema: "tenants" +limits: + cpu: "500m" + memory: "512M" +requests: + cpu: "100m" + memory: "256M" +# Enabling this will publicly expose your Elasticsearch instance. +# Only enable this if you have security enabled on your cluster +ingress: + enabled: true + annotations: {} + # kubernetes.io/ingress.class: "nginx" + pathtype: ImplementationSpecific + hosts: + - host: "" + paths: + - path: / + tls: [] + # - secretName: sandbox-secret + # hosts: + # - chart-example.local +deployment: + apiVersion: "apps/v1" + annotations: + deployTime: "{{ .Values.deployTime }}" \ No newline at end of file diff --git a/ph-ee-env-labs/helm/dpga-compliance-barebone/operations-web/Chart.yaml b/ph-ee-env-labs/helm/dpga-compliance-barebone/operations-web/Chart.yaml new file mode 100644 index 000000000..f8bb2b28d --- /dev/null +++ b/ph-ee-env-labs/helm/dpga-compliance-barebone/operations-web/Chart.yaml @@ -0,0 +1,5 @@ +apiVersion: v1 +description: ph-ee-operations-web +name: operations_web +version: 1.0.0 +appVersion: "1.0.0" \ No newline at end of file diff --git a/ph-ee-env-labs/helm/dpga-compliance-barebone/operations-web/templates/configmap.yaml b/ph-ee-env-labs/helm/dpga-compliance-barebone/operations-web/templates/configmap.yaml new file mode 100644 index 000000000..e5ef74dd6 --- /dev/null +++ b/ph-ee-env-labs/helm/dpga-compliance-barebone/operations-web/templates/configmap.yaml @@ -0,0 +1,13 @@ +apiVersion: {{ .Values.configmap.apiversion }} +kind: ConfigMap +data: + configuration.properties: | + oauth.enabled false + oauth.basicAuth true + oauth.basicAuthToken Y2xpZW50Og== + oauth.serverUrl https://{{ .Values.configmap.identity.hostname }} + serverUrl https://{{ .Values.configmap.hostname }} + auth.enabled false + auth.tenant phdefault +metadata: + name: ph-ee-operations-web-config \ No newline at end of file diff --git a/ph-ee-env-labs/helm/dpga-compliance-barebone/operations-web/templates/deployment.yaml b/ph-ee-env-labs/helm/dpga-compliance-barebone/operations-web/templates/deployment.yaml new file mode 100644 index 000000000..fb97ce510 --- /dev/null +++ b/ph-ee-env-labs/helm/dpga-compliance-barebone/operations-web/templates/deployment.yaml @@ -0,0 +1,44 @@ +{{- if .Values.enabled -}} + +apiVersion: apps/v1 +kind: Deployment +metadata: + name: ph-ee-operations-web + labels: + app: ph-ee-operations-web +spec: + replicas: {{ .Values.replicas }} + selector: + matchLabels: + app: ph-ee-operations-web + template: + metadata: + labels: + app: ph-ee-operations-web + annotations: +{{- if .Values.deployment.annotations }} +{{ toYaml .Values.deployment.annotations | indent 8 }} +{{- end }} + spec: + containers: + - name: ph-ee-operations-web + image: "{{ .Values.image }}" + imagePullPolicy: "{{ .Values.global.imagePullPolicy }}" + ports: + - containerPort: 4200 + resources: + limits: + memory: "{{ .Values.limits.memory }}" + cpu: "{{ .Values.limits.cpu }}" + requests: + memory: "{{ .Values.requests.memory }}" + cpu: "{{ .Values.requests.cpu }}" + volumeMounts: +{{- if .Values.deployment.config }} +{{ toYaml .Values.deployment.config | indent 12 }} +{{- end }} + volumes: + - name: ph-ee-operations-web-config + configMap: + name: ph-ee-operations-web-config +{{- end }} \ No newline at end of file diff --git a/ph-ee-env-labs/helm/dpga-compliance-barebone/operations-web/templates/ingress.yaml b/ph-ee-env-labs/helm/dpga-compliance-barebone/operations-web/templates/ingress.yaml new file mode 100644 index 000000000..bc3bb407d --- /dev/null +++ b/ph-ee-env-labs/helm/dpga-compliance-barebone/operations-web/templates/ingress.yaml @@ -0,0 +1,49 @@ +{{- if .Values.ingress.enabled -}} +{{- $pathtype := .Values.ingress.pathtype -}} +{{- $ingressPath := .Values.ingress.path -}} +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: ph-ee-dpg-operations-web + labels: + app: {{ .Chart.Name }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +{{- with .Values.ingress.annotations }} + annotations: +{{ toYaml . | indent 4 }} +{{- end }} +spec: + {{- if .Values.ingress.className }} + ingressClassName: {{ .Values.ingress.className | quote }} + {{- end }} +{{- if .Values.ingress.tls }} + tls: + {{- if .ingressPath }} + {{- range .Values.ingress.tls }} + - hosts: + {{- range .hosts }} + - {{ . }} + {{- end }} + secretName: {{ .secretName }} + {{- end }} +{{- else }} +{{ toYaml .Values.ingress.tls | indent 4 }} + {{- end }} +{{- end}} + rules: + {{- range .Values.ingress.hosts }} + - host: {{ .host }} + http: + paths: + {{- range .paths }} + - path: {{ .path }} + pathType: {{ $pathtype }} + backend: + service: + name: {{ .backend.service.name}} + port: + number: {{ .backend.service.port.number}} + {{- end }} + {{- end }} + {{- end }} diff --git a/ph-ee-env-labs/helm/dpga-compliance-barebone/operations-web/templates/service.yaml b/ph-ee-env-labs/helm/dpga-compliance-barebone/operations-web/templates/service.yaml new file mode 100644 index 000000000..2d2a3d174 --- /dev/null +++ b/ph-ee-env-labs/helm/dpga-compliance-barebone/operations-web/templates/service.yaml @@ -0,0 +1,12 @@ +{{- if .Values.enabled -}} +apiVersion: {{ .Values.service.apiversion }} +kind: Service +metadata: + name: ph-ee-operations-web +spec: + selector: + app: ph-ee-operations-web + ports: + - protocol: TCP + port: 4200 +{{- end }} \ No newline at end of file diff --git a/ph-ee-env-labs/helm/dpga-compliance-barebone/operations-web/values.yaml b/ph-ee-env-labs/helm/dpga-compliance-barebone/operations-web/values.yaml new file mode 100644 index 000000000..8e6ec2348 --- /dev/null +++ b/ph-ee-env-labs/helm/dpga-compliance-barebone/operations-web/values.yaml @@ -0,0 +1,42 @@ +service: + apiversion: "v1" + +secret: + apiversion: "v1" + +enabled: true +image: "" +imageTag: "" +SPRING_PROFILES_ACTIVE: "bb" +hostname: "ops.sandbox.mifos.io" +webhost: "ops.sandbox.mifos.io" +limits: + cpu: "500m" + memory: "512M" +requests: + cpu: "100m" + memory: "256M" +# Enabling this will publicly expose your Elasticsearch instance. +# Only enable this if you have security enabled on your cluster +ingress: + enabled: false + annotations: {} + # kubernetes.io/ingress.class: "nginx" + pathtype: ImplementationSpecific + hosts: + - host: "" + paths: + - path: / + tls: [] + # - secretName: sandbox-secret + # hosts: + # - chart-example.local +deployment: + apiVersion: "apps/v1" + config: {} + +configmap: + apiversion: "v1" + hostname: "ops.sandbox.mifos.io" + identity: + hostname: "ops-bk.sandbox.mifos.io" \ No newline at end of file diff --git a/ph-ee-env-labs/helm/dpga-compliance-barebone/ph-ee-dpg-importer-rdbms/Chart.yaml b/ph-ee-env-labs/helm/dpga-compliance-barebone/ph-ee-dpg-importer-rdbms/Chart.yaml new file mode 100644 index 000000000..f86132056 --- /dev/null +++ b/ph-ee-env-labs/helm/dpga-compliance-barebone/ph-ee-dpg-importer-rdbms/Chart.yaml @@ -0,0 +1,5 @@ +apiVersion: v1 +description: ph-ee-dpg-importer-rdbms +name: dpg-importer-rdbms +version: 1.0.0 +appVersion: "1.0.0" diff --git a/ph-ee-env-labs/helm/dpga-compliance-barebone/ph-ee-dpg-importer-rdbms/README.md b/ph-ee-env-labs/helm/dpga-compliance-barebone/ph-ee-dpg-importer-rdbms/README.md new file mode 100644 index 000000000..5ee0325b5 --- /dev/null +++ b/ph-ee-env-labs/helm/dpga-compliance-barebone/ph-ee-dpg-importer-rdbms/README.md @@ -0,0 +1,67 @@ +# channel + +![Version: 1.0.0](https://img.shields.io/badge/Version-1.0.0-informational?style=flat-square) ![AppVersion: 1.0.0](https://img.shields.io/badge/AppVersion-1.0.0-informational?style=flat-square) + +ph-ee-connector-channel + +## Values + +| Key | Type | Default | Description | +|-----|------|---------|-------------| +| DFSPIDS | string | `""` | | +| LOGGING_LEVEL_ROOT | string | `"INFO"` | | +| SPRING_PROFILES_ACTIVE | string | `"bb,tenants"` | | +| configmap.apiversion | string | `"v1"` | | +| deployment.annotations.deployTime | string | `"{{ .Values.deployTime }}"` | | +| deployment.apiVersion | string | `"apps/v1"` | | +| enabled | bool | `true` | | +| hostname | string | `"channel.sandbox.mifos.io"` | | +| image | string | `""` | | +| imagePullPolicy | string | `"Always"` | | +| imageTag | string | `"latest"` | | +| ingress.annotations."kubernetes.io/ingress.class" | string | `"nginx"` | | +| ingress.apiversion | string | `"networking.k8s.io/v1"` | | +| ingress.backend.service.name | string | `"ph-ee-connector-channel"` | | +| ingress.backend.service.port.number | int | `80` | | +| ingress.className | string | `"nginx"` | | +| ingress.enabled | bool | `true` | | +| ingress.path | string | `"/"` | | +| ingress.stub_backend.service.name | string | `"ph-ee-connector-channel"` | | +| ingress.stub_backend.service.port.number | int | `82` | | +| ingress.tls[0].hosts | string | `"notifications.sandbox.mifos.io"` | | +| ingress.tls[1].secretName | string | `"sandbox-secret"` | | +| limits.cpu | string | `"500m"` | | +| limits.memory | string | `"512M"` | | +| livenessProbe.httpGet.path | string | `"/actuator/health/liveness"` | | +| livenessProbe.httpGet.port | int | `8080` | | +| livenessProbe.initialDelaySeconds | int | `20` | | +| livenessProbe.periodSeconds | int | `30` | | +| notifications.NOTIFICATION_FAILURE_ENABLED | string | `"false"` | | +| notifications.NOTIFICATION_SUCCESS_ENABLED | string | `"false"` | | +| operations.authEnabled | bool | `false` | | +| operations.url | string | `"http://ops-bk.sandbox.mifos.io/api/v1"` | | +| readinessProbe.httpGet.path | string | `"/actuator/health/readiness"` | | +| readinessProbe.httpGet.port | int | `8080` | | +| readinessProbe.initialDelaySeconds | int | `20` | | +| readinessProbe.periodSeconds | int | `30` | | +| redis.host | string | `"127.0.0.1"` | | +| redis.idempotency.apiList | string | `"/channel/transfer,/channel/collection,/channel/gsma/transaction,/channel/transactionRequest"` | | +| redis.idempotency.enabled | bool | `true` | | +| redis.idempotency.keyFormat | string | `"clientCorrelationId_tenant_api"` | | +| redis.password | string | `""` | | +| redis.port | int | `6379` | | +| requests.cpu | string | `"100m"` | | +| requests.memory | string | `"256M"` | | +| secret.apiversion | string | `"v1"` | | +| service.apiversion | string | `"v1"` | | +| stub_hostname | string | `"channel-gsma.sandbox.mifos.io"` | | +| tenantPrimary.clientId | string | `"mifos"` | | +| tenantPrimary.clientSecret | string | `"password"` | | +| tenantPrimary.tenant | string | `"rhino"` | | +| tenantSecondary.clientId | string | `"mifos"` | | +| tenantSecondary.clientSecret | string | `"password"` | | +| tenantSecondary.tenant | string | `"gorilla"` | | +| wildcardhostname | string | `"channel.sandbox.mifos.io"` | | + +---------------------------------------------- +Autogenerated from chart metadata using [helm-docs v1.11.0](https://github.com/norwoodj/helm-docs/releases/v1.11.0) diff --git a/ph-ee-env-labs/helm/dpga-compliance-barebone/ph-ee-dpg-importer-rdbms/templates/deployment.yaml b/ph-ee-env-labs/helm/dpga-compliance-barebone/ph-ee-dpg-importer-rdbms/templates/deployment.yaml new file mode 100644 index 000000000..cef90eed3 --- /dev/null +++ b/ph-ee-env-labs/helm/dpga-compliance-barebone/ph-ee-dpg-importer-rdbms/templates/deployment.yaml @@ -0,0 +1,44 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: ph-ee-dpg-importer-rdbms + labels: + app: ph-ee-dpg-importer-rdbms +spec: + replicas: 1 + selector: + matchLabels: + app: ph-ee-dpg-importer-rdbms + template: + metadata: + labels: + app: ph-ee-dpg-importer-rdbms + annotations: + kubernetes.io/ingress.class: "nginx" + nginx.ingress.kubernetes.io/backend-protocol: "HTTP" + spec: + containers: + - name: ph-ee-dpg-importer-rdbms + image: "{{ .Values.image }}" + env: + - name: kafka.brokers + value: {{ .Values.kafka.brokers }} + - name: kafka.consumer-group + value: {{ .Values.kafka.consumer_group }} + ports: + - containerPort: 8080 + imagePullPolicy: "{{ .Values.imagePullPolicy }}" + resources: + limits: + memory: "{{ .Values.limits.memory }}" + cpu: "{{ .Values.limits.cpu }}" + requests: + memory: "{{ .Values.requests.memory }}" + cpu: "{{ .Values.requests.cpu }}" +# volumeMounts: +# - name: importer-config +# mountPath: "/etc/config" +# volumes: +# - name: importer-config +# configMap: +# name: importer-config \ No newline at end of file diff --git a/ph-ee-env-labs/helm/dpga-compliance-barebone/ph-ee-dpg-importer-rdbms/templates/ingress.yaml b/ph-ee-env-labs/helm/dpga-compliance-barebone/ph-ee-dpg-importer-rdbms/templates/ingress.yaml new file mode 100644 index 000000000..2b7d0469c --- /dev/null +++ b/ph-ee-env-labs/helm/dpga-compliance-barebone/ph-ee-dpg-importer-rdbms/templates/ingress.yaml @@ -0,0 +1,22 @@ +{{- if .Values.ingress.enabled }} +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: ph-ee-dpg-importer-rdbms +{{- with .Values.ingress.annotations }} + annotations: +{{ toYaml . | indent 4 }} +{{- end }} +spec: + rules: + - host: "{{ .Values.ingress.hostname }}" + http: + paths: + - path: "{{ .Values.ingress.path }}" + pathType: Prefix + backend: + service: + name: ph-ee-dpg-importer-rdbms + port: + number: 80 +{{- end }} diff --git a/ph-ee-env-labs/helm/dpga-compliance-barebone/ph-ee-dpg-importer-rdbms/templates/service.yaml b/ph-ee-env-labs/helm/dpga-compliance-barebone/ph-ee-dpg-importer-rdbms/templates/service.yaml new file mode 100644 index 000000000..391224ea0 --- /dev/null +++ b/ph-ee-env-labs/helm/dpga-compliance-barebone/ph-ee-dpg-importer-rdbms/templates/service.yaml @@ -0,0 +1,18 @@ +{{- if .Values.enabled -}} +apiVersion: {{ .Values.service.apiversion }} +kind: Service +metadata: + labels: + app: ph-ee-dpg-importer-rdbms + name: ph-ee-dpg-importer-rdbms +spec: + ports: + - name: port + port: 80 + protocol: TCP + targetPort: 8080 + selector: + app: ph-ee-dpg-importer-rdbms + sessionAffinity: None + type: ClusterIP +{{- end }} \ No newline at end of file diff --git a/ph-ee-env-labs/helm/dpga-compliance-barebone/ph-ee-dpg-importer-rdbms/values.yaml b/ph-ee-env-labs/helm/dpga-compliance-barebone/ph-ee-dpg-importer-rdbms/values.yaml new file mode 100644 index 000000000..64a5bad18 --- /dev/null +++ b/ph-ee-env-labs/helm/dpga-compliance-barebone/ph-ee-dpg-importer-rdbms/values.yaml @@ -0,0 +1,48 @@ +service: + apiversion: "v1" + +secret: + apiversion: "v1" + +configmap: + apiversion: "v1" + +enabled: true +image: "419830066942.dkr.ecr.ap-south-1.amazonaws.com/ph-ee-dpg-importer-rdbms:trial" +imageTag: latest +imagePullPolicy: "Always" +SPRING_PROFILES_ACTIVE: "application" +#LOGGING_LEVEL_ROOT: "INFO" +DFSPIDS: "lion,gorilla,rhino" +limits: + cpu: "500m" + memory: "512M" +requests: + cpu: "100m" + memory: "256M" +livenessProbe: + httpGet: + path: /actuator/health/liveness + port: 8443 + initialDelaySeconds: 20 + periodSeconds: 30 +readinessProbe: + httpGet: + path: /actuator/health/readiness + port: 8443 + initialDelaySeconds: 20 + periodSeconds: 30 +## Enabling this will publicly expose your channel instance. +## Only enable this if you have security enabled on your cluster +ingress: + enabled: true + hostname: "ph-ee-dpg-importer-rdbms.sandbox.fynarfin.io" + path: "/" + wildcardhostname: "*.sandbox.fynarfin.io" + annotations: + kubernetes.io/ingress.class: "nginx" + nginx.ingress.kubernetes.io/backend-protocol: "HTTP" + +kafka: + brokers: "kafka:9092" + consumer_group: ch1 diff --git a/ph-ee-env-labs/helm/dpga-compliance-barebone/templates/config.yml b/ph-ee-env-labs/helm/dpga-compliance-barebone/templates/config.yml new file mode 100644 index 000000000..98f65ae95 --- /dev/null +++ b/ph-ee-env-labs/helm/dpga-compliance-barebone/templates/config.yml @@ -0,0 +1,6 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: ph-ee-config +data: +{{ (.Files.Glob "config/**.properties").AsConfig | nindent 2 }} diff --git a/ph-ee-env-labs/helm/dpga-compliance-barebone/values.yaml b/ph-ee-env-labs/helm/dpga-compliance-barebone/values.yaml new file mode 100644 index 000000000..f7ed5b4f6 --- /dev/null +++ b/ph-ee-env-labs/helm/dpga-compliance-barebone/values.yaml @@ -0,0 +1,349 @@ +global: + SPRING_PROFILES_ACTIVE: "bb" + imagePullPolicy: "Always" + LOGGING_LEVEL_ROOT: "INFO" + LOGGING_PATTERN_CONSOLE: "%d{dd-MM-yyyy HH:mm:ss.SSS} %magenta([%thread]) %highlight(%-5level) %logger.%M - %msg%n" + postgresql: + auth: + postgresPassword: "conductor" + username: "conductor" + password: "conductor" + +kafka: + enabled: true + fullnameOverride: kafka + global: + imageRegistry: docker.io + imagePullSecrets: [ ] + storageClass: "" + + provisioning: + enabled: true + topics: + - name: conductor + partitions: 1 + replicationFactor: 1 + + controller: + replicaCount: 3 + + listeners: + client: + protocol: PLAINTEXT + + controller: + protocol: PLAINTEXT + + interbroker: + protocol: PLAINTEXT + + external: + protocol: PLAINTEXT + + kraft: + clusterId: spDnn4oSr6DLKPx3cEheLp + +operationsmysql: + fullnameOverride: "operationsmysql" + image: + tag: "5.7" + debug: false + auth: + database: "tenants" + username: "mifos" + password: "password" + rootPassword: "ethieTieCh8ahv" + initdbScripts: + setup.sql: |- + CREATE DATABASE messagegateway; + CREATE DATABASE `rhino`; + CREATE DATABASE `gorilla`; + CREATE DATABASE `lion`; + CREATE DATABASE `identity_account_mapper`; + CREATE DATABASE `voucher_management`; + GRANT ALL PRIVILEGES ON `rhino`.* TO 'mifos'; + GRANT ALL PRIVILEGES ON `gorilla`.* TO 'mifos'; + GRANT ALL PRIVILEGES ON `lion`.* TO 'mifos'; + GRANT ALL ON *.* TO 'root'@'%'; + GRANT ALL PRIVILEGES ON messagegateway.* TO 'mifos'; + GRANT ALL PRIVILEGES ON `identity_account_mapper`.* TO 'mifos'; + GRANT ALL PRIVILEGES ON `voucher_management`.* TO 'mifos'; + volumeClaimTemplate: + storageClassName: "gp2" + + +operations_app: + enabled: true + replicas: 1 + image: 419830066942.dkr.ecr.ap-south-1.amazonaws.com/ph-ee-dpg-operations-app:dpg + imagePullPolicy: "Always" + token_client_channel_secret: "" + tenants: "rhino,gorilla,lion" +# hostname: "ops-bk.sandbox.mifos.io" + datasource: + username: "mifos" + password: "password" + host: "operationsmysql" + port: 3306 + schema: "tenants" + livenessProbe: + httpGet: + path: /actuator/health/liveness + port: 9191 + initialDelaySeconds: 120 + periodSeconds: 30 + failureThreshold: 3 + timeoutSeconds: 5 + readinessProbe: + httpGet: + path: /actuator/health/readiness + port: 9191 + initialDelaySeconds: 120 + periodSeconds: 30 + failureThreshold: 3 + timeoutSeconds: 5 + # Whether this chart should self-manage its service account, role, and associated role binding. + managedServiceAccount: true + # Custom service account override that the pod will use + serviceAccount: "" + # Annotations to add to the ServiceAccount that is created if the serviceAccount value isn't set. + serviceAccountAnnotations: {} + # How long to wait for operations_app pods to stop gracefully + terminationGracePeriod: 30 + # Extra environment variables for operations_app container. + envFrom: [] + # - configMapRef: + # name: config-secret + extraEnvs: [] + # This is the PriorityClass settings as defined in + # https://kubernetes.io/docs/concepts/configuration/pod-priority-preemption/#priorityclass + priorityClassName: "" + # operations_appConfig: "" + # operations_app.yml: | + # - User that the container will execute as. + # Not necessary to run as root (0) as the operations_app Deployment use cases do not need access to Kubernetes Node internals + # - Typically not necessarily unless running within environments such as OpenShift. + securityContext: + runAsUser: 0 + privileged: false + resources: + limits: + memory: "512M" + cpu: "500m" + requests: + memory: "512M" + cpu: "100m" + # Enabling this will publicly expose your operations_app instance. + # Only enable this if you have security enabled on your cluster + ingress: + enabled: true + annotations: + kubernetes.io/ingress.class: nginx + tls: + - secretName: sandbox-secret + hosts: + - host: ops-bk-dpg.sandbox.fynarfin.io + paths: + - path: "/" + backend: + service: + name: "ph-ee-operations-app" + port: + number: 80 + deployment: + annotations: + deployTime: "{{ .Values.deployTime }}" + affinity: {} + nodeSelector: {} + tolerations: [] + envFrom: [] + # - configMapRef: + # name: config-secret + extraEnvs: [] + # - User that the container will execute as. + # Not necessary to run as root (0) as the operations_app Deployment use cases do not need access to Kubernetes Node internals + # - Typically not necessarily unless running within environments such as OpenShift. + securityContext: + runAsUser: 0 + privileged: false + resources: + limits: + memory: "512M" + cpu: "500m" + requests: + memory: "512M" + cpu: "100m" + # Allows you to add any config files in /usr/share/ + # such as operations_app.yml for deployment + + +operations_web: + enabled: true + replicas: 1 + image: docker.io/openmf/ph-ee-operations-web:latest + hostname: "ops.sandbox.mifos.io" + imagePullPolicy: "Always" + imagePullSecrets: [] + webhost: "" + livenessProbe: + httpGet: + path: /actuator/health/liveness + port: 9191 + initialDelaySeconds: 120 + periodSeconds: 30 + failureThreshold: 3 + timeoutSeconds: 5 + readinessProbe: + httpGet: + path: /actuator/health/readiness + port: 9191 + initialDelaySeconds: 120 + periodSeconds: 30 + failureThreshold: 3 + timeoutSeconds: 5 + # Whether this chart should self-manage its service account, role, and associated role binding. + managedServiceAccount: true + # Custom service account override that the pod will use + serviceAccount: "" + # Annotations to add to the ServiceAccount that is created if the serviceAccount value isn't set. + serviceAccountAnnotations: {} + # How long to wait for operations_web pods to stop gracefully + terminationGracePeriod: 30 + # Extra environment variables for operations_web container. + envFrom: [] + # - configMapRef: + # name: config-secret + extraEnvs: [] + # This is the PriorityClass settings as defined in + # https://kubernetes.io/docs/concepts/configuration/pod-priority-preemption/#priorityclass + priorityClassName: "" + # ph-ee-operations-web-configConfig: "" + # ph-ee-operations-web-config.yml: | + # - User that the container will execute as. + # Not necessary to run as root (0) as the operations_web Deployment use cases do not need access to Kubernetes Node internals + # - Typically not necessarily unless running within environments such as OpenShift. + securityContext: + runAsUser: 0 + privileged: false + resources: + limits: + memory: "512M" + cpu: "500m" + requests: + memory: "512M" + cpu: "100m" + # Enabling this will publicly expose your operations_web instance. + # Only enable this if you have security enabled on your cluster + ingress: + enabled: true + tls: + - secretName: sandbox-secret + hosts: + - host: ops-dpg.sandbox.fynarfin.io + paths: + - path: "/" + backend: + service: + name: "ph-ee-operations-web" + port: + number: 4200 + deployment: + config: + - name: ph-ee-operations-web-config + mountPath: "/usr/share/nginx/html/assets/configuration.properties" + subPath: "configuration.properties" + annotations: {} + affinity: {} + nodeSelector: {} + tolerations: [] + envFrom: [] + # - configMapRef: + # name: config-secret + extraEnvs: [] + # - User that the container will execute as. + # Not necessary to run as root (0) as the operation-web Deployment use cases do not need access to Kubernetes Node internals + # - Typically not necessarily unless running within environments such as OpenShift. + securityContext: + runAsUser: 0 + privileged: false + resources: + limits: + memory: "512M" + cpu: "500m" + requests: + memory: "512M" + cpu: "100m" + # Allows you to add any config files in /usr/share/ + # such as ph-ee-operations-web.yml for deployment + # ph-ee-operations-webConfig: {} + # ph-ee-operations-web.yml: | + +ingress: + enabled: true + +elasticsearch: + enabled: true + replicas: 1 + protocol: http + fullnameOverride: "es" + clusterName: "elasticsearch" + minimumMasterNodes: 1 + esConfig: + elasticsearch.yml: | + xpack.security.enabled: false + transport.host: 0.0.0.0 + # extraEnvs: + # - name: ES_JAVA_OPTS + # value: "-Xms512m -Xmx1024m" + config: + transport.host: 0.0.0.0 + discovery.type: single-node + xpack.security.enabled: "false" + healthCheckPath: / + healthCheckPort: 9200 + persistence: + enabled: true + resources: + requests: + cpu: "100m" + memory: "1024M" + limits: + cpu: "1000m" + memory: "1024M" + volumeClaimTemplate: + accessModes: [ "ReadWriteOnce" ] + storageClassName: "gp2" + resources: + requests: + storage: 10Gi + + +redis: + enabled: true + fullnameOverride: "rs" + replica: + replicaCount: 0 + usePassword: false + auth: + enabled: false + + +postgresql: + enabled: true + fullnameOverride: "postgres" + postgresUser: conductor + postgresPassword: conductor + persistence: + enabled: true + primary: + initdb: + scripts: + setup.sql: |- + CREATE DATABASE conductor; + GRANT ALL PRIVILEGES ON `conductor`.* TO 'conductor'; + GRANT ALL ON *.* TO 'root'@'%'; + +networks: + internal: {} + +tls: "" diff --git a/ph-ee-env-labs/helm/es-secret/Makefile b/ph-ee-env-labs/helm/es-secret/Makefile new file mode 100644 index 000000000..644831507 --- /dev/null +++ b/ph-ee-env-labs/helm/es-secret/Makefile @@ -0,0 +1,37 @@ +default: test +include examples.mk +RELEASE := helm-es-security +ELASTICSEARCH_IMAGE := docker.elastic.co/elasticsearch/elasticsearch:$(STACK_VERSION) +TIMEOUT := 1200s +install: + helm upgrade --wait --timeout=$(TIMEOUT) --install --values values.yaml $(RELEASE) ../../ +test: secrets install goss +purge: + kubectl delete secrets elastic-credentials elastic-certificates elastic-certificate-pem elastic-certificate-crt|| true + helm del $(RELEASE) +pull-elasticsearch-image: + docker pull $(ELASTICSEARCH_IMAGE) + +secrets: + #----------------------random password generator---------------- + # docker rm -f elastic-helm-charts-certs || true + # rm -f elastic-certificates.p12 elastic-certificate.pem elastic-certificate.crt elastic-stack-ca.p12 || true + # password=$$([ ! -z "$$ELASTIC_PASSWORD" ] && echo $$ELASTIC_PASSWORD || echo $$(docker run --rm busybox:1.31.1 /bin/sh -c "< /dev/urandom tr -cd '[:alnum:]' | head -c20")) && \ + # docker run --name elastic-helm-charts-certs -i -w /app \ + # $(ELASTICSEARCH_IMAGE) \ + # /bin/sh -c " \ + # elasticsearch-certutil ca --out /app/elastic-stack-ca.p12 --pass '' && \ + # elasticsearch-certutil cert --name security-master --dns security-master --ca /app/elastic-stack-ca.p12 --pass '' --ca-pass '' --out /app/elastic-certificates.p12" && \ + # docker cp elastic-helm-charts-certs:/app/elastic-certificates.p12 ./ && \ + # docker rm -f elastic-helm-charts-certs && \ + #--------------------------------------------------------------- + + password="XVYgwycNuEygEEEI0hQF" && \ + openssl pkcs12 -nodes -passin pass:'' -in elastic-certificates.p12 -out elastic-certificate.pem && \ + openssl x509 -outform der -in elastic-certificate.pem -out elastic-certificate.crt && \ + kubectl create namespace $(NAMESPACE) || echo "namespace already exists" && \ + kubectl create secret generic elastic-certificates --namespace=$(NAMESPACE) --from-file=elastic-certificates.p12 && \ + kubectl create secret generic elastic-certificate-pem --namespace=$(NAMESPACE) --from-file=elastic-certificate.pem && \ + kubectl create secret generic elastic-certificate-crt --namespace=$(NAMESPACE) --from-file=elastic-certificate.crt && \ + kubectl create secret generic elastic-credentials --namespace=$(NAMESPACE) --from-literal=password=$$password --from-literal=username=elastic + # rm -f elastic-certificates.p12 elastic-certificate.pem elastic-certificate.crt elastic-stack-ca.p12 \ No newline at end of file diff --git a/ph-ee-env-labs/helm/es-secret/elastic-certificates.p12 b/ph-ee-env-labs/helm/es-secret/elastic-certificates.p12 new file mode 100644 index 000000000..c2af70e2e Binary files /dev/null and b/ph-ee-env-labs/helm/es-secret/elastic-certificates.p12 differ diff --git a/ph-ee-env-labs/helm/es-secret/examples.mk b/ph-ee-env-labs/helm/es-secret/examples.mk new file mode 100644 index 000000000..7d3449580 --- /dev/null +++ b/ph-ee-env-labs/helm/es-secret/examples.mk @@ -0,0 +1,29 @@ +SHELL := /bin/bash +GOSS_VERSION := v0.3.18 +GOSS_FILE ?= goss.yaml +GOSS_SELECTOR ?= release=$(RELEASE) +STACK_VERSION := 7.17.3 +TIMEOUT := 900s +NAMESPACE = $(ENV_NAMESPACE) + +.PHONY: help +help: ## Display this help + @awk 'BEGIN {FS = ":.*##"; printf "Usage: make \033[36m\033[0m\n\nTargets:\n"} /^[a-zA-Z0-9_-]+:.*?##/ { printf " \033[36m%-10s\033[0m %s\n", $$1, $$2 }' $(MAKEFILE_LIST) + +.PHONY: goss +goss: ## Run goss tests + set -e; \ + for i in $$(seq 1 5); do \ + curl -s -L "https://github.com/aelsabbahy/goss/releases/download/$(GOSS_VERSION)/goss-linux-amd64" -o /tmp/goss; \ + if [ -z "$$GOSS_CONTAINER" ]; then \ + sleep 5; \ + echo "Retrieving pod ($$i/5)"; \ + GOSS_CONTAINER=$$(kubectl get --no-headers=true pods -l "$(GOSS_SELECTOR)" -o custom-columns=:metadata.name --field-selector=status.phase=Running --sort-by=.metadata.creationTimestamp | tail -1 ); \ + else \ + echo "Testing with pod: $$GOSS_CONTAINER" && \ + kubectl cp "test/$(GOSS_FILE)" "$$GOSS_CONTAINER:/tmp/$(GOSS_FILE)" && \ + kubectl cp "/tmp/goss" "$$GOSS_CONTAINER:/tmp/goss" && \ + kubectl exec "$$GOSS_CONTAINER" -- sh -c "chmod +rx /tmp/goss && if [ -f ~/.elasticsearch-serviceaccounttoken ]; then . ~/.elasticsearch-serviceaccounttoken; fi; /tmp/goss --gossfile \"/tmp/$(GOSS_FILE)\" validate --retry-timeout 300s --sleep 5s --color --format documentation"; \ + break; \ + fi; \ + done \ No newline at end of file diff --git a/ph-ee-env-labs/helm/fin-phee/Chart.yaml b/ph-ee-env-labs/helm/fin-phee/Chart.yaml new file mode 100644 index 000000000..4950f3f09 --- /dev/null +++ b/ph-ee-env-labs/helm/fin-phee/Chart.yaml @@ -0,0 +1,12 @@ +apiVersion: v2 +name: ph-ee-barebone +description: PaymentHub EE Barebone Edition + +type: application +version: 0.1.0 +appVersion: 1.16.0 + +dependencies: +- name: ph-ee-engine-oaf + repository: https://fynarfin.io/images/ + version: 1.0.0-SNAPSHOT diff --git a/ph-ee-env-labs/helm/fin-phee/templates/config.yml b/ph-ee-env-labs/helm/fin-phee/templates/config.yml new file mode 100644 index 000000000..98f65ae95 --- /dev/null +++ b/ph-ee-env-labs/helm/fin-phee/templates/config.yml @@ -0,0 +1,6 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: ph-ee-config +data: +{{ (.Files.Glob "config/**.properties").AsConfig | nindent 2 }} diff --git a/ph-ee-env-labs/helm/fin-phee/values.yaml b/ph-ee-env-labs/helm/fin-phee/values.yaml new file mode 100644 index 000000000..e5472f8a5 --- /dev/null +++ b/ph-ee-env-labs/helm/fin-phee/values.yaml @@ -0,0 +1,263 @@ +ph-ee-engine-oaf: + zeebe: + broker: + contactpoint: "zeebe-zeebe-gateway:26500" + zeebe-cluster-helm: + global: + elasticsearch: + host: "ph-ee-elasticsearch" + image: + repository: camunda/zeebe + tag: 1.1.0 + + clusterSize: "1" + partitionCount: "1" + replicationFactor: "1" + + elasticsearch: + enabled: false + kibana: + enabled: false + + extraInitContainers: | + - name: init-ph-ee-kafka-exporter + image: busybox:1.28 + command: ['/bin/sh', '-c'] + args: ['wget -O /exporters/ph-ee-kafka-exporter.jar "https://paymenthub-ee-dev.s3.us-east-2.amazonaws.com/jars/exporter-1.0.0-SNAPSHOT.jar"; ls -al /exporters/'] + volumeMounts: + - name: exporters + mountPath: /exporters/ + + zeebe-operate-helm: + enabled: true + image: + repository: camunda/operate + tag: 1.1.0 + global: + elasticsearch: + host: "ph-ee-elasticsearch" + clusterName: "ph-ee-elasticsearch" + ingress: + enabled: false + className: "nginx" + path: /zeebe + host: fin-db.onenet.xyz + tls: + enabled: true + secretName: oafqa-tls + + kibana: + enabled: true + imageTag: 7.13.2 + ingress: + enabled: false + className: "nginx" + pathtype: ImplementationSpecific + hosts: + - host: fin-db.onenet.xyz + paths: + - path: /kibana + tls: + - secretName: sawtelqa-tls + hosts: + - "*.fin-db.onenet.xyz" + kibanaConfig: + kibana.yml: | + monitoring.enabled: false + + + elasticsearch: + enabled: true + replicas: 1 + imageTag: 7.13.2 + minimumMasterNodes: 1 + + #Single Node Solution + clusterHealthCheckParams: "wait_for_status=yellow&timeout=100s" + master: + readinessProbe: + httpGet: + path: /_cluster/health?wait_for_status=yellow&timeout=5s + port: 9200 + initialDelaySeconds: 30 + data: + readinessProbe: + httpGet: + path: /_cluster/health?wait_for_status=yellow&timeout=5s + port: 9200 + initialDelaySeconds: 30 + + + + # Shrink default JVM heap. + esJavaOpts: "-Xmx512m -Xms512m" + + # Allocate smaller chunks of memory per pod. + resources: + requests: + cpu: "200m" + memory: "1024M" + limits: + cpu: "1000m" + memory: "1024M" + volumeClaimTemplate: + accessModes: [ "ReadWriteOnce" ] + storageClassName: "standard" + resources: + requests: + storage: 10Gi + + + + operations: + enabled: true + + operationsMysql: + image: + tag: "5.7" + debug: true + auth: + database: "tenants" + username: "mifos" + password: "password" + rootPassword: "4ET6ywqlGt" + initdbScripts: + setup.sql: |- + CREATE DATABASE IF NOT EXISTS oaf; + CREATE DATABASE IF NOT EXISTS messagegateway; + GRANT ALL ON *.* TO 'root'@'%'; + GRANT ALL PRIVILEGES ON messagegateway.* TO 'mifos'; + GRANT ALL PRIVILEGES ON oaf.* TO 'mifos'; + + channel: + DFSPIDS: "dosh" + transaction_id_length: 20 + SPRING_PROFILES_ACTIVE: "bb" + hostname: "fin-db.onenet.xyz" + AWS_ACCESS_KEY: "xxx" + AWS_SECRET_KEY: "xxx" + image: "fynarfin.azurecr.io/phee-connector-channel" + ingress: + enabled: false + annotations: + kubernetes.io/ingress.class: "nginx" + + operations_app: + TENANTS: "dosh" + SPRING_PROFILES_ACTIVE: "bb" + hostname: "fin-db.onenet.xyz" + image: "fynarfin.azurecr.io/ph-ee-ops-bk" + ingress: + enabled: false + annotations: + kubernetes.io/ingress.class: "nginx" + + operations_web: + SPRING_PROFILES_ACTIVE: "bb" + hostname: "fin-db.onenet.xyz" + webhost: "fin-db.onenet.xyz" + path: "/" + image: "fynarfin.azurecr.io/ph-ee-ops-web" + ingress: + enabled: false + annotations: + kubernetes.io/ingress.class: "nginx" + + identity: + hostname: "fin-db.onenet.xyz" + ingress: + enabled: false + annotations: + kubernetes.io/ingress.class: "nginx" + + mpesa: + enabled: true + tenant: "sawtel" + SPRING_PROFILES_ACTIVE: "bb" + hostname: "fin-db.onenet.xyz" + image: "fynarfin.azurecr.io/ph-ee-mpesa" + business_short_code: "668158" + till_number: "9347335" + callback_host: "https://fin-db.onenet.xyz/mpesa" + retry_count: 3 + safaricom: + auth_host: "https://api.safaricom.co.ke/oauth/v1/generate" + api_host: "https://api.safaricom.co.ke" + secret: + value: + client_key: "MHBMeGJOODNGck9sNU5kMEZoOVppNUJRbE14U0wybjUK" + client_secret: "WXp1R05vSnhldWI4WkM2ZAo=" + pass_key: "YmZiMjc5ZjlhYTliZGJjZjE1OGU5N2RkNzFhNDY3Y2QyZTBjODkzMDU5YjEwZjc4ZTZiNzJhZGExZWQyYzkxOQo=" + ingress: + enabled: false + annotations: + kubernetes.io/ingress.class: "nginx" + + roster_connector: + enabled: true + SPRING_PROFILES_ACTIVE: "bb" + image: "fynarfin.azurecr.io/ph-ee-connector-ams-pesa" + pesacore: + base_url: "https://qaoperations01.oneacrefund.org" + auth_header: "PaymentHubTest" + ams: + local: + enabled: true + + notifications: + enabled: true + SPRING_PROFILES_ACTIVE: "bb" + image: "fynarfin.azurecr.io/ph-ee-notifications" + hostname: "fin-db.onenet.xyz" + CALLBACKCONFIG_HOST: "fin-db.onenet.xyz/notifications" + MESSAGEGATEWAYCONFIG_HOST: "message-gateway" + NOTIFICATION_LOCAL_HOST: "ph-ee-connector-notifications" + NOTIFICATION_SUCCESS_ENABLED: "false" + NOTIFICATION_FAILURE_ENABLED: "false" + ingress: + enabled: false + annotations: + kubernetes.io/ingress.class: "kong" + konghq.com/strip-path: "true" + + + zeebe_ops: + enabled: true + image: "fynarfin.azurecr.io/phee-zeebe-ops" + ingress: + enabled: false + annotations: + kubernetes.io/ingress.class: "nginx" + + messagegateway: + enabled: true + image: "fynarfin.azurecr.io/message-gateway" + hostname: "fin-db.onenet.xyz" + CALLBACKCONFIG_HOST: "ph-ee-connector-notifications" + MESSAGEGATEWAYCONFIG_HOST: "message-gateway" + HOSTCONFIG_HOST: "message-gateway" + hostname: "fin-db.onenet.xyz" + secret: + value: + api_key: "ZUtpQzFfSldkS3k3ZWFUR1FGSHhYWGpYamFjcjYwVzlabnRs" + project_id: "UEo1ZmY1NTJjZTAxZDI5Nzhj" + MYSQL_USERNAME: "mifos" + MYSQL_PASSWORD: "password" + PROVIDERSOURCE_FROMDATABASE: "disabled" + PROVIDERSOURCE_FROMYML: "enabled" + + ingress: + enabled: false + annotations: + kubernetes.io/ingress.class: "nginx" + + + importer_es: + image: "fynarfin.azurecr.io/phee-es-importer" + + importer_rdbms: + image: "fynarfin.azurecr.io/ph-ee-importer-rdbms" + + wildcardhostname: "*.onenet.xyz" + + tls: "sawtelqa-tls" diff --git a/ph-ee-env-labs/helm/g2p-sandbox-fynarfin-SIT/Chart.yaml b/ph-ee-env-labs/helm/g2p-sandbox-fynarfin-SIT/Chart.yaml new file mode 100644 index 000000000..5d4ed5b5d --- /dev/null +++ b/ph-ee-env-labs/helm/g2p-sandbox-fynarfin-SIT/Chart.yaml @@ -0,0 +1,12 @@ +apiVersion: v2 +name: ph-ee-g2psandbox-fynarfin +description: PaymentHub EE Barebone Edition + +type: application +version: 0.2.0 +appVersion: 1.16.0 + +dependencies: +- name: ph-ee-g2psandbox + repository: https://fynarfin.io/images/ph-ee-g2psandbox-0.0.0 + version: 0.0.0 diff --git a/ph-ee-env-labs/helm/g2p-sandbox-fynarfin-SIT/README.md b/ph-ee-env-labs/helm/g2p-sandbox-fynarfin-SIT/README.md new file mode 100644 index 000000000..b66a53e3a --- /dev/null +++ b/ph-ee-env-labs/helm/g2p-sandbox-fynarfin-SIT/README.md @@ -0,0 +1,21 @@ +Helm Upgrade command ----> +helm upgrade -f helm/g2p-sandbox/values.yaml g2pconnect helm/g2p-sandbox --install --create-namespace --namespace paymenthub + +Known Issue +Migration script race condition Operation app startup issue work around +1. Port forward operationsmysqlpodname -3307 (kubectl get operationsmysql pod name) +2. Connect to mysql with root passwrod (kubectl get secret operationsmysql, take root password and base64 decode it, mysql -uroot -P3307 -p) +3. Delete tenants (drop database tenants;) +4. Run the SQL scripts which didn’t run successfully + +4a. CREATE DATABASE `tenants`; + +4b. GRANT ALL PRIVILEGES ON `tenants`.* TO 'mifos'; + +4c. GRANT ALL PRIVILEGES ON `rhino`.* TO 'mifos'; + +4d. GRANT ALL PRIVILEGES ON `gorilla`.* TO 'mifos'; + +4e. GRANT ALL ON *.* TO 'root'@'%'; + +5. Restart ops-app pod diff --git a/ph-ee-env-labs/helm/g2p-sandbox-fynarfin-SIT/config/application-bb.properties b/ph-ee-env-labs/helm/g2p-sandbox-fynarfin-SIT/config/application-bb.properties new file mode 100644 index 000000000..247d5028e --- /dev/null +++ b/ph-ee-env-labs/helm/g2p-sandbox-fynarfin-SIT/config/application-bb.properties @@ -0,0 +1,9 @@ +store.local.interop.host=https://rhino.mifos.g2pconnect.io +store.local.customer.host=https://rhino.mifos.g2pconnect.io +zeebe.broker.contactpoint=g2p-sandbox-zeebe-gateway:26500 + +security.oauth2.resource.jwt.key-uri=http://ops-bk.mifos.g2pconnect.io/oauth/token_key +rest.authorization.enabled=false +rest.authorization.host=http://ops-bk.mifos.g2pconnect.io + +dfspids=rhino, gorilla diff --git a/ph-ee-env-labs/helm/g2p-sandbox-fynarfin-SIT/config/application-fin12.properties b/ph-ee-env-labs/helm/g2p-sandbox-fynarfin-SIT/config/application-fin12.properties new file mode 100644 index 000000000..21ef31da8 --- /dev/null +++ b/ph-ee-env-labs/helm/g2p-sandbox-fynarfin-SIT/config/application-fin12.properties @@ -0,0 +1,8 @@ +ams.localenabled=true +zeebe.broker.contactpoint=g2p-sandbox-zeebe-gateway:26500 +ph-ee-g2psandbox.ph-ee-engine.ph_ee_connector_ams_mifos.ams_local_interop_host="https://fynams.sandbox.fynarfin.io/" +ph-ee-g2psandbox.ph-ee-engine.ph_ee_connector_ams_mifos.ams_local_account_host="https://fynams.sandbox.fynarfin.io/" +ph-ee-g2psandbox.ph-ee-engine.ph_ee_connector_ams_mifos.ams_local_customer_host="https://fynams.sandbox.fynarfin.io/" +ph-ee-g2psandbox.ph-ee-engine.ph_ee_connector_ams_mifos.ams_local_auth_host="https://fynams.sandbox.fynarfin.io/" +ph-ee-g2psandbox.ph-ee-engine.ph_ee_connector_ams_mifos.ams_local_loan_host="https://fynams.sandbox.fynarfin.io/" +ph-ee-g2psandbox.ph-ee-engine.ph_ee_connector_ams_mifos.dfspids="rhino,gorilla" \ No newline at end of file diff --git a/ph-ee-env-labs/helm/g2p-sandbox-fynarfin-SIT/config/application-tenants.properties b/ph-ee-env-labs/helm/g2p-sandbox-fynarfin-SIT/config/application-tenants.properties new file mode 100644 index 000000000..efcc36559 --- /dev/null +++ b/ph-ee-env-labs/helm/g2p-sandbox-fynarfin-SIT/config/application-tenants.properties @@ -0,0 +1,8 @@ +bpmns.tenants[0].id= rhino +bpmns.tenants[0].flows.payment-transfer= minimal_mock_fund_transfer_account_lookup-{dfspid} +bpmns.tenants[1].id= gorilla +bpmns.tenants[1].flows.payment-transfer= minimal_mock_fund_transfer-{dfspid} +bpmns.tenants[1].flows.outbound-transfer-request= minimal_mock_transfer_request-{dfspid} +bpmns.tenants[2].id= wakanda +bpmns.tenants[2].flows.payment-transfer= PayerFundTransfer-{dfspid} +bpmns.tenants[2].flows.outbound-transfer-request= {ps}_flow_{ams}-{dfspid} \ No newline at end of file diff --git a/ph-ee-env-labs/helm/g2p-sandbox-fynarfin-SIT/config/application-tenantsConnection.properties b/ph-ee-env-labs/helm/g2p-sandbox-fynarfin-SIT/config/application-tenantsConnection.properties new file mode 100644 index 000000000..abff5621f --- /dev/null +++ b/ph-ee-env-labs/helm/g2p-sandbox-fynarfin-SIT/config/application-tenantsConnection.properties @@ -0,0 +1,78 @@ +tenants.connections[0].auto_update=true +tenants.connections[0].deadlock_max_retries=0 +tenants.connections[0].deadlock_max_retry_interval=1 +tenants.connections[0].driver_class=com.mysql.cj.jdbc.Driver +tenants.connections[0].jdbcProtocol=jdbc +tenants.connections[0].jdbcSubProtocol=mysql +tenants.connections[0].name=gorilla +tenants.connections[0].pool_abandon_when_percentage_full=50 +tenants.connections[0].pool_initial_size=5 +tenants.connections[0].pool_log_abandoned=1 +tenants.connections[0].pool_max_active=40 +tenants.connections[0].pool_max_idle=10 +tenants.connections[0].pool_min_evictable_idle_time_millis=60000 +tenants.connections[0].pool_min_idle=20 +tenants.connections[0].pool_remove_abandoned=1 +tenants.connections[0].pool_remove_abandoned_timeout=60 +tenants.connections[0].pool_suspect_timeout=60 +tenants.connections[0].pool_test_on_borrow=1 +tenants.connections[0].pool_time_between_eviction_runs_millis=34000 +tenants.connections[0].pool_validation_interval=30000 +tenants.connections[0].schema_connection_parameters=null +tenants.connections[0].schema_name=gorilla +tenants.connections[0].schema_password=password +tenants.connections[0].schema_server=operationsmysql +tenants.connections[0].schema_server_port=3306 +tenants.connections[0].schema_username=mifos +tenants.connections[1].auto_update=true +tenants.connections[1].deadlock_max_retries=0 +tenants.connections[1].deadlock_max_retry_interval=1 +tenants.connections[1].driver_class=com.mysql.cj.jdbc.Driver +tenants.connections[1].jdbcProtocol=jdbc +tenants.connections[1].jdbcSubProtocol=mysql +tenants.connections[1].name=rhino +tenants.connections[1].pool_abandon_when_percentage_full=50 +tenants.connections[1].pool_initial_size=5 +tenants.connections[1].pool_log_abandoned=1 +tenants.connections[1].pool_max_active=40 +tenants.connections[1].pool_max_idle=10 +tenants.connections[1].pool_min_evictable_idle_time_millis=60000 +tenants.connections[1].pool_min_idle=20 +tenants.connections[1].pool_remove_abandoned=1 +tenants.connections[1].pool_remove_abandoned_timeout=60 +tenants.connections[1].pool_suspect_timeout=60 +tenants.connections[1].pool_test_on_borrow=1 +tenants.connections[1].pool_time_between_eviction_runs_millis=34000 +tenants.connections[1].pool_validation_interval=30000 +tenants.connections[1].schema_connection_parameters=null +tenants.connections[1].schema_name=rhino +tenants.connections[1].schema_password=password +tenants.connections[1].schema_server=operationsmysql +tenants.connections[1].schema_server_port=3306 +tenants.connections[1].schema_username=mifos +tenants.connections[2].auto_update=true +tenants.connections[2].deadlock_max_retries=0 +tenants.connections[2].deadlock_max_retry_interval=1 +tenants.connections[2].driver_class=com.mysql.cj.jdbc.Driver +tenants.connections[2].jdbcProtocol=jdbc +tenants.connections[2].jdbcSubProtocol=mysql +tenants.connections[2].name=wakanda +tenants.connections[2].pool_abandon_when_percentage_full=50 +tenants.connections[2].pool_initial_size=5 +tenants.connections[2].pool_log_abandoned=1 +tenants.connections[2].pool_max_active=40 +tenants.connections[2].pool_max_idle=10 +tenants.connections[2].pool_min_evictable_idle_time_millis=60000 +tenants.connections[2].pool_min_idle=20 +tenants.connections[2].pool_remove_abandoned=1 +tenants.connections[2].pool_remove_abandoned_timeout=60 +tenants.connections[2].pool_suspect_timeout=60 +tenants.connections[2].pool_test_on_borrow=1 +tenants.connections[2].pool_time_between_eviction_runs_millis=34000 +tenants.connections[2].pool_validation_interval=30000 +tenants.connections[2].schema_connection_parameters=null +tenants.connections[2].schema_name=wakanda +tenants.connections[2].schema_password=password +tenants.connections[2].schema_server=operationsmysql +tenants.connections[2].schema_server_port=3306 +tenants.connections[2].schema_username=mifos \ No newline at end of file diff --git a/ph-ee-env-labs/helm/g2p-sandbox-fynarfin-SIT/templates/config.yml b/ph-ee-env-labs/helm/g2p-sandbox-fynarfin-SIT/templates/config.yml new file mode 100644 index 000000000..98f65ae95 --- /dev/null +++ b/ph-ee-env-labs/helm/g2p-sandbox-fynarfin-SIT/templates/config.yml @@ -0,0 +1,6 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: ph-ee-config +data: +{{ (.Files.Glob "config/**.properties").AsConfig | nindent 2 }} diff --git a/ph-ee-env-labs/helm/g2p-sandbox-fynarfin-SIT/values.yaml b/ph-ee-env-labs/helm/g2p-sandbox-fynarfin-SIT/values.yaml new file mode 100644 index 000000000..19c756251 --- /dev/null +++ b/ph-ee-env-labs/helm/g2p-sandbox-fynarfin-SIT/values.yaml @@ -0,0 +1,507 @@ +ph-ee-g2psandbox: + ph-ee-engine: + + zeebe-cluster-helm: + enabled: true + + elasticsearch: + enabled: false + kibana: + enabled: true + + zeebe-operate-helm: + ingress: + enabled: true + host: operate.sandbox.fynarfin.io + + global: + DFSPIDS: "gorilla,rhino,wakanda,pluto,venus,jupiter" + + kibana: + ingress: + enabled: true + className: "nginx" + pathtype: "Prefix" + annotations: {} + # kubernetes.io/ingress.class: nginx + # kubernetes.io/tls-acme: "true" + hosts: + - host: analytics.sandbox.fynarfin.io + paths: + - path: / + + operations: + + ph_ee_connector_ams_mifos: + enabled: true + image: docker.io/openmf/ph-ee-connector-ams-mifos:latest + imageTag: v1.2.2 + deployment: + annotations: + rollme: '{{ randAlphaNum 5 | quote }}' + ams_local_interop_host: "https://fynams.sandbox.fynarfin.io/" + ams_local_account_host: "https://fynams.sandbox.fynarfin.io/" + ams_local_customer_host: "https://fynams.sandbox.fynarfin.io/" + ams_local_auth_host: "https://fynams.sandbox.fynarfin.io/" + ams_local_loan_host: "https://fynams.sandbox.fynarfin.io/" + ingress: + enabled: true + hosts: + - host: ams-mifos.sandbox.fynarfin.io + paths: + - path: "/" + backend: + service: + name: ph-ee-connector-ams-mifos + port: + number: 80 + - host: ams-mifos-mock.sandbox.fynarfin.io + paths: + - path: "/" + backend: + service: + name: ph-ee-connector-ams-mifos + port: + number: 7070 + + ph_ee_connector_mojaloop: + enabled: true + image: docker.io/openmf/ph-ee-connector-mojaloop:latest + imageTag: "830df54849" + switch: + quotes: + host: "http://quoting-service.sandbox.fynarfin.io" + service: "quoting-service.sandbox.fynarfin.io" + als: + host: "http://account-lookup-service.sandbox.fynarfin.io" + service: "account-lookup-service.sandbox.fynarfin.io" + transfers: + host: "http://ml-api-adapter.sandbox.fynarfin.io" + service: "api-adapter.sandbox.fynarfin.io" + transactions: + host: "http://ml-api-adapter.sandbox.fynarfin.io" + service: "ml-api-adapter.sandbox.fynarfin.io" + oracle: + host: "http://moja-simulator.sandbox.fynarfin.io" + deployment: + extraEnvs: + - name: parties_0_domain + value: "https://fynams.sandbox.fynarfin.io/" + - name: parties_1_domain + value: "mojaloop.sandbox.fynarfin.io" + - name: parties_2_domain + value: "mojaloop.sandbox.fynarfin.io" + - name: parties_3_domain + value: "mojaloop.sandbox.fynarfin.io" + - name: parties_0_tenantId + value: "wakanda" + - name: parties_1_tenantId + value: "jupiter" + - name: parties_2_tenantId + value: "pluto" + - name: parties_3_tenantId + value: "venus" + - name: parties_0_fspId + value: "payerfsp" + - name: parties_1_fspId + value: "payeefsp" + - name: parties_2_fspId + value: "payeefsp2" + - name: parties_3_fspId + value: "payeefsp3" + + ingress: + enabled: true + tls: + - secretName: fyn-cert + hosts: + - host: mojaloop.sandbox.fynarfin.io + paths: + - path: "/" + backend: + service: + name: ph-ee-connector-mojaloop-java + port: + number: 80 + + # kafka: + + channel: + enabled: true + image: docker.io/openmf/ph-ee-connector-channel:latest + default_headers: "user-agent,accept,postman-token,host,accept-encoding,connection,content-type,content-length,x-request-id,x-real-ip,x-forwarded-host,x-forwarded-port,x-forwarded-proto,x-forwarded-scheme,x-scheme,x-forwarded-path" + server: + ssl: + keyPassword: "password" + keyStorePassword: "password" + deployment: + annotations: + rollme: "{{ randAlphaNum 5 | quote }}" + service: + annotations: + konghq.com/protocol: "https" + ingress: + enabled: true + className: "kong" + hosts: + - host: channel.sandbox.fynarfin.io + paths: + - path: "/" + backend: + service: + name: "ph-ee-connector-channel" + port: + number: 8443 + - host: channel-gsma.sandbox.fynarfin.io + paths: + - path: "/" + backend: + service: + name: "ph-ee-connector-channel-gsma" + port: + number: 82 + + + operations_app: + enabled: true + image: docker.io/openmf/ph-ee-operations-app:latest + tenants: "rhino,gorilla" + minio_public_host: "http://minio.sandbox.fynarfin.io" + deployment: + annotations: + rollme: "{{ randAlphaNum 5 | quote }}" + ingress: + enabled: true + hosts: + - host: ops-bk.sandbox.fynarfin.io + paths: + - path: "/" + backend: + service: + name: "ph-ee-operations-app" + port: + number: 80 + + + operations_web: + enabled: true + image: docker.io/openmf/ph-ee-operations-web:latest + ingress: + enabled: true + annotations: + kubernetes.io/ingress.class: "nginx" + hosts: + - host: ops.sandbox.fynarfin.io + paths: + - path: "/" + backend: + service: + name: "ph-ee-operations-web" + port: + number: 4200 + backend: + PH_OPS_BACKEND_SERVER_URL: https://ops-bk.sandbox.fynarfin.io/api/v1 + PH_VOU_BACKEND_SERVER_URL: https://vouchers.sandbox.fynarfin.io + PH_ACT_BACKEND_SERVER_URL: https://identity-mapper.sandbox.fynarfin.io + PH_PLATFORM_TENANT_ID: gorilla + PH_PLATFORM_TENANT_IDS: gorilla + PH_REGISTERING_INSTITUTION_ID: 123 + auth: + PH_AUTH_ENABLED: false + PH_OAUTH_ENABLED: false + PH_OAUTH_TYPE: keycloak + PH_OAUTH_SERVER_URL: http://keycloak.sandbox.fynarfin.io/auth + PH_OAUTH_REALM: paymenthub + PH_OAUTH_CLIENT_ID: opsapp + PH_OAUTH_CLIENT_SECRET: Y2xpZW50Og== + PH_OAUTH_BASIC_AUTH: true + PH_OAUTH_BASIC_AUTH_TOKEN: Y2xpZW50Og== + PH_DEFAULT_LANGUAGE: en + PH_SUPPORTED_LANGUAGES: en,fr,es + + ph_ee_connector_gsma: + enabled: true + image: docker.io/openmf/ph-ee-connector-gsma:latest + ingress: + enabled: true + + ph_ee_connector_slcb: + enabled: false + + mpesa: + enabled: false + + roster_connector: + enabled: false + + paygops_connector: + enabled: false + + notifications: + enabled: true + image: docker.io/openmf/ph-ee-notifications:latest + NOTIFICATION_FAILURE_ENABLED: "false" + ingress: + enabled: true + hosts: + - host: notifications.sandbox.fynarfin.io + paths: + - path: "/" + backend: + service: + name: "ph-ee-connector-notifications" + port: + number: 80 + + + connector_bulk: + enabled: true + image: docker.io/openmf/ph-ee-bulk-processor:latest + tenants: "rhino,gorilla" + deployment: + annotations: + rollme: "{{ randAlphaNum 5 | quote }}" + operations_app: + contactpoint: "https://ops-bk.sandbox.fynarfin.io/" + endpoints: + batch_transaction: "/api/v1/batch/transactions" + identity_account_mapper: + hostname: "https://identity-mapper.sandbox.fynarfin.io" + ingress: + enabled: true + className: "kong" + tls: + - secretName: sandbox-secret + hosts: + - host: bulk-connector.sandbox.fynarfin.io + paths: + - path: "/" + backend: + service: + name: "ph-ee-connector-bulk" + port: + number: 8443 + + zeebe_ops: + enabled: true + tenants: "rhino,gorilla" + ingress: + enabled: true + hosts: + - host: zeebeops.sandbox.fynarfin.io + paths: + - path: "/" + backend: + service: + name: "ph-ee-zeebe-ops" + port: + number: 80 + + messagegateway: + enabled: true + image: docker.io/openmf/message-gateway:latest + secret: + value: + api_key: "eKiC1_JWdKy7eaTGQFHxXXjXjacr60W9Zntl" + project_id: "PJ5ff552ce01d2978c" + ingress: + enabled: true + hosts: + - host: messagegateway.sandbox.fynarfin.io + paths: + - path: "/" + backend: + service: + name: "message-gateway" + port: + number: 80 + + importer_es: + enabled: true + image: docker.io/openmf/ph-ee-importer-es:latest + + importer_rdbms: + enabled: true + image: docker.io/openmf/ph-ee-importer-rdbms:latest + aws: + region: "ap-south-1" + + mockpayment: + enabled: true + image: docker.io/openmf/ph-ee-connector-mock-payment-schema:latest + ingress: + enabled: true + annotations: + kubernetes.io/ingress.class: nginx + hosts: + - host: mockpaymentschema.sandbox.fynarfin.io + paths: + - path: "/" + backend: + service: + name: "ph-ee-connector-mock-payment-schema" + port: + number: 8080 + + billPay: + enabled: true + image: docker.io/openmf/ph-ee-bill-pay:latest + billpay: + contactpoint: "https://bill-pay.sandbox.fynarfin.io" + connector: + contactpoint: "https://connector.sandbox.fynarfin.io" + ingress: + enabled: true + annotations: + kubernetes.io/ingress.class: nginx + hosts: + - host: bill-pay.sandbox.fynarfin.io + paths: + - path: "/" + backend: + service: + name: "ph-ee-connector-bill-pay" + port: + number: 8080 + crm: + enabled: true + image: docker.io/openmf/ph-ee-connector-crm:latest + ingress: + enabled: true + annotations: + kubernetes.io/ingress.class: nginx + hosts: + - host: connector-crm.sandbox.fynarfin.io + paths: + - path: "/" + backend: + service: + name: "ph-ee-connector-crm" + port: + number: 8080 + + wildcardhostname: "*.sandbox.fynarfin.io" + tls: "" + + post_installation_job: + enabled: false + + keycloak: + enabled: false + ingress: + enabled: true + rules: + - host: 'keycloak.sandbox.fynarfin.io' + paths: + - path: / + pathType: Prefix + + + kong: + enabled: false + ingress: + enabled: true + hostname: admin-kong.sandbox.fynarfin.io + + redis: + enabled: true + replica: + replicaCount: 0 + + vouchers: + enabled: true + image: docker.io/openmf/ph-ee-vouchers:latest + + voucher: + hostname: "https://vouchers.sandbox.fynarfin.io" + + salting: + enabled: true + + identity-account-mapper: + hostname: "https://identity-mapper.sandbox.fynarfin.io" + operations: + hostname: "https://ops-bk.sandbox.fynarfin.io" + endpoints: + transfers: "/api/v1/transfers?size=1&page=0" + + deployment: + annotations: + rollme: "{{ randAlphaNum 5 | quote }}" + ingress: + enabled: true + annotations: + kubernetes.io/ingress.class: nginx + tls: + - secretName: sandbox-secret + hosts: + - host: vouchers.sandbox.fynarfin.io + paths: + - path: "/" + backend: + service: + name: "ph-ee-vouchers" + port: + number: 80 + ph-ee-connector: + enabled: true + image: docker.io/openmf/ph-ee-connector-bulk:latest + deployment: + annotations: + rollme: "{{ randAlphaNum 5 | quote }}" + ingress: + enabled: true + annotations: + kubernetes.io/ingress.class: nginx + tls: + - secretName: sandbox-secret + hosts: + - host: connector.sandbox.fynarfin.io + paths: + - path: "/" + backend: + service: + name: "ph-ee-connector" + port: + number: 80 + minio: + enabled: true + consoleIngress: + enabled: true + annotations: + kubernetes.io/ingress.class: "nginx" + nginx.ingress.kubernetes.io/backend-protocol: "HTTP" + hosts: + - minio-console.sandbox.fynarfin.io + ingress: + enabled: true + annotations: + kubernetes.io/ingress.class: "nginx" + nginx.ingress.kubernetes.io/backend-protocol: "HTTP" + hosts: + - minio.sandbox.fynarfin.io + account_mapper: + enabled: true + image: docker.io/openmf/ph-ee-identity-account-mapper:latest + deployment: + annotations: + rollme: "{{ randAlphaNum 5 | quote }}" + ingress: + enabled: true + annotations: + kubernetes.io/ingress.class: nginx + tls: + - secretName: sandbox-secret + hosts: + - host: identity-mapper.sandbox.fynarfin.io + paths: + - path: "/" + backend: + service: + name: "ph-ee-identity-account-mapper" + port: + number: 80 + + + + diff --git a/ph-ee-env-labs/helm/g2p-sandbox-fynarfin-demo/Chart.yaml b/ph-ee-env-labs/helm/g2p-sandbox-fynarfin-demo/Chart.yaml new file mode 100644 index 000000000..b2a1beb56 --- /dev/null +++ b/ph-ee-env-labs/helm/g2p-sandbox-fynarfin-demo/Chart.yaml @@ -0,0 +1,12 @@ +apiVersion: v2 +name: ph-ee-g2psandbox-fynarfin-demo +description: PaymentHub EE Barebone Edition + +type: application +version: 0.2.0 +appVersion: 1.0.0 + +dependencies: +- name: ph-ee-g2psandbox + repository: https://fynarfin.io/images/ph-ee-g2psandbox-0.0.0 + version: 0.0.0 diff --git a/ph-ee-env-labs/helm/g2p-sandbox-fynarfin-demo/README.md b/ph-ee-env-labs/helm/g2p-sandbox-fynarfin-demo/README.md new file mode 100644 index 000000000..b66a53e3a --- /dev/null +++ b/ph-ee-env-labs/helm/g2p-sandbox-fynarfin-demo/README.md @@ -0,0 +1,21 @@ +Helm Upgrade command ----> +helm upgrade -f helm/g2p-sandbox/values.yaml g2pconnect helm/g2p-sandbox --install --create-namespace --namespace paymenthub + +Known Issue +Migration script race condition Operation app startup issue work around +1. Port forward operationsmysqlpodname -3307 (kubectl get operationsmysql pod name) +2. Connect to mysql with root passwrod (kubectl get secret operationsmysql, take root password and base64 decode it, mysql -uroot -P3307 -p) +3. Delete tenants (drop database tenants;) +4. Run the SQL scripts which didn’t run successfully + +4a. CREATE DATABASE `tenants`; + +4b. GRANT ALL PRIVILEGES ON `tenants`.* TO 'mifos'; + +4c. GRANT ALL PRIVILEGES ON `rhino`.* TO 'mifos'; + +4d. GRANT ALL PRIVILEGES ON `gorilla`.* TO 'mifos'; + +4e. GRANT ALL ON *.* TO 'root'@'%'; + +5. Restart ops-app pod diff --git a/ph-ee-env-labs/helm/g2p-sandbox-fynarfin-demo/config/application-bb.properties b/ph-ee-env-labs/helm/g2p-sandbox-fynarfin-demo/config/application-bb.properties new file mode 100644 index 000000000..247d5028e --- /dev/null +++ b/ph-ee-env-labs/helm/g2p-sandbox-fynarfin-demo/config/application-bb.properties @@ -0,0 +1,9 @@ +store.local.interop.host=https://rhino.mifos.g2pconnect.io +store.local.customer.host=https://rhino.mifos.g2pconnect.io +zeebe.broker.contactpoint=g2p-sandbox-zeebe-gateway:26500 + +security.oauth2.resource.jwt.key-uri=http://ops-bk.mifos.g2pconnect.io/oauth/token_key +rest.authorization.enabled=false +rest.authorization.host=http://ops-bk.mifos.g2pconnect.io + +dfspids=rhino, gorilla diff --git a/ph-ee-env-labs/helm/g2p-sandbox-fynarfin-demo/config/application-fin12.properties b/ph-ee-env-labs/helm/g2p-sandbox-fynarfin-demo/config/application-fin12.properties new file mode 100644 index 000000000..21ef31da8 --- /dev/null +++ b/ph-ee-env-labs/helm/g2p-sandbox-fynarfin-demo/config/application-fin12.properties @@ -0,0 +1,8 @@ +ams.localenabled=true +zeebe.broker.contactpoint=g2p-sandbox-zeebe-gateway:26500 +ph-ee-g2psandbox.ph-ee-engine.ph_ee_connector_ams_mifos.ams_local_interop_host="https://fynams.sandbox.fynarfin.io/" +ph-ee-g2psandbox.ph-ee-engine.ph_ee_connector_ams_mifos.ams_local_account_host="https://fynams.sandbox.fynarfin.io/" +ph-ee-g2psandbox.ph-ee-engine.ph_ee_connector_ams_mifos.ams_local_customer_host="https://fynams.sandbox.fynarfin.io/" +ph-ee-g2psandbox.ph-ee-engine.ph_ee_connector_ams_mifos.ams_local_auth_host="https://fynams.sandbox.fynarfin.io/" +ph-ee-g2psandbox.ph-ee-engine.ph_ee_connector_ams_mifos.ams_local_loan_host="https://fynams.sandbox.fynarfin.io/" +ph-ee-g2psandbox.ph-ee-engine.ph_ee_connector_ams_mifos.dfspids="rhino,gorilla" \ No newline at end of file diff --git a/ph-ee-env-labs/helm/g2p-sandbox-fynarfin-demo/config/application-tenants.properties b/ph-ee-env-labs/helm/g2p-sandbox-fynarfin-demo/config/application-tenants.properties new file mode 100644 index 000000000..07b08651e --- /dev/null +++ b/ph-ee-env-labs/helm/g2p-sandbox-fynarfin-demo/config/application-tenants.properties @@ -0,0 +1,8 @@ +bpmns.tenants[0].id= lion +bpmns.tenants[0].flows.payment-transfer= minimal_mock_fund_transfer_account_lookup-{dfspid} +bpmns.tenants[1].id= rhino +bpmns.tenants[1].flows.payment-transfer= minimal_mock_fund_transfer-{dfspid} +bpmns.tenants[1].flows.outbound-transfer-request= minimal_mock_transfer_request-{dfspid} +bpmns.tenants[2].id= gorilla +bpmns.tenants[2].flows.payment-transfer= PayerFundTransfer-{dfspid} +bpmns.tenants[2].flows.outbound-transfer-request= {ps}_flow_{ams}-{dfspid} \ No newline at end of file diff --git a/ph-ee-env-labs/helm/g2p-sandbox-fynarfin-demo/config/application-tenantsConnection.properties b/ph-ee-env-labs/helm/g2p-sandbox-fynarfin-demo/config/application-tenantsConnection.properties new file mode 100644 index 000000000..6cecf68b7 --- /dev/null +++ b/ph-ee-env-labs/helm/g2p-sandbox-fynarfin-demo/config/application-tenantsConnection.properties @@ -0,0 +1,78 @@ +tenants.connections[0].auto_update=true +tenants.connections[0].deadlock_max_retries=0 +tenants.connections[0].deadlock_max_retry_interval=1 +tenants.connections[0].driver_class=com.mysql.cj.jdbc.Driver +tenants.connections[0].jdbcProtocol=jdbc +tenants.connections[0].jdbcSubProtocol=mysql +tenants.connections[0].name=gorilla +tenants.connections[0].pool_abandon_when_percentage_full=50 +tenants.connections[0].pool_initial_size=5 +tenants.connections[0].pool_log_abandoned=1 +tenants.connections[0].pool_max_active=40 +tenants.connections[0].pool_max_idle=10 +tenants.connections[0].pool_min_evictable_idle_time_millis=60000 +tenants.connections[0].pool_min_idle=20 +tenants.connections[0].pool_remove_abandoned=1 +tenants.connections[0].pool_remove_abandoned_timeout=60 +tenants.connections[0].pool_suspect_timeout=60 +tenants.connections[0].pool_test_on_borrow=1 +tenants.connections[0].pool_time_between_eviction_runs_millis=34000 +tenants.connections[0].pool_validation_interval=30000 +tenants.connections[0].schema_connection_parameters=null +tenants.connections[0].schema_name=gorilla +tenants.connections[0].schema_password=password +tenants.connections[0].schema_server=operationsmysql +tenants.connections[0].schema_server_port=3306 +tenants.connections[0].schema_username=mifos +tenants.connections[1].auto_update=true +tenants.connections[1].deadlock_max_retries=0 +tenants.connections[1].deadlock_max_retry_interval=1 +tenants.connections[1].driver_class=com.mysql.cj.jdbc.Driver +tenants.connections[1].jdbcProtocol=jdbc +tenants.connections[1].jdbcSubProtocol=mysql +tenants.connections[1].name=rhino +tenants.connections[1].pool_abandon_when_percentage_full=50 +tenants.connections[1].pool_initial_size=5 +tenants.connections[1].pool_log_abandoned=1 +tenants.connections[1].pool_max_active=40 +tenants.connections[1].pool_max_idle=10 +tenants.connections[1].pool_min_evictable_idle_time_millis=60000 +tenants.connections[1].pool_min_idle=20 +tenants.connections[1].pool_remove_abandoned=1 +tenants.connections[1].pool_remove_abandoned_timeout=60 +tenants.connections[1].pool_suspect_timeout=60 +tenants.connections[1].pool_test_on_borrow=1 +tenants.connections[1].pool_time_between_eviction_runs_millis=34000 +tenants.connections[1].pool_validation_interval=30000 +tenants.connections[1].schema_connection_parameters=null +tenants.connections[1].schema_name=rhino +tenants.connections[1].schema_password=password +tenants.connections[1].schema_server=operationsmysql +tenants.connections[1].schema_server_port=3306 +tenants.connections[1].schema_username=mifos +tenants.connections[2].auto_update=true +tenants.connections[2].deadlock_max_retries=0 +tenants.connections[2].deadlock_max_retry_interval=1 +tenants.connections[2].driver_class=com.mysql.cj.jdbc.Driver +tenants.connections[2].jdbcProtocol=jdbc +tenants.connections[2].jdbcSubProtocol=mysql +tenants.connections[2].name=lion +tenants.connections[2].pool_abandon_when_percentage_full=50 +tenants.connections[2].pool_initial_size=5 +tenants.connections[2].pool_log_abandoned=1 +tenants.connections[2].pool_max_active=40 +tenants.connections[2].pool_max_idle=10 +tenants.connections[2].pool_min_evictable_idle_time_millis=60000 +tenants.connections[2].pool_min_idle=20 +tenants.connections[2].pool_remove_abandoned=1 +tenants.connections[2].pool_remove_abandoned_timeout=60 +tenants.connections[2].pool_suspect_timeout=60 +tenants.connections[2].pool_test_on_borrow=1 +tenants.connections[2].pool_time_between_eviction_runs_millis=34000 +tenants.connections[2].pool_validation_interval=30000 +tenants.connections[2].schema_connection_parameters=null +tenants.connections[2].schema_name=lion +tenants.connections[2].schema_password=password +tenants.connections[2].schema_server=operationsmysql +tenants.connections[2].schema_server_port=3306 +tenants.connections[2].schema_username=mifos \ No newline at end of file diff --git a/ph-ee-env-labs/helm/g2p-sandbox-fynarfin-demo/templates/config.yml b/ph-ee-env-labs/helm/g2p-sandbox-fynarfin-demo/templates/config.yml new file mode 100644 index 000000000..98f65ae95 --- /dev/null +++ b/ph-ee-env-labs/helm/g2p-sandbox-fynarfin-demo/templates/config.yml @@ -0,0 +1,6 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: ph-ee-config +data: +{{ (.Files.Glob "config/**.properties").AsConfig | nindent 2 }} diff --git a/ph-ee-env-labs/helm/g2p-sandbox-fynarfin-demo/values.yaml b/ph-ee-env-labs/helm/g2p-sandbox-fynarfin-demo/values.yaml new file mode 100644 index 000000000..def5c84ba --- /dev/null +++ b/ph-ee-env-labs/helm/g2p-sandbox-fynarfin-demo/values.yaml @@ -0,0 +1,503 @@ +ph-ee-g2psandbox: + ph-ee-engine: + + zeebe-cluster-helm: + enabled: true + + elasticsearch: + enabled: false + kibana: + enabled: true + + zeebe-operate-helm: + ingress: + enabled: true + host: operate-demo.sandbox.fynarfin.io + + kibana: + ingress: + enabled: true + className: "nginx" + pathtype: "Prefix" + annotations: {} + # kubernetes.io/ingress.class: nginx + # kubernetes.io/tls-acme: "true" + hosts: + - host: analytics-demo.sandbox.fynarfin.io + paths: + - path: / + + operations: + + ph-ee-connector: + ingress: + enabled: true + annotations: + kubernetes.io/ingress.class: nginx + tls: + - secretName: sandbox-secret + hosts: + - host: connector-demo.sandbox.mifos.io + paths: + - path: "/" + backend: + service: + name: ph-ee-connector + port: + number: 80 + + + ph_ee_connector_ams_mifos: + enabled: true + image: docker.io/openmf/ph-ee-connector-ams-mifos:latest + imageTag: v1.2.2 + deployment: + annotations: + rollme: '{{ randAlphaNum 5 | quote }}' + ams_local_interop_host: "https://fynams.sandbox.fynarfin.io/" + ams_local_account_host: "https://fynams.sandbox.fynarfin.io/" + ams_local_customer_host: "https://fynams.sandbox.fynarfin.io/" + ams_local_auth_host: "https://fynams.sandbox.fynarfin.io/" + ams_local_loan_host: "https://fynams.sandbox.fynarfin.io/" + ingress: + enabled: true + hosts: + - host: ams-mifos-demo.sandbox.fynarfin.io + paths: + - path: "/" + backend: + service: + name: ph-ee-connector-ams-mifos + port: + number: 80 + - host: ams-mifos-mock-demo.sandbox.fynarfin.io + paths: + - path: "/" + backend: + service: + name: ph-ee-connector-ams-mifos + port: + number: 7070 + + ph_ee_connector_mojaloop: + enabled: true + image: docker.io/openmf/ph-ee-connector-mojaloop:latest + imageTag: "830df54849" + switch: + quotes: + host: "http://quoting-service.sandbox.fynarfin.io" + service: "quoting-service.sandbox.fynarfin.io" + als: + host: "http://account-lookup-service.sandbox.fynarfin.io" + service: "account-lookup-service.sandbox.fynarfin.io" + transfers: + host: "http://ml-api-adapter.sandbox.fynarfin.io" + service: "api-adapter.sandbox.fynarfin.io" + transactions: + host: "http://ml-api-adapter.sandbox.fynarfin.io" + service: "ml-api-adapter.sandbox.fynarfin.io" + oracle: + host: "http://moja-simulator.sandbox.fynarfin.io" + deployment: + extraEnvs: + - name: parties_0_domain + value: "https://fynams.sandbox.fynarfin.io/" + - name: parties_1_domain + value: "mojaloop-demo.sandbox.fynarfin.io" + - name: parties_0_tenantId + value: "gorilla" + - name: parties_1_tenantId + value: "lion" + - name: parties_0_fspId + value: "payerfsp" + - name: parties_1_fspId + value: "payeefsp" + + ingress: + enabled: true + tls: + - secretName: fyn-cert + hosts: + - host: mojaloop-demo.sandbox.fynarfin.io + paths: + - path: "/" + backend: + service: + name: ph-ee-connector-mojaloop-java + port: + number: 80 + + # kafka: + + channel: + enabled: true + image: docker.io/openmf/ph-ee-connector-channel:latest + server: + ssl: + keyPassword: "password" + keyStorePassword: "password" + deployment: + annotations: + rollme: "{{ randAlphaNum 5 | quote }}" + service: + annotations: + konghq.com/protocol: "https" + ingress: + enabled: true + annotations: + kubernetes.io/ingress.class: nginx + nginx.ingress.kubernetes.io/backend-protocol: "HTTPS" + hosts: + - host: channel-demo.sandbox.fynarfin.io + paths: + - path: "/" + backend: + service: + name: "ph-ee-connector-channel" + port: + number: 8443 + - host: channel-gsma-demo.sandbox.fynarfin.io + paths: + - path: "/" + backend: + service: + name: "ph-ee-connector-channel-gsma" + port: + number: 82 + + + operations_app: + enabled: true + image: docker.io/openmf/ph-ee-operations-app:latest + tenants: "rhino,gorilla" + deployment: + annotations: + rollme: "{{ randAlphaNum 5 | quote }}" + ingress: + enabled: true + hosts: + - host: ops-bk-demo.sandbox.fynarfin.io + paths: + - path: "/" + backend: + service: + name: "ph-ee-operations-app" + port: + number: 80 + + operations_web: + enabled: true + image: docker.io/openmf/ph-ee-operations-web:latest + ingress: + enabled: true + annotations: + kubernetes.io/ingress.class: "nginx" + hosts: + - host: ops-demo.sandbox.fynarfin.io + paths: + - path: "/" + backend: + service: + name: "ph-ee-operations-web" + port: + number: 4200 + backend: + PH_OPS_BACKEND_SERVER_URL: https://ops-bk-demo.sandbox.fynarfin.io/api/v1 + PH_VOU_BACKEND_SERVER_URL: https://vouchers-demo.sandbox.fynarfin.io + PH_ACT_BACKEND_SERVER_URL: https://identity-mapper-demo.sandbox.fynarfin.io + PH_PLATFORM_TENANT_ID: gorilla + PH_PLATFORM_TENANT_IDS: gorilla + PH_REGISTERING_INSTITUTION_ID: 123 + auth: + PH_AUTH_ENABLED: false + PH_OAUTH_ENABLED: false + PH_OAUTH_TYPE: keycloak + PH_OAUTH_SERVER_URL: http://keycloak.sandbox.fynarfin.io/auth + PH_OAUTH_REALM: paymenthub + PH_OAUTH_CLIENT_ID: opsapp + PH_OAUTH_CLIENT_SECRET: Y2xpZW50Og== + PH_OAUTH_BASIC_AUTH: true + PH_OAUTH_BASIC_AUTH_TOKEN: Y2xpZW50Og== + PH_DEFAULT_LANGUAGE: en + PH_SUPPORTED_LANGUAGES: en,fr,es + + ph_ee_connector_gsma: + enabled: true + image: docker.io/openmf/ph-ee-connector-gsma:latest + ingress: + enabled: true + + ph_ee_connector_slcb: + enabled: false + + mpesa: + enabled: false + + roster_connector: + enabled: false + + paygops_connector: + enabled: false + + notifications: + enabled: true + image: docker.io/openmf/ph-ee-notifications:latest + NOTIFICATION_FAILURE_ENABLED: "false" + ingress: + enabled: true + hosts: + - host: notifications-demo.sandbox.fynarfin.io + paths: + - path: "/" + backend: + service: + name: "ph-ee-connector-notifications" + port: + number: 80 + + + connector_bulk: + enabled: true + image: docker.io/openmf/ph-ee-bulk-processor:latest + tenants: "rhino,gorilla" + deployment: + annotations: + rollme: "{{ randAlphaNum 5 | quote }}" + operations_app: + contactpoint: "https://ops-bk-demo.sandbox.fynarfin.io/" + endpoints: + batch_transaction: "/api/v1/batch/transactions" + identity_account_mapper: + hostname: "https://identity-mapper-demo.sandbox.fynarfin.io" + ingress: + enabled: true + annotations: + kubernetes.io/ingress.class: nginx + tls: + - secretName: sandbox-secret + hosts: + - host: bulk-connector-demo.sandbox.fynarfin.io + paths: + - path: "/" + backend: + service: + name: "ph-ee-connector-bulk" + port: + number: 8443 + + zeebe_ops: + enabled: true + tenants: "rhino,gorilla" + ingress: + enabled: true + hosts: + - host: zeebeops-demo.sandbox.fynarfin.io + paths: + - path: "/" + backend: + service: + name: "ph-ee-zeebe-ops" + port: + number: 80 + + messagegateway: + enabled: true + image: docker.io/openmf/message-gateway:latest + secret: + value: + api_key: "eKiC1_JWdKy7eaTGQFHxXXjXjacr60W9Zntl" + project_id: "PJ5ff552ce01d2978c" + ingress: + enabled: true + hosts: + - host: messagegateway-demo.sandbox.fynarfin.io + paths: + - path: "/" + backend: + service: + name: "message-gateway" + port: + number: 80 + + importer_es: + enabled: true + image: docker.io/openmf/ph-ee-importer-es:latest + + importer_rdbms: + enabled: true + image: docker.io/openmf/ph-ee-importer-rdbms:latest + aws: + region: "ap-south-1" + + mockpayment: + enabled: true + image: docker.io/openmf/ph-ee-connector-mock-payment-schema:latest + ingress: + enabled: true + annotations: + kubernetes.io/ingress.class: nginx + hosts: + - host: mockpaymentschema-demo.sandbox.fynarfin.io + paths: + - path: "/" + backend: + service: + name: "ph-ee-connector-mock-payment-schema" + port: + number: 8080 + + billPay: + enabled: true + image: docker.io/openmf/ph-ee-bill-pay:latest + billpay: + contactpoint: "https://bill-pay-demo.sandbox.fynarfin.io" + connector: + contactpoint: "https://connector-demo.sandbox.fynarfin.io" + ingress: + enabled: true + annotations: + kubernetes.io/ingress.class: nginx + hosts: + - host: bill-pay-demo.sandbox.fynarfin.io + paths: + - path: "/" + backend: + service: + name: "ph-ee-connector-bill-pay" + port: + number: 8080 + crm: + enabled: true + image: docker.io/openmf/ph-ee-connector-crm:latest + ingress: + enabled: true + annotations: + kubernetes.io/ingress.class: nginx + hosts: + - host: connector-crm-demo.sandbox.fynarfin.io + paths: + - path: "/" + backend: + service: + name: "ph-ee-connector-crm" + port: + number: 8080 + + wildcardhostname: "*.sandbox.fynarfin.io" + tls: "" + + post_installation_job: + enabled: false + + keycloak: + enabled: false + ingress: + enabled: true + rules: + - host: 'keycloak.sandbox.fynarfin.io' + paths: + - path: / + pathType: Prefix + + + kong: + enabled: false + ingress: + enabled: true + hostname: admin-kong.sandbox.fynarfin.io + + redis: + enabled: true + replica: + replicaCount: 0 + + vouchers: + enabled: true + image: docker.io/openmf/ph-ee-vouchers:latest + + voucher: + hostname: "https://vouchers-demo.sandbox.fynarfin.io" + + salting: + enabled: true + + identity-account-mapper: + hostname: "https://identity-mapper-demo.sandbox.fynarfin.io" + operations: + hostname: "https://ops-bk-demo.sandbox.fynarfin.io" + endpoints: + transfers: "/api/v1/transfers?size=1&page=0" + + deployment: + annotations: + rollme: "{{ randAlphaNum 5 | quote }}" + ingress: + enabled: true + annotations: + kubernetes.io/ingress.class: nginx + tls: + - secretName: sandbox-secret + hosts: + - host: vouchers-demo.sandbox.fynarfin.io + paths: + - path: "/" + backend: + service: + name: "ph-ee-vouchers" + port: + number: 80 + connector: + enabled: true + image: docker.io/openmf/ph-ee-connector-bulk:latest + deployment: + annotations: + rollme: "{{ randAlphaNum 5 | quote }}" + ingress: + enabled: true + annotations: + kubernetes.io/ingress.class: nginx + tls: + - secretName: sandbox-secret + hosts: + - host: connector-demo.sandbox.fynarfin.io + paths: + - path: "/" + backend: + service: + name: "ph-ee-connector" + port: + number: 80 + minio: + enabled: true + consoleIngress: + enabled: true + annotations: + kubernetes.io/ingress.class: "nginx" + nginx.ingress.kubernetes.io/backend-protocol: "HTTP" + hosts: + - minio-console-demo.sandbox.fynarfin.io + account_mapper: + enabled: true + image: docker.io/openmf/ph-ee-identity-account-mapper:latest + deployment: + annotations: + rollme: "{{ randAlphaNum 5 | quote }}" + ingress: + enabled: true + annotations: + kubernetes.io/ingress.class: nginx + tls: + - secretName: sandbox-secret + hosts: + - host: identity-mapper-demo.sandbox.fynarfin.io + paths: + - path: "/" + backend: + service: + name: "ph-ee-identity-account-mapper" + port: + number: 80 + + + + diff --git a/ph-ee-env-labs/helm/g2p-sandbox-security-fynarfin-SIT/Chart.yaml b/ph-ee-env-labs/helm/g2p-sandbox-security-fynarfin-SIT/Chart.yaml new file mode 100644 index 000000000..d859cc80e --- /dev/null +++ b/ph-ee-env-labs/helm/g2p-sandbox-security-fynarfin-SIT/Chart.yaml @@ -0,0 +1,11 @@ +apiVersion: v2 +name: ph-ee-g2psandbox-security-fynarfin +description: PaymentHub EE Barebone Edition +type: application +version: 0.0.0 +appVersion: 1.0.0 + +dependencies: +- name: ph-ee-g2psandbox-security + repository: https://fynarfin.io/images/ph-ee-g2psandbox-security + version: 0.0.0 \ No newline at end of file diff --git a/ph-ee-env-labs/helm/g2p-sandbox-security-fynarfin-SIT/README.md b/ph-ee-env-labs/helm/g2p-sandbox-security-fynarfin-SIT/README.md new file mode 100644 index 000000000..5f69c0ac8 --- /dev/null +++ b/ph-ee-env-labs/helm/g2p-sandbox-security-fynarfin-SIT/README.md @@ -0,0 +1,2 @@ +Helm Upgrade command ----> +hehelm upgrade -f helm/g2p-sandbox-security/values.yaml g2p-sandbox-security helm/g2p-sandbox-security --install --create-namespace --namespace security \ No newline at end of file diff --git a/ph-ee-env-labs/helm/g2p-sandbox-security-fynarfin-SIT/values.yaml b/ph-ee-env-labs/helm/g2p-sandbox-security-fynarfin-SIT/values.yaml new file mode 100644 index 000000000..cc6c2bb32 --- /dev/null +++ b/ph-ee-env-labs/helm/g2p-sandbox-security-fynarfin-SIT/values.yaml @@ -0,0 +1,25 @@ +ph-ee-g2psandbox-security: + ph-ee-engine: + + keycloak: + enabled: true + ingress: + enabled: true + ingressClassName: "kong" + rules: + - host: 'keycloak.sandbox.fynarfin.io' + paths: + - path: / + pathType: Prefix + + kong: + enabled: true + env: + database: "postgres" + admin: + ingress: + enabled: true + hostname: 'kong-admin.sandbox.fynarfin.io' + + wildcardhostname: "*.sandbox.fynarfin.io" + tls: "" \ No newline at end of file diff --git a/ph-ee-env-labs/helm/international-remittance/Chart.yaml b/ph-ee-env-labs/helm/international-remittance/Chart.yaml new file mode 100644 index 000000000..afb7a3316 --- /dev/null +++ b/ph-ee-env-labs/helm/international-remittance/Chart.yaml @@ -0,0 +1,12 @@ +apiVersion: v2 +name: ph-ee-barebone +description: PaymentHub EE Barebone Edition + +type: application +version: 0.1.0 +appVersion: 1.16.0 + +dependencies: +- name: ph-ee-engine + repository: https://fynarfin.io/images/ + version: 1.0.0-SNAPSHOT diff --git a/ph-ee-env-labs/helm/international-remittance/config/application-bb.properties b/ph-ee-env-labs/helm/international-remittance/config/application-bb.properties new file mode 100644 index 000000000..316b37f62 --- /dev/null +++ b/ph-ee-env-labs/helm/international-remittance/config/application-bb.properties @@ -0,0 +1,9 @@ +ams.local.interop.host=https://rhino.mifos.io:8443 +ams.local.customer.host=https://rhino.mifos.io:8443 +zeebe.broker.contactpoint=zeebe-zeebe-gateway:26500 + +security.oauth2.resource.jwt.key-uri=http://bb-identity.mifos.io/oauth/token_key +rest.authorization.enabled=false +rest.authorization.host=http://bb-identity.mifos.io + +dfspids=tn03,tn04 \ No newline at end of file diff --git a/ph-ee-env-labs/helm/international-remittance/config/application-fin12.properties b/ph-ee-env-labs/helm/international-remittance/config/application-fin12.properties new file mode 100644 index 000000000..660ad0184 --- /dev/null +++ b/ph-ee-env-labs/helm/international-remittance/config/application-fin12.properties @@ -0,0 +1,2 @@ +ams.localenabled=true +zeebe.broker.contactpoint=zeebe-zeebe-gateway:26500 \ No newline at end of file diff --git a/ph-ee-env-labs/helm/international-remittance/templates/config.yml b/ph-ee-env-labs/helm/international-remittance/templates/config.yml new file mode 100644 index 000000000..98f65ae95 --- /dev/null +++ b/ph-ee-env-labs/helm/international-remittance/templates/config.yml @@ -0,0 +1,6 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: ph-ee-config +data: +{{ (.Files.Glob "config/**.properties").AsConfig | nindent 2 }} diff --git a/ph-ee-env-labs/helm/international-remittance/templates/elephant-connector-mojaloop-java-ingress.yml b/ph-ee-env-labs/helm/international-remittance/templates/elephant-connector-mojaloop-java-ingress.yml new file mode 100644 index 000000000..da6b82871 --- /dev/null +++ b/ph-ee-env-labs/helm/international-remittance/templates/elephant-connector-mojaloop-java-ingress.yml @@ -0,0 +1,14 @@ +apiVersion: extensions/v1beta1 +kind: Ingress +metadata: + name: in02tn04-ph-ee-connector-mojaloop-java + annotations: + kubernetes.io/ingress.class: azure/application-gateway +spec: + rules: + - host: in02tn04.mifos.io + http: + paths: + - backend: + serviceName: ph-ee-connector-mojaloop-java + servicePort: 80 diff --git a/ph-ee-env-labs/helm/international-remittance/templates/rhino-connector-mojaloop-java-ingress.yml b/ph-ee-env-labs/helm/international-remittance/templates/rhino-connector-mojaloop-java-ingress.yml new file mode 100644 index 000000000..7bd314447 --- /dev/null +++ b/ph-ee-env-labs/helm/international-remittance/templates/rhino-connector-mojaloop-java-ingress.yml @@ -0,0 +1,14 @@ +apiVersion: extensions/v1beta1 +kind: Ingress +metadata: + name: in02tn03-ph-ee-connector-mojaloop-java + annotations: + kubernetes.io/ingress.class: azure/application-gateway +spec: + rules: + - host: in02tn03.mifos.io + http: + paths: + - backend: + serviceName: ph-ee-connector-mojaloop-java + servicePort: 80 diff --git a/ph-ee-env-labs/helm/international-remittance/values.yaml b/ph-ee-env-labs/helm/international-remittance/values.yaml new file mode 100644 index 000000000..1a12c67cf --- /dev/null +++ b/ph-ee-env-labs/helm/international-remittance/values.yaml @@ -0,0 +1,134 @@ +ph-ee-engine: + zeebe-cluster-helm: + global: + elasticsearch: + host: "ph-ee-elasticsearch" + image: + repository: camunda/zeebe + tag: 1.1.0 + + clusterSize: "1" + partitionCount: "1" + replicationFactor: "1" + + elasticsearch: + enabled: false + kibana: + enabled: false + + extraInitContainers: | + - name: init-ph-ee-kafka-exporter + image: busybox:1.28 + command: ['/bin/sh', '-c'] + args: ['wget -O /exporters/ph-ee-kafka-exporter.jar "https://paymenthub-ee-dev.s3.us-east-2.amazonaws.com/jars/exporter-1.0.0-SNAPSHOT.jar"; ls -al /exporters/'] + volumeMounts: + - name: exporters + mountPath: /exporters/ + + zeebe-operate-helm: + enabled: true + image: + repository: camunda/operate + tag: 1.1.0 + global: + elasticsearch: + host: "ph-ee-elasticsearch" + clusterName: "ph-ee-elasticsearch" + + elasticsearch: + enabled: true + replicas: 1 + imageTag: 7.13.2 + minimumMasterNodes: 1 + + #Single Node Solution + clusterHealthCheckParams: "wait_for_status=yellow&timeout=100s" + master: + readinessProbe: + httpGet: + path: /_cluster/health?wait_for_status=yellow&timeout=5s + port: 9200 + initialDelaySeconds: 30 + data: + readinessProbe: + httpGet: + path: /_cluster/health?wait_for_status=yellow&timeout=5s + port: 9200 + initialDelaySeconds: 30 + + esConfig: + elasticsearch.yml: | + discovery: + type: single-node + seed_hosts: "" + xpack: + security: + enabled: false + + # Shrink default JVM heap. + esJavaOpts: "-Xmx128m -Xms128m" + + # Allocate smaller chunks of memory per pod. + resources: + requests: + cpu: "100m" + memory: "512M" + limits: + cpu: "1000m" + memory: "512M" + volumeClaimTemplate: + accessModes: [ "ReadWriteOnce" ] + storageClassName: "standard" + resources: + requests: + storage: 10Gi + + kibana: + enabled: true + imageTag: 7.13.2 + + kibanaConfig: + kibana.yml: | + monitoring.enabled: false + + operations: + enabled: true + + operationsMysql: + mysqlRootPassword: "ethieTieCh8ahv" + mysqlUser: "mifos" + mysqlPassword: "password" + mysqlDatabase: "tenants" + initializationFiles: + setup.sql: |- + CREATE DATABASE tn03; + CREATE DATABASE tn04; + GRANT ALL PRIVILEGES ON tn03.* TO 'mifos'; + GRANT ALL PRIVILEGES ON tn04.* TO 'mifos'; + + ph_ee_connector_ams_mifos: + SPRING_PROFILES_ACTIVE: "fin12,bb" + + ph_ee_connector_mojaloop: + SPRING_PROFILES_ACTIVE: "bb" + + ph_ee_connector_channel: + SPRING_PROFILES_ACTIVE: "bb" + hostname: "barebone-connector-channel.mifos.io" + AWS_ACCESS_KEY: "xxx" + AWS_SECRET_KEY: "xxx" + + ph_ee_operations_app: + SPRING_PROFILES_ACTIVE: "bb" + hostname: "barebone-operations.mifos.io" + + ph_ee_operations: + SPRING_PROFILES_ACTIVE: "bb" + hostname: "barebone-operations.mifos.io" + webhost: "barebone-operations-ui.mifos.io" + + ph_ee_identity: + hostname: "barebone-identity.mifos.io" + + ph_ee_connector_gsma: + SPRING_PROFILES_ACTIVE: "bb" diff --git a/ph-ee-env-labs/helm/kibana-secret/examples.mk b/ph-ee-env-labs/helm/kibana-secret/examples.mk new file mode 100644 index 000000000..9c8b851b5 --- /dev/null +++ b/ph-ee-env-labs/helm/kibana-secret/examples.mk @@ -0,0 +1,29 @@ +SHELL := /bin/bash +GOSS_VERSION := v0.3.18 +GOSS_FILE ?= goss.yaml +GOSS_SELECTOR ?= release=$(RELEASE) +STACK_VERSION := 7.16.3 +TIMEOUT := 900s +NAMESPACE = $(ENV_NAMESPACE) + +.PHONY: help +help: ## Display this help + @awk 'BEGIN {FS = ":.*##"; printf "Usage: make \033[36m\033[0m\n\nTargets:\n"} /^[a-zA-Z0-9_-]+:.*?##/ { printf " \033[36m%-10s\033[0m %s\n", $$1, $$2 }' $(MAKEFILE_LIST) + +.PHONY: goss +goss: ## Run goss tests + set -e; \ + for i in $$(seq 1 5); do \ + curl -s -L "https://github.com/aelsabbahy/goss/releases/download/$(GOSS_VERSION)/goss-linux-amd64" -o /tmp/goss; \ + if [ -z "$$GOSS_CONTAINER" ]; then \ + sleep 5; \ + echo "Retrieving pod ($$i/5)"; \ + GOSS_CONTAINER=$$(kubectl get --no-headers=true pods -l "$(GOSS_SELECTOR)" -o custom-columns=:metadata.name --field-selector=status.phase=Running --sort-by=.metadata.creationTimestamp | tail -1 ); \ + else \ + echo "Testing with pod: $$GOSS_CONTAINER" && \ + kubectl cp "test/$(GOSS_FILE)" "$$GOSS_CONTAINER:/tmp/$(GOSS_FILE)" && \ + kubectl cp "/tmp/goss" "$$GOSS_CONTAINER:/tmp/goss" && \ + kubectl exec "$$GOSS_CONTAINER" -- sh -c "chmod +rx /tmp/goss && if [ -f ~/.elasticsearch-serviceaccounttoken ]; then . ~/.elasticsearch-serviceaccounttoken; fi; /tmp/goss --gossfile \"/tmp/$(GOSS_FILE)\" validate --retry-timeout 300s --sleep 5s --color --format documentation"; \ + break; \ + fi; \ + done diff --git a/ph-ee-env-labs/helm/kibana-secret/makefile b/ph-ee-env-labs/helm/kibana-secret/makefile new file mode 100644 index 000000000..91fa41972 --- /dev/null +++ b/ph-ee-env-labs/helm/kibana-secret/makefile @@ -0,0 +1,19 @@ +default: test +include examples.mk +RELEASE := helm-kibana-security + +install: + helm upgrade --wait --timeout=$(TIMEOUT) --install --values values.yaml $(RELEASE) ../../ + +test: secrets install goss + +purge: + kubectl delete secret kibana || true + helm del $(RELEASE) + +secrets: + #encryptionkey=$$(docker run --rm busybox:1.31.1 /bin/sh -c "< /dev/urandom tr -dc _A-Za-z0-9 | head -c50") && \ + + encryptionkey=MMFI5EFpJnib4MDDbRPuJ1UNIRiHuMud_r_EfBNprx7qVRlO7R && \ + kubectl create namespace $(NAMESPACE) || echo "namespace already exists" && \ + kubectl create secret generic kibana --namespace=$(NAMESPACE) --from-literal=encryptionkey=$$encryptionkey diff --git a/ph-ee-env-labs/helm/mojaloop-barebone/.helmignore b/ph-ee-env-labs/helm/mojaloop-barebone/.helmignore new file mode 100644 index 000000000..0e8a0eb36 --- /dev/null +++ b/ph-ee-env-labs/helm/mojaloop-barebone/.helmignore @@ -0,0 +1,23 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*.orig +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ diff --git a/ph-ee-env-labs/helm/mojaloop-barebone/Chart.yaml b/ph-ee-env-labs/helm/mojaloop-barebone/Chart.yaml new file mode 100644 index 000000000..afb7a3316 --- /dev/null +++ b/ph-ee-env-labs/helm/mojaloop-barebone/Chart.yaml @@ -0,0 +1,12 @@ +apiVersion: v2 +name: ph-ee-barebone +description: PaymentHub EE Barebone Edition + +type: application +version: 0.1.0 +appVersion: 1.16.0 + +dependencies: +- name: ph-ee-engine + repository: https://fynarfin.io/images/ + version: 1.0.0-SNAPSHOT diff --git a/ph-ee-env-labs/helm/mojaloop-barebone/OAFUAT b/ph-ee-env-labs/helm/mojaloop-barebone/OAFUAT new file mode 100644 index 000000000..5c300d37f --- /dev/null +++ b/ph-ee-env-labs/helm/mojaloop-barebone/OAFUAT @@ -0,0 +1,45 @@ +Barebones + +cd ph-ee-env-template +cd helm/ph-ee-engine +rm -f Chart.lock requirements.lock charts/* +helm dep up +cd .. +helm package ph-ee-engine +helm repo index . + +scp -i /Users/avik/Downloads/fynarfin.pem index.yaml ph-ee-engine-1.0.0-SNAPSHOT.tgz ec2-user@13.233.68.128:~/ +ssh -i /Users/avik/Downloads/fynarfin.pem ec2-user@13.233.68.128 +sudo mv index.yaml /apps/apache-tomcat-7.0.82/webapps/ROOT/images/ +sudo mv ph-ee-engine-1.0.0-SNAPSHOT.tgz /apps/apache-tomcat-7.0.82/webapps/ROOT/images/ +exit + +cd ../.. +cd ph-ee-env-labs/helm/payment-hub-barebone/ +rm -f Chart.lock requirements.lock charts/* +helm dep up +cd .. +helm upgrade -f payment-hub-barebone/values.yaml payment-hub-barebone-1599042110 payment-hub-barebone +cd ../.. + + +helm install -f payment-hub-barebone/values.yaml payment-hub-barebone payment-hub-barebone + +https://paymenthub.qa.oneacrefund.org/channel +https://paymenthub.qa.oneacrefund.org/identity +https://paymenthub.qa.oneacrefund.org/ops-bk +https://paymenthub.qa.oneacrefund.org/ops +https://paymenthub.qa.oneacrefund.org/analytics +https://paymenthub.qa.oneacrefund.org/zeebe +https://paymenthub.qa.oneacrefund.org/mpesa +https://paymenthub.qa.oneacrefund.org/notifications +https://paymenthub.qa.oneacrefund.org/roster + + + +- Supertset (gsma + intl remittance + oaf + g2p) ph-ee-engine (env-template) and helm chart (env labs) added. +- Simplified Superset Chart Deployment (https://docs.google.com/document/d/13c4whmzEYv3BbTT4yEk1BRLJSkzyva8x177El0peC94/edit?usp=sharing) + +- . + + diff --git a/ph-ee-env-labs/helm/mojaloop-barebone/config/application-bb.properties b/ph-ee-env-labs/helm/mojaloop-barebone/config/application-bb.properties new file mode 100644 index 000000000..316b37f62 --- /dev/null +++ b/ph-ee-env-labs/helm/mojaloop-barebone/config/application-bb.properties @@ -0,0 +1,9 @@ +ams.local.interop.host=https://rhino.mifos.io:8443 +ams.local.customer.host=https://rhino.mifos.io:8443 +zeebe.broker.contactpoint=zeebe-zeebe-gateway:26500 + +security.oauth2.resource.jwt.key-uri=http://bb-identity.mifos.io/oauth/token_key +rest.authorization.enabled=false +rest.authorization.host=http://bb-identity.mifos.io + +dfspids=tn03,tn04 \ No newline at end of file diff --git a/ph-ee-env-labs/helm/mojaloop-barebone/config/application-fin12.properties b/ph-ee-env-labs/helm/mojaloop-barebone/config/application-fin12.properties new file mode 100644 index 000000000..660ad0184 --- /dev/null +++ b/ph-ee-env-labs/helm/mojaloop-barebone/config/application-fin12.properties @@ -0,0 +1,2 @@ +ams.localenabled=true +zeebe.broker.contactpoint=zeebe-zeebe-gateway:26500 \ No newline at end of file diff --git a/ph-ee-env-labs/helm/mojaloop-barebone/templates/config.yml b/ph-ee-env-labs/helm/mojaloop-barebone/templates/config.yml new file mode 100644 index 000000000..98f65ae95 --- /dev/null +++ b/ph-ee-env-labs/helm/mojaloop-barebone/templates/config.yml @@ -0,0 +1,6 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: ph-ee-config +data: +{{ (.Files.Glob "config/**.properties").AsConfig | nindent 2 }} diff --git a/ph-ee-env-labs/helm/mojaloop-barebone/templates/elephant-connector-mojaloop-java-ingress.yml b/ph-ee-env-labs/helm/mojaloop-barebone/templates/elephant-connector-mojaloop-java-ingress.yml new file mode 100644 index 000000000..d50ad5eb2 --- /dev/null +++ b/ph-ee-env-labs/helm/mojaloop-barebone/templates/elephant-connector-mojaloop-java-ingress.yml @@ -0,0 +1,18 @@ +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: in02tn04-ph-ee-connector-mojaloop-java + annotations: + kubernetes.io/ingress.class: azure/application-gateway +spec: + rules: + - host: in02tn04.mifos.io + http: + paths: + - path: / + pathType: ImplementationSpecific + backend: + service: + name: ph-ee-connector-mojaloop-java + port: + number: 80 diff --git a/ph-ee-env-labs/helm/mojaloop-barebone/templates/rhino-connector-mojaloop-java-ingress.yml b/ph-ee-env-labs/helm/mojaloop-barebone/templates/rhino-connector-mojaloop-java-ingress.yml new file mode 100644 index 000000000..1053b8082 --- /dev/null +++ b/ph-ee-env-labs/helm/mojaloop-barebone/templates/rhino-connector-mojaloop-java-ingress.yml @@ -0,0 +1,18 @@ +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: in02tn03-ph-ee-connector-mojaloop-java + annotations: + kubernetes.io/ingress.class: azure/application-gateway +spec: + rules: + - host: in02tn03.mifos.io + http: + paths: + - path: / + pathType: "ImplementationSpecific" + backend: + service: + name: ph-ee-connector-mojaloop-java + port: + number: 80 \ No newline at end of file diff --git a/ph-ee-env-labs/helm/mojaloop-barebone/values.yaml b/ph-ee-env-labs/helm/mojaloop-barebone/values.yaml new file mode 100644 index 000000000..65eb6d451 --- /dev/null +++ b/ph-ee-env-labs/helm/mojaloop-barebone/values.yaml @@ -0,0 +1,129 @@ +ph-ee-engine: + zeebe-cluster-helm: + global: + elasticsearch: + host: "ph-ee-elasticsearch" + image: + repository: camunda/zeebe + tag: 1.1.0 + + clusterSize: "1" + partitionCount: "1" + replicationFactor: "1" + + elasticsearch: + enabled: false + kibana: + enabled: false + + extraInitContainers: | + - name: init-ph-ee-kafka-exporter + image: busybox:1.28 + command: ['/bin/sh', '-c'] + args: ['wget -O /exporters/ph-ee-kafka-exporter.jar "https://paymenthub-ee-dev.s3.us-east-2.amazonaws.com/jars/exporter-1.0.0-SNAPSHOT.jar"; ls -al /exporters/'] + volumeMounts: + - name: exporters + mountPath: /exporters/ + + zeebe-operate-helm: + enabled: true + image: + repository: camunda/operate + tag: 1.1.0 + global: + elasticsearch: + host: "ph-ee-elasticsearch" + clusterName: "ph-ee-elasticsearch" + + elasticsearch: + enabled: true + replicas: 1 + imageTag: 7.13.2 + minimumMasterNodes: 1 + + #Single Node Solution + clusterHealthCheckParams: "wait_for_status=yellow&timeout=100s" + master: + readinessProbe: + httpGet: + path: /_cluster/health?wait_for_status=yellow&timeout=5s + port: 9200 + initialDelaySeconds: 30 + data: + readinessProbe: + httpGet: + path: /_cluster/health?wait_for_status=yellow&timeout=5s + port: 9200 + initialDelaySeconds: 30 + + + # Shrink default JVM heap. + esJavaOpts: "-Xmx512m -Xms512m" + + # Allocate smaller chunks of memory per pod. + resources: + requests: + cpu: "200m" + memory: "1024M" + limits: + cpu: "1000m" + memory: "1024M" + volumeClaimTemplate: + accessModes: [ "ReadWriteOnce" ] + storageClassName: "standard" + resources: + requests: + storage: 10Gi + + kibana: + enabled: true + imageTag: 7.13.2 + + kibanaConfig: + kibana.yml: | + monitoring.enabled: false + + operations: + enabled: true + + operationsMysql: + mysqlRootPassword: "ethieTieCh8ahv" + mysqlUser: "mifos" + mysqlPassword: "password" + mysqlDatabase: "tenants" + initializationFiles: + setup.sql: |- + CREATE DATABASE tn03; + CREATE DATABASE tn04; + GRANT ALL PRIVILEGES ON tn03.* TO 'mifos'; + GRANT ALL PRIVILEGES ON tn04.* TO 'mifos'; + + ph_ee_connector_ams_mifos: + SPRING_PROFILES_ACTIVE: "fin12,bb" + + ph_ee_connector_mojaloop: + SPRING_PROFILES_ACTIVE: "bb" + + ph_ee_connector_channel: + SPRING_PROFILES_ACTIVE: "bb" + hostname: "barebone-connector-channel.mifos.io" + AWS_ACCESS_KEY: "xxx" + AWS_SECRET_KEY: "xxx" + + ph_ee_operations_app: + SPRING_PROFILES_ACTIVE: "bb" + hostname: "barebone-operations.mifos.io" + + ph_ee_operations: + SPRING_PROFILES_ACTIVE: "bb" + hostname: "barebone-operations.mifos.io" + webhost: "barebone-operations-ui.mifos.io" + + ph_ee_identity: + hostname: "barebone-identity.mifos.io" + + ph-ee-connector-mpesa: + hostname: "mpesa.ibank.financial" + + ph_ee_connector_gsma: + SPRING_PROFILES_ACTIVE: "bb" diff --git a/ph-ee-env-labs/helm/oaf/Chart.yaml b/ph-ee-env-labs/helm/oaf/Chart.yaml new file mode 100644 index 000000000..5b4392905 --- /dev/null +++ b/ph-ee-env-labs/helm/oaf/Chart.yaml @@ -0,0 +1,12 @@ +apiVersion: v2 +name: ph-ee-barebone +description: PaymentHub EE Barebone Edition + +type: application +version: 0.2.0 +appVersion: 1.16.0 + +dependencies: +- name: ph-ee-engine + repository: https://fynarfin.io/images/ + version: 1.2.0-SNAPSHOT diff --git a/ph-ee-env-labs/helm/oaf/config/application-bb.properties b/ph-ee-env-labs/helm/oaf/config/application-bb.properties new file mode 100644 index 000000000..197a81b31 --- /dev/null +++ b/ph-ee-env-labs/helm/oaf/config/application-bb.properties @@ -0,0 +1,17 @@ +ams.local.interop.host=https://rhino.mifos.io:8443 +ams.local.customer.host=https://rhino.mifos.io:8443 +zeebe.broker.contactpoint=zeebe-zeebe-gateway:26500 + +security.oauth2.resource.jwt.key-uri=http://bb-identity.mifos.io/oauth/token_key +rest.authorization.enabled=false +rest.authorization.host=http://bb-identity.mifos.io + +dfspids=tn03,tn04 +token.client.channel.secret=p1234 + +ams.groups[0].identifier= ACCOUNTID +ams.groups[0].value= roster +ams.groups[1].identifier= FOUNDATIONALID +ams.groups[1].value= paygops +ams.groups[2].identifier= default +ams.groups[2].value= paygops \ No newline at end of file diff --git a/ph-ee-env-labs/helm/oaf/config/application-fin12.properties b/ph-ee-env-labs/helm/oaf/config/application-fin12.properties new file mode 100644 index 000000000..660ad0184 --- /dev/null +++ b/ph-ee-env-labs/helm/oaf/config/application-fin12.properties @@ -0,0 +1,2 @@ +ams.localenabled=true +zeebe.broker.contactpoint=zeebe-zeebe-gateway:26500 \ No newline at end of file diff --git a/ph-ee-env-labs/helm/oaf/templates/config.yml b/ph-ee-env-labs/helm/oaf/templates/config.yml new file mode 100644 index 000000000..98f65ae95 --- /dev/null +++ b/ph-ee-env-labs/helm/oaf/templates/config.yml @@ -0,0 +1,6 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: ph-ee-config +data: +{{ (.Files.Glob "config/**.properties").AsConfig | nindent 2 }} diff --git a/ph-ee-env-labs/helm/oaf/values.yaml b/ph-ee-env-labs/helm/oaf/values.yaml new file mode 100644 index 000000000..2ee761025 --- /dev/null +++ b/ph-ee-env-labs/helm/oaf/values.yaml @@ -0,0 +1,394 @@ +ph-ee-engine: + elasticsearch: + minimumMasterNodes: 1 + esConfig: + elasticsearch.yml: | + xpack.security.enabled: true + xpack.security.transport.ssl.enabled: true + xpack.security.transport.ssl.verification_mode: certificate + xpack.security.transport.ssl.keystore.path: /usr/share/elasticsearch/config/certs/elastic-certificates.p12 + xpack.security.transport.ssl.truststore.path: /usr/share/elasticsearch/config/certs/elastic-certificates.p12 + xpack.security.http.ssl.enabled: true + xpack.security.http.ssl.truststore.path: /usr/share/elasticsearch/config/certs/elastic-certificates.p12 + xpack.security.http.ssl.keystore.path: /usr/share/elasticsearch/config/certs/elastic-certificates.p12 + secretMounts: + - name: elastic-certificates + secretName: elastic-certificates + path: /usr/share/elasticsearch/config/certs + extraEnvs: + - name: ELASTIC_PASSWORD + valueFrom: + secretKeyRef: + name: elastic-credentials + key: password + + + + #Single Node Solution + clusterHealthCheckParams: "wait_for_status=yellow&timeout=100s" + protocol: https + master: + readinessProbe: + httpGet: + allow-insecure: true + username: elastic + password: "{{ .Env.ELASTIC_PASSWORD }}" + path: /_cluster/health?wait_for_status=yellow&timeout=5s + port: 9200 + initialDelaySeconds: 30 + data: + readinessProbe: + httpGet: + allow-insecure: true + username: elastic + password: "{{ .Env.ELASTIC_PASSWORD }}" + path: /_cluster/health?wait_for_status=yellow&timeout=5s + port: 9200 + initialDelaySeconds: 30 + + + # Shrink default JVM heap. + esJavaOpts: "-Xmx512m -Xms512m" + + # Allocate smaller chunks of memory per pod. + resources: + requests: + cpu: "100m" + memory: "512M" + limits: + cpu: "1000m" + memory: "1024M" + volumeClaimTemplate: + accessModes: [ "ReadWriteOnce" ] + storageClassName: "oaf-storage" + resources: + requests: + storage: 10Gi + + kibana: + readinessProbe: + initialDelaySeconds: 45 + timeoutSeconds: 15 + successThreshold: 1 + enabled: true + kibanaConfig: + kibana.yml: | + monitoring.enabled: false + xpack.encryptedSavedObjects.encryptionKey: 5f4dcc3b5aa765d61d8327deb882cf99 + server.ssl: + enabled: true + key: /usr/share/kibana/config/certs/elastic-certificate.pem + certificate: /usr/share/kibana/config/certs/elastic-certificate.pem + xpack.security.encryptionKey: ${KIBANA_ENCRYPTION_KEY} + elasticsearch.ssl: + certificateAuthorities: /usr/share/kibana/config/certs/elastic-certificate.pem + verificationMode: certificate + secretMounts: + - name: elastic-certificate-pem + secretName: elastic-certificate-pem + path: /usr/share/kibana/config/certs + extraEnvs: + - name: 'ELASTICSEARCH_USERNAME' + valueFrom: + secretKeyRef: + name: elastic-credentials + key: username + - name: 'ELASTICSEARCH_PASSWORD' + valueFrom: + secretKeyRef: + name: elastic-credentials + key: password + - name: 'KIBANA_ENCRYPTION_KEY' + valueFrom: + secretKeyRef: + name: kibana + key: encryptionkey + ingress: + enabled: true + className: "nginx" + pathtype: ImplementationSpecific + hosts: + - host: ph-kibana.qa.oneacrefund.org + paths: + - path: / + tls: + - secretName: oafqa-tls + hosts: + - "*.qa.oneacrefund.org" +# env: +# - name: KIBANA_SSL_ENABLED +# value: true + + channel: + DFSPIDS: "oaf" + SPRING_PROFILES_ACTIVE: "bb" + LOGGING_LEVEL_ROOT: "INFO" + hostname: "paymenthub.qa.oneacrefund.org" + image: "oaftech.azurecr.io/phee-ns/ph-ee-connector-channel" + ingress: + annotations: + kubernetes.io/ingress.class: "kong" + konghq.com/strip-path: "true" + backend: + service: + name: ph-ee-connector-channel + port: + number: 80 + deployment: + annotations: + co.elastic.logs/enabled: "true" + deployTime: "{{ .Values.deployTime }}" + ams: + groups: + - identifier: "ACCOUNTID" + value: "paygops" + - identifier: "FOUNDATIONALID" + value: "roster" + + operations: + enabled: true + + operationsmysql: + initdbScripts: + setup.sql: |- + CREATE DATABASE IF NOT EXISTS oaf; + CREATE DATABASE IF NOT EXISTS messagegateway; + GRANT ALL ON *.* TO 'root'@'%'; + GRANT ALL PRIVILEGES ON messagegateway.* TO 'mifos'; + GRANT ALL PRIVILEGES ON oaf.* TO 'mifos'; + + + + + operations_app: + tenants: "oaf" + SPRING_PROFILES_ACTIVE: "bb" + hostname: "paymenthub.qa.oneacrefund.org" + image: "oaftech.azurecr.io/phee-ns/ph-ee-operations-app" + LOGGING_LEVEL_ROOT: "INFO" + ingress: + enabled: true + annotations: + kubernetes.io/ingress.class: "kong" + konghq.com/strip-path: "true" + backend: + service: + name: ph-ee-operations-app + port: + number: 80 + deployment: + annotations: + co.elastic.logs/enabled: "true" + deployTime: "{{ .Values.deployTime }}" + + operations_web: + SPRING_PROFILES_ACTIVE: "bb" + hostname: "ph-web.qa.oneacrefund.org" + webhost: "ph-web.qa.oneacrefund.org" + path: "/" + image: "oaftech.azurecr.io/phee-ns/ops-web" + ingress: + enabled: true + annotations: + kubernetes.io/ingress.class: "nginx" + backend: + service: + name: ph-ee-operations-web + port: + number: 4200 + deployment: + annotations: + co.elastic.logs/enabled: "true" + + identity: + hostname: "paymenthub.qa.oneacrefund.org" + ingress: + annotations: + kubernetes.io/ingress.class: "kong" + konghq.com/strip-path: "true" + + mpesa: + tenant: "oaf" + enabled: true + SPRING_PROFILES_ACTIVE: "bb" + hostname: "paymenthub.qa.oneacrefund.org" + image: "oaftech.azurecr.io/phee-ns/ph-ee-connector-mpesa" + callback_host: "https://paymenthub.qa.oneacrefund.org/mpesa" + zeebe_init_transfer_wait_timer: 5 + retry_count: 3 + accounts: + roster: + name: "roster" + business_short_code: "7385028" + till: "1234567" + auth_host: "https://sandbox.safaricom.co.ke/oauth/v1/generate" + api_host: "https://sandbox.safaricom.co.ke" + client_key: "0pLxbN83FrOl5Nd0Fh9Zi5BQlMxSL2n5" + client_secret: "YzuGNoJxeub8ZC6d" + pass_key: "bfb279f9aa9bdbcf158e97dd71a467cd2e0c893059b10f78e6b72ada1ed2c919" + paygops: + name: "paygops" + business_short_code: "174379" + till: "9347335" + auth_host: "https://sandbox.safaricom.co.ke/oauth/v1/generate" + api_host: "https://sandbox.safaricom.co.ke" + client_key: "0pLxbN83FrOl5Nd0Fh9Zi5BQlMxSL2n5" + client_secret: "YzuGNoJxeub8ZC6d" + pass_key: "bfb279f9aa9bdbcf158e97dd71a467cd2e0c893059b10f78e6b72ada1ed2c919" + LOGGING_LEVEL_ROOT: "INFO" + ingress: + annotations: + kubernetes.io/ingress.class: "kong" + konghq.com/strip-path: "true" + backend: + service: + name: ph-ee-connector-mpesa + port: + number: 80 + deployment: + annotations: + co.elastic.logs/enabled: "true" + deployTime: "{{ .Values.deployTime }}" + skip: + enabled: false + + roster_connector: + enabled: true + SPRING_PROFILES_ACTIVE: "bb" + image: "oaftech.azurecr.io/phee-ns/ph-ee-connector-ams-pesa" + pesacore: + base_url: "https://qaoperations01.oneacrefund.org" + auth_header: "PaymentHubTest" + LOGGING_LEVEL_ROOT: "INFO" + ams: + local: + enabled: true + deployment: + annotations: + co.elastic.logs/enabled: "true" + deployTime: "{{ .Values.deployTime }}" + + paygops_connector: + enabled: true + SPRING_PROFILES_ACTIVE: "bb" + image: "oaftech.azurecr.io/phee-ns/ph-ee-connector-ams-paygops" + paygops: + base_url: "https://feature-test1.paygops.com/" + authheader: "PaymentHubTest" + LOGGING_LEVEL_ROOT: "INFO" + ams: + local: + enabled: true + deployment: + annotations: + co.elastic.logs/enabled: "true" + deployTime: "{{ .Values.deployTime }}" + + notifications: + enabled: true + SPRING_PROFILES_ACTIVE: "bb" + image: "oaftech.azurecr.io/phee-ns/ph-ee-notifications" + hostname: "paymenthub.qa.oneacrefund.org" + LOGGING_LEVEL_ROOT: "INFO" + ingress: + annotations: + kubernetes.io/ingress.class: "kong" + konghq.com/strip-path: "true" + backend: + service: + name: ph-ee-connector-notifications + port: + number: 80 + deployment: + annotations: + co.elastic.logs/enabled: "true" + deployTime: "{{ .Values.deployTime }}" + + + zeebe_ops: + enabled: true + image: "oaftech.azurecr.io/phee-ns/phee-zeebe-ops" + hostname: "paymenthub.qa.oneacrefund.org" + elasticsearch_sslverification: true + elasticsearch_security_enabled: true + ingress: + annotations: + kubernetes.io/ingress.class: "kong" + konghq.com/strip-path: "true" + backend: + service: + name: ph-ee-zeebe-ops + port: + number: 80 + deployment: + annotations: + co.elastic.logs/enabled: "true" + deployTime: "{{ .Values.deployTime }}" + + messagegateway: + enabled: true + image: "oaftech.azurecr.io/phee-ns/message-gateway" + secret: + value: + api_key: "eKiC1_JWdKy7eaTGQFHxXXjXjacr60W9Zntl" + project_id: "PJ5ff552ce01d2978c" + hostname: "paymenthub.qa.oneacrefund.org" + LOGGING_LEVEL_ROOT: "INFO" + ingress: + annotations: + kubernetes.io/ingress.class: "kong" + konghq.com/strip-path: "true" + backend: + service: + name: message-gateway + port: + number: 80 + deployment: + annotations: + co.elastic.logs/enabled: "true" + + + importer_es: + image: "oaftech.azurecr.io/phee-ns/ph-ee-importer-es" + elasticsearch_sslverification: true + elasticsearch_security_enabled: true + reporting: + enabled: true + fields: + amount: true + accountId: true + errorCode: false + errorDescription: true + externalId: true + initiator: false + initiatorType: false + isNotificationsFailureEnabled: false + isNotificationsSuccessEnabled: false + mpesaTransactionId: false + mpesaTransactionStatusRetryCount: false + originDate: false + partyLookupFailed: false + phoneNumber: true + processDefinitionKey: false + processInstanceKey: true + scenario: false + tenantId: false + timer: false + timestamp: true + transactionFailed: false + transactionId: false + transferCreateFailed: false + transferSettlementFailed: false + transferResponseCREATE: false + + importer_rdbms: + enabled: true + image: "oaftech.azurecr.io/phee-ns/ph-ee-importer-rdbms" + LOGGING_LEVEL_ROOT: "INFO" + deployment: + annotations: + co.elastic.logs/enabled: "true" + + wildcardhostname: "*.qa.oneacrefund.org" + + tls: "oafqa-tls" diff --git a/ph-ee-env-labs/helm/openg2p/Chart.yaml b/ph-ee-env-labs/helm/openg2p/Chart.yaml new file mode 100644 index 000000000..afb7a3316 --- /dev/null +++ b/ph-ee-env-labs/helm/openg2p/Chart.yaml @@ -0,0 +1,12 @@ +apiVersion: v2 +name: ph-ee-barebone +description: PaymentHub EE Barebone Edition + +type: application +version: 0.1.0 +appVersion: 1.16.0 + +dependencies: +- name: ph-ee-engine + repository: https://fynarfin.io/images/ + version: 1.0.0-SNAPSHOT diff --git a/ph-ee-env-labs/helm/openg2p/config/application-bb.properties b/ph-ee-env-labs/helm/openg2p/config/application-bb.properties new file mode 100644 index 000000000..7e4e204fe --- /dev/null +++ b/ph-ee-env-labs/helm/openg2p/config/application-bb.properties @@ -0,0 +1,9 @@ +ams.local.interop.host=https://us-pf.ibank.financial +ams.local.customer.host=https://in-pf.ibank.financial +zeebe.broker.contactpoint=zeebe-zeebe-gateway:26500 + +security.oauth2.resource.jwt.key-uri=http://us-pf.ibank.financial/oauth/token_key +rest.authorization.enabled=false +rest.authorization.host=http://ops-bk.ibank.financial + +dfspids=tn03,tn04 \ No newline at end of file diff --git a/ph-ee-env-labs/helm/openg2p/config/application-fin12.properties b/ph-ee-env-labs/helm/openg2p/config/application-fin12.properties new file mode 100644 index 000000000..660ad0184 --- /dev/null +++ b/ph-ee-env-labs/helm/openg2p/config/application-fin12.properties @@ -0,0 +1,2 @@ +ams.localenabled=true +zeebe.broker.contactpoint=zeebe-zeebe-gateway:26500 \ No newline at end of file diff --git a/ph-ee-env-labs/helm/openg2p/templates/config.yml b/ph-ee-env-labs/helm/openg2p/templates/config.yml new file mode 100644 index 000000000..98f65ae95 --- /dev/null +++ b/ph-ee-env-labs/helm/openg2p/templates/config.yml @@ -0,0 +1,6 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: ph-ee-config +data: +{{ (.Files.Glob "config/**.properties").AsConfig | nindent 2 }} diff --git a/ph-ee-env-labs/helm/openg2p/values.yaml b/ph-ee-env-labs/helm/openg2p/values.yaml new file mode 100644 index 000000000..1a12c67cf --- /dev/null +++ b/ph-ee-env-labs/helm/openg2p/values.yaml @@ -0,0 +1,134 @@ +ph-ee-engine: + zeebe-cluster-helm: + global: + elasticsearch: + host: "ph-ee-elasticsearch" + image: + repository: camunda/zeebe + tag: 1.1.0 + + clusterSize: "1" + partitionCount: "1" + replicationFactor: "1" + + elasticsearch: + enabled: false + kibana: + enabled: false + + extraInitContainers: | + - name: init-ph-ee-kafka-exporter + image: busybox:1.28 + command: ['/bin/sh', '-c'] + args: ['wget -O /exporters/ph-ee-kafka-exporter.jar "https://paymenthub-ee-dev.s3.us-east-2.amazonaws.com/jars/exporter-1.0.0-SNAPSHOT.jar"; ls -al /exporters/'] + volumeMounts: + - name: exporters + mountPath: /exporters/ + + zeebe-operate-helm: + enabled: true + image: + repository: camunda/operate + tag: 1.1.0 + global: + elasticsearch: + host: "ph-ee-elasticsearch" + clusterName: "ph-ee-elasticsearch" + + elasticsearch: + enabled: true + replicas: 1 + imageTag: 7.13.2 + minimumMasterNodes: 1 + + #Single Node Solution + clusterHealthCheckParams: "wait_for_status=yellow&timeout=100s" + master: + readinessProbe: + httpGet: + path: /_cluster/health?wait_for_status=yellow&timeout=5s + port: 9200 + initialDelaySeconds: 30 + data: + readinessProbe: + httpGet: + path: /_cluster/health?wait_for_status=yellow&timeout=5s + port: 9200 + initialDelaySeconds: 30 + + esConfig: + elasticsearch.yml: | + discovery: + type: single-node + seed_hosts: "" + xpack: + security: + enabled: false + + # Shrink default JVM heap. + esJavaOpts: "-Xmx128m -Xms128m" + + # Allocate smaller chunks of memory per pod. + resources: + requests: + cpu: "100m" + memory: "512M" + limits: + cpu: "1000m" + memory: "512M" + volumeClaimTemplate: + accessModes: [ "ReadWriteOnce" ] + storageClassName: "standard" + resources: + requests: + storage: 10Gi + + kibana: + enabled: true + imageTag: 7.13.2 + + kibanaConfig: + kibana.yml: | + monitoring.enabled: false + + operations: + enabled: true + + operationsMysql: + mysqlRootPassword: "ethieTieCh8ahv" + mysqlUser: "mifos" + mysqlPassword: "password" + mysqlDatabase: "tenants" + initializationFiles: + setup.sql: |- + CREATE DATABASE tn03; + CREATE DATABASE tn04; + GRANT ALL PRIVILEGES ON tn03.* TO 'mifos'; + GRANT ALL PRIVILEGES ON tn04.* TO 'mifos'; + + ph_ee_connector_ams_mifos: + SPRING_PROFILES_ACTIVE: "fin12,bb" + + ph_ee_connector_mojaloop: + SPRING_PROFILES_ACTIVE: "bb" + + ph_ee_connector_channel: + SPRING_PROFILES_ACTIVE: "bb" + hostname: "barebone-connector-channel.mifos.io" + AWS_ACCESS_KEY: "xxx" + AWS_SECRET_KEY: "xxx" + + ph_ee_operations_app: + SPRING_PROFILES_ACTIVE: "bb" + hostname: "barebone-operations.mifos.io" + + ph_ee_operations: + SPRING_PROFILES_ACTIVE: "bb" + hostname: "barebone-operations.mifos.io" + webhost: "barebone-operations-ui.mifos.io" + + ph_ee_identity: + hostname: "barebone-identity.mifos.io" + + ph_ee_connector_gsma: + SPRING_PROFILES_ACTIVE: "bb" diff --git a/ph-ee-env-labs/helm/operations/Chart.yaml b/ph-ee-env-labs/helm/operations/Chart.yaml new file mode 100644 index 000000000..4ce68d1f9 --- /dev/null +++ b/ph-ee-env-labs/helm/operations/Chart.yaml @@ -0,0 +1,18 @@ +apiVersion: v2 +name: operations +description: A Helm chart for Kubernetes +type: application +version: 0.1.0 +appVersion: 1.0.0 + +dependencies: +- name: prometheus + repository: https://prometheus-community.github.io/helm-charts + version: 13.5.0 + condition: "prometheus.enabled" + +- name: grafana + repository: https://grafana.github.io/helm-charts + version: 7.0.0 + condition: "grafana.enabled" + diff --git a/ph-ee-env-labs/helm/operations/grafana.sh b/ph-ee-env-labs/helm/operations/grafana.sh new file mode 100755 index 000000000..7bfc1a840 --- /dev/null +++ b/ph-ee-env-labs/helm/operations/grafana.sh @@ -0,0 +1 @@ +helm install --namespace operations grafana grafana/grafana diff --git a/ph-ee-env-labs/helm/operations/prometheus.sh b/ph-ee-env-labs/helm/operations/prometheus.sh new file mode 100755 index 000000000..a2349bfd0 --- /dev/null +++ b/ph-ee-env-labs/helm/operations/prometheus.sh @@ -0,0 +1 @@ +helm install --namespace operations prometheus prometheus-community/prometheus diff --git a/ph-ee-env-labs/helm/operations/values.yaml b/ph-ee-env-labs/helm/operations/values.yaml new file mode 100644 index 000000000..71653f698 --- /dev/null +++ b/ph-ee-env-labs/helm/operations/values.yaml @@ -0,0 +1,68 @@ +prometheus: + enabled: true + server: + global: + scrape_interval: 10s + retention: "7d" + retentionSize: "7GB" + +grafana: + enabled: true + ingress: + enabled: true + annotations: + kubernetes.io/ingress.class: "nginx" + hosts: ["grafana.sandbox.fynarfin.io"] + path: / + tls: + - secretName: sandbox-secret + persistence: + enabled: true # enable persistence using Persistent Volumes + datasources: + datasources.yaml: + apiVersion: 1 + datasources: # configure Grafana to read metrics from Prometheus + - name: Prometheus + type: prometheus + url: http://operate-prometheus-server # Since Prometheus is deployed in + access: proxy # same namespace, this resolves + # to the Prometheus Server we installed previous + isDefault: true # The default data source is Prometheus + + dashboardProviders: + dashboardproviders.yaml: + apiVersion: 1 + providers: + - name: 'default' # Configure a dashboard provider file to + orgId: 1 # put Kong dashboard into. + folder: '' + type: file + disableDeletion: false + editable: true + options: + path: /var/lib/grafana/dashboards/default + dashboards: + default: + kong-dash: + gnetId: 7424 # Install the following Grafana dashboard in the + revision: 11 # instance: https://grafana.com/dashboards/7424 + datasource: Prometheus + kic-dash: + gnetId: 15662 + datasource: Prometheus + kubernetes-cluster-monitoring: + gnetId: 1621 + revision: 1 + datasource: Prometheus + kubernetes-resource-requests: + gnetId: 7187 + revision: 1 + datasource: Prometheus + kubernetes-pods: + gnetId: 6336 + revision: 1 + datasource: Prometheus + kubernetes-cluster: + gnetId: 6417 + revision: 1 + datasource: Prometheus diff --git a/ph-ee-env-labs/helm/payment-hub-barebone/Chart.yaml b/ph-ee-env-labs/helm/payment-hub-barebone/Chart.yaml new file mode 100644 index 000000000..f559e4277 --- /dev/null +++ b/ph-ee-env-labs/helm/payment-hub-barebone/Chart.yaml @@ -0,0 +1,12 @@ +apiVersion: v2 +name: payment-hub-barebone +description: PaymentHub EE Barebone Edition + +type: application +version: 0.1.0 +appVersion: 1.16.0 + +dependencies: +- name: ph-ee-engine + repository: https://fynarfin.io/images/ph-ee-engine-0.0.0-SNAPSHOT/ + version: 0.0.0-SNAPSHOT diff --git a/ph-ee-env-labs/helm/payment-hub-barebone/config/application-bb.properties b/ph-ee-env-labs/helm/payment-hub-barebone/config/application-bb.properties new file mode 100644 index 000000000..316b37f62 --- /dev/null +++ b/ph-ee-env-labs/helm/payment-hub-barebone/config/application-bb.properties @@ -0,0 +1,9 @@ +ams.local.interop.host=https://rhino.mifos.io:8443 +ams.local.customer.host=https://rhino.mifos.io:8443 +zeebe.broker.contactpoint=zeebe-zeebe-gateway:26500 + +security.oauth2.resource.jwt.key-uri=http://bb-identity.mifos.io/oauth/token_key +rest.authorization.enabled=false +rest.authorization.host=http://bb-identity.mifos.io + +dfspids=tn03,tn04 \ No newline at end of file diff --git a/ph-ee-env-labs/helm/payment-hub-barebone/config/application-fin12.properties b/ph-ee-env-labs/helm/payment-hub-barebone/config/application-fin12.properties new file mode 100644 index 000000000..660ad0184 --- /dev/null +++ b/ph-ee-env-labs/helm/payment-hub-barebone/config/application-fin12.properties @@ -0,0 +1,2 @@ +ams.localenabled=true +zeebe.broker.contactpoint=zeebe-zeebe-gateway:26500 \ No newline at end of file diff --git a/ph-ee-env-labs/helm/payment-hub-barebone/templates/config.yml b/ph-ee-env-labs/helm/payment-hub-barebone/templates/config.yml new file mode 100644 index 000000000..98f65ae95 --- /dev/null +++ b/ph-ee-env-labs/helm/payment-hub-barebone/templates/config.yml @@ -0,0 +1,6 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: ph-ee-config +data: +{{ (.Files.Glob "config/**.properties").AsConfig | nindent 2 }} diff --git a/ph-ee-env-labs/helm/payment-hub-barebone/values.yaml b/ph-ee-env-labs/helm/payment-hub-barebone/values.yaml new file mode 100644 index 000000000..3c176e3f1 --- /dev/null +++ b/ph-ee-env-labs/helm/payment-hub-barebone/values.yaml @@ -0,0 +1,122 @@ +ph-ee-engine: + camunda-platform: + global: + elasticsearch: + host: "ph-ee-elasticsearch" +# zeebe: +# javaOpts: "-Xms2g -Xmx2g -XX:+UseParallelGC -XX:MinHeapFreeRatio=5 -XX:MaxHeapFreeRatio=10 -XX:MaxRAMPercentage=25.0 -XX:GCTimeRatio=4 -XX:AdaptiveSizePolicyWeight=90 -XX:+PrintFlagsFinal" + elasticsearch: + enabled: false + + elasticsearch: + enabled: true + replicas: 1 +# imageTag: 7.13.2 + minimumMasterNodes: 1 + + #Single Node Solution + clusterHealthCheckParams: "wait_for_status=yellow&timeout=100s" + + # Shrink default JVM heap. + esJavaOpts: "-Xmx512m -Xms512m" + + # Allocate smaller chunks of memory per pod. + resources: + requests: + cpu: "200m" + memory: "1024M" + limits: + cpu: "1000m" + memory: "1024M" + volumeClaimTemplate: + accessModes: [ "ReadWriteOnce" ] + resources: + requests: + storage: 10Gi + + kibana: + enabled: true + imageTag: 7.13.2 + + kibanaConfig: + kibana.yml: | + monitoring.enabled: false + + operations: + enabled: true + + ph_ee_connector_ams_mifos: + SPRING_PROFILES_ACTIVE: "fin12,bb" + + ph_ee_connector_mojaloop: + SPRING_PROFILES_ACTIVE: "bb" + + channel: + enabled: true + SPRING_PROFILES_ACTIVE: "bb" + imageTag: latest + redis: + idempotency: + enabled: false + ingress: + enabled: false + + operations_app: + SPRING_PROFILES_ACTIVE: "bb" + ingress: + enabled: false + + mpesa: + enabled: false + + ph_ee_connector_gsma: + enabled: false + + operationsmysql: + auth: + database: "tenants" + username: "mifos" + password: "password" + rootPassword: "ethieTieCh8ahv" + initdbScripts: + setup.sql: |- + CREATE DATABASE messagegateway; + CREATE DATABASE `rhino`; + CREATE DATABASE `gorilla`; + CREATE DATABASE `identity_account_mapper`; + CREATE DATABASE `voucher_management`; + GRANT ALL PRIVILEGES ON `rhino`.* TO 'mifos'; + GRANT ALL PRIVILEGES ON `gorilla`.* TO 'mifos'; + GRANT ALL ON *.* TO 'root'@'%'; + GRANT ALL PRIVILEGES ON messagegateway.* TO 'mifos'; + GRANT ALL PRIVILEGES ON `identity_account_mapper`.* TO 'mifos'; + GRANT ALL PRIVILEGES ON `voucher_management`.* TO 'mifos'; + + kafka: + enabled: true + nodePort: 30094 + advertised: + host: "kafka" + port: "8096" + image: "spotify/kafka" + deployment: + annotations: + deployTime: "{{ .Values.deployTime }}" + + notifications: + enabled: false + + operations_web: + enabled: false + + redis: + enabled: false + + importer_es: + enabled: true + imageTag: latest + + mockpayment: + enabled: true + ingress: + enabled: false diff --git a/ph-ee-env-labs/helm/payment-hub-large/.helmignore b/ph-ee-env-labs/helm/payment-hub-large/.helmignore new file mode 100644 index 000000000..0e8a0eb36 --- /dev/null +++ b/ph-ee-env-labs/helm/payment-hub-large/.helmignore @@ -0,0 +1,23 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*.orig +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ diff --git a/ph-ee-env-labs/helm/payment-hub-large/Chart.yaml b/ph-ee-env-labs/helm/payment-hub-large/Chart.yaml new file mode 100644 index 000000000..b01b937fa --- /dev/null +++ b/ph-ee-env-labs/helm/payment-hub-large/Chart.yaml @@ -0,0 +1,26 @@ +apiVersion: v2 +name: ph-ee-large +description: A Helm chart for Kubernetes + +# A chart can be either an 'application' or a 'library' chart. +# +# Application charts are a collection of templates that can be packaged into versioned archives +# to be deployed. +# +# Library charts provide useful utilities or functions for the chart developer. They're included as +# a dependency of application charts to inject those utilities and functions into the rendering +# pipeline. Library charts do not define any templates and therefore cannot be deployed. +type: application + +# This is the chart version. This version number should be incremented each time you make changes +# to the chart and its templates, including the app version. +version: 0.1.1 + +# This is the version number of the application being deployed. This version number should be +# incremented each time you make changes to the application. +appVersion: 1.16.0 + +dependencies: +- name: ph-ee-engine + repository: http://jenkins.mifos.io:8082/ + version: 1.0.0-SNAPSHOT diff --git a/ph-ee-env-labs/helm/payment-hub-large/config/application-fincn.properties b/ph-ee-env-labs/helm/payment-hub-large/config/application-fincn.properties new file mode 100644 index 000000000..e69de29bb diff --git a/ph-ee-env-labs/helm/payment-hub-large/config/application-large.properties b/ph-ee-env-labs/helm/payment-hub-large/config/application-large.properties new file mode 100644 index 000000000..64dc33909 --- /dev/null +++ b/ph-ee-env-labs/helm/payment-hub-large/config/application-large.properties @@ -0,0 +1,17 @@ +mojaloop.enabled=true +ams.local.enabled=true +security.oauth2.resource.jwt.key-uri=http://large-identity.mifos.io/oauth/token_key + +rest.authorization.enabled=true +rest.authorization.host=http://large-identity.mifos.io + +dfspids=tn01,tn02 +zeebe.broker.contactpoint=zeebe-zeebe-gateway:26500 +zeebe.client.max-execution-threads=100 + +fineract.datasource.core.username=mifos +fineract.datasource.core.password=password + +switch.quotes-host=http://perf3-elb-quoting-service.mojaloop.live +switch.als-host=http://perf3-elb-account-lookup.mojaloop.live +switch.transfers-host=http://perf3-elb-ml-api-adapter.mojaloop.live \ No newline at end of file diff --git a/ph-ee-env-labs/helm/payment-hub-large/templates/buffalo-connector-mojaloop-java-ingress.yml b/ph-ee-env-labs/helm/payment-hub-large/templates/buffalo-connector-mojaloop-java-ingress.yml new file mode 100644 index 000000000..a94218938 --- /dev/null +++ b/ph-ee-env-labs/helm/payment-hub-large/templates/buffalo-connector-mojaloop-java-ingress.yml @@ -0,0 +1,14 @@ +apiVersion: extensions/v1beta1 +kind: Ingress +metadata: + name: in01tn01-ph-ee-connector-mojaloop-java + annotations: + kubernetes.io/ingress.class: azure/application-gateway +spec: + rules: + - host: in01tn01.mifos.io + http: + paths: + - backend: + serviceName: ph-ee-connector-mojaloop-java + servicePort: 80 diff --git a/ph-ee-env-labs/helm/payment-hub-large/templates/config.yml b/ph-ee-env-labs/helm/payment-hub-large/templates/config.yml new file mode 100644 index 000000000..98f65ae95 --- /dev/null +++ b/ph-ee-env-labs/helm/payment-hub-large/templates/config.yml @@ -0,0 +1,6 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: ph-ee-config +data: +{{ (.Files.Glob "config/**.properties").AsConfig | nindent 2 }} diff --git a/ph-ee-env-labs/helm/payment-hub-large/templates/lion-connector-mojaloop-java-ingress.yml b/ph-ee-env-labs/helm/payment-hub-large/templates/lion-connector-mojaloop-java-ingress.yml new file mode 100644 index 000000000..b370848a9 --- /dev/null +++ b/ph-ee-env-labs/helm/payment-hub-large/templates/lion-connector-mojaloop-java-ingress.yml @@ -0,0 +1,14 @@ +apiVersion: extensions/v1beta1 +kind: Ingress +metadata: + name: in01tn02-ph-ee-connector-mojaloop-java + annotations: + kubernetes.io/ingress.class: azure/application-gateway +spec: + rules: + - host: in01tn02.mifos.io + http: + paths: + - backend: + serviceName: ph-ee-connector-mojaloop-java + servicePort: 80 diff --git a/ph-ee-env-labs/helm/payment-hub-large/values.yaml b/ph-ee-env-labs/helm/payment-hub-large/values.yaml new file mode 100644 index 000000000..b7fd97fe1 --- /dev/null +++ b/ph-ee-env-labs/helm/payment-hub-large/values.yaml @@ -0,0 +1,77 @@ +ph-ee-engine: + zeebe-cluster: + clusterSize: "3" + partitionCount: "15" + replicationFactor: "2" + + cpuThreadCount: "6" + ioThreadCount: "2" + + #pvcStorageClassName: "fast-disks" + JavaOpts: "-Xms32g -Xmx32g -XX:+UseParallelGC -XX:MinHeapFreeRatio=5 -XX:MaxHeapFreeRatio=10 -XX:MaxRAMPercentage=25.0 -XX:GCTimeRatio=4 -XX:AdaptiveSizePolicyWeight=90 -XX:+PrintFlagsFinal" + #JavaOpts: "-Xms32g -Xmx32g -XX:+UseParallelGC -XX:+PrintFlagsFinal" + + elasticsearch: + enabled: true + kibana: + enabled: true + + resources: + requests: + cpu: 2000m + memory: 4Gi + limits: + cpu: 7820m + memory: 48Gi + + annotations: + prometheus.io/scrape: 'true' + prometheus.io/port: '9600' + prometheus.io/path: '/metrics' + + nodeSelector: + agentpool: defaultv6 + + zeebe-operate: + enabled: true + + elasticsearch: + enabled: true + replicas: 1 + + kibana: + enabled: true + + operationsMysql: + mysqlRootPassword: "ethieTieCh8ahv" + mysqlUser: "mifos" + mysqlPassword: "password" + mysqlDatabase: "tenants" + initializationFiles: + setup.sql: |- + CREATE DATABASE tn01; + CREATE DATABASE tn02; + GRANT ALL PRIVILEGES ON tn01.* TO 'mifos'; + GRANT ALL PRIVILEGES ON tn02.* TO 'mifos'; + + ph_ee_connector_ams_mifos: + SPRING_PROFILES_ACTIVE: "fincn,large" + + ph_ee_connector_mojaloop: + SPRING_PROFILES_ACTIVE: "large" + + ph_ee_connector_channel: + SPRING_PROFILES_ACTIVE: "large" + hostname: "large-connector-channel.mifos.io" + + ph_ee_operations_app: + SPRING_PROFILES_ACTIVE: "large" + hostname: "large-operations.mifos.io" + + ph_ee_operations: + SPRING_PROFILES_ACTIVE: "large" + hostname: "large-operations.mifos.io" + webhost: "large-operations-ui.mifos.io" + + ph_ee_identity: + hostname: "large-identity.mifos.io" diff --git a/ph-ee-env-labs/helm/payment-hub-med/.helmignore b/ph-ee-env-labs/helm/payment-hub-med/.helmignore new file mode 100644 index 000000000..0e8a0eb36 --- /dev/null +++ b/ph-ee-env-labs/helm/payment-hub-med/.helmignore @@ -0,0 +1,23 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*.orig +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ diff --git a/ph-ee-env-labs/helm/payment-hub-med/Chart.yaml b/ph-ee-env-labs/helm/payment-hub-med/Chart.yaml new file mode 100644 index 000000000..141da546e --- /dev/null +++ b/ph-ee-env-labs/helm/payment-hub-med/Chart.yaml @@ -0,0 +1,13 @@ +apiVersion: v2 +name: ph-ee-med +description: PaymentHub EE Medium Edition + +type: application +version: 0.1.0 +appVersion: 1.16.0 + +dependencies: +- name: ph-ee-engine + repository: http://jenkins.mifos.io:8082/ + version: 1.0.0-SNAPSHOT + diff --git a/ph-ee-env-labs/helm/payment-hub-med/config/application-fin12.properties b/ph-ee-env-labs/helm/payment-hub-med/config/application-fin12.properties new file mode 100644 index 000000000..e69de29bb diff --git a/ph-ee-env-labs/helm/payment-hub-med/config/application-med.properties b/ph-ee-env-labs/helm/payment-hub-med/config/application-med.properties new file mode 100644 index 000000000..598cb6a7b --- /dev/null +++ b/ph-ee-env-labs/helm/payment-hub-med/config/application-med.properties @@ -0,0 +1,15 @@ +security.oauth2.resource.jwt.key-uri=http://med-identity.mifos.io/oauth/token_key + +rest.authorization.enabled=true +rest.authorization.host=http://med-identity.mifos.io + +dfspids=tn05,tn06 +zeebe.broker.contactpoint=zeebe-zeebe-gateway:26500 +zeebe.client.max-execution-threads=100 + +fineract.datasource.core.username=mifos +fineract.datasource.core.password=password + +switch.quotes-host=http://perf3-elb-quoting-service.mojaloop.live +switch.als-host=http://perf3-elb-account-lookup.mojaloop.live +switch.transfers-host=http://perf3-elb-ml-api-adapter.mojaloop.live \ No newline at end of file diff --git a/ph-ee-env-labs/helm/payment-hub-med/templates/config.yml b/ph-ee-env-labs/helm/payment-hub-med/templates/config.yml new file mode 100644 index 000000000..98f65ae95 --- /dev/null +++ b/ph-ee-env-labs/helm/payment-hub-med/templates/config.yml @@ -0,0 +1,6 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: ph-ee-config +data: +{{ (.Files.Glob "config/**.properties").AsConfig | nindent 2 }} diff --git a/ph-ee-env-labs/helm/payment-hub-med/templates/gorilla-connector-mojaloop-java-ingress.yml b/ph-ee-env-labs/helm/payment-hub-med/templates/gorilla-connector-mojaloop-java-ingress.yml new file mode 100644 index 000000000..b1c652830 --- /dev/null +++ b/ph-ee-env-labs/helm/payment-hub-med/templates/gorilla-connector-mojaloop-java-ingress.yml @@ -0,0 +1,14 @@ +apiVersion: extensions/v1beta1 +kind: Ingress +metadata: + name: in03tn06-ph-ee-connector-mojaloop-java + annotations: + kubernetes.io/ingress.class: azure/application-gateway +spec: + rules: + - host: in03tn06.mifos.io + http: + paths: + - backend: + serviceName: ph-ee-connector-mojaloop-java + servicePort: 80 diff --git a/ph-ee-env-labs/helm/payment-hub-med/templates/leopard-connector-mojaloop-java-ingress.yml b/ph-ee-env-labs/helm/payment-hub-med/templates/leopard-connector-mojaloop-java-ingress.yml new file mode 100644 index 000000000..bd34aa1c7 --- /dev/null +++ b/ph-ee-env-labs/helm/payment-hub-med/templates/leopard-connector-mojaloop-java-ingress.yml @@ -0,0 +1,14 @@ +apiVersion: extensions/v1beta1 +kind: Ingress +metadata: + name: in03tn05-ph-ee-connector-mojaloop-java + annotations: + kubernetes.io/ingress.class: azure/application-gateway +spec: + rules: + - host: in03tn05.mifos.io + http: + paths: + - backend: + serviceName: ph-ee-connector-mojaloop-java + servicePort: 80 diff --git a/ph-ee-env-labs/helm/payment-hub-med/values.yaml b/ph-ee-env-labs/helm/payment-hub-med/values.yaml new file mode 100644 index 000000000..4795644a4 --- /dev/null +++ b/ph-ee-env-labs/helm/payment-hub-med/values.yaml @@ -0,0 +1,54 @@ +ph-ee-engine: + zeebe-cluster: + clusterSize: "1" + partitionCount: "1" + replicationFactor: "1" + + elasticsearch: + enabled: true + kibana: + enabled: false + + zeebe-operate: + enabled: true + + elasticsearch: + enabled: true + replicas: 1 + + kibana: + enabled: true + + operationsMysql: + mysqlRootPassword: "ethieTieCh8ahv" + mysqlUser: "mifos" + mysqlPassword: "password" + mysqlDatabase: "tenants" + initializationFiles: + setup.sql: |- + CREATE DATABASE tn05; + CREATE DATABASE tn06; + GRANT ALL PRIVILEGES ON tn05.* TO 'mifos'; + GRANT ALL PRIVILEGES ON tn06.* TO 'mifos'; + + ph_ee_connector_ams_mifos: + SPRING_PROFILES_ACTIVE: "fin12,med" + + ph_ee_connector_mojaloop: + SPRING_PROFILES_ACTIVE: "med" + + ph_ee_connector_channel: + SPRING_PROFILES_ACTIVE: "med" + hostname: "med-connector-channel.mifos.io" + + ph_ee_operations_app: + SPRING_PROFILES_ACTIVE: "med" + hostname: "med-operations.mifos.io" + + ph_ee_operations: + SPRING_PROFILES_ACTIVE: "med" + hostname: "med-operations.mifos.io" + webhost: "med-operations-ui.mifos.io" + + ph_ee_identity: + hostname: "med-identity.mifos.io" diff --git a/ph-ee-env-labs/helm/ph-barebone-minikube/Chart.yaml b/ph-ee-env-labs/helm/ph-barebone-minikube/Chart.yaml new file mode 100644 index 000000000..ca2853028 --- /dev/null +++ b/ph-ee-env-labs/helm/ph-barebone-minikube/Chart.yaml @@ -0,0 +1,12 @@ +apiVersion: v2 +name: ph-barebone-minikube +description: PaymentHub EE Barebone minikube Edition + +type: application +version: 0.0.0 +appVersion: 1.16.0 + +dependencies: +- name: ph-ee-engine + repository: https://fynarfin.io/images/ph-ee-engine-0.0.0-SNAPSHOT/ + version: 0.0.0-SNAPSHOT diff --git a/ph-ee-env-labs/helm/ph-barebone-minikube/config/application-bb.properties b/ph-ee-env-labs/helm/ph-barebone-minikube/config/application-bb.properties new file mode 100644 index 000000000..316b37f62 --- /dev/null +++ b/ph-ee-env-labs/helm/ph-barebone-minikube/config/application-bb.properties @@ -0,0 +1,9 @@ +ams.local.interop.host=https://rhino.mifos.io:8443 +ams.local.customer.host=https://rhino.mifos.io:8443 +zeebe.broker.contactpoint=zeebe-zeebe-gateway:26500 + +security.oauth2.resource.jwt.key-uri=http://bb-identity.mifos.io/oauth/token_key +rest.authorization.enabled=false +rest.authorization.host=http://bb-identity.mifos.io + +dfspids=tn03,tn04 \ No newline at end of file diff --git a/ph-ee-env-labs/helm/ph-barebone-minikube/config/application-fin12.properties b/ph-ee-env-labs/helm/ph-barebone-minikube/config/application-fin12.properties new file mode 100644 index 000000000..660ad0184 --- /dev/null +++ b/ph-ee-env-labs/helm/ph-barebone-minikube/config/application-fin12.properties @@ -0,0 +1,2 @@ +ams.localenabled=true +zeebe.broker.contactpoint=zeebe-zeebe-gateway:26500 \ No newline at end of file diff --git a/ph-ee-env-labs/helm/ph-barebone-minikube/templates/config.yml b/ph-ee-env-labs/helm/ph-barebone-minikube/templates/config.yml new file mode 100644 index 000000000..98f65ae95 --- /dev/null +++ b/ph-ee-env-labs/helm/ph-barebone-minikube/templates/config.yml @@ -0,0 +1,6 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: ph-ee-config +data: +{{ (.Files.Glob "config/**.properties").AsConfig | nindent 2 }} diff --git a/ph-ee-env-labs/helm/ph-barebone-minikube/values.yaml b/ph-ee-env-labs/helm/ph-barebone-minikube/values.yaml new file mode 100644 index 000000000..c41e0446d --- /dev/null +++ b/ph-ee-env-labs/helm/ph-barebone-minikube/values.yaml @@ -0,0 +1,133 @@ +ph-ee-engine: + camunda-platform: + global: + elasticsearch: + host: "ph-ee-elasticsearch" +# zeebe: +# javaOpts: "-Xms2g -Xmx2g -XX:+UseParallelGC -XX:MinHeapFreeRatio=5 -XX:MaxHeapFreeRatio=10 -XX:MaxRAMPercentage=25.0 -XX:GCTimeRatio=4 -XX:AdaptiveSizePolicyWeight=90 -XX:+PrintFlagsFinal" + elasticsearch: + enabled: false + + elasticsearch: + enabled: true + replicas: 1 +# imageTag: 7.13.2 + minimumMasterNodes: 1 + + #Single Node Solution + clusterHealthCheckParams: "wait_for_status=yellow&timeout=100s" + + # Shrink default JVM heap. + esJavaOpts: "-Xmx512m -Xms512m" + + # Allocate smaller chunks of memory per pod. + resources: + requests: + cpu: "200m" + memory: "1024M" + limits: + cpu: "1000m" + memory: "1024M" + volumeClaimTemplate: + accessModes: [ "ReadWriteOnce" ] + storageClassName: "standard" + resources: + requests: + storage: 10Gi + + kibana: + enabled: true + imageTag: 7.13.2 + ingress: + enabled: false + + kibanaConfig: + kibana.yml: | + monitoring.enabled: false + + operations: + enabled: true + + + ph_ee_connector_ams_mifos: + SPRING_PROFILES_ACTIVE: "fin12,bb" + ingress: + enabled: false + + ph_ee_connector_mojaloop: + SPRING_PROFILES_ACTIVE: "bb" + ingress: + enabled: false + + channel: + enabled: true + SPRING_PROFILES_ACTIVE: "bb" + ingress: + enabled: false + + operations_app: + SPRING_PROFILES_ACTIVE: "bb" + ingress: + enabled: false + + mpesa: + enabled: false + ingress: + enabled: false + + ph_ee_connector_gsma: + enabled: false + ingress: + enabled: false + + operationsmysql: + auth: + database: "tenants" + username: "mifos" + password: "password" + rootPassword: "ethieTieCh8ahv" + initdbScripts: + setup.sql: |- + CREATE DATABASE messagegateway; + CREATE DATABASE `rhino`; + CREATE DATABASE `gorilla`; + CREATE DATABASE `identity_account_mapper`; + CREATE DATABASE `voucher_management`; + GRANT ALL PRIVILEGES ON `rhino`.* TO 'mifos'; + GRANT ALL PRIVILEGES ON `gorilla`.* TO 'mifos'; + GRANT ALL ON *.* TO 'root'@'%'; + GRANT ALL PRIVILEGES ON messagegateway.* TO 'mifos'; + GRANT ALL PRIVILEGES ON `identity_account_mapper`.* TO 'mifos'; + GRANT ALL PRIVILEGES ON `voucher_management`.* TO 'mifos'; + + kafka: + enabled: true + image: "spotify/kafka" + advertised: + host: "kafka" + port: "9092" + deployment: + annotations: + deployTime: "{{ .Values.deployTime }}" + + notifications: + enabled: false + ingress: + enabled: false + + operations_web: + enabled: false + ingress: + enabled: false + + redis: + enabled: false + + + importer_es: + enabled: true + + mockpayment: + enabled: true + ingress: + enabled: fasle \ No newline at end of file diff --git a/ph-ee-env-labs/helm/ph-ee-fin-back-end/Chart.yaml b/ph-ee-env-labs/helm/ph-ee-fin-back-end/Chart.yaml new file mode 100644 index 000000000..403ecda2b --- /dev/null +++ b/ph-ee-env-labs/helm/ph-ee-fin-back-end/Chart.yaml @@ -0,0 +1,20 @@ +apiVersion: v2 +name: back-end +description: A Helm chart for front-end services +type: application +version: 1.0.0 +appVersion: "ph-ee-superset: v1.16.0; ph-ee-engine:v1.16.0; fin-engine: v1.0.0; operations: 1.0.0;" + +dependencies: +- name: ph-ee-engine + repository: "https://fynarfin.io/images/ph-ee-engine-1.7.2-SNAPSHOT/" + version: 1.7.2-SNAPSHOT + condition: "ph-ee-engine.enabled" +- name: fin-engine + repository: "https://fynarfin.io/images/fineract/" + version: 1.0.0-SNAPSHOT + condition: "fin-engine.enabled" +- name: operations + repository: "https://fynarfin.io/images/operations/" + version: "0.1.0" + condition: "operations.enabled" diff --git a/ph-ee-env-labs/helm/ph-ee-fin-back-end/Makefile b/ph-ee-env-labs/helm/ph-ee-fin-back-end/Makefile new file mode 100644 index 000000000..369343c55 --- /dev/null +++ b/ph-ee-env-labs/helm/ph-ee-fin-back-end/Makefile @@ -0,0 +1,41 @@ +default: test +include examples.mk +RELEASE := helm-es-security +ELASTICSEARCH_IMAGE := docker.elastic.co/elasticsearch/elasticsearch:$(STACK_VERSION) +TIMEOUT := 1200s +install: + helm upgrade --wait --timeout=$(TIMEOUT) --install --values values.yaml $(RELEASE) ../../ +test: secrets install goss +purge: + kubectl delete secrets elastic-certificates elastic-certificate-pem elastic-certificate-crt|| true + helm del $(RELEASE) +pull-elasticsearch-image: + docker pull $(ELASTICSEARCH_IMAGE) + +elasticSecrets: + docker rm -f elastic-helm-charts-certs || true + rm -f elastic-certificates.p12 elastic-certificate.pem elastic-certificate.crt elastic-stack-ca.p12 || true + password=$$([ ! -z "$$ELASTIC_PASSWORD" ] && echo $$ELASTIC_PASSWORD || echo $$(docker run --rm busybox:1.31.1 /bin/sh -c "< /dev/urandom tr -cd '[:alnum:]' | head -c20")) && \ + docker run --name elastic-helm-charts-certs -i -w /app \ + $(ELASTICSEARCH_IMAGE) \ + /bin/sh -c " \ + elasticsearch-certutil ca --out /app/elastic-stack-ca.p12 --pass '' && \ + elasticsearch-certutil cert --name security-master --dns security-master --ca /app/elastic-stack-ca.p12 --pass '' --ca-pass '' --out /app/elastic-certificates.p12" && \ + docker cp elastic-helm-charts-certs:/app/elastic-certificates.p12 ./ && \ + docker rm -f elastic-helm-charts-certs && \ + openssl pkcs12 -nodes -passin pass:'' -in elastic-certificates.p12 -out elastic-certificate.pem && \ + openssl x509 -outform der -in elastic-certificate.pem -out elastic-certificate.crt && \ + kubectl create namespace back-end || echo "namespace already exists" && \ + kubectl create secret generic elastic-certificates --namespace=back-end --from-file=elastic-certificates.p12 && \ + kubectl create secret generic elastic-certificate-pem --namespace=back-end --from-file=elastic-certificate.pem && \ + kubectl create secret generic elastic-certificate-crt --namespace=back-end --from-file=elastic-certificate.crt && \ + kubectl create secret generic elastic-credentials --namespace=back-end --from-literal=password=$$password --from-literal=username=elastic && \ + rm -f elastic-certificates.p12 elastic-certificate.pem elastic-certificate.crt elastic-stack-ca.p12 + +kibanaSecrets: + encryptionkey=$$(docker run --rm busybox:1.31.1 /bin/sh -c "< /dev/urandom tr -dc _A-Za-z0-9 | head -c50") && \ + kubectl create namespace back-end || echo "namespace already exists" && \ + kubectl create secret generic kibana --namespace=back-end --from-literal=encryptionkey=$$encryptionkey + +#realmSecrets: +# kubectl create secret generic realm-secret --namespace=back-end --from-file=./templates/kong-keycloak-realm.json \ No newline at end of file diff --git a/ph-ee-env-labs/helm/ph-ee-fin-back-end/config/application-bb.properties b/ph-ee-env-labs/helm/ph-ee-fin-back-end/config/application-bb.properties new file mode 100644 index 000000000..508b11ecc --- /dev/null +++ b/ph-ee-env-labs/helm/ph-ee-fin-back-end/config/application-bb.properties @@ -0,0 +1,19 @@ +store.local.interop.host=https://us.ibank.financial +store.local.customer.host=https://us.ibank.financial +zeebe.broker.contactpoint=zeebe-zeebe-gateway:26500 + +security.oauth2.resource.jwt.key-uri=http://ops-bk.ibank.financial/oauth/token_key +rest.authorization.enabled=false +rest.authorization.host=http://ops-bk.ibank.financial + +dfspids=ibank-usa, ibank-india + +ams.groups[0].identifier= ACCOUNTID +ams.groups[0].value= roster +ams.groups[1].identifier= FOUNDATIONALID +ams.groups[1].value= paygops +ams.groups[2].identifier= default +ams.groups[2].value= paygops + + + diff --git a/ph-ee-env-labs/helm/ph-ee-fin-back-end/config/application-fin12.properties b/ph-ee-env-labs/helm/ph-ee-fin-back-end/config/application-fin12.properties new file mode 100644 index 000000000..00da52cce --- /dev/null +++ b/ph-ee-env-labs/helm/ph-ee-fin-back-end/config/application-fin12.properties @@ -0,0 +1,13 @@ +ams.localenabled=true +zeebe.broker.contactpoint=zeebe-zeebe-gateway:26500 + +ams.local.tenants[0].name=gorilla +ams.local.tenants[1].name=rhino +ams.local.tenants[0].user=mifos +ams.local.tenants[1].user=mifos +ams.local.tenants[0].password=password +ams.local.tenants[1].password=password +ams.local.tenants[0].authtype=basic +ams.local.tenants[1].authtype=basic +ams.local.tenants[0].fspId=payerfsp +ams.local.tenants[1].fspId=payeefsp diff --git a/ph-ee-env-labs/helm/ph-ee-fin-back-end/config/application-tenants.properties b/ph-ee-env-labs/helm/ph-ee-fin-back-end/config/application-tenants.properties new file mode 100644 index 000000000..dc9bc2ed3 --- /dev/null +++ b/ph-ee-env-labs/helm/ph-ee-fin-back-end/config/application-tenants.properties @@ -0,0 +1,6 @@ +bpmns.tenants[0].id= "lion" +bpmns.tenants[0].flows.payment-transfer= "mock_payment_transfer-{dfspid}" +bpmns.tenants[1].id= "rhino" +bpmns.tenants[1].flows.payment-transfer= "MockPayerFundTransfer-{dfspid}" +bpmns.tenants[2].id= "gorilla" +bpmns.tenants[2].flows.payment-transfer= "PayerFundTransfer-{dfspid}" \ No newline at end of file diff --git a/ph-ee-env-labs/helm/ph-ee-fin-back-end/examples.mk b/ph-ee-env-labs/helm/ph-ee-fin-back-end/examples.mk new file mode 100644 index 000000000..9cb8bffcd --- /dev/null +++ b/ph-ee-env-labs/helm/ph-ee-fin-back-end/examples.mk @@ -0,0 +1,28 @@ +SHELL := /bin/bash +GOSS_VERSION := v0.3.18 +GOSS_FILE ?= goss.yaml +GOSS_SELECTOR ?= release=$(RELEASE) +STACK_VERSION := 7.16.3 +TIMEOUT := 900s + +.PHONY: help +help: ## Display this help + @awk 'BEGIN {FS = ":.*##"; printf "Usage: make \033[36m\033[0m\n\nTargets:\n"} /^[a-zA-Z0-9_-]+:.*?##/ { printf " \033[36m%-10s\033[0m %s\n", $$1, $$2 }' $(MAKEFILE_LIST) + +.PHONY: goss +goss: ## Run goss tests + set -e; \ + for i in $$(seq 1 5); do \ + curl -s -L "https://github.com/aelsabbahy/goss/releases/download/$(GOSS_VERSION)/goss-linux-amd64" -o /tmp/goss; \ + if [ -z "$$GOSS_CONTAINER" ]; then \ + sleep 5; \ + echo "Retrieving pod ($$i/5)"; \ + GOSS_CONTAINER=$$(kubectl get --no-headers=true pods -l "$(GOSS_SELECTOR)" -o custom-columns=:metadata.name --field-selector=status.phase=Running --sort-by=.metadata.creationTimestamp | tail -1 ); \ + else \ + echo "Testing with pod: $$GOSS_CONTAINER" && \ + kubectl cp "test/$(GOSS_FILE)" "$$GOSS_CONTAINER:/tmp/$(GOSS_FILE)" && \ + kubectl cp "/tmp/goss" "$$GOSS_CONTAINER:/tmp/goss" && \ + kubectl exec "$$GOSS_CONTAINER" -- sh -c "chmod +rx /tmp/goss && if [ -f ~/.elasticsearch-serviceaccounttoken ]; then . ~/.elasticsearch-serviceaccounttoken; fi; /tmp/goss --gossfile \"/tmp/$(GOSS_FILE)\" validate --retry-timeout 300s --sleep 5s --color --format documentation"; \ + break; \ + fi; \ + done \ No newline at end of file diff --git a/ph-ee-env-labs/helm/ph-ee-fin-back-end/kong-keycloak-realm.json b/ph-ee-env-labs/helm/ph-ee-fin-back-end/kong-keycloak-realm.json new file mode 100644 index 000000000..315a577d3 --- /dev/null +++ b/ph-ee-env-labs/helm/ph-ee-fin-back-end/kong-keycloak-realm.json @@ -0,0 +1,2172 @@ +{ + "id": "Kong", + "realm": "Kong", + "notBefore": 0, + "defaultSignatureAlgorithm": "RS256", + "revokeRefreshToken": false, + "refreshTokenMaxReuse": 0, + "accessTokenLifespan": 300, + "accessTokenLifespanForImplicitFlow": 900, + "ssoSessionIdleTimeout": 1800, + "ssoSessionMaxLifespan": 36000, + "ssoSessionIdleTimeoutRememberMe": 0, + "ssoSessionMaxLifespanRememberMe": 0, + "offlineSessionIdleTimeout": 2592000, + "offlineSessionMaxLifespanEnabled": false, + "offlineSessionMaxLifespan": 5184000, + "clientSessionIdleTimeout": 0, + "clientSessionMaxLifespan": 0, + "clientOfflineSessionIdleTimeout": 0, + "clientOfflineSessionMaxLifespan": 0, + "accessCodeLifespan": 60, + "accessCodeLifespanUserAction": 300, + "accessCodeLifespanLogin": 1800, + "actionTokenGeneratedByAdminLifespan": 43200, + "actionTokenGeneratedByUserLifespan": 300, + "oauth2DeviceCodeLifespan": 600, + "oauth2DevicePollingInterval": 5, + "enabled": true, + "sslRequired": "external", + "registrationAllowed": false, + "registrationEmailAsUsername": false, + "rememberMe": false, + "verifyEmail": false, + "loginWithEmailAllowed": true, + "duplicateEmailsAllowed": false, + "resetPasswordAllowed": false, + "editUsernameAllowed": false, + "bruteForceProtected": false, + "permanentLockout": false, + "maxFailureWaitSeconds": 900, + "minimumQuickLoginWaitSeconds": 60, + "waitIncrementSeconds": 60, + "quickLoginCheckMilliSeconds": 1000, + "maxDeltaTimeSeconds": 43200, + "failureFactor": 30, + "roles": { + "realm": [ + { + "id": "e56ce8e6-314f-4bf1-98f6-51d9f3bee0bd", + "name": "uma_authorization", + "description": "${role_uma_authorization}", + "composite": false, + "clientRole": false, + "containerId": "Kong", + "attributes": {} + }, + { + "id": "75cecb6c-eeee-4ac5-ae3f-16fb17d670a5", + "name": "offline_access", + "description": "${role_offline-access}", + "composite": false, + "clientRole": false, + "containerId": "Kong", + "attributes": {} + }, + { + "id": "f306be38-5b0a-4f72-b32c-acc9843c3948", + "name": "default-roles-kong", + "description": "${role_default-roles}", + "composite": true, + "composites": { + "realm": [ + "offline_access", + "uma_authorization" + ], + "client": { + "account": [ + "view-profile", + "manage-account" + ] + } + }, + "clientRole": false, + "containerId": "Kong", + "attributes": {} + } + ], + "client": { + "kong-oidc": [], + "realm-management": [ + { + "id": "2cf527ea-dfbd-4061-9ff2-9016f3be572f", + "name": "manage-events", + "description": "${role_manage-events}", + "composite": false, + "clientRole": true, + "containerId": "a696932a-e9fc-4598-b656-bc4995a9532e", + "attributes": {} + }, + { + "id": "49b1f4e4-e2e5-4809-b8a1-3a1309648a79", + "name": "realm-admin", + "description": "${role_realm-admin}", + "composite": true, + "composites": { + "client": { + "realm-management": [ + "manage-events", + "create-client", + "view-realm", + "manage-realm", + "view-authorization", + "manage-clients", + "manage-identity-providers", + "query-clients", + "query-realms", + "view-users", + "view-clients", + "view-identity-providers", + "manage-users", + "query-users", + "manage-authorization", + "view-events", + "impersonation", + "query-groups" + ] + } + }, + "clientRole": true, + "containerId": "a696932a-e9fc-4598-b656-bc4995a9532e", + "attributes": {} + }, + { + "id": "784f03f8-c24f-4d53-854f-de53e7224eaf", + "name": "create-client", + "description": "${role_create-client}", + "composite": false, + "clientRole": true, + "containerId": "a696932a-e9fc-4598-b656-bc4995a9532e", + "attributes": {} + }, + { + "id": "859464b4-174e-4370-8c20-51c42552f89a", + "name": "view-realm", + "description": "${role_view-realm}", + "composite": false, + "clientRole": true, + "containerId": "a696932a-e9fc-4598-b656-bc4995a9532e", + "attributes": {} + }, + { + "id": "994cdfea-9f7d-4fb9-84d8-9a64d6fd7458", + "name": "manage-realm", + "description": "${role_manage-realm}", + "composite": false, + "clientRole": true, + "containerId": "a696932a-e9fc-4598-b656-bc4995a9532e", + "attributes": {} + }, + { + "id": "b7b27085-bd72-4f3e-b0e3-23a590927127", + "name": "view-authorization", + "description": "${role_view-authorization}", + "composite": false, + "clientRole": true, + "containerId": "a696932a-e9fc-4598-b656-bc4995a9532e", + "attributes": {} + }, + { + "id": "e79a28ab-05ca-44d9-978e-dc98d4b14dbb", + "name": "manage-clients", + "description": "${role_manage-clients}", + "composite": false, + "clientRole": true, + "containerId": "a696932a-e9fc-4598-b656-bc4995a9532e", + "attributes": {} + }, + { + "id": "7358345e-cc0a-40e5-818c-1777e7aaff3b", + "name": "manage-identity-providers", + "description": "${role_manage-identity-providers}", + "composite": false, + "clientRole": true, + "containerId": "a696932a-e9fc-4598-b656-bc4995a9532e", + "attributes": {} + }, + { + "id": "08ba0de2-a85c-406a-8707-8b27a7104a5a", + "name": "query-clients", + "description": "${role_query-clients}", + "composite": false, + "clientRole": true, + "containerId": "a696932a-e9fc-4598-b656-bc4995a9532e", + "attributes": {} + }, + { + "id": "2aca0e4c-a736-4341-af8c-78c836dd01fa", + "name": "query-realms", + "description": "${role_query-realms}", + "composite": false, + "clientRole": true, + "containerId": "a696932a-e9fc-4598-b656-bc4995a9532e", + "attributes": {} + }, + { + "id": "7dc50f4e-7854-460f-9f43-e67971f38704", + "name": "view-clients", + "description": "${role_view-clients}", + "composite": true, + "composites": { + "client": { + "realm-management": [ + "query-clients" + ] + } + }, + "clientRole": true, + "containerId": "a696932a-e9fc-4598-b656-bc4995a9532e", + "attributes": {} + }, + { + "id": "5332e3a6-9283-4256-8ced-edf552d42a23", + "name": "view-users", + "description": "${role_view-users}", + "composite": true, + "composites": { + "client": { + "realm-management": [ + "query-users", + "query-groups" + ] + } + }, + "clientRole": true, + "containerId": "a696932a-e9fc-4598-b656-bc4995a9532e", + "attributes": {} + }, + { + "id": "8cd0251b-6d63-42b5-aa8f-813d6d696dc7", + "name": "manage-users", + "description": "${role_manage-users}", + "composite": false, + "clientRole": true, + "containerId": "a696932a-e9fc-4598-b656-bc4995a9532e", + "attributes": {} + }, + { + "id": "1a80c1f2-8d4e-429e-9983-362d0d1aadfa", + "name": "query-users", + "description": "${role_query-users}", + "composite": false, + "clientRole": true, + "containerId": "a696932a-e9fc-4598-b656-bc4995a9532e", + "attributes": {} + }, + { + "id": "017fba9a-31d5-4c65-8934-931ba58c9d3a", + "name": "view-identity-providers", + "description": "${role_view-identity-providers}", + "composite": false, + "clientRole": true, + "containerId": "a696932a-e9fc-4598-b656-bc4995a9532e", + "attributes": {} + }, + { + "id": "be66f0c8-d654-4f4c-a445-b460fefc548e", + "name": "manage-authorization", + "description": "${role_manage-authorization}", + "composite": false, + "clientRole": true, + "containerId": "a696932a-e9fc-4598-b656-bc4995a9532e", + "attributes": {} + }, + { + "id": "000dad61-9f98-499f-8dd0-f0f7142c29e8", + "name": "view-events", + "description": "${role_view-events}", + "composite": false, + "clientRole": true, + "containerId": "a696932a-e9fc-4598-b656-bc4995a9532e", + "attributes": {} + }, + { + "id": "f99314e6-7877-40e4-b471-705714638dde", + "name": "impersonation", + "description": "${role_impersonation}", + "composite": false, + "clientRole": true, + "containerId": "a696932a-e9fc-4598-b656-bc4995a9532e", + "attributes": {} + }, + { + "id": "4556dea7-a103-41fe-9d78-fff6b1bcb057", + "name": "query-groups", + "description": "${role_query-groups}", + "composite": false, + "clientRole": true, + "containerId": "a696932a-e9fc-4598-b656-bc4995a9532e", + "attributes": {} + } + ], + "security-admin-console": [], + "admin-cli": [], + "account-console": [], + "broker": [ + { + "id": "fb6b3047-933d-4278-b657-191300d65c62", + "name": "read-token", + "description": "${role_read-token}", + "composite": false, + "clientRole": true, + "containerId": "01f4013e-c990-4983-ae7f-7a0d025c0e14", + "attributes": {} + } + ], + "account": [ + { + "id": "05e1d956-aec5-4a59-b4ba-5a765207c405", + "name": "view-applications", + "description": "${role_view-applications}", + "composite": false, + "clientRole": true, + "containerId": "361e8d18-d33a-46ce-b492-a5d19251101a", + "attributes": {} + }, + { + "id": "765b0dea-3f94-42eb-b9d5-f2dc9cf69c1b", + "name": "manage-account-links", + "description": "${role_manage-account-links}", + "composite": false, + "clientRole": true, + "containerId": "361e8d18-d33a-46ce-b492-a5d19251101a", + "attributes": {} + }, + { + "id": "2139eb6e-ef7f-41fb-93d6-752c2dc89a73", + "name": "view-profile", + "description": "${role_view-profile}", + "composite": false, + "clientRole": true, + "containerId": "361e8d18-d33a-46ce-b492-a5d19251101a", + "attributes": {} + }, + { + "id": "16551f6b-109d-4714-903d-f21477d4cbd4", + "name": "manage-account", + "description": "${role_manage-account}", + "composite": true, + "composites": { + "client": { + "account": [ + "manage-account-links" + ] + } + }, + "clientRole": true, + "containerId": "361e8d18-d33a-46ce-b492-a5d19251101a", + "attributes": {} + }, + { + "id": "9f367d45-e730-4462-aac6-8b9fc5cef660", + "name": "view-consent", + "description": "${role_view-consent}", + "composite": false, + "clientRole": true, + "containerId": "361e8d18-d33a-46ce-b492-a5d19251101a", + "attributes": {} + }, + { + "id": "1f06a316-225c-443b-917f-700165ad462a", + "name": "delete-account", + "description": "${role_delete-account}", + "composite": false, + "clientRole": true, + "containerId": "361e8d18-d33a-46ce-b492-a5d19251101a", + "attributes": {} + }, + { + "id": "af167558-8414-4e5c-9e11-61f459e3c914", + "name": "manage-consent", + "description": "${role_manage-consent}", + "composite": true, + "composites": { + "client": { + "account": [ + "view-consent" + ] + } + }, + "clientRole": true, + "containerId": "361e8d18-d33a-46ce-b492-a5d19251101a", + "attributes": {} + } + ] + } + }, + "groups": [ + { + "id": "c5dd34ff-bf1f-43ea-9976-7fb1371f9432", + "name": "test", + "path": "/test", + "attributes": {}, + "realmRoles": [], + "clientRoles": {}, + "subGroups": [] + } + ], + "defaultRole": { + "id": "f306be38-5b0a-4f72-b32c-acc9843c3948", + "name": "default-roles-kong", + "description": "${role_default-roles}", + "composite": true, + "clientRole": false, + "containerId": "Kong" + }, + "requiredCredentials": [ + "password" + ], + "otpPolicyType": "totp", + "otpPolicyAlgorithm": "HmacSHA1", + "otpPolicyInitialCounter": 0, + "otpPolicyDigits": 6, + "otpPolicyLookAheadWindow": 1, + "otpPolicyPeriod": 30, + "otpSupportedApplications": [ + "FreeOTP", + "Google Authenticator" + ], + "webAuthnPolicyRpEntityName": "keycloak", + "webAuthnPolicySignatureAlgorithms": [ + "ES256" + ], + "webAuthnPolicyRpId": "", + "webAuthnPolicyAttestationConveyancePreference": "not specified", + "webAuthnPolicyAuthenticatorAttachment": "not specified", + "webAuthnPolicyRequireResidentKey": "not specified", + "webAuthnPolicyUserVerificationRequirement": "not specified", + "webAuthnPolicyCreateTimeout": 0, + "webAuthnPolicyAvoidSameAuthenticatorRegister": false, + "webAuthnPolicyAcceptableAaguids": [], + "webAuthnPolicyPasswordlessRpEntityName": "keycloak", + "webAuthnPolicyPasswordlessSignatureAlgorithms": [ + "ES256" + ], + "webAuthnPolicyPasswordlessRpId": "", + "webAuthnPolicyPasswordlessAttestationConveyancePreference": "not specified", + "webAuthnPolicyPasswordlessAuthenticatorAttachment": "not specified", + "webAuthnPolicyPasswordlessRequireResidentKey": "not specified", + "webAuthnPolicyPasswordlessUserVerificationRequirement": "not specified", + "webAuthnPolicyPasswordlessCreateTimeout": 0, + "webAuthnPolicyPasswordlessAvoidSameAuthenticatorRegister": false, + "webAuthnPolicyPasswordlessAcceptableAaguids": [], + "scopeMappings": [ + { + "clientScope": "offline_access", + "roles": [ + "offline_access" + ] + } + ], + "clientScopeMappings": { + "account": [ + { + "client": "account-console", + "roles": [ + "manage-account" + ] + } + ] + }, + "clients": [ + { + "id": "361e8d18-d33a-46ce-b492-a5d19251101a", + "clientId": "account", + "name": "${client_account}", + "rootUrl": "${authBaseUrl}", + "baseUrl": "/realms/Kong/account/", + "surrogateAuthRequired": false, + "enabled": true, + "alwaysDisplayInConsole": false, + "clientAuthenticatorType": "client-secret", + "redirectUris": [ + "/realms/Kong/account/*" + ], + "webOrigins": [], + "notBefore": 0, + "bearerOnly": false, + "consentRequired": false, + "standardFlowEnabled": true, + "implicitFlowEnabled": false, + "directAccessGrantsEnabled": false, + "serviceAccountsEnabled": false, + "publicClient": true, + "frontchannelLogout": false, + "protocol": "openid-connect", + "attributes": {}, + "authenticationFlowBindingOverrides": {}, + "fullScopeAllowed": false, + "nodeReRegistrationTimeout": 0, + "defaultClientScopes": [ + "web-origins", + "profile", + "roles", + "email" + ], + "optionalClientScopes": [ + "address", + "phone", + "offline_access", + "microprofile-jwt" + ] + }, + { + "id": "67a7488e-a386-445f-acd1-655e81a641cf", + "clientId": "account-console", + "name": "${client_account-console}", + "rootUrl": "${authBaseUrl}", + "baseUrl": "/realms/Kong/account/", + "surrogateAuthRequired": false, + "enabled": true, + "alwaysDisplayInConsole": false, + "clientAuthenticatorType": "client-secret", + "redirectUris": [ + "/realms/Kong/account/*" + ], + "webOrigins": [], + "notBefore": 0, + "bearerOnly": false, + "consentRequired": false, + "standardFlowEnabled": true, + "implicitFlowEnabled": false, + "directAccessGrantsEnabled": false, + "serviceAccountsEnabled": false, + "publicClient": true, + "frontchannelLogout": false, + "protocol": "openid-connect", + "attributes": { + "pkce.code.challenge.method": "S256" + }, + "authenticationFlowBindingOverrides": {}, + "fullScopeAllowed": false, + "nodeReRegistrationTimeout": 0, + "protocolMappers": [ + { + "id": "6cbfddd1-b385-48ba-86e7-3c6160e5635f", + "name": "audience resolve", + "protocol": "openid-connect", + "protocolMapper": "oidc-audience-resolve-mapper", + "consentRequired": false, + "config": {} + } + ], + "defaultClientScopes": [ + "web-origins", + "profile", + "roles", + "email" + ], + "optionalClientScopes": [ + "address", + "phone", + "offline_access", + "microprofile-jwt" + ] + }, + { + "id": "1fc9f83b-83c2-4769-89af-4ff8a0f09989", + "clientId": "admin-cli", + "name": "${client_admin-cli}", + "surrogateAuthRequired": false, + "enabled": true, + "alwaysDisplayInConsole": false, + "clientAuthenticatorType": "client-secret", + "redirectUris": [], + "webOrigins": [], + "notBefore": 0, + "bearerOnly": false, + "consentRequired": false, + "standardFlowEnabled": false, + "implicitFlowEnabled": false, + "directAccessGrantsEnabled": true, + "serviceAccountsEnabled": false, + "publicClient": true, + "frontchannelLogout": false, + "protocol": "openid-connect", + "attributes": {}, + "authenticationFlowBindingOverrides": {}, + "fullScopeAllowed": false, + "nodeReRegistrationTimeout": 0, + "defaultClientScopes": [ + "web-origins", + "profile", + "roles", + "email" + ], + "optionalClientScopes": [ + "address", + "phone", + "offline_access", + "microprofile-jwt" + ] + }, + { + "id": "01f4013e-c990-4983-ae7f-7a0d025c0e14", + "clientId": "broker", + "name": "${client_broker}", + "surrogateAuthRequired": false, + "enabled": true, + "alwaysDisplayInConsole": false, + "clientAuthenticatorType": "client-secret", + "redirectUris": [], + "webOrigins": [], + "notBefore": 0, + "bearerOnly": true, + "consentRequired": false, + "standardFlowEnabled": true, + "implicitFlowEnabled": false, + "directAccessGrantsEnabled": false, + "serviceAccountsEnabled": false, + "publicClient": false, + "frontchannelLogout": false, + "protocol": "openid-connect", + "attributes": {}, + "authenticationFlowBindingOverrides": {}, + "fullScopeAllowed": false, + "nodeReRegistrationTimeout": 0, + "defaultClientScopes": [ + "web-origins", + "profile", + "roles", + "email" + ], + "optionalClientScopes": [ + "address", + "phone", + "offline_access", + "microprofile-jwt" + ] + }, + { + "id": "578e995e-7de0-4f09-9fa8-c4caab51843f", + "clientId": "kong-oidc", + "surrogateAuthRequired": false, + "enabled": true, + "alwaysDisplayInConsole": false, + "clientAuthenticatorType": "client-secret", + "secret": "**********", + "redirectUris": [ + "*" + ], + "webOrigins": [ + "localhost (Allowed CORS origin)", + "cribbi.io (Allowed CORS origin)" + ], + "notBefore": 0, + "bearerOnly": false, + "consentRequired": false, + "standardFlowEnabled": true, + "implicitFlowEnabled": false, + "directAccessGrantsEnabled": true, + "serviceAccountsEnabled": false, + "publicClient": false, + "frontchannelLogout": false, + "protocol": "openid-connect", + "attributes": { + "saml.force.post.binding": "false", + "saml.multivalued.roles": "false", + "oauth2.device.authorization.grant.enabled": "false", + "backchannel.logout.revoke.offline.tokens": "false", + "saml.server.signature.keyinfo.ext": "false", + "use.refresh.tokens": "true", + "oidc.ciba.grant.enabled": "false", + "backchannel.logout.session.required": "true", + "client_credentials.use_refresh_token": "false", + "require.pushed.authorization.requests": "false", + "saml.client.signature": "false", + "id.token.as.detached.signature": "false", + "saml.assertion.signature": "false", + "saml.encrypt": "false", + "saml.server.signature": "false", + "exclude.session.state.from.auth.response": "false", + "saml.artifact.binding": "false", + "saml_force_name_id_format": "false", + "acr.loa.map": "{}", + "tls.client.certificate.bound.access.tokens": "false", + "saml.authnstatement": "false", + "display.on.consent.screen": "false", + "token.response.type.bearer.lower-case": "false", + "saml.onetimeuse.condition": "false" + }, + "authenticationFlowBindingOverrides": {}, + "fullScopeAllowed": true, + "nodeReRegistrationTimeout": -1, + "defaultClientScopes": [ + "web-origins", + "profile", + "roles", + "email" + ], + "optionalClientScopes": [ + "address", + "phone", + "offline_access", + "microprofile-jwt" + ] + }, + { + "id": "a696932a-e9fc-4598-b656-bc4995a9532e", + "clientId": "realm-management", + "name": "${client_realm-management}", + "surrogateAuthRequired": false, + "enabled": true, + "alwaysDisplayInConsole": false, + "clientAuthenticatorType": "client-secret", + "redirectUris": [], + "webOrigins": [], + "notBefore": 0, + "bearerOnly": true, + "consentRequired": false, + "standardFlowEnabled": true, + "implicitFlowEnabled": false, + "directAccessGrantsEnabled": false, + "serviceAccountsEnabled": false, + "publicClient": false, + "frontchannelLogout": false, + "protocol": "openid-connect", + "attributes": {}, + "authenticationFlowBindingOverrides": {}, + "fullScopeAllowed": false, + "nodeReRegistrationTimeout": 0, + "defaultClientScopes": [ + "web-origins", + "profile", + "roles", + "email" + ], + "optionalClientScopes": [ + "address", + "phone", + "offline_access", + "microprofile-jwt" + ] + }, + { + "id": "50a77f13-4089-4fd1-8648-e13e15259fe0", + "clientId": "security-admin-console", + "name": "${client_security-admin-console}", + "rootUrl": "${authAdminUrl}", + "baseUrl": "/admin/Kong/console/", + "surrogateAuthRequired": false, + "enabled": true, + "alwaysDisplayInConsole": false, + "clientAuthenticatorType": "client-secret", + "redirectUris": [ + "/admin/Kong/console/*" + ], + "webOrigins": [ + "+" + ], + "notBefore": 0, + "bearerOnly": false, + "consentRequired": false, + "standardFlowEnabled": true, + "implicitFlowEnabled": false, + "directAccessGrantsEnabled": false, + "serviceAccountsEnabled": false, + "publicClient": true, + "frontchannelLogout": false, + "protocol": "openid-connect", + "attributes": { + "pkce.code.challenge.method": "S256" + }, + "authenticationFlowBindingOverrides": {}, + "fullScopeAllowed": false, + "nodeReRegistrationTimeout": 0, + "protocolMappers": [ + { + "id": "16d66308-424e-4452-85a2-52cff0320374", + "name": "locale", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "locale", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "locale", + "jsonType.label": "String" + } + } + ], + "defaultClientScopes": [ + "web-origins", + "profile", + "roles", + "email" + ], + "optionalClientScopes": [ + "address", + "phone", + "offline_access", + "microprofile-jwt" + ] + } + ], + "clientScopes": [ + { + "id": "67332a08-3545-43d0-bc9b-96ec04ab7b1d", + "name": "microprofile-jwt", + "description": "Microprofile - JWT built-in scope", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "true", + "display.on.consent.screen": "false" + }, + "protocolMappers": [ + { + "id": "29e8353e-1062-461c-bcbc-24533b66c4f1", + "name": "upn", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-property-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "username", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "upn", + "jsonType.label": "String" + } + }, + { + "id": "3dc57511-4b31-4711-baf2-e7e4a50e2ef6", + "name": "groups", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-realm-role-mapper", + "consentRequired": false, + "config": { + "multivalued": "true", + "user.attribute": "foo", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "groups", + "jsonType.label": "String" + } + } + ] + }, + { + "id": "e5b5ed97-ee0c-4c02-ad2d-c0101b0e0afa", + "name": "profile", + "description": "OpenID Connect built-in scope: profile", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "true", + "display.on.consent.screen": "true", + "consent.screen.text": "${profileScopeConsentText}" + }, + "protocolMappers": [ + { + "id": "f7273dce-bbc2-4c81-a254-85ff4f085aee", + "name": "given name", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-property-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "firstName", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "given_name", + "jsonType.label": "String" + } + }, + { + "id": "071021ea-04dd-4488-818a-fb0f05974405", + "name": "locale", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "locale", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "locale", + "jsonType.label": "String" + } + }, + { + "id": "e7957678-5936-4be8-af5c-f6c0d3fac1c6", + "name": "zoneinfo", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "zoneinfo", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "zoneinfo", + "jsonType.label": "String" + } + }, + { + "id": "904f3690-0e12-4963-8e8d-19cfe8ee2584", + "name": "website", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "website", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "website", + "jsonType.label": "String" + } + }, + { + "id": "924e8b62-a034-4965-9774-31e2194deac1", + "name": "updated at", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "updatedAt", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "updated_at", + "jsonType.label": "String" + } + }, + { + "id": "f824795d-93ed-41aa-9df4-a69aa5ce8e9b", + "name": "username", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-property-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "username", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "preferred_username", + "jsonType.label": "String" + } + }, + { + "id": "c7f4abf7-80ff-4af1-bb8d-fed39588b902", + "name": "middle name", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "middleName", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "middle_name", + "jsonType.label": "String" + } + }, + { + "id": "ea2ecaf4-5bc2-4b1d-9787-44f7336a485d", + "name": "full name", + "protocol": "openid-connect", + "protocolMapper": "oidc-full-name-mapper", + "consentRequired": false, + "config": { + "id.token.claim": "true", + "access.token.claim": "true", + "userinfo.token.claim": "true" + } + }, + { + "id": "b5c860eb-a96f-42de-bc30-d57de18e8167", + "name": "family name", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-property-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "lastName", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "family_name", + "jsonType.label": "String" + } + }, + { + "id": "b31777f1-d8d4-47b6-9cfc-c0a6c6bf9f3c", + "name": "nickname", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "nickname", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "nickname", + "jsonType.label": "String" + } + }, + { + "id": "35a54a53-7ea0-4082-8979-1ad167d6bcee", + "name": "gender", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "gender", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "gender", + "jsonType.label": "String" + } + }, + { + "id": "f98c231e-3d9d-400e-9ff8-3ed607d5c89c", + "name": "profile", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "profile", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "profile", + "jsonType.label": "String" + } + }, + { + "id": "6159c05d-fec9-407e-b433-596460417380", + "name": "picture", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "picture", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "picture", + "jsonType.label": "String" + } + }, + { + "id": "352521b1-7188-4cdd-bcc9-a5e5294f2a00", + "name": "birthdate", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "birthdate", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "birthdate", + "jsonType.label": "String" + } + } + ] + }, + { + "id": "3e886f78-4185-4d08-9d4c-cf4322a3f483", + "name": "email", + "description": "OpenID Connect built-in scope: email", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "true", + "display.on.consent.screen": "true", + "consent.screen.text": "${emailScopeConsentText}" + }, + "protocolMappers": [ + { + "id": "0f38213b-565b-49f3-a1f9-7f3f5c40a93b", + "name": "email", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-property-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "email", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "email", + "jsonType.label": "String" + } + }, + { + "id": "58c8e210-5154-49d3-8515-14826db18ccd", + "name": "email verified", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-property-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "emailVerified", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "email_verified", + "jsonType.label": "boolean" + } + } + ] + }, + { + "id": "3f5aafd7-c703-4aa7-881e-d0a2cd1ff022", + "name": "phone", + "description": "OpenID Connect built-in scope: phone", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "true", + "display.on.consent.screen": "true", + "consent.screen.text": "${phoneScopeConsentText}" + }, + "protocolMappers": [ + { + "id": "42c0ddb2-d2c6-4766-8ac6-b7573e5aa4e0", + "name": "phone number", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "phoneNumber", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "phone_number", + "jsonType.label": "String" + } + }, + { + "id": "6e0ec5d2-6149-4ba8-882f-d2f808750ac0", + "name": "phone number verified", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "phoneNumberVerified", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "phone_number_verified", + "jsonType.label": "boolean" + } + } + ] + }, + { + "id": "1c14fd95-79a4-4142-956a-68369ad383ba", + "name": "roles", + "description": "OpenID Connect scope for add user roles to the access token", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "false", + "display.on.consent.screen": "true", + "consent.screen.text": "${rolesScopeConsentText}" + }, + "protocolMappers": [ + { + "id": "1c0dcbe2-8934-4ff7-bfda-75d7f4499f61", + "name": "client roles", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-client-role-mapper", + "consentRequired": false, + "config": { + "user.attribute": "foo", + "access.token.claim": "true", + "claim.name": "resource_access.${client_id}.roles", + "jsonType.label": "String", + "multivalued": "true" + } + }, + { + "id": "a0228fb1-992d-4981-80a1-282413ffa750", + "name": "realm roles", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-realm-role-mapper", + "consentRequired": false, + "config": { + "user.attribute": "foo", + "access.token.claim": "true", + "claim.name": "realm_access.roles", + "jsonType.label": "String", + "multivalued": "true" + } + }, + { + "id": "aa809dfb-4e86-4b07-a108-982ff5ce05f2", + "name": "audience resolve", + "protocol": "openid-connect", + "protocolMapper": "oidc-audience-resolve-mapper", + "consentRequired": false, + "config": {} + } + ] + }, + { + "id": "984e29a9-934b-48e8-8765-c05b030192db", + "name": "offline_access", + "description": "OpenID Connect built-in scope: offline_access", + "protocol": "openid-connect", + "attributes": { + "consent.screen.text": "${offlineAccessScopeConsentText}", + "display.on.consent.screen": "true" + } + }, + { + "id": "fa54415e-c8de-414e-bfba-2efad0cc096f", + "name": "role_list", + "description": "SAML role list", + "protocol": "saml", + "attributes": { + "consent.screen.text": "${samlRoleListScopeConsentText}", + "display.on.consent.screen": "true" + }, + "protocolMappers": [ + { + "id": "6c111b35-14f0-4080-a729-3dcf54c3f486", + "name": "role list", + "protocol": "saml", + "protocolMapper": "saml-role-list-mapper", + "consentRequired": false, + "config": { + "single": "false", + "attribute.nameformat": "Basic", + "attribute.name": "Role" + } + } + ] + }, + { + "id": "b5ba65c3-f227-4226-a61f-f7903b9dda79", + "name": "web-origins", + "description": "OpenID Connect scope for add allowed web origins to the access token", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "false", + "display.on.consent.screen": "false", + "consent.screen.text": "" + }, + "protocolMappers": [ + { + "id": "aaf653b5-63d0-4653-ba4b-0d6a5adbb503", + "name": "allowed web origins", + "protocol": "openid-connect", + "protocolMapper": "oidc-allowed-origins-mapper", + "consentRequired": false, + "config": {} + } + ] + }, + { + "id": "b6ddeac5-64c3-409b-8455-6199f81afaa7", + "name": "address", + "description": "OpenID Connect built-in scope: address", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "true", + "display.on.consent.screen": "true", + "consent.screen.text": "${addressScopeConsentText}" + }, + "protocolMappers": [ + { + "id": "2026f3a1-de52-4d85-bf9e-2c42b4125d5d", + "name": "address", + "protocol": "openid-connect", + "protocolMapper": "oidc-address-mapper", + "consentRequired": false, + "config": { + "user.attribute.formatted": "formatted", + "user.attribute.country": "country", + "user.attribute.postal_code": "postal_code", + "userinfo.token.claim": "true", + "user.attribute.street": "street", + "id.token.claim": "true", + "user.attribute.region": "region", + "access.token.claim": "true", + "user.attribute.locality": "locality" + } + } + ] + } + ], + "defaultDefaultClientScopes": [ + "role_list", + "profile", + "email", + "roles", + "web-origins" + ], + "defaultOptionalClientScopes": [ + "offline_access", + "address", + "phone", + "microprofile-jwt" + ], + "browserSecurityHeaders": { + "contentSecurityPolicyReportOnly": "", + "xContentTypeOptions": "nosniff", + "xRobotsTag": "none", + "xFrameOptions": "SAMEORIGIN", + "contentSecurityPolicy": "frame-src 'self'; frame-ancestors 'self'; object-src 'none';", + "xXSSProtection": "1; mode=block", + "strictTransportSecurity": "max-age=31536000; includeSubDomains" + }, + "smtpServer": {}, + "eventsEnabled": false, + "eventsListeners": [ + "jboss-logging" + ], + "enabledEventTypes": [], + "adminEventsEnabled": false, + "adminEventsDetailsEnabled": false, + "identityProviders": [], + "identityProviderMappers": [], + "components": { + "org.keycloak.services.clientregistration.policy.ClientRegistrationPolicy": [ + { + "id": "047ce841-138f-4a63-adc2-41c3314222ba", + "name": "Trusted Hosts", + "providerId": "trusted-hosts", + "subType": "anonymous", + "subComponents": {}, + "config": { + "host-sending-registration-request-must-match": [ + "true" + ], + "client-uris-must-match": [ + "true" + ] + } + }, + { + "id": "1634ff3d-d6e8-4f42-a8a7-38a0ccb6e4f2", + "name": "Consent Required", + "providerId": "consent-required", + "subType": "anonymous", + "subComponents": {}, + "config": {} + }, + { + "id": "6ddd1fd4-598a-4cc3-9890-ed4f0586362c", + "name": "Allowed Client Scopes", + "providerId": "allowed-client-templates", + "subType": "anonymous", + "subComponents": {}, + "config": { + "allow-default-scopes": [ + "true" + ] + } + }, + { + "id": "35e64bb1-cfbe-4343-be5c-fbc2218b8b2a", + "name": "Max Clients Limit", + "providerId": "max-clients", + "subType": "anonymous", + "subComponents": {}, + "config": { + "max-clients": [ + "200" + ] + } + }, + { + "id": "656ba51c-48ee-427d-8896-e1af0e0f4d5b", + "name": "Allowed Client Scopes", + "providerId": "allowed-client-templates", + "subType": "authenticated", + "subComponents": {}, + "config": { + "allow-default-scopes": [ + "true" + ] + } + }, + { + "id": "b9d0fbbf-3f54-4f14-8748-4c00dd43bf7c", + "name": "Allowed Protocol Mapper Types", + "providerId": "allowed-protocol-mappers", + "subType": "authenticated", + "subComponents": {}, + "config": { + "allowed-protocol-mapper-types": [ + "saml-role-list-mapper", + "oidc-sha256-pairwise-sub-mapper", + "oidc-address-mapper", + "oidc-usermodel-property-mapper", + "oidc-full-name-mapper", + "saml-user-attribute-mapper", + "saml-user-property-mapper", + "oidc-usermodel-attribute-mapper" + ] + } + }, + { + "id": "4f0f7c7e-fb7f-4c05-8e91-4715e9e0d163", + "name": "Allowed Protocol Mapper Types", + "providerId": "allowed-protocol-mappers", + "subType": "anonymous", + "subComponents": {}, + "config": { + "allowed-protocol-mapper-types": [ + "oidc-address-mapper", + "oidc-full-name-mapper", + "saml-user-property-mapper", + "oidc-usermodel-attribute-mapper", + "oidc-sha256-pairwise-sub-mapper", + "saml-role-list-mapper", + "saml-user-attribute-mapper", + "oidc-usermodel-property-mapper" + ] + } + }, + { + "id": "73f90916-f316-45b1-a5f4-c01dadfb02e8", + "name": "Full Scope Disabled", + "providerId": "scope", + "subType": "anonymous", + "subComponents": {}, + "config": {} + } + ], + "org.keycloak.keys.KeyProvider": [ + { + "id": "1bb336de-2a5a-4c52-a6d7-7d8de191d5b3", + "name": "rsa-enc-generated", + "providerId": "rsa-enc-generated", + "subComponents": {}, + "config": { + "priority": [ + "100" + ], + "algorithm": [ + "RSA-OAEP" + ] + } + }, + { + "id": "b91a01f0-a022-40ef-9a6f-2525408d65ba", + "name": "rsa-generated", + "providerId": "rsa-generated", + "subComponents": {}, + "config": { + "priority": [ + "100" + ] + } + }, + { + "id": "97787b65-617e-4f76-a448-efd954e90f76", + "name": "hmac-generated", + "providerId": "hmac-generated", + "subComponents": {}, + "config": { + "priority": [ + "100" + ], + "algorithm": [ + "HS256" + ] + } + }, + { + "id": "c8e87279-c3c9-40f8-aadf-0aed34733df9", + "name": "aes-generated", + "providerId": "aes-generated", + "subComponents": {}, + "config": { + "priority": [ + "100" + ] + } + } + ] + }, + "internationalizationEnabled": false, + "supportedLocales": [], + "authenticationFlows": [ + { + "id": "f180127f-0236-4ac9-a512-1faf661ce8f4", + "alias": "Account verification options", + "description": "Method with which to verity the existing account", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "idp-email-verification", + "authenticatorFlow": false, + "requirement": "ALTERNATIVE", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "ALTERNATIVE", + "priority": 20, + "autheticatorFlow": true, + "flowAlias": "Verify Existing Account by Re-authentication", + "userSetupAllowed": false + } + ] + }, + { + "id": "deec2692-a27c-4aaf-b12d-096dd94e80bb", + "alias": "Authentication Options", + "description": "Authentication options.", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "basic-auth", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "basic-auth-otp", + "authenticatorFlow": false, + "requirement": "DISABLED", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "auth-spnego", + "authenticatorFlow": false, + "requirement": "DISABLED", + "priority": 30, + "autheticatorFlow": false, + "userSetupAllowed": false + } + ] + }, + { + "id": "46e967c9-e9f3-4902-bed7-b7fcd7ac552d", + "alias": "Browser - Conditional OTP", + "description": "Flow to determine if the OTP is required for the authentication", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "conditional-user-configured", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "auth-otp-form", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + } + ] + }, + { + "id": "90dcf889-ae92-407f-b80c-3d895a0944b4", + "alias": "Direct Grant - Conditional OTP", + "description": "Flow to determine if the OTP is required for the authentication", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "conditional-user-configured", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "direct-grant-validate-otp", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + } + ] + }, + { + "id": "f7d55ec4-fff1-4c0c-bf0a-1bd9e6738bff", + "alias": "First broker login - Conditional OTP", + "description": "Flow to determine if the OTP is required for the authentication", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "conditional-user-configured", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "auth-otp-form", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + } + ] + }, + { + "id": "0a8e1e82-33e8-48c0-b0db-38a20ffe9a2d", + "alias": "Handle Existing Account", + "description": "Handle what to do if there is existing account with same email/username like authenticated identity provider", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "idp-confirm-link", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "REQUIRED", + "priority": 20, + "autheticatorFlow": true, + "flowAlias": "Account verification options", + "userSetupAllowed": false + } + ] + }, + { + "id": "1db84d52-1c92-4ce4-95c0-033cfe94f0f3", + "alias": "Reset - Conditional OTP", + "description": "Flow to determine if the OTP should be reset or not. Set to REQUIRED to force.", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "conditional-user-configured", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "reset-otp", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + } + ] + }, + { + "id": "02deb437-dc9c-4e36-b73f-34fa609bf5c0", + "alias": "User creation or linking", + "description": "Flow for the existing/non-existing user alternatives", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticatorConfig": "create unique user config", + "authenticator": "idp-create-user-if-unique", + "authenticatorFlow": false, + "requirement": "ALTERNATIVE", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "ALTERNATIVE", + "priority": 20, + "autheticatorFlow": true, + "flowAlias": "Handle Existing Account", + "userSetupAllowed": false + } + ] + }, + { + "id": "6820ed9f-e18d-4ad1-9e08-79a369f1d501", + "alias": "Verify Existing Account by Re-authentication", + "description": "Reauthentication of existing account", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "idp-username-password-form", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "CONDITIONAL", + "priority": 20, + "autheticatorFlow": true, + "flowAlias": "First broker login - Conditional OTP", + "userSetupAllowed": false + } + ] + }, + { + "id": "0de7d34e-cdea-49eb-93b2-241c83b6aeae", + "alias": "browser", + "description": "browser based authentication", + "providerId": "basic-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "auth-cookie", + "authenticatorFlow": false, + "requirement": "ALTERNATIVE", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "auth-spnego", + "authenticatorFlow": false, + "requirement": "DISABLED", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "identity-provider-redirector", + "authenticatorFlow": false, + "requirement": "ALTERNATIVE", + "priority": 25, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "ALTERNATIVE", + "priority": 30, + "autheticatorFlow": true, + "flowAlias": "forms", + "userSetupAllowed": false + } + ] + }, + { + "id": "8ee4765d-e660-448d-8fd8-a356dc08d88e", + "alias": "clients", + "description": "Base authentication for clients", + "providerId": "client-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "client-secret", + "authenticatorFlow": false, + "requirement": "ALTERNATIVE", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "client-jwt", + "authenticatorFlow": false, + "requirement": "ALTERNATIVE", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "client-secret-jwt", + "authenticatorFlow": false, + "requirement": "ALTERNATIVE", + "priority": 30, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "client-x509", + "authenticatorFlow": false, + "requirement": "ALTERNATIVE", + "priority": 40, + "autheticatorFlow": false, + "userSetupAllowed": false + } + ] + }, + { + "id": "bd9c9450-1a92-4ffc-ac3c-b1b8c3a038d2", + "alias": "direct grant", + "description": "OpenID Connect Resource Owner Grant", + "providerId": "basic-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "direct-grant-validate-username", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "direct-grant-validate-password", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "CONDITIONAL", + "priority": 30, + "autheticatorFlow": true, + "flowAlias": "Direct Grant - Conditional OTP", + "userSetupAllowed": false + } + ] + }, + { + "id": "2727dd7b-89d9-4063-b813-4489cc7310fb", + "alias": "docker auth", + "description": "Used by Docker clients to authenticate against the IDP", + "providerId": "basic-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "docker-http-basic-authenticator", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + } + ] + }, + { + "id": "9e332813-ea2e-46e1-bd74-323b49fe7a40", + "alias": "first broker login", + "description": "Actions taken after first broker login with identity provider account, which is not yet linked to any Keycloak account", + "providerId": "basic-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticatorConfig": "review profile config", + "authenticator": "idp-review-profile", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "REQUIRED", + "priority": 20, + "autheticatorFlow": true, + "flowAlias": "User creation or linking", + "userSetupAllowed": false + } + ] + }, + { + "id": "710dfe13-0fd3-48d3-959d-a541620544e3", + "alias": "forms", + "description": "Username, password, otp and other auth forms.", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "auth-username-password-form", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "CONDITIONAL", + "priority": 20, + "autheticatorFlow": true, + "flowAlias": "Browser - Conditional OTP", + "userSetupAllowed": false + } + ] + }, + { + "id": "3c9456b1-8c60-4409-af25-af6f567cf7c0", + "alias": "http challenge", + "description": "An authentication flow based on challenge-response HTTP Authentication Schemes", + "providerId": "basic-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "no-cookie-redirect", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "REQUIRED", + "priority": 20, + "autheticatorFlow": true, + "flowAlias": "Authentication Options", + "userSetupAllowed": false + } + ] + }, + { + "id": "214d41fe-ba80-478b-bcd9-a15221f79801", + "alias": "registration", + "description": "registration flow", + "providerId": "basic-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "registration-page-form", + "authenticatorFlow": true, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": true, + "flowAlias": "registration form", + "userSetupAllowed": false + } + ] + }, + { + "id": "bd3b9631-d962-43cb-9042-580f30e5544e", + "alias": "registration form", + "description": "registration form", + "providerId": "form-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "registration-user-creation", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "registration-profile-action", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 40, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "registration-password-action", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 50, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "registration-recaptcha-action", + "authenticatorFlow": false, + "requirement": "DISABLED", + "priority": 60, + "autheticatorFlow": false, + "userSetupAllowed": false + } + ] + }, + { + "id": "f9ef35b4-e352-4637-8988-0b06810485a0", + "alias": "reset credentials", + "description": "Reset credentials for a user if they forgot their password or something", + "providerId": "basic-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "reset-credentials-choose-user", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "reset-credential-email", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "reset-password", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 30, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "CONDITIONAL", + "priority": 40, + "autheticatorFlow": true, + "flowAlias": "Reset - Conditional OTP", + "userSetupAllowed": false + } + ] + }, + { + "id": "5ffd4f1f-30a0-4c96-adde-407a08d036cf", + "alias": "saml ecp", + "description": "SAML ECP Profile Authentication Flow", + "providerId": "basic-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "http-basic-authenticator", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + } + ] + } + ], + "authenticatorConfig": [ + { + "id": "335da768-988c-46a4-9928-e97285cf23b2", + "alias": "create unique user config", + "config": { + "require.password.update.after.registration": "false" + } + }, + { + "id": "b671f49e-3824-4c80-b933-540a55f1dd37", + "alias": "review profile config", + "config": { + "update.profile.on.first.login": "missing" + } + } + ], + "requiredActions": [ + { + "alias": "CONFIGURE_TOTP", + "name": "Configure OTP", + "providerId": "CONFIGURE_TOTP", + "enabled": true, + "defaultAction": false, + "priority": 10, + "config": {} + }, + { + "alias": "terms_and_conditions", + "name": "Terms and Conditions", + "providerId": "terms_and_conditions", + "enabled": false, + "defaultAction": false, + "priority": 20, + "config": {} + }, + { + "alias": "UPDATE_PASSWORD", + "name": "Update Password", + "providerId": "UPDATE_PASSWORD", + "enabled": true, + "defaultAction": false, + "priority": 30, + "config": {} + }, + { + "alias": "UPDATE_PROFILE", + "name": "Update Profile", + "providerId": "UPDATE_PROFILE", + "enabled": true, + "defaultAction": false, + "priority": 40, + "config": {} + }, + { + "alias": "VERIFY_EMAIL", + "name": "Verify Email", + "providerId": "VERIFY_EMAIL", + "enabled": true, + "defaultAction": false, + "priority": 50, + "config": {} + }, + { + "alias": "delete_account", + "name": "Delete Account", + "providerId": "delete_account", + "enabled": false, + "defaultAction": false, + "priority": 60, + "config": {} + }, + { + "alias": "update_user_locale", + "name": "Update User Locale", + "providerId": "update_user_locale", + "enabled": true, + "defaultAction": false, + "priority": 1000, + "config": {} + } + ], + "browserFlow": "browser", + "registrationFlow": "registration", + "directGrantFlow": "direct grant", + "resetCredentialsFlow": "reset credentials", + "clientAuthenticationFlow": "clients", + "dockerAuthenticationFlow": "docker auth", + "attributes": { + "cibaBackchannelTokenDeliveryMode": "poll", + "cibaExpiresIn": "120", + "cibaAuthRequestedUserHint": "login_hint", + "oauth2DeviceCodeLifespan": "600", + "oauth2DevicePollingInterval": "5", + "parRequestUriLifespan": "60", + "cibaInterval": "5" + }, + "keycloakVersion": "17.0.1", + "userManagedAccessAllowed": false, + "clientProfiles": { + "profiles": [] + }, + "clientPolicies": { + "policies": [] + } +} \ No newline at end of file diff --git a/ph-ee-env-labs/helm/ph-ee-fin-back-end/templates/config.yml b/ph-ee-env-labs/helm/ph-ee-fin-back-end/templates/config.yml new file mode 100644 index 000000000..98f65ae95 --- /dev/null +++ b/ph-ee-env-labs/helm/ph-ee-fin-back-end/templates/config.yml @@ -0,0 +1,6 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: ph-ee-config +data: +{{ (.Files.Glob "config/**.properties").AsConfig | nindent 2 }} diff --git a/ph-ee-env-labs/helm/ph-ee-fin-back-end/templates/relm-secret.yaml b/ph-ee-env-labs/helm/ph-ee-fin-back-end/templates/relm-secret.yaml new file mode 100644 index 000000000..8e415e647 --- /dev/null +++ b/ph-ee-env-labs/helm/ph-ee-fin-back-end/templates/relm-secret.yaml @@ -0,0 +1,9 @@ +apiVersion: v1 +kind: Secret +metadata: + name: realm-secret +#labels: +# app: keycloak +type: Opaque +data: +{{ (.Files.Glob "kong-keycloak-realm.json").AsSecrets | indent 2 }} \ No newline at end of file diff --git a/ph-ee-env-labs/helm/ph-ee-fin-back-end/values.yaml b/ph-ee-env-labs/helm/ph-ee-fin-back-end/values.yaml new file mode 100644 index 000000000..dff697d03 --- /dev/null +++ b/ph-ee-env-labs/helm/ph-ee-fin-back-end/values.yaml @@ -0,0 +1,108 @@ +ph-ee-engine: + enabled: true + + zeebe-operate-helm: + enabled: true + + elasticsearch: + enabled: true + + kibana: + enabled: false + + operations: + enabled: true + + ph_ee_connector_ams_mifos: + enabled: true + + ph_ee_connector_mojaloop: + enabled: false + + kafka: + enabled: true + + channel: + enabled: true + + mockpayment: + enabled: true + + gsmachannel: + enabled: false + + operations_app: + enabled: true + + operations_web: + enabled: false + + ph_ee_connector_gsma: + enabled: false + + ph_ee_connector_slcb: + enabled: true + image: "419830066942.dkr.ecr.ap-south-1.amazonaws.com/ph-ee-slcb" + imageTag: latest + + mpesa: + enabled: true + + roster_connector: + enabled: true + pesacore: + auth_header: "PaymentHub" + + paygops_connector: + enabled: true + paygops: + authheader: "PaymentHubTest" + + notifications: + enabled: true + + connector_bulk: + enabled: true + + zeebe_ops: + enabled: true + + messagegateway: + enabled: true + + importer_es: + enabled: true + + importer_rdbms: + enabled: true + + kong: + enabled: false + + keycloak: + enabled: false + + mock-oracle: + enabled: true + + redis: + enabled: true + +fin-engine: + enabled: true + communityapp: + enabled: false + + fineract: + enabled: true + + mariadb: + enabled: true + fullnameOverride: mysql + +operations: + enabled: true + grafana: + enabled: false + prometheus: + enabled: true \ No newline at end of file diff --git a/ph-ee-env-labs/helm/ph-ee-fin-front-end/Chart.yaml b/ph-ee-env-labs/helm/ph-ee-fin-front-end/Chart.yaml new file mode 100644 index 000000000..1eb55897e --- /dev/null +++ b/ph-ee-env-labs/helm/ph-ee-fin-front-end/Chart.yaml @@ -0,0 +1,17 @@ +apiVersion: v2 +name: front-end +description: A Helm chart for front-end services +type: application +version: 1.0.0 +appVersion: "ph-ee-superset: v1.16.0; ph-ee-engine:v1.16.0; fin-engine: v1.0.0; operations: 1.0.0;" + +dependencies: +- name: ph-ee-engine + repository: "https://fynarfin.io/images/ph-ee-engine-1.7.2-SNAPSHOT/" + version: 1.7.2-SNAPSHOT +- name: fin-engine + repository: "https://fynarfin.io/images/fineract/" + version: 1.0.0-SNAPSHOT +- name: operations + repository: "https://fynarfin.io/images/operations/" + version: "0.1.0" diff --git a/ph-ee-env-labs/helm/ph-ee-fin-front-end/values.yaml b/ph-ee-env-labs/helm/ph-ee-fin-front-end/values.yaml new file mode 100644 index 000000000..85c154b30 --- /dev/null +++ b/ph-ee-env-labs/helm/ph-ee-fin-front-end/values.yaml @@ -0,0 +1,112 @@ +ph-ee-engine: + zeebe-cluster-helm: + enabled: false + + zeebe-operate-helm: + enabled: false + + elasticsearch: + enabled: false + + kibana: + enabled: true + + operations: + mysql: + enabled: false + enabled: false + + operationsmysql: + enabled: false + + ph_ee_connector_ams_mifos: + enabled: false + + ph_ee_connector_mojaloop: + enabled: false + + kafka: + enabled: false + + channel: + enabled: false + + mockpayment: + enabled: false + + gsmachannel: + enabled: false + + operations_app: + enabled: false + + operations_web: + enabled: true + + ph_ee_connector_gsma: + enabled: false + + ph_ee_connector_slcb: + enabled: false + + mpesa: + enabled: false + + roster_connector: + enabled: false + #remove this after updating the env-template chart + pesacore: + auth_header: "PaymentHub" + + paygops_connector: + enabled: false + #remove this after updating the env-template chart + paygops: + authheader: "PaymentHub" + + notifications: + enabled: false + + connector_bulk: + enabled: false + + zeebe_ops: + enabled: false + + messagegateway: + enabled: false + + importer_es: + enabled: false + + importer_rdbms: + enabled: false + + kong: + enabled: false + + keycloak: + enabled: false + + zeebe-operate: + enabled: false + + mock-oracle: + enabled: false + + redis: + enabled: false + +fin-engine: + communityapp: + enabled: true + fineract: + enabled: false + mariadb: + enabled: false + +operations: + grafana: + enabled: true + prometheus: + enabled: false \ No newline at end of file diff --git a/ph-ee-env-labs/helm/ph-ee-g2p-sandbox-ci/Chart.yaml b/ph-ee-env-labs/helm/ph-ee-g2p-sandbox-ci/Chart.yaml new file mode 100644 index 000000000..f6e8b8100 --- /dev/null +++ b/ph-ee-env-labs/helm/ph-ee-g2p-sandbox-ci/Chart.yaml @@ -0,0 +1,12 @@ +apiVersion: v2 +name: ph-ee-g2p-sandbox-ci +description: A Helm chart for CI/CD + +type: application +version: 0.0.0 +appVersion: 0.0.0 + +dependencies: +- name: ph-ee-g2psandbox + repository: https://fynarfin.io/images/ph-ee-g2psandbox-0.0.0 + version: 0.0.0 diff --git a/ph-ee-env-labs/helm/ph-ee-g2p-sandbox-ci/values.yaml b/ph-ee-env-labs/helm/ph-ee-g2p-sandbox-ci/values.yaml new file mode 100644 index 000000000..1eec1f052 --- /dev/null +++ b/ph-ee-env-labs/helm/ph-ee-g2p-sandbox-ci/values.yaml @@ -0,0 +1,187 @@ +ph-ee-g2psandbox: + account_mapper: + LOGGING_LEVEL_ROOT: INFO + limits: + cpu: "400m" + memory: "384M" + requests: + cpu: "150m" + memory: "256M" + livenessProbe: + initialDelaySeconds: 20 + periodSeconds: 30 + readinessProbe: + initialDelaySeconds: 180 + periodSeconds: 30 + + ph-ee-engine: + camunda-platform: + zeebe: + pvcSize: "5Gi" + resources: + limits: + cpu: "250m" + memory: "768Mi" + requests: + cpu: "150m" + memory: "500Mi" + zeebe-gateway: + readinessProbe: + initialDelaySeconds: 180 + channel: + readinessProbe: + initialDelaySeconds: 180 + limits: + memory: "512M" + cpu: "300m" + requests: + memory: "256M" + cpu: "150m" + operationsmysql: + primary: + persistence: + size: 3Gi + readinessProbe: + initialDelaySeconds: 180 + ph_ee_connector_ams_mifos: + resources: + limits: + memory: "384M" + cpu: "150m" + requests: + memory: "256M" + cpu: "100m" + ph_ee_connector_mojaloop: + readinessProbe: + initialDelaySeconds: 120 + limits: + memory: "384M" + cpu: "150m" + requests: + memory: "256M" + cpu: "100m" + operations_app: + readinessProbe: + initialDelaySeconds: 180 + limits: + memory: "384M" + cpu: "350m" + requests: + memory: "256M" + cpu: "200m" + zeebe_ops: + readinessProbe: + initialDelaySeconds: 180 + limits: + memory: "384M" + cpu: "300m" + requests: + memory: "256M" + cpu: "150m" + mockpayment: + limits: + memory: "512M" + cpu: "250m" + requests: + memory: "256M" + cpu: "150m" + kafka: + controller: + persistence: + size: "4Gi" + readinessProbe: + initialDelaySeconds: 5 + global: + storageClass: standard + provisioning: + enabled: false + importer_rdbms: + readinessProbe: + initialDelaySeconds: 180 + limits: + memory: "384M" + cpu: "250m" + requests: + memory: "256M" + cpu: "150m" + connector_bulk: + readinessProbe: + initialDelaySeconds: 180 + limits: + memory: "448M" + cpu: "250m" + requests: + memory: "256M" + cpu: "100m" + ph_ee_connector_gsma: + limits: + memory: "256M" + cpu: "150m" + requests: + memory: "256M" + cpu: "100m" + ph-ee-connector: + limits: + cpu: "250m" + memory: "384M" + requests: + cpu: "150m" + memory: "256M" + integration_test: + limits: + cpu: "800m" + memory: "1200M" + requests: + cpu: "250m" + memory: "256M" + redis: + master: + resources: + limits: + cpu: "200m" + memory: "256M" + requests: + cpu: "100m" + memory: "100M" + persistence: + size: "3Gi" + readinessProbe: + initialDelaySeconds: 180 + replica: + replicaCount: 0 + vouchers: + readinessProbe: + initialDelaySeconds: 180 + livenessProbe: + initialDelaySeconds: 180 + limits: + cpu: "250m" + memory: "512M" + requests: + cpu: "150m" + memory: "256M" + billPay: + readinessProbe: + initialDelaySeconds: 180 + limits: + memory: "384M" + cpu: "250m" + requests: + memory: "256M" + cpu: "100m" + crm: + readinessProbe: + initialDelaySeconds: 180 + limits: + memory: "384M" + cpu: "150m" + requests: + memory: "256M" + cpu: "100m" + minio: + resources: + requests: + memory: 150Mi + persistence: + enabled: true + size: 512Mi diff --git a/ph-ee-env-labs/helm/ph-ee-g2p-sandbox-ci/values_p1.yaml b/ph-ee-env-labs/helm/ph-ee-g2p-sandbox-ci/values_p1.yaml new file mode 100644 index 000000000..e8d3cb8bd --- /dev/null +++ b/ph-ee-env-labs/helm/ph-ee-g2p-sandbox-ci/values_p1.yaml @@ -0,0 +1,25 @@ +ph-ee-g2psandbox: + ph-ee-engine: + post_installation_job: + enabled: true + importer_es: + enabled: false + ph_ee_connector_ams_mifos: + enabled: false + crm: + enabled: false + billPay: + enabled: false + kibana: + enabled: false + messagegateway: + enabled: false + notifications: + enabled: false + operations_web: + enabled: false + elasticsearch: + enabled: false + volumeClaimTemplate: + storageClassName: standard + diff --git a/ph-ee-env-labs/helm/ph-ee-g2p-sandbox-ci/values_p2.yaml b/ph-ee-env-labs/helm/ph-ee-g2p-sandbox-ci/values_p2.yaml new file mode 100644 index 000000000..704ee12fc --- /dev/null +++ b/ph-ee-env-labs/helm/ph-ee-g2p-sandbox-ci/values_p2.yaml @@ -0,0 +1,22 @@ +ph-ee-g2psandbox: + ph-ee-engine: + post_installation_job: + enabled: false + elasticsearch: + enabled: false + kibana: + enabled: false + messagegateway: + enabled: false + notifications: + enabled: false + operations_web: + enabled: false + importer_es: + enabled: false + ph_ee_connector_ams_mifos: + enabled: true + ams_local_interop_host: "https://fynams.sandbox.fynarfin.io/" + ams_local_account_host: "https://fynams.sandbox.fynarfin.io/" + ams_local_customer_host: "https://fynams.sandbox.fynarfin.io/" + ams_local_auth_host: "https://fynams.sandbox.fynarfin.io/" diff --git a/ph-ee-env-labs/helm/superset-release/Chart.yaml b/ph-ee-env-labs/helm/superset-release/Chart.yaml new file mode 100644 index 000000000..1555c16db --- /dev/null +++ b/ph-ee-env-labs/helm/superset-release/Chart.yaml @@ -0,0 +1,14 @@ +apiVersion: v2 +name: ph-ee-superset-release +description: PaymentHub EE Barebone Edition + +type: application +version: 1.0.0 +appVersion: 1.16.0 + +dependencies: +- name: ph-ee-superset + repository: "file://../superset" + version: 0.2.0 + + diff --git a/ph-ee-env-labs/helm/superset-release/values.yaml b/ph-ee-env-labs/helm/superset-release/values.yaml new file mode 100644 index 000000000..804655e08 --- /dev/null +++ b/ph-ee-env-labs/helm/superset-release/values.yaml @@ -0,0 +1,68 @@ +ph-ee-superset: + ph-ee-engine: + + # zeebe-operate-helm: + + # elasticsearch: + + # kibana: + + # operations: + + ph_ee_connector_ams_mifos: + imageTag: "v1.2.2" + + ph_ee_connector_mojaloop: + imageTag: "latest" + + # kafka: + + channel: + imageTag: "v1.5.1" + + + operations_app: + imageTag: "v1.4.0" + + operations_web: + imageTag: "v1.3.1" + + ph_ee_connector_gsma: + imageTag: "v1.0.2" + + ph_ee_connector_slcb: + imageTag: "v1.1.1" + + mpesa: + imageTag: "v1.4.1" + + roster_connector: + imageTag: "v1.2.0" + + paygops_connector: + imageTag: "v1.5.0" + + notifications: + imageTag: "v1.1.0" + + connector_bulk: + imageTag: "v1.5.0" + + zeebe_ops: + imageTag: "v1.0.2" + + messagegateway: + imageTag: "v1.0.0" + + importer_es: + imageTag: "v1.4.0" + + importer_rdbms: + imageTag: "v1.3.1" + + # kong: + + # zeebe-operate: + + # mock-oracle: + diff --git a/ph-ee-env-labs/helm/superset/Chart.yaml b/ph-ee-env-labs/helm/superset/Chart.yaml new file mode 100644 index 000000000..d83e94e18 --- /dev/null +++ b/ph-ee-env-labs/helm/superset/Chart.yaml @@ -0,0 +1,12 @@ +apiVersion: v2 +name: ph-ee-superset +description: PaymentHub EE Barebone Edition + +type: application +version: 0.2.0 +appVersion: 1.16.0 + +dependencies: +- name: ph-ee-engine + repository: https://fynarfin.io/images/ + version: 0.0.0-SNAPSHOT diff --git a/ph-ee-env-labs/helm/superset/config/application-bb.properties b/ph-ee-env-labs/helm/superset/config/application-bb.properties new file mode 100644 index 000000000..508b11ecc --- /dev/null +++ b/ph-ee-env-labs/helm/superset/config/application-bb.properties @@ -0,0 +1,19 @@ +store.local.interop.host=https://us.ibank.financial +store.local.customer.host=https://us.ibank.financial +zeebe.broker.contactpoint=zeebe-zeebe-gateway:26500 + +security.oauth2.resource.jwt.key-uri=http://ops-bk.ibank.financial/oauth/token_key +rest.authorization.enabled=false +rest.authorization.host=http://ops-bk.ibank.financial + +dfspids=ibank-usa, ibank-india + +ams.groups[0].identifier= ACCOUNTID +ams.groups[0].value= roster +ams.groups[1].identifier= FOUNDATIONALID +ams.groups[1].value= paygops +ams.groups[2].identifier= default +ams.groups[2].value= paygops + + + diff --git a/ph-ee-env-labs/helm/superset/config/application-fin12.properties b/ph-ee-env-labs/helm/superset/config/application-fin12.properties new file mode 100644 index 000000000..00da52cce --- /dev/null +++ b/ph-ee-env-labs/helm/superset/config/application-fin12.properties @@ -0,0 +1,13 @@ +ams.localenabled=true +zeebe.broker.contactpoint=zeebe-zeebe-gateway:26500 + +ams.local.tenants[0].name=gorilla +ams.local.tenants[1].name=rhino +ams.local.tenants[0].user=mifos +ams.local.tenants[1].user=mifos +ams.local.tenants[0].password=password +ams.local.tenants[1].password=password +ams.local.tenants[0].authtype=basic +ams.local.tenants[1].authtype=basic +ams.local.tenants[0].fspId=payerfsp +ams.local.tenants[1].fspId=payeefsp diff --git a/ph-ee-env-labs/helm/superset/config/application-tenants.properties b/ph-ee-env-labs/helm/superset/config/application-tenants.properties new file mode 100644 index 000000000..dc9bc2ed3 --- /dev/null +++ b/ph-ee-env-labs/helm/superset/config/application-tenants.properties @@ -0,0 +1,6 @@ +bpmns.tenants[0].id= "lion" +bpmns.tenants[0].flows.payment-transfer= "mock_payment_transfer-{dfspid}" +bpmns.tenants[1].id= "rhino" +bpmns.tenants[1].flows.payment-transfer= "MockPayerFundTransfer-{dfspid}" +bpmns.tenants[2].id= "gorilla" +bpmns.tenants[2].flows.payment-transfer= "PayerFundTransfer-{dfspid}" \ No newline at end of file diff --git a/ph-ee-env-labs/helm/superset/templates/config.yml b/ph-ee-env-labs/helm/superset/templates/config.yml new file mode 100644 index 000000000..98f65ae95 --- /dev/null +++ b/ph-ee-env-labs/helm/superset/templates/config.yml @@ -0,0 +1,6 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: ph-ee-config +data: +{{ (.Files.Glob "config/**.properties").AsConfig | nindent 2 }} diff --git a/ph-ee-env-labs/helm/superset/values.yaml b/ph-ee-env-labs/helm/superset/values.yaml new file mode 100644 index 000000000..04b4031d2 --- /dev/null +++ b/ph-ee-env-labs/helm/superset/values.yaml @@ -0,0 +1,992 @@ +ph-ee-engine: + zeebe: + broker: + contactpoint: "zeebe-zeebe-gateway:26500" + + # Whether this chart should self-manage its service account, role, and associated role binding. + managedServiceAccount: true + # Custom service account override that the pod will use + serviceAccount: "paymenthub" + # Annotations to add to the ServiceAccount that is created if the serviceAccount value isn't set. + serviceAccountAnnotations: {} + + zeebe-cluster-helm: + enabled: true + global: + elasticsearch: + host: "ph-ee-elasticsearch" + image: + repository: camunda/zeebe + tag: 1.1.0 + + clusterSize: "1" + partitionCount: "1" + replicationFactor: "1" + JavaOpts: "-Xms8g -Xmx8g -XX:+UseParallelGC -XX:MinHeapFreeRatio=5 -XX:MaxHeapFreeRatio=10 -XX:MaxRAMPercentage=25.0 -XX:GCTimeRatio=4 -XX:AdaptiveSizePolicyWeight=90 -XX:+PrintFlagsFinal" + + elasticsearch: + enabled: false + kibana: + enabled: false + + extraInitContainers: | + - name: init-ph-ee-kafka-exporter + image: busybox:1.28 + command: ['/bin/sh', '-c'] + args: ['wget -O /exporters/ph-ee-kafka-exporter.jar "https://paymenthub-ee-dev.s3.us-east-2.amazonaws.com/jars/exporter-1.0.0-SNAPSHOT.jar"; ls -al /exporters/'] + volumeMounts: + - name: exporters + mountPath: /exporters/ + + zeebe-operate-helm: + enabled: true + image: + repository: camunda/operate + tag: 1.1.0 + global: + elasticsearch: + host: "ph-ee-elasticsearch" + clusterName: "ph-ee-elasticsearch" + ingress: + enabled: false + className: "kong" + path: "/" + host: operate.sandbox.fynarfin.io + tls: + - secretName: sandbox-secret + + elasticsearch: + enabled: true + replicas: 1 + imageTag: 7.16.3 + minimumMasterNodes: 1 + esConfig: + elasticsearch.yml: | + xpack.security.enabled: false + xpack.security.transport.ssl.enabled: false + xpack.security.transport.ssl.verification_mode: certificate + xpack.security.transport.ssl.keystore.path: /usr/share/elasticsearch/config/certs/elastic-certificates.p12 + xpack.security.transport.ssl.truststore.path: /usr/share/elasticsearch/config/certs/elastic-certificates.p12 + xpack.security.http.ssl.enabled: false + xpack.security.http.ssl.truststore.path: /usr/share/elasticsearch/config/certs/elastic-certificates.p12 + xpack.security.http.ssl.keystore.path: /usr/share/elasticsearch/config/certs/elastic-certificates.p12 + secretMounts: + - name: elastic-certificates + secretName: elastic-certificates + path: /usr/share/elasticsearch/config/certs + extraEnvs: + - name: ELASTIC_PASSWORD + valueFrom: + secretKeyRef: + name: elastic-credentials + key: password + + #Single Node Solution + clusterHealthCheckParams: "wait_for_status=yellow&timeout=100s" + protocol: http + master: + readinessProbe: + httpGet: + allow-insecure: true + username: elastic + password: "{{ .Env.ELASTIC_PASSWORD }}" + path: /_cluster/health?wait_for_status=yellow&timeout=5s + port: 9200 + initialDelaySeconds: 30 + data: + readinessProbe: + httpGet: + allow-insecure: true + username: elastic + password: "{{ .Env.ELASTIC_PASSWORD }}" + path: /_cluster/health?wait_for_status=yellow&timeout=5s + port: 9200 + initialDelaySeconds: 30 + + + + # Shrink default JVM heap. + esJavaOpts: "-Xmx512m -Xms512m" + + # Allocate smaller chunks of memory per pod. + resources: + requests: + cpu: "100m" + memory: "1024M" + limits: + cpu: "1000m" + memory: "1024M" + volumeClaimTemplate: + accessModes: [ "ReadWriteOnce" ] + storageClassName: "gp2" + resources: + requests: + storage: 10Gi + + kibana: + readinessProbe: + initialDelaySeconds: 45 + timeoutSeconds: 15 + successThreshold: 1 + enabled: true + elasticsearchHosts: "http://ph-ee-elasticsearch:9200/" + imageTag: 7.16.3 + kibanaConfig: + kibana.yml: | + monitoring.enabled: false + xpack.encryptedSavedObjects.encryptionKey: 5f4dcc3b5aa765d61d8327deb882cf99 + server.ssl: + enabled: false + key: /usr/share/kibana/config/certs/elastic-certificate.pem + certificate: /usr/share/kibana/config/certs/elastic-certificate.pem + xpack.security.encryptionKey: ${KIBANA_ENCRYPTION_KEY} + elasticsearch.ssl: + certificateAuthorities: /usr/share/kibana/config/certs/elastic-certificate.pem + verificationMode: certificate + secretMounts: + - name: elastic-certificate-pem + secretName: elastic-certificate-pem + path: /usr/share/kibana/config/certs + extraEnvs: + - name: 'ELASTICSEARCH_USERNAME' + valueFrom: + secretKeyRef: + name: elastic-credentials + key: username + - name: 'ELASTICSEARCH_PASSWORD' + valueFrom: + secretKeyRef: + name: elastic-credentials + key: password + - name: 'KIBANA_ENCRYPTION_KEY' + valueFrom: + secretKeyRef: + name: kibana + key: encryptionkey + ingress: + enabled: true + className: "nginx" + pathtype: ImplementationSpecific + annotations: + # kubernetes.io/ingress.class: nginx + # kubernetes.io/ingress.class: kong + # kubernetes.io/tls-acme: "true" + hosts: + - host: analytics.sandbox.fynarfin.io + paths: + - path: "/" + tls: + - secretName: sandbox-secret + # hosts: + # - chart-example.local + + operations: + enabled: true + + operationsmysql: + enabled: true + auth: + database: "tenants" + username: "mifos" + password: "password" + rootPassword: "ethieTieCh8ahv" + initdbScripts: + setup.sql: |- + CREATE DATABASE messagegateway; + CREATE DATABASE `lion`; + CREATE DATABASE `gorilla`; + GRANT ALL PRIVILEGES ON `lion`.* TO 'mifos'; + GRANT ALL PRIVILEGES ON `gorilla`.* TO 'mifos'; + GRANT ALL ON *.* TO 'root'@'%'; + GRANT ALL PRIVILEGES ON messagegateway.* TO 'mifos'; + + ph_ee_connector_ams_mifos: + enabled: true + image: "419830066942.dkr.ecr.ap-south-1.amazonaws.com/ph-ee-ams" + imageTag: latest + SPRING_PROFILES_ACTIVE: "fin12" + hostname: "amsmifos.sandbox.fynarfin.io" + ams_local_enabled: true + ams_local_interop_host : "https://fynams.sandbox.fynarfin.io" + ams_local_customer_host : "https://fynams.sandbox.fynarfin.io" + ams_local_account_host : "https://fynams.sandbox.fynarfin.io" + ams_local_auth_host : "https://fynams.sandbox.fynarfin.io" + ams_local_loan_host : "https://fynams.sandbox.fynarfin.io/" + dfspids: "gorilla,rhino" + ## tenants properties have been moved to fin12 + limits: + cpu: "500m" + memory: "512M" + requests: + cpu: "100m" + memory: "256M" + ingress: + enabled: true + annotations: + kubernetes.io/ingress.class: "nginx" + tls: + - secretName: sandbox-secret + path: "/" + backend: + service: + name: ph-ee-connector-ams-mifos + port: + number: 80 + deployment: + annotations: + deployTime: "{{ .Values.deployTime }}" + + ph_ee_connector_mojaloop: + enabled: true + image: "419830066942.dkr.ecr.ap-south-1.amazonaws.com/phee-mojaloop" + imageTag: "latest" + SPRING_PROFILES_ACTIVE: "bb" + hostname: "mojaloop.sandbox.fynarfin.io" + DFSPIDS: "gorilla,rhino" + switch: + quotes: + host: "http://quoting-service.sandbox.fynarfin.io" + service: "quoting-service.sandbox.fynarfin.io" + als: + host: "http://account-lookup-service.sandbox.fynarfin.io" + service: "account-lookup-service.local" + transfers: + host: "http://api-adapter.sandbox.fynarfin.io" + service: "api-adapter.sandbox.fynarfin.io" + transactions: + host: "http://ml-api-adapter.sandbox.fynarfin.io" + service: "ml-api-adapter.sandbox.fynarfin.io" + oracle: + host: "http://moja-simulator.sandbox.fynarfin.io" + limits: + cpu: "500m" + memory: "512M" + requests: + cpu: "100m" + memory: "256M" + ingress: + enabled: true + className: "nginx" + annotations: + kubernetes.io/ingress.class: "nginx" + tls: + - secretName: sandbox-secret + path: "/" + backend: + service: + name: ph-ee-connector-mojaloop-java + port: + number: 80 + deployment: + annotations: + deployTime: "{{ .Values.deployTime }}" + + kafka: + enabled: true + image: "spotify/kafka" + advertised: + host: "kafka" + port: "9092" + limits: + cpu: "500m" + memory: "1G" + requests: + cpu: "100m" + memory: "512M" + deployment: + annotations: + deployTime: "{{ .Values.deployTime }}" + + channel: + enabled: true + image: "419830066942.dkr.ecr.ap-south-1.amazonaws.com/phee-channel" + imageTag: latest + SPRING_PROFILES_ACTIVE: "bb,tenants" + hostname: "channel.sandbox.fynarfin.io" + stub_hostname: "channel-gsma.sandbox.fynarfin.io" + DFSPIDS: "gorilla,lion" + operations: + url: "http://ops-bk.sandbox.fynarfin.io/api/v1" + authEnabled: false + tenantPrimary: + clientId: "mifos" + clientSecret: "password" + tenant: "rhino" + tenantSecondary: + clientId: "mifos" + clientSecret: "password" + tenant: "gorilla" + limits: + cpu: "500m" + memory: "512M" + requests: + cpu: "100m" + memory: "256M" + ingress: + enabled: true + className: "nginx" + annotations: + kubernetes.io/ingress.class: "nginx" + tls: + - secretName: sandbox-secret + path: "/" + backend: + service: + name: ph-ee-connector-channel + port: + number: 80 + stub_backend: + service: + name: ph-ee-connector-channel + port: + number: 82 + deployment: + annotations: + deployTime: "{{ .Values.deployTime }}" + + + mockpayment: + enabled: true + image: "419830066942.dkr.ecr.ap-south-1.amazonaws.com/phee-mock-payment-schema" + imageTag: latest + SPRING_PROFILES_ACTIVE: "bb,tenants" + DFSPIDS: "gorilla,lion" + limits: + cpu: "500m" + memory: "512M" + requests: + cpu: "100m" + memory: "256M" + deployment: + annotations: + deployTime: "{{ .Values.deployTime }}" + + + gsmachannel: + enabled: true + image: "419830066942.dkr.ecr.ap-south-1.amazonaws.com/phee-gsma-channel" + imageTag: latest + SPRING_PROFILES_ACTIVE: "bb" + DFSPIDS: "gorilla,lion" + limits: + cpu: "500m" + memory: "512M" + requests: + cpu: "100m" + memory: "256M" + ingress: + enabled: true + className: "nginx" + annotations: + kubernetes.io/ingress.class: "nginx" + tls: + - secretName: sandbox-secret + path: "/" + backend: + service: + name: ph-ee-connector-gsma-channel + port: + number: 80 + stub_backend: + service: + name: ph-ee-connector-gsma-channel + port: + number: 82 + deployment: + annotations: + deployTime: "{{ .Values.deployTime }}" + + gsmachannelsimulator: + enabled: true + image: "419830066942.dkr.ecr.ap-south-1.amazonaws.com/phee-gsma-channel-simulator" + imageTag: latest + SPRING_PROFILES_ACTIVE: "bb" + DFSPIDS: "gorilla,lion" + limits: + cpu: "500m" + memory: "512M" + requests: + cpu: "100m" + memory: "256M" + ingress: + enabled: true + className: "nginx" + annotations: + kubernetes.io/ingress.class: "nginx" + tls: + - secretName: sandbox-secret + path: "/" + backend: + service: + name: ph-ee-connector-gsma-channel-simulator + port: + number: 80 + stub_backend: + service: + name: ph-ee-connector-gsma-channel-simulator + port: + number: 82 + deployment: + annotations: + deployTime: "{{ .Values.deployTime }}" + + operations_app: + enabled: true + image: "419830066942.dkr.ecr.ap-south-1.amazonaws.com/ph-ee-ops-bk" + imageTag: "latest" + SPRING_PROFILES_ACTIVE: "bb" + tenants: "gorilla,lion, phdefault" + hostname: "ops-bk.sandbox.fynarfin.io" + datasource: + username: "mifos" + password: "password" + host: "operationsmysql" + port: 3306 + schema: "tenants" + limits: + cpu: "500m" + memory: "512M" + requests: + cpu: "100m" + memory: "256M" + ingress: + enabled: true + className: "kong" + annotations: + kubernetes.io/ingress.class: "nginx" + nginx.ingress.kubernetes.io/configuration-snippet: | + more_set_headers "Access-Control-Allow-Origin: *"; + more_set_headers "Platform-TenantId: *"; + nginx.ingress.kubernetes.io/cors-allow-credentials: 'true' + nginx.ingress.kubernetes.io/cors-allow-headers: >- + DNT,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization,Platform-TenantId + nginx.ingress.kubernetes.io/cors-allow-methods: PUT, GET, POST, OPTIONS, DELETE, PATCH + nginx.ingress.kubernetes.io/enable-cors: 'true' + tls: + - secretName: sandbox-secret + path: "/" + backend: + service: + name: ph-ee-operations-app + port: + number: 80 + deployment: + annotations: + deployTime: "{{ .Values.deployTime }}" + + operations_web: + enabled: true + image: "419830066942.dkr.ecr.ap-south-1.amazonaws.com/phee-ops-web" + imageTag: "latest" + SPRING_PROFILES_ACTIVE: "bb" + hostname: "ops.sandbox.fynarfin.io" + webhost: "ops.sandbox.fynarfin.io" + limits: + cpu: "500m" + memory: "512M" + requests: + cpu: "100m" + memory: "256M" + ingress: + className: "kong" + enabled: true + annotations: + kubernetes.io/ingress.class: "nginx" + konghq.com/plugins: request-transformer,oidc,cors + tls: + - secretName: sandbox-secret + path: "/" + backend: + service: + name: ph-ee-operations-web + port: + number: 4200 + deployment: + config: {} + + identity: + hostname: "ops-bk.sandbox.fynarfin.io" + + ph_ee_connector_gsma: + enabled: true + image: "419830066942.dkr.ecr.ap-south-1.amazonaws.com/phee-gsma" + imageTag: latest + SPRING_PROFILES_ACTIVE: "bb" + api: + channel: "" + limits: + cpu: "500m" + memory: "512M" + requests: + cpu: "100m" + memory: "256M" + deployment: + annotations: + deployTime: "{{ .Values.deployTime }}" + + ph_ee_connector_slcb: + enabled: true + image: "419830066942.dkr.ecr.ap-south-1.amazonaws.com/ph-ee-slcb" + imageTag: latest + SPRING_PROFILES_ACTIVE: "bb" + deployment: + annotations: + deployTime: "{{ .Values.deployTime }}" + + mpesa: + enabled: true + image: "419830066942.dkr.ecr.ap-south-1.amazonaws.com/ph-mpesa" + imageTag: latest + SPRING_PROFILES_ACTIVE: "bb" + hostname: "mpesa.sandbox.fynarfin.io" + tenant: "lion" + zeebe_broker_contactpoint: "zeebe-zeebe-gateway:26500" + callback_host: "https://mpesa.sandbox.fynarfin.io/" + retry_count: 3 + api_timeout: 60000 + channel: + host: "http://ph-ee-connector-channel" + paygops: + host: "http://ph-ee-connector-ams-paygops" + roster: + host: "http://ph-ee-connector-ams-roster" + accounts: + roster: + name: "roster" + business_short_code: "7385028" + till: "1234567" + auth_host: "https://sandbox.safaricom.co.ke/oauth/v1/generate" + api_host: "https://sandbox.safaricom.co.ke" + client_key: "0pLxbN83FrOl5Nd0Fh9Zi5BQlMxSL2n5" + client_secret: "YzuGNoJxeub8ZC6d" + pass_key: "bfb279f9aa9bdbcf158e97dd71a467cd2e0c893059b10f78e6b72ada1ed2c919" + paygops: + name: "paygops" + business_short_code: "668158" + till: "9347335" + auth_host: "https://sandbox.safaricom.co.ke/oauth/v1/generate" + api_host: "https://sandbox.safaricom.co.ke" + client_key: "0pLxbN83FrOl5Nd0Fh9Zi5BQlMxSL2n5" + client_secret: "YzuGNoJxeub8ZC6d" + pass_key: "bfb279f9aa9bdbcf158e97dd71a467cd2e0c893059b10f78e6b72ada1ed2c919" + paybill: + accountHoldingInstitutionId: "gorilla" + paygops: + business_short_code: "24322607" + currency: "KES" + roster: + business_short_code: "12345678" + currency: "KES" + limits: + cpu: "500m" + memory: "512M" + requests: + cpu: "100m" + memory: "256M" + ingress: + enabled: true + className: "nginx" + annotations: + kubernetes.io/ingress.class: "nginx" + tls: + - secretName: sandbox-secret + path: "/" + backend: + service: + name: ph-ee-connector-mpesa + port: + number: 80 + deployment: + annotations: + deployTime: "{{ .Values.deployTime }}" + skip: + enabled: false + + roster_connector: + enabled: true + image: "419830066942.dkr.ecr.ap-south-1.amazonaws.com/phee-roster" + imageTag: latest + SPRING_PROFILES_ACTIVE: "bb" + ams: + local: + enabled: true + pesacore: + auth_header: "PaymentHub" + limits: + cpu: "500m" + memory: "512M" + requests: + cpu: "100m" + memory: "256M" + deployment: + annotations: + deployTime: "{{ .Values.deployTime }}" + + paygops_connector: + enabled: true + image: "419830066942.dkr.ecr.ap-south-1.amazonaws.com/phee-connector-ams-paygops" + imageTag: latest + SPRING_PROFILES_ACTIVE: "bb" + LOGGING_LEVEL_ROOT: "INFO" + ams: + local: + enabled: false + paygops: + authheader: "PaymentHubTest" + base_url: "https://feature-test1.paygops.com/" + limits: + cpu: "500m" + memory: "512M" + requests: + cpu: "100m" + memory: "256M" + deployment: + annotations: + deployTime: "{{ .Values.deployTime }}" + + notifications: + enabled: true + image: "419830066942.dkr.ecr.ap-south-1.amazonaws.com/ph-ee-notifications" + imageTag: latest + SPRING_PROFILES_ACTIVE: "bb" + hostname: "notifications.sandbox.fynarfin.io" + MESSAGEGATEWAYCONFIG_HOST: "message-gateway" + NOTIFICATION_LOCAL_HOST: "ph-ee-connector-notifications" + NOTIFICATION_SUCCESS_ENABLED: "false" + NOTIFICATION_FAILURE_ENABLED: "false" + zeebe_broker_contactpoint: "zeebe-zeebe-gateway:26500" + hostconfig: + host: "message-gateway" + port: 80 + limits: + cpu: "500m" + memory: "512M" + requests: + cpu: "100m" + memory: "256M" + ingress: + enabled: true + annotations: + kubernetes.io/ingress.class: "nginx" + tls: + - secretName: sandbox-secret + path: "/" + backend: + service: + name: ph-ee-connector-notifications + port: + number: 80 + deployment: + annotations: + deployTime: "{{ .Values.deployTime }}" + + connector_bulk: + enabled: true + image: "419830066942.dkr.ecr.ap-south-1.amazonaws.com/phee-bulk-processor" + imageTag: latest + tenants: "gorilla,lion" + hostname: "bulk-connector.sandbox.fynarfin.io" + aws: + region: "us-east-2" + access_key: "AKIAX32JM37TZOJ5AKFB" + secret_key: "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" + operations_app: + contactpoint: "https://ops-bk.sandbox.fynarfin.io/" + endpoints: + batch_transaction: "/api/v1/batch/transactions" + limits: + cpu: "500m" + memory: "512M" + requests: + cpu: "100m" + memory: "256M" + ingress: + enabled: true + className: "kong" + annotations: + kubernetes.io/ingress.class: "nginx" + konghq.com/plugins: cors + tls: + - secretName: sandbox-secret + path: "/" + backend: + service: + name: ph-ee-connector-bulk + port: + number: 80 + deployment: + annotations: + deployTime: "{{ .Values.deployTime }}" + + zeebe_ops: + enabled: true + image: "419830066942.dkr.ecr.ap-south-1.amazonaws.com/phee-zeebe-ops" + imageTag: latest + hostname: "zeebeops.sandbox.fynarfin.io" + zeebe_broker_contactpoint: "zeebe-zeebe-gateway:26500" + elasticsearch_url: "http://ph-ee-elasticsearch:9200/" + elasticsearch_contactpoint: "ph-ee-elasticsearch:9200" + tenants: "gorilla,lion" + elasticsearch_sslverification: false + elasticsearch_security_enabled: false + limits: + cpu: "500m" + memory: "512M" + requests: + cpu: "100m" + memory: "256M" + ingress: + enabled: true + className: "nginx" + annotations: + kubernetes.io/ingress.class: "nginx" + tls: + - secretName: sandbox-secret + path: "/" + backend: + service: + name: ph-ee-zeebe-ops + port: + number: 80 + deployment: + annotations: + deployTime: "{{ .Values.deployTime }}" + + messagegateway: + enabled: true + image: "419830066942.dkr.ecr.ap-south-1.amazonaws.com/phee-message-gateway" + imageTag: latest + secret: + value: + api_key: "eKiC1_JWdKy7eaTGQFHxXXjXjacr60W9Zntl" + project_id: "PJ5ff552ce01d2978c" + hostname: "messagegateway.sandbox.fynarfin.io" + CALLBACKCONFIG_HOST: "ph-ee-connector-notifications" + HOSTCONFIG_HOST: "message-gateway" + MYSQL_USERNAME: "mifos" + MYSQL_PASSWORD: "password" + DATASOURCE_URL: jdbc:mysql:thin://operationsmysql:3306/messagegateway + PROVIDERSOURCE_FROMDATABASE: "disabled" + PROVIDERSOURCE_FROMYML: "enabled" + limits: + cpu: "500m" + memory: "512M" + requests: + cpu: "100m" + memory: "256M" + ingress: + enabled: true + className: "nginx" + annotations: + kubernetes.io/ingress.class: "nginx" + tls: + - secretName: sandbox-secret + path: "/" + backend: + service: + name: message-gateway + port: + number: 80 + + importer_es: + enabled: true + image: "419830066942.dkr.ecr.ap-south-1.amazonaws.com/ph-es-importer" + imageTag: latest + elasticsearch_sslverification: false + elasticsearch_security_enabled: false + importer_elasticsearch_url: "http://ph-ee-elasticsearch:9200/" + reporting: + enabled: true + fields: + amount: true + accountId: true + ams: true + clientCorrelationId: true + currency: true + customData: true + confirmationReceived: true + errorInformation: true + errorCode: false + errorDescription: true + externalId: true + initiator: false + initiatorType: false + isNotificationsFailureEnabled: false + isNotificationsSuccessEnabled: false + mpesaTransactionId: false + mpesaTransactionStatusRetryCount: false + originDate: false + partyLookupFailed: false + phoneNumber: true + processDefinitionKey: false + processInstanceKey: true + scenario: false + tenantId: false + timer: false + timestamp: true + transactionFailed: false + transactionId: false + transferCreateFailed: false + transferSettlementFailed: false + transferResponseCREATE: false + limits: + cpu: "500m" + memory: "512M" + requests: + cpu: "100m" + memory: "256M" + + importer_rdbms: + enabled: true + image: "419830066942.dkr.ecr.ap-south-1.amazonaws.com/phee-importer-rdbms" + imageTag: latest + LOGGING_LEVEL_ROOT: "DEBUG" + limits: + cpu: "500m" + memory: "512M" + requests: + cpu: "100m" + memory: "256M" + datasource: + username: "mifos" + password: "password" + host: "operationsmysql" + port: 3306 + schema: "tenants" + + kong: + enabled: flase + image: + repository: revomatico/docker-kong-oidc + tag: "latest" + env: + plugins: "bundled,oidc" + admin: + enabled: true + http: + enabled: true + tls: + enabled: false + ingress: + enabled: true + ingressClassName: "kong" + hostname: admin-kong.sandbox.fynarfin.io + extraObjects: + - apiVersion: configuration.konghq.com/v1 + kind: KongClusterPlugin + metadata: + name: request-transformer + annotations: + kubernetes.io/ingress.class: "kong" + labels: + global: "false" + disabled: false # optionally disable the plugin in Kong + plugin: request-transformer + config: + remove: + headers: + - cookie + - x-id-token + - apiVersion: configuration.konghq.com/v1 + kind: KongClusterPlugin + metadata: + name: cors + annotations: + kubernetes.io/ingress.class: "kong" + labels: + global: "true" + disabled: false # optionally disable the plugin in Kong + plugin: cors + config: + origins: + - "*" + credentials: true + max_age: 3600 + exposed_headers : + - "X-Auth-Token" + preflight_continue: false + - apiVersion: configuration.konghq.com/v1 + kind: KongClusterPlugin + metadata: + name: oidc + annotations: + kubernetes.io/ingress.class: "kong" + labels: + global: "false" + disabled: false # optionally disable the plugin in Kong + plugin: oidc + config: # configuration for the plugin + client_id: kong-oidc + client_secret: xxxxxxxx # Generated on keyCloak + realm: kong + discovery: https://keycloak.sandbox.fynarfin.io/auth/realms/kong-oidc/.well-known/openid-configuration + scope: openid + + keycloak: + enabled: false + ingress: + enabled: true + ingressClassName: "kong" + rules: + - host: 'keycloak.sandbox.fynarfin.io' + paths: + - path: / + pathType: Prefix + tls: [] + extraVolumes: | + - name: realm-secret + secret: + secretName: realm-secret + extraVolumeMounts: | + - name: realm-secret + mountPath: "/realm/" + readOnly: true + extraEnv: | + - name: KEYCLOAK_IMPORT + value: /realm/kong-keycloak-realm.json + + wildcardhostname: "*.sandbox.fynarfin.io" + + tls: "sandbox-secret" + + zeebe-operate: + ingress: + enabled: true + hostname: "zeebeoperate.sandbox.fynarfin.io" + className: "kong" + annotations: + kubernetes.io/ingress.class: "kong" + tls: + - secretName: sandbox-secret + path: "/" + backend: + service: + name: "zeebe-operate" + port: + number: 80 + +mock-oracle: + enabled: true + replicas: 1 + image: "419830066942.dkr.ecr.ap-south-1.amazonaws.com/mock-asl-oracle" + imagePullPolicy: "Always" + hostname: "mockoracle.sandbox.fynarfin.io" + ingress: + enabled: true + path: "/" + className: "nginx" + annotations: + kubernetes.io/ingress.class: "nginx" + backend: + service: + name: mock-oracle + port: + number: 80 + deployment: + annotations: + deployTime: "{{ .Values.deployTime }}" + + redis: + enabled: true + replica: + replicaCount: 0 diff --git a/ph-ee-env-labs/helm/zeebe-test/Chart.yaml b/ph-ee-env-labs/helm/zeebe-test/Chart.yaml new file mode 100644 index 000000000..d3934cd8d --- /dev/null +++ b/ph-ee-env-labs/helm/zeebe-test/Chart.yaml @@ -0,0 +1,12 @@ +apiVersion: v2 +name: ph-ee-zeebe-test +description: PaymentHub EE Barebone Edition + +type: application +version: 0.2.0 +appVersion: 1.16.0 + +dependencies: +- name: ph-ee-engine + repository: https://fynarfin.io/images/ + version: 0.0.0-SNAPSHOT diff --git a/ph-ee-env-labs/helm/zeebe-test/config/application-bb.properties b/ph-ee-env-labs/helm/zeebe-test/config/application-bb.properties new file mode 100644 index 000000000..c31624168 --- /dev/null +++ b/ph-ee-env-labs/helm/zeebe-test/config/application-bb.properties @@ -0,0 +1,13 @@ +store.local.interop.host=https://rhino2.sandbox.fynarfin.io +store.local.customer.host=https://rhino2.sandbox.fynarfin.io +zeebe.broker.contactpoint=zeebetest-zeebe-gateway:26500 + +security.oauth2.resource.jwt.key-uri=http://ops-bk2.sandbox.fynarfin.io/oauth/token_key +rest.authorization.enabled=false +rest.authorization.host=http://ops-bk2.sandbox.fynarfin.io + +dfspids=rhino, gorilla + + + + diff --git a/ph-ee-env-labs/helm/zeebe-test/config/application-fin12.properties b/ph-ee-env-labs/helm/zeebe-test/config/application-fin12.properties new file mode 100644 index 000000000..660ad0184 --- /dev/null +++ b/ph-ee-env-labs/helm/zeebe-test/config/application-fin12.properties @@ -0,0 +1,2 @@ +ams.localenabled=true +zeebe.broker.contactpoint=zeebe-zeebe-gateway:26500 \ No newline at end of file diff --git a/ph-ee-env-labs/helm/zeebe-test/templates/config.yml b/ph-ee-env-labs/helm/zeebe-test/templates/config.yml new file mode 100644 index 000000000..98f65ae95 --- /dev/null +++ b/ph-ee-env-labs/helm/zeebe-test/templates/config.yml @@ -0,0 +1,6 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: ph-ee-config +data: +{{ (.Files.Glob "config/**.properties").AsConfig | nindent 2 }} diff --git a/ph-ee-env-labs/helm/zeebe-test/values.yaml b/ph-ee-env-labs/helm/zeebe-test/values.yaml new file mode 100644 index 000000000..06dc6f665 --- /dev/null +++ b/ph-ee-env-labs/helm/zeebe-test/values.yaml @@ -0,0 +1,428 @@ +ph-ee-engine: + zeebe: + broker: + contactpoint: "zeebetest-zeebe-gateway:26500" + + #Old zeebe configuration to be replaced with camunda-platform:zeebe/zeebe gateway: +# zeebe-cluster-helm: +# global: +# elasticsearch: +# host: "ph-ee-elasticsearch" +# image: +# repository: camunda/zeebe +# tag: 1.1.0 +# +# clusterSize: "1" +# partitionCount: "1" +# replicationFactor: "1" +# JavaOpts: "-Xms8g -Xmx8g -XX:+UseParallelGC -XX:MinHeapFreeRatio=5 -XX:MaxHeapFreeRatio=10 -XX:MaxRAMPercentage=25.0 -XX:GCTimeRatio=4 -XX:AdaptiveSizePolicyWeight=90 -XX:+PrintFlagsFinal" +# +# elasticsearch: +# enabled: false +# kibana: +# enabled: false +# +# extraInitContainers: | +# - name: init-ph-ee-kafka-exporter +# image: busybox:1.28 +# command: ['/bin/sh', '-c'] +# args: ['wget -O /exporters/ph-ee-kafka-exporter.jar "https://paymenthub-ee-dev.s3.us-east-2.amazonaws.com/jars/exporter-1.0.0-SNAPSHOT.jar"; ls -al /exporters/'] +# volumeMounts: +# - name: exporters +# mountPath: /exporters/ + + elasticsearch: + enabled: true + replicas: 1 + imageTag: 7.16.3 + minimumMasterNodes: 1 + esConfig: + elasticsearch.yml: | + xpack.security.enabled: false + xpack.security.transport.ssl.enabled: false + xpack.security.transport.ssl.verification_mode: certificate + xpack.security.transport.ssl.keystore.path: /usr/share/elasticsearch/config/certs/elastic-certificates.p12 + xpack.security.transport.ssl.truststore.path: /usr/share/elasticsearch/config/certs/elastic-certificates.p12 + xpack.security.http.ssl.enabled: false + xpack.security.http.ssl.truststore.path: /usr/share/elasticsearch/config/certs/elastic-certificates.p12 + xpack.security.http.ssl.keystore.path: /usr/share/elasticsearch/config/certs/elastic-certificates.p12 + secretMounts: + - name: elastic-certificates + secretName: elastic-certificates + path: /usr/share/elasticsearch/config/certs + extraEnvs: + - name: ELASTIC_PASSWORD + valueFrom: + secretKeyRef: + name: elastic-credentials + key: password + + #Single Node Solution + clusterHealthCheckParams: "wait_for_status=yellow&timeout=100s" + protocol: http + master: + readinessProbe: + httpGet: + allow-insecure: true + username: elastic + password: "{{ .Env.ELASTIC_PASSWORD }}" + path: /_cluster/health?wait_for_status=yellow&timeout=5s + port: 9200 + initialDelaySeconds: 30 + data: + readinessProbe: + httpGet: + allow-insecure: true + username: elastic + password: "{{ .Env.ELASTIC_PASSWORD }}" + path: /_cluster/health?wait_for_status=yellow&timeout=5s + port: 9200 + initialDelaySeconds: 30 + + + + # Shrink default JVM heap. + esJavaOpts: "-Xmx512m -Xms512m" + + # Allocate smaller chunks of memory per pod. + resources: + requests: + cpu: "100m" + memory: "1024M" + limits: + cpu: "1000m" + memory: "1024M" + volumeClaimTemplate: + accessModes: [ "ReadWriteOnce" ] + storageClassName: "gp2" + resources: + requests: + storage: 10Gi + + kibana: + readinessProbe: + initialDelaySeconds: 45 + timeoutSeconds: 15 + successThreshold: 1 + enabled: true + protocol: http + imageTag: 7.16.3 + kibanaConfig: + kibana.yml: | + monitoring.enabled: false + xpack.encryptedSavedObjects.encryptionKey: 5f4dcc3b5aa765d61d8327deb882cf99 + server.ssl: + enabled: false + key: /usr/share/kibana/config/certs/elastic-certificate.pem + certificate: /usr/share/kibana/config/certs/elastic-certificate.pem + xpack.security.encryptionKey: ${KIBANA_ENCRYPTION_KEY} + elasticsearch.ssl: + certificateAuthorities: /usr/share/kibana/config/certs/elastic-certificate.pem + verificationMode: certificate + secretMounts: + - name: elastic-certificate-pem + secretName: elastic-certificate-pem + path: /usr/share/kibana/config/certs + extraEnvs: + - name: 'ELASTICSEARCH_USERNAME' + valueFrom: + secretKeyRef: + name: elastic-credentials + key: username + - name: 'ELASTICSEARCH_PASSWORD' + valueFrom: + secretKeyRef: + name: elastic-credentials + key: password + - name: 'KIBANA_ENCRYPTION_KEY' + valueFrom: + secretKeyRef: + name: kibana + key: encryptionkey + ingress: + enabled: true + className: "nginx" + pathtype: ImplementationSpecific + annotations: {} + kubernetes.io/ingress.class: nginx + kubernetes.io/tls-acme: "true" + hosts: + - host: analytics2.sandbox.fynarfin.io + paths: + - path: / + #tls: [] + # - secretName: chart-example-tls + # hosts: + # - chart-example.local + + operations: + enabled: true + + operationsmysql: + auth: + database: "tenants" + username: "mifos" + password: "password" + rootPassword: "ethieTieCh8ahv" + initdbScripts: + setup.sql: |- + CREATE DATABASE messagegateway; + CREATE DATABASE `rhino`; + CREATE DATABASE `gorilla`; + GRANT ALL PRIVILEGES ON `rhino`.* TO 'mifos'; + GRANT ALL PRIVILEGES ON `gorilla`.* TO 'mifos'; + GRANT ALL ON *.* TO 'root'@'%'; + GRANT ALL PRIVILEGES ON messagegateway.* TO 'mifos'; + + ph_ee_connector_ams_mifos: + enabled: true + image: "419830066942.dkr.ecr.ap-south-1.amazonaws.com/ph-ee-ams" + imageTag: latest + imagePullPolicy: "Always" + SPRING_PROFILES_ACTIVE: "fin12,bb" + ams_local_enabled: false + ams_local_interop_host: "https://fynams2.sandbox.fynarfin.io/" + ams_local_account_host: "https://fynams2.sandbox.fynarfin.io/" + ams_local_customer_host: "https://fynams2.sandbox.fynarfin.io/" + ams_local_auth_host: "https://fynams2.sandbox.fynarfin.io/" + limits: + cpu: "500m" + memory: "512M" + requests: + cpu: "100m" + memory: "256M" + deployment: + annotations: + deployTime: "{{ .Values.deployTime }}" + + ph_ee_connector_mojaloop: + enabled: false + + kafka: + enabled: true + image: "spotify/kafka" + advertised: + host: "kafka" + port: "9092" + limits: + cpu: "500m" + memory: "1G" + requests: + cpu: "100m" + memory: "512M" + deployment: + annotations: + deployTime: "{{ .Values.deployTime }}" + + channel: + enabled: true + image: "419830066942.dkr.ecr.ap-south-1.amazonaws.com/phee-channel-test" + imageTag: test + SPRING_PROFILES_ACTIVE: "bb" + hostname: "channel2.sandbox.fynarfin.io" + stub_hostname: "channel-gsma2.sandbox.fynarfin.io" + DFSPIDS: "rhino,gorilla" + zeebe: + broker: + contactpoint: "zeebetest-zeebe-gateway:26500" + limits: + cpu: "500m" + memory: "512M" + requests: + cpu: "100m" + memory: "256M" + ingress: + enabled: true + annotations: + kubernetes.io/ingress.class: "nginx" + path: "/" + backend: + service: + name: ph-ee-connector-channel + port: + number: 80 + stub_backend: + service: + name: ph-ee-connector-channel + port: + number: 82 + deployment: + annotations: + deployTime: "{{ .Values.deployTime }}" + + operations_app: + enabled: true + image: "419830066942.dkr.ecr.ap-south-1.amazonaws.com/ph-ee-ops-bk" + imageTag: latest + SPRING_PROFILES_ACTIVE: "bb" + tenants: "rhino,gorilla" + hostname: "ops-bk2.sandbox.fynarfin.io" + datasource: + username: "mifos" + password: "password" + host: "operationsmysql" + port: 3306 + schema: "tenants" + limits: + cpu: "500m" + memory: "512M" + requests: + cpu: "100m" + memory: "256M" + ingress: + enabled: true + annotations: + kubernetes.io/ingress.class: "nginx" + path: "/" + backend: + service: + name: ph-ee-operations-app + port: + number: 80 + deployment: + annotations: + deployTime: "{{ .Values.deployTime }}" + + operations_web: + enabled: true + image: "419830066942.dkr.ecr.ap-south-1.amazonaws.com/phee-ops-web" + imageTag: latest + SPRING_PROFILES_ACTIVE: "bb" + hostname: "ops2.sandbox.fynarfin.io" + webhost: "ops2.sandbox.fynarfin.io" + limits: + cpu: "500m" + memory: "512M" + requests: + cpu: "100m" + memory: "256M" + ingress: + enabled: true + annotations: + kubernetes.io/ingress.class: "nginx" + path: "/" + backend: + service: + name: ph-ee-operations-web + port: + number: 4200 + + identity: + hostname: "ops-bk2.sandbox.fynarfin.io" + + ph_ee_connector_gsma: + enabled: false + + ph_ee_connector_slcb: + enabled: false + + mpesa: + enabled: false + + roster_connector: + enabled: false + + paygops_connector: + enabled: false + + notifications: + enabled: false + + connector_bulk: + enabled: false + + zeebe_ops: + enabled: true + image: "419830066942.dkr.ecr.ap-south-1.amazonaws.com/phee-zeebe-ops" + imageTag: latest + hostname: "zeebeops2.sandbox.fynarfin.io" + zeebe_broker_contactpoint: "zeebetest-zeebe-gateway:26500" + elasticsearch_contactpoint: "ph-ee-elasticsearch:9200" + tenants: "rhino,gorilla" + elasticsearch_sslverification: false + elasticsearch_security_enabled: false + limits: + cpu: "500m" + memory: "512M" + requests: + cpu: "100m" + memory: "256M" + ingress: + enabled: true + annotations: + kubernetes.io/ingress.class: "nginx" + path: "/" + backend: + service: + name: ph-ee-zeebe-ops + port: + number: 80 + deployment: + annotations: + deployTime: "{{ .Values.deployTime }}" + + messagegateway: + enabled: false + + importer_es: + image: "419830066942.dkr.ecr.ap-south-1.amazonaws.com/ph-es-importer" + imageTag: latest + enabled: true + elasticsearch_sslverification: false + elasticsearch_security_enabled: false + reporting: + enabled: false + fields: + amount: true + accountId: true + errorCode: false + errorDescription: true + externalId: true + initiator: false + initiatorType: false + isNotificationsFailureEnabled: false + isNotificationsSuccessEnabled: false + mpesaTransactionId: false + mpesaTransactionStatusRetryCount: false + originDate: false + partyLookupFailed: false + phoneNumber: true + processDefinitionKey: false + processInstanceKey: true + scenario: false + tenantId: false + timer: false + timestamp: true + transactionFailed: false + transactionId: false + transferCreateFailed: false + transferSettlementFailed: false + transferResponseCREATE: false + limits: + cpu: "500m" + memory: "512M" + requests: + cpu: "100m" + memory: "256M" + + importer_rdbms: + enabled: true + image: "419830066942.dkr.ecr.ap-south-1.amazonaws.com/phee-importer-rdbms" + imageTag: latest + LOGGING_LEVEL_ROOT: "DEBUG" + limits: + cpu: "500m" + memory: "512M" + requests: + cpu: "100m" + memory: "256M" + datasource: + username: "mifos" + password: "password" + host: "operationsmysql" + port: 3306 + schema: "tenants" + + wildcardhostname: "*.sandbox.fynarfin.io" + + tls: "" diff --git a/ph-ee-env-labs/jenkinfile b/ph-ee-env-labs/jenkinfile new file mode 100644 index 000000000..bfa1bc222 --- /dev/null +++ b/ph-ee-env-labs/jenkinfile @@ -0,0 +1,60 @@ +pipeline { + + environment { + IBM_CRED = credentials('IBM_CRED') + } + + agent any + + stages { + stage('Cloning from Git') { + steps { + git url: 'https://github.com/fynarfin/ph-ee-env-labs.git/', branch: 'master' + } + } + stage('IBM ENV SETUP') { + steps { + sh 'ibmcloud login -u ${IBM_CRED_USR} -p ${IBM_CRED_PSW} -r us-east -g Default' + sh 'ibmcloud ks cluster config --cluster bstcsf4w0hhnpvg8kk5g' + sh 'kubectl config use-context mycluster-us-east-3-bx2.8x32/bstcsf4w0hhnpvg8kk5g' + sh 'kubectl config get-contexts' + } + } + stage('Deploy Helm Chart') { + steps { + sh 'rm -f helm/superset/Chart.lock helm/superset/requirements.lock helm/superset/charts/*' + sh 'helm dep up helm/superset' + sh 'echo $HOME' + sh 'helm upgrade -f helm/superset/values.yaml ph-ee-barebone helm/superset --install' + } + } + stage('WAITING FOR PODS') { + steps { + echo "I am going to sleep for 2 minutes" + sleep(time:120,unit:"SECONDS") + } + } + stage('DEPLOYING BPMNS') { + steps { + sh """#!/bin/bash + if [ "${BPMN}" = "Disable" ]; then + echo "Skipping bpmn deployment" + exit 0 + fi + HOST=http://localhost:3306/zeebe/upload + deploy(){ + cmd="curl --location --request POST \$HOST \ + --header 'Platform-TenantId: ibank-india' \ + --form 'file=@"\$PWD/\$1"'" + eval \$cmd + } + + LOC=orchestration/feel/*.bpmn + for f in \$LOC; do + deploy \$f + done + """ + } + } + } +} \ No newline at end of file diff --git a/ph-ee-env-labs/jmeter/phee.jmx b/ph-ee-env-labs/jmeter/phee.jmx new file mode 100644 index 000000000..2d1508dbf --- /dev/null +++ b/ph-ee-env-labs/jmeter/phee.jmx @@ -0,0 +1,254 @@ + + + + + + false + true + false + + + + + + + + + + + large-connector-channel.mifos.io + + + + + 6 + + + + + + + + Content-Type + application/json + + + Platform-TenantId + tn01 + + + + + + 2 + + 1 + count + + false + + + + + continue + 10 + 0 + + 50 + + + + S + + + + true + + + + false + { + "payer": { + "partyIdInfo": { + "partyIdType": "MSISDN", + "partyIdentifier": "27710101999" + } + }, + "payee": { + "partyIdInfo": { + "partyIdType": "MSISDN", + "partyIdentifier": "27710305999" + } + }, + "amount": { + "amount": ${count}, + "currency": "TZS" + } +} + = + + + + + + + + /channel/transfer + POST + true + false + true + false + + Java + + + + + + + continue + + false + 20 + + 500 + 20 + false + + + true + + + + true + + + + false + { + "payer": { + "partyIdInfo": { + "partyIdType": "MSISDN", + "partyIdentifier": "666627710101999", + "fspId": "in01tn01" + } + }, + "payee": { + "partyIdInfo": { + "partyIdType": "MSISDN", + "partyIdentifier": "27710305999" + } + }, + "amount": { + "amount": ${count}, + "currency": "TZS" + }, + "transactionType": { + "scenario": "WITHDRAWAL", + "initiator": "PAYER", + "initiatorType": "CONSUMER" + } +} + = + + + + localhost + 5000 + + + /channel/transfer + POST + true + false + true + false + + + + + + + 1000 + 500.0 + + + + + false + + saveConfig + + + true + true + true + + true + true + true + true + false + true + true + false + false + false + true + false + false + false + true + 0 + true + true + true + true + true + true + + + + + + + false + + saveConfig + + + true + true + true + + true + true + true + true + false + true + true + false + false + false + true + false + false + false + true + 0 + true + true + true + true + true + true + + + + + + + + diff --git a/ph-ee-env-labs/orchestration/bpmn/Mock Payment Fund Transfer-DFSPID.png b/ph-ee-env-labs/orchestration/bpmn/Mock Payment Fund Transfer-DFSPID.png new file mode 100644 index 000000000..4e91c7c5b Binary files /dev/null and b/ph-ee-env-labs/orchestration/bpmn/Mock Payment Fund Transfer-DFSPID.png differ diff --git a/ph-ee-env-labs/orchestration/bpmn/PayeePartyLookup-DFSPID.png b/ph-ee-env-labs/orchestration/bpmn/PayeePartyLookup-DFSPID.png new file mode 100644 index 000000000..be312fca3 Binary files /dev/null and b/ph-ee-env-labs/orchestration/bpmn/PayeePartyLookup-DFSPID.png differ diff --git a/ph-ee-env-labs/orchestration/bpmn/PayeeQuoteTransfer-DFSPID.png b/ph-ee-env-labs/orchestration/bpmn/PayeeQuoteTransfer-DFSPID.png new file mode 100644 index 000000000..bebcfd0eb Binary files /dev/null and b/ph-ee-env-labs/orchestration/bpmn/PayeeQuoteTransfer-DFSPID.png differ diff --git a/ph-ee-env-labs/orchestration/bpmn/PayerFundTransfer-DFSPID.png b/ph-ee-env-labs/orchestration/bpmn/PayerFundTransfer-DFSPID.png new file mode 100644 index 000000000..722b27447 Binary files /dev/null and b/ph-ee-env-labs/orchestration/bpmn/PayerFundTransfer-DFSPID.png differ diff --git a/ph-ee-env-labs/orchestration/bpmn/bill-inquiry-DFSPID.png b/ph-ee-env-labs/orchestration/bpmn/bill-inquiry-DFSPID.png new file mode 100644 index 000000000..91aa8095d Binary files /dev/null and b/ph-ee-env-labs/orchestration/bpmn/bill-inquiry-DFSPID.png differ diff --git a/ph-ee-env-labs/orchestration/bpmn/bill_request-DFSPID.png b/ph-ee-env-labs/orchestration/bpmn/bill_request-DFSPID.png new file mode 100644 index 000000000..0281feb90 Binary files /dev/null and b/ph-ee-env-labs/orchestration/bpmn/bill_request-DFSPID.png differ diff --git a/ph-ee-env-labs/orchestration/bpmn/bulk_connector_closedloop-DFSPID.png b/ph-ee-env-labs/orchestration/bpmn/bulk_connector_closedloop-DFSPID.png new file mode 100644 index 000000000..583aa8cb2 Binary files /dev/null and b/ph-ee-env-labs/orchestration/bpmn/bulk_connector_closedloop-DFSPID.png differ diff --git a/ph-ee-env-labs/orchestration/bpmn/bulk_processor-DFSPID.png b/ph-ee-env-labs/orchestration/bpmn/bulk_processor-DFSPID.png new file mode 100644 index 000000000..885a964a2 Binary files /dev/null and b/ph-ee-env-labs/orchestration/bpmn/bulk_processor-DFSPID.png differ diff --git a/ph-ee-env-labs/orchestration/bpmn/bulk_processor.png b/ph-ee-env-labs/orchestration/bpmn/bulk_processor.png new file mode 100644 index 000000000..00214b43e Binary files /dev/null and b/ph-ee-env-labs/orchestration/bpmn/bulk_processor.png differ diff --git a/ph-ee-env-labs/orchestration/bpmn/bulk_processor_account_lookup-DFSPID.png b/ph-ee-env-labs/orchestration/bpmn/bulk_processor_account_lookup-DFSPID.png new file mode 100644 index 000000000..c917ea010 Binary files /dev/null and b/ph-ee-env-labs/orchestration/bpmn/bulk_processor_account_lookup-DFSPID.png differ diff --git a/ph-ee-env-labs/orchestration/bpmn/debit-party-process-DFSPID.png b/ph-ee-env-labs/orchestration/bpmn/debit-party-process-DFSPID.png new file mode 100644 index 000000000..2056304d0 Binary files /dev/null and b/ph-ee-env-labs/orchestration/bpmn/debit-party-process-DFSPID.png differ diff --git a/ph-ee-env-labs/orchestration/bpmn/gsma-bill-payment.png b/ph-ee-env-labs/orchestration/bpmn/gsma-bill-payment.png new file mode 100644 index 000000000..58dd8eaed Binary files /dev/null and b/ph-ee-env-labs/orchestration/bpmn/gsma-bill-payment.png differ diff --git a/ph-ee-env-labs/orchestration/bpmn/gsma-inttransfer-payer.png b/ph-ee-env-labs/orchestration/bpmn/gsma-inttransfer-payer.png new file mode 100644 index 000000000..60a03c77b Binary files /dev/null and b/ph-ee-env-labs/orchestration/bpmn/gsma-inttransfer-payer.png differ diff --git a/ph-ee-env-labs/orchestration/bpmn/gsma-link-based-transfer.png b/ph-ee-env-labs/orchestration/bpmn/gsma-link-based-transfer.png new file mode 100644 index 000000000..10e221c2b Binary files /dev/null and b/ph-ee-env-labs/orchestration/bpmn/gsma-link-based-transfer.png differ diff --git a/ph-ee-env-labs/orchestration/bpmn/gsma-p2p-account-lookup.png b/ph-ee-env-labs/orchestration/bpmn/gsma-p2p-account-lookup.png new file mode 100644 index 000000000..df65ee65a Binary files /dev/null and b/ph-ee-env-labs/orchestration/bpmn/gsma-p2p-account-lookup.png differ diff --git a/ph-ee-env-labs/orchestration/bpmn/gsma-p2p-wo-local-quote.png b/ph-ee-env-labs/orchestration/bpmn/gsma-p2p-wo-local-quote.png new file mode 100644 index 000000000..197568517 Binary files /dev/null and b/ph-ee-env-labs/orchestration/bpmn/gsma-p2p-wo-local-quote.png differ diff --git a/ph-ee-env-labs/orchestration/bpmn/gsma-p2p.png b/ph-ee-env-labs/orchestration/bpmn/gsma-p2p.png new file mode 100644 index 000000000..1485c9eec Binary files /dev/null and b/ph-ee-env-labs/orchestration/bpmn/gsma-p2p.png differ diff --git a/ph-ee-env-labs/orchestration/bpmn/gsma-payee-process.png b/ph-ee-env-labs/orchestration/bpmn/gsma-payee-process.png new file mode 100644 index 000000000..a0c928951 Binary files /dev/null and b/ph-ee-env-labs/orchestration/bpmn/gsma-payee-process.png differ diff --git a/ph-ee-env-labs/orchestration/bpmn/gsma-payee-transfer.png b/ph-ee-env-labs/orchestration/bpmn/gsma-payee-transfer.png new file mode 100644 index 000000000..0923b7f80 Binary files /dev/null and b/ph-ee-env-labs/orchestration/bpmn/gsma-payee-transfer.png differ diff --git a/ph-ee-env-labs/orchestration/bpmn/inbound_transfer-mifos-DFSPID.png b/ph-ee-env-labs/orchestration/bpmn/inbound_transfer-mifos-DFSPID.png new file mode 100644 index 000000000..ae011d87d Binary files /dev/null and b/ph-ee-env-labs/orchestration/bpmn/inbound_transfer-mifos-DFSPID.png differ diff --git a/ph-ee-env-labs/orchestration/bpmn/inbound_transfer_paygops-DFSPID.png b/ph-ee-env-labs/orchestration/bpmn/inbound_transfer_paygops-DFSPID.png new file mode 100644 index 000000000..c5cd896fd Binary files /dev/null and b/ph-ee-env-labs/orchestration/bpmn/inbound_transfer_paygops-DFSPID.png differ diff --git a/ph-ee-env-labs/orchestration/bpmn/inbound_transfer_roster-DFSPID.png b/ph-ee-env-labs/orchestration/bpmn/inbound_transfer_roster-DFSPID.png new file mode 100644 index 000000000..16dae9fba Binary files /dev/null and b/ph-ee-env-labs/orchestration/bpmn/inbound_transfer_roster-DFSPID.png differ diff --git a/ph-ee-env-labs/orchestration/bpmn/international-remittance-payee-process-DFSPID.png b/ph-ee-env-labs/orchestration/bpmn/international-remittance-payee-process-DFSPID.png new file mode 100644 index 000000000..fcf1d8e19 Binary files /dev/null and b/ph-ee-env-labs/orchestration/bpmn/international-remittance-payee-process-DFSPID.png differ diff --git a/ph-ee-env-labs/orchestration/bpmn/international-remittance-payer-process-DFSPID.png b/ph-ee-env-labs/orchestration/bpmn/international-remittance-payer-process-DFSPID.png new file mode 100644 index 000000000..4140e32ac Binary files /dev/null and b/ph-ee-env-labs/orchestration/bpmn/international-remittance-payer-process-DFSPID.png differ diff --git a/ph-ee-env-labs/orchestration/bpmn/minimal_mock_fund_transfer-DFSPID.png b/ph-ee-env-labs/orchestration/bpmn/minimal_mock_fund_transfer-DFSPID.png new file mode 100644 index 000000000..772b0e3e0 Binary files /dev/null and b/ph-ee-env-labs/orchestration/bpmn/minimal_mock_fund_transfer-DFSPID.png differ diff --git a/ph-ee-env-labs/orchestration/bpmn/minimal_mock_fund_transfer_account_lookup-DFSPID.png b/ph-ee-env-labs/orchestration/bpmn/minimal_mock_fund_transfer_account_lookup-DFSPID.png new file mode 100644 index 000000000..00da79703 Binary files /dev/null and b/ph-ee-env-labs/orchestration/bpmn/minimal_mock_fund_transfer_account_lookup-DFSPID.png differ diff --git a/ph-ee-env-labs/orchestration/bpmn/minimal_mock_transfer_request-DFSPID.png b/ph-ee-env-labs/orchestration/bpmn/minimal_mock_transfer_request-DFSPID.png new file mode 100644 index 000000000..be7f06915 Binary files /dev/null and b/ph-ee-env-labs/orchestration/bpmn/minimal_mock_transfer_request-DFSPID.png differ diff --git a/ph-ee-env-labs/orchestration/bpmn/mock-payer-fund-transfer-DFSPID.png b/ph-ee-env-labs/orchestration/bpmn/mock-payer-fund-transfer-DFSPID.png new file mode 100644 index 000000000..9be69d1a8 Binary files /dev/null and b/ph-ee-env-labs/orchestration/bpmn/mock-payer-fund-transfer-DFSPID.png differ diff --git a/ph-ee-env-labs/orchestration/bpmn/mock-payer-fund-transfer_account_lookup-DFSPID.png b/ph-ee-env-labs/orchestration/bpmn/mock-payer-fund-transfer_account_lookup-DFSPID.png new file mode 100644 index 000000000..a1fbfde67 Binary files /dev/null and b/ph-ee-env-labs/orchestration/bpmn/mock-payer-fund-transfer_account_lookup-DFSPID.png differ diff --git a/ph-ee-env-labs/orchestration/bpmn/mock_payment_transfer_account_lookup-DFSPID.png b/ph-ee-env-labs/orchestration/bpmn/mock_payment_transfer_account_lookup-DFSPID.png new file mode 100644 index 000000000..82ba41ca8 Binary files /dev/null and b/ph-ee-env-labs/orchestration/bpmn/mock_payment_transfer_account_lookup-DFSPID.png differ diff --git a/ph-ee-env-labs/orchestration/bpmn/mock_payment_transfer_debit-DFSPID.png b/ph-ee-env-labs/orchestration/bpmn/mock_payment_transfer_debit-DFSPID.png new file mode 100644 index 000000000..ad23d48b2 Binary files /dev/null and b/ph-ee-env-labs/orchestration/bpmn/mock_payment_transfer_debit-DFSPID.png differ diff --git a/ph-ee-env-labs/orchestration/bpmn/mojaloop-account-validation.png b/ph-ee-env-labs/orchestration/bpmn/mojaloop-account-validation.png new file mode 100644 index 000000000..35b822806 Binary files /dev/null and b/ph-ee-env-labs/orchestration/bpmn/mojaloop-account-validation.png differ diff --git a/ph-ee-env-labs/orchestration/bpmn/mpesa-flow_roster-oaf.png b/ph-ee-env-labs/orchestration/bpmn/mpesa-flow_roster-oaf.png new file mode 100644 index 000000000..965fe36a9 Binary files /dev/null and b/ph-ee-env-labs/orchestration/bpmn/mpesa-flow_roster-oaf.png differ diff --git a/ph-ee-env-labs/orchestration/bpmn/mpesa_flow_paygops-oaf.png b/ph-ee-env-labs/orchestration/bpmn/mpesa_flow_paygops-oaf.png new file mode 100644 index 000000000..bb5445966 Binary files /dev/null and b/ph-ee-env-labs/orchestration/bpmn/mpesa_flow_paygops-oaf.png differ diff --git a/ph-ee-env-labs/orchestration/bpmn/outbound_refund.png b/ph-ee-env-labs/orchestration/bpmn/outbound_refund.png new file mode 100644 index 000000000..37ba5349d Binary files /dev/null and b/ph-ee-env-labs/orchestration/bpmn/outbound_refund.png differ diff --git a/ph-ee-env-labs/orchestration/bpmn/outbound_txn.png b/ph-ee-env-labs/orchestration/bpmn/outbound_txn.png new file mode 100644 index 000000000..622443e6c Binary files /dev/null and b/ph-ee-env-labs/orchestration/bpmn/outbound_txn.png differ diff --git a/ph-ee-env-labs/orchestration/bpmn/party-registration-DFSPID.png b/ph-ee-env-labs/orchestration/bpmn/party-registration-DFSPID.png new file mode 100644 index 000000000..739bb78b9 Binary files /dev/null and b/ph-ee-env-labs/orchestration/bpmn/party-registration-DFSPID.png differ diff --git a/ph-ee-env-labs/orchestration/bpmn/payee-transaction-request-DFSPID.png b/ph-ee-env-labs/orchestration/bpmn/payee-transaction-request-DFSPID.png new file mode 100644 index 000000000..d704f531e Binary files /dev/null and b/ph-ee-env-labs/orchestration/bpmn/payee-transaction-request-DFSPID.png differ diff --git a/ph-ee-env-labs/orchestration/bpmn/payer-fund-transfer-DFSPID.png b/ph-ee-env-labs/orchestration/bpmn/payer-fund-transfer-DFSPID.png new file mode 100644 index 000000000..dbc5f9a52 Binary files /dev/null and b/ph-ee-env-labs/orchestration/bpmn/payer-fund-transfer-DFSPID.png differ diff --git a/ph-ee-env-labs/orchestration/bpmn/payer-fund-transfer-terminate-DFSPID.png b/ph-ee-env-labs/orchestration/bpmn/payer-fund-transfer-terminate-DFSPID.png new file mode 100644 index 000000000..5b6d7aa79 Binary files /dev/null and b/ph-ee-env-labs/orchestration/bpmn/payer-fund-transfer-terminate-DFSPID.png differ diff --git a/ph-ee-env-labs/orchestration/bpmn/payer-transaction-request-DFSPID.png b/ph-ee-env-labs/orchestration/bpmn/payer-transaction-request-DFSPID.png new file mode 100644 index 000000000..eefcbca9d Binary files /dev/null and b/ph-ee-env-labs/orchestration/bpmn/payer-transaction-request-DFSPID.png differ diff --git a/ph-ee-env-labs/orchestration/bpmn/payment-notification-DFSPID.png b/ph-ee-env-labs/orchestration/bpmn/payment-notification-DFSPID.png new file mode 100644 index 000000000..cf5e538de Binary files /dev/null and b/ph-ee-env-labs/orchestration/bpmn/payment-notification-DFSPID.png differ diff --git a/ph-ee-env-labs/orchestration/bpmn/perftest.png b/ph-ee-env-labs/orchestration/bpmn/perftest.png new file mode 100644 index 000000000..6a640f1a7 Binary files /dev/null and b/ph-ee-env-labs/orchestration/bpmn/perftest.png differ diff --git a/ph-ee-env-labs/orchestration/bpmn/perftest2.png b/ph-ee-env-labs/orchestration/bpmn/perftest2.png new file mode 100644 index 000000000..c42997496 Binary files /dev/null and b/ph-ee-env-labs/orchestration/bpmn/perftest2.png differ diff --git a/ph-ee-env-labs/orchestration/bpmn/redeem_and_pay_voucher.png b/ph-ee-env-labs/orchestration/bpmn/redeem_and_pay_voucher.png new file mode 100644 index 000000000..ce6335e93 Binary files /dev/null and b/ph-ee-env-labs/orchestration/bpmn/redeem_and_pay_voucher.png differ diff --git a/ph-ee-env-labs/orchestration/bpmn/slcb-DFSPID.png b/ph-ee-env-labs/orchestration/bpmn/slcb-DFSPID.png new file mode 100644 index 000000000..ca528539e Binary files /dev/null and b/ph-ee-env-labs/orchestration/bpmn/slcb-DFSPID.png differ diff --git a/ph-ee-env-labs/orchestration/bpmn/voucher_budget_check.png b/ph-ee-env-labs/orchestration/bpmn/voucher_budget_check.png new file mode 100644 index 000000000..6214a451d Binary files /dev/null and b/ph-ee-env-labs/orchestration/bpmn/voucher_budget_check.png differ diff --git a/ph-ee-env-labs/orchestration/deployBpmn.sh b/ph-ee-env-labs/orchestration/deployBpmn.sh new file mode 100644 index 000000000..1801cfb63 --- /dev/null +++ b/ph-ee-env-labs/orchestration/deployBpmn.sh @@ -0,0 +1,20 @@ +#!/bin/sh +HOST="https://zeebeops.sandbox.fynarfin.io/zeebe/upload" +deploy(){ + cmd="curl --insecure --location --request POST $HOST \ + --header 'Platform-TenantId: gorilla' \ + --form 'file=@\"$PWD/$1\"'" + echo $cmd + eval $cmd + #If curl response is not 200 it should fail the eval cmd +} + +LOC=orchestration/feel/*.bpmn +for f in $LOC; do + deploy $f +done + +LOC2=orchestration/feel/example/*.bpmn +for f in $LOC2; do + deploy $f +done \ No newline at end of file diff --git a/ph-ee-env-labs/orchestration/feel/Archive/debit-party-process-DFSPID.bpmn b/ph-ee-env-labs/orchestration/feel/Archive/debit-party-process-DFSPID.bpmn new file mode 100644 index 000000000..96833b80b --- /dev/null +++ b/ph-ee-env-labs/orchestration/feel/Archive/debit-party-process-DFSPID.bpmn @@ -0,0 +1,319 @@ + + + + + Flow_1iz4su9 + + + Flow_1khpy8b + + + + + + + Flow_0drcaub + Flow_0r7t1vh + Flow_0fq2w8b + + + Flow_0fq2w8b + Flow_0z3yk8q + + + Flow_16b1s15 + + PT60S + + + + Flow_16b1s15 + Flow_0drcaub + Flow_177y51s + + + =payeeAccountStatusRetry < 3 + + + + Flow_0z3yk8q + Flow_1rd2qbu + Flow_06fadz1 + + + + + + + + Flow_1g9y30t + Flow_1khpy8b + + + Flow_1rbhwaj + + + =partyLookupFailed = true + + + Flow_1rd8f1u + + + + + + + + + Flow_177y51s + Flow_1rd8f1u + + + + + + + Flow_1rd2qbu + Flow_0vpl387 + Flow_1rbhwaj + + + + + + Flow_06fadz1 + Flow_1ojxhgg + + + Flow_1ojxhgg + Flow_0vpl387 + Flow_053zh7e + + + + + + + Flow_053zh7e + Flow_11ks5lq + + + Flow_11ks5lq + Flow_0ygr2i6 + Flow_1g9y30t + + + + =transferPrepareFailed = true + + + =transferCreateFailed = true + + + + + + + Flow_0ygr2i6 + Flow_02nd84o + + + Flow_02nd84o + + + + + + + Flow_1iz4su9 + Flow_0r7t1vh + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ph-ee-env-labs/orchestration/feel/Archive/gsma-bill-payment.bpmn b/ph-ee-env-labs/orchestration/feel/Archive/gsma-bill-payment.bpmn new file mode 100644 index 000000000..82d5b387d --- /dev/null +++ b/ph-ee-env-labs/orchestration/feel/Archive/gsma-bill-payment.bpmn @@ -0,0 +1,409 @@ + + + + + Flow_0tk2ifu + + + Flow_1xmvmed + + + + + + Flow_1eb232y + Flow_09uoau8 + + + Flow_09uoau8 + Flow_17xcyxt + Flow_0xr934y + + + Flow_1bqhdy1 + Flow_10lx4kv + Flow_0d9tmm4 + + + + + + Flow_10rvrb2 + Flow_1bqhdy1 + + + Flow_0d9tmm4 + Flow_11r1axh + Flow_1i00n59 + + + + + + Flow_160tmjo + Flow_1xmvmed + + + Flow_1mdj95p + Flow_1bqfmi7 + Flow_1rjo4c4 + + + Flow_0zhx7zw + + + Flow_1etcf1u + + + + + + Flow_1rjo4c4 + Flow_1etcf1u + + + + + + Flow_17xcyxt + Flow_0uh3hk9 + Flow_0d2lx0j + Flow_0zhx7zw + + + + + + Flow_0xr934y + Flow_16ajdal + + + Flow_16ajdal + Flow_10rvrb2 + Flow_0uh3hk9 + + + + + + Flow_11r1axh + Flow_1rp6lna + + + Flow_1rp6lna + Flow_160tmjo + Flow_0e0628v + + + + + + Flow_1i00n59 + Flow_10c5opy + + + + + + Flow_0e0628v + Flow_05ijvs7 + Flow_0zkx4io + + + Flow_0zkx4io + + + Flow_10c5opy + Flow_0d2lx0j + Flow_05ijvs7 + + + + + + Flow_0tk2ifu + Flow_1eb232y + + + Flow_1mdj95p + + PT60S + + + + + + + + =billStatusError = true + + + + + + =paymentTransferRetry < 3 + + + + + =transactionFailed = true + + + + + + + + =transferPrepareFailed = true + + + + + + =transferCreateFailed = true + + + + =transferReleaseFailed = true + + + + + + + Flow_1bqfmi7 + Flow_10lx4kv + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ph-ee-env-labs/orchestration/feel/Archive/gsma-inttransfer-payer.bpmn b/ph-ee-env-labs/orchestration/feel/Archive/gsma-inttransfer-payer.bpmn new file mode 100644 index 000000000..2a33b35ce --- /dev/null +++ b/ph-ee-env-labs/orchestration/feel/Archive/gsma-inttransfer-payer.bpmn @@ -0,0 +1,592 @@ + + + + + Flow_0hymeub + + + Flow_14zk5zf + + + + + + Flow_1lnunl7 + Flow_08ry6kb + Flow_1l37gfy + + + Flow_1l37gfy + Flow_0tpdj7v + + + Flow_0eo8qz6 + Flow_1lnunl7 + Flow_0zw1ae7 + + + Flow_0tpdj7v + Flow_0mkf71e + Flow_1ugc26m + + + Flow_1mmeifz + Flow_1xdeqyv + Flow_1nhcqs5 + + + + + + Flow_0spn1nz + Flow_1mmeifz + + + Flow_1nhcqs5 + Flow_1i8dcbu + Flow_16358wv + + + + + + Flow_1hd7asg + Flow_14zk5zf + + + Flow_15t0wnt + Flow_1jj70lx + Flow_0j4cgfu + + + Flow_1bnldtz + + + Flow_1gacwmh + + + + + + Flow_0zw1ae7 + Flow_0j4cgfu + Flow_0vj8tsx + Flow_1gacwmh + + + + + + Flow_0mkf71e + Flow_1qe4zz1 + Flow_0e9435i + Flow_17k1e4j + Flow_1bnldtz + + + + + + Flow_1rg60pi + Flow_0e92dsh + + + Flow_0e92dsh + Flow_0spn1nz + Flow_1qe4zz1 + + + + + + Flow_1i8dcbu + Flow_08moqcp + + + Flow_08moqcp + Flow_1hd7asg + Flow_090t7bu + + + + + + Flow_16358wv + Flow_0uscqbi + + + + + + Flow_090t7bu + Flow_0prbs2c + Flow_0osg66n + + + Flow_0osg66n + + + Flow_0uscqbi + Flow_0e9435i + Flow_0prbs2c + + + + + + Flow_0hymeub + Flow_08ry6kb + + + Flow_0eo8qz6 + + PT60S + + + + Flow_15t0wnt + + PT60S + + + + + + =payeeAccountStatusRetry < 3 + + + + + + + + =partyLookupFailed = true + + + + + + =paymentTransferRetry < 3 + + + + + =transactionFailed = true + + + + + + + + =transferPrepareFailed = true + + + + + + =transferCreateFailed = true + + + + =transferReleaseFailed = true + + + + + + + + Flow_1ugc26m + Flow_1pohph2 + Flow_19zmt8a + + + Flow_19zmt8a + Flow_0okvk4r + + + Flow_06ojh3o + + PT60S + + + + Flow_06ojh3o + Flow_0vj8tsx + Flow_1pohph2 + + + + + =quoteRetryCount < 3 + + + Flow_0okvk4r + Flow_17k1e4j + Flow_1b65dfh + + + =gsmaQuoteFailed = true + + + + + + + + + Flow_1b65dfh + Flow_1rg60pi + + + + + + Flow_1jj70lx + Flow_1xdeqyv + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ph-ee-env-labs/orchestration/feel/Archive/gsma-link-based-transfer.bpmn b/ph-ee-env-labs/orchestration/feel/Archive/gsma-link-based-transfer.bpmn new file mode 100644 index 000000000..22d731582 --- /dev/null +++ b/ph-ee-env-labs/orchestration/feel/Archive/gsma-link-based-transfer.bpmn @@ -0,0 +1,560 @@ + + + + + Flow_1v217se + + + Flow_1051pnn + + + + + + Flow_18gj14i + Flow_0wbgbny + Flow_1yf0wh8 + + + Flow_1yf0wh8 + Flow_0qjn5ay + + + Flow_0p2feb1 + Flow_18gj14i + Flow_01ivm2n + + + Flow_0qjn5ay + Flow_0qfg7ma + Flow_0zr3bxl + + + Flow_1v7vwto + Flow_1282nka + Flow_165lzj4 + + + + + + Flow_1nohbyk + Flow_1v7vwto + + + Flow_165lzj4 + Flow_0scb2p0 + Flow_1ieoorm + + + + + + Flow_0yn2pcx + Flow_1051pnn + + + Flow_1tkyo8r + Flow_0uh8wz8 + Flow_1kacb4n + + + Flow_1tbs7kd + + + Flow_1p3v3zi + + + + + + Flow_01ivm2n + Flow_1kacb4n + Flow_1yy9jqc + Flow_1p3v3zi + + + + + + Flow_0qfg7ma + Flow_18o5655 + Flow_0zk5cvc + Flow_11l9zbd + Flow_1tbs7kd + + + + + + Flow_0hfbu8w + Flow_07bmth7 + + + Flow_07bmth7 + Flow_1nohbyk + Flow_18o5655 + + + + + + Flow_0scb2p0 + Flow_0eziyaa + + + Flow_0eziyaa + Flow_0yn2pcx + Flow_05h76w0 + + + + + + Flow_1ieoorm + Flow_1lf3yyw + + + + + + Flow_05h76w0 + Flow_0baupe0 + Flow_0x9t7lb + + + Flow_0x9t7lb + + + Flow_1lf3yyw + Flow_0zk5cvc + Flow_0baupe0 + + + + + + Flow_1v217se + Flow_0wbgbny + + + Flow_1tkyo8r + + PT60S + + + + + + =payeeAccountStatusRetry < 3 + + + + + + + + =partyLookupFailed = true + + + + + + =paymentTransferRetry < 3 + + + + + =transactionFailed = true + + + + + + + + =transferPrepareFailed = true + + + + + + =transferCreateFailed = true + + + + =transferReleaseFailed = true + + + + + Flow_1ksdq93 + Flow_0hfbu8w + Flow_11l9zbd + + + + + =linkCreationFailed = true + + + Flow_12o082h + Flow_1ksdq93 + + + + + + Flow_0zr3bxl + Flow_1qz445y + Flow_12o082h + + + Flow_1y4b8dl + + PT60S + + + + Flow_0p2feb1 + + PT60S + + + + + Flow_1y4b8dl + Flow_1yy9jqc + Flow_1qz445y + + + + =linkCreationRetryCount < 3 + + + + + + Flow_0uh8wz8 + Flow_1282nka + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ph-ee-env-labs/orchestration/feel/Archive/inbound_transfer_paygops-DFSPID.bpmn b/ph-ee-env-labs/orchestration/feel/Archive/inbound_transfer_paygops-DFSPID.bpmn new file mode 100644 index 000000000..2ddb53146 --- /dev/null +++ b/ph-ee-env-labs/orchestration/feel/Archive/inbound_transfer_paygops-DFSPID.bpmn @@ -0,0 +1,205 @@ + + + + + Flow_0zj5svb + Flow_0z91exw + Flow_0w8uoju + + + Flow_1ecfldo + + + Flow_1w6x088 + Flow_1oum6u4 + + + Flow_16hk9gv + Flow_1w6x088 + Flow_0zj5svb + + + =partyLookupFailed = false + + + Flow_16hk9gv + + + + + + + Flow_17r5yck + Flow_1kw3y0l + + + Flow_1mlv58f + Flow_1oum6u4 + Flow_17r5yck + Flow_0mkgxc2 + + + =confirmationReceived = true + + + Flow_1kw3y0l + Flow_1ecfldo + Flow_0z91exw + + + + =transferSettlementFailed = false + + + + =confirmationReceived = false + + + =partyLookupFailed = true + + + =transferSettlementFailed = true + + + Flow_1mlv58f + + = timer + + + + + + + + + Flow_0mkgxc2 + Flow_0w8uoju + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ph-ee-env-labs/orchestration/feel/Archive/inbound_transfer_roster-DFSPID.bpmn b/ph-ee-env-labs/orchestration/feel/Archive/inbound_transfer_roster-DFSPID.bpmn new file mode 100644 index 000000000..0ac4eb542 --- /dev/null +++ b/ph-ee-env-labs/orchestration/feel/Archive/inbound_transfer_roster-DFSPID.bpmn @@ -0,0 +1,205 @@ + + + + + Flow_0zj5svb + Flow_0z91exw + Flow_0625458 + + + Flow_1ecfldo + + + Flow_1w6x088 + Flow_1oum6u4 + + + Flow_16hk9gv + Flow_1w6x088 + Flow_0zj5svb + + + =partyLookupFailed = false + + + Flow_16hk9gv + + + + + + + Flow_17r5yck + Flow_1kw3y0l + + + Flow_1mlv58f + Flow_1oum6u4 + Flow_17r5yck + Flow_0mkgxc2 + + + =confirmationReceived = true + + + Flow_1kw3y0l + Flow_1ecfldo + Flow_0z91exw + + + + =transferSettlementFailed = false + + + + =confirmationReceived = false + + + =partyLookupFailed = true + + + =transferSettlementFailed = true + + + Flow_1mlv58f + + = timer + + + + + + + + + Flow_0mkgxc2 + Flow_0625458 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ph-ee-env-labs/orchestration/feel/Archive/international-remittance-payer-process-DFSPID.bpmn b/ph-ee-env-labs/orchestration/feel/Archive/international-remittance-payer-process-DFSPID.bpmn new file mode 100644 index 000000000..6282216e1 --- /dev/null +++ b/ph-ee-env-labs/orchestration/feel/Archive/international-remittance-payer-process-DFSPID.bpmn @@ -0,0 +1,467 @@ + + + + + Flow_1iz4su9 + + + Flow_1khpy8b + + + + + + + Flow_0drcaub + Flow_0r7t1vh + Flow_0fq2w8b + + + Flow_0fq2w8b + Flow_0z3yk8q + + + Flow_16b1s15 + + PT60S + + + + Flow_16b1s15 + Flow_0drcaub + Flow_177y51s + + + =payeeAccountStatusRetry < 3 + + + + Flow_0z3yk8q + Flow_1rd2qbu + Flow_06fadz1 + + + + Flow_0vfzj5k + Flow_1oiw1si + Flow_1yuhu0t + + + + + + Flow_0s5yx0e + Flow_0vfzj5k + + + + + + Flow_1yuhu0t + Flow_04sgr67 + Flow_11fn478 + + + + + + + Flow_1g9y30t + Flow_1khpy8b + + + Flow_126dexs + + PT60S + + + + Flow_126dexs + Flow_150jms5 + Flow_1lf6hxg + + + + =paymentTransferRetry < 3 + + + Flow_1rbhwaj + + + =partyLookupFailed = true + + + =transactionFailed = true + + + Flow_1rd8f1u + + + + + + + + + + Flow_177y51s + Flow_1lf6hxg + Flow_1rd8f1u + + + + + + + Flow_1rd2qbu + Flow_0vpl387 + Flow_0o49cl4 + Flow_1rbhwaj + + + + + + Flow_06fadz1 + Flow_1ojxhgg + + + Flow_1ojxhgg + Flow_0vpl387 + Flow_0s5yx0e + + + + + + + Flow_04sgr67 + Flow_11ks5lq + + + Flow_11ks5lq + Flow_0ygr2i6 + Flow_1g9y30t + + + + =transferPrepareFailed = true + + + =transferCreateFailed = true + + + + + + + + Flow_11fn478 + Flow_03o1q44 + + + + + + Flow_1kzho50 + Flow_0ygr2i6 + Flow_02nd84o + + + Flow_02nd84o + + + + Flow_03o1q44 + Flow_1kzho50 + Flow_0o49cl4 + + + + =transferReleaseFailed = true + + + + + + + Flow_1iz4su9 + Flow_0r7t1vh + + + + + + + + Flow_150jms5 + Flow_1oiw1si + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ph-ee-env-labs/orchestration/feel/Archive/mock-payer-fund-transfer-DFSPID.bpmn b/ph-ee-env-labs/orchestration/feel/Archive/mock-payer-fund-transfer-DFSPID.bpmn new file mode 100644 index 000000000..6b70d9628 --- /dev/null +++ b/ph-ee-env-labs/orchestration/feel/Archive/mock-payer-fund-transfer-DFSPID.bpmn @@ -0,0 +1,975 @@ + + + + + SequenceFlow_1pymsem + + + + + SequenceFlow_0h8jckr + SequenceFlow_06tbhc9 + + + SequenceFlow_1ffxwgp + SequenceFlow_0uphhfj + + + + + + SequenceFlow_1pymsem + SequenceFlow_0vrua4x + SequenceFlow_0h8jckr + + + SequenceFlow_12nueew + SequenceFlow_09gkp54 + SequenceFlow_0zniywb + + + + + + SequenceFlow_09gkp54 + SequenceFlow_11uuh51 + SequenceFlow_1eicyj6 + + + =quoteRetryCount < 3 + + + + + + + + SequenceFlow_0zniywb + SequenceFlow_1d2huaz + SequenceFlow_0t11r3b + SequenceFlow_0eh0472 + SequenceFlow_1oanf9v + SequenceFlow_1bb7vzi + + + + + + + SequenceFlow_0ew6rln + SequenceFlow_1ffxwgp + + + SequenceFlow_0uphhfj + SequenceFlow_1oanf9v + SequenceFlow_0jl4afa + + + + SequenceFlow_1bb7vzi + + + SequenceFlow_03gw2ot + SequenceFlow_0fyvo3u + SequenceFlow_0ew6rln + SequenceFlow_1d2huaz + + + + =quoteFailed = true + + + SequenceFlow_06tbhc9 + SequenceFlow_11uuh51 + SequenceFlow_0t11r3b + + + + =partyLookupFailed = true + + + SequenceFlow_0u5ni5c + + PT60S + + + + SequenceFlow_0u5ni5c + SequenceFlow_0vrua4x + SequenceFlow_0eh0472 + + + + =partyLookupRetryCount < 3 + + + + + + =payerConfirmed = true + + + SequenceFlow_1eicyj6 + SequenceFlow_15wc77c + SequenceFlow_0h2j62g + SequenceFlow_087rb2p + + + + + SequenceFlow_15wc77c + SequenceFlow_03gw2ot + + + + + SequenceFlow_0h2j62g + SequenceFlow_0fyvo3u + + + + + + SequenceFlow_087rb2p + SequenceFlow_12nueew + + PT60S + + + + + + SequenceFlow_021l36b + SequenceFlow_0hjdph9 + + + SequenceFlow_0zv37c6 + + + + + + SequenceFlow_0jl4afa + SequenceFlow_0dt42vk + + + + + + SequenceFlow_1a0pfuq + SequenceFlow_1ptml7u + SequenceFlow_021l36b + + + + + + SequenceFlow_1222rpl + SequenceFlow_1k13ccu + SequenceFlow_1emjz5s + + + SequenceFlow_039x2o8 + SequenceFlow_1a0pfuq + SequenceFlow_1u7fhxg + + + SequenceFlow_0hjdph9 + SequenceFlow_11ybwbd + SequenceFlow_1222rpl + SequenceFlow_1ic2uyb + + + + + + SequenceFlow_02o4g3y + SequenceFlow_0zv37c6 + + + + + + SequenceFlow_1f823z7 + SequenceFlow_0r1oaqw + + + + + + SequenceFlow_1u7fhxg + SequenceFlow_1md51ht + + + + + + SequenceFlow_1ic2uyb + SequenceFlow_0wlity5 + SequenceFlow_1gmvm2h + + + SequenceFlow_0jviy8g + SequenceFlow_11ybwbd + SequenceFlow_0udfio5 + + + + + + SequenceFlow_13qetbt + SequenceFlow_0jviy8g + + + SequenceFlow_0dt42vk + SequenceFlow_1ptml7u + SequenceFlow_1f823z7 + + + SequenceFlow_1emjz5s + SequenceFlow_02o4g3y + SequenceFlow_0t11txa + + + + + + SequenceFlow_1md51ht + SequenceFlow_13qetbt + + + SequenceFlow_0ntctr3 + + + SequenceFlow_0r1oaqw + + + SequenceFlow_1gmvm2h + SequenceFlow_17okil0 + SequenceFlow_0jgx2x0 + + + SequenceFlow_0ogstcm + + + + + + SequenceFlow_0t11txa + SequenceFlow_1g74z3o + + + + + + SequenceFlow_0jgx2x0 + SequenceFlow_1tq3ry1 + + + + + + SequenceFlow_1g74z3o + SequenceFlow_0xh7fo1 + + + + + + SequenceFlow_1tq3ry1 + SequenceFlow_1k0in2i + + + SequenceFlow_1k0in2i + SequenceFlow_0wlity5 + SequenceFlow_0ntctr3 + + + + + + SequenceFlow_17okil0 + SequenceFlow_0ogstcm + + + SequenceFlow_0xh7fo1 + SequenceFlow_1k13ccu + SequenceFlow_14hz2nf + + + SequenceFlow_14hz2nf + + + SequenceFlow_0udfio5 + + + SequenceFlow_039x2o8 + + PT60S + + + + + + + + =transferRetryCount < 3 + + + + + + + + + + =transferFailed = true or transferState != "COMMITTED" + + + + =transferPrepareFailed = true + + + + + + + + =operatorManualOverride = true + + + + =transferCreateFailed = true + + + =operatorManualOverride = true + + + + =transferReleaseFailed = true + + + + + + + + =operatorManualOverride = true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ph-ee-env-labs/orchestration/feel/Archive/mock-payer-fund-transfer_account_lookup-DFSPID.bpmn b/ph-ee-env-labs/orchestration/feel/Archive/mock-payer-fund-transfer_account_lookup-DFSPID.bpmn new file mode 100644 index 000000000..c10ee7850 --- /dev/null +++ b/ph-ee-env-labs/orchestration/feel/Archive/mock-payer-fund-transfer_account_lookup-DFSPID.bpmn @@ -0,0 +1,977 @@ + + + + + SequenceFlow_1pymsem + + + + + SequenceFlow_0h8jckr + SequenceFlow_06tbhc9 + + + SequenceFlow_1ffxwgp + SequenceFlow_0uphhfj + + + + + + SequenceFlow_1pymsem + SequenceFlow_0vrua4x + SequenceFlow_0h8jckr + + + SequenceFlow_12nueew + SequenceFlow_09gkp54 + SequenceFlow_0zniywb + + + + + + SequenceFlow_09gkp54 + SequenceFlow_11uuh51 + SequenceFlow_1eicyj6 + + + =quoteRetryCount < 3 + + + + + + + + SequenceFlow_0zniywb + SequenceFlow_1d2huaz + SequenceFlow_0t11r3b + SequenceFlow_0eh0472 + SequenceFlow_1oanf9v + SequenceFlow_1bb7vzi + + + + + + + SequenceFlow_0ew6rln + SequenceFlow_1ffxwgp + + + SequenceFlow_0uphhfj + SequenceFlow_1oanf9v + SequenceFlow_0jl4afa + + + + SequenceFlow_1bb7vzi + + + SequenceFlow_03gw2ot + SequenceFlow_0fyvo3u + SequenceFlow_0ew6rln + SequenceFlow_1d2huaz + + + + =quoteFailed = true + + + SequenceFlow_06tbhc9 + SequenceFlow_11uuh51 + SequenceFlow_0t11r3b + + + + =partyLookupFailed = true + + + SequenceFlow_0u5ni5c + + PT60S + + + + SequenceFlow_0u5ni5c + SequenceFlow_0vrua4x + SequenceFlow_0eh0472 + + + + =partyLookupRetryCount < 3 + + + + + + =payerConfirmed = true + + + SequenceFlow_1eicyj6 + SequenceFlow_15wc77c + SequenceFlow_0h2j62g + SequenceFlow_087rb2p + + + + + SequenceFlow_15wc77c + SequenceFlow_03gw2ot + + + + + SequenceFlow_0h2j62g + SequenceFlow_0fyvo3u + + + + + + SequenceFlow_087rb2p + SequenceFlow_12nueew + + PT60S + + + + + + SequenceFlow_021l36b + SequenceFlow_0hjdph9 + + + SequenceFlow_0zv37c6 + + + + + + SequenceFlow_0jl4afa + SequenceFlow_0dt42vk + + + + + + SequenceFlow_1a0pfuq + SequenceFlow_1ptml7u + SequenceFlow_021l36b + + + + + + SequenceFlow_1222rpl + SequenceFlow_1k13ccu + SequenceFlow_1emjz5s + + + SequenceFlow_039x2o8 + SequenceFlow_1a0pfuq + SequenceFlow_1u7fhxg + + + SequenceFlow_0hjdph9 + SequenceFlow_11ybwbd + SequenceFlow_1222rpl + SequenceFlow_1ic2uyb + + + + + + SequenceFlow_02o4g3y + SequenceFlow_0zv37c6 + + + + + + SequenceFlow_1f823z7 + SequenceFlow_0r1oaqw + + + + + + SequenceFlow_1u7fhxg + SequenceFlow_1md51ht + + + + + + SequenceFlow_1ic2uyb + SequenceFlow_0wlity5 + SequenceFlow_1gmvm2h + + + SequenceFlow_0jviy8g + SequenceFlow_11ybwbd + SequenceFlow_0udfio5 + + + + + + SequenceFlow_13qetbt + SequenceFlow_0jviy8g + + + SequenceFlow_0dt42vk + SequenceFlow_1ptml7u + SequenceFlow_1f823z7 + + + SequenceFlow_1emjz5s + SequenceFlow_02o4g3y + SequenceFlow_0t11txa + + + + + + SequenceFlow_1md51ht + SequenceFlow_13qetbt + + + SequenceFlow_0ntctr3 + + + SequenceFlow_0r1oaqw + + + SequenceFlow_1gmvm2h + SequenceFlow_17okil0 + SequenceFlow_0jgx2x0 + + + SequenceFlow_0ogstcm + + + + + + SequenceFlow_0t11txa + SequenceFlow_1g74z3o + + + + + + SequenceFlow_0jgx2x0 + SequenceFlow_1tq3ry1 + + + + + + SequenceFlow_1g74z3o + SequenceFlow_0xh7fo1 + + + + + + SequenceFlow_1tq3ry1 + SequenceFlow_1k0in2i + + + SequenceFlow_1k0in2i + SequenceFlow_0wlity5 + SequenceFlow_0ntctr3 + + + + + + SequenceFlow_17okil0 + SequenceFlow_0ogstcm + + + SequenceFlow_0xh7fo1 + SequenceFlow_1k13ccu + SequenceFlow_14hz2nf + + + SequenceFlow_14hz2nf + + + SequenceFlow_0udfio5 + + + SequenceFlow_039x2o8 + + PT60S + + + + + + + + =transferRetryCount < 3 + + + + + + + + + + =transferFailed = true or transferState != "COMMITTED" + + + + =transferPrepareFailed = true + + + + + + + + =operatorManualOverride = true + + + + =transferCreateFailed = true + + + =operatorManualOverride = true + + + + =transferReleaseFailed = true + + + + + + + + =operatorManualOverride = true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ph-ee-env-labs/orchestration/feel/Archive/mpesa-flow_roster-oaf.bpmn b/ph-ee-env-labs/orchestration/feel/Archive/mpesa-flow_roster-oaf.bpmn new file mode 100644 index 000000000..dbfcac099 --- /dev/null +++ b/ph-ee-env-labs/orchestration/feel/Archive/mpesa-flow_roster-oaf.bpmn @@ -0,0 +1,420 @@ + + + + + Flow_0pzfqw0 + + + + + + Flow_0pzfqw0 + Flow_1bgw31z + + + + + + + Flow_0o6a4em + Flow_1pz4ziy + + + Flow_1bgw31z + Flow_0o6a4em + Flow_0p3uki2 + + + + + Flow_0p6zk5f + Flow_1iasrai + Flow_0k1p4li + + + + Flow_0gupfxr + Flow_03q232e + Flow_0p6zk5f + + + + + + Flow_0wms0vt + Flow_0gupfxr + + + + + + + + Flow_1urs4q3 + Flow_0bd5ax9 + + + + + + Flow_1iasrai + Flow_1e07bww + + + + + + Flow_1f9c8i5 + Flow_03ncatg + + + Flow_1j9hjuz + + + Flow_0jqg26i + + + + + + Flow_0bd5ax9 + Flow_03ncatg + Flow_1xxzwtm + + + + + + Flow_1pj1te5 + Flow_18aq99i + + + Flow_1xxzwtm + Flow_18aq99i + Flow_0j6zo4i + + + Flow_0j6zo4i + Flow_1j9hjuz + Flow_0jqg26i + + + + =isMessageDelivered = true + + + + + + + + Flow_0wms0vt + + = timer + + + + + Flow_1pj1te5 + + = timer + + + + Flow_1pz4ziy + Flow_03q232e + Flow_0v0sejv + + + + + + Flow_1e07bww + Flow_1ysutq4 + Flow_1urs4q3 + Flow_1c4vglu + + + + Flow_1ysutq4 + + + =isNotificationsSuccessEnabled = false + + + =isNotificationsSuccessEnabled = true + + + =transferSettlementFailed = true + + + =partyLookupFailed = true + + + =transactionFailed = true + + + =transactionFailed = true + + + Flow_1c4vglu + Flow_0k1p4li + Flow_0v0sejv + Flow_0p3uki2 + Flow_1f9c8i5 + Flow_136eckn + + + =isNotificationsFailureEnabled = true + + + Flow_136eckn + + + =isNotificationsFailureEnabled = false + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ph-ee-env-labs/orchestration/feel/Archive/mpesa_flow_paygops-oaf.bpmn b/ph-ee-env-labs/orchestration/feel/Archive/mpesa_flow_paygops-oaf.bpmn new file mode 100644 index 000000000..373687870 --- /dev/null +++ b/ph-ee-env-labs/orchestration/feel/Archive/mpesa_flow_paygops-oaf.bpmn @@ -0,0 +1,420 @@ + + + + + Flow_0pzfqw0 + + + + + + Flow_0pzfqw0 + Flow_1bgw31z + + + + + + + Flow_0o6a4em + Flow_1pz4ziy + + + Flow_1bgw31z + Flow_0o6a4em + Flow_0p3uki2 + + + + + Flow_0p6zk5f + Flow_1iasrai + Flow_0k1p4li + + + + Flow_0gupfxr + Flow_03q232e + Flow_0p6zk5f + + + + + + Flow_0wms0vt + Flow_0gupfxr + + + + + + + + Flow_1urs4q3 + Flow_0bd5ax9 + + + + + + Flow_1iasrai + Flow_1e07bww + + + + + + Flow_1f9c8i5 + Flow_03ncatg + + + Flow_1j9hjuz + + + Flow_0jqg26i + + + + + + Flow_0bd5ax9 + Flow_03ncatg + Flow_1xxzwtm + + + + + + Flow_1pj1te5 + Flow_18aq99i + + + Flow_1xxzwtm + Flow_18aq99i + Flow_0j6zo4i + + + Flow_0j6zo4i + Flow_1j9hjuz + Flow_0jqg26i + + + + =isMessageDelivered = true + + + + + + + + Flow_0wms0vt + + = timer + + + + + Flow_1pj1te5 + + = timer + + + + Flow_1pz4ziy + Flow_03q232e + Flow_0v0sejv + + + + + + Flow_1e07bww + Flow_1ysutq4 + Flow_1urs4q3 + Flow_1c4vglu + + + + Flow_1ysutq4 + + + =isNotificationsSuccessEnabled = false + + + =isNotificationsSuccessEnabled = true + + + =transferSettlementFailed = true + + + =partyLookupFailed = true + + + =transactionFailed = true + + + =transactionFailed = true + + + Flow_1c4vglu + Flow_0k1p4li + Flow_0v0sejv + Flow_0p3uki2 + Flow_1f9c8i5 + Flow_136eckn + + + =isNotificationsFailureEnabled = true + + + Flow_136eckn + + + =isNotificationsFailureEnabled = false + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ph-ee-env-labs/orchestration/feel/Archive/outbound_refund.bpmn b/ph-ee-env-labs/orchestration/feel/Archive/outbound_refund.bpmn new file mode 100644 index 000000000..ec0f79217 --- /dev/null +++ b/ph-ee-env-labs/orchestration/feel/Archive/outbound_refund.bpmn @@ -0,0 +1,172 @@ + + + + + Flow_1qarsr9 + + + + Flow_1qarsr9 + send-otp + Flow_1j53hez + + + refund-initialization-success + Flow_08b89yg + + + Flow_08b89yg + perform-refund + send-otp + + + + perform-refund + Flow_189hh5j + + + =resendOtp=false + + + =resendOtp=true + + + Flow_189hh5j + refund-success + refund-failed + + + + refund-success + + + =isRefundFailed=false + + + refund-failed + + + =isRefundFailed=true + + + Flow_1j53hez + refund-initialization-success + refund-initialization-failed + + + + =isRefundInitializationFailed=false + + + refund-initialization-failed + + + =isRefundInitializationFailed=true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ph-ee-env-labs/orchestration/feel/Archive/outbound_txn.bpmn b/ph-ee-env-labs/orchestration/feel/Archive/outbound_txn.bpmn new file mode 100644 index 000000000..b00db11cc --- /dev/null +++ b/ph-ee-env-labs/orchestration/feel/Archive/outbound_txn.bpmn @@ -0,0 +1,525 @@ + + + + + Flow_0otgls9 + + + + Flow_0xrfa47 + Flow_1x78sqd + Flow_1tf5p4g + + + + Flow_012u03p + Flow_1derzkg + Flow_0vp7ky9 + + + =isRecipientLookupFailed=false + + + =isRecipientLookupFailed=true + + + + Flow_0eea14z + Flow_1tsya4d + Flow_1j8qhtp + + + + Flow_1tsya4d + Flow_1q8tqwk + Flow_1ysolp0 + + + =isTransferFailed=true + + + =retry<3 + + + Flow_1j8qhtp + Flow_025c2x2 + Flow_1s8rxn8 + + + + =isTransferCompleted=false + + + Flow_049hk9s + Flow_0u8sxwg + Flow_1ry3ym8 + + + + Flow_0u8sxwg + Flow_0fh7319 + Flow_0bu7c12 + + + isTransferPending=true + + + =retry<3 + + + + Flow_0dhalz2 + Flow_1s6aksg + Flow_1cpoger + + + + Flow_1s6aksg + + + =isTransactionSuccess=true + + + Flow_1s8rxn8 + + + =isTransferCompleted=true + + + Flow_1cpoger + Flow_0040tlg + Flow_1ysolp0 + Flow_0bu7c12 + Flow_019nssu + + + =isTransactionSuccess=false + + + Flow_17pm8os + Flow_0040tlg + Flow_04mpyqn + + + + =isRecipientAdded=false + + + Flow_0vp7ky9 + Flow_17pm8os + + + Flow_1o874e1 + Flow_1q8tqwk + Flow_0eea14z + + + Flow_025c2x2 + Flow_0fh7319 + Flow_049hk9s + + + Flow_1ry3ym8 + Flow_0dhalz2 + + + Flow_1derzkg + Flow_04mpyqn + Flow_1o874e1 + + + Flow_0otgls9 + Flow_0xrfa47 + + + =retry>=3 + + + =retry>=3 + + + =isSenderLookupFailed=false + + + =isSenderLookupFailed=true + + + + Flow_1tf5p4g + Flow_0krv7di + + + + Flow_1x0e8li + Flow_1w8nvno + Flow_1f5szwd + + + Flow_0krv7di + Flow_1x0e8li + + + Flow_18ofjgo + Flow_011z76g + + + Flow_1f5szwd + Flow_18ofjgo + Flow_03o50ie + + + + =resendOtp=false + + + =resendOtp=true + + + + Flow_03o50ie + Flow_1w8nvno + + + Flow_011z76g + Flow_019nssu + Flow_1ob8gwu + + + + =isSenderLookupFailed=true + + + =isSenderLookupFailed=false + + + Flow_1x78sqd + Flow_1ob8gwu + Flow_0r31sb4 + + + + Flow_0r31sb4 + Flow_012u03p + + + + =isRecipientAdded=true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ph-ee-env-labs/orchestration/feel/Archive/paybill_workflow.bpmn b/ph-ee-env-labs/orchestration/feel/Archive/paybill_workflow.bpmn new file mode 100644 index 000000000..0c229d53c --- /dev/null +++ b/ph-ee-env-labs/orchestration/feel/Archive/paybill_workflow.bpmn @@ -0,0 +1,190 @@ + + + + + Flow_0mkgxc2 + Flow_0zj5svb + Flow_0z91exw + + + Flow_1ecfldo + + + Flow_1w6x088 + Flow_1oum6u4 + + + Flow_16hk9gv + Flow_1w6x088 + Flow_0zj5svb + + + =validationFailed = false + + + Flow_16hk9gv + + + + + + + Flow_17r5yck + Flow_1kw3y0l + + + Flow_1mlv58f + Flow_1oum6u4 + Flow_17r5yck + Flow_0mkgxc2 + + + =confirmationReceived = true + + + Flow_1kw3y0l + Flow_1ecfldo + Flow_0z91exw + + + + =transferSettlementFailed = false + + + + =confirmationReceived = false + + + =validationFailed = true + + + =transferSettlementFailed = true + + + Flow_1mlv58f + + = timer + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ph-ee-env-labs/orchestration/feel/Archive/payer-fund-transfer-terminate-DFSPID.bpmn b/ph-ee-env-labs/orchestration/feel/Archive/payer-fund-transfer-terminate-DFSPID.bpmn new file mode 100644 index 000000000..88ecdc0d9 --- /dev/null +++ b/ph-ee-env-labs/orchestration/feel/Archive/payer-fund-transfer-terminate-DFSPID.bpmn @@ -0,0 +1,1003 @@ + + + + + SequenceFlow_0h8jckr + + + + SequenceFlow_0r3ndmt + SequenceFlow_06tbhc9 + + + SequenceFlow_0btqmmg + SequenceFlow_0p78e79 + + + + SequenceFlow_1ffxwgp + SequenceFlow_0uphhfj + + + + + + SequenceFlow_0vrua4x + SequenceFlow_1n9vz7k + SequenceFlow_0r3ndmt + + + + + + SequenceFlow_0ew6rln + SequenceFlow_0q7anwv + + + + SequenceFlow_0mavnpt + SequenceFlow_09gkp54 + SequenceFlow_0zniywb + + + + + + SequenceFlow_09gkp54 + SequenceFlow_11uuh51 + SequenceFlow_0btqmmg + + + + =quoteRetryCount < 3 + + + + SequenceFlow_0mavnpt + + PT60S + + + + + + + + SequenceFlow_0zniywb + SequenceFlow_1d2huaz + SequenceFlow_0t11r3b + SequenceFlow_1l16e8u + SequenceFlow_0eh0472 + SequenceFlow_1oanf9v + SequenceFlow_1bb7vzi + + + + + + + SequenceFlow_01tpjgc + SequenceFlow_1ffxwgp + + + SequenceFlow_0uphhfj + SequenceFlow_1oanf9v + SequenceFlow_0jl4afa + + + + SequenceFlow_1bb7vzi + + + SequenceFlow_0p78e79 + SequenceFlow_0ew6rln + SequenceFlow_1d2huaz + + + + =quoteFailed = true + + + SequenceFlow_06tbhc9 + SequenceFlow_11uuh51 + SequenceFlow_0t11r3b + + + + =partyLookupFailed = true + + + SequenceFlow_0u5ni5c + + PT60S + + + + SequenceFlow_0q7anwv + SequenceFlow_01tpjgc + SequenceFlow_1l16e8u + + + + + =localQuoteFailed = true + + + SequenceFlow_0u5ni5c + SequenceFlow_0vrua4x + SequenceFlow_0eh0472 + + + + =partyLookupRetryCount < 3 + + + + + + =payerConfirmed = true + + + SequenceFlow_0h8jckr + SequenceFlow_0vwctf9 + SequenceFlow_1n9vz7k + + + SequenceFlow_0vwctf9 + + + =specialTermination = true + + + + + SequenceFlow_03m8dg4 + SequenceFlow_1qehqub + + + SequenceFlow_0cbkq69 + + + + + + SequenceFlow_0jl4afa + SequenceFlow_11izqno + + + + + + SequenceFlow_0450tx1 + SequenceFlow_0jf92kt + SequenceFlow_03m8dg4 + + + + + + SequenceFlow_1ps0i3p + SequenceFlow_1cvx4xc + SequenceFlow_1rp6mhy + + + SequenceFlow_0pu9eue + SequenceFlow_0450tx1 + SequenceFlow_0ugj3y3 + + + SequenceFlow_1qehqub + SequenceFlow_1ntmelw + SequenceFlow_1ps0i3p + SequenceFlow_0pgvsiz + + + + + + SequenceFlow_182gjov + SequenceFlow_0cbkq69 + + + + + + SequenceFlow_1khx8a1 + SequenceFlow_1hfhut1 + + + + + + SequenceFlow_0ugj3y3 + SequenceFlow_135twhv + + + + + + SequenceFlow_0pgvsiz + SequenceFlow_0t893eu + SequenceFlow_1kb0r09 + + + SequenceFlow_0xsgp3a + SequenceFlow_1ntmelw + SequenceFlow_1k82m25 + + + + + + SequenceFlow_0ajmktz + SequenceFlow_0xsgp3a + + + SequenceFlow_11izqno + SequenceFlow_0jf92kt + SequenceFlow_1khx8a1 + + + SequenceFlow_1rp6mhy + SequenceFlow_182gjov + SequenceFlow_0i4hpcx + + + + + + SequenceFlow_135twhv + SequenceFlow_0ajmktz + + + SequenceFlow_0lujb79 + + + SequenceFlow_1hfhut1 + + + SequenceFlow_1kb0r09 + SequenceFlow_1focmwo + SequenceFlow_1qxpd7p + + + SequenceFlow_1ip04gc + + + + + + SequenceFlow_0i4hpcx + SequenceFlow_0vhkjcs + + + + + + SequenceFlow_1qxpd7p + SequenceFlow_0okrzx7 + + + + + + SequenceFlow_0vhkjcs + SequenceFlow_1ao3fqx + + + + + + SequenceFlow_0okrzx7 + SequenceFlow_01urrn7 + + + SequenceFlow_01urrn7 + SequenceFlow_0t893eu + SequenceFlow_0lujb79 + + + + + + SequenceFlow_1focmwo + SequenceFlow_1ip04gc + + + SequenceFlow_1ao3fqx + SequenceFlow_1cvx4xc + SequenceFlow_1jb3jhv + + + SequenceFlow_1jb3jhv + + + SequenceFlow_1k82m25 + + + SequenceFlow_0pu9eue + + PT60S + + + + + + + + =transferRetryCount < 3 + + + + + + + + + + =transferFailed = true or transferState != "COMMITTED" + + + + =transferPrepareFailed = true + + + + + + + + =operatorManualOverride = true + + + + =transferCreateFailed = true + + + =operatorManualOverride = true + + + + =transferReleaseFailed = true + + + + + + + + =operatorManualOverride = true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ph-ee-env-labs/orchestration/feel/Archive/payer-transaction-request-DFSPID.bpmn b/ph-ee-env-labs/orchestration/feel/Archive/payer-transaction-request-DFSPID.bpmn new file mode 100644 index 000000000..bec37fc22 --- /dev/null +++ b/ph-ee-env-labs/orchestration/feel/Archive/payer-transaction-request-DFSPID.bpmn @@ -0,0 +1,1098 @@ + + + + + + + + SequenceFlow_0sxzzzv + SequenceFlow_0anhzen + SequenceFlow_0rvpgij + + + SequenceFlow_0tfe08e + SequenceFlow_0sxzzzv + SequenceFlow_01bkf5x + + + + + + SequenceFlow_02phkif + SequenceFlow_1xq7wiz + + + SequenceFlow_1f8ez7c + + + + + + SequenceFlow_1f8ez7c + SequenceFlow_02phkif + + + + + + SequenceFlow_1vbwmau + SequenceFlow_1tycp8s + SequenceFlow_1x48wlr + + + SequenceFlow_0bxjqxn + SequenceFlow_11uzipj + SequenceFlow_1x0uf57 + SequenceFlow_1c0nrf0 + + + SequenceFlow_1x48wlr + SequenceFlow_1n7w31w + + + + + + SequenceFlow_1n7w31w + SequenceFlow_11uzipj + + + + + + SequenceFlow_1x0uf57 + SequenceFlow_0t1uw8e + + + + + + SequenceFlow_0foazs5 + SequenceFlow_1drvhkw + + + SequenceFlow_1drvhkw + SequenceFlow_0bxjqxn + + + SequenceFlow_0k56b3o + SequenceFlow_0foazs5 + SequenceFlow_0y5jjvn + + + + + + SequenceFlow_0y5jjvn + SequenceFlow_1vbwmau + + + SequenceFlow_1eqt91u + SequenceFlow_1tycp8s + SequenceFlow_0t895dl + + + + + + SequenceFlow_01bkf5x + SequenceFlow_0t895dl + SequenceFlow_1abz2tc + SequenceFlow_0e7ewhm + SequenceFlow_0q5pn1h + + + SequenceFlow_0q5pn1h + + + SequenceFlow_0t1uw8e + + + SequenceFlow_1eqt91u + + PT60S + + + + + =quoteRetryCount < 3 + + + + + + + =payerAuthorisationRetryCount < 3 + + + + + + =payerConfirmed = false or authValidationSuccess = false + + + + + + + =isAuthorisationRequired = true + + + + + + + SequenceFlow_1xq7wiz + SequenceFlow_0anhzen + SequenceFlow_1abz2tc + + + + =localQuoteFailed = true + + + SequenceFlow_066uoky + SequenceFlow_097qxd5 + SequenceFlow_0k56b3o + SequenceFlow_0e7ewhm + + + + =quoteFailed = true + + + + + + SequenceFlow_1c0nrf0 + SequenceFlow_16x0c56 + + + + SequenceFlow_0rvpgij + SequenceFlow_0vri98a + SequenceFlow_1oo0diq + SequenceFlow_0jufwjm + + + + SequenceFlow_0vri98a + SequenceFlow_0tfe08e + + PT60S + + + + + + SequenceFlow_1oo0diq + SequenceFlow_066uoky + + + + + SequenceFlow_0jufwjm + SequenceFlow_097qxd5 + + + + + + + SequenceFlow_0ywnpg5 + SequenceFlow_1df9rne + + + SequenceFlow_04g7cal + + + + + + SequenceFlow_16x0c56 + SequenceFlow_18a60z0 + + + + + + SequenceFlow_1fecrog + SequenceFlow_16tylai + SequenceFlow_0ywnpg5 + + + + + + SequenceFlow_0mwa7db + SequenceFlow_1xqhnh7 + SequenceFlow_17aymop + + + SequenceFlow_1fjqlh5 + SequenceFlow_1fecrog + SequenceFlow_0njqai4 + + + SequenceFlow_1df9rne + SequenceFlow_11y0j6g + SequenceFlow_0mwa7db + SequenceFlow_0x4goeh + + + + + + SequenceFlow_1mhtysl + SequenceFlow_04g7cal + + + + + + SequenceFlow_1w6ltol + SequenceFlow_0eikt98 + + + + + + SequenceFlow_0njqai4 + SequenceFlow_1ee0znw + + + + + + SequenceFlow_0x4goeh + SequenceFlow_0c0qern + SequenceFlow_0u4vni9 + + + SequenceFlow_0otg70y + SequenceFlow_11y0j6g + SequenceFlow_0bod8m0 + + + + + + SequenceFlow_169rv3d + SequenceFlow_0otg70y + + + SequenceFlow_18a60z0 + SequenceFlow_16tylai + SequenceFlow_1w6ltol + + + SequenceFlow_17aymop + SequenceFlow_1mhtysl + SequenceFlow_0dkjgrl + + + + + + SequenceFlow_1ee0znw + SequenceFlow_169rv3d + + + SequenceFlow_0vkxaq5 + + + SequenceFlow_0eikt98 + + + SequenceFlow_0u4vni9 + SequenceFlow_0uao3pp + SequenceFlow_1boe2c9 + + + SequenceFlow_1adbkua + + + + + + SequenceFlow_0dkjgrl + SequenceFlow_1hyuajh + + + + + + SequenceFlow_1boe2c9 + SequenceFlow_1536b43 + + + + + + SequenceFlow_1hyuajh + SequenceFlow_11btf8v + + + + + + SequenceFlow_1536b43 + SequenceFlow_11yul02 + + + SequenceFlow_11yul02 + SequenceFlow_0c0qern + SequenceFlow_0vkxaq5 + + + + + + SequenceFlow_0uao3pp + SequenceFlow_1adbkua + + + SequenceFlow_11btf8v + SequenceFlow_1xqhnh7 + SequenceFlow_1oszge5 + + + SequenceFlow_1oszge5 + + + SequenceFlow_0bod8m0 + + + SequenceFlow_1fjqlh5 + + PT60S + + + + + + + + =transferRetryCount < 3 + + + + + + + + + + =transferFailed = true or transferState != "COMMITTED" + + + + =transferPrepareFailed = true + + + + + + + + =operatorManualOverride = true + + + + =transferCreateFailed = true + + + =operatorManualOverride = true + + + + =transferReleaseFailed = true + + + + + + + + =operatorManualOverride = true + + + incoming trans request initialize flow + + + who validates otp? + + + who generates and send otp? + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ph-ee-env-labs/orchestration/feel/Archive/perftest.bpmn b/ph-ee-env-labs/orchestration/feel/Archive/perftest.bpmn new file mode 100644 index 000000000..63d9a2ebb --- /dev/null +++ b/ph-ee-env-labs/orchestration/feel/Archive/perftest.bpmn @@ -0,0 +1,71 @@ + + + + + SequenceFlow_0zjdhkk + + + + + + + SequenceFlow_12m5tke + + + + + + SequenceFlow_0zjdhkk + SequenceFlow_0yazklo + + + + + + SequenceFlow_0yazklo + SequenceFlow_0ks02bb + + + + + + SequenceFlow_0ks02bb + SequenceFlow_12m5tke + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ph-ee-env-labs/orchestration/feel/Archive/perftest2.bpmn b/ph-ee-env-labs/orchestration/feel/Archive/perftest2.bpmn new file mode 100644 index 000000000..6e3a6d371 --- /dev/null +++ b/ph-ee-env-labs/orchestration/feel/Archive/perftest2.bpmn @@ -0,0 +1,26 @@ + + + + + SequenceFlow_0zjdhkk + + + + SequenceFlow_0zjdhkk + + + + + + + + + + + + + + + + + diff --git a/ph-ee-env-labs/orchestration/feel/Archive/zeebe-test.bpmn b/ph-ee-env-labs/orchestration/feel/Archive/zeebe-test.bpmn new file mode 100644 index 000000000..31d40c2c0 --- /dev/null +++ b/ph-ee-env-labs/orchestration/feel/Archive/zeebe-test.bpmn @@ -0,0 +1,44 @@ + + + + + + + + Flow_055gsbq + Flow_1wnhehp + + + Flow_1wnhehp + + + Flow_055gsbq + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ph-ee-env-labs/orchestration/feel/PayeePartyLookup-DFSPID.bpmn b/ph-ee-env-labs/orchestration/feel/PayeePartyLookup-DFSPID.bpmn new file mode 100644 index 000000000..469e0ea81 --- /dev/null +++ b/ph-ee-env-labs/orchestration/feel/PayeePartyLookup-DFSPID.bpmn @@ -0,0 +1,83 @@ + + + + + SequenceFlow_1jawp7n + + + + + + + SequenceFlow_1jawp7n + SequenceFlow_0vk18w4 + + + + + + SequenceFlow_0vk18w4 + SequenceFlow_1cpr2t7 + + + SequenceFlow_1cpr2t7 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ph-ee-env-labs/orchestration/feel/PayeeQuoteTransfer-DFSPID.bpmn b/ph-ee-env-labs/orchestration/feel/PayeeQuoteTransfer-DFSPID.bpmn new file mode 100644 index 000000000..09719ada5 --- /dev/null +++ b/ph-ee-env-labs/orchestration/feel/PayeeQuoteTransfer-DFSPID.bpmn @@ -0,0 +1,403 @@ + + + + + SequenceFlow_0upmeol + + + + + + + SequenceFlow_0upmeol + SequenceFlow_07ubxkp + + + + + + SequenceFlow_12altlz + SequenceFlow_1871cq3 + + + SequenceFlow_1yi59vy + + + SequenceFlow_1871cq3 + SequenceFlow_0ha729a + SequenceFlow_0tifm4f + SequenceFlow_1rjfrgt + + + SequenceFlow_0ha729a + SequenceFlow_0j1b0rd + + + + + SequenceFlow_1rjfrgt + SequenceFlow_1dg7uh7 + + PT60S + + + + + + + SequenceFlow_04hdoau + SequenceFlow_00cmaa9 + + + + + + SequenceFlow_1nhsyf3 + SequenceFlow_0qveqrp + + + SequenceFlow_07ubxkp + SequenceFlow_12altlz + SequenceFlow_1l50z66 + + + + + + + SequenceFlow_0j1b0rd + SequenceFlow_1tkl7ok + + + + + SequenceFlow_1b5fd21 + + + + + + SequenceFlow_0gp1sbx + SequenceFlow_1b5fd21 + + + + SequenceFlow_1tkl7ok + SequenceFlow_1nxdko8 + SequenceFlow_0gp1sbx + + + + =quoteFailed = true + + + SequenceFlow_0tifm4f + SequenceFlow_0bhw2cx + + + + + + SequenceFlow_1dg7uh7 + + + SequenceFlow_0bhw2cx + + + SequenceFlow_1l50z66 + + + + + + + SequenceFlow_1nxdko8 + SequenceFlow_04hdoau + SequenceFlow_1nhsyf3 + + + + =transferCreateFailed = true + + + + SequenceFlow_00cmaa9 + SequenceFlow_0qveqrp + SequenceFlow_1yi59vy + + + + + + + + + + + + add timeout dynamically for transfer and rtp? + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ph-ee-env-labs/orchestration/feel/PayerFundTransfer-DFSPID.bpmn b/ph-ee-env-labs/orchestration/feel/PayerFundTransfer-DFSPID.bpmn new file mode 100644 index 000000000..200f36e54 --- /dev/null +++ b/ph-ee-env-labs/orchestration/feel/PayerFundTransfer-DFSPID.bpmn @@ -0,0 +1,1028 @@ + + + + + SequenceFlow_1pymsem + + + + + SequenceFlow_0h8jckr + SequenceFlow_06tbhc9 + + + SequenceFlow_1ffxwgp + SequenceFlow_0uphhfj + + + + + + SequenceFlow_1pymsem + SequenceFlow_0vrua4x + SequenceFlow_0h8jckr + + + + + + SequenceFlow_0ew6rln + SequenceFlow_0q7anwv + + + SequenceFlow_12nueew + SequenceFlow_09gkp54 + SequenceFlow_0zniywb + + + + + + SequenceFlow_09gkp54 + SequenceFlow_11uuh51 + SequenceFlow_1eicyj6 + + + =quoteRetryCount < 3 + + + + + + + + SequenceFlow_0zniywb + SequenceFlow_1d2huaz + SequenceFlow_0t11r3b + SequenceFlow_1l16e8u + SequenceFlow_0eh0472 + SequenceFlow_1oanf9v + SequenceFlow_1bb7vzi + + + + + + + SequenceFlow_01tpjgc + SequenceFlow_1ffxwgp + + + SequenceFlow_0uphhfj + SequenceFlow_1oanf9v + SequenceFlow_0jl4afa + + + + SequenceFlow_1bb7vzi + + + SequenceFlow_03gw2ot + SequenceFlow_0fyvo3u + SequenceFlow_0ew6rln + SequenceFlow_1d2huaz + + + + =quoteFailed = true + + + SequenceFlow_06tbhc9 + SequenceFlow_11uuh51 + SequenceFlow_0t11r3b + + + + =partyLookupFailed = true + + + SequenceFlow_0u5ni5c + + PT60S + + + + SequenceFlow_0q7anwv + SequenceFlow_01tpjgc + SequenceFlow_1l16e8u + + + + + =localQuoteFailed = true + + + SequenceFlow_0u5ni5c + SequenceFlow_0vrua4x + SequenceFlow_0eh0472 + + + + =partyLookupRetryCount < 3 + + + + + + =payerConfirmed = true + + + SequenceFlow_1eicyj6 + SequenceFlow_15wc77c + SequenceFlow_0h2j62g + SequenceFlow_087rb2p + + + + + SequenceFlow_15wc77c + SequenceFlow_03gw2ot + + + + + SequenceFlow_0h2j62g + SequenceFlow_0fyvo3u + + + + + + SequenceFlow_087rb2p + SequenceFlow_12nueew + + PT60S + + + + + + SequenceFlow_021l36b + SequenceFlow_0hjdph9 + + + SequenceFlow_0zv37c6 + + + + + + SequenceFlow_0jl4afa + SequenceFlow_0dt42vk + + + + + + SequenceFlow_1a0pfuq + SequenceFlow_1ptml7u + SequenceFlow_021l36b + + + + + + SequenceFlow_1222rpl + SequenceFlow_1k13ccu + SequenceFlow_1emjz5s + + + SequenceFlow_039x2o8 + SequenceFlow_1a0pfuq + SequenceFlow_1u7fhxg + + + SequenceFlow_0hjdph9 + SequenceFlow_11ybwbd + SequenceFlow_1222rpl + SequenceFlow_1ic2uyb + + + + + + SequenceFlow_02o4g3y + SequenceFlow_0zv37c6 + + + + + + SequenceFlow_1f823z7 + SequenceFlow_0r1oaqw + + + + + + SequenceFlow_1u7fhxg + SequenceFlow_1md51ht + + + + + + SequenceFlow_1ic2uyb + SequenceFlow_0wlity5 + SequenceFlow_1gmvm2h + + + SequenceFlow_0jviy8g + SequenceFlow_11ybwbd + SequenceFlow_0udfio5 + + + + + + SequenceFlow_13qetbt + SequenceFlow_0jviy8g + + + SequenceFlow_0dt42vk + SequenceFlow_1ptml7u + SequenceFlow_1f823z7 + + + SequenceFlow_1emjz5s + SequenceFlow_02o4g3y + SequenceFlow_0t11txa + + + + + + SequenceFlow_1md51ht + SequenceFlow_13qetbt + + + SequenceFlow_0ntctr3 + + + SequenceFlow_0r1oaqw + + + SequenceFlow_1gmvm2h + SequenceFlow_17okil0 + SequenceFlow_0jgx2x0 + + + SequenceFlow_0ogstcm + + + + + + SequenceFlow_0t11txa + SequenceFlow_1g74z3o + + + + + + SequenceFlow_0jgx2x0 + SequenceFlow_1tq3ry1 + + + + + + SequenceFlow_1g74z3o + SequenceFlow_0xh7fo1 + + + + + + SequenceFlow_1tq3ry1 + SequenceFlow_1k0in2i + + + SequenceFlow_1k0in2i + SequenceFlow_0wlity5 + SequenceFlow_0ntctr3 + + + + + + SequenceFlow_17okil0 + SequenceFlow_0ogstcm + + + SequenceFlow_0xh7fo1 + SequenceFlow_1k13ccu + SequenceFlow_14hz2nf + + + SequenceFlow_14hz2nf + + + SequenceFlow_0udfio5 + + + SequenceFlow_039x2o8 + + PT60S + + + + + + + + =transferRetryCount < 3 + + + + + + + + + + =transferFailed = true or transferState != "COMMITTED" + + + + =transferPrepareFailed = true + + + + + + + + =operatorManualOverride = true + + + + =transferCreateFailed = true + + + =operatorManualOverride = true + + + + =transferReleaseFailed = true + + + + + + + + =operatorManualOverride = true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ph-ee-env-labs/orchestration/feel/bill-inquiry-DFSPID.bpmn b/ph-ee-env-labs/orchestration/feel/bill-inquiry-DFSPID.bpmn new file mode 100644 index 000000000..004d95560 --- /dev/null +++ b/ph-ee-env-labs/orchestration/feel/bill-inquiry-DFSPID.bpmn @@ -0,0 +1,135 @@ + + + + + Flow_1guz4a0 + + + + + + + Flow_1bwc6vb + Flow_0hxrt63 + + + + + + Flow_1guz4a0 + Flow_1q3mrws + + + Flow_0nvd0uz + + + Flow_1q3mrws + Flow_1bwc6vb + Flow_0uwehp9 + + + + + + + + Flow_0hxrt63 + Flow_0uwehp9 + Flow_0nvd0uz + + + + + =billerFetchFailed= true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ph-ee-env-labs/orchestration/feel/bill-request-DFSPID.bpmn b/ph-ee-env-labs/orchestration/feel/bill-request-DFSPID.bpmn new file mode 100644 index 000000000..140f21a1f --- /dev/null +++ b/ph-ee-env-labs/orchestration/feel/bill-request-DFSPID.bpmn @@ -0,0 +1,134 @@ + + + + + Flow_18mhs3y + + + + Flow_1lrx329 + Flow_0nmf60x + + + + Flow_0nmf60x + Flow_1qqrnnz + Flow_1rcc8xo + Flow_1jl9gd4 + + + + Flow_1rcc8xo + Flow_1qqrnnz + + + + + Flow_1jl9gd4 + Flow_0i0faop + + + + + + Flow_1wmzova + Flow_01bodrz + + + Flow_0i0faop + Flow_1wmzova + + + Flow_18mhs3y + Flow_1lrx329 + + + + + Flow_01bodrz + Flow_04vv3ch + + + Flow_04vv3ch + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ph-ee-env-labs/orchestration/feel/bill_request-DFSPID.bpmn b/ph-ee-env-labs/orchestration/feel/bill_request-DFSPID.bpmn new file mode 100644 index 000000000..7394bc978 --- /dev/null +++ b/ph-ee-env-labs/orchestration/feel/bill_request-DFSPID.bpmn @@ -0,0 +1,195 @@ + + + + + Flow_18mhs3y + + + + + + + Flow_18mhs3y + Flow_0nmf60x + + + + + + + Flow_0own4p9 + Flow_0s19sq9 + + + + + + Flow_0nmf60x + Flow_1bkzw6r + + + Flow_1bkzw6r + Flow_0own4p9 + Flow_0oxlbkd + + + + = payerRtpRequestSuccess = true + + + + + + Flow_0oxlbkd + Flow_1uwblh4 + + + Flow_1uwblh4 + + + + + + + + Flow_041io3y + Flow_0s19sq9 + Flow_0a7x7ww + + + Flow_0a7x7ww + Flow_041io3y + Flow_0jl54pj + + + + + + Flow_0jl54pj + Flow_19k1cqy + + + Flow_19k1cqy + + + =billPayFailed = true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ph-ee-env-labs/orchestration/feel/bulk_connector_closedloop-DFSPID.bpmn b/ph-ee-env-labs/orchestration/feel/bulk_connector_closedloop-DFSPID.bpmn new file mode 100644 index 000000000..380b69ada --- /dev/null +++ b/ph-ee-env-labs/orchestration/feel/bulk_connector_closedloop-DFSPID.bpmn @@ -0,0 +1,184 @@ + + + + + Flow_18pidwz + + + + + Flow_1y51aki + Flow_0bptiw6 + Flow_1r2y00f + + + + = batchSummarySuccess = true + + + Flow_19jf63d + Flow_0tp63bk + Flow_02silk7 + + + + + + + Flow_18pidwz + Flow_18j0g8r + + + + + + Flow_18j0g8r + Flow_0ok3dms + Flow_1y51aki + + + + + + Flow_0bptiw6 + Flow_19jf63d + + + Flow_0tp63bk + + + = batchDetailSuccess = true + + + Flow_0wr743r + Flow_02silk7 + + + Flow_0y0aw9b + Flow_0ok3dms + + = waitTimer + + + + + Flow_1r2y00f + Flow_0wr743r + Flow_0y0aw9b + + + = currentRetryCount > maxRetryCount + + + = batchSummarySuccess = false + + + = currentRetryCount <= maxRetryCount + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ph-ee-env-labs/orchestration/feel/bulk_connector_slcb-DFSPID.bpmn b/ph-ee-env-labs/orchestration/feel/bulk_connector_slcb-DFSPID.bpmn new file mode 100644 index 000000000..592bc65b0 --- /dev/null +++ b/ph-ee-env-labs/orchestration/feel/bulk_connector_slcb-DFSPID.bpmn @@ -0,0 +1,233 @@ + + + + + Flow_0tf4rfr + + + + + + + Flow_0tf4rfr + Flow_0loafq6 + + + transferSuccessFlow + + + transferFailedFlow + + + Flow_0h3hfit + transferSuccessFlow + transferFailedFlow + + + =transferFailed = false + + + =transferFailed = true + + + Flow_0loafq6 + Flow_1clyw06 + Flow_0h3hfit + + + + =isReconciliationEnabled = true + + + + + + Flow_1clyw06 + Flow_1k6w0b6 + Flow_0dznwrv + + + =isReconciliationEnabled = false + + + Flow_0dznwrv + reconciliationSuccessFlow + reconciliationFailedFlow + + + + =isReconciliationSuccess = true + + + reconciliationFailedFlow + retryFlow + reconciliationFailedRetryExhausted + + + =isReconciliationSuccess = false + + + reconciliationSuccessFlow + + + retryFlow + Flow_1k6w0b6 + + = reconciliationWaitTimer + + + + = reconciliationRetry <= reconciliationRetryCount + + + + reconciliationFailedRetryExhausted + + + = reconciliationRetry > reconciliationRetryCount + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ph-ee-env-labs/orchestration/feel/bulk_processor-DFSPID.bpmn b/ph-ee-env-labs/orchestration/feel/bulk_processor-DFSPID.bpmn new file mode 100644 index 000000000..3a8fc8a5b --- /dev/null +++ b/ph-ee-env-labs/orchestration/feel/bulk_processor-DFSPID.bpmn @@ -0,0 +1,1289 @@ + + + + + Flow_13bbfpz + + + Flow_153sx5h + Flow_1j06peu + Flow_0mqykzn + Flow_1ytq8zs + + + + Flow_0mznm0b + Flow_1jxlcdn + Flow_1vjnnon + Flow_0d8gl37 + + + + =orderingEnabled = true + + + Flow_0d8gl37 + Flow_1s35nqg + Flow_1vdc80r + Flow_1t978vp + + + + =orderingEnabled = false + + + Flow_13bnu4n + Flow_1ve5awe + Flow_16agh2e + + = thresholdDelay + + + + Flow_12pvmjx + Flow_0ywsmwg + Flow_13bnu4n + + + Flow_0ywsmwg + Flow_1q4njje + Flow_06vro2j + + + + =completionThresholdCheckEnabled = false + + + =splittingEnabled = true + + + Flow_1t978vp + Flow_1sciac1 + Flow_06qdxek + Flow_0ylfdlk + + + + =splittingEnabled = true + + + =splittingEnabled = false + + + + =splittingEnabled = false + + + Flow_1yizik2 + Flow_153sx5h + Flow_01p8efv + + + =partyLookupFailed = false + + + Flow_160kxi5 + Flow_0xq6gd6 + Flow_1j06peu + + + =partyLookupEnabled = true + + + =partyLookupEnabled = false + + + Flow_081dt35 + Flow_07xk2cv + Flow_0qr8tho + + + Flow_1fd2eaj + Flow_1s35nqg + Flow_1f1ibfg + + + =orderingFailed = false + + + Flow_1n6whyu + Flow_1sciac1 + Flow_0pyarpp + + + =formattingFailed = false + + + Flow_09ezd99 + Flow_14kaash + Flow_0wi2mgf + + + =splittingFailed = false + + + + + + Flow_0xq6gd6 + Flow_1yizik2 + + + + + + Flow_0ibgdic + Flow_081dt35 + + + + + + Flow_1vjnnon + Flow_1fd2eaj + + + + + + Flow_1vdc80r + Flow_1n6whyu + + + + + + Flow_1i7um70 + Flow_18c5uxb + + + Flow_1wsncqq + Flow_0vi2nzc + Flow_1rquimq + + + + + + Flow_14kaash + Flow_0ylfdlk + Flow_1hvz4mz + Flow_1o2hvra + + + Flow_1o2hvra + Flow_12pvmjx + Flow_1hvz4mz + + + =remainingSubBatch = 0 + + + Flow_06vro2j + Flow_10ljkqz + Flow_0xgaqao + + + =mergeEnabled = true + + + + + + + Flow_06qdxek + Flow_09ezd99 + + + + + + Flow_10ljkqz + Flow_10qbvqn + Flow_1kk2jxw + + + Flow_0vi2nzc + Flow_0xgaqao + Flow_06lz8g7 + + + =mergeFailed = false + + + =mergeEnabled = false + + + Flow_1kk2jxw + Flow_1wsncqq + Flow_10qbvqn + + + =mergeCompleted = true + + + =mergeCompleted = false + + + =remainingSubBatch > 0 + + + + + + + Flow_1phtnlz + Flow_0djfdh8 + Flow_1x68ryh + + + Flow_1x68ryh + Flow_07plw2d + Flow_10j2ug7 + + + Flow_07plw2d + Flow_1phtnlz + Flow_0hnp6f8 + + + = responseCode <=199 or responseCode >=300 + + + + = callbackRetryCount < maxStatusRetry + + + Flow_06lz8g7 + Flow_01p8efv + Flow_07xk2cv + Flow_1f1ibfg + Flow_0pyarpp + Flow_0wi2mgf + Flow_1rquimq + Flow_1e3gi84 + Flow_16yundm + Flow_145ut1o + Flow_08jjm67 + Flow_0czqxi5 + Flow_0v5a0du + + + + =partyLookupFailed = true + + + =approvalFailed = true + + + =orderingFailed = true + + + =formattingFailed = true + + + =splittingFailed = true + + + =mergeFailed = true + + + + + + Flow_0czqxi5 + Flow_10l0nox + + + Flow_145ut1o + Flow_1263i40 + + + Flow_08jjm67 + + + =isNotificationsFailureEnabled = false + + + =isNotificationsSuccessEnabled = false + + + + + + Flow_0v5a0du + Flow_0cwo87q + + + =isNotificationsFailureEnabled = true + + + =isNotificationsSuccessEnabled = true + + + + + + Flow_10l0nox + Flow_0cwo87q + Flow_0i7ujhe + + + + + Flow_08i54z1 + Flow_1iatqkc + Flow_174lwz0 + + + Flow_1tvkw1p + + = callbackTimer + + + + Flow_0i7ujhe + Flow_08i54z1 + Flow_1ch4lto + + + + =messageStatus = pending + + + Flow_1ch4lto + Flow_1czpfw1 + + + =messageStatus = failed + + + + + + Flow_1tvkw1p + Flow_1iatqkc + + + + + Flow_174lwz0 + Flow_1czpfw1 + Flow_0jdr3x6 + + + Flow_0jdr3x6 + + + + + =isMessageDelivered = true + + + =completionThresholdCheckEnabled = true + + + Flow_0yhvmsf + Flow_1qjmjs6 + Flow_0x5g1yx + + + Flow_1qjmjs6 + Flow_1ve5awe + Flow_0cpybki + + + + =completionRate < completionThreshold and retry < maxStatusRetry + + + Flow_0cpybki + Flow_1q28jgi + Flow_1q4njje + + + =retry >= maxStatusRetry + + + + + Flow_0x5g1yx + Flow_0hnp6f8 + Flow_10j2ug7 + Flow_0djfdh8 + Flow_1q28jgi + + + = some x in phases satisfies x <= completionRate + + + + = callbackRetryCount >= maxStatusRetry + + + =responseCode >= 200 and responseCode <=299 + + + Flow_13bbfpz + Flow_160kxi5 + Flow_1263i40 + + + + + =isFileValid = false + + + Flow_16agh2e + Flow_1i7um70 + Flow_0lg9iie + + + + =batchAggregateEnabled = false + + + =batchAggregateEnabled = true + + + + + + Flow_0lg9iie + Flow_14pwl6g + + + =authorizationEnabled = true + + + + + + Flow_0mqykzn + Flow_1jw6zm2 + + + + Flow_1jw6zm2 + Flow_1swu9fe + + + Flow_1swu9fe + Flow_14v5hao + Flow_1e3gi84 + + + + Flow_14v5hao + Flow_1ytq8zs + Flow_0ibgdic + Flow_0avvjpj + + + =authorizationSuccessful = true + + + =authorizationSuccessful = false + + + =authorizationEnabled = false + + + =approvalEnabled = true + + + =approvalEnabled = false + + + Flow_0qr8tho + Flow_0avvjpj + Flow_1qfedra + Flow_1jxlcdn + + + =approvalFailed = false + + + Flow_01as8cw + Flow_0mznm0b + Flow_16yundm + + + + =deduplicationFailed = false + + + =deduplicationEnabled = true + + + =deduplicationEnabled = false + + + + + + Flow_1qfedra + Flow_01as8cw + + + =deduplicationFailed = true + + + Flow_18c5uxb + Flow_14pwl6g + Flow_0yhvmsf + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ph-ee-env-labs/orchestration/feel/bulk_processor_account_lookup-DFSPID.bpmn b/ph-ee-env-labs/orchestration/feel/bulk_processor_account_lookup-DFSPID.bpmn new file mode 100644 index 000000000..6567f37ec --- /dev/null +++ b/ph-ee-env-labs/orchestration/feel/bulk_processor_account_lookup-DFSPID.bpmn @@ -0,0 +1,1265 @@ + + + + + Flow_13bbfpz + + + Flow_153sx5h + Flow_1j06peu + Flow_0mqykzn + Flow_1ytq8zs + + + Flow_1qa9egn + Flow_0avvjpj + Flow_1vjnnon + Flow_0d8gl37 + + + + =orderingEnabled = true + + + Flow_0d8gl37 + Flow_1s35nqg + Flow_1vdc80r + Flow_1t978vp + + + + =orderingEnabled = false + + + Flow_13bnu4n + Flow_1ve5awe + Flow_16agh2e + + = thresholdDelay + + + + Flow_12pvmjx + Flow_0ywsmwg + Flow_13bnu4n + + + Flow_0ywsmwg + Flow_1q4njje + Flow_06vro2j + + + + =completionThresholdCheckEnabled = false + + + =splittingEnabled = true + + + Flow_1t978vp + Flow_1sciac1 + Flow_06qdxek + Flow_0ylfdlk + + + + =splittingEnabled = true + + + =splittingEnabled = false + + + + =splittingEnabled = false + + + Flow_0fadq7p + Flow_153sx5h + Flow_01p8efv + + + =partyLookupFailed = false + + + Flow_160kxi5 + Flow_0xq6gd6 + Flow_1j06peu + + + =partyLookupEnabled = true + + + =partyLookupEnabled = false + + + Flow_081dt35 + Flow_1qa9egn + Flow_07xk2cv + + + =approvalFailed = false + + + Flow_1fd2eaj + Flow_1s35nqg + Flow_1f1ibfg + + + =orderingFailed = false + + + Flow_1n6whyu + Flow_1sciac1 + Flow_0pyarpp + + + =formattingFailed = false + + + Flow_09ezd99 + Flow_14kaash + Flow_0wi2mgf + + + =splittingFailed = false + + + + + + Flow_0ibgdic + Flow_081dt35 + + + + + + Flow_1vjnnon + Flow_1fd2eaj + + + + + + Flow_1vdc80r + Flow_1n6whyu + + + + + + Flow_1i7um70 + Flow_0t6zlmj + + + Flow_1wsncqq + Flow_0vi2nzc + Flow_1rquimq + + + + + + Flow_14kaash + Flow_0ylfdlk + Flow_1hvz4mz + Flow_1o2hvra + + + Flow_1o2hvra + Flow_12pvmjx + Flow_1hvz4mz + + + =remainingSubBatch = 0 + + + Flow_06vro2j + Flow_10ljkqz + Flow_0xgaqao + + + =mergeEnabled = true + + + + + + + Flow_06qdxek + Flow_09ezd99 + + + + + + Flow_10ljkqz + Flow_10qbvqn + Flow_1kk2jxw + + + Flow_0vi2nzc + Flow_0xgaqao + Flow_06lz8g7 + + + =mergeFailed = false + + + =mergeEnabled = false + + + Flow_1kk2jxw + Flow_1wsncqq + Flow_10qbvqn + + + =mergeCompleted = true + + + =mergeCompleted = false + + + =remainingSubBatch > 0 + + + + + + + Flow_1phtnlz + Flow_0djfdh8 + Flow_1x68ryh + + + Flow_1x68ryh + Flow_07plw2d + Flow_10j2ug7 + + + Flow_07plw2d + Flow_1phtnlz + Flow_0hnp6f8 + + + = responseCode <=199 or responseCode >=300 + + + + = callbackRetryCount < maxStatusRetry + + + Flow_06lz8g7 + Flow_01p8efv + Flow_07xk2cv + Flow_1f1ibfg + Flow_0pyarpp + Flow_0wi2mgf + Flow_1rquimq + Flow_1e3gi84 + Flow_145ut1o + Flow_08jjm67 + Flow_0czqxi5 + Flow_0v5a0du + + + + =partyLookupFailed = true + + + =approvalFailed = true + + + =orderingFailed = true + + + =formattingFailed = true + + + =splittingFailed = true + + + =mergeFailed = true + + + + + + Flow_0czqxi5 + Flow_10l0nox + + + Flow_145ut1o + Flow_1263i40 + + + Flow_08jjm67 + + + =isNotificationsFailureEnabled = false + + + =isNotificationsSuccessEnabled = false + + + + + + Flow_0v5a0du + Flow_0cwo87q + + + =isNotificationsFailureEnabled = true + + + =isNotificationsSuccessEnabled = true + + + + + + Flow_10l0nox + Flow_0cwo87q + Flow_0i7ujhe + + + + + Flow_08i54z1 + Flow_1iatqkc + Flow_174lwz0 + + + Flow_1tvkw1p + + = callbackTimer + + + + Flow_0i7ujhe + Flow_08i54z1 + Flow_1ch4lto + + + + =messageStatus = pending + + + Flow_1ch4lto + Flow_1czpfw1 + + + =messageStatus = failed + + + + + + Flow_1tvkw1p + Flow_1iatqkc + + + + + Flow_174lwz0 + Flow_1czpfw1 + Flow_0jdr3x6 + + + Flow_0jdr3x6 + + + + + =isMessageDelivered = true + + + =completionThresholdCheckEnabled = true + + + Flow_1qjmjs6 + Flow_1ve5awe + Flow_0cpybki + + + + =completionRate < completionThreshold and retry < maxStatusRetry + + + Flow_0cpybki + Flow_1q28jgi + Flow_1q4njje + + + =retry >= maxStatusRetry + + + + + Flow_0x5g1yx + Flow_0hnp6f8 + Flow_10j2ug7 + Flow_0djfdh8 + Flow_1q28jgi + + + = some x in phases satisfies x <= completionRate + + + + = callbackRetryCount >= maxStatusRetry + + + =responseCode >= 200 and responseCode <=299 + + + Flow_13bbfpz + Flow_160kxi5 + Flow_1263i40 + + + + + =isFileValid = false + + + Flow_16agh2e + Flow_1i7um70 + Flow_0lg9iie + + + + =batchAggregateEnabled = false + + + =batchAggregateEnabled = true + + + + + + Flow_0lg9iie + Flow_0irbmnw + + + =authorizationEnabled = true + + + + + + Flow_0mqykzn + Flow_1jw6zm2 + + + + Flow_1jw6zm2 + Flow_1swu9fe + + + Flow_1swu9fe + Flow_14v5hao + Flow_1e3gi84 + + + + Flow_14v5hao + Flow_1ytq8zs + Flow_0ibgdic + Flow_0avvjpj + + + =authorizationSuccessful = true + + + =authorizationSuccessful = false + + + =authorizationEnabled = false + + + =approvalEnabled = true + + + =approvalEnabled = false + + + + + + Flow_0b2epzq + Flow_0fadq7p + + + Flow_07t8xe1 + Flow_0b2epzq + + + + + + Flow_0xq6gd6 + Flow_07t8xe1 + + + + + + Flow_1m61ayg + Flow_0x5g1yx + Flow_1qjmjs6 + + + Flow_0t6zlmj + Flow_0irbmnw + Flow_1m61ayg + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ph-ee-env-labs/orchestration/feel/draft/payee-iso20022-fund-transfer-DFSPID.bpmn b/ph-ee-env-labs/orchestration/feel/draft/payee-iso20022-fund-transfer-DFSPID.bpmn new file mode 100644 index 000000000..5da052811 --- /dev/null +++ b/ph-ee-env-labs/orchestration/feel/draft/payee-iso20022-fund-transfer-DFSPID.bpmn @@ -0,0 +1,400 @@ + + + + + SequenceFlow_1ujj7bf + + + + + + + SequenceFlow_1ujj7bf + SequenceFlow_1uur72v + + + + + + + SequenceFlow_1u2a2b3 + SequenceFlow_1uur72v + SequenceFlow_1g75hpz + + + + SequenceFlow_1g75hpz + SequenceFlow_11umrph + + + SequenceFlow_11umrph + SequenceFlow_1t0fplh + SequenceFlow_1lozpuf + + + + + SequenceFlow_1cxw3ik + SequenceFlow_12qgsxa + SequenceFlow_1kfsrrq + + + + SequenceFlow_0ligfjf + + PT60S + + + + SequenceFlow_0ligfjf + SequenceFlow_1u2a2b3 + SequenceFlow_10fbgld + + + + =sendResponseRetryCount < 3 + + + + SequenceFlow_0wgm093 + + + + + + + SequenceFlow_10fbgld + SequenceFlow_0wgm093 + + + =forwardMojaloop = true + + + SequenceFlow_1kfsrrq + + + + + + + SequenceFlow_12qgsxa + SequenceFlow_0nufa3t + + + + SequenceFlow_0nufa3t + + + SequenceFlow_1lozpuf + + + =settlementFailed = true + + + SequenceFlow_19c5mv1 + SequenceFlow_1cxw3ik + SequenceFlow_1rk0kts + + + + + + SequenceFlow_1es78pe + SequenceFlow_13i7ykb + + + SequenceFlow_13i7ykb + SequenceFlow_0jubcs1 + SequenceFlow_0ykpqal + + + + + =transferCreateFailed = true + + + + + + SequenceFlow_1rk0kts + SequenceFlow_1es78pe + + + + + SequenceFlow_0ykpqal + + + =operatorStop = true + + + + + + SequenceFlow_1t0fplh + SequenceFlow_0jubcs1 + SequenceFlow_19c5mv1 + + + + + + + + ISO20022 pacs.002 SendStatusReportRequest + + + + ISO20022 pacs.008 SendCreditTransferRequest + + + + ISO20022 pacs.002 SendCreditTransferResponse + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ph-ee-env-labs/orchestration/feel/example/PayeePartyLookup-gorilla.bpmn b/ph-ee-env-labs/orchestration/feel/example/PayeePartyLookup-gorilla.bpmn new file mode 100644 index 000000000..6cf96a662 --- /dev/null +++ b/ph-ee-env-labs/orchestration/feel/example/PayeePartyLookup-gorilla.bpmn @@ -0,0 +1,83 @@ + + + + + SequenceFlow_1jawp7n + + + + + + + SequenceFlow_1jawp7n + SequenceFlow_0vk18w4 + + + + + + SequenceFlow_0vk18w4 + SequenceFlow_1cpr2t7 + + + SequenceFlow_1cpr2t7 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ph-ee-env-labs/orchestration/feel/example/PayeePartyLookup-rhino.bpmn b/ph-ee-env-labs/orchestration/feel/example/PayeePartyLookup-rhino.bpmn new file mode 100644 index 000000000..11ff696f9 --- /dev/null +++ b/ph-ee-env-labs/orchestration/feel/example/PayeePartyLookup-rhino.bpmn @@ -0,0 +1,83 @@ + + + + + SequenceFlow_1jawp7n + + + + + + + SequenceFlow_1jawp7n + SequenceFlow_0vk18w4 + + + + + + SequenceFlow_0vk18w4 + SequenceFlow_1cpr2t7 + + + SequenceFlow_1cpr2t7 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ph-ee-env-labs/orchestration/feel/example/PayeeQuoteTransfer-gorilla.bpmn b/ph-ee-env-labs/orchestration/feel/example/PayeeQuoteTransfer-gorilla.bpmn new file mode 100644 index 000000000..e49ffd9e2 --- /dev/null +++ b/ph-ee-env-labs/orchestration/feel/example/PayeeQuoteTransfer-gorilla.bpmn @@ -0,0 +1,403 @@ + + + + + SequenceFlow_0upmeol + + + + + + + SequenceFlow_0upmeol + SequenceFlow_07ubxkp + + + + + + SequenceFlow_12altlz + SequenceFlow_1871cq3 + + + SequenceFlow_1yi59vy + + + SequenceFlow_1871cq3 + SequenceFlow_0ha729a + SequenceFlow_0tifm4f + SequenceFlow_1rjfrgt + + + SequenceFlow_0ha729a + SequenceFlow_0j1b0rd + + + + + SequenceFlow_1rjfrgt + SequenceFlow_1dg7uh7 + + PT60S + + + + + + + SequenceFlow_04hdoau + SequenceFlow_00cmaa9 + + + + + + SequenceFlow_1nhsyf3 + SequenceFlow_0qveqrp + + + SequenceFlow_07ubxkp + SequenceFlow_12altlz + SequenceFlow_1l50z66 + + + + + + + SequenceFlow_0j1b0rd + SequenceFlow_1tkl7ok + + + + + SequenceFlow_1b5fd21 + + + + + + SequenceFlow_0gp1sbx + SequenceFlow_1b5fd21 + + + + SequenceFlow_1tkl7ok + SequenceFlow_1nxdko8 + SequenceFlow_0gp1sbx + + + + =quoteFailed = true + + + SequenceFlow_0tifm4f + SequenceFlow_0bhw2cx + + + + + + SequenceFlow_1dg7uh7 + + + SequenceFlow_0bhw2cx + + + SequenceFlow_1l50z66 + + + + + + + SequenceFlow_1nxdko8 + SequenceFlow_04hdoau + SequenceFlow_1nhsyf3 + + + + =transferCreateFailed = true + + + + SequenceFlow_00cmaa9 + SequenceFlow_0qveqrp + SequenceFlow_1yi59vy + + + + + + + + + + + + add timeout dynamically for transfer and rtp? + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ph-ee-env-labs/orchestration/feel/example/PayeeQuoteTransfer-rhino.bpmn b/ph-ee-env-labs/orchestration/feel/example/PayeeQuoteTransfer-rhino.bpmn new file mode 100644 index 000000000..882998baf --- /dev/null +++ b/ph-ee-env-labs/orchestration/feel/example/PayeeQuoteTransfer-rhino.bpmn @@ -0,0 +1,403 @@ + + + + + SequenceFlow_0upmeol + + + + + + + SequenceFlow_0upmeol + SequenceFlow_07ubxkp + + + + + + SequenceFlow_12altlz + SequenceFlow_1871cq3 + + + SequenceFlow_1yi59vy + + + SequenceFlow_1871cq3 + SequenceFlow_0ha729a + SequenceFlow_0tifm4f + SequenceFlow_1rjfrgt + + + SequenceFlow_0ha729a + SequenceFlow_0j1b0rd + + + + + SequenceFlow_1rjfrgt + SequenceFlow_1dg7uh7 + + PT60S + + + + + + + SequenceFlow_04hdoau + SequenceFlow_00cmaa9 + + + + + + SequenceFlow_1nhsyf3 + SequenceFlow_0qveqrp + + + SequenceFlow_07ubxkp + SequenceFlow_12altlz + SequenceFlow_1l50z66 + + + + + + + SequenceFlow_0j1b0rd + SequenceFlow_1tkl7ok + + + + + SequenceFlow_1b5fd21 + + + + + + SequenceFlow_0gp1sbx + SequenceFlow_1b5fd21 + + + + SequenceFlow_1tkl7ok + SequenceFlow_1nxdko8 + SequenceFlow_0gp1sbx + + + + =quoteFailed = true + + + SequenceFlow_0tifm4f + SequenceFlow_0bhw2cx + + + + + + SequenceFlow_1dg7uh7 + + + SequenceFlow_0bhw2cx + + + SequenceFlow_1l50z66 + + + + + + + SequenceFlow_1nxdko8 + SequenceFlow_04hdoau + SequenceFlow_1nhsyf3 + + + + =transferCreateFailed = true + + + + SequenceFlow_00cmaa9 + SequenceFlow_0qveqrp + SequenceFlow_1yi59vy + + + + + + + + + + + + add timeout dynamically for transfer and rtp? + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ph-ee-env-labs/orchestration/feel/example/PayerFundTransfer-gorilla.bpmn b/ph-ee-env-labs/orchestration/feel/example/PayerFundTransfer-gorilla.bpmn new file mode 100644 index 000000000..5946f72ee --- /dev/null +++ b/ph-ee-env-labs/orchestration/feel/example/PayerFundTransfer-gorilla.bpmn @@ -0,0 +1,1028 @@ + + + + + SequenceFlow_1pymsem + + + + + SequenceFlow_0h8jckr + SequenceFlow_06tbhc9 + + + SequenceFlow_1ffxwgp + SequenceFlow_0uphhfj + + + + + + SequenceFlow_1pymsem + SequenceFlow_0vrua4x + SequenceFlow_0h8jckr + + + + + + SequenceFlow_0ew6rln + SequenceFlow_0q7anwv + + + SequenceFlow_12nueew + SequenceFlow_09gkp54 + SequenceFlow_0zniywb + + + + + + SequenceFlow_09gkp54 + SequenceFlow_11uuh51 + SequenceFlow_1eicyj6 + + + =quoteRetryCount < 3 + + + + + + + + SequenceFlow_0zniywb + SequenceFlow_1d2huaz + SequenceFlow_0t11r3b + SequenceFlow_1l16e8u + SequenceFlow_0eh0472 + SequenceFlow_1oanf9v + SequenceFlow_1bb7vzi + + + + + + + SequenceFlow_01tpjgc + SequenceFlow_1ffxwgp + + + SequenceFlow_0uphhfj + SequenceFlow_1oanf9v + SequenceFlow_0jl4afa + + + + SequenceFlow_1bb7vzi + + + SequenceFlow_03gw2ot + SequenceFlow_0fyvo3u + SequenceFlow_0ew6rln + SequenceFlow_1d2huaz + + + + =quoteFailed = true + + + SequenceFlow_06tbhc9 + SequenceFlow_11uuh51 + SequenceFlow_0t11r3b + + + + =partyLookupFailed = true + + + SequenceFlow_0u5ni5c + + PT60S + + + + SequenceFlow_0q7anwv + SequenceFlow_01tpjgc + SequenceFlow_1l16e8u + + + + + =localQuoteFailed = true + + + SequenceFlow_0u5ni5c + SequenceFlow_0vrua4x + SequenceFlow_0eh0472 + + + + =partyLookupRetryCount < 3 + + + + + + =payerConfirmed = true + + + SequenceFlow_1eicyj6 + SequenceFlow_15wc77c + SequenceFlow_0h2j62g + SequenceFlow_087rb2p + + + + + SequenceFlow_15wc77c + SequenceFlow_03gw2ot + + + + + SequenceFlow_0h2j62g + SequenceFlow_0fyvo3u + + + + + + SequenceFlow_087rb2p + SequenceFlow_12nueew + + PT60S + + + + + + SequenceFlow_021l36b + SequenceFlow_0hjdph9 + + + SequenceFlow_0zv37c6 + + + + + + SequenceFlow_0jl4afa + SequenceFlow_0dt42vk + + + + + + SequenceFlow_1a0pfuq + SequenceFlow_1ptml7u + SequenceFlow_021l36b + + + + + + SequenceFlow_1222rpl + SequenceFlow_1k13ccu + SequenceFlow_1emjz5s + + + SequenceFlow_039x2o8 + SequenceFlow_1a0pfuq + SequenceFlow_1u7fhxg + + + SequenceFlow_0hjdph9 + SequenceFlow_11ybwbd + SequenceFlow_1222rpl + SequenceFlow_1ic2uyb + + + + + + SequenceFlow_02o4g3y + SequenceFlow_0zv37c6 + + + + + + SequenceFlow_1f823z7 + SequenceFlow_0r1oaqw + + + + + + SequenceFlow_1u7fhxg + SequenceFlow_1md51ht + + + + + + SequenceFlow_1ic2uyb + SequenceFlow_0wlity5 + SequenceFlow_1gmvm2h + + + SequenceFlow_0jviy8g + SequenceFlow_11ybwbd + SequenceFlow_0udfio5 + + + + + + SequenceFlow_13qetbt + SequenceFlow_0jviy8g + + + SequenceFlow_0dt42vk + SequenceFlow_1ptml7u + SequenceFlow_1f823z7 + + + SequenceFlow_1emjz5s + SequenceFlow_02o4g3y + SequenceFlow_0t11txa + + + + + + SequenceFlow_1md51ht + SequenceFlow_13qetbt + + + SequenceFlow_0ntctr3 + + + SequenceFlow_0r1oaqw + + + SequenceFlow_1gmvm2h + SequenceFlow_17okil0 + SequenceFlow_0jgx2x0 + + + SequenceFlow_0ogstcm + + + + + + SequenceFlow_0t11txa + SequenceFlow_1g74z3o + + + + + + SequenceFlow_0jgx2x0 + SequenceFlow_1tq3ry1 + + + + + + SequenceFlow_1g74z3o + SequenceFlow_0xh7fo1 + + + + + + SequenceFlow_1tq3ry1 + SequenceFlow_1k0in2i + + + SequenceFlow_1k0in2i + SequenceFlow_0wlity5 + SequenceFlow_0ntctr3 + + + + + + SequenceFlow_17okil0 + SequenceFlow_0ogstcm + + + SequenceFlow_0xh7fo1 + SequenceFlow_1k13ccu + SequenceFlow_14hz2nf + + + SequenceFlow_14hz2nf + + + SequenceFlow_0udfio5 + + + SequenceFlow_039x2o8 + + PT60S + + + + + + + + =transferRetryCount < 3 + + + + + + + + + + =transferFailed = true or transferState != "COMMITTED" + + + + =transferPrepareFailed = true + + + + + + + + =operatorManualOverride = true + + + + =transferCreateFailed = true + + + =operatorManualOverride = true + + + + =transferReleaseFailed = true + + + + + + + + =operatorManualOverride = true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ph-ee-env-labs/orchestration/feel/example/PayerFundTransfer-rhino.bpmn b/ph-ee-env-labs/orchestration/feel/example/PayerFundTransfer-rhino.bpmn new file mode 100644 index 000000000..d1d944929 --- /dev/null +++ b/ph-ee-env-labs/orchestration/feel/example/PayerFundTransfer-rhino.bpmn @@ -0,0 +1,1028 @@ + + + + + SequenceFlow_1pymsem + + + + + SequenceFlow_0h8jckr + SequenceFlow_06tbhc9 + + + SequenceFlow_1ffxwgp + SequenceFlow_0uphhfj + + + + + + SequenceFlow_1pymsem + SequenceFlow_0vrua4x + SequenceFlow_0h8jckr + + + + + + SequenceFlow_0ew6rln + SequenceFlow_0q7anwv + + + SequenceFlow_12nueew + SequenceFlow_09gkp54 + SequenceFlow_0zniywb + + + + + + SequenceFlow_09gkp54 + SequenceFlow_11uuh51 + SequenceFlow_1eicyj6 + + + =quoteRetryCount < 3 + + + + + + + + SequenceFlow_0zniywb + SequenceFlow_1d2huaz + SequenceFlow_0t11r3b + SequenceFlow_1l16e8u + SequenceFlow_0eh0472 + SequenceFlow_1oanf9v + SequenceFlow_1bb7vzi + + + + + + + SequenceFlow_01tpjgc + SequenceFlow_1ffxwgp + + + SequenceFlow_0uphhfj + SequenceFlow_1oanf9v + SequenceFlow_0jl4afa + + + + SequenceFlow_1bb7vzi + + + SequenceFlow_03gw2ot + SequenceFlow_0fyvo3u + SequenceFlow_0ew6rln + SequenceFlow_1d2huaz + + + + =quoteFailed = true + + + SequenceFlow_06tbhc9 + SequenceFlow_11uuh51 + SequenceFlow_0t11r3b + + + + =partyLookupFailed = true + + + SequenceFlow_0u5ni5c + + PT60S + + + + SequenceFlow_0q7anwv + SequenceFlow_01tpjgc + SequenceFlow_1l16e8u + + + + + =localQuoteFailed = true + + + SequenceFlow_0u5ni5c + SequenceFlow_0vrua4x + SequenceFlow_0eh0472 + + + + =partyLookupRetryCount < 3 + + + + + + =payerConfirmed = true + + + SequenceFlow_1eicyj6 + SequenceFlow_15wc77c + SequenceFlow_0h2j62g + SequenceFlow_087rb2p + + + + + SequenceFlow_15wc77c + SequenceFlow_03gw2ot + + + + + SequenceFlow_0h2j62g + SequenceFlow_0fyvo3u + + + + + + SequenceFlow_087rb2p + SequenceFlow_12nueew + + PT60S + + + + + + SequenceFlow_021l36b + SequenceFlow_0hjdph9 + + + SequenceFlow_0zv37c6 + + + + + + SequenceFlow_0jl4afa + SequenceFlow_0dt42vk + + + + + + SequenceFlow_1a0pfuq + SequenceFlow_1ptml7u + SequenceFlow_021l36b + + + + + + SequenceFlow_1222rpl + SequenceFlow_1k13ccu + SequenceFlow_1emjz5s + + + SequenceFlow_039x2o8 + SequenceFlow_1a0pfuq + SequenceFlow_1u7fhxg + + + SequenceFlow_0hjdph9 + SequenceFlow_11ybwbd + SequenceFlow_1222rpl + SequenceFlow_1ic2uyb + + + + + + SequenceFlow_02o4g3y + SequenceFlow_0zv37c6 + + + + + + SequenceFlow_1f823z7 + SequenceFlow_0r1oaqw + + + + + + SequenceFlow_1u7fhxg + SequenceFlow_1md51ht + + + + + + SequenceFlow_1ic2uyb + SequenceFlow_0wlity5 + SequenceFlow_1gmvm2h + + + SequenceFlow_0jviy8g + SequenceFlow_11ybwbd + SequenceFlow_0udfio5 + + + + + + SequenceFlow_13qetbt + SequenceFlow_0jviy8g + + + SequenceFlow_0dt42vk + SequenceFlow_1ptml7u + SequenceFlow_1f823z7 + + + SequenceFlow_1emjz5s + SequenceFlow_02o4g3y + SequenceFlow_0t11txa + + + + + + SequenceFlow_1md51ht + SequenceFlow_13qetbt + + + SequenceFlow_0ntctr3 + + + SequenceFlow_0r1oaqw + + + SequenceFlow_1gmvm2h + SequenceFlow_17okil0 + SequenceFlow_0jgx2x0 + + + SequenceFlow_0ogstcm + + + + + + SequenceFlow_0t11txa + SequenceFlow_1g74z3o + + + + + + SequenceFlow_0jgx2x0 + SequenceFlow_1tq3ry1 + + + + + + SequenceFlow_1g74z3o + SequenceFlow_0xh7fo1 + + + + + + SequenceFlow_1tq3ry1 + SequenceFlow_1k0in2i + + + SequenceFlow_1k0in2i + SequenceFlow_0wlity5 + SequenceFlow_0ntctr3 + + + + + + SequenceFlow_17okil0 + SequenceFlow_0ogstcm + + + SequenceFlow_0xh7fo1 + SequenceFlow_1k13ccu + SequenceFlow_14hz2nf + + + SequenceFlow_14hz2nf + + + SequenceFlow_0udfio5 + + + SequenceFlow_039x2o8 + + PT60S + + + + + + + + =transferRetryCount < 3 + + + + + + + + + + =transferFailed = true or transferState != "COMMITTED" + + + + =transferPrepareFailed = true + + + + + + + + =operatorManualOverride = true + + + + =transferCreateFailed = true + + + =operatorManualOverride = true + + + + =transferReleaseFailed = true + + + + + + + + =operatorManualOverride = true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ph-ee-env-labs/orchestration/feel/example/gsma_base_transaction-gorilla.bpmn b/ph-ee-env-labs/orchestration/feel/example/gsma_base_transaction-gorilla.bpmn new file mode 100644 index 000000000..40659964f --- /dev/null +++ b/ph-ee-env-labs/orchestration/feel/example/gsma_base_transaction-gorilla.bpmn @@ -0,0 +1,467 @@ + + + + + Flow_1iz4su9 + + + Flow_1khpy8b + + + + + + + Flow_0drcaub + Flow_0r7t1vh + Flow_0fq2w8b + + + Flow_0fq2w8b + Flow_0z3yk8q + + + Flow_16b1s15 + + PT60S + + + + Flow_16b1s15 + Flow_0drcaub + Flow_177y51s + + + =payeeAccountStatusRetry < 3 + + + + Flow_0z3yk8q + Flow_1rd2qbu + Flow_06fadz1 + + + + Flow_0vfzj5k + Flow_1oiw1si + Flow_1yuhu0t + + + + + + Flow_0s5yx0e + Flow_0vfzj5k + + + + + + Flow_1yuhu0t + Flow_04sgr67 + Flow_11fn478 + + + + + + + Flow_1g9y30t + Flow_1khpy8b + + + Flow_126dexs + + PT60S + + + + Flow_126dexs + Flow_150jms5 + Flow_1lf6hxg + + + + =paymentTransferRetry < 3 + + + Flow_1rbhwaj + + + =partyLookupFailed = true + + + =transactionFailed = true + + + Flow_1rd8f1u + + + + + + + + + + Flow_177y51s + Flow_1lf6hxg + Flow_1rd8f1u + + + + + + + Flow_1rd2qbu + Flow_0vpl387 + Flow_0o49cl4 + Flow_1rbhwaj + + + + + + Flow_06fadz1 + Flow_1ojxhgg + + + Flow_1ojxhgg + Flow_0vpl387 + Flow_0s5yx0e + + + + + + + Flow_04sgr67 + Flow_11ks5lq + + + Flow_11ks5lq + Flow_0ygr2i6 + Flow_1g9y30t + + + + =transferPrepareFailed = true + + + =transferCreateFailed = true + + + + + + + + Flow_11fn478 + Flow_03o1q44 + + + + + + Flow_1kzho50 + Flow_0ygr2i6 + Flow_02nd84o + + + Flow_02nd84o + + + + Flow_03o1q44 + Flow_1kzho50 + Flow_0o49cl4 + + + + =transferReleaseFailed = true + + + + + + + Flow_1iz4su9 + Flow_0r7t1vh + + + + + + + + Flow_150jms5 + Flow_1oiw1si + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ph-ee-env-labs/orchestration/feel/example/gsma_base_transaction-rhino.bpmn b/ph-ee-env-labs/orchestration/feel/example/gsma_base_transaction-rhino.bpmn new file mode 100644 index 000000000..d1d738c90 --- /dev/null +++ b/ph-ee-env-labs/orchestration/feel/example/gsma_base_transaction-rhino.bpmn @@ -0,0 +1,467 @@ + + + + + Flow_1iz4su9 + + + Flow_1khpy8b + + + + + + + Flow_0drcaub + Flow_0r7t1vh + Flow_0fq2w8b + + + Flow_0fq2w8b + Flow_0z3yk8q + + + Flow_16b1s15 + + PT60S + + + + Flow_16b1s15 + Flow_0drcaub + Flow_177y51s + + + =payeeAccountStatusRetry < 3 + + + + Flow_0z3yk8q + Flow_1rd2qbu + Flow_06fadz1 + + + + Flow_0vfzj5k + Flow_1oiw1si + Flow_1yuhu0t + + + + + + Flow_0s5yx0e + Flow_0vfzj5k + + + + + + Flow_1yuhu0t + Flow_04sgr67 + Flow_11fn478 + + + + + + + Flow_1g9y30t + Flow_1khpy8b + + + Flow_126dexs + + PT60S + + + + Flow_126dexs + Flow_150jms5 + Flow_1lf6hxg + + + + =paymentTransferRetry < 3 + + + Flow_1rbhwaj + + + =partyLookupFailed = true + + + =transactionFailed = true + + + Flow_1rd8f1u + + + + + + + + + + Flow_177y51s + Flow_1lf6hxg + Flow_1rd8f1u + + + + + + + Flow_1rd2qbu + Flow_0vpl387 + Flow_0o49cl4 + Flow_1rbhwaj + + + + + + Flow_06fadz1 + Flow_1ojxhgg + + + Flow_1ojxhgg + Flow_0vpl387 + Flow_0s5yx0e + + + + + + + Flow_04sgr67 + Flow_11ks5lq + + + Flow_11ks5lq + Flow_0ygr2i6 + Flow_1g9y30t + + + + =transferPrepareFailed = true + + + =transferCreateFailed = true + + + + + + + + Flow_11fn478 + Flow_03o1q44 + + + + + + Flow_1kzho50 + Flow_0ygr2i6 + Flow_02nd84o + + + Flow_02nd84o + + + + Flow_03o1q44 + Flow_1kzho50 + Flow_0o49cl4 + + + + =transferReleaseFailed = true + + + + + + + Flow_1iz4su9 + Flow_0r7t1vh + + + + + + + + Flow_150jms5 + Flow_1oiw1si + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ph-ee-env-labs/orchestration/feel/example/international_remittance_payee_process-gorilla.bpmn b/ph-ee-env-labs/orchestration/feel/example/international_remittance_payee_process-gorilla.bpmn new file mode 100644 index 000000000..b4456dcc3 --- /dev/null +++ b/ph-ee-env-labs/orchestration/feel/example/international_remittance_payee_process-gorilla.bpmn @@ -0,0 +1,77 @@ + + + + + Flow_1oh4r14 + + + + + + Flow_1oh4r14 + Flow_15u0t1f + + + Flow_0dl6v3u + + + + + Flow_15u0t1f + Flow_0dl6v3u + Flow_1ybr1l5 + + + + =transferCreateFailed = true + + + Flow_1ybr1l5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ph-ee-env-labs/orchestration/feel/example/international_remittance_payee_process-rhino.bpmn b/ph-ee-env-labs/orchestration/feel/example/international_remittance_payee_process-rhino.bpmn new file mode 100644 index 000000000..5853382ac --- /dev/null +++ b/ph-ee-env-labs/orchestration/feel/example/international_remittance_payee_process-rhino.bpmn @@ -0,0 +1,77 @@ + + + + + Flow_1oh4r14 + + + + + + Flow_1oh4r14 + Flow_15u0t1f + + + Flow_0dl6v3u + + + + + Flow_15u0t1f + Flow_0dl6v3u + Flow_1ybr1l5 + + + + =transferCreateFailed = true + + + Flow_1ybr1l5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ph-ee-env-labs/orchestration/feel/gsma-p2p-account-lookup.bpmn b/ph-ee-env-labs/orchestration/feel/gsma-p2p-account-lookup.bpmn new file mode 100644 index 000000000..6e0953629 --- /dev/null +++ b/ph-ee-env-labs/orchestration/feel/gsma-p2p-account-lookup.bpmn @@ -0,0 +1,493 @@ + + + + + Flow_1iz4su9 + + + Flow_1khpy8b + + + + + + + Flow_0drcaub + Flow_0r7t1vh + Flow_0fq2w8b + + + Flow_0fq2w8b + Flow_0z3yk8q + + + Flow_16b1s15 + + PT60S + + + + Flow_16b1s15 + Flow_0drcaub + Flow_177y51s + + + =payeeAccountStatusRetry < 3 + + + + Flow_0z3yk8q + Flow_1sh7v1m + Flow_1rd2qbu + + + + + Flow_0vfzj5k + Flow_1yuhu0t + + + + + + Flow_150jms5 + Flow_0s5yx0e + Flow_0vfzj5k + + + + + + Flow_1yuhu0t + Flow_04sgr67 + Flow_11fn478 + + + + + + + Flow_1g9y30t + Flow_1khpy8b + + + Flow_126dexs + + PT60S + + + + Flow_126dexs + Flow_150jms5 + Flow_1lf6hxg + + + + =paymentTransferRetry < 3 + + + Flow_1rbhwaj + + + =partyLookupFailed = true + + + =transactionFailed = true + + + Flow_1rd8f1u + + + + + + + + + + Flow_177y51s + Flow_1lf6hxg + Flow_1rd8f1u + + + + + + + Flow_1rd2qbu + Flow_192jsmu + Flow_0vpl387 + Flow_0o49cl4 + Flow_1rbhwaj + + + + + + Flow_1sh7v1m + Flow_1orxtvv + + + Flow_1orxtvv + Flow_192jsmu + Flow_0fw3ncg + + + =localQuoteFailed = true + + + + + + + + Flow_0fw3ncg + Flow_1ojxhgg + + + Flow_1ojxhgg + Flow_0vpl387 + Flow_0s5yx0e + + + + + + + Flow_04sgr67 + Flow_11ks5lq + + + Flow_11ks5lq + Flow_0ygr2i6 + Flow_1g9y30t + + + + =transferPrepareFailed = true + + + =transferCreateFailed = true + + + + + + + + Flow_11fn478 + Flow_03o1q44 + + + + + + Flow_1kzho50 + Flow_0ygr2i6 + Flow_02nd84o + + + Flow_02nd84o + + + + Flow_03o1q44 + Flow_1kzho50 + Flow_0o49cl4 + + + + =transferReleaseFailed = true + + + + + + + Flow_1iz4su9 + Flow_0r7t1vh + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ph-ee-env-labs/orchestration/feel/gsma-p2p-wo-local-quote.bpmn b/ph-ee-env-labs/orchestration/feel/gsma-p2p-wo-local-quote.bpmn new file mode 100644 index 000000000..92d08986d --- /dev/null +++ b/ph-ee-env-labs/orchestration/feel/gsma-p2p-wo-local-quote.bpmn @@ -0,0 +1,509 @@ + + + + + Flow_0msknqm + + + Flow_1khpy8b + + + + + + + Flow_0drcaub + Flow_0r7t1vh + Flow_0fq2w8b + + + Flow_0fq2w8b + Flow_0z3yk8q + + + Flow_16b1s15 + + PT60S + + + + Flow_16b1s15 + Flow_0drcaub + Flow_177y51s + + + =payeeAccountStatusRetry < 3 + + + + Flow_0z3yk8q + Flow_1rd2qbu + Flow_06fadz1 + + + + Flow_0vfzj5k + Flow_1oiw1si + Flow_1yuhu0t + + + + + + Flow_0s5yx0e + Flow_0vfzj5k + + + + + + Flow_1yuhu0t + Flow_04sgr67 + Flow_11fn478 + + + + + + + Flow_1g9y30t + Flow_1khpy8b + + + Flow_126dexs + + PT60S + + + + Flow_126dexs + Flow_150jms5 + Flow_1lf6hxg + + + + =paymentTransferRetry < 3 + + + Flow_1rbhwaj + Flow_0nysfrk + + + =partyLookupFailed = true + + + =transactionFailed = true + + + Flow_1rd8f1u + + + + + + + + + Flow_177y51s + Flow_1lf6hxg + Flow_1rd8f1u + + + + + + + Flow_1rd2qbu + Flow_0vpl387 + Flow_0o49cl4 + Flow_1rbhwaj + + + + + + Flow_06fadz1 + Flow_1ojxhgg + + + Flow_1ojxhgg + Flow_0vpl387 + Flow_0s5yx0e + + + + + + + Flow_04sgr67 + Flow_11ks5lq + + + Flow_11ks5lq + Flow_0ygr2i6 + Flow_1g9y30t + + + + =transferPrepareFailed = true + + + =transferCreateFailed = true + + + + + + + + Flow_11fn478 + Flow_03o1q44 + + + + + + Flow_1kzho50 + Flow_0ygr2i6 + Flow_02nd84o + + + Flow_02nd84o + + + + Flow_03o1q44 + Flow_1kzho50 + Flow_0o49cl4 + + + + =transferReleaseFailed = true + + + + + + + Flow_1n2xz2x + Flow_0r7t1vh + + + + + + + + Flow_150jms5 + Flow_1oiw1si + + + + + + + Flow_0msknqm + Flow_1156tbw + + + + Flow_1156tbw + Flow_1n2xz2x + Flow_0nysfrk + + + + + = isTxnValid = false + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ph-ee-env-labs/orchestration/feel/gsma-p2p.bpmn b/ph-ee-env-labs/orchestration/feel/gsma-p2p.bpmn new file mode 100644 index 000000000..cd5d9d079 --- /dev/null +++ b/ph-ee-env-labs/orchestration/feel/gsma-p2p.bpmn @@ -0,0 +1,491 @@ + + + + + Flow_1iz4su9 + + + Flow_1khpy8b + + + + + + + Flow_0drcaub + Flow_0r7t1vh + Flow_0fq2w8b + + + Flow_0fq2w8b + Flow_0z3yk8q + + + Flow_16b1s15 + + PT60S + + + + Flow_16b1s15 + Flow_0drcaub + Flow_177y51s + + + =payeeAccountStatusRetry < 3 + + + + Flow_0z3yk8q + Flow_1sh7v1m + Flow_1rd2qbu + + + + + Flow_0vfzj5k + Flow_1yuhu0t + + + + + + Flow_150jms5 + Flow_0s5yx0e + Flow_0vfzj5k + + + + + + Flow_1yuhu0t + Flow_04sgr67 + Flow_11fn478 + + + + + + + Flow_1g9y30t + Flow_1khpy8b + + + Flow_126dexs + + PT60S + + + + Flow_126dexs + Flow_150jms5 + Flow_1lf6hxg + + + + =paymentTransferRetry < 3 + + + Flow_1rbhwaj + + + =partyLookupFailed = true + + + =transactionFailed = true + + + Flow_1rd8f1u + + + + + + + + + + Flow_177y51s + Flow_1lf6hxg + Flow_1rd8f1u + + + + + + + Flow_1rd2qbu + Flow_192jsmu + Flow_0vpl387 + Flow_0o49cl4 + Flow_1rbhwaj + + + + + + Flow_1sh7v1m + Flow_1orxtvv + + + Flow_1orxtvv + Flow_192jsmu + Flow_0fw3ncg + + + =localQuoteFailed = true + + + + + + + + Flow_0fw3ncg + Flow_1ojxhgg + + + Flow_1ojxhgg + Flow_0vpl387 + Flow_0s5yx0e + + + + + + + Flow_04sgr67 + Flow_11ks5lq + + + Flow_11ks5lq + Flow_0ygr2i6 + Flow_1g9y30t + + + + =transferPrepareFailed = true + + + =transferCreateFailed = true + + + + + + + + Flow_11fn478 + Flow_03o1q44 + + + + + + Flow_1kzho50 + Flow_0ygr2i6 + Flow_02nd84o + + + Flow_02nd84o + + + + Flow_03o1q44 + Flow_1kzho50 + Flow_0o49cl4 + + + + =transferReleaseFailed = true + + + + + + + Flow_1iz4su9 + Flow_0r7t1vh + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ph-ee-env-labs/orchestration/feel/gsma-payee-process.bpmn b/ph-ee-env-labs/orchestration/feel/gsma-payee-process.bpmn new file mode 100644 index 000000000..52263ee92 --- /dev/null +++ b/ph-ee-env-labs/orchestration/feel/gsma-payee-process.bpmn @@ -0,0 +1,288 @@ + + + + + Flow_1jp0uac + + + + + + Flow_1jp0uac + Flow_1qylaeu + + + Flow_1eioo1e + + + Flow_0l4vst0 + Flow_0bb479o + Flow_0whzjay + Flow_1rwwmqg + + + Flow_0bb479o + Flow_0qf8vno + + + + Flow_1rwwmqg + Flow_1idno0h + + PT60S + + + + + + + Flow_0i2fojt + Flow_1eioo1e + + + Flow_1qylaeu + Flow_0l4vst0 + Flow_0kma2kd + + + + + + Flow_0qf8vno + Flow_16vrj0s + + + Flow_0kp58m6 + + + Flow_16vrj0s + Flow_1no09i2 + Flow_0i2fojt + + + Flow_0whzjay + Flow_0rtotew + + + + Flow_1idno0h + + + Flow_0rtotew + + + Flow_0kma2kd + + + + + + + + + + + + =quoteFailed = true + + + + =transferCreateFailed = true + + + + + + + + Flow_1no09i2 + Flow_0kp58m6 + + + + + + add timeout dynamically for transfer and rtp? + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ph-ee-env-labs/orchestration/feel/gsma-payee-transfer.bpmn b/ph-ee-env-labs/orchestration/feel/gsma-payee-transfer.bpmn new file mode 100644 index 000000000..8e8b02e4a --- /dev/null +++ b/ph-ee-env-labs/orchestration/feel/gsma-payee-transfer.bpmn @@ -0,0 +1,383 @@ + + + + + Flow_0ao1g7c + + + Flow_1v5iuvx + Flow_07p7x6s + + + Flow_07zv7t5 + Flow_0ajk81k + + + Flow_07p7x6s + Flow_0tb55c7 + Flow_00vfw5y + + + + + + Flow_0ajk81k + Flow_00vfw5y + Flow_0zwb6ut + Flow_1fsohe8 + Flow_02o8xzy + Flow_05ept57 + Flow_1a97ey7 + + + Flow_1a97ey7 + + + + + + Flow_0tb55c7 + Flow_0zoteng + Flow_0za0l9f + + + Flow_0za0l9f + Flow_070pc0z + + + Flow_1kgnsb8 + Flow_0zwb6ut + Flow_0zoteng + + + Flow_0jr8i67 + + + Flow_070pc0z + Flow_1fsohe8 + Flow_05fdird + + + + + + Flow_1jmde75 + Flow_0jr8i67 + + + Flow_1todusq + Flow_02o8xzy + Flow_1jmde75 + Flow_1wy69jw + + + Flow_07zv7t5 + + PT60S + + + + Flow_1kgnsb8 + + PT60S + + + + + + + + =partyLookupFailed = true + + + + =transactionRequestFailed = true + + + =transactionState != "ACCEPTED" + + + + + =transactionRequestRetryCount < 3 + + + + + + + + =isAuthorisationRequired and (transactionRequestFailed = true or transActionState = "REJECTED") + + + + + + Flow_0ao1g7c + Flow_1v5iuvx + + + + + Flow_0rvu1jq + Flow_05fdird + Flow_1todusq + + + Flow_1vji14u + Flow_1wy69jw + Flow_0rvu1jq + Flow_05ept57 + + + Flow_1vji14u + + PT60S + + + + =isAuthorisationRequired = true and authRetriesLeftCount < authRetriesLeft + + + + + + Starts GSMA peer to peer transfer flow from payer side + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ph-ee-env-labs/orchestration/feel/gsma_base_transaction-DFSPID.bpmn b/ph-ee-env-labs/orchestration/feel/gsma_base_transaction-DFSPID.bpmn new file mode 100644 index 000000000..bc425178a --- /dev/null +++ b/ph-ee-env-labs/orchestration/feel/gsma_base_transaction-DFSPID.bpmn @@ -0,0 +1,467 @@ + + + + + Flow_1iz4su9 + + + Flow_1khpy8b + + + + + + + Flow_0drcaub + Flow_0r7t1vh + Flow_0fq2w8b + + + Flow_0fq2w8b + Flow_0z3yk8q + + + Flow_16b1s15 + + PT60S + + + + Flow_16b1s15 + Flow_0drcaub + Flow_177y51s + + + =payeeAccountStatusRetry < 3 + + + + Flow_0z3yk8q + Flow_1rd2qbu + Flow_06fadz1 + + + + Flow_0vfzj5k + Flow_1oiw1si + Flow_1yuhu0t + + + + + + Flow_0s5yx0e + Flow_0vfzj5k + + + + + + Flow_1yuhu0t + Flow_04sgr67 + Flow_11fn478 + + + + + + + Flow_1g9y30t + Flow_1khpy8b + + + Flow_126dexs + + PT60S + + + + Flow_126dexs + Flow_150jms5 + Flow_1lf6hxg + + + + =paymentTransferRetry < 3 + + + Flow_1rbhwaj + + + =partyLookupFailed = true + + + =transactionFailed = true + + + Flow_1rd8f1u + + + + + + + + + + Flow_177y51s + Flow_1lf6hxg + Flow_1rd8f1u + + + + + + + Flow_1rd2qbu + Flow_0vpl387 + Flow_0o49cl4 + Flow_1rbhwaj + + + + + + Flow_06fadz1 + Flow_1ojxhgg + + + Flow_1ojxhgg + Flow_0vpl387 + Flow_0s5yx0e + + + + + + + Flow_04sgr67 + Flow_11ks5lq + + + Flow_11ks5lq + Flow_0ygr2i6 + Flow_1g9y30t + + + + =transferPrepareFailed = true + + + =transferCreateFailed = true + + + + + + + + Flow_11fn478 + Flow_03o1q44 + + + + + + Flow_1kzho50 + Flow_0ygr2i6 + Flow_02nd84o + + + Flow_02nd84o + + + + Flow_03o1q44 + Flow_1kzho50 + Flow_0o49cl4 + + + + =transferReleaseFailed = true + + + + + + + Flow_1iz4su9 + Flow_0r7t1vh + + + + + + + + Flow_150jms5 + Flow_1oiw1si + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ph-ee-env-labs/orchestration/feel/inbound_transfer-mifos-DFSPID.bpmn b/ph-ee-env-labs/orchestration/feel/inbound_transfer-mifos-DFSPID.bpmn new file mode 100644 index 000000000..d90fe27bf --- /dev/null +++ b/ph-ee-env-labs/orchestration/feel/inbound_transfer-mifos-DFSPID.bpmn @@ -0,0 +1,127 @@ + + + + + Flow_1qse416 + + + + + + + Flow_1qse416 + Flow_1fg54hw + + + Flow_1fg54hw + Flow_13zeayn + Flow_1drryfj + + + + = accountIdentifier = "L" + + + = accountIdentifier = "S" + + + + + + Flow_13zeayn + Flow_12wedix + + + + + + Flow_1drryfj + Flow_06gwhv5 + + + + + + Flow_12wedix + Flow_06gwhv5 + Flow_0gxopv1 + + + Flow_0gxopv1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ph-ee-env-labs/orchestration/feel/international-remittance-payee-process-DFSPID.bpmn b/ph-ee-env-labs/orchestration/feel/international-remittance-payee-process-DFSPID.bpmn new file mode 100644 index 000000000..d26fb6f2f --- /dev/null +++ b/ph-ee-env-labs/orchestration/feel/international-remittance-payee-process-DFSPID.bpmn @@ -0,0 +1,77 @@ + + + + + Flow_1oh4r14 + + + + + + Flow_1oh4r14 + Flow_15u0t1f + + + Flow_0dl6v3u + + + + + Flow_15u0t1f + Flow_0dl6v3u + Flow_1ybr1l5 + + + + =transferCreateFailed = true + + + Flow_1ybr1l5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ph-ee-env-labs/orchestration/feel/minimal_mock_fund_transfer-DFSPID.bpmn b/ph-ee-env-labs/orchestration/feel/minimal_mock_fund_transfer-DFSPID.bpmn new file mode 100644 index 000000000..312ba6464 --- /dev/null +++ b/ph-ee-env-labs/orchestration/feel/minimal_mock_fund_transfer-DFSPID.bpmn @@ -0,0 +1,176 @@ + + + + + Flow_1iz4su9 + + + Flow_0gya237 + + + + + + + Flow_1iz4su9 + Flow_0fq2w8b + + + Flow_0z3yk8q + Flow_1rd2qbu + Flow_0o8mgiy + + + + + + + Flow_0o8mgiy + Flow_0vfzj5k + + + + + Flow_1yuhu0t + Flow_0gya237 + Flow_19zt5r8 + + + Flow_1rbhwaj + + + + + + + Flow_1rd2qbu + Flow_19zt5r8 + Flow_1rbhwaj + + + + =partyLookupFailed = true + + + + + + Flow_0fq2w8b + Flow_0z3yk8q + + + Flow_0vfzj5k + Flow_1yuhu0t + + + + + =transactionFailed = true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ph-ee-env-labs/orchestration/feel/minimal_mock_fund_transfer_account_lookup-DFSPID.bpmn b/ph-ee-env-labs/orchestration/feel/minimal_mock_fund_transfer_account_lookup-DFSPID.bpmn new file mode 100644 index 000000000..ca4944bfc --- /dev/null +++ b/ph-ee-env-labs/orchestration/feel/minimal_mock_fund_transfer_account_lookup-DFSPID.bpmn @@ -0,0 +1,196 @@ + + + + + Flow_1iz4su9 + + + Flow_0gya237 + + + + + + + Flow_1iz4su9 + Flow_0fq2w8b + + + Flow_1bm2cy4 + Flow_1rd2qbu + Flow_1v5oogu + + + + + + Flow_0zhc5hk + Flow_0vfzj5k + + + + + Flow_1yuhu0t + Flow_0gya237 + Flow_19zt5r8 + + + Flow_1rbhwaj + + + + + + + Flow_1rd2qbu + Flow_19zt5r8 + Flow_1rbhwaj + + + + =accountLookupFailed = true + + + Flow_0vfzj5k + Flow_1yuhu0t + + + + = transactionFailed = true + + + + + + Flow_0fq2w8b + Flow_1bm2cy4 + + + + + + Flow_1v5oogu + Flow_0zhc5hk + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ph-ee-env-labs/orchestration/feel/minimal_mock_transfer_request-DFSPID.bpmn b/ph-ee-env-labs/orchestration/feel/minimal_mock_transfer_request-DFSPID.bpmn new file mode 100644 index 000000000..66b1a4b42 --- /dev/null +++ b/ph-ee-env-labs/orchestration/feel/minimal_mock_transfer_request-DFSPID.bpmn @@ -0,0 +1,235 @@ + + + + + Flow_1yedu1l + + + + + + Flow_1yedu1l + Flow_1sjtiii + + + Flow_1sjtiii + Flow_06amose + Flow_1hg0ktv + + + + + + Flow_1b083ea + Flow_1tgbeo8 + Flow_0oghpah + + + + Flow_1cr6ydq + Flow_1hg0ktv + Flow_0oghpah + Flow_1aprvsb + + + Flow_10mudcv + + + Flow_0bpfbzs + Flow_10mudcv + Flow_1cr6ydq + + + + + =transferSettlementFailed = true + + + + + + Flow_1tgbeo8 + Flow_0bpfbzs + + + + + + Flow_06amose + Flow_0yzbk3i + + + =partyLookupFailed = true + + + =transactionFailed = true + + + Flow_0yzbk3i + Flow_1aprvsb + Flow_0zpekcd + + + =transactionFailed = true + + + + + + Flow_1jsu94x + Flow_0xuo5p2 + + + + Flow_0zpekcd + Flow_0xuo5p2 + Flow_1b083ea + + + + + Flow_1jsu94x + + = timer + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ph-ee-env-labs/orchestration/feel/mock_payment_transfer-DFSPID.bpmn b/ph-ee-env-labs/orchestration/feel/mock_payment_transfer-DFSPID.bpmn new file mode 100644 index 000000000..e67702bd0 --- /dev/null +++ b/ph-ee-env-labs/orchestration/feel/mock_payment_transfer-DFSPID.bpmn @@ -0,0 +1,306 @@ + + + + + Flow_1iz4su9 + + + Flow_1g9y30t + + + + + + + Flow_1iz4su9 + Flow_0fq2w8b + + + Flow_0z3yk8q + Flow_1rd2qbu + Flow_15zi3ty + + + + + + + Flow_0s5yx0e + Flow_0vfzj5k + + + + + Flow_1yuhu0t + Flow_04sgr67 + Flow_11fn478 + + + + Flow_1rbhwaj + + + =transactionFailed = true + + + + + + + Flow_15zi3ty + Flow_1ojxhgg + + + Flow_1ojxhgg + Flow_0s5yx0e + Flow_0vpl387 + + + + + + + Flow_04sgr67 + Flow_11ks5lq + + + Flow_11ks5lq + Flow_0ygr2i6 + Flow_1g9y30t + + + + =transferCreateFailed = true + + + + + + + + Flow_11fn478 + Flow_03o1q44 + + + + + + Flow_05wu268 + Flow_02nd84o + + + Flow_02nd84o + + + + Flow_03o1q44 + Flow_0ygr2i6 + Flow_05wu268 + + + + + + + Flow_1rd2qbu + Flow_0vpl387 + Flow_1rbhwaj + + + + =partyLookupFailed = true + + + =transferPrepareFailed = true + + + + + + Flow_0fq2w8b + Flow_0z3yk8q + + + + Flow_0vfzj5k + Flow_1yuhu0t + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ph-ee-env-labs/orchestration/feel/mock_payment_transfer_account_lookup-DFSPID.bpmn b/ph-ee-env-labs/orchestration/feel/mock_payment_transfer_account_lookup-DFSPID.bpmn new file mode 100644 index 000000000..1f09fb6b3 --- /dev/null +++ b/ph-ee-env-labs/orchestration/feel/mock_payment_transfer_account_lookup-DFSPID.bpmn @@ -0,0 +1,358 @@ + + + + + Flow_1iz4su9 + + + Flow_1g9y30t + + + + + + + Flow_1iz4su9 + Flow_07ynm1q + Flow_0fq2w8b + + + Flow_0z3yk8q + Flow_1rd2qbu + Flow_15zi3ty + + + + + + + Flow_0s5yx0e + Flow_0vfzj5k + + + + + Flow_1yuhu0t + Flow_04sgr67 + Flow_11fn478 + + + + Flow_1rbhwaj + Flow_082bvyi + + + =transactionFailed = true + + + + + + + Flow_15zi3ty + Flow_1ojxhgg + + + Flow_1ojxhgg + Flow_0s5yx0e + Flow_0vpl387 + + + + + + + Flow_04sgr67 + Flow_11ks5lq + + + Flow_11ks5lq + Flow_0ygr2i6 + Flow_1g9y30t + + + + =transferCreateFailed = true + + + + + + + + Flow_11fn478 + Flow_03o1q44 + + + + + + Flow_05wu268 + Flow_02nd84o + + + Flow_02nd84o + + + + Flow_03o1q44 + Flow_0ygr2i6 + Flow_05wu268 + + + + + + + Flow_1rd2qbu + Flow_0vpl387 + Flow_1rbhwaj + + + + =partyLookupFailed = true + + + =transferPrepareFailed = true + + + + Flow_0vfzj5k + Flow_1yuhu0t + + + + + + + Flow_0fq2w8b + Flow_0z3yk8q + + + Flow_1mki4sp + + PT60S + + + + Flow_1mki4sp + Flow_07ynm1q + Flow_082bvyi + + + + =partyLookupRetryCount < 3 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ph-ee-env-labs/orchestration/feel/mock_payment_transfer_debit-DFSPID.bpmn b/ph-ee-env-labs/orchestration/feel/mock_payment_transfer_debit-DFSPID.bpmn new file mode 100644 index 000000000..9efdf8f91 --- /dev/null +++ b/ph-ee-env-labs/orchestration/feel/mock_payment_transfer_debit-DFSPID.bpmn @@ -0,0 +1,326 @@ + + + + + Flow_1iz4su9 + + + Flow_1g9y30t + + + + + + + Flow_1iz4su9 + Flow_0fq2w8b + + + Flow_0z3yk8q + Flow_1rd2qbu + Flow_15zi3ty + + + + + + + Flow_0s5yx0e + Flow_0vfzj5k + + + + + Flow_1yuhu0t + Flow_04sgr67 + Flow_11fn478 + + + + Flow_1rbhwaj + + + =transactionFailed = true + + + + + + + Flow_15zi3ty + Flow_1ojxhgg + + + Flow_1ojxhgg + Flow_0s5yx0e + Flow_0vpl387 + + + + + + + Flow_04sgr67 + Flow_11ks5lq + + + Flow_11ks5lq + Flow_0ygr2i6 + Flow_1g9y30t + + + + =transferCreateFailed = true + + + + + + + + Flow_11fn478 + Flow_03o1q44 + + + + + + Flow_05wu268 + Flow_02nd84o + + + Flow_02nd84o + + + + Flow_03o1q44 + Flow_0ygr2i6 + Flow_05wu268 + + + + + + + Flow_1rd2qbu + Flow_0vpl387 + Flow_1rbhwaj + + + + =partyLookupFailed = true + + + =transferPrepareFailed = true + + + + + + Flow_0fq2w8b + Flow_0z3yk8q + + + + Flow_0vfzj5k + Flow_1yuhu0t + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ph-ee-env-labs/orchestration/feel/mojaloop-account-validation.bpmn b/ph-ee-env-labs/orchestration/feel/mojaloop-account-validation.bpmn new file mode 100644 index 000000000..5bd82c799 --- /dev/null +++ b/ph-ee-env-labs/orchestration/feel/mojaloop-account-validation.bpmn @@ -0,0 +1,143 @@ + + + + + Flow_0sx1b39 + + + + + + + + Flow_0sx1b39 + Flow_0i7wdll + Flow_1ct1j5x + + + Flow_1ct1j5x + Flow_14suduk + + + Flow_11wuvd1 + + PT60S + + + + Flow_11wuvd1 + Flow_0i7wdll + Flow_1ny6eb4 + + + + =partyLookupRetryCount < 3 + + + Flow_1ny6eb4 + Flow_0ed2zt8 + + + + + + Flow_0nyneh2 + Flow_07939e1 + + + + Flow_07939e1 + + + + Flow_14suduk + Flow_0nyneh2 + Flow_0ed2zt8 + + + + + =partyLookupFailed = true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ph-ee-env-labs/orchestration/feel/party-registration-DFSPID.bpmn b/ph-ee-env-labs/orchestration/feel/party-registration-DFSPID.bpmn new file mode 100644 index 000000000..302119513 --- /dev/null +++ b/ph-ee-env-labs/orchestration/feel/party-registration-DFSPID.bpmn @@ -0,0 +1,162 @@ + + + + + SequenceFlow_0mm8w9q + + + + + + + SequenceFlow_0sdmgw0 + SequenceFlow_1is80vv + + + + + + SequenceFlow_0mm8w9q + SequenceFlow_13043ai + + + SequenceFlow_0a5fuor + + + + + SequenceFlow_13043ai + SequenceFlow_0sdmgw0 + SequenceFlow_10m9u5m + + + + =interopRegistrationFailed = true + + + + + + SequenceFlow_10m9u5m + SequenceFlow_0errykb + + + SequenceFlow_0errykb + + + + + + + SequenceFlow_1is80vv + SequenceFlow_0a5fuor + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ph-ee-env-labs/orchestration/feel/payee-transaction-request-DFSPID.bpmn b/ph-ee-env-labs/orchestration/feel/payee-transaction-request-DFSPID.bpmn new file mode 100644 index 000000000..0e6ad30d4 --- /dev/null +++ b/ph-ee-env-labs/orchestration/feel/payee-transaction-request-DFSPID.bpmn @@ -0,0 +1,525 @@ + + + + + SequenceFlow_1dldf5u + + + + + + SequenceFlow_1dldf5u + SequenceFlow_0o29r29 + SequenceFlow_0rxpy99 + + + SequenceFlow_0rxpy99 + SequenceFlow_10d0o2e + + + SequenceFlow_1kmhgv4 + + PT60S + + + + + + SequenceFlow_1kmhgv4 + SequenceFlow_0o29r29 + SequenceFlow_1lq4sr3 + + + + =partyLookupRetryCount < 3 + + + SequenceFlow_10d0o2e + SequenceFlow_04z6eyn + SequenceFlow_0cnxbrt + + + + + + + SequenceFlow_1lq4sr3 + SequenceFlow_0c992gd + SequenceFlow_0cnxbrt + SequenceFlow_0n3s2my + SequenceFlow_1u4tw9n + SequenceFlow_0vg1fr1 + SequenceFlow_1e0lfr2 + + + SequenceFlow_1e0lfr2 + + + + + + + SequenceFlow_04z6eyn + SequenceFlow_0iaw247 + SequenceFlow_1532e69 + + + + SequenceFlow_1532e69 + SequenceFlow_0l514h3 + + + SequenceFlow_0grg9ft + + PT60S + + + + + SequenceFlow_0grg9ft + SequenceFlow_0iaw247 + SequenceFlow_0c992gd + + + + =transactionRequestRetryCount < 3 + + + + SequenceFlow_05uckab + SequenceFlow_1mlqc0y + + + SequenceFlow_066fuyi + SequenceFlow_05uckab + SequenceFlow_1czisxf + + + =isAuthorisationRequired = true + + + SequenceFlow_0811wi8 + + + + + + + SequenceFlow_1mlqc0y + SequenceFlow_1w0hf64 + + + + SequenceFlow_1w0hf64 + SequenceFlow_11nrc5m + + + + + + + SequenceFlow_11nrc5m + SequenceFlow_037fe7e + SequenceFlow_0olwno4 + + + + + =partyLookupFailed = true + + + SequenceFlow_0l514h3 + SequenceFlow_0n3s2my + SequenceFlow_066fuyi + + + =transactionRequestFailed = true + + + + + + + SequenceFlow_0x2glrz + SequenceFlow_0811wi8 + + + + SequenceFlow_0olwno4 + SequenceFlow_1czisxf + SequenceFlow_1g5sx74 + + + + + SequenceFlow_1g5sx74 + SequenceFlow_0vg1fr1 + SequenceFlow_1jr6oyv + SequenceFlow_0x2glrz + + + =transactionState != "ACCEPTED" + + + SequenceFlow_1xc38wk + + PT60S + + + + SequenceFlow_1xc38wk + SequenceFlow_1jr6oyv + SequenceFlow_037fe7e + SequenceFlow_1u4tw9n + + + + =isAuthorisationRequired = true and authRetriesLeftCount < authRetriesLeft + + + + =isAuthorisationRequired and (transactionRequestFailed = true or transActionState = "REJECTED") + + + + + + + send to where? + + + + channel initializes rtp + + + + wait for response on which channel? + + + + retryCount should be greater or equal then auth:retriesLeft + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ph-ee-env-labs/orchestration/feel/payer-fund-transfer-DFSPID.bpmn b/ph-ee-env-labs/orchestration/feel/payer-fund-transfer-DFSPID.bpmn new file mode 100644 index 000000000..a6ab72f6d --- /dev/null +++ b/ph-ee-env-labs/orchestration/feel/payer-fund-transfer-DFSPID.bpmn @@ -0,0 +1,1069 @@ + + + + + Flow_0zizvel + + + + SequenceFlow_0h8jckr + SequenceFlow_06tbhc9 + + + SequenceFlow_1ffxwgp + SequenceFlow_0uphhfj + + + + + + SequenceFlow_0vrua4x + Flow_17ezf3t + SequenceFlow_0h8jckr + + + + + + SequenceFlow_0ew6rln + SequenceFlow_0q7anwv + + + SequenceFlow_12nueew + SequenceFlow_09gkp54 + SequenceFlow_0zniywb + + + + + + SequenceFlow_09gkp54 + SequenceFlow_11uuh51 + SequenceFlow_1eicyj6 + + + =quoteRetryCount < 3 + + + + + + + + SequenceFlow_0zniywb + SequenceFlow_1d2huaz + SequenceFlow_0t11r3b + SequenceFlow_1l16e8u + SequenceFlow_0eh0472 + SequenceFlow_1oanf9v + SequenceFlow_1bb7vzi + + + + + + + SequenceFlow_01tpjgc + SequenceFlow_1ffxwgp + + + SequenceFlow_0uphhfj + SequenceFlow_1oanf9v + SequenceFlow_0jl4afa + + + + SequenceFlow_1bb7vzi + Flow_0uzqnw0 + + + SequenceFlow_03gw2ot + SequenceFlow_0fyvo3u + SequenceFlow_0ew6rln + SequenceFlow_1d2huaz + + + + =quoteFailed = true + + + SequenceFlow_06tbhc9 + SequenceFlow_11uuh51 + SequenceFlow_0t11r3b + + + + =partyLookupFailed = true + + + SequenceFlow_0u5ni5c + + PT60S + + + + SequenceFlow_0q7anwv + SequenceFlow_01tpjgc + SequenceFlow_1l16e8u + + + + + =localQuoteFailed = true + + + SequenceFlow_0u5ni5c + SequenceFlow_0vrua4x + SequenceFlow_0eh0472 + + + + =partyLookupRetryCount < 3 + + + + + + =payerConfirmed = true + + + SequenceFlow_1eicyj6 + SequenceFlow_15wc77c + SequenceFlow_0h2j62g + SequenceFlow_087rb2p + + + + + SequenceFlow_15wc77c + SequenceFlow_03gw2ot + + + + + SequenceFlow_0h2j62g + SequenceFlow_0fyvo3u + + + + + + SequenceFlow_087rb2p + SequenceFlow_12nueew + + PT60S + + + + + + SequenceFlow_021l36b + SequenceFlow_0hjdph9 + + + SequenceFlow_0zv37c6 + + + + + + SequenceFlow_0jl4afa + SequenceFlow_0dt42vk + + + + + + SequenceFlow_1a0pfuq + SequenceFlow_1ptml7u + SequenceFlow_021l36b + + + + + + SequenceFlow_1222rpl + SequenceFlow_1k13ccu + SequenceFlow_1emjz5s + + + SequenceFlow_039x2o8 + SequenceFlow_1a0pfuq + SequenceFlow_1u7fhxg + + + SequenceFlow_0hjdph9 + SequenceFlow_11ybwbd + SequenceFlow_1222rpl + SequenceFlow_1ic2uyb + + + + + + SequenceFlow_02o4g3y + SequenceFlow_0zv37c6 + + + + + + SequenceFlow_1f823z7 + SequenceFlow_0r1oaqw + + + + + + SequenceFlow_1u7fhxg + SequenceFlow_1md51ht + + + + + + SequenceFlow_1ic2uyb + SequenceFlow_0wlity5 + SequenceFlow_1gmvm2h + + + SequenceFlow_0jviy8g + SequenceFlow_11ybwbd + SequenceFlow_0udfio5 + + + + + + SequenceFlow_13qetbt + SequenceFlow_0jviy8g + + + SequenceFlow_0dt42vk + SequenceFlow_1ptml7u + SequenceFlow_1f823z7 + + + SequenceFlow_1emjz5s + SequenceFlow_02o4g3y + SequenceFlow_0t11txa + + + + + + SequenceFlow_1md51ht + SequenceFlow_13qetbt + + + SequenceFlow_0ntctr3 + + + SequenceFlow_0r1oaqw + + + SequenceFlow_1gmvm2h + SequenceFlow_17okil0 + SequenceFlow_0jgx2x0 + + + SequenceFlow_0ogstcm + + + + + + SequenceFlow_0t11txa + SequenceFlow_1g74z3o + + + + + + SequenceFlow_0jgx2x0 + SequenceFlow_1tq3ry1 + + + + + + SequenceFlow_1g74z3o + SequenceFlow_0xh7fo1 + + + + + + SequenceFlow_1tq3ry1 + SequenceFlow_1k0in2i + + + SequenceFlow_1k0in2i + SequenceFlow_0wlity5 + SequenceFlow_0ntctr3 + + + + + + SequenceFlow_17okil0 + SequenceFlow_0ogstcm + + + SequenceFlow_0xh7fo1 + SequenceFlow_1k13ccu + SequenceFlow_14hz2nf + + + SequenceFlow_14hz2nf + + + SequenceFlow_0udfio5 + + + SequenceFlow_039x2o8 + + PT60S + + + + + + + + =transferRetryCount < 3 + + + + + + + + + + =transferFailed = true or transferState != "COMMITTED" + + + + =transferPrepareFailed = true + + + + + + + + =operatorManualOverride = true + + + + =transferCreateFailed = true + + + =operatorManualOverride = true + + + + =transferReleaseFailed = true + + + + + + + + =operatorManualOverride = true + + + Flow_0inynl6 + Flow_17ezf3t + Flow_0uzqnw0 + + + + + + + + Flow_0zizvel + Flow_0inynl6 + + + + = isTxnValid = false + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ph-ee-env-labs/orchestration/feel/payment-notification-DFSPID.bpmn b/ph-ee-env-labs/orchestration/feel/payment-notification-DFSPID.bpmn new file mode 100644 index 000000000..6426376b5 --- /dev/null +++ b/ph-ee-env-labs/orchestration/feel/payment-notification-DFSPID.bpmn @@ -0,0 +1,108 @@ + + + + + Flow_18mhs3y + + + + + + + Flow_18mhs3y + Flow_0e2d78d + Flow_0mcgw4e + + + Flow_0mcgw4e + Flow_0e2d78d + Flow_12n05di + + + + =billPayFailed = true + + + + + + + Flow_12n05di + Flow_0es9ovt + + + Flow_0es9ovt + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ph-ee-env-labs/orchestration/feel/redeem_and_pay_voucher.bpmn b/ph-ee-env-labs/orchestration/feel/redeem_and_pay_voucher.bpmn new file mode 100644 index 000000000..9f046a66c --- /dev/null +++ b/ph-ee-env-labs/orchestration/feel/redeem_and_pay_voucher.bpmn @@ -0,0 +1,261 @@ + + + + + Flow_00w7ruu + + + Flow_0olwtrb + + + + + + + Flow_00w7ruu + Flow_1w6372d + + + + + + Flow_0jkpjqm + Flow_1lceswe + Flow_0mlf0kh + + + + + + Flow_0jau9ol + Flow_0doccdo + Flow_1eocjk2 + + + Flow_0043fku + Flow_1mq18rg + + + Flow_1mq18rg + Flow_0jkpjqm + Flow_0b379n1 + + + + + =accountLookupFailed = true + + + + Flow_16j97ct + + + + + + Flow_0b379n1 + Flow_0cxqoa1 + Flow_1xscxb6 + Flow_0olwtrb + + + Flow_1eocjk2 + Flow_0wiilam + Flow_0cdt1mv + + + + Flow_0wiilam + Flow_0jau9ol + + = thresholdDelay + + + + + =transactionCompleted = false and retry < maxRetry + + + Flow_0cdt1mv + Flow_0cxqoa1 + Flow_0j9qhau + + + + =transactionCompleted = false + + + Flow_0mlf0kh + Flow_0doccdo + Flow_0p17skk + + + + =paymentAdvice = false + + + Flow_1w6372d + Flow_0043fku + Flow_1lceswe + Flow_1xscxb6 + + + + =statusCode = 202 + + + =statusCode = 200 + + + + + + + Flow_0p17skk + Flow_0j9qhau + Flow_16j97ct + + + =paymentAdvice = true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ph-ee-env-labs/orchestration/feel/voucher_budget_check.bpmn b/ph-ee-env-labs/orchestration/feel/voucher_budget_check.bpmn new file mode 100644 index 000000000..1ef22e33d --- /dev/null +++ b/ph-ee-env-labs/orchestration/feel/voucher_budget_check.bpmn @@ -0,0 +1,73 @@ + + + + + Flow_1a7rxbb + + + + + + + + Flow_1a7rxbb + Flow_1x764j5 + + + Flow_1x764j5 + Flow_027y2fy + + + + Flow_1cf5s97 + + + + + + + Flow_027y2fy + Flow_1cf5s97 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ph-ee-env-labs/sample-requests/bb-to-large.json b/ph-ee-env-labs/sample-requests/bb-to-large.json new file mode 100644 index 000000000..023e92f5d --- /dev/null +++ b/ph-ee-env-labs/sample-requests/bb-to-large.json @@ -0,0 +1,20 @@ +{ + "payer": { + "partyIdInfo": { + "partyIdType": "MSISDN", + "partyIdentifier": "27710303999", + "fspId": "in03tn05" + } + }, + "payee": { + "partyIdInfo": { + "partyIdType": "MSISDN", + "partyIdentifier": "27710101999" + } + }, + "amount": { + "amount": 204, + "currency": "TZS" + } +} + diff --git a/ph-ee-env-labs/sample-requests/large-to-bb.json b/ph-ee-env-labs/sample-requests/large-to-bb.json new file mode 100644 index 000000000..13e350bb1 --- /dev/null +++ b/ph-ee-env-labs/sample-requests/large-to-bb.json @@ -0,0 +1,19 @@ +{ + "payer": { + "partyIdInfo": { + "partyIdType": "MSISDN", + "partyIdentifier": "27710101999", + "fspId": "in01tn01" + } + }, + "payee": { + "partyIdInfo": { + "partyIdType": "MSISDN", + "partyIdentifier": "27710303999" + } + }, + "amount": { + "amount": 420, + "currency": "TZS" + } +} diff --git a/ph-ee-env-labs/sample-requests/large-to-med.json b/ph-ee-env-labs/sample-requests/large-to-med.json new file mode 100644 index 000000000..8950d792b --- /dev/null +++ b/ph-ee-env-labs/sample-requests/large-to-med.json @@ -0,0 +1,19 @@ +{ + "payer": { + "partyIdInfo": { + "partyIdType": "MSISDN", + "partyIdentifier": "27710101999", + "fspId": "in01tn01" + } + }, + "payee": { + "partyIdInfo": { + "partyIdType": "MSISDN", + "partyIdentifier": "27710305999" + } + }, + "amount": { + "amount": 416, + "currency": "TZS" + } +} diff --git a/ph-ee-env-labs/sample-requests/med-to-large.json b/ph-ee-env-labs/sample-requests/med-to-large.json new file mode 100644 index 000000000..fe8b7706a --- /dev/null +++ b/ph-ee-env-labs/sample-requests/med-to-large.json @@ -0,0 +1,20 @@ +{ + "payer": { + "partyIdInfo": { + "partyIdType": "MSISDN", + "partyIdentifier": "27710305999", + "fspId": "in03tn05" + } + }, + "payee": { + "partyIdInfo": { + "partyIdType": "MSISDN", + "partyIdentifier": "27710101999" + } + }, + "amount": { + "amount": 207, + "currency": "TZS" + } +} + diff --git a/ph-ee-env-template/.circleci/config.yml b/ph-ee-env-template/.circleci/config.yml new file mode 100644 index 000000000..a63761dda --- /dev/null +++ b/ph-ee-env-template/.circleci/config.yml @@ -0,0 +1,614 @@ +version: 2.1 +orbs: + slack: circleci/slack@4.12.5 + helm: circleci/helm@2.0.1 + aws-eks: circleci/aws-eks@2.2.0 + kubernetes: circleci/kubernetes@1.3 + fynarfin-orb: fynarfin/docker-image-availability-check-and-upgrade@1.0.2 + +jobs: + build-g2p-sandbox-ci-chart: + docker: + - image: cimg/python:3.10 + working_directory: ~/repo + environment: + TERM: dumb + steps: + - checkout + - run: git clone https://github.com/fynarfin/ph-ee-env-labs + - run: rm -f ph-ee-env-labs/helm/ph-ee-g2p-sandbox-ci/Chart.lock ph-ee-env-labs/helm/ph-ee-g2p-sandbox-ci/requirements.lock ph-ee-env-labs/helm/ph-ee-g2p-sandbox-ci/charts/* + - helm/install-helm-client: + version: "v3.8.2" + # - run: "sed -i '12s/.*/version: 0.0.0/' helm/ph-ee-g2p-sandbox-ci/Chart.yaml" + - run: + name: build-and-host-ph-ee-g2p-sandbox-ci + environment: + JIRA_STORY: '' + JIRA_STORY_DIR: '' + command: | + if [ "$CIRCLE_BRANCH" != "develop" ]; then + PR_NUMBER=$(basename $CIRCLE_PULL_REQUEST) + PR_TITLE=$(curl -sSL "https://api.github.com/repos/fynarfin/$CIRCLE_PROJECT_REPONAME/pulls/$PR_NUMBER" | jq -r '.title') + JIRA_STORY=-$(echo $PR_TITLE | cut -d "[" -f2 | cut -d "]" -f1 | tr '[A-Z]' '[a-z]') + if [ -z "$JIRA_STORY" ]; then echo "Invalid PR title" && exit 1; else echo "Ticket NO: $JIRA_STORY" && JIRA_STORY_DIR=$(echo /jira-story-version); fi + echo Charts will save in https://fynarfin.io/images/fynarfin$JIRA_STORY_DIR + fi + CHART_URL="https://fynarfin.io/images/fynarfin$JIRA_STORY_DIR/ph-ee-g2p-sandbox-ci-0.0.0$JIRA_STORY" + if curl --output /dev/null --silent --head --fail "$CHART_URL"; then + sed -i "11s@^ *repository:.*\$@ repository: $CHART_URL@" ph-ee-env-labs/helm/ph-ee-g2p-sandbox-ci/Chart.yaml + sed -i "12s@^ *version:.*\$@ version: 0.0.0$JIRA_STORY@" ph-ee-env-labs/helm/ph-ee-g2p-sandbox-ci/Chart.yaml + echo "chart used: < $CHART_URL >" + else + CHART_URL="https://fynarfin.io/images/fynarfin/ph-ee-g2p-sandbox-ci-0.0.0" + echo "chart used: < $CHART_URL >" + fi + sed -i "6s/.*/version: 0.0.0$JIRA_STORY/" ph-ee-env-labs/helm/ph-ee-g2p-sandbox-ci/Chart.yaml + cat ph-ee-env-labs/helm/ph-ee-g2p-sandbox-ci/Chart.yaml + helm dep up ph-ee-env-labs/helm/ph-ee-g2p-sandbox-ci + helm package ph-ee-env-labs/helm/ph-ee-g2p-sandbox-ci + helm repo index . + echo "$CERT_FILE" | base64 --decode > b64encoded.pem + chmod 400 b64encoded.pem + ssh -i b64encoded.pem -o StrictHostKeyChecking=No ec2-user@13.233.68.128 sudo mkdir -p /apps/apache-tomcat-7.0.82/webapps/ROOT/images/fynarfin$JIRA_STORY_DIR/ph-ee-g2p-sandbox-ci$JIRA_STORY + scp -o StrictHostKeyChecking=No -i b64encoded.pem index.yaml ph-ee-g2p-sandbox-ci-0.0.0$JIRA_STORY.tgz ec2-user@13.233.68.128:~/ + ssh -i b64encoded.pem -o StrictHostKeyChecking=No ec2-user@13.233.68.128 sudo mv -t /apps/apache-tomcat-7.0.82/webapps/ROOT/images/fynarfin$JIRA_STORY_DIR/ph-ee-g2p-sandbox-ci$JIRA_STORY index.yaml ph-ee-g2p-sandbox-ci-0.0.0$JIRA_STORY.tgz + build-and-host-engine: + docker: + - image: cimg/python:3.10 + working_directory: ~/repo + environment: + TERM: dumb + steps: + - checkout + - run: rm -f helm/ph-ee-engine/Chart.lock helm/ph-ee-engine/requirements.lock helm/ph-ee-engine/charts/* + - helm/install-helm-client: + version: "v3.8.2" + - run: + name: build-and-host-engine + environment: + JIRA_STORY: '' + JIRA_STORY_DIR: '' + command: | + if [ "$CIRCLE_BRANCH" != "develop" ]; then + PR_NUMBER=$(basename $CIRCLE_PULL_REQUEST) + PR_TITLE=$(curl -sSL "https://api.github.com/repos/fynarfin/$CIRCLE_PROJECT_REPONAME/pulls/$PR_NUMBER" | jq -r '.title') + JIRA_STORY=-$(echo $PR_TITLE | cut -d "[" -f2 | cut -d "]" -f1 | tr '[A-Z]' '[a-z]') + if [ -z "$JIRA_STORY" ]; then echo "Invalid PR title" && exit 1; else echo "Ticket NO: $JIRA_STORY" && JIRA_STORY_DIR=$(echo /jira-story-version); fi + echo Charts will save in https://fynarfin.io/images/fynarfin$JIRA_STORY_DIR + fi + sed -i "5s/.*/version: 0.0.0-SNAPSHOT$JIRA_STORY/" helm/ph-ee-engine/Chart.yaml + helm dep up helm/ph-ee-engine + helm package helm/ph-ee-engine + helm repo index . + echo "$CERT_FILE" | base64 --decode > b64encoded.pem + chmod 400 b64encoded.pem + ssh -i b64encoded.pem -o StrictHostKeyChecking=No ec2-user@13.233.68.128 sudo mkdir -p /apps/apache-tomcat-7.0.82/webapps/ROOT/images/fynarfin$JIRA_STORY_DIR/ph-ee-engine-0.0.0-SNAPSHOT$JIRA_STORY + scp -o StrictHostKeyChecking=No -i b64encoded.pem index.yaml ph-ee-engine-0.0.0-SNAPSHOT$JIRA_STORY.tgz ec2-user@13.233.68.128:~/ + ssh -i b64encoded.pem -o StrictHostKeyChecking=No ec2-user@13.233.68.128 sudo cp -t /apps/apache-tomcat-7.0.82/webapps/ROOT/images/fynarfin$JIRA_STORY_DIR/ph-ee-engine-0.0.0-SNAPSHOT$JIRA_STORY index.yaml ph-ee-engine-0.0.0-SNAPSHOT$JIRA_STORY.tgz + build-and-host-g2p-sandbox: + docker: + - image: cimg/python:3.10 + working_directory: ~/repo + environment: + TERM: dumb + steps: + - checkout + - run: rm -f helm/g2p-sandbox/Chart.lock helm/g2p-sandbox/requirements.lock helm/g2p-sandbox/charts/* + - helm/install-helm-client: + version: "v3.8.2" + - run: + name: build-and-host-g2p-sandbox + environment: + JIRA_STORY: '' + JIRA_STORY_DIR: '' + command: | + if [ "$CIRCLE_BRANCH" != "develop" ]; then + PR_NUMBER=$(basename $CIRCLE_PULL_REQUEST) + PR_TITLE=$(curl -sSL "https://api.github.com/repos/fynarfin/$CIRCLE_PROJECT_REPONAME/pulls/$PR_NUMBER" | jq -r '.title') + JIRA_STORY=-$(echo $PR_TITLE | cut -d "[" -f2 | cut -d "]" -f1 | tr '[A-Z]' '[a-z]') + if [ -z "$JIRA_STORY" ]; then echo "Invalid PR title" && exit 1; else echo "Ticket NO: $JIRA_STORY" && JIRA_STORY_DIR=$(echo /jira-story-version); fi + fi + CHART_URL="https://fynarfin.io/images/fynarfin$JIRA_STORY_DIR/ph-ee-engine-0.0.0-SNAPSHOT$JIRA_STORY" + if curl --output /dev/null --silent --head --fail "$CHART_URL"; then + sed -i "10s@^ *repository:.*\$@ repository: $CHART_URL@" helm/g2p-sandbox/Chart.yaml + sed -i "11s@^ *version:.*\$@ version: 0.0.0-SNAPSHOT$JIRA_STORY@" helm/g2p-sandbox/Chart.yaml + echo "chart used: < $CHART_URL >" + else + CHART_URL="https://fynarfin.io/images/fynarfin/ph-ee-engine-0.0.0-SNAPSHOT" + echo "chart used: < $CHART_URL >" + fi + sed -i "5s/.*/version: 0.0.0$JIRA_STORY/" helm/g2p-sandbox/Chart.yaml + # rm -rf helm/g2p-sandbox/templates/config.yml + cat helm/g2p-sandbox/Chart.yaml + helm dep up helm/g2p-sandbox + helm package helm/g2p-sandbox + helm repo index . + echo "$CERT_FILE" | base64 --decode > b64encoded.pem + chmod 400 b64encoded.pem + ssh -i b64encoded.pem -o StrictHostKeyChecking=No ec2-user@13.233.68.128 sudo mkdir -p /apps/apache-tomcat-7.0.82/webapps/ROOT/images/fynarfin$JIRA_STORY_DIR/ph-ee-g2psandbox-0.0.0$JIRA_STORY + scp -o StrictHostKeyChecking=No -i b64encoded.pem index.yaml ph-ee-g2psandbox-0.0.0$JIRA_STORY.tgz ec2-user@13.233.68.128:~/ + ssh -i b64encoded.pem -o StrictHostKeyChecking=No ec2-user@13.233.68.128 sudo mv -t /apps/apache-tomcat-7.0.82/webapps/ROOT/images/fynarfin$JIRA_STORY_DIR/ph-ee-g2psandbox-0.0.0$JIRA_STORY index.yaml ph-ee-g2psandbox-0.0.0$JIRA_STORY.tgz + build-host-g2p-fyn-chart: + docker: + - image: cimg/python:3.10 + working_directory: ~/repo + environment: + TERM: dumb + steps: + - run: git clone https://github.com/fynarfin/ph-ee-env-labs + - run: rm -f ph-ee-env-labs/helm/g2p-sandbox-fynarfin-SIT/Chart.lock ph-ee-env-labs/helm/g2p-sandbox-fynarfin-SIT/requirements.lock ph-ee-env-labs/helm/g2p-sandbox-fynarfin-SIT/charts/* + - helm/install-helm-client: + version: "v3.8.2" + # - run: "sed -i '12s/.*/version: 0.0.0/' helm/g2p-sandbox-fynarfin-SIT/Chart.yaml" + - run: + name: build-host-g2p-fyn-chart + environment: + JIRA_STORY: '' + JIRA_STORY_DIR: '' + command: | + if [ "$CIRCLE_BRANCH" != "develop" ]; then + PR_NUMBER=$(basename $CIRCLE_PULL_REQUEST) + PR_TITLE=$(curl -sSL "https://api.github.com/repos/fynarfin/$CIRCLE_PROJECT_REPONAME/pulls/$PR_NUMBER" | jq -r '.title') + JIRA_STORY=-$(echo $PR_TITLE | cut -d "[" -f2 | cut -d "]" -f1 | tr '[A-Z]' '[a-z]') + if [ -z "$JIRA_STORY" ]; then echo "Invalid PR title" && exit 1; else echo "Ticket NO: $JIRA_STORY" && JIRA_STORY_DIR=$(echo /jira-story-version); fi + fi + CHART_URL="https://fynarfin.io/images/fynarfin$JIRA_STORY_DIR/ph-ee-g2psandbox-0.0.0$JIRA_STORY" + if curl --output /dev/null --silent --head --fail "$CHART_URL"; then + sed -i "11s@^ *repository:.*\$@ repository: $CHART_URL@" ph-ee-env-labs/helm/g2p-sandbox-fynarfin-SIT/Chart.yaml + sed -i "12s@^ *version:.*\$@ version: 0.0.0$JIRA_STORY@" ph-ee-env-labs/helm/g2p-sandbox-fynarfin-SIT/Chart.yaml + echo "chart used: < $CHART_URL >" + else + CHART_URL="https://fynarfin.io/images/fynarfin/ph-ee-g2psandbox-0.0.0" + echo "chart used: < $CHART_URL >" + fi + sed -i "6s/.*/version: 0.2.0$JIRA_STORY/" ph-ee-env-labs/helm/g2p-sandbox-fynarfin-SIT/Chart.yaml + cat ph-ee-env-labs/helm/g2p-sandbox-fynarfin-SIT/Chart.yaml + helm dep up ph-ee-env-labs/helm/g2p-sandbox-fynarfin-SIT + helm package ph-ee-env-labs/helm/g2p-sandbox-fynarfin-SIT + helm repo index . + echo "$CERT_FILE" | base64 --decode > b64encoded.pem + chmod 400 b64encoded.pem + ssh -i b64encoded.pem -o StrictHostKeyChecking=No ec2-user@13.233.68.128 sudo mkdir -p /apps/apache-tomcat-7.0.82/webapps/ROOT/images/fynarfin$JIRA_STORY_DIR/ph-ee-g2psandbox-fynarfin$JIRA_STORY + scp -o StrictHostKeyChecking=No -i b64encoded.pem index.yaml ph-ee-g2psandbox-fynarfin-0.2.0$JIRA_STORY.tgz ec2-user@13.233.68.128:~/ + ssh -i b64encoded.pem -o StrictHostKeyChecking=No ec2-user@13.233.68.128 sudo mv -t /apps/apache-tomcat-7.0.82/webapps/ROOT/images/fynarfin$JIRA_STORY_DIR/ph-ee-g2psandbox-fynarfin$JIRA_STORY index.yaml ph-ee-g2psandbox-fynarfin-0.2.0$JIRA_STORY.tgz + build-and-host-g2p-sandbox-security: + docker: + - image: cimg/python:3.10 + working_directory: ~/repo + environment: + TERM: dumb + steps: + - checkout + - run: rm -f helm/g2p-sandbox-security/Chart.lock helm/g2p-sandbox-security/requirements.lock helm/g2p-sandbox-security/charts/* + - helm/install-helm-client: + version: "v3.8.2" + - run: + name: build-and-host-g2p-sandbox-security + environment: + JIRA_STORY: '' + JIRA_STORY_DIR: '' + command: | + if [ "$CIRCLE_BRANCH" != "develop" ]; then + PR_NUMBER=$(basename $CIRCLE_PULL_REQUEST) + PR_TITLE=$(curl -sSL "https://api.github.com/repos/fynarfin/$CIRCLE_PROJECT_REPONAME/pulls/$PR_NUMBER" | jq -r '.title') + JIRA_STORY=-$(echo $PR_TITLE | cut -d "[" -f2 | cut -d "]" -f1 | tr '[A-Z]' '[a-z]') + if [ -z "$JIRA_STORY" ]; then echo "Invalid PR title" && exit 1; else echo "Ticket NO: $JIRA_STORY" && JIRA_STORY_DIR=$(echo /jira-story-version); fi + fi + CHART_URL="https://fynarfin.io/images/fynarfin$JIRA_STORY_DIR/ph-ee-engine-0.0.0-SNAPSHOT$JIRA_STORY" + if curl --output /dev/null --silent --head --fail "$CHART_URL"; then + sed -i "10s@^ *repository:.*\$@ repository: $CHART_URL@" helm/g2p-sandbox-security/Chart.yaml + sed -i "11s@^ *version:.*\$@ version: 0.0.0-SNAPSHOT$JIRA_STORY@" helm/g2p-sandbox-security/Chart.yaml + echo "chart used: < $CHART_URL >" + else + CHART_URL="https://fynarfin.io/images/fynarfin/ph-ee-engine-0.0.0-SNAPSHOT" + echo "chart used: < $CHART_URL >" + fi + sed -i "5s/.*/version: 0.0.0$JIRA_STORY/" helm/g2p-sandbox-security/Chart.yaml + cat helm/g2p-sandbox-security/Chart.yaml + # - run: "sed -i '4s/.*/version: 0.0.0-SNAPSHOT/' helm/g2p-sandbox-security/requirements.yaml" + # SED & replace dependency with 0.0.0 + helm dep up helm/g2p-sandbox-security + helm package helm/g2p-sandbox-security + helm repo index . + echo "$CERT_FILE" | base64 --decode > b64encoded.pem + chmod 400 b64encoded.pem + ssh -i b64encoded.pem -o StrictHostKeyChecking=No ec2-user@13.233.68.128 sudo mkdir -p /apps/apache-tomcat-7.0.82/webapps/ROOT/images/fynarfin$JIRA_STORY_DIR/ph-ee-g2psandbox-security$JIRA_STORY + scp -o StrictHostKeyChecking=No -i b64encoded.pem index.yaml ph-ee-g2psandbox-security-0.0.0$JIRA_STORY.tgz ec2-user@13.233.68.128:~/ + ssh -i b64encoded.pem -o StrictHostKeyChecking=No ec2-user@13.233.68.128 sudo mv -t /apps/apache-tomcat-7.0.82/webapps/ROOT/images/fynarfin$JIRA_STORY_DIR/ph-ee-g2psandbox-security$JIRA_STORY index.yaml ph-ee-g2psandbox-security-0.0.0$JIRA_STORY.tgz + minikube-run-helm-upgrade-and-helm-test: + machine: + image: ubuntu-2004:current + docker_layer_caching: true + resource_class: large + environment: + TERM: dumb + parameters: + namespace: + default: "paymenthub" + description: | + The kubernetes namespace that should be used. + type: string + release-name: + default: "g2p-sandbox" + description: | + Specify a name for the release. + type: string + cluster-name: + default: "minikube" + type: string + service-file-path: + default: https://raw.githubusercontent.com/fynarfin/ph-ee-env-labs/develop/.circleci/services.txt + type: string + chart-base-url: + default: https://fynarfin.io/images/fynarfin + type: string + chart-name: + default: ph-ee-g2p-sandbox-ci + type: string + chart-version: + default: 0.0.0 + type: string + steps: + - helm/install-helm-client: + version: "v3.8.2" + - run: + name: run minikube + no_output_timeout: 40m + command : | + free -m + #!/bin/bash + #insatll kubectl-------- + echo hello + sudo apt-get update + sudo apt-get install -y apt-transport-https ca-certificates curl gpg + sudo mkdir -p /etc/apt/keyrings + sudo touch -y /etc/apt/keyrings/kubernetes-apt-keyring.gpg || echo done + curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.28/deb/Release.key | sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg + echo 'deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.28/deb/ /' | sudo tee /etc/apt/sources.list.d/kubernetes.list + sudo apt-get update + sudo apt-get install -y kubelet kubeadm kubectl + sudo apt-mark hold kubelet kubeadm kubectl + + #Setup Minikube + curl -LO https://storage.googleapis.com/minikube/releases/latest/minikube_latest_amd64.deb + sudo dpkg -i minikube_latest_amd64.deb + echo minikube waiting + minikube config set cpus 4 + minikube config set memory 15721 + minikube start #--extra-config=kubelet.max-pods=60 --cpus max --memory max --disk-size 50g + echo "Minikube started-----------------------------------------------------" + minikube addons enable metrics-server + # To check the allocated values + #minikube config get cpus + #minikube config get memory + + MINIKUBE_IP=`minikube ip` + echo $MINIKUBE_IP + # cat ~/.kube/config + + minikube kubectl -- get po -A #Interact with Minikube cluster + kubectl create namespace paymenthub + kubectl get -A namespace + + # # For remote access to minikube uncomment the following lines. + # #---------------------minikube remote aceess start--------------------- + # sudo apt install nginx + # sudo touch /etc/nginx/conf.d/minikube.conf + # echo "create nginx conf" + # sudo chmod 777 -R /etc/nginx/conf.d/ + # echo "changed access" + + # sudo apt-get install apache2-utils -y + # echo "apache2-utils installed" + # htpasswd -bc /home/circleci/project/.htpasswd minikube minikube + + # sudo cat \< /etc/nginx/conf.d/minikube.conf + # server { + # listen 8080; + # listen [::]:8080; + # server_name localhost; + # access_log /home/circleci/project/nginx_access.log; + # auth_basic "Administrators Area"; + # auth_basic_user_file /home/circleci/project/.htpasswd; + + # location / { + # proxy_pass https://$MINIKUBE_IP:8443; + # proxy_ssl_certificate /home/circleci/.minikube/profiles/minikube/client.crt; + # proxy_ssl_certificate_key /home/circleci/.minikube/profiles/minikube/client.key; + # } + # } + # EOF + # sudo service nginx restart || echo 'start nginx' + # SYSTEMD_LESS=FRXMK systemctl status nginx.service + + # sleep 10 + + # echo "test-nginx-proxy" + # curl -u minikube:minikube http://localhost:8080 + + # curl -s https://ngrok-agent.s3.amazonaws.com/ngrok.asc | sudo tee /etc/apt/trusted.gpg.d/ngrok.asc >/dev/null && echo "deb https://ngrok-agent.s3.amazonaws.com buster main" | sudo tee /etc/apt/sources.list.d/ngrok.list && sudo apt update && sudo apt install ngrok + # ngrok config add-authtoken $AUTH_TOKEN + # echo "web_addr: $LOCAL_PORT" >> /home/circleci/.config/ngrok/ngrok.yml + # ngrok http 8080 > /dev/null & + + # echo -n "Extracting ngrok public url ." + # NGROK_PUBLIC_URL="" + # while [ -z "$NGROK_PUBLIC_URL" ]; do + # # Run 'curl' against ngrok API and extract public (using 'sed' command) + # export NGROK_PUBLIC_URL=$(curl --silent --max-time 10 --connect-timeout 5 \ + # --show-error http://127.0.0.1:$LOCAL_PORT/api/tunnels | \ + # sed -nE 's/.*public_url":"https:..([^"]*).*/\1/p') + # sleep 1 + # echo -n "." + # done + # echo ---------copy the below public_URL for NGrok---------- + # echo "https://$NGROK_PUBLIC_URL" + # echo "https://$NGROK_PUBLIC_URL" + + # echo "test ngrok " + # curl -u minikube:minikube https://$NGROK_PUBLIC_URL + # echo "https://$NGROK_PUBLIC_URL" + # # ---------------------minikube remote access end--------------------- + + curl https://baltocdn.com/helm/signing.asc | gpg --dearmor | sudo tee /usr/share/keyrings/helm.gpg > /dev/null + sudo apt-get install apt-transport-https --yes + echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/helm.gpg] https://baltocdn.com/helm/stable/debian/ all main" | sudo tee /etc/apt/sources.list.d/helm-stable-debian.list + #helm install + sudo apt-get update + sudo apt-get install helm + kubectl create namespace paymenthub || echo namespace already exists + minikube ssh -- free -m + echo ------------MEMORY CHECK ----------- + + - run: + no_output_timeout: 20m + name: fetch docker images and helm upgrade + environment: + ORB_CHART_BASE_URL: << parameters.chart-base-url >> + ORB_CHART_NAME: << parameters.chart-name >> + ORB_CHART_VERSION: << parameters.chart-version >> + ORB_PARAM_NAMESPACE: << parameters.namespace >> + ORB_PARAM_RELEASE_NAME: << parameters.release-name >> + JIRA_STORY: '' + JIRA_STORY_DIR: '' + VALUES_TO_OVERRIDE: '' + SERVICE_FILE_PATH: << parameters.service-file-path>> + command: | + function get_services_from_file() { + file=$1 + while IFS= read -r line || [ -n "$line" ]; do + generate_values_to_override $line + done < "$file" + } + + function generate_values_to_override() { + PREFIX="docker.io/" + if [ "$CIRCLE_BRANCH" != "develop" ] && check_for_image_tag ${2#"$PREFIX"} ${JIRA_STORY}; then + echo "image: < $1=$2:$JIRA_STORY >" + VALUES_TO_OVERRIDE+=$(echo "$1=$2:$JIRA_STORY"), + else + echo "image: < $1=$2:latest >" + VALUES_TO_OVERRIDE+=$(echo "$1=$2:latest"), + fi + } + function check_for_image_tag(){ + curl --silent -f --head -lL https://hub.docker.com/v2/repositories/$1/tags/$2/ > /dev/null + } + if [ "$CIRCLE_BRANCH" != "develop" ]; then + + PR_NUMBER=$(basename $CIRCLE_PULL_REQUEST) + PR_TITLE=$(curl -sSL "https://api.github.com/repos/fynarfin/$CIRCLE_PROJECT_REPONAME/pulls/$PR_NUMBER" | jq -r '.title') + JIRA_STORY=$(echo $PR_TITLE | cut -d "[" -f2 | cut -d "]" -f1 | tr '[A-Z]' '[a-z]') + if [ -z "$JIRA_STORY" ]; then echo "Invalid PR title" && exit 1; else echo "Ticket NO: $JIRA_STORY" && JIRA_STORY_DIR=$(echo /jira-story-version); fi + fi + + echo $SERVICE_FILE_PATH + wget $SERVICE_FILE_PATH + filename=$(basename "$SERVICE_FILE_PATH") + #Using sed replace ph-ee-g2psandbox. with empty string + sed -i 's/ph-ee-g2p-sandbox-ci\.p/p/g' $filename + echo $filename + get_services_from_file $filename + + if [ -n "${VALUES_TO_OVERRIDE}" ]; then + VALUES_TO_OVERRIDE=$(echo --set ${VALUES_TO_OVERRIDE::-1}) + echo "VALUES_TO_OVERRIDE: $VALUES_TO_OVERRIDE" + fi + + if [ -n "${ORB_PARAM_NAMESPACE}" ]; then + ORB_PARAM_NAMESPACE=$(echo --namespace ${ORB_PARAM_NAMESPACE}) + fi + if [ -n "${JIRA_STORY}" ]; then + JIRA_STORY=-$(echo $JIRA_STORY) + fi + + # Generating the chart url for deployment + # chart: "https://fynarfin.io/images/ph-ee-g2p-sandbox-ci/ph-ee-g2p-sandbox-ci-0.0.0.tgz" + ORB_PARAM_CHART=$(echo "$ORB_CHART_BASE_URL$JIRA_STORY_DIR/$ORB_CHART_NAME$JIRA_STORY/$ORB_CHART_NAME-$ORB_CHART_VERSION$JIRA_STORY.tgz") + + CHART_URL="$ORB_PARAM_CHART" + if curl --output /dev/null --silent --head --fail "$CHART_URL"; then + echo "chart used: < $CHART_URL >" + # add-repo: "https://fynarfin.io/images/ph-ee-g2p-sandbox-ci" + ORB_PARAM_REPO=$(echo "$ORB_CHART_BASE_URL$JIRA_STORY_DIR/$ORB_CHART_NAME$JIRA_STORY") + else + CHART_URL="https://fynarfin.io/images/ph-ee-g2p-sandbox-ci/ph-ee-g2p-sandbox-ci-0.0.0.tgz" + ORB_PARAM_REPO=$(echo "$ORB_CHART_BASE_URL/$ORB_CHART_NAME") + echo "chart used: < $CHART_URL >" + fi + + echo helm repo add "${ORB_PARAM_RELEASE_NAME}" "${ORB_PARAM_REPO}" + helm repo add "${ORB_PARAM_RELEASE_NAME}" "${ORB_PARAM_REPO}" + + kubectl apply -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/main/example/prometheus-operator-crd/monitoring.coreos.com_servicemonitors.yaml #Install ServiceMonitor + helm repo update + echo "helm upgrade --install ${VALUES_TO_OVERRIDE} ${ORB_PARAM_RELEASE_NAME} ${ORB_PARAM_CHART} ${ORB_PARAM_NAMESPACE}" + echo helm chart install starts + + # Download ph-ee-g2p-sandbox-ci-chart and extract + curl -O $ORB_CHART_BASE_URL$JIRA_STORY_DIR/$ORB_CHART_NAME$JIRA_STORY/$ORB_CHART_NAME-$ORB_CHART_VERSION$JIRA_STORY.tgz && tar xvf $ORB_CHART_NAME-$ORB_CHART_VERSION$JIRA_STORY.tgz + rm -rf $ORB_CHART_NAME-$ORB_CHART_VERSION$JIRA_STORY.tgz + + ORB_PARAM_REPO=$(echo "$ORB_CHART_BASE_URL/$ORB_CHART_NAME") + + EXTRA_VALUES=$(echo "-f ph-ee-g2p-sandbox-ci/values_p1.yaml") + helm upgrade ${EXTRA_VALUES} --install --timeout=1h ${VALUES_TO_OVERRIDE} ${ORB_PARAM_RELEASE_NAME} ${ORB_PARAM_CHART} ${ORB_PARAM_NAMESPACE} + echo --------------------helm upgrade in Phase 1 done--------------------- + EXTRA_VALUES=$(echo "-f ph-ee-g2p-sandbox-ci/values_p2.yaml") + helm upgrade ${EXTRA_VALUES} --install --timeout=1h ${VALUES_TO_OVERRIDE} ${ORB_PARAM_RELEASE_NAME} ${ORB_PARAM_CHART} ${ORB_PARAM_NAMESPACE} + echo --------------------helm upgrade in Phase 2 done--------------------- + echo --------------------helm upgrade is done--------------------- + sleep 1m; + + # ----------------------Post-Installation-Steps-starts--------------------------- + # #ES and Kibana secret creation + # git clone -b 7.17 https://github.com/elastic/helm-charts.git elastic/helm-charts + # cd elastic/helm-charts/elasticsearch/examples/security/ + # make secrets || echo "elastic-secrets" already exists + # git clone -b 7.17 https://github.com/elastic/helm-charts.git elastic/helm-charts + # cd elastic/helm-charts/kibana/examples/security/ + # make secrets || echo "kibana-secrets" already exists + # kubectl get secret elastic-certificate-crt -n default -o yaml | sed 's/namespace: default/namespace: paymenthub/' | kubectl create -f - + # kubectl get secret elastic-certificate-pem -n default -o yaml | sed 's/namespace: default/namespace: paymenthub/' | kubectl create -f - + # kubectl get secret elastic-certificates -n default -o yaml | sed 's/namespace: default/namespace: paymenthub/' | kubectl create -f - + # kubectl get secret elastic-credentials -n default -o yaml | sed 's/namespace: default/namespace: paymenthub/' | kubectl create -f - + # kubectl get secret kibana -n default -o yaml | sed 's/namespace: default/namespace: paymenthub/' | kubectl create -f - + # kubectl get secrets -n paymenthub + # echo ---------secrets created-------- + + # #insatll netcat + # sudo apt install -y netcat + # check_count=0 + # until ((check_count==20)) || nc -vz ph-ee-zeebe-ops 80; do + # echo "Waiting for zeebe-ops service"; + # sleep 5; + # check_count=$(($check_count + 1)); + # done; + # echo ------zeebe-ops service available----------- + # # until nc -vz ph-ee-zeebe-ops 80; do echo "Waiting for zeebe-ops service"; sleep 2; done; + + # #Deploy BPMN + # kubectl port-forward service/ph-ee-zeebe-ops 5000:80 -n paymenthub & #portforward zeebe-ops &' + # git clone https://github.com/fynarfin/ph-ee-env-labs.git fynarfin/ph-ee-env-labs + # cd fynarfin/ph-ee-env-labs/orchestration + # ls + # sed -i "/HOST=/c\HOST=http://localhost:5000/zeebe/upload" deployBpmn.sh + # cat deployBpmn.sh + # cd .. + # sh orchestration/deployBpmn.sh || echo 'deploy Bpmn done' + #------------------Post-Installation-Steps-ends------------------------------- + + - run: + name: Run Helm Tests + command: | + helm test g2p-sandbox --filter name=g2p-sandbox-test-gov --namespace paymenthub || echo test + helm test g2p-sandbox --filter name=g2p-sandbox-test-ams --namespace paymenthub || echo test + + - run: + name: Fetch Integration Test Report + command: | + #!/bin/bash + mkdir -p integration_report/test-report + + echo "Fetch Integration Test Report for ams" + kubectl cp paymenthub/`kubectl get pods -n paymenthub | grep g2p-sandbox-test-ams |cut -d " " -f1`:/ph-ee-connector-integration-test/build integration_report/test-report + # Specify the path to the downloaded file + downloaded_file="integration_report/test-report/cucumber.xml" + # Loop until the file is not empty + while [ ! -s $downloaded_file ]; do + echo "File is empty, waiting..." + sleep 60 # You can adjust the sleep interval as needed + kubectl cp paymenthub/`kubectl get pods -n paymenthub | grep g2p-sandbox-test-ams |cut -d " " -f1`:/ph-ee-connector-integration-test/build/ integration_report/test-report + downloaded_file="integration_report/test-report/cucumber.xml" + done + echo "File is no longer empty, processing..." + mv integration_report/test-report/cucumber.xml integration_report/test-report/cucumber_ams.xml + mv integration_report/test-report/reports/tests/test integration_report/test-report/reports/tests/test_ams + # kubectl cp paymenthubb/`kubectl get pods -n paymenthub | grep g2p-sandbox-test-ams |cut -d " " -f1`:/ph-ee-connector-integration-test/build integration_report/test-report + + for i in $(kubectl get pods -n paymenthub | grep g2p-sandbox-test-ams |cut -d " " -f1); do + echo "--------------------------------------------------------------------Logs of $i Start---------------------------------------------------------------------------" >> all_pod_logs.log + kubectl logs -n paymenthub $i --all-containers=true >> all_pod_logs.log + echo "---------------------------------------------------------------------Logs of $i End----------------------------------------------------------------------------" >> all_pod_logs.log + echo " " >> all_pod_logs.log + echo " " >> all_pod_logs.log + done + + echo "Fetch Integration Test Report for GOV" + kubectl cp paymenthub/`kubectl get pods -n paymenthub | grep g2p-sandbox-test-gov |cut -d " " -f1`:/ph-ee-connector-integration-test/build integration_report/test-report + # Specify the path to the downloaded file + downloaded_file="integration_report/test-report/cucumber.xml" + # Loop until the file is not empty + while [ ! -s $downloaded_file ]; do + echo "File is empty, waiting..." + sleep 60 # You can adjust the sleep interval as needed + kubectl cp paymenthub/`kubectl get pods -n paymenthub | grep g2p-sandbox-test-gov |cut -d " " -f1`:/ph-ee-connector-integration-test/build/ integration_report/test-report + downloaded_file="integration_report/test-report/cucumber.xml" + done + echo "File is no longer empty, processing..." + mv integration_report/test-report/cucumber.xml integration_report/test-report/cucumber_gov.xml + mv integration_report/test-report/reports/tests/test integration_report/test-report/reports/tests/test_gov + + mkdir -p integration_report_final + cp integration_report/test-report/cucumber_gov.xml integration_report_final/ || echo "" + cp integration_report/test-report/cucumber_ams.xml integration_report_final/ || echo "" + + ls integration_report/test-report/ + # kubectl cp paymenthub/`kubectl get pods -n paymenthub | grep g2p-sandbox-test-gov |cut -d " " -f1`:/ph-ee-connector-integration-test/build integration_report/test-report + for i in $(kubectl get pods -n paymenthub |cut -d " " -f1|tail -n +2); do + echo "--------------------------------------------------------------------Logs of $i Start---------------------------------------------------------------------------" >> all_pod_logs.log + kubectl logs -n paymenthub $i --all-containers=true >> all_pod_logs.log + echo "---------------------------------------------------------------------Logs of $i End----------------------------------------------------------------------------" >> all_pod_logs.log + echo " " >> all_pod_logs.log + echo " " >> all_pod_logs.log + done + mv all_pod_logs.log integration_report/test-report/reports/tests/ + + - store_test_results: + path: integration_report_final/ + - store_artifacts: + path: integration_report/test-report/reports/tests + +workflows: + deploy: + jobs: + - build-and-host-engine: + context: + - AWS + - Helm + - slack + - build-and-host-g2p-sandbox: + requires: + - build-and-host-engine + context: + - AWS + - Helm + - slack + - build-host-g2p-fyn-chart: + requires: + - build-and-host-g2p-sandbox + context: + - AWS + - Helm + - build-g2p-sandbox-ci-chart: + requires: + - build-host-g2p-fyn-chart + context: + - AWS + - Helm + - slack + - build-and-host-g2p-sandbox-security: + requires: + - build-g2p-sandbox-ci-chart + context: + - AWS + - Helm + - slack + - minikube-run-helm-upgrade-and-helm-test: + context: + - AWS + - Helm + - slack + - Ngrok + requires: + - build-g2p-sandbox-ci-chart diff --git a/ph-ee-env-template/.circleci/docker-image-availability-check-and-upgrade.yml b/ph-ee-env-template/.circleci/docker-image-availability-check-and-upgrade.yml new file mode 100644 index 000000000..32e2ca93c --- /dev/null +++ b/ph-ee-env-template/.circleci/docker-image-availability-check-and-upgrade.yml @@ -0,0 +1,165 @@ +version: 2.1 +description: "Check for docker image availability wrt jira story and do helm upgrade" +orbs: + helm: circleci/helm@2.0.1 + aws-eks: circleci/aws-eks@2.2.0 + kubernetes: circleci/kubernetes@1.3 +commands: + docker-image-availability-check-and-upgrade: + parameters: + namespace: + default: "" + description: | + The kubernetes namespace that should be used. + type: string + release-name: + default: "" + description: | + Specify a name for the release. + type: string + cluster-name: + default: "sit" + type: string + aws-region: + default: "${REGION}" + type: string + service-file-path: + default: https://raw.githubusercontent.com/fynarfin/ph-ee-env-labs/develop/.circleci/services.txt + type: string + chart-base-url: + default: https://fynarfin.io/images/fynarfin + type: string + chart-name: + default: ph-ee-g2psandbox-fynarfin + type: string + chart-version: + default: 0.2.0 + type: string + + steps: + - checkout + - aws-eks/update-kubeconfig-with-authenticator: + cluster-name: <> + aws-region: <> + - helm/install-helm-client: + version: "v3.8.2" + - run: + name: fetch docker images and helm upgrade + environment: + ORB_CHART_BASE_URL: << parameters.chart-base-url >> + ORB_CHART_NAME: << parameters.chart-name >> + ORB_CHART_VERSION: << parameters.chart-version >> + ORB_PARAM_NAMESPACE: << parameters.namespace >> + ORB_PARAM_RELEASE_NAME: << parameters.release-name >> + JIRA_STORY: '' + JIRA_STORY_DIR: '' + VALUES_TO_OVERRIDE: '' + SERVICE_FILE_PATH: << parameters.service-file-path>> + command: | + function get_services_from_file() { + file=$1 + while IFS= read -r line || [ -n "$line" ]; do + generate_values_to_override $line + done < "$file" + } + + function generate_values_to_override() { + PREFIX="docker.io/" + if [ "$CIRCLE_BRANCH" != "develop" ] && check_for_image_tag ${2#"$PREFIX"} ${JIRA_STORY}; then + echo "image: < $1=$2:$JIRA_STORY >" + VALUES_TO_OVERRIDE+=$(echo "$1=$2:$JIRA_STORY"), + else + echo "image: < $1=$2:latest >" + VALUES_TO_OVERRIDE+=$(echo "$1=$2:latest"), + fi + } + function check_for_image_tag(){ + curl --silent -f --head -lL https://hub.docker.com/v2/repositories/$1/tags/$2/ > /dev/null + } + if [ "$CIRCLE_BRANCH" != "develop" ]; then + + PR_NUMBER=$(basename $CIRCLE_PULL_REQUEST) + PR_TITLE=$(curl -sSL "https://api.github.com/repos/fynarfin/$CIRCLE_PROJECT_REPONAME/pulls/$PR_NUMBER" | jq -r '.title') + JIRA_STORY=$(echo $PR_TITLE | cut -d "[" -f2 | cut -d "]" -f1 | tr '[A-Z]' '[a-z]') + if [ -z "$JIRA_STORY" ]; then echo "Invalid PR title" && exit 1; else echo "Ticket NO: $JIRA_STORY" && JIRA_STORY_DIR=$(echo /jira-story-version); fi + fi + + echo $SERVICE_FILE_PATH + wget $SERVICE_FILE_PATH + filename=$(basename "$SERVICE_FILE_PATH") + get_services_from_file $filename + + if [ -n "${VALUES_TO_OVERRIDE}" ]; then + VALUES_TO_OVERRIDE=$(echo --set ${VALUES_TO_OVERRIDE::-1}) + echo "VALUES_TO_OVERRIDE: $VALUES_TO_OVERRIDE" + fi + + if [ -n "${ORB_PARAM_NAMESPACE}" ]; then + ORB_PARAM_NAMESPACE=$(echo --namespace ${ORB_PARAM_NAMESPACE}) + fi + if [ -n "${JIRA_STORY}" ]; then + JIRA_STORY=-$(echo $JIRA_STORY) + fi + + # Generating the chart url for deployment + # chart: "https://fynarfin.io/images/fynarfin/ph-ee-g2psandbox-fynarfin/ph-ee-g2psandbox-fynarfin-0.2.0.tgz" + ORB_PARAM_CHART=$(echo "$ORB_CHART_BASE_URL$JIRA_STORY_DIR/$ORB_CHART_NAME$JIRA_STORY/$ORB_CHART_NAME-$ORB_CHART_VERSION$JIRA_STORY.tgz") + + CHART_URL="$ORB_PARAM_CHART" + if curl --output /dev/null --silent --head --fail "$CHART_URL"; then + echo "chart used: < $CHART_URL >" + # add-repo: "https://fynarfin.io/images/fynarfin/ph-ee-g2psandbox-fynarfin" + ORB_PARAM_REPO=$(echo "$ORB_CHART_BASE_URL$JIRA_STORY_DIR/$ORB_CHART_NAME$JIRA_STORY") + else + CHART_URL="https://fynarfin.io/images/fynarfin/ph-ee-g2psandbox-fynarfin/ph-ee-g2psandbox-fynarfin-0.2.0.tgz" + ORB_PARAM_REPO=$(echo "$ORB_CHART_BASE_URL/$ORB_CHART_NAME") + echo "chart used: < $CHART_URL >" + fi + + echo helm repo add "${ORB_PARAM_RELEASE_NAME}" "${ORB_PARAM_REPO}" + helm repo add "${ORB_PARAM_RELEASE_NAME}" "${ORB_PARAM_REPO}" + + helm repo update + echo "helm upgrade --install ${VALUES_TO_OVERRIDE} ${ORB_PARAM_RELEASE_NAME} ${ORB_PARAM_CHART} ${ORB_PARAM_NAMESPACE}" + helm upgrade --install ${VALUES_TO_OVERRIDE} ${ORB_PARAM_RELEASE_NAME} ${ORB_PARAM_CHART} ${ORB_PARAM_NAMESPACE} + +jobs: + docker-image-availability-check-and-upgrade: + docker: + - image: cimg/openjdk:17.0.0 + parameters: + namespace: + type: string + default: "" + release-name: + default: "" + type: string + cluster-name: + default: "sit" + type: string + aws-region: + default: "$REGION" + type: string + service-file-path: + default: https://raw.githubusercontent.com/fynarfin/ph-ee-env-labs/develop/.circleci/services.txt + type: string + chart-base-url: + default: https://fynarfin.io/images/fynarfin/ + type: string + chart-name: + default: ph-ee-g2psandbox-fynarfin + type: string + chart-version: + default: 0.2.0 + type: string + + steps: + - docker-image-availability-check-and-upgrade: + namespace: <> + release-name: <> + cluster-name: <> + aws-region: <> + chart-base-url: https://fynarfin.io/images/fynarfin/ + chart-name: ph-ee-g2psandbox-fynarfin + chart-version: 0.2.0 + diff --git a/ph-ee-env-template/.github/pull_request_template.md b/ph-ee-env-template/.github/pull_request_template.md new file mode 100644 index 000000000..98a182a2e --- /dev/null +++ b/ph-ee-env-template/.github/pull_request_template.md @@ -0,0 +1,22 @@ +## Description + +* PR title should have jira ticket enclosed in `[]`.
+Format: ``` [jira_ticket] description```
+ex: [phee-123] PR title. +* Add a link to the Jira ticket. +* Describe the changes made and why they were made. + +## Checklist + +Please make sure these boxes are checked before submitting your pull request - thanks! +- [ ] Followed the PR title naming convention mentioned above. + +- [ ] Design related bullet points or design document link related to this PR added in the description above. + +- [ ] Updated corresponding Postman Collection or Api documentation for the changes in this PR. + +- [ ] Created/updated unit or integration tests for verifying the changes made. + +- [ ] Added required Swagger annotation and update API documentation with details of any API changes if applicable + +- [ ] Followed the naming conventions as given in https://docs.google.com/document/d/1Q4vaMSzrTxxh9TS0RILuNkSkYCxotuYk1Xe0CMIkkCU/edit?usp=sharing diff --git a/ph-ee-env-template/.gitignore b/ph-ee-env-template/.gitignore new file mode 100644 index 000000000..89b1ef6d4 --- /dev/null +++ b/ph-ee-env-template/.gitignore @@ -0,0 +1,12 @@ +charts/ +helm/*.tgz +.idea/ + +*.iml +**/*.lock + +.DS_Store +.env +index.yaml +helm/index.yaml +*.tgz \ No newline at end of file diff --git a/ph-ee-env-template/.harness/Build_openMF_ph_ee_env_template_1704892298403-pr-trigger-input-set-1704892299474.yaml b/ph-ee-env-template/.harness/Build_openMF_ph_ee_env_template_1704892298403-pr-trigger-input-set-1704892299474.yaml new file mode 100644 index 000000000..f0315bc06 --- /dev/null +++ b/ph-ee-env-template/.harness/Build_openMF_ph_ee_env_template_1704892298403-pr-trigger-input-set-1704892299474.yaml @@ -0,0 +1,14 @@ +inputSet: + name: Build_openMF_ph_ee_env_template_1704892298403-pr-trigger-input-set + identifier: Build_openMF_ph_ee_env_template_1704892298403prtriggerinputset + orgIdentifier: default + projectIdentifier: default_project + pipeline: + identifier: Build_openMF_ph_ee_env_template_1704892298403 + properties: + ci: + codebase: + build: + type: PR + spec: + number: <+trigger.prNumber> diff --git a/ph-ee-env-template/.harness/Build_openMF_ph_ee_env_template_1704892298403-push-trigger-input-set-1704892300729.yaml b/ph-ee-env-template/.harness/Build_openMF_ph_ee_env_template_1704892298403-push-trigger-input-set-1704892300729.yaml new file mode 100644 index 000000000..2f1edc01a --- /dev/null +++ b/ph-ee-env-template/.harness/Build_openMF_ph_ee_env_template_1704892298403-push-trigger-input-set-1704892300729.yaml @@ -0,0 +1,14 @@ +inputSet: + name: Build_openMF_ph_ee_env_template_1704892298403-push-trigger-input-set + identifier: Build_openMF_ph_ee_env_template_1704892298403pushtriggerinputset + orgIdentifier: default + projectIdentifier: default_project + pipeline: + identifier: Build_openMF_ph_ee_env_template_1704892298403 + properties: + ci: + codebase: + build: + type: branch + spec: + branch: <+trigger.branch> diff --git a/ph-ee-env-template/.harness/pipelines/ph-ee-env-template-1704892291705.yaml b/ph-ee-env-template/.harness/pipelines/ph-ee-env-template-1704892291705.yaml new file mode 100644 index 000000000..e0aaad87a --- /dev/null +++ b/ph-ee-env-template/.harness/pipelines/ph-ee-env-template-1704892291705.yaml @@ -0,0 +1,33 @@ +pipeline: + identifier: Build_openMF_ph_ee_env_template_1704892298403 + name: Build ph-ee-env-template + orgIdentifier: default + projectIdentifier: default_project + properties: + ci: + codebase: + build: <+input> + connectorRef: account.Github + repoName: openMF/ph-ee-env-template + stages: + - stage: + identifier: build + name: build + spec: + cloneCodebase: true + execution: + steps: + - step: + identifier: echo + name: echo + spec: + command: echo hello world + timeout: "" + type: Run + platform: + arch: Amd64 + os: Linux + runtime: + spec: {} + type: Cloud + type: CI diff --git a/ph-ee-env-template/Jenkinsfile b/ph-ee-env-template/Jenkinsfile new file mode 100644 index 000000000..8077f4e00 --- /dev/null +++ b/ph-ee-env-template/Jenkinsfile @@ -0,0 +1,22 @@ +pipeline { + agent any + stages { + stage('deploy helm chart') { + steps { + sh ''' +cd helm/ +cd ph-ee-engine +rm -f Chart.lock requirements.lock charts/* +helm dep up +cd - +rm -f ph-ee-engine-1.0.0-SNAPSHOT.tgz + +helm package ph-ee-engine +helm repo index . + +cp index.yaml ph-ee-engine-1.0.0-SNAPSHOT.tgz /srv/data/helm-charts/ +''' + } + } + } +} diff --git a/ph-ee-env-template/Keycloak/kong-keycloak-realm.json b/ph-ee-env-template/Keycloak/kong-keycloak-realm.json new file mode 100644 index 000000000..315a577d3 --- /dev/null +++ b/ph-ee-env-template/Keycloak/kong-keycloak-realm.json @@ -0,0 +1,2172 @@ +{ + "id": "Kong", + "realm": "Kong", + "notBefore": 0, + "defaultSignatureAlgorithm": "RS256", + "revokeRefreshToken": false, + "refreshTokenMaxReuse": 0, + "accessTokenLifespan": 300, + "accessTokenLifespanForImplicitFlow": 900, + "ssoSessionIdleTimeout": 1800, + "ssoSessionMaxLifespan": 36000, + "ssoSessionIdleTimeoutRememberMe": 0, + "ssoSessionMaxLifespanRememberMe": 0, + "offlineSessionIdleTimeout": 2592000, + "offlineSessionMaxLifespanEnabled": false, + "offlineSessionMaxLifespan": 5184000, + "clientSessionIdleTimeout": 0, + "clientSessionMaxLifespan": 0, + "clientOfflineSessionIdleTimeout": 0, + "clientOfflineSessionMaxLifespan": 0, + "accessCodeLifespan": 60, + "accessCodeLifespanUserAction": 300, + "accessCodeLifespanLogin": 1800, + "actionTokenGeneratedByAdminLifespan": 43200, + "actionTokenGeneratedByUserLifespan": 300, + "oauth2DeviceCodeLifespan": 600, + "oauth2DevicePollingInterval": 5, + "enabled": true, + "sslRequired": "external", + "registrationAllowed": false, + "registrationEmailAsUsername": false, + "rememberMe": false, + "verifyEmail": false, + "loginWithEmailAllowed": true, + "duplicateEmailsAllowed": false, + "resetPasswordAllowed": false, + "editUsernameAllowed": false, + "bruteForceProtected": false, + "permanentLockout": false, + "maxFailureWaitSeconds": 900, + "minimumQuickLoginWaitSeconds": 60, + "waitIncrementSeconds": 60, + "quickLoginCheckMilliSeconds": 1000, + "maxDeltaTimeSeconds": 43200, + "failureFactor": 30, + "roles": { + "realm": [ + { + "id": "e56ce8e6-314f-4bf1-98f6-51d9f3bee0bd", + "name": "uma_authorization", + "description": "${role_uma_authorization}", + "composite": false, + "clientRole": false, + "containerId": "Kong", + "attributes": {} + }, + { + "id": "75cecb6c-eeee-4ac5-ae3f-16fb17d670a5", + "name": "offline_access", + "description": "${role_offline-access}", + "composite": false, + "clientRole": false, + "containerId": "Kong", + "attributes": {} + }, + { + "id": "f306be38-5b0a-4f72-b32c-acc9843c3948", + "name": "default-roles-kong", + "description": "${role_default-roles}", + "composite": true, + "composites": { + "realm": [ + "offline_access", + "uma_authorization" + ], + "client": { + "account": [ + "view-profile", + "manage-account" + ] + } + }, + "clientRole": false, + "containerId": "Kong", + "attributes": {} + } + ], + "client": { + "kong-oidc": [], + "realm-management": [ + { + "id": "2cf527ea-dfbd-4061-9ff2-9016f3be572f", + "name": "manage-events", + "description": "${role_manage-events}", + "composite": false, + "clientRole": true, + "containerId": "a696932a-e9fc-4598-b656-bc4995a9532e", + "attributes": {} + }, + { + "id": "49b1f4e4-e2e5-4809-b8a1-3a1309648a79", + "name": "realm-admin", + "description": "${role_realm-admin}", + "composite": true, + "composites": { + "client": { + "realm-management": [ + "manage-events", + "create-client", + "view-realm", + "manage-realm", + "view-authorization", + "manage-clients", + "manage-identity-providers", + "query-clients", + "query-realms", + "view-users", + "view-clients", + "view-identity-providers", + "manage-users", + "query-users", + "manage-authorization", + "view-events", + "impersonation", + "query-groups" + ] + } + }, + "clientRole": true, + "containerId": "a696932a-e9fc-4598-b656-bc4995a9532e", + "attributes": {} + }, + { + "id": "784f03f8-c24f-4d53-854f-de53e7224eaf", + "name": "create-client", + "description": "${role_create-client}", + "composite": false, + "clientRole": true, + "containerId": "a696932a-e9fc-4598-b656-bc4995a9532e", + "attributes": {} + }, + { + "id": "859464b4-174e-4370-8c20-51c42552f89a", + "name": "view-realm", + "description": "${role_view-realm}", + "composite": false, + "clientRole": true, + "containerId": "a696932a-e9fc-4598-b656-bc4995a9532e", + "attributes": {} + }, + { + "id": "994cdfea-9f7d-4fb9-84d8-9a64d6fd7458", + "name": "manage-realm", + "description": "${role_manage-realm}", + "composite": false, + "clientRole": true, + "containerId": "a696932a-e9fc-4598-b656-bc4995a9532e", + "attributes": {} + }, + { + "id": "b7b27085-bd72-4f3e-b0e3-23a590927127", + "name": "view-authorization", + "description": "${role_view-authorization}", + "composite": false, + "clientRole": true, + "containerId": "a696932a-e9fc-4598-b656-bc4995a9532e", + "attributes": {} + }, + { + "id": "e79a28ab-05ca-44d9-978e-dc98d4b14dbb", + "name": "manage-clients", + "description": "${role_manage-clients}", + "composite": false, + "clientRole": true, + "containerId": "a696932a-e9fc-4598-b656-bc4995a9532e", + "attributes": {} + }, + { + "id": "7358345e-cc0a-40e5-818c-1777e7aaff3b", + "name": "manage-identity-providers", + "description": "${role_manage-identity-providers}", + "composite": false, + "clientRole": true, + "containerId": "a696932a-e9fc-4598-b656-bc4995a9532e", + "attributes": {} + }, + { + "id": "08ba0de2-a85c-406a-8707-8b27a7104a5a", + "name": "query-clients", + "description": "${role_query-clients}", + "composite": false, + "clientRole": true, + "containerId": "a696932a-e9fc-4598-b656-bc4995a9532e", + "attributes": {} + }, + { + "id": "2aca0e4c-a736-4341-af8c-78c836dd01fa", + "name": "query-realms", + "description": "${role_query-realms}", + "composite": false, + "clientRole": true, + "containerId": "a696932a-e9fc-4598-b656-bc4995a9532e", + "attributes": {} + }, + { + "id": "7dc50f4e-7854-460f-9f43-e67971f38704", + "name": "view-clients", + "description": "${role_view-clients}", + "composite": true, + "composites": { + "client": { + "realm-management": [ + "query-clients" + ] + } + }, + "clientRole": true, + "containerId": "a696932a-e9fc-4598-b656-bc4995a9532e", + "attributes": {} + }, + { + "id": "5332e3a6-9283-4256-8ced-edf552d42a23", + "name": "view-users", + "description": "${role_view-users}", + "composite": true, + "composites": { + "client": { + "realm-management": [ + "query-users", + "query-groups" + ] + } + }, + "clientRole": true, + "containerId": "a696932a-e9fc-4598-b656-bc4995a9532e", + "attributes": {} + }, + { + "id": "8cd0251b-6d63-42b5-aa8f-813d6d696dc7", + "name": "manage-users", + "description": "${role_manage-users}", + "composite": false, + "clientRole": true, + "containerId": "a696932a-e9fc-4598-b656-bc4995a9532e", + "attributes": {} + }, + { + "id": "1a80c1f2-8d4e-429e-9983-362d0d1aadfa", + "name": "query-users", + "description": "${role_query-users}", + "composite": false, + "clientRole": true, + "containerId": "a696932a-e9fc-4598-b656-bc4995a9532e", + "attributes": {} + }, + { + "id": "017fba9a-31d5-4c65-8934-931ba58c9d3a", + "name": "view-identity-providers", + "description": "${role_view-identity-providers}", + "composite": false, + "clientRole": true, + "containerId": "a696932a-e9fc-4598-b656-bc4995a9532e", + "attributes": {} + }, + { + "id": "be66f0c8-d654-4f4c-a445-b460fefc548e", + "name": "manage-authorization", + "description": "${role_manage-authorization}", + "composite": false, + "clientRole": true, + "containerId": "a696932a-e9fc-4598-b656-bc4995a9532e", + "attributes": {} + }, + { + "id": "000dad61-9f98-499f-8dd0-f0f7142c29e8", + "name": "view-events", + "description": "${role_view-events}", + "composite": false, + "clientRole": true, + "containerId": "a696932a-e9fc-4598-b656-bc4995a9532e", + "attributes": {} + }, + { + "id": "f99314e6-7877-40e4-b471-705714638dde", + "name": "impersonation", + "description": "${role_impersonation}", + "composite": false, + "clientRole": true, + "containerId": "a696932a-e9fc-4598-b656-bc4995a9532e", + "attributes": {} + }, + { + "id": "4556dea7-a103-41fe-9d78-fff6b1bcb057", + "name": "query-groups", + "description": "${role_query-groups}", + "composite": false, + "clientRole": true, + "containerId": "a696932a-e9fc-4598-b656-bc4995a9532e", + "attributes": {} + } + ], + "security-admin-console": [], + "admin-cli": [], + "account-console": [], + "broker": [ + { + "id": "fb6b3047-933d-4278-b657-191300d65c62", + "name": "read-token", + "description": "${role_read-token}", + "composite": false, + "clientRole": true, + "containerId": "01f4013e-c990-4983-ae7f-7a0d025c0e14", + "attributes": {} + } + ], + "account": [ + { + "id": "05e1d956-aec5-4a59-b4ba-5a765207c405", + "name": "view-applications", + "description": "${role_view-applications}", + "composite": false, + "clientRole": true, + "containerId": "361e8d18-d33a-46ce-b492-a5d19251101a", + "attributes": {} + }, + { + "id": "765b0dea-3f94-42eb-b9d5-f2dc9cf69c1b", + "name": "manage-account-links", + "description": "${role_manage-account-links}", + "composite": false, + "clientRole": true, + "containerId": "361e8d18-d33a-46ce-b492-a5d19251101a", + "attributes": {} + }, + { + "id": "2139eb6e-ef7f-41fb-93d6-752c2dc89a73", + "name": "view-profile", + "description": "${role_view-profile}", + "composite": false, + "clientRole": true, + "containerId": "361e8d18-d33a-46ce-b492-a5d19251101a", + "attributes": {} + }, + { + "id": "16551f6b-109d-4714-903d-f21477d4cbd4", + "name": "manage-account", + "description": "${role_manage-account}", + "composite": true, + "composites": { + "client": { + "account": [ + "manage-account-links" + ] + } + }, + "clientRole": true, + "containerId": "361e8d18-d33a-46ce-b492-a5d19251101a", + "attributes": {} + }, + { + "id": "9f367d45-e730-4462-aac6-8b9fc5cef660", + "name": "view-consent", + "description": "${role_view-consent}", + "composite": false, + "clientRole": true, + "containerId": "361e8d18-d33a-46ce-b492-a5d19251101a", + "attributes": {} + }, + { + "id": "1f06a316-225c-443b-917f-700165ad462a", + "name": "delete-account", + "description": "${role_delete-account}", + "composite": false, + "clientRole": true, + "containerId": "361e8d18-d33a-46ce-b492-a5d19251101a", + "attributes": {} + }, + { + "id": "af167558-8414-4e5c-9e11-61f459e3c914", + "name": "manage-consent", + "description": "${role_manage-consent}", + "composite": true, + "composites": { + "client": { + "account": [ + "view-consent" + ] + } + }, + "clientRole": true, + "containerId": "361e8d18-d33a-46ce-b492-a5d19251101a", + "attributes": {} + } + ] + } + }, + "groups": [ + { + "id": "c5dd34ff-bf1f-43ea-9976-7fb1371f9432", + "name": "test", + "path": "/test", + "attributes": {}, + "realmRoles": [], + "clientRoles": {}, + "subGroups": [] + } + ], + "defaultRole": { + "id": "f306be38-5b0a-4f72-b32c-acc9843c3948", + "name": "default-roles-kong", + "description": "${role_default-roles}", + "composite": true, + "clientRole": false, + "containerId": "Kong" + }, + "requiredCredentials": [ + "password" + ], + "otpPolicyType": "totp", + "otpPolicyAlgorithm": "HmacSHA1", + "otpPolicyInitialCounter": 0, + "otpPolicyDigits": 6, + "otpPolicyLookAheadWindow": 1, + "otpPolicyPeriod": 30, + "otpSupportedApplications": [ + "FreeOTP", + "Google Authenticator" + ], + "webAuthnPolicyRpEntityName": "keycloak", + "webAuthnPolicySignatureAlgorithms": [ + "ES256" + ], + "webAuthnPolicyRpId": "", + "webAuthnPolicyAttestationConveyancePreference": "not specified", + "webAuthnPolicyAuthenticatorAttachment": "not specified", + "webAuthnPolicyRequireResidentKey": "not specified", + "webAuthnPolicyUserVerificationRequirement": "not specified", + "webAuthnPolicyCreateTimeout": 0, + "webAuthnPolicyAvoidSameAuthenticatorRegister": false, + "webAuthnPolicyAcceptableAaguids": [], + "webAuthnPolicyPasswordlessRpEntityName": "keycloak", + "webAuthnPolicyPasswordlessSignatureAlgorithms": [ + "ES256" + ], + "webAuthnPolicyPasswordlessRpId": "", + "webAuthnPolicyPasswordlessAttestationConveyancePreference": "not specified", + "webAuthnPolicyPasswordlessAuthenticatorAttachment": "not specified", + "webAuthnPolicyPasswordlessRequireResidentKey": "not specified", + "webAuthnPolicyPasswordlessUserVerificationRequirement": "not specified", + "webAuthnPolicyPasswordlessCreateTimeout": 0, + "webAuthnPolicyPasswordlessAvoidSameAuthenticatorRegister": false, + "webAuthnPolicyPasswordlessAcceptableAaguids": [], + "scopeMappings": [ + { + "clientScope": "offline_access", + "roles": [ + "offline_access" + ] + } + ], + "clientScopeMappings": { + "account": [ + { + "client": "account-console", + "roles": [ + "manage-account" + ] + } + ] + }, + "clients": [ + { + "id": "361e8d18-d33a-46ce-b492-a5d19251101a", + "clientId": "account", + "name": "${client_account}", + "rootUrl": "${authBaseUrl}", + "baseUrl": "/realms/Kong/account/", + "surrogateAuthRequired": false, + "enabled": true, + "alwaysDisplayInConsole": false, + "clientAuthenticatorType": "client-secret", + "redirectUris": [ + "/realms/Kong/account/*" + ], + "webOrigins": [], + "notBefore": 0, + "bearerOnly": false, + "consentRequired": false, + "standardFlowEnabled": true, + "implicitFlowEnabled": false, + "directAccessGrantsEnabled": false, + "serviceAccountsEnabled": false, + "publicClient": true, + "frontchannelLogout": false, + "protocol": "openid-connect", + "attributes": {}, + "authenticationFlowBindingOverrides": {}, + "fullScopeAllowed": false, + "nodeReRegistrationTimeout": 0, + "defaultClientScopes": [ + "web-origins", + "profile", + "roles", + "email" + ], + "optionalClientScopes": [ + "address", + "phone", + "offline_access", + "microprofile-jwt" + ] + }, + { + "id": "67a7488e-a386-445f-acd1-655e81a641cf", + "clientId": "account-console", + "name": "${client_account-console}", + "rootUrl": "${authBaseUrl}", + "baseUrl": "/realms/Kong/account/", + "surrogateAuthRequired": false, + "enabled": true, + "alwaysDisplayInConsole": false, + "clientAuthenticatorType": "client-secret", + "redirectUris": [ + "/realms/Kong/account/*" + ], + "webOrigins": [], + "notBefore": 0, + "bearerOnly": false, + "consentRequired": false, + "standardFlowEnabled": true, + "implicitFlowEnabled": false, + "directAccessGrantsEnabled": false, + "serviceAccountsEnabled": false, + "publicClient": true, + "frontchannelLogout": false, + "protocol": "openid-connect", + "attributes": { + "pkce.code.challenge.method": "S256" + }, + "authenticationFlowBindingOverrides": {}, + "fullScopeAllowed": false, + "nodeReRegistrationTimeout": 0, + "protocolMappers": [ + { + "id": "6cbfddd1-b385-48ba-86e7-3c6160e5635f", + "name": "audience resolve", + "protocol": "openid-connect", + "protocolMapper": "oidc-audience-resolve-mapper", + "consentRequired": false, + "config": {} + } + ], + "defaultClientScopes": [ + "web-origins", + "profile", + "roles", + "email" + ], + "optionalClientScopes": [ + "address", + "phone", + "offline_access", + "microprofile-jwt" + ] + }, + { + "id": "1fc9f83b-83c2-4769-89af-4ff8a0f09989", + "clientId": "admin-cli", + "name": "${client_admin-cli}", + "surrogateAuthRequired": false, + "enabled": true, + "alwaysDisplayInConsole": false, + "clientAuthenticatorType": "client-secret", + "redirectUris": [], + "webOrigins": [], + "notBefore": 0, + "bearerOnly": false, + "consentRequired": false, + "standardFlowEnabled": false, + "implicitFlowEnabled": false, + "directAccessGrantsEnabled": true, + "serviceAccountsEnabled": false, + "publicClient": true, + "frontchannelLogout": false, + "protocol": "openid-connect", + "attributes": {}, + "authenticationFlowBindingOverrides": {}, + "fullScopeAllowed": false, + "nodeReRegistrationTimeout": 0, + "defaultClientScopes": [ + "web-origins", + "profile", + "roles", + "email" + ], + "optionalClientScopes": [ + "address", + "phone", + "offline_access", + "microprofile-jwt" + ] + }, + { + "id": "01f4013e-c990-4983-ae7f-7a0d025c0e14", + "clientId": "broker", + "name": "${client_broker}", + "surrogateAuthRequired": false, + "enabled": true, + "alwaysDisplayInConsole": false, + "clientAuthenticatorType": "client-secret", + "redirectUris": [], + "webOrigins": [], + "notBefore": 0, + "bearerOnly": true, + "consentRequired": false, + "standardFlowEnabled": true, + "implicitFlowEnabled": false, + "directAccessGrantsEnabled": false, + "serviceAccountsEnabled": false, + "publicClient": false, + "frontchannelLogout": false, + "protocol": "openid-connect", + "attributes": {}, + "authenticationFlowBindingOverrides": {}, + "fullScopeAllowed": false, + "nodeReRegistrationTimeout": 0, + "defaultClientScopes": [ + "web-origins", + "profile", + "roles", + "email" + ], + "optionalClientScopes": [ + "address", + "phone", + "offline_access", + "microprofile-jwt" + ] + }, + { + "id": "578e995e-7de0-4f09-9fa8-c4caab51843f", + "clientId": "kong-oidc", + "surrogateAuthRequired": false, + "enabled": true, + "alwaysDisplayInConsole": false, + "clientAuthenticatorType": "client-secret", + "secret": "**********", + "redirectUris": [ + "*" + ], + "webOrigins": [ + "localhost (Allowed CORS origin)", + "cribbi.io (Allowed CORS origin)" + ], + "notBefore": 0, + "bearerOnly": false, + "consentRequired": false, + "standardFlowEnabled": true, + "implicitFlowEnabled": false, + "directAccessGrantsEnabled": true, + "serviceAccountsEnabled": false, + "publicClient": false, + "frontchannelLogout": false, + "protocol": "openid-connect", + "attributes": { + "saml.force.post.binding": "false", + "saml.multivalued.roles": "false", + "oauth2.device.authorization.grant.enabled": "false", + "backchannel.logout.revoke.offline.tokens": "false", + "saml.server.signature.keyinfo.ext": "false", + "use.refresh.tokens": "true", + "oidc.ciba.grant.enabled": "false", + "backchannel.logout.session.required": "true", + "client_credentials.use_refresh_token": "false", + "require.pushed.authorization.requests": "false", + "saml.client.signature": "false", + "id.token.as.detached.signature": "false", + "saml.assertion.signature": "false", + "saml.encrypt": "false", + "saml.server.signature": "false", + "exclude.session.state.from.auth.response": "false", + "saml.artifact.binding": "false", + "saml_force_name_id_format": "false", + "acr.loa.map": "{}", + "tls.client.certificate.bound.access.tokens": "false", + "saml.authnstatement": "false", + "display.on.consent.screen": "false", + "token.response.type.bearer.lower-case": "false", + "saml.onetimeuse.condition": "false" + }, + "authenticationFlowBindingOverrides": {}, + "fullScopeAllowed": true, + "nodeReRegistrationTimeout": -1, + "defaultClientScopes": [ + "web-origins", + "profile", + "roles", + "email" + ], + "optionalClientScopes": [ + "address", + "phone", + "offline_access", + "microprofile-jwt" + ] + }, + { + "id": "a696932a-e9fc-4598-b656-bc4995a9532e", + "clientId": "realm-management", + "name": "${client_realm-management}", + "surrogateAuthRequired": false, + "enabled": true, + "alwaysDisplayInConsole": false, + "clientAuthenticatorType": "client-secret", + "redirectUris": [], + "webOrigins": [], + "notBefore": 0, + "bearerOnly": true, + "consentRequired": false, + "standardFlowEnabled": true, + "implicitFlowEnabled": false, + "directAccessGrantsEnabled": false, + "serviceAccountsEnabled": false, + "publicClient": false, + "frontchannelLogout": false, + "protocol": "openid-connect", + "attributes": {}, + "authenticationFlowBindingOverrides": {}, + "fullScopeAllowed": false, + "nodeReRegistrationTimeout": 0, + "defaultClientScopes": [ + "web-origins", + "profile", + "roles", + "email" + ], + "optionalClientScopes": [ + "address", + "phone", + "offline_access", + "microprofile-jwt" + ] + }, + { + "id": "50a77f13-4089-4fd1-8648-e13e15259fe0", + "clientId": "security-admin-console", + "name": "${client_security-admin-console}", + "rootUrl": "${authAdminUrl}", + "baseUrl": "/admin/Kong/console/", + "surrogateAuthRequired": false, + "enabled": true, + "alwaysDisplayInConsole": false, + "clientAuthenticatorType": "client-secret", + "redirectUris": [ + "/admin/Kong/console/*" + ], + "webOrigins": [ + "+" + ], + "notBefore": 0, + "bearerOnly": false, + "consentRequired": false, + "standardFlowEnabled": true, + "implicitFlowEnabled": false, + "directAccessGrantsEnabled": false, + "serviceAccountsEnabled": false, + "publicClient": true, + "frontchannelLogout": false, + "protocol": "openid-connect", + "attributes": { + "pkce.code.challenge.method": "S256" + }, + "authenticationFlowBindingOverrides": {}, + "fullScopeAllowed": false, + "nodeReRegistrationTimeout": 0, + "protocolMappers": [ + { + "id": "16d66308-424e-4452-85a2-52cff0320374", + "name": "locale", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "locale", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "locale", + "jsonType.label": "String" + } + } + ], + "defaultClientScopes": [ + "web-origins", + "profile", + "roles", + "email" + ], + "optionalClientScopes": [ + "address", + "phone", + "offline_access", + "microprofile-jwt" + ] + } + ], + "clientScopes": [ + { + "id": "67332a08-3545-43d0-bc9b-96ec04ab7b1d", + "name": "microprofile-jwt", + "description": "Microprofile - JWT built-in scope", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "true", + "display.on.consent.screen": "false" + }, + "protocolMappers": [ + { + "id": "29e8353e-1062-461c-bcbc-24533b66c4f1", + "name": "upn", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-property-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "username", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "upn", + "jsonType.label": "String" + } + }, + { + "id": "3dc57511-4b31-4711-baf2-e7e4a50e2ef6", + "name": "groups", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-realm-role-mapper", + "consentRequired": false, + "config": { + "multivalued": "true", + "user.attribute": "foo", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "groups", + "jsonType.label": "String" + } + } + ] + }, + { + "id": "e5b5ed97-ee0c-4c02-ad2d-c0101b0e0afa", + "name": "profile", + "description": "OpenID Connect built-in scope: profile", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "true", + "display.on.consent.screen": "true", + "consent.screen.text": "${profileScopeConsentText}" + }, + "protocolMappers": [ + { + "id": "f7273dce-bbc2-4c81-a254-85ff4f085aee", + "name": "given name", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-property-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "firstName", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "given_name", + "jsonType.label": "String" + } + }, + { + "id": "071021ea-04dd-4488-818a-fb0f05974405", + "name": "locale", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "locale", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "locale", + "jsonType.label": "String" + } + }, + { + "id": "e7957678-5936-4be8-af5c-f6c0d3fac1c6", + "name": "zoneinfo", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "zoneinfo", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "zoneinfo", + "jsonType.label": "String" + } + }, + { + "id": "904f3690-0e12-4963-8e8d-19cfe8ee2584", + "name": "website", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "website", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "website", + "jsonType.label": "String" + } + }, + { + "id": "924e8b62-a034-4965-9774-31e2194deac1", + "name": "updated at", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "updatedAt", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "updated_at", + "jsonType.label": "String" + } + }, + { + "id": "f824795d-93ed-41aa-9df4-a69aa5ce8e9b", + "name": "username", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-property-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "username", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "preferred_username", + "jsonType.label": "String" + } + }, + { + "id": "c7f4abf7-80ff-4af1-bb8d-fed39588b902", + "name": "middle name", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "middleName", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "middle_name", + "jsonType.label": "String" + } + }, + { + "id": "ea2ecaf4-5bc2-4b1d-9787-44f7336a485d", + "name": "full name", + "protocol": "openid-connect", + "protocolMapper": "oidc-full-name-mapper", + "consentRequired": false, + "config": { + "id.token.claim": "true", + "access.token.claim": "true", + "userinfo.token.claim": "true" + } + }, + { + "id": "b5c860eb-a96f-42de-bc30-d57de18e8167", + "name": "family name", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-property-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "lastName", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "family_name", + "jsonType.label": "String" + } + }, + { + "id": "b31777f1-d8d4-47b6-9cfc-c0a6c6bf9f3c", + "name": "nickname", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "nickname", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "nickname", + "jsonType.label": "String" + } + }, + { + "id": "35a54a53-7ea0-4082-8979-1ad167d6bcee", + "name": "gender", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "gender", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "gender", + "jsonType.label": "String" + } + }, + { + "id": "f98c231e-3d9d-400e-9ff8-3ed607d5c89c", + "name": "profile", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "profile", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "profile", + "jsonType.label": "String" + } + }, + { + "id": "6159c05d-fec9-407e-b433-596460417380", + "name": "picture", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "picture", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "picture", + "jsonType.label": "String" + } + }, + { + "id": "352521b1-7188-4cdd-bcc9-a5e5294f2a00", + "name": "birthdate", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "birthdate", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "birthdate", + "jsonType.label": "String" + } + } + ] + }, + { + "id": "3e886f78-4185-4d08-9d4c-cf4322a3f483", + "name": "email", + "description": "OpenID Connect built-in scope: email", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "true", + "display.on.consent.screen": "true", + "consent.screen.text": "${emailScopeConsentText}" + }, + "protocolMappers": [ + { + "id": "0f38213b-565b-49f3-a1f9-7f3f5c40a93b", + "name": "email", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-property-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "email", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "email", + "jsonType.label": "String" + } + }, + { + "id": "58c8e210-5154-49d3-8515-14826db18ccd", + "name": "email verified", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-property-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "emailVerified", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "email_verified", + "jsonType.label": "boolean" + } + } + ] + }, + { + "id": "3f5aafd7-c703-4aa7-881e-d0a2cd1ff022", + "name": "phone", + "description": "OpenID Connect built-in scope: phone", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "true", + "display.on.consent.screen": "true", + "consent.screen.text": "${phoneScopeConsentText}" + }, + "protocolMappers": [ + { + "id": "42c0ddb2-d2c6-4766-8ac6-b7573e5aa4e0", + "name": "phone number", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "phoneNumber", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "phone_number", + "jsonType.label": "String" + } + }, + { + "id": "6e0ec5d2-6149-4ba8-882f-d2f808750ac0", + "name": "phone number verified", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "phoneNumberVerified", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "phone_number_verified", + "jsonType.label": "boolean" + } + } + ] + }, + { + "id": "1c14fd95-79a4-4142-956a-68369ad383ba", + "name": "roles", + "description": "OpenID Connect scope for add user roles to the access token", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "false", + "display.on.consent.screen": "true", + "consent.screen.text": "${rolesScopeConsentText}" + }, + "protocolMappers": [ + { + "id": "1c0dcbe2-8934-4ff7-bfda-75d7f4499f61", + "name": "client roles", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-client-role-mapper", + "consentRequired": false, + "config": { + "user.attribute": "foo", + "access.token.claim": "true", + "claim.name": "resource_access.${client_id}.roles", + "jsonType.label": "String", + "multivalued": "true" + } + }, + { + "id": "a0228fb1-992d-4981-80a1-282413ffa750", + "name": "realm roles", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-realm-role-mapper", + "consentRequired": false, + "config": { + "user.attribute": "foo", + "access.token.claim": "true", + "claim.name": "realm_access.roles", + "jsonType.label": "String", + "multivalued": "true" + } + }, + { + "id": "aa809dfb-4e86-4b07-a108-982ff5ce05f2", + "name": "audience resolve", + "protocol": "openid-connect", + "protocolMapper": "oidc-audience-resolve-mapper", + "consentRequired": false, + "config": {} + } + ] + }, + { + "id": "984e29a9-934b-48e8-8765-c05b030192db", + "name": "offline_access", + "description": "OpenID Connect built-in scope: offline_access", + "protocol": "openid-connect", + "attributes": { + "consent.screen.text": "${offlineAccessScopeConsentText}", + "display.on.consent.screen": "true" + } + }, + { + "id": "fa54415e-c8de-414e-bfba-2efad0cc096f", + "name": "role_list", + "description": "SAML role list", + "protocol": "saml", + "attributes": { + "consent.screen.text": "${samlRoleListScopeConsentText}", + "display.on.consent.screen": "true" + }, + "protocolMappers": [ + { + "id": "6c111b35-14f0-4080-a729-3dcf54c3f486", + "name": "role list", + "protocol": "saml", + "protocolMapper": "saml-role-list-mapper", + "consentRequired": false, + "config": { + "single": "false", + "attribute.nameformat": "Basic", + "attribute.name": "Role" + } + } + ] + }, + { + "id": "b5ba65c3-f227-4226-a61f-f7903b9dda79", + "name": "web-origins", + "description": "OpenID Connect scope for add allowed web origins to the access token", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "false", + "display.on.consent.screen": "false", + "consent.screen.text": "" + }, + "protocolMappers": [ + { + "id": "aaf653b5-63d0-4653-ba4b-0d6a5adbb503", + "name": "allowed web origins", + "protocol": "openid-connect", + "protocolMapper": "oidc-allowed-origins-mapper", + "consentRequired": false, + "config": {} + } + ] + }, + { + "id": "b6ddeac5-64c3-409b-8455-6199f81afaa7", + "name": "address", + "description": "OpenID Connect built-in scope: address", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "true", + "display.on.consent.screen": "true", + "consent.screen.text": "${addressScopeConsentText}" + }, + "protocolMappers": [ + { + "id": "2026f3a1-de52-4d85-bf9e-2c42b4125d5d", + "name": "address", + "protocol": "openid-connect", + "protocolMapper": "oidc-address-mapper", + "consentRequired": false, + "config": { + "user.attribute.formatted": "formatted", + "user.attribute.country": "country", + "user.attribute.postal_code": "postal_code", + "userinfo.token.claim": "true", + "user.attribute.street": "street", + "id.token.claim": "true", + "user.attribute.region": "region", + "access.token.claim": "true", + "user.attribute.locality": "locality" + } + } + ] + } + ], + "defaultDefaultClientScopes": [ + "role_list", + "profile", + "email", + "roles", + "web-origins" + ], + "defaultOptionalClientScopes": [ + "offline_access", + "address", + "phone", + "microprofile-jwt" + ], + "browserSecurityHeaders": { + "contentSecurityPolicyReportOnly": "", + "xContentTypeOptions": "nosniff", + "xRobotsTag": "none", + "xFrameOptions": "SAMEORIGIN", + "contentSecurityPolicy": "frame-src 'self'; frame-ancestors 'self'; object-src 'none';", + "xXSSProtection": "1; mode=block", + "strictTransportSecurity": "max-age=31536000; includeSubDomains" + }, + "smtpServer": {}, + "eventsEnabled": false, + "eventsListeners": [ + "jboss-logging" + ], + "enabledEventTypes": [], + "adminEventsEnabled": false, + "adminEventsDetailsEnabled": false, + "identityProviders": [], + "identityProviderMappers": [], + "components": { + "org.keycloak.services.clientregistration.policy.ClientRegistrationPolicy": [ + { + "id": "047ce841-138f-4a63-adc2-41c3314222ba", + "name": "Trusted Hosts", + "providerId": "trusted-hosts", + "subType": "anonymous", + "subComponents": {}, + "config": { + "host-sending-registration-request-must-match": [ + "true" + ], + "client-uris-must-match": [ + "true" + ] + } + }, + { + "id": "1634ff3d-d6e8-4f42-a8a7-38a0ccb6e4f2", + "name": "Consent Required", + "providerId": "consent-required", + "subType": "anonymous", + "subComponents": {}, + "config": {} + }, + { + "id": "6ddd1fd4-598a-4cc3-9890-ed4f0586362c", + "name": "Allowed Client Scopes", + "providerId": "allowed-client-templates", + "subType": "anonymous", + "subComponents": {}, + "config": { + "allow-default-scopes": [ + "true" + ] + } + }, + { + "id": "35e64bb1-cfbe-4343-be5c-fbc2218b8b2a", + "name": "Max Clients Limit", + "providerId": "max-clients", + "subType": "anonymous", + "subComponents": {}, + "config": { + "max-clients": [ + "200" + ] + } + }, + { + "id": "656ba51c-48ee-427d-8896-e1af0e0f4d5b", + "name": "Allowed Client Scopes", + "providerId": "allowed-client-templates", + "subType": "authenticated", + "subComponents": {}, + "config": { + "allow-default-scopes": [ + "true" + ] + } + }, + { + "id": "b9d0fbbf-3f54-4f14-8748-4c00dd43bf7c", + "name": "Allowed Protocol Mapper Types", + "providerId": "allowed-protocol-mappers", + "subType": "authenticated", + "subComponents": {}, + "config": { + "allowed-protocol-mapper-types": [ + "saml-role-list-mapper", + "oidc-sha256-pairwise-sub-mapper", + "oidc-address-mapper", + "oidc-usermodel-property-mapper", + "oidc-full-name-mapper", + "saml-user-attribute-mapper", + "saml-user-property-mapper", + "oidc-usermodel-attribute-mapper" + ] + } + }, + { + "id": "4f0f7c7e-fb7f-4c05-8e91-4715e9e0d163", + "name": "Allowed Protocol Mapper Types", + "providerId": "allowed-protocol-mappers", + "subType": "anonymous", + "subComponents": {}, + "config": { + "allowed-protocol-mapper-types": [ + "oidc-address-mapper", + "oidc-full-name-mapper", + "saml-user-property-mapper", + "oidc-usermodel-attribute-mapper", + "oidc-sha256-pairwise-sub-mapper", + "saml-role-list-mapper", + "saml-user-attribute-mapper", + "oidc-usermodel-property-mapper" + ] + } + }, + { + "id": "73f90916-f316-45b1-a5f4-c01dadfb02e8", + "name": "Full Scope Disabled", + "providerId": "scope", + "subType": "anonymous", + "subComponents": {}, + "config": {} + } + ], + "org.keycloak.keys.KeyProvider": [ + { + "id": "1bb336de-2a5a-4c52-a6d7-7d8de191d5b3", + "name": "rsa-enc-generated", + "providerId": "rsa-enc-generated", + "subComponents": {}, + "config": { + "priority": [ + "100" + ], + "algorithm": [ + "RSA-OAEP" + ] + } + }, + { + "id": "b91a01f0-a022-40ef-9a6f-2525408d65ba", + "name": "rsa-generated", + "providerId": "rsa-generated", + "subComponents": {}, + "config": { + "priority": [ + "100" + ] + } + }, + { + "id": "97787b65-617e-4f76-a448-efd954e90f76", + "name": "hmac-generated", + "providerId": "hmac-generated", + "subComponents": {}, + "config": { + "priority": [ + "100" + ], + "algorithm": [ + "HS256" + ] + } + }, + { + "id": "c8e87279-c3c9-40f8-aadf-0aed34733df9", + "name": "aes-generated", + "providerId": "aes-generated", + "subComponents": {}, + "config": { + "priority": [ + "100" + ] + } + } + ] + }, + "internationalizationEnabled": false, + "supportedLocales": [], + "authenticationFlows": [ + { + "id": "f180127f-0236-4ac9-a512-1faf661ce8f4", + "alias": "Account verification options", + "description": "Method with which to verity the existing account", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "idp-email-verification", + "authenticatorFlow": false, + "requirement": "ALTERNATIVE", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "ALTERNATIVE", + "priority": 20, + "autheticatorFlow": true, + "flowAlias": "Verify Existing Account by Re-authentication", + "userSetupAllowed": false + } + ] + }, + { + "id": "deec2692-a27c-4aaf-b12d-096dd94e80bb", + "alias": "Authentication Options", + "description": "Authentication options.", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "basic-auth", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "basic-auth-otp", + "authenticatorFlow": false, + "requirement": "DISABLED", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "auth-spnego", + "authenticatorFlow": false, + "requirement": "DISABLED", + "priority": 30, + "autheticatorFlow": false, + "userSetupAllowed": false + } + ] + }, + { + "id": "46e967c9-e9f3-4902-bed7-b7fcd7ac552d", + "alias": "Browser - Conditional OTP", + "description": "Flow to determine if the OTP is required for the authentication", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "conditional-user-configured", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "auth-otp-form", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + } + ] + }, + { + "id": "90dcf889-ae92-407f-b80c-3d895a0944b4", + "alias": "Direct Grant - Conditional OTP", + "description": "Flow to determine if the OTP is required for the authentication", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "conditional-user-configured", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "direct-grant-validate-otp", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + } + ] + }, + { + "id": "f7d55ec4-fff1-4c0c-bf0a-1bd9e6738bff", + "alias": "First broker login - Conditional OTP", + "description": "Flow to determine if the OTP is required for the authentication", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "conditional-user-configured", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "auth-otp-form", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + } + ] + }, + { + "id": "0a8e1e82-33e8-48c0-b0db-38a20ffe9a2d", + "alias": "Handle Existing Account", + "description": "Handle what to do if there is existing account with same email/username like authenticated identity provider", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "idp-confirm-link", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "REQUIRED", + "priority": 20, + "autheticatorFlow": true, + "flowAlias": "Account verification options", + "userSetupAllowed": false + } + ] + }, + { + "id": "1db84d52-1c92-4ce4-95c0-033cfe94f0f3", + "alias": "Reset - Conditional OTP", + "description": "Flow to determine if the OTP should be reset or not. Set to REQUIRED to force.", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "conditional-user-configured", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "reset-otp", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + } + ] + }, + { + "id": "02deb437-dc9c-4e36-b73f-34fa609bf5c0", + "alias": "User creation or linking", + "description": "Flow for the existing/non-existing user alternatives", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticatorConfig": "create unique user config", + "authenticator": "idp-create-user-if-unique", + "authenticatorFlow": false, + "requirement": "ALTERNATIVE", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "ALTERNATIVE", + "priority": 20, + "autheticatorFlow": true, + "flowAlias": "Handle Existing Account", + "userSetupAllowed": false + } + ] + }, + { + "id": "6820ed9f-e18d-4ad1-9e08-79a369f1d501", + "alias": "Verify Existing Account by Re-authentication", + "description": "Reauthentication of existing account", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "idp-username-password-form", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "CONDITIONAL", + "priority": 20, + "autheticatorFlow": true, + "flowAlias": "First broker login - Conditional OTP", + "userSetupAllowed": false + } + ] + }, + { + "id": "0de7d34e-cdea-49eb-93b2-241c83b6aeae", + "alias": "browser", + "description": "browser based authentication", + "providerId": "basic-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "auth-cookie", + "authenticatorFlow": false, + "requirement": "ALTERNATIVE", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "auth-spnego", + "authenticatorFlow": false, + "requirement": "DISABLED", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "identity-provider-redirector", + "authenticatorFlow": false, + "requirement": "ALTERNATIVE", + "priority": 25, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "ALTERNATIVE", + "priority": 30, + "autheticatorFlow": true, + "flowAlias": "forms", + "userSetupAllowed": false + } + ] + }, + { + "id": "8ee4765d-e660-448d-8fd8-a356dc08d88e", + "alias": "clients", + "description": "Base authentication for clients", + "providerId": "client-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "client-secret", + "authenticatorFlow": false, + "requirement": "ALTERNATIVE", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "client-jwt", + "authenticatorFlow": false, + "requirement": "ALTERNATIVE", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "client-secret-jwt", + "authenticatorFlow": false, + "requirement": "ALTERNATIVE", + "priority": 30, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "client-x509", + "authenticatorFlow": false, + "requirement": "ALTERNATIVE", + "priority": 40, + "autheticatorFlow": false, + "userSetupAllowed": false + } + ] + }, + { + "id": "bd9c9450-1a92-4ffc-ac3c-b1b8c3a038d2", + "alias": "direct grant", + "description": "OpenID Connect Resource Owner Grant", + "providerId": "basic-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "direct-grant-validate-username", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "direct-grant-validate-password", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "CONDITIONAL", + "priority": 30, + "autheticatorFlow": true, + "flowAlias": "Direct Grant - Conditional OTP", + "userSetupAllowed": false + } + ] + }, + { + "id": "2727dd7b-89d9-4063-b813-4489cc7310fb", + "alias": "docker auth", + "description": "Used by Docker clients to authenticate against the IDP", + "providerId": "basic-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "docker-http-basic-authenticator", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + } + ] + }, + { + "id": "9e332813-ea2e-46e1-bd74-323b49fe7a40", + "alias": "first broker login", + "description": "Actions taken after first broker login with identity provider account, which is not yet linked to any Keycloak account", + "providerId": "basic-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticatorConfig": "review profile config", + "authenticator": "idp-review-profile", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "REQUIRED", + "priority": 20, + "autheticatorFlow": true, + "flowAlias": "User creation or linking", + "userSetupAllowed": false + } + ] + }, + { + "id": "710dfe13-0fd3-48d3-959d-a541620544e3", + "alias": "forms", + "description": "Username, password, otp and other auth forms.", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "auth-username-password-form", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "CONDITIONAL", + "priority": 20, + "autheticatorFlow": true, + "flowAlias": "Browser - Conditional OTP", + "userSetupAllowed": false + } + ] + }, + { + "id": "3c9456b1-8c60-4409-af25-af6f567cf7c0", + "alias": "http challenge", + "description": "An authentication flow based on challenge-response HTTP Authentication Schemes", + "providerId": "basic-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "no-cookie-redirect", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "REQUIRED", + "priority": 20, + "autheticatorFlow": true, + "flowAlias": "Authentication Options", + "userSetupAllowed": false + } + ] + }, + { + "id": "214d41fe-ba80-478b-bcd9-a15221f79801", + "alias": "registration", + "description": "registration flow", + "providerId": "basic-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "registration-page-form", + "authenticatorFlow": true, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": true, + "flowAlias": "registration form", + "userSetupAllowed": false + } + ] + }, + { + "id": "bd3b9631-d962-43cb-9042-580f30e5544e", + "alias": "registration form", + "description": "registration form", + "providerId": "form-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "registration-user-creation", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "registration-profile-action", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 40, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "registration-password-action", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 50, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "registration-recaptcha-action", + "authenticatorFlow": false, + "requirement": "DISABLED", + "priority": 60, + "autheticatorFlow": false, + "userSetupAllowed": false + } + ] + }, + { + "id": "f9ef35b4-e352-4637-8988-0b06810485a0", + "alias": "reset credentials", + "description": "Reset credentials for a user if they forgot their password or something", + "providerId": "basic-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "reset-credentials-choose-user", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "reset-credential-email", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "reset-password", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 30, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "CONDITIONAL", + "priority": 40, + "autheticatorFlow": true, + "flowAlias": "Reset - Conditional OTP", + "userSetupAllowed": false + } + ] + }, + { + "id": "5ffd4f1f-30a0-4c96-adde-407a08d036cf", + "alias": "saml ecp", + "description": "SAML ECP Profile Authentication Flow", + "providerId": "basic-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "http-basic-authenticator", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + } + ] + } + ], + "authenticatorConfig": [ + { + "id": "335da768-988c-46a4-9928-e97285cf23b2", + "alias": "create unique user config", + "config": { + "require.password.update.after.registration": "false" + } + }, + { + "id": "b671f49e-3824-4c80-b933-540a55f1dd37", + "alias": "review profile config", + "config": { + "update.profile.on.first.login": "missing" + } + } + ], + "requiredActions": [ + { + "alias": "CONFIGURE_TOTP", + "name": "Configure OTP", + "providerId": "CONFIGURE_TOTP", + "enabled": true, + "defaultAction": false, + "priority": 10, + "config": {} + }, + { + "alias": "terms_and_conditions", + "name": "Terms and Conditions", + "providerId": "terms_and_conditions", + "enabled": false, + "defaultAction": false, + "priority": 20, + "config": {} + }, + { + "alias": "UPDATE_PASSWORD", + "name": "Update Password", + "providerId": "UPDATE_PASSWORD", + "enabled": true, + "defaultAction": false, + "priority": 30, + "config": {} + }, + { + "alias": "UPDATE_PROFILE", + "name": "Update Profile", + "providerId": "UPDATE_PROFILE", + "enabled": true, + "defaultAction": false, + "priority": 40, + "config": {} + }, + { + "alias": "VERIFY_EMAIL", + "name": "Verify Email", + "providerId": "VERIFY_EMAIL", + "enabled": true, + "defaultAction": false, + "priority": 50, + "config": {} + }, + { + "alias": "delete_account", + "name": "Delete Account", + "providerId": "delete_account", + "enabled": false, + "defaultAction": false, + "priority": 60, + "config": {} + }, + { + "alias": "update_user_locale", + "name": "Update User Locale", + "providerId": "update_user_locale", + "enabled": true, + "defaultAction": false, + "priority": 1000, + "config": {} + } + ], + "browserFlow": "browser", + "registrationFlow": "registration", + "directGrantFlow": "direct grant", + "resetCredentialsFlow": "reset credentials", + "clientAuthenticationFlow": "clients", + "dockerAuthenticationFlow": "docker auth", + "attributes": { + "cibaBackchannelTokenDeliveryMode": "poll", + "cibaExpiresIn": "120", + "cibaAuthRequestedUserHint": "login_hint", + "oauth2DeviceCodeLifespan": "600", + "oauth2DevicePollingInterval": "5", + "parRequestUriLifespan": "60", + "cibaInterval": "5" + }, + "keycloakVersion": "17.0.1", + "userManagedAccessAllowed": false, + "clientProfiles": { + "profiles": [] + }, + "clientPolicies": { + "policies": [] + } +} \ No newline at end of file diff --git a/ph-ee-env-template/Keycloak/paymenthub-realm.json b/ph-ee-env-template/Keycloak/paymenthub-realm.json new file mode 100644 index 000000000..fc3d7ff8d --- /dev/null +++ b/ph-ee-env-template/Keycloak/paymenthub-realm.json @@ -0,0 +1,2175 @@ +{ + "id": "Paymenthub", + "realm": "paymenthub", + "notBefore": 0, + "defaultSignatureAlgorithm": "RS256", + "revokeRefreshToken": false, + "refreshTokenMaxReuse": 0, + "accessTokenLifespan": 300, + "accessTokenLifespanForImplicitFlow": 900, + "ssoSessionIdleTimeout": 1800, + "ssoSessionMaxLifespan": 36000, + "ssoSessionIdleTimeoutRememberMe": 0, + "ssoSessionMaxLifespanRememberMe": 0, + "offlineSessionIdleTimeout": 2592000, + "offlineSessionMaxLifespanEnabled": false, + "offlineSessionMaxLifespan": 5184000, + "clientSessionIdleTimeout": 0, + "clientSessionMaxLifespan": 0, + "clientOfflineSessionIdleTimeout": 0, + "clientOfflineSessionMaxLifespan": 0, + "accessCodeLifespan": 60, + "accessCodeLifespanUserAction": 300, + "accessCodeLifespanLogin": 1800, + "actionTokenGeneratedByAdminLifespan": 43200, + "actionTokenGeneratedByUserLifespan": 300, + "oauth2DeviceCodeLifespan": 600, + "oauth2DevicePollingInterval": 5, + "enabled": false, + "sslRequired": "external", + "registrationAllowed": true, + "registrationEmailAsUsername": false, + "rememberMe": false, + "verifyEmail": false, + "loginWithEmailAllowed": true, + "duplicateEmailsAllowed": false, + "resetPasswordAllowed": false, + "editUsernameAllowed": false, + "bruteForceProtected": false, + "permanentLockout": false, + "maxFailureWaitSeconds": 900, + "minimumQuickLoginWaitSeconds": 60, + "waitIncrementSeconds": 60, + "quickLoginCheckMilliSeconds": 1000, + "maxDeltaTimeSeconds": 43200, + "failureFactor": 30, + "roles": { + "realm": [ + { + "id": "549c51ad-a639-4fde-a465-762301fca598", + "name": "offline_access", + "description": "${role_offline-access}", + "composite": false, + "clientRole": false, + "containerId": "Paymenthub", + "attributes": {} + }, + { + "id": "e33a712c-1359-4eb7-b885-c5daac2b50cb", + "name": "default-roles-paymenthub", + "description": "${role_default-roles}", + "composite": true, + "composites": { + "realm": [ + "offline_access", + "uma_authorization" + ], + "client": { + "account": [ + "view-profile", + "manage-account" + ] + } + }, + "clientRole": false, + "containerId": "Paymenthub", + "attributes": {} + }, + { + "id": "286a97f9-1073-450e-9199-6f05b5d08e30", + "name": "uma_authorization", + "description": "${role_uma_authorization}", + "composite": false, + "clientRole": false, + "containerId": "Paymenthub", + "attributes": {} + } + ], + "client": { + "kong-oidc": [], + "realm-management": [ + { + "id": "9b836414-5acd-43dd-b848-b127d92d3bcf", + "name": "manage-identity-providers", + "description": "${role_manage-identity-providers}", + "composite": false, + "clientRole": true, + "containerId": "46adff7b-9cad-46da-92c8-2fdb15ff2d92", + "attributes": {} + }, + { + "id": "fd65877e-c584-4b45-ba97-1187bc9ac8f6", + "name": "create-client", + "description": "${role_create-client}", + "composite": false, + "clientRole": true, + "containerId": "46adff7b-9cad-46da-92c8-2fdb15ff2d92", + "attributes": {} + }, + { + "id": "9ddbfaae-180d-4358-999f-ebb963e860c0", + "name": "impersonation", + "description": "${role_impersonation}", + "composite": false, + "clientRole": true, + "containerId": "46adff7b-9cad-46da-92c8-2fdb15ff2d92", + "attributes": {} + }, + { + "id": "25f137a6-8268-4231-892f-cc3ede67e640", + "name": "manage-users", + "description": "${role_manage-users}", + "composite": false, + "clientRole": true, + "containerId": "46adff7b-9cad-46da-92c8-2fdb15ff2d92", + "attributes": {} + }, + { + "id": "73baa2be-9553-427c-bc9a-a0fa12d216ac", + "name": "query-groups", + "description": "${role_query-groups}", + "composite": false, + "clientRole": true, + "containerId": "46adff7b-9cad-46da-92c8-2fdb15ff2d92", + "attributes": {} + }, + { + "id": "6f3a867d-ce35-400d-ae1a-f9a5ccd51815", + "name": "query-users", + "description": "${role_query-users}", + "composite": false, + "clientRole": true, + "containerId": "46adff7b-9cad-46da-92c8-2fdb15ff2d92", + "attributes": {} + }, + { + "id": "201f75d3-f752-40f3-951b-0b828af325f8", + "name": "view-realm", + "description": "${role_view-realm}", + "composite": false, + "clientRole": true, + "containerId": "46adff7b-9cad-46da-92c8-2fdb15ff2d92", + "attributes": {} + }, + { + "id": "b8767be4-111d-453c-8186-875a90d3cf67", + "name": "query-clients", + "description": "${role_query-clients}", + "composite": false, + "clientRole": true, + "containerId": "46adff7b-9cad-46da-92c8-2fdb15ff2d92", + "attributes": {} + }, + { + "id": "13ac89fd-3d18-442a-834f-c71168d5440c", + "name": "manage-authorization", + "description": "${role_manage-authorization}", + "composite": false, + "clientRole": true, + "containerId": "46adff7b-9cad-46da-92c8-2fdb15ff2d92", + "attributes": {} + }, + { + "id": "d348d05c-d12f-4fdd-b539-461c05515498", + "name": "realm-admin", + "description": "${role_realm-admin}", + "composite": true, + "composites": { + "client": { + "realm-management": [ + "manage-identity-providers", + "create-client", + "manage-users", + "impersonation", + "view-realm", + "query-users", + "query-groups", + "query-clients", + "manage-authorization", + "view-identity-providers", + "view-users", + "manage-realm", + "manage-events", + "view-clients", + "view-events", + "query-realms", + "view-authorization", + "manage-clients" + ] + } + }, + "clientRole": true, + "containerId": "46adff7b-9cad-46da-92c8-2fdb15ff2d92", + "attributes": {} + }, + { + "id": "e0c0d4f4-c6ad-471b-8c3f-5989ef05ec86", + "name": "view-identity-providers", + "description": "${role_view-identity-providers}", + "composite": false, + "clientRole": true, + "containerId": "46adff7b-9cad-46da-92c8-2fdb15ff2d92", + "attributes": {} + }, + { + "id": "a06e6a9f-d5df-4543-9c9b-920768f9fa76", + "name": "manage-realm", + "description": "${role_manage-realm}", + "composite": false, + "clientRole": true, + "containerId": "46adff7b-9cad-46da-92c8-2fdb15ff2d92", + "attributes": {} + }, + { + "id": "91b8fa7b-690d-46a6-b33d-6c27bc52ffc1", + "name": "view-users", + "description": "${role_view-users}", + "composite": true, + "composites": { + "client": { + "realm-management": [ + "query-users", + "query-groups" + ] + } + }, + "clientRole": true, + "containerId": "46adff7b-9cad-46da-92c8-2fdb15ff2d92", + "attributes": {} + }, + { + "id": "4f85c9b3-d6ae-4955-9bef-2c4c7db29301", + "name": "manage-events", + "description": "${role_manage-events}", + "composite": false, + "clientRole": true, + "containerId": "46adff7b-9cad-46da-92c8-2fdb15ff2d92", + "attributes": {} + }, + { + "id": "9919fc5d-cd43-418f-a4e1-012b8822ba6b", + "name": "view-clients", + "description": "${role_view-clients}", + "composite": true, + "composites": { + "client": { + "realm-management": [ + "query-clients" + ] + } + }, + "clientRole": true, + "containerId": "46adff7b-9cad-46da-92c8-2fdb15ff2d92", + "attributes": {} + }, + { + "id": "b140e61b-7779-4fba-853c-731d42472206", + "name": "view-events", + "description": "${role_view-events}", + "composite": false, + "clientRole": true, + "containerId": "46adff7b-9cad-46da-92c8-2fdb15ff2d92", + "attributes": {} + }, + { + "id": "96abd872-0703-4251-b3bd-9e62f20dcc91", + "name": "query-realms", + "description": "${role_query-realms}", + "composite": false, + "clientRole": true, + "containerId": "46adff7b-9cad-46da-92c8-2fdb15ff2d92", + "attributes": {} + }, + { + "id": "9c69385c-d158-41bb-90ad-6de05db28c8b", + "name": "view-authorization", + "description": "${role_view-authorization}", + "composite": false, + "clientRole": true, + "containerId": "46adff7b-9cad-46da-92c8-2fdb15ff2d92", + "attributes": {} + }, + { + "id": "2ab01fd8-856d-4b82-a1b6-51992763e3ec", + "name": "manage-clients", + "description": "${role_manage-clients}", + "composite": false, + "clientRole": true, + "containerId": "46adff7b-9cad-46da-92c8-2fdb15ff2d92", + "attributes": {} + } + ], + "security-admin-console": [], + "admin-cli": [], + "account-console": [], + "broker": [ + { + "id": "bf68bf87-706e-4190-b752-40f2dd897843", + "name": "read-token", + "description": "${role_read-token}", + "composite": false, + "clientRole": true, + "containerId": "225ff448-e199-445a-9a82-f649cd0b9f7d", + "attributes": {} + } + ], + "account": [ + { + "id": "164dc953-052f-4288-a9b8-37ddb9b58f40", + "name": "view-consent", + "description": "${role_view-consent}", + "composite": false, + "clientRole": true, + "containerId": "7e9648be-e884-482a-b42d-b21b9c5baf22", + "attributes": {} + }, + { + "id": "85b7419d-1de0-4d2b-9607-588164079a67", + "name": "manage-consent", + "description": "${role_manage-consent}", + "composite": true, + "composites": { + "client": { + "account": [ + "view-consent" + ] + } + }, + "clientRole": true, + "containerId": "7e9648be-e884-482a-b42d-b21b9c5baf22", + "attributes": {} + }, + { + "id": "2bb052fe-06e1-4e64-8f5a-668d5f2a0d0f", + "name": "view-applications", + "description": "${role_view-applications}", + "composite": false, + "clientRole": true, + "containerId": "7e9648be-e884-482a-b42d-b21b9c5baf22", + "attributes": {} + }, + { + "id": "8c07a465-cf02-43a4-9983-a4574004b29c", + "name": "view-profile", + "description": "${role_view-profile}", + "composite": false, + "clientRole": true, + "containerId": "7e9648be-e884-482a-b42d-b21b9c5baf22", + "attributes": {} + }, + { + "id": "82852ff9-6405-42e2-906d-d0fe03664f31", + "name": "delete-account", + "description": "${role_delete-account}", + "composite": false, + "clientRole": true, + "containerId": "7e9648be-e884-482a-b42d-b21b9c5baf22", + "attributes": {} + }, + { + "id": "6f4787fe-499a-42a4-a85e-0a4dd5c6671f", + "name": "manage-account-links", + "description": "${role_manage-account-links}", + "composite": false, + "clientRole": true, + "containerId": "7e9648be-e884-482a-b42d-b21b9c5baf22", + "attributes": {} + }, + { + "id": "ba790c83-6951-452e-9ae2-ef1c4c04957b", + "name": "manage-account", + "description": "${role_manage-account}", + "composite": true, + "composites": { + "client": { + "account": [ + "manage-account-links" + ] + } + }, + "clientRole": true, + "containerId": "7e9648be-e884-482a-b42d-b21b9c5baf22", + "attributes": {} + } + ] + } + }, + "groups": [], + "defaultRole": { + "id": "e33a712c-1359-4eb7-b885-c5daac2b50cb", + "name": "default-roles-paymenthub", + "description": "${role_default-roles}", + "composite": true, + "clientRole": false, + "containerId": "Paymenthub" + }, + "requiredCredentials": [ + "password" + ], + "otpPolicyType": "totp", + "otpPolicyAlgorithm": "HmacSHA1", + "otpPolicyInitialCounter": 0, + "otpPolicyDigits": 6, + "otpPolicyLookAheadWindow": 1, + "otpPolicyPeriod": 30, + "otpSupportedApplications": [ + "FreeOTP", + "Google Authenticator" + ], + "webAuthnPolicyRpEntityName": "keycloak", + "webAuthnPolicySignatureAlgorithms": [ + "ES256" + ], + "webAuthnPolicyRpId": "", + "webAuthnPolicyAttestationConveyancePreference": "not specified", + "webAuthnPolicyAuthenticatorAttachment": "not specified", + "webAuthnPolicyRequireResidentKey": "not specified", + "webAuthnPolicyUserVerificationRequirement": "not specified", + "webAuthnPolicyCreateTimeout": 0, + "webAuthnPolicyAvoidSameAuthenticatorRegister": false, + "webAuthnPolicyAcceptableAaguids": [], + "webAuthnPolicyPasswordlessRpEntityName": "keycloak", + "webAuthnPolicyPasswordlessSignatureAlgorithms": [ + "ES256" + ], + "webAuthnPolicyPasswordlessRpId": "", + "webAuthnPolicyPasswordlessAttestationConveyancePreference": "not specified", + "webAuthnPolicyPasswordlessAuthenticatorAttachment": "not specified", + "webAuthnPolicyPasswordlessRequireResidentKey": "not specified", + "webAuthnPolicyPasswordlessUserVerificationRequirement": "not specified", + "webAuthnPolicyPasswordlessCreateTimeout": 0, + "webAuthnPolicyPasswordlessAvoidSameAuthenticatorRegister": false, + "webAuthnPolicyPasswordlessAcceptableAaguids": [], + "scopeMappings": [ + { + "clientScope": "offline_access", + "roles": [ + "offline_access" + ] + } + ], + "clientScopeMappings": { + "account": [ + { + "client": "account-console", + "roles": [ + "manage-account" + ] + } + ] + }, + "clients": [ + { + "id": "7e9648be-e884-482a-b42d-b21b9c5baf22", + "clientId": "account", + "name": "${client_account}", + "rootUrl": "${authBaseUrl}", + "baseUrl": "/realms/paymenthub/account/", + "surrogateAuthRequired": false, + "enabled": true, + "alwaysDisplayInConsole": false, + "clientAuthenticatorType": "client-secret", + "redirectUris": [ + "/realms/paymenthub/account/*" + ], + "webOrigins": [], + "notBefore": 0, + "bearerOnly": false, + "consentRequired": false, + "standardFlowEnabled": true, + "implicitFlowEnabled": false, + "directAccessGrantsEnabled": false, + "serviceAccountsEnabled": false, + "publicClient": true, + "frontchannelLogout": false, + "protocol": "openid-connect", + "attributes": {}, + "authenticationFlowBindingOverrides": {}, + "fullScopeAllowed": false, + "nodeReRegistrationTimeout": 0, + "defaultClientScopes": [ + "web-origins", + "roles", + "profile", + "email" + ], + "optionalClientScopes": [ + "address", + "phone", + "offline_access", + "microprofile-jwt" + ] + }, + { + "id": "4d1c448b-7012-4ddb-93ca-47af71992b42", + "clientId": "account-console", + "name": "${client_account-console}", + "rootUrl": "${authBaseUrl}", + "baseUrl": "/realms/Paymenthub/account/", + "surrogateAuthRequired": false, + "enabled": true, + "alwaysDisplayInConsole": false, + "clientAuthenticatorType": "client-secret", + "redirectUris": [ + "/realms/Paymenthub/account/*" + ], + "webOrigins": [], + "notBefore": 0, + "bearerOnly": false, + "consentRequired": false, + "standardFlowEnabled": true, + "implicitFlowEnabled": false, + "directAccessGrantsEnabled": false, + "serviceAccountsEnabled": false, + "publicClient": true, + "frontchannelLogout": false, + "protocol": "openid-connect", + "attributes": { + "pkce.code.challenge.method": "S256" + }, + "authenticationFlowBindingOverrides": {}, + "fullScopeAllowed": false, + "nodeReRegistrationTimeout": 0, + "protocolMappers": [ + { + "id": "b24f506a-cfc7-4824-b1ef-ebf75156a671", + "name": "audience resolve", + "protocol": "openid-connect", + "protocolMapper": "oidc-audience-resolve-mapper", + "consentRequired": false, + "config": {} + } + ], + "defaultClientScopes": [ + "web-origins", + "roles", + "profile", + "email" + ], + "optionalClientScopes": [ + "address", + "phone", + "offline_access", + "microprofile-jwt" + ] + }, + { + "id": "96c93b5b-ee00-4290-8e32-995ba282dce3", + "clientId": "admin-cli", + "name": "${client_admin-cli}", + "surrogateAuthRequired": false, + "enabled": true, + "alwaysDisplayInConsole": false, + "clientAuthenticatorType": "client-secret", + "redirectUris": [], + "webOrigins": [], + "notBefore": 0, + "bearerOnly": false, + "consentRequired": false, + "standardFlowEnabled": false, + "implicitFlowEnabled": false, + "directAccessGrantsEnabled": true, + "serviceAccountsEnabled": false, + "publicClient": true, + "frontchannelLogout": false, + "protocol": "openid-connect", + "attributes": {}, + "authenticationFlowBindingOverrides": {}, + "fullScopeAllowed": false, + "nodeReRegistrationTimeout": 0, + "defaultClientScopes": [ + "web-origins", + "roles", + "profile", + "email" + ], + "optionalClientScopes": [ + "address", + "phone", + "offline_access", + "microprofile-jwt" + ] + }, + { + "id": "225ff448-e199-445a-9a82-f649cd0b9f7d", + "clientId": "broker", + "name": "${client_broker}", + "surrogateAuthRequired": false, + "enabled": true, + "alwaysDisplayInConsole": false, + "clientAuthenticatorType": "client-secret", + "redirectUris": [], + "webOrigins": [], + "notBefore": 0, + "bearerOnly": true, + "consentRequired": false, + "standardFlowEnabled": true, + "implicitFlowEnabled": false, + "directAccessGrantsEnabled": false, + "serviceAccountsEnabled": false, + "publicClient": false, + "frontchannelLogout": false, + "protocol": "openid-connect", + "attributes": {}, + "authenticationFlowBindingOverrides": {}, + "fullScopeAllowed": false, + "nodeReRegistrationTimeout": 0, + "defaultClientScopes": [ + "web-origins", + "roles", + "profile", + "email" + ], + "optionalClientScopes": [ + "address", + "phone", + "offline_access", + "microprofile-jwt" + ] + }, + { + "id": "a67c6071-b06e-4e06-b948-caacdf29ab3b", + "clientId": "kong-oidc", + "surrogateAuthRequired": false, + "enabled": true, + "alwaysDisplayInConsole": false, + "clientAuthenticatorType": "client-secret", + "secret": "**********", + "redirectUris": [ + "*" + ], + "webOrigins": [ + "localhost (Allowed CORS origin)", + "cribbi.io (Allowed CORS origin)" + ], + "notBefore": 0, + "bearerOnly": false, + "consentRequired": false, + "standardFlowEnabled": true, + "implicitFlowEnabled": false, + "directAccessGrantsEnabled": true, + "serviceAccountsEnabled": false, + "publicClient": false, + "frontchannelLogout": false, + "protocol": "openid-connect", + "attributes": { + "saml.force.post.binding": "false", + "saml.multivalued.roles": "false", + "oauth2.device.authorization.grant.enabled": "false", + "backchannel.logout.revoke.offline.tokens": "false", + "saml.server.signature.keyinfo.ext": "false", + "use.refresh.tokens": "true", + "oidc.ciba.grant.enabled": "false", + "backchannel.logout.session.required": "true", + "client_credentials.use_refresh_token": "false", + "require.pushed.authorization.requests": "false", + "saml.client.signature": "false", + "id.token.as.detached.signature": "false", + "saml.assertion.signature": "false", + "saml.encrypt": "false", + "saml.server.signature": "false", + "exclude.session.state.from.auth.response": "false", + "saml.artifact.binding": "false", + "saml_force_name_id_format": "false", + "acr.loa.map": "{}", + "tls.client.certificate.bound.access.tokens": "false", + "saml.authnstatement": "false", + "display.on.consent.screen": "false", + "token.response.type.bearer.lower-case": "false", + "saml.onetimeuse.condition": "false" + }, + "authenticationFlowBindingOverrides": {}, + "fullScopeAllowed": true, + "nodeReRegistrationTimeout": -1, + "defaultClientScopes": [ + "web-origins", + "roles", + "profile", + "email" + ], + "optionalClientScopes": [ + "address", + "phone", + "offline_access", + "microprofile-jwt" + ] + }, + { + "id": "46adff7b-9cad-46da-92c8-2fdb15ff2d92", + "clientId": "realm-management", + "name": "${client_realm-management}", + "surrogateAuthRequired": false, + "enabled": true, + "alwaysDisplayInConsole": false, + "clientAuthenticatorType": "client-secret", + "redirectUris": [], + "webOrigins": [], + "notBefore": 0, + "bearerOnly": true, + "consentRequired": false, + "standardFlowEnabled": true, + "implicitFlowEnabled": false, + "directAccessGrantsEnabled": false, + "serviceAccountsEnabled": false, + "publicClient": false, + "frontchannelLogout": false, + "protocol": "openid-connect", + "attributes": {}, + "authenticationFlowBindingOverrides": {}, + "fullScopeAllowed": false, + "nodeReRegistrationTimeout": 0, + "defaultClientScopes": [ + "web-origins", + "roles", + "profile", + "email" + ], + "optionalClientScopes": [ + "address", + "phone", + "offline_access", + "microprofile-jwt" + ] + }, + { + "id": "d18dc49b-eb0e-474a-8f67-f0a4fae0a48f", + "clientId": "security-admin-console", + "name": "${client_security-admin-console}", + "rootUrl": "${authAdminUrl}", + "baseUrl": "/admin/paymenthub/console/", + "surrogateAuthRequired": false, + "enabled": true, + "alwaysDisplayInConsole": false, + "clientAuthenticatorType": "client-secret", + "redirectUris": [ + "/admin/paymenthub/console/*" + ], + "webOrigins": [ + "+" + ], + "notBefore": 0, + "bearerOnly": false, + "consentRequired": false, + "standardFlowEnabled": true, + "implicitFlowEnabled": false, + "directAccessGrantsEnabled": false, + "serviceAccountsEnabled": false, + "publicClient": true, + "frontchannelLogout": false, + "protocol": "openid-connect", + "attributes": { + "pkce.code.challenge.method": "S256" + }, + "authenticationFlowBindingOverrides": {}, + "fullScopeAllowed": false, + "nodeReRegistrationTimeout": 0, + "protocolMappers": [ + { + "id": "52c7b01a-258c-44e1-8cb1-5bb924406899", + "name": "locale", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "locale", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "locale", + "jsonType.label": "String" + } + } + ], + "defaultClientScopes": [ + "web-origins", + "roles", + "profile", + "email" + ], + "optionalClientScopes": [ + "address", + "phone", + "offline_access", + "microprofile-jwt" + ] + } + ], + "clientScopes": [ + { + "id": "5a495ce6-15ae-42ed-8147-5d62368cf50d", + "name": "roles", + "description": "OpenID Connect scope for add user roles to the access token", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "false", + "display.on.consent.screen": "true", + "consent.screen.text": "${rolesScopeConsentText}" + }, + "protocolMappers": [ + { + "id": "42862da0-b6eb-4740-be5e-1bc05bb0814b", + "name": "realm roles", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-realm-role-mapper", + "consentRequired": false, + "config": { + "user.attribute": "foo", + "access.token.claim": "true", + "claim.name": "realm_access.roles", + "jsonType.label": "String", + "multivalued": "true" + } + }, + { + "id": "8e0dfa0f-baeb-4d1a-9a19-36458639f904", + "name": "client roles", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-client-role-mapper", + "consentRequired": false, + "config": { + "user.attribute": "foo", + "access.token.claim": "true", + "claim.name": "resource_access.${client_id}.roles", + "jsonType.label": "String", + "multivalued": "true" + } + }, + { + "id": "ac119ede-0ac4-402f-a6d5-1628f67e104a", + "name": "audience resolve", + "protocol": "openid-connect", + "protocolMapper": "oidc-audience-resolve-mapper", + "consentRequired": false, + "config": {} + } + ] + }, + { + "id": "8ea276f1-c7e2-4293-9b21-4e02085f81fe", + "name": "microprofile-jwt", + "description": "Microprofile - JWT built-in scope", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "true", + "display.on.consent.screen": "false" + }, + "protocolMappers": [ + { + "id": "7dbe0811-5d29-4755-a471-13ff8e29569b", + "name": "upn", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-property-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "username", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "upn", + "jsonType.label": "String" + } + }, + { + "id": "44e8795b-e353-45fa-a2a6-a7f248976bc4", + "name": "groups", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-realm-role-mapper", + "consentRequired": false, + "config": { + "multivalued": "true", + "user.attribute": "foo", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "groups", + "jsonType.label": "String" + } + } + ] + }, + { + "id": "01c08711-a05d-490b-bb55-6fea40683292", + "name": "email", + "description": "OpenID Connect built-in scope: email", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "true", + "display.on.consent.screen": "true", + "consent.screen.text": "${emailScopeConsentText}" + }, + "protocolMappers": [ + { + "id": "bce79d57-b738-494d-b4b0-31ed85598b49", + "name": "email verified", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-property-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "emailVerified", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "email_verified", + "jsonType.label": "boolean" + } + }, + { + "id": "f3b33b2b-4fde-4bdb-8d1d-a48eaea45145", + "name": "email", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-property-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "email", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "email", + "jsonType.label": "String" + } + } + ] + }, + { + "id": "b07a6151-d7ed-48f2-b06c-7b38f3134d0d", + "name": "web-origins", + "description": "OpenID Connect scope for add allowed web origins to the access token", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "false", + "display.on.consent.screen": "false", + "consent.screen.text": "" + }, + "protocolMappers": [ + { + "id": "c27c8f85-a0cd-4a94-9872-34cea5eeaa29", + "name": "allowed web origins", + "protocol": "openid-connect", + "protocolMapper": "oidc-allowed-origins-mapper", + "consentRequired": false, + "config": {} + } + ] + }, + { + "id": "a74166cd-17c4-4ee8-a4ad-c53594ec2833", + "name": "phone", + "description": "OpenID Connect built-in scope: phone", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "true", + "display.on.consent.screen": "true", + "consent.screen.text": "${phoneScopeConsentText}" + }, + "protocolMappers": [ + { + "id": "c652135d-d4a5-4190-a88d-074c9b52df80", + "name": "phone number", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "phoneNumber", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "phone_number", + "jsonType.label": "String" + } + }, + { + "id": "b667fdfd-43fa-47bd-a115-f48fc7dacc43", + "name": "phone number verified", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "phoneNumberVerified", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "phone_number_verified", + "jsonType.label": "boolean" + } + } + ] + }, + { + "id": "e4d7380a-80f2-493c-8b0c-90770175921b", + "name": "role_list", + "description": "SAML role list", + "protocol": "saml", + "attributes": { + "consent.screen.text": "${samlRoleListScopeConsentText}", + "display.on.consent.screen": "true" + }, + "protocolMappers": [ + { + "id": "e060aa7d-fcf4-4a0c-936b-043035aa63e8", + "name": "role list", + "protocol": "saml", + "protocolMapper": "saml-role-list-mapper", + "consentRequired": false, + "config": { + "single": "false", + "attribute.nameformat": "Basic", + "attribute.name": "Role" + } + } + ] + }, + { + "id": "c8a7ec0e-2fd0-403c-b240-4bf7e1754379", + "name": "offline_access", + "description": "OpenID Connect built-in scope: offline_access", + "protocol": "openid-connect", + "attributes": { + "consent.screen.text": "${offlineAccessScopeConsentText}", + "display.on.consent.screen": "true" + } + }, + { + "id": "3748d8e1-eeff-4b22-b87c-ef620901de20", + "name": "profile", + "description": "OpenID Connect built-in scope: profile", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "true", + "display.on.consent.screen": "true", + "consent.screen.text": "${profileScopeConsentText}" + }, + "protocolMappers": [ + { + "id": "5a6ff525-99e1-48b8-8a25-90408c943f66", + "name": "updated at", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "updatedAt", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "updated_at", + "jsonType.label": "String" + } + }, + { + "id": "b300739f-a456-493b-abc9-9c30d62643ac", + "name": "middle name", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "middleName", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "middle_name", + "jsonType.label": "String" + } + }, + { + "id": "89529f53-f334-405f-b30d-b1254a71f7c5", + "name": "given name", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-property-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "firstName", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "given_name", + "jsonType.label": "String" + } + }, + { + "id": "154008ed-fea4-4a3d-9aee-e5855624c058", + "name": "nickname", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "nickname", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "nickname", + "jsonType.label": "String" + } + }, + { + "id": "1d402228-9e34-4f94-9ed8-d0424ff2ff1a", + "name": "website", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "website", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "website", + "jsonType.label": "String" + } + }, + { + "id": "53f5be75-7630-4656-b0a7-b9b31e9cf25d", + "name": "family name", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-property-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "lastName", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "family_name", + "jsonType.label": "String" + } + }, + { + "id": "2dee0d17-7420-4551-b1b6-0e2d6be0c4c1", + "name": "gender", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "gender", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "gender", + "jsonType.label": "String" + } + }, + { + "id": "3bbb3138-1e65-4e61-8c9c-31bcf2b733c3", + "name": "birthdate", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "birthdate", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "birthdate", + "jsonType.label": "String" + } + }, + { + "id": "f8173917-4073-48f8-8a95-bded6ddb2679", + "name": "locale", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "locale", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "locale", + "jsonType.label": "String" + } + }, + { + "id": "153b18e0-2afa-4e2e-a9d8-df5f9c480fc6", + "name": "zoneinfo", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "zoneinfo", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "zoneinfo", + "jsonType.label": "String" + } + }, + { + "id": "2362bfab-49c2-4d76-ba24-138694165e16", + "name": "full name", + "protocol": "openid-connect", + "protocolMapper": "oidc-full-name-mapper", + "consentRequired": false, + "config": { + "id.token.claim": "true", + "access.token.claim": "true", + "userinfo.token.claim": "true" + } + }, + { + "id": "71b3660b-9ca6-4916-a121-72079f3c0893", + "name": "username", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-property-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "username", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "preferred_username", + "jsonType.label": "String" + } + }, + { + "id": "8c7bb104-ac46-46ec-a4c3-e4793d921ff2", + "name": "profile", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "profile", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "profile", + "jsonType.label": "String" + } + }, + { + "id": "74e722c3-6e47-4309-b8ef-9110cdab0d83", + "name": "picture", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "picture", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "picture", + "jsonType.label": "String" + } + } + ] + }, + { + "id": "95f65578-1ea6-4b1d-960f-177f9a190569", + "name": "address", + "description": "OpenID Connect built-in scope: address", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "true", + "display.on.consent.screen": "true", + "consent.screen.text": "${addressScopeConsentText}" + }, + "protocolMappers": [ + { + "id": "12bb4233-c84a-4086-831a-9572f6541cfe", + "name": "address", + "protocol": "openid-connect", + "protocolMapper": "oidc-address-mapper", + "consentRequired": false, + "config": { + "user.attribute.formatted": "formatted", + "user.attribute.country": "country", + "user.attribute.postal_code": "postal_code", + "userinfo.token.claim": "true", + "user.attribute.street": "street", + "id.token.claim": "true", + "user.attribute.region": "region", + "access.token.claim": "true", + "user.attribute.locality": "locality" + } + } + ] + } + ], + "defaultDefaultClientScopes": [ + "role_list", + "profile", + "email", + "roles", + "web-origins" + ], + "defaultOptionalClientScopes": [ + "offline_access", + "address", + "phone", + "microprofile-jwt" + ], + "browserSecurityHeaders": { + "contentSecurityPolicyReportOnly": "", + "xContentTypeOptions": "nosniff", + "xRobotsTag": "none", + "xFrameOptions": "SAMEORIGIN", + "contentSecurityPolicy": "frame-src 'self'; frame-ancestors 'self'; object-src 'none';", + "xXSSProtection": "1; mode=block", + "strictTransportSecurity": "max-age=31536000; includeSubDomains" + }, + "smtpServer": {}, + "eventsEnabled": false, + "eventsListeners": [ + "jboss-logging" + ], + "enabledEventTypes": [], + "adminEventsEnabled": false, + "adminEventsDetailsEnabled": false, + "identityProviders": [], + "identityProviderMappers": [], + "components": { + "org.keycloak.services.clientregistration.policy.ClientRegistrationPolicy": [ + { + "id": "9d47655a-0ecb-4958-9a24-5eaab1e7f345", + "name": "Allowed Client Scopes", + "providerId": "allowed-client-templates", + "subType": "authenticated", + "subComponents": {}, + "config": { + "allow-default-scopes": [ + "true" + ] + } + }, + { + "id": "9eb278a7-6694-4faa-962b-dd433009ad51", + "name": "Max Clients Limit", + "providerId": "max-clients", + "subType": "anonymous", + "subComponents": {}, + "config": { + "max-clients": [ + "200" + ] + } + }, + { + "id": "deb2a46c-34df-4ce0-b981-a969317d7040", + "name": "Trusted Hosts", + "providerId": "trusted-hosts", + "subType": "anonymous", + "subComponents": {}, + "config": { + "host-sending-registration-request-must-match": [ + "true" + ], + "client-uris-must-match": [ + "true" + ] + } + }, + { + "id": "8fc093e1-63ca-4f49-8936-88831e4bfe68", + "name": "Full Scope Disabled", + "providerId": "scope", + "subType": "anonymous", + "subComponents": {}, + "config": {} + }, + { + "id": "2d3fdb64-4ed6-4563-87d3-bdc79a7db3af", + "name": "Allowed Client Scopes", + "providerId": "allowed-client-templates", + "subType": "anonymous", + "subComponents": {}, + "config": { + "allow-default-scopes": [ + "true" + ] + } + }, + { + "id": "a92ac9f3-e948-4a03-8e6f-2ac6741521f4", + "name": "Allowed Protocol Mapper Types", + "providerId": "allowed-protocol-mappers", + "subType": "anonymous", + "subComponents": {}, + "config": { + "allowed-protocol-mapper-types": [ + "oidc-sha256-pairwise-sub-mapper", + "saml-user-property-mapper", + "saml-role-list-mapper", + "oidc-address-mapper", + "oidc-usermodel-property-mapper", + "oidc-full-name-mapper", + "oidc-usermodel-attribute-mapper", + "saml-user-attribute-mapper" + ] + } + }, + { + "id": "dfb12dd4-4b71-4cce-9ee1-504ef0754d54", + "name": "Allowed Protocol Mapper Types", + "providerId": "allowed-protocol-mappers", + "subType": "authenticated", + "subComponents": {}, + "config": { + "allowed-protocol-mapper-types": [ + "oidc-address-mapper", + "saml-role-list-mapper", + "oidc-usermodel-attribute-mapper", + "saml-user-property-mapper", + "oidc-usermodel-property-mapper", + "oidc-sha256-pairwise-sub-mapper", + "saml-user-attribute-mapper", + "oidc-full-name-mapper" + ] + } + }, + { + "id": "c099c0e1-34cf-4265-be37-561c37d383d3", + "name": "Consent Required", + "providerId": "consent-required", + "subType": "anonymous", + "subComponents": {}, + "config": {} + } + ], + "org.keycloak.userprofile.UserProfileProvider": [ + { + "id": "b1545352-3f54-4204-be5e-46f285b2b49d", + "providerId": "declarative-user-profile", + "subComponents": {}, + "config": {} + } + ], + "org.keycloak.keys.KeyProvider": [ + { + "id": "c15c367b-7160-4422-8adb-91f73d17a704", + "name": "aes-generated", + "providerId": "aes-generated", + "subComponents": {}, + "config": { + "priority": [ + "100" + ] + } + }, + { + "id": "edaccdbb-dba3-4a33-92f9-61d426319742", + "name": "rsa-generated", + "providerId": "rsa-generated", + "subComponents": {}, + "config": { + "priority": [ + "100" + ] + } + }, + { + "id": "6ce5d13d-b16b-45a2-9905-15f18651351f", + "name": "hmac-generated", + "providerId": "hmac-generated", + "subComponents": {}, + "config": { + "priority": [ + "100" + ], + "algorithm": [ + "HS256" + ] + } + }, + { + "id": "f12fd983-370a-4d0d-a89c-29161ce4b7c5", + "name": "rsa-enc-generated", + "providerId": "rsa-enc-generated", + "subComponents": {}, + "config": { + "priority": [ + "100" + ], + "algorithm": [ + "RSA-OAEP" + ] + } + } + ] + }, + "internationalizationEnabled": false, + "supportedLocales": [], + "authenticationFlows": [ + { + "id": "538b8c77-6732-4413-9221-1e139020ee52", + "alias": "Account verification options", + "description": "Method with which to verity the existing account", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "idp-email-verification", + "authenticatorFlow": false, + "requirement": "ALTERNATIVE", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "ALTERNATIVE", + "priority": 20, + "autheticatorFlow": true, + "flowAlias": "Verify Existing Account by Re-authentication", + "userSetupAllowed": false + } + ] + }, + { + "id": "9a4ce9f0-7421-4722-80b5-6459fc39beba", + "alias": "Authentication Options", + "description": "Authentication options.", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "basic-auth", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "basic-auth-otp", + "authenticatorFlow": false, + "requirement": "DISABLED", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "auth-spnego", + "authenticatorFlow": false, + "requirement": "DISABLED", + "priority": 30, + "autheticatorFlow": false, + "userSetupAllowed": false + } + ] + }, + { + "id": "255b18ea-f0c7-45d4-b7c4-ef4ae380ffcf", + "alias": "Browser - Conditional OTP", + "description": "Flow to determine if the OTP is required for the authentication", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "conditional-user-configured", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "auth-otp-form", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + } + ] + }, + { + "id": "66e1c0ec-09d6-41c3-982e-81a89eb10d0a", + "alias": "Direct Grant - Conditional OTP", + "description": "Flow to determine if the OTP is required for the authentication", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "conditional-user-configured", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "direct-grant-validate-otp", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + } + ] + }, + { + "id": "3617fdb1-82e2-4b6e-8ff8-5c50ef1925d1", + "alias": "First broker login - Conditional OTP", + "description": "Flow to determine if the OTP is required for the authentication", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "conditional-user-configured", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "auth-otp-form", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + } + ] + }, + { + "id": "6a981570-c2c4-4f03-a72d-58864b9e610f", + "alias": "Handle Existing Account", + "description": "Handle what to do if there is existing account with same email/username like authenticated identity provider", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "idp-confirm-link", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "REQUIRED", + "priority": 20, + "autheticatorFlow": true, + "flowAlias": "Account verification options", + "userSetupAllowed": false + } + ] + }, + { + "id": "5173cf4e-d5dc-4899-9b08-f7a5dd7f5f49", + "alias": "Reset - Conditional OTP", + "description": "Flow to determine if the OTP should be reset or not. Set to REQUIRED to force.", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "conditional-user-configured", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "reset-otp", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + } + ] + }, + { + "id": "3944e6b8-7c7c-47dd-828f-237c354262b2", + "alias": "User creation or linking", + "description": "Flow for the existing/non-existing user alternatives", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticatorConfig": "create unique user config", + "authenticator": "idp-create-user-if-unique", + "authenticatorFlow": false, + "requirement": "ALTERNATIVE", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "ALTERNATIVE", + "priority": 20, + "autheticatorFlow": true, + "flowAlias": "Handle Existing Account", + "userSetupAllowed": false + } + ] + }, + { + "id": "d057c641-4f1c-4cbd-9550-47afc4a89b9d", + "alias": "Verify Existing Account by Re-authentication", + "description": "Reauthentication of existing account", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "idp-username-password-form", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "CONDITIONAL", + "priority": 20, + "autheticatorFlow": true, + "flowAlias": "First broker login - Conditional OTP", + "userSetupAllowed": false + } + ] + }, + { + "id": "169c6d5c-9711-4b57-8277-2b5e65ff78a2", + "alias": "browser", + "description": "browser based authentication", + "providerId": "basic-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "auth-cookie", + "authenticatorFlow": false, + "requirement": "ALTERNATIVE", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "auth-spnego", + "authenticatorFlow": false, + "requirement": "DISABLED", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "identity-provider-redirector", + "authenticatorFlow": false, + "requirement": "ALTERNATIVE", + "priority": 25, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "ALTERNATIVE", + "priority": 30, + "autheticatorFlow": true, + "flowAlias": "forms", + "userSetupAllowed": false + } + ] + }, + { + "id": "9e043b19-f6be-43d3-8ab8-9aec447ba763", + "alias": "clients", + "description": "Base authentication for clients", + "providerId": "client-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "client-secret", + "authenticatorFlow": false, + "requirement": "ALTERNATIVE", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "client-jwt", + "authenticatorFlow": false, + "requirement": "ALTERNATIVE", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "client-secret-jwt", + "authenticatorFlow": false, + "requirement": "ALTERNATIVE", + "priority": 30, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "client-x509", + "authenticatorFlow": false, + "requirement": "ALTERNATIVE", + "priority": 40, + "autheticatorFlow": false, + "userSetupAllowed": false + } + ] + }, + { + "id": "28932326-a331-45e6-a148-c276b272c08e", + "alias": "direct grant", + "description": "OpenID Connect Resource Owner Grant", + "providerId": "basic-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "direct-grant-validate-username", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "direct-grant-validate-password", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "CONDITIONAL", + "priority": 30, + "autheticatorFlow": true, + "flowAlias": "Direct Grant - Conditional OTP", + "userSetupAllowed": false + } + ] + }, + { + "id": "240b9658-a3c7-44fa-9f38-ef09f3780eef", + "alias": "docker auth", + "description": "Used by Docker clients to authenticate against the IDP", + "providerId": "basic-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "docker-http-basic-authenticator", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + } + ] + }, + { + "id": "c145ec09-67d4-42f7-811a-d4a2f266a5d2", + "alias": "first broker login", + "description": "Actions taken after first broker login with identity provider account, which is not yet linked to any Keycloak account", + "providerId": "basic-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticatorConfig": "review profile config", + "authenticator": "idp-review-profile", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "REQUIRED", + "priority": 20, + "autheticatorFlow": true, + "flowAlias": "User creation or linking", + "userSetupAllowed": false + } + ] + }, + { + "id": "d8b5ba31-3954-4ba1-a80d-e779506155c6", + "alias": "forms", + "description": "Username, password, otp and other auth forms.", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "auth-username-password-form", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "CONDITIONAL", + "priority": 20, + "autheticatorFlow": true, + "flowAlias": "Browser - Conditional OTP", + "userSetupAllowed": false + } + ] + }, + { + "id": "5410290d-5da7-4644-b6ca-c7796457ef44", + "alias": "http challenge", + "description": "An authentication flow based on challenge-response HTTP Authentication Schemes", + "providerId": "basic-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "no-cookie-redirect", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "REQUIRED", + "priority": 20, + "autheticatorFlow": true, + "flowAlias": "Authentication Options", + "userSetupAllowed": false + } + ] + }, + { + "id": "e84eda3c-4695-455b-9568-4cf8b0d12e66", + "alias": "registration", + "description": "registration flow", + "providerId": "basic-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "registration-page-form", + "authenticatorFlow": true, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": true, + "flowAlias": "registration form", + "userSetupAllowed": false + } + ] + }, + { + "id": "11e42f93-acf5-414e-9558-0e0fff40cec2", + "alias": "registration form", + "description": "registration form", + "providerId": "form-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "registration-user-creation", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "registration-profile-action", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 40, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "registration-password-action", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 50, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "registration-recaptcha-action", + "authenticatorFlow": false, + "requirement": "DISABLED", + "priority": 60, + "autheticatorFlow": false, + "userSetupAllowed": false + } + ] + }, + { + "id": "fc88ebd6-64e2-426e-9d95-1b4a36207ca8", + "alias": "reset credentials", + "description": "Reset credentials for a user if they forgot their password or something", + "providerId": "basic-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "reset-credentials-choose-user", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "reset-credential-email", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "reset-password", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 30, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "CONDITIONAL", + "priority": 40, + "autheticatorFlow": true, + "flowAlias": "Reset - Conditional OTP", + "userSetupAllowed": false + } + ] + }, + { + "id": "611eff2b-fbe4-4a09-9ba9-0eb8256f6776", + "alias": "saml ecp", + "description": "SAML ECP Profile Authentication Flow", + "providerId": "basic-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "http-basic-authenticator", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + } + ] + } + ], + "authenticatorConfig": [ + { + "id": "72f04ac9-9468-4692-894e-f3cac25e73e2", + "alias": "create unique user config", + "config": { + "require.password.update.after.registration": "false" + } + }, + { + "id": "190a63f8-72ad-4b7f-a2b6-1937f410d97e", + "alias": "review profile config", + "config": { + "update.profile.on.first.login": "missing" + } + } + ], + "requiredActions": [ + { + "alias": "CONFIGURE_TOTP", + "name": "Configure OTP", + "providerId": "CONFIGURE_TOTP", + "enabled": true, + "defaultAction": false, + "priority": 10, + "config": {} + }, + { + "alias": "terms_and_conditions", + "name": "Terms and Conditions", + "providerId": "terms_and_conditions", + "enabled": false, + "defaultAction": false, + "priority": 20, + "config": {} + }, + { + "alias": "UPDATE_PASSWORD", + "name": "Update Password", + "providerId": "UPDATE_PASSWORD", + "enabled": true, + "defaultAction": false, + "priority": 30, + "config": {} + }, + { + "alias": "UPDATE_PROFILE", + "name": "Update Profile", + "providerId": "UPDATE_PROFILE", + "enabled": true, + "defaultAction": false, + "priority": 40, + "config": {} + }, + { + "alias": "VERIFY_EMAIL", + "name": "Verify Email", + "providerId": "VERIFY_EMAIL", + "enabled": true, + "defaultAction": false, + "priority": 50, + "config": {} + }, + { + "alias": "delete_account", + "name": "Delete Account", + "providerId": "delete_account", + "enabled": false, + "defaultAction": false, + "priority": 60, + "config": {} + }, + { + "alias": "update_user_locale", + "name": "Update User Locale", + "providerId": "update_user_locale", + "enabled": true, + "defaultAction": false, + "priority": 1000, + "config": {} + } + ], + "browserFlow": "browser", + "registrationFlow": "registration", + "directGrantFlow": "direct grant", + "resetCredentialsFlow": "reset credentials", + "clientAuthenticationFlow": "clients", + "dockerAuthenticationFlow": "docker auth", + "attributes": { + "cibaBackchannelTokenDeliveryMode": "poll", + "cibaExpiresIn": "120", + "cibaAuthRequestedUserHint": "login_hint", + "oauth2DeviceCodeLifespan": "600", + "oauth2DevicePollingInterval": "5", + "clientOfflineSessionMaxLifespan": "0", + "clientSessionIdleTimeout": "0", + "userProfileEnabled": "false", + "parRequestUriLifespan": "60", + "clientSessionMaxLifespan": "0", + "clientOfflineSessionIdleTimeout": "0", + "cibaInterval": "5" + }, + "keycloakVersion": "17.0.1", + "userManagedAccessAllowed": false, + "clientProfiles": { + "profiles": [] + }, + "clientPolicies": { + "policies": [] + } +} \ No newline at end of file diff --git a/ph-ee-env-template/Keycloak/readme.md b/ph-ee-env-template/Keycloak/readme.md new file mode 100644 index 000000000..8263cd2ac --- /dev/null +++ b/ph-ee-env-template/Keycloak/readme.md @@ -0,0 +1,90 @@ +# Initial Setup/ User creation +* Step 1: Open the keycloak administration console in browser and click `Administration Console` as shown in below snippet.
+Screenshot 2023-11-23 at 2 26 39 PM

+ +* Step 2: Enter the admin username/email and password. Then click on `Sign In` button, as shown in below snippet.
+Screenshot 2023-11-23 at 2 26 50 PM

+ +* Step 3: On successful login below screen will open, with list of all the realms. Click on the realm which you wnat to use.
+Screenshot 2023-11-23 at 2 32 16 PM

+ +* Step 4: Click on `Add user` by navigating to the `Users` section from left menu. As shown in below snippet.
+Screenshot 2023-12-12 at 8 56 00 PM

+ +* Step 5: Enter the username and relevant information as per the need adn click on the `Save` button, as shown in the below snippet. +* Create a user with username as 'admin' and password as 'admin'.
+Screenshot 2023-12-12 at 9 00 51 PM

+ +* Step 6: Once user is created navigate to `Credential/Role Mapping` tabs for updating relevant information, as shown in below screenshot. +* Add user-manage role from realm-management to the 'admin' user.
+Screenshot 2023-12-12 at 9 04 38 PM

+ +# How to export realm configuration +* Step 1: Open the keycloak administration console in browser and click `Administration Console` as shown in below snippet.
+Screenshot 2023-11-23 at 2 26 39 PM

+ +* Step 2: Enter the admin username/email and password. Then click on `Sign In` button, as shown in below snippet.
+Screenshot 2023-11-23 at 2 26 50 PM

+ +* Step 3: On successful login below screen will open, with list of all the realms. Click on the realm you want to export.
+Screenshot 2023-11-23 at 2 32 16 PM

+ +* Step 4: In the left menu panel, select `Export` under the manage section. Refer below snippet.
+Screenshot 2023-11-23 at 2 33 45 PM

+ +* Step 5: In the `Partial Export` section enable both the toggle i.e. `Export groups and roles` and `Export clients`, then click on the `Export` button, as shown in the below snippet.
+Screenshot 2023-11-23 at 2 38 08 PM

+ +* Step 6: Once clicked on the `Export` in previous step a popup window will open as shown in below snippet, read the instruction and click on the `Export` button.
+Screenshot 2023-11-23 at 2 41 50 PM

+ + +# How to import realm configuration + +* Step 1: Open the keycloak administration console in browser and click `Administration Console` as shown in below snippet.
+Screenshot 2023-11-23 at 2 26 39 PM

+ +* Step 2: Enter the admin username/email and password. Then click on `Sign In` button, as shown in below snippet.
+Screenshot 2023-11-23 at 2 26 50 PM

+ +* Step 3: On successful login below screen will open, with list of all the realms. Click on the `master` realm.
+Screenshot 2023-11-23 at 2 32 16 PM

+ +* Step 4: In the left menu panel, select `Import` under the manage section. Refer below snippet.
+Screenshot 2023-11-23 at 2 53 49 PM

+ +* Step 5: In the `Partial Export` section click on the `Select file` button, as shown in below snipper. A system file selector window will open, select the configuration by navigating into the system files.
+Screenshot 2023-11-23 at 2 55 55 PM

+ +* Step 6: Once valid configuration file in submited, a below screen will open. + * Use `View details` button to see the raw configuration file. + * Use the toggle buttons to import selectively or enable all the toggle button to import everything. + * In the `If a resource exists` dropdown, click on the dropdown and select `Skip`, this will make sure the resources which are already present are skipped while importing the realm. or you can choose from `Fail`, `Skip` and `Overwrite` based on your requirements
+Screenshot 2023-11-23 at 3 00 25 PM

+ +# How to see/generate client secret +* Step 1: Open the keycloak administration console in browser and click `Administration Console` as shown in below snippet.
+Screenshot 2023-11-23 at 2 26 39 PM

+ +* Step 2: Enter the admin username/email and password. Then click on `Sign In` button, as shown in below snippet.
+Screenshot 2023-11-23 at 2 26 50 PM

+ +* Step 3: On successful login below screen will open, with list of all the realms. Click on the realm which you wnat to use.
+Screenshot 2023-11-23 at 2 32 16 PM

+ +* Step 4: Navigate to clients section by clicking on the `Clients`, in the the left menu panel under the configure section. Then click on the client you want to see/generate the secret for. Refer the below snippet.
+Screenshot 2023-11-23 at 3 19 22 PM

+ +* Step 5: A new screen will open with the multiple information about the client you selected. In the top bar click on the `Credentials` tab, as shown in the below snippet.
+Screenshot 2023-11-23 at 3 23 06 PM

+ +* Step 6: In the credentials tab you can see the mulitple information regarding the client secret and its type. + * Use the `Client Authenticator` drop down to select the type of secret you want to generate(for exsiting secret the drop down will be autopopulated with the secret type). + * Use the `Regenerate Secret` button to generate the secret. + * A text box present just beside the `Regenerate Secret` will contain the latest generated secret.
+ Screenshot 2023-11-23 at 3 26 46 PM +

+ +Add a role with name admin +select realm-management in the Roles select box and add user-management role to this role. +create an admin user with username as 'admin' and password as 'admin' in the realm paymenthub. diff --git a/ph-ee-env-template/Kibana Visualisations/Datatables.ndjson b/ph-ee-env-template/Kibana Visualisations/Datatables.ndjson new file mode 100644 index 000000000..e7037c2f8 --- /dev/null +++ b/ph-ee-env-template/Kibana Visualisations/Datatables.ndjson @@ -0,0 +1,7 @@ +{"attributes":{"fieldAttrs":"{\"value.bpmnProcessId\":{\"count\":6},\"value.processDefinitionKey\":{\"count\":4},\"value.processDefinitionVersion\":{\"count\":3},\"value.processInstanceKey\":{\"count\":10},\"value.elementId\":{\"count\":6},\"value.retries\":{\"count\":2},\"value.type\":{\"count\":4},\"intent\":{\"count\":3},\"timestamp\":{\"count\":1},\"value.flowScopeKey\":{\"count\":2},\"value.version\":{\"count\":1},\"value.errorCode\":{\"count\":4},\"value.errorMessage\":{\"count\":4},\"value.errorType\":{\"count\":4},\"value.value\":{\"count\":2},\"value.name\":{\"count\":1},\"_index\":{\"count\":1},\"_type\":{\"count\":2},\"key\":{\"count\":1},\"value.worker\":{\"count\":2},\"value.bpmnElementType\":{\"count\":1}}","fields":"[]","runtimeFieldMap":"{}","timeFieldName":"timestamp","title":"zeebe-*"},"coreMigrationVersion":"7.13.2","id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","migrationVersion":{"index-pattern":"7.11.0"},"references":[],"type":"index-pattern","updated_at":"2022-02-14T08:39:45.748Z","version":"WzkxNDksMTZd"} +{"attributes":{"columns":["value.processInstanceKey","value.errorMessage","value.elementId","value.bpmnProcessId","value.errorType"],"description":"","hits":0,"kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[{\"meta\":{\"alias\":null,\"negate\":false,\"disabled\":false,\"type\":\"exists\",\"key\":\"value.errorType\",\"value\":\"exists\",\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index\"},\"exists\":{\"field\":\"value.errorType\"},\"$state\":{\"store\":\"appState\"}}],\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\"}"},"sort":[["timestamp","desc"]],"title":"Incidents [All]","version":1},"coreMigrationVersion":"7.13.2","id":"9814c8c0-8a92-11ec-92d2-2d974edf9929","migrationVersion":{"search":"7.9.3"},"references":[{"id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","name":"kibanaSavedObjectMeta.searchSourceJSON.index","type":"index-pattern"},{"id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","name":"kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index","type":"index-pattern"}],"type":"search","updated_at":"2022-02-10T16:57:56.300Z","version":"WzY0NDEsMTZd"} +{"attributes":{"columns":["value.processInstanceKey","value.value"],"description":"","hits":0,"kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[{\"meta\":{\"type\":\"phrases\",\"key\":\"value.name\",\"value\":\"deliveryErrorMessage, errorInformation\",\"params\":[\"deliveryErrorMessage\",\"errorInformation\"],\"alias\":null,\"negate\":false,\"disabled\":false,\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index\"},\"query\":{\"bool\":{\"should\":[{\"match_phrase\":{\"value.name\":\"deliveryErrorMessage\"}},{\"match_phrase\":{\"value.name\":\"errorInformation\"}}],\"minimum_should_match\":1}},\"$state\":{\"store\":\"appState\"}}],\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\"}"},"sort":[["timestamp","desc"]],"title":"Transaction Errors","version":1},"coreMigrationVersion":"7.13.2","id":"b3a9e540-8a77-11ec-92d2-2d974edf9929","migrationVersion":{"search":"7.9.3"},"references":[{"id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","name":"kibanaSavedObjectMeta.searchSourceJSON.index","type":"index-pattern"},{"id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","name":"kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index","type":"index-pattern"}],"type":"search","updated_at":"2022-02-10T16:48:44.554Z","version":"WzYzODMsMTZd"} +{"attributes":{"columns":["value.processInstanceKey"],"description":"","hits":0,"kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[{\"meta\":{\"alias\":null,\"negate\":false,\"disabled\":false,\"type\":\"phrase\",\"key\":\"intent\",\"params\":{\"query\":\"ELEMENT_TERMINATED\"},\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index\"},\"query\":{\"match_phrase\":{\"intent\":\"ELEMENT_TERMINATED\"}},\"$state\":{\"store\":\"appState\"}},{\"meta\":{\"alias\":null,\"negate\":false,\"disabled\":false,\"type\":\"phrase\",\"key\":\"value.elementId\",\"params\":{\"query\":\"mpesa-flow-v3-oaf\"},\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.filter[1].meta.index\"},\"query\":{\"match_phrase\":{\"value.elementId\":\"mpesa-flow-v3-oaf\"}},\"$state\":{\"store\":\"appState\"}},{\"meta\":{\"alias\":null,\"negate\":false,\"disabled\":false,\"type\":\"phrase\",\"key\":\"value.version\",\"params\":{\"query\":3},\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.filter[2].meta.index\"},\"query\":{\"match_phrase\":{\"value.version\":3}},\"$state\":{\"store\":\"appState\"}}],\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\"}"},"sort":[["timestamp","desc"]],"title":"Incomplete/Cancelled Txns","version":1},"coreMigrationVersion":"7.13.2","id":"b25fe0a0-8a99-11ec-92d2-2d974edf9929","migrationVersion":{"search":"7.9.3"},"references":[{"id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","name":"kibanaSavedObjectMeta.searchSourceJSON.index","type":"index-pattern"},{"id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","name":"kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index","type":"index-pattern"},{"id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","name":"kibanaSavedObjectMeta.searchSourceJSON.filter[1].meta.index","type":"index-pattern"},{"id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","name":"kibanaSavedObjectMeta.searchSourceJSON.filter[2].meta.index","type":"index-pattern"}],"type":"search","updated_at":"2022-02-11T14:58:44.727Z","version":"Wzg3OTEsMTZd"} +{"attributes":{"description":null,"state":{"datasourceStates":{"indexpattern":{"layers":{"23f63150-df2e-4674-985c-2e1a4671e30b":{"columnOrder":["3d0da674-c79b-4d5d-9c00-2a6c53fcdd4f","35b8c0d3-3098-4e2b-8227-fa65acfef92f"],"columns":{"35b8c0d3-3098-4e2b-8227-fa65acfef92f":{"customLabel":false,"dataType":"string","filter":{"language":"kuery","query":"NOT value.bpmnElementType : \"PROCESS\" and NOT value.bpmnElementType : \"EXCLUSIVE_GATEWAY\" and NOT value.bpmnElementType : \"SEQUENCE_FLOW\" and NOT value.bpmnElementType : \"END_EVENT\" and value.elementId : * and NOT value.bpmnElementType : \"START_EVENT\" and NOT value.bpmnElementType : \"BOUNDARY_EVENT\" "},"isBucketed":false,"label":"Last value of value.elementId","operationType":"last_value","params":{"sortField":"timestamp"},"scale":"ordinal","sourceField":"value.elementId"},"3d0da674-c79b-4d5d-9c00-2a6c53fcdd4f":{"dataType":"number","isBucketed":true,"label":"Top values of value.processInstanceKey","operationType":"terms","params":{"missingBucket":false,"orderBy":{"fallback":true,"type":"alphabetical"},"orderDirection":"desc","otherBucket":true,"size":50},"scale":"ordinal","sourceField":"value.processInstanceKey"}},"incompleteColumns":{}}}}},"filters":[],"query":{"language":"kuery","query":""},"visualization":{"columns":[{"columnId":"3d0da674-c79b-4d5d-9c00-2a6c53fcdd4f","isTransposed":false},{"alignment":"center","columnId":"35b8c0d3-3098-4e2b-8227-fa65acfef92f","isTransposed":false}],"layerId":"23f63150-df2e-4674-985c-2e1a4671e30b"}},"title":"Cancelled Txns Draft","visualizationType":"lnsDatatable"},"coreMigrationVersion":"7.13.2","id":"2ba21b00-8b3e-11ec-92d2-2d974edf9929","migrationVersion":{"lens":"7.13.1"},"references":[{"id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","name":"indexpattern-datasource-current-indexpattern","type":"index-pattern"},{"id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","name":"indexpattern-datasource-layer-23f63150-df2e-4674-985c-2e1a4671e30b","type":"index-pattern"}],"type":"lens","updated_at":"2022-02-14T08:32:51.926Z","version":"WzkwMzgsMTZd"} +{"attributes":{"description":"","hits":0,"kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[]}"},"optionsJSON":"{\"hidePanelTitles\":false,\"useMargins\":true}","panelsJSON":"[{\"version\":\"7.13.2\",\"type\":\"lens\",\"gridData\":{\"x\":0,\"y\":0,\"w\":48,\"h\":16,\"i\":\"f9aa0bbd-c7d1-4e95-b76b-7691c7daeb51\"},\"panelIndex\":\"f9aa0bbd-c7d1-4e95-b76b-7691c7daeb51\",\"embeddableConfig\":{\"attributes\":{\"title\":\"Txn Variables\",\"type\":\"lens\",\"visualizationType\":\"lnsDatatable\",\"state\":{\"datasourceStates\":{\"indexpattern\":{\"layers\":{\"f1b1bd9f-1516-428c-88cb-a8fbbcbf8814\":{\"columns\":{\"acbf1b5a-c412-4c4d-b4f1-748c264e0e27\":{\"label\":\"Top values of value.name\",\"dataType\":\"string\",\"operationType\":\"terms\",\"scale\":\"ordinal\",\"sourceField\":\"value.name\",\"isBucketed\":true,\"params\":{\"size\":20,\"orderBy\":{\"type\":\"alphabetical\",\"fallback\":false},\"orderDirection\":\"asc\",\"otherBucket\":false,\"missingBucket\":true},\"customLabel\":false},\"f68b8c7c-7d6d-4c86-85c2-147fcd19af92\":{\"label\":\"Instance ID\",\"dataType\":\"number\",\"operationType\":\"terms\",\"scale\":\"ordinal\",\"sourceField\":\"value.processInstanceKey\",\"isBucketed\":true,\"params\":{\"size\":10,\"orderBy\":{\"type\":\"alphabetical\",\"fallback\":true},\"orderDirection\":\"desc\",\"otherBucket\":true,\"missingBucket\":false},\"customLabel\":true},\"541db045-e06b-448d-beab-fb4337bda7e7\":{\"label\":\" \",\"dataType\":\"string\",\"operationType\":\"last_value\",\"isBucketed\":false,\"scale\":\"ordinal\",\"sourceField\":\"value.value\",\"params\":{\"sortField\":\"timestamp\"},\"customLabel\":true}},\"columnOrder\":[\"acbf1b5a-c412-4c4d-b4f1-748c264e0e27\",\"f68b8c7c-7d6d-4c86-85c2-147fcd19af92\",\"541db045-e06b-448d-beab-fb4337bda7e7\"],\"incompleteColumns\":{}}}}},\"visualization\":{\"columns\":[{\"columnId\":\"acbf1b5a-c412-4c4d-b4f1-748c264e0e27\",\"isTransposed\":true},{\"columnId\":\"f68b8c7c-7d6d-4c86-85c2-147fcd19af92\",\"isTransposed\":false,\"width\":174},{\"columnId\":\"541db045-e06b-448d-beab-fb4337bda7e7\",\"isTransposed\":false,\"width\":195}],\"layerId\":\"f1b1bd9f-1516-428c-88cb-a8fbbcbf8814\"},\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filters\":[{\"meta\":{\"negate\":true,\"type\":\"phrase\",\"key\":\"value.name\",\"params\":{\"query\":\"buyGoodsRequestBody\"},\"disabled\":false,\"alias\":null,\"indexRefName\":\"filter-index-pattern-0\"},\"query\":{\"match_phrase\":{\"value.name\":\"buyGoodsRequestBody\"}},\"$state\":{\"store\":\"appState\"}},{\"meta\":{\"negate\":true,\"type\":\"phrase\",\"key\":\"value.name\",\"params\":{\"query\":\"channelRequest\"},\"disabled\":false,\"alias\":null,\"indexRefName\":\"filter-index-pattern-1\"},\"query\":{\"match_phrase\":{\"value.name\":\"channelRequest\"}},\"$state\":{\"store\":\"appState\"}},{\"meta\":{\"negate\":true,\"type\":\"phrase\",\"key\":\"value.name\",\"params\":{\"query\":\"deliveryMessage\"},\"disabled\":false,\"alias\":null,\"indexRefName\":\"filter-index-pattern-2\"},\"query\":{\"match_phrase\":{\"value.name\":\"deliveryMessage\"}},\"$state\":{\"store\":\"appState\"}},{\"meta\":{\"negate\":true,\"type\":\"phrase\",\"key\":\"value.name\",\"params\":{\"query\":\"deliveryErrorMessage\"},\"disabled\":false,\"alias\":null,\"indexRefName\":\"filter-index-pattern-3\"},\"query\":{\"match_phrase\":{\"value.name\":\"deliveryErrorMessage\"}},\"$state\":{\"store\":\"appState\"}},{\"meta\":{\"negate\":true,\"type\":\"phrase\",\"key\":\"value.name\",\"params\":{\"query\":\"callbackRetry\"},\"disabled\":false,\"alias\":null,\"indexRefName\":\"filter-index-pattern-4\"},\"query\":{\"match_phrase\":{\"value.name\":\"callbackRetry\"}},\"$state\":{\"store\":\"appState\"}},{\"meta\":{\"negate\":true,\"type\":\"phrase\",\"key\":\"value.name\",\"params\":{\"query\":\"initiatorType\"},\"disabled\":false,\"alias\":null,\"indexRefName\":\"filter-index-pattern-5\"},\"query\":{\"match_phrase\":{\"value.name\":\"initiatorType\"}},\"$state\":{\"store\":\"appState\"}},{\"meta\":{\"negate\":true,\"type\":\"phrase\",\"key\":\"value.name\",\"params\":{\"query\":\"initiator\"},\"disabled\":false,\"alias\":null,\"indexRefName\":\"filter-index-pattern-6\"},\"query\":{\"match_phrase\":{\"value.name\":\"initiator\"}},\"$state\":{\"store\":\"appState\"}},{\"meta\":{\"negate\":true,\"type\":\"phrase\",\"key\":\"value.name\",\"params\":{\"query\":\"errorInformation\"},\"disabled\":false,\"alias\":null,\"indexRefName\":\"filter-index-pattern-7\"},\"query\":{\"match_phrase\":{\"value.name\":\"errorInformation\"}},\"$state\":{\"store\":\"appState\"}},{\"meta\":{\"negate\":true,\"type\":\"phrase\",\"key\":\"value.name\",\"params\":{\"query\":\"internalId\"},\"disabled\":false,\"alias\":null,\"indexRefName\":\"filter-index-pattern-8\"},\"query\":{\"match_phrase\":{\"value.name\":\"internalId\"}},\"$state\":{\"store\":\"appState\"}},{\"meta\":{\"negate\":true,\"type\":\"phrase\",\"key\":\"value.name\",\"params\":{\"query\":\"mpesaChannelRequest\"},\"disabled\":false,\"alias\":null,\"indexRefName\":\"filter-index-pattern-9\"},\"query\":{\"match_phrase\":{\"value.name\":\"mpesaChannelRequest\"}},\"$state\":{\"store\":\"appState\"}},{\"meta\":{\"negate\":true,\"type\":\"phrase\",\"key\":\"value.name\",\"params\":{\"query\":\"scenario\"},\"disabled\":false,\"alias\":null,\"indexRefName\":\"filter-index-pattern-10\"},\"query\":{\"match_phrase\":{\"value.name\":\"scenario\"}},\"$state\":{\"store\":\"appState\"}},{\"meta\":{\"negate\":true,\"type\":\"phrase\",\"key\":\"value.name\",\"params\":{\"query\":\"tenantId\"},\"disabled\":false,\"alias\":null,\"indexRefName\":\"filter-index-pattern-11\"},\"query\":{\"match_phrase\":{\"value.name\":\"tenantId\"}},\"$state\":{\"store\":\"appState\"}},{\"meta\":{\"negate\":true,\"type\":\"phrase\",\"key\":\"value.name\",\"params\":{\"query\":\"transferCreateFailed\"},\"disabled\":false,\"alias\":null,\"indexRefName\":\"filter-index-pattern-12\"},\"query\":{\"match_phrase\":{\"value.name\":\"transferCreateFailed\"}},\"$state\":{\"store\":\"appState\"}},{\"meta\":{\"negate\":true,\"type\":\"phrase\",\"key\":\"value.name\",\"params\":{\"query\":\"transferResponse-CREATE\"},\"disabled\":false,\"alias\":null,\"indexRefName\":\"filter-index-pattern-13\"},\"query\":{\"match_phrase\":{\"value.name\":\"transferResponse-CREATE\"}},\"$state\":{\"store\":\"appState\"}}]},\"references\":[{\"type\":\"index-pattern\",\"id\":\"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b\",\"name\":\"indexpattern-datasource-current-indexpattern\"},{\"type\":\"index-pattern\",\"id\":\"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b\",\"name\":\"indexpattern-datasource-layer-f1b1bd9f-1516-428c-88cb-a8fbbcbf8814\"},{\"name\":\"filter-index-pattern-0\",\"type\":\"index-pattern\",\"id\":\"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b\"},{\"name\":\"filter-index-pattern-1\",\"type\":\"index-pattern\",\"id\":\"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b\"},{\"name\":\"filter-index-pattern-2\",\"type\":\"index-pattern\",\"id\":\"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b\"},{\"name\":\"filter-index-pattern-3\",\"type\":\"index-pattern\",\"id\":\"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b\"},{\"name\":\"filter-index-pattern-4\",\"type\":\"index-pattern\",\"id\":\"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b\"},{\"name\":\"filter-index-pattern-5\",\"type\":\"index-pattern\",\"id\":\"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b\"},{\"name\":\"filter-index-pattern-6\",\"type\":\"index-pattern\",\"id\":\"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b\"},{\"name\":\"filter-index-pattern-7\",\"type\":\"index-pattern\",\"id\":\"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b\"},{\"name\":\"filter-index-pattern-8\",\"type\":\"index-pattern\",\"id\":\"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b\"},{\"name\":\"filter-index-pattern-9\",\"type\":\"index-pattern\",\"id\":\"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b\"},{\"name\":\"filter-index-pattern-10\",\"type\":\"index-pattern\",\"id\":\"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b\"},{\"name\":\"filter-index-pattern-11\",\"type\":\"index-pattern\",\"id\":\"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b\"},{\"name\":\"filter-index-pattern-12\",\"type\":\"index-pattern\",\"id\":\"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b\"},{\"name\":\"filter-index-pattern-13\",\"type\":\"index-pattern\",\"id\":\"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b\"}]},\"enhancements\":{}}},{\"version\":\"7.13.2\",\"type\":\"search\",\"gridData\":{\"x\":24,\"y\":16,\"w\":24,\"h\":15,\"i\":\"33ff30ee-1ec0-40f1-9ac2-025054125fff\"},\"panelIndex\":\"33ff30ee-1ec0-40f1-9ac2-025054125fff\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_33ff30ee-1ec0-40f1-9ac2-025054125fff\"},{\"version\":\"7.13.2\",\"type\":\"search\",\"gridData\":{\"x\":0,\"y\":16,\"w\":24,\"h\":15,\"i\":\"2d515280-ed7d-492a-a4cf-0d940df659bb\"},\"panelIndex\":\"2d515280-ed7d-492a-a4cf-0d940df659bb\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_2d515280-ed7d-492a-a4cf-0d940df659bb\"},{\"version\":\"7.13.2\",\"type\":\"search\",\"gridData\":{\"x\":0,\"y\":31,\"w\":24,\"h\":15,\"i\":\"7d4e3a8c-41d6-4fcd-b0e7-704a38648cc6\"},\"panelIndex\":\"7d4e3a8c-41d6-4fcd-b0e7-704a38648cc6\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_7d4e3a8c-41d6-4fcd-b0e7-704a38648cc6\"},{\"version\":\"7.13.2\",\"type\":\"lens\",\"gridData\":{\"x\":24,\"y\":31,\"w\":24,\"h\":15,\"i\":\"fade4208-a8a0-4b4a-a9fb-af8adbcdb30f\"},\"panelIndex\":\"fade4208-a8a0-4b4a-a9fb-af8adbcdb30f\",\"embeddableConfig\":{\"hidePanelTitles\":false,\"enhancements\":{}},\"title\":\"Cancelled Txn Last State\",\"panelRefName\":\"panel_fade4208-a8a0-4b4a-a9fb-af8adbcdb30f\"}]","timeRestore":false,"title":"Datatables","version":1},"coreMigrationVersion":"7.13.2","id":"ae94ac00-8a92-11ec-92d2-2d974edf9929","migrationVersion":{"dashboard":"7.13.1"},"references":[{"id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","name":"f9aa0bbd-c7d1-4e95-b76b-7691c7daeb51:indexpattern-datasource-current-indexpattern","type":"index-pattern"},{"id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","name":"f9aa0bbd-c7d1-4e95-b76b-7691c7daeb51:indexpattern-datasource-layer-f1b1bd9f-1516-428c-88cb-a8fbbcbf8814","type":"index-pattern"},{"id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","name":"f9aa0bbd-c7d1-4e95-b76b-7691c7daeb51:filter-index-pattern-0","type":"index-pattern"},{"id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","name":"f9aa0bbd-c7d1-4e95-b76b-7691c7daeb51:filter-index-pattern-1","type":"index-pattern"},{"id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","name":"f9aa0bbd-c7d1-4e95-b76b-7691c7daeb51:filter-index-pattern-2","type":"index-pattern"},{"id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","name":"f9aa0bbd-c7d1-4e95-b76b-7691c7daeb51:filter-index-pattern-3","type":"index-pattern"},{"id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","name":"f9aa0bbd-c7d1-4e95-b76b-7691c7daeb51:filter-index-pattern-4","type":"index-pattern"},{"id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","name":"f9aa0bbd-c7d1-4e95-b76b-7691c7daeb51:filter-index-pattern-5","type":"index-pattern"},{"id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","name":"f9aa0bbd-c7d1-4e95-b76b-7691c7daeb51:filter-index-pattern-6","type":"index-pattern"},{"id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","name":"f9aa0bbd-c7d1-4e95-b76b-7691c7daeb51:filter-index-pattern-7","type":"index-pattern"},{"id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","name":"f9aa0bbd-c7d1-4e95-b76b-7691c7daeb51:filter-index-pattern-8","type":"index-pattern"},{"id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","name":"f9aa0bbd-c7d1-4e95-b76b-7691c7daeb51:filter-index-pattern-9","type":"index-pattern"},{"id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","name":"f9aa0bbd-c7d1-4e95-b76b-7691c7daeb51:filter-index-pattern-10","type":"index-pattern"},{"id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","name":"f9aa0bbd-c7d1-4e95-b76b-7691c7daeb51:filter-index-pattern-11","type":"index-pattern"},{"id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","name":"f9aa0bbd-c7d1-4e95-b76b-7691c7daeb51:filter-index-pattern-12","type":"index-pattern"},{"id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","name":"f9aa0bbd-c7d1-4e95-b76b-7691c7daeb51:filter-index-pattern-13","type":"index-pattern"},{"id":"9814c8c0-8a92-11ec-92d2-2d974edf9929","name":"33ff30ee-1ec0-40f1-9ac2-025054125fff:panel_33ff30ee-1ec0-40f1-9ac2-025054125fff","type":"search"},{"id":"b3a9e540-8a77-11ec-92d2-2d974edf9929","name":"2d515280-ed7d-492a-a4cf-0d940df659bb:panel_2d515280-ed7d-492a-a4cf-0d940df659bb","type":"search"},{"id":"b25fe0a0-8a99-11ec-92d2-2d974edf9929","name":"7d4e3a8c-41d6-4fcd-b0e7-704a38648cc6:panel_7d4e3a8c-41d6-4fcd-b0e7-704a38648cc6","type":"search"},{"id":"2ba21b00-8b3e-11ec-92d2-2d974edf9929","name":"fade4208-a8a0-4b4a-a9fb-af8adbcdb30f:panel_fade4208-a8a0-4b4a-a9fb-af8adbcdb30f","type":"lens"}],"type":"dashboard","updated_at":"2022-02-14T07:25:50.124Z","version":"Wzg5NTAsMTZd"} +{"exportedCount":6,"missingRefCount":0,"missingReferences":[]} \ No newline at end of file diff --git a/ph-ee-env-template/Kibana Visualisations/PHEE.ndjson b/ph-ee-env-template/Kibana Visualisations/PHEE.ndjson new file mode 100644 index 000000000..bd3263e0c --- /dev/null +++ b/ph-ee-env-template/Kibana Visualisations/PHEE.ndjson @@ -0,0 +1,11 @@ +{"attributes":{"fieldAttrs":"{\"value.bpmnProcessId\":{\"count\":6},\"value.processDefinitionKey\":{\"count\":4},\"value.processDefinitionVersion\":{\"count\":3},\"value.processInstanceKey\":{\"count\":10},\"value.elementId\":{\"count\":6},\"value.retries\":{\"count\":2},\"value.type\":{\"count\":4},\"intent\":{\"count\":3},\"timestamp\":{\"count\":1},\"value.flowScopeKey\":{\"count\":2},\"value.version\":{\"count\":1},\"value.errorCode\":{\"count\":4},\"value.errorMessage\":{\"count\":4},\"value.errorType\":{\"count\":4},\"value.value\":{\"count\":2},\"value.name\":{\"count\":1},\"_index\":{\"count\":1},\"_type\":{\"count\":2},\"key\":{\"count\":1},\"value.worker\":{\"count\":2},\"value.bpmnElementType\":{\"count\":1}}","fields":"[]","runtimeFieldMap":"{}","timeFieldName":"timestamp","title":"zeebe-*"},"coreMigrationVersion":"7.13.2","id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","migrationVersion":{"index-pattern":"7.11.0"},"references":[],"type":"index-pattern","updated_at":"2022-02-14T08:39:45.748Z","version":"WzkxNDksMTZd"} +{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[],\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\"}"},"title":"ProcessInstanceCount","uiStateJSON":"{}","version":1,"visState":"{\"title\":\"ProcessInstanceCount\",\"type\":\"table\",\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"cardinality\",\"params\":{\"field\":\"value.processInstanceKey\",\"customLabel\":\"processInstanceCount\"},\"schema\":\"metric\"},{\"id\":\"2\",\"enabled\":true,\"type\":\"terms\",\"params\":{\"field\":\"value.bpmnProcessId\",\"orderBy\":\"1\",\"order\":\"desc\",\"size\":10,\"otherBucket\":false,\"otherBucketLabel\":\"Other\",\"missingBucket\":false,\"missingBucketLabel\":\"Missing\",\"customLabel\":\"processDefinition\"},\"schema\":\"bucket\"}],\"params\":{\"perPage\":10,\"showPartialRows\":false,\"showMetricsAtAllLevels\":false,\"showTotal\":false,\"showToolbar\":false,\"totalFunc\":\"sum\",\"percentageCol\":\"\"}}"},"coreMigrationVersion":"7.13.2","id":"f21cb760-26bf-11ec-95b3-cb627b5ccd4b","migrationVersion":{"visualization":"7.13.1"},"references":[{"id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","name":"kibanaSavedObjectMeta.searchSourceJSON.index","type":"index-pattern"}],"type":"visualization","updated_at":"2022-01-18T11:55:14.105Z","version":"WzIzODksMTZd"} +{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[],\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\"}"},"title":"ProcessInstanceKeys","uiStateJSON":"{}","version":1,"visState":"{\"title\":\"ProcessInstanceKeys\",\"type\":\"table\",\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"count\",\"params\":{},\"schema\":\"metric\"},{\"id\":\"2\",\"enabled\":true,\"type\":\"terms\",\"params\":{\"field\":\"value.bpmnProcessId\",\"orderBy\":\"1\",\"order\":\"desc\",\"size\":1005,\"otherBucket\":false,\"otherBucketLabel\":\"Other\",\"missingBucket\":false,\"missingBucketLabel\":\"Missing\",\"customLabel\":\"ProcessDef\"},\"schema\":\"bucket\"},{\"id\":\"3\",\"enabled\":true,\"type\":\"terms\",\"params\":{\"field\":\"value.processInstanceKey\",\"orderBy\":\"1\",\"order\":\"desc\",\"size\":5,\"otherBucket\":true,\"otherBucketLabel\":\"Other\",\"missingBucket\":false,\"missingBucketLabel\":\"Missing\",\"customLabel\":\"ProcessInstanceKey\"},\"schema\":\"bucket\"}],\"params\":{\"perPage\":10,\"showPartialRows\":false,\"showMetricsAtAllLevels\":false,\"showTotal\":false,\"showToolbar\":false,\"totalFunc\":\"sum\",\"percentageCol\":\"\"}}"},"coreMigrationVersion":"7.13.2","id":"df1144f0-26c0-11ec-95b3-cb627b5ccd4b","migrationVersion":{"visualization":"7.13.1"},"references":[{"id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","name":"kibanaSavedObjectMeta.searchSourceJSON.index","type":"index-pattern"}],"type":"visualization","updated_at":"2022-01-18T11:55:14.105Z","version":"WzIzOTAsMTZd"} +{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[],\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\"}"},"title":"Process Variables","uiStateJSON":"{}","version":1,"visState":"{\"title\":\"Process Variables\",\"type\":\"table\",\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"count\",\"params\":{},\"schema\":\"metric\"},{\"id\":\"2\",\"enabled\":true,\"type\":\"terms\",\"params\":{\"field\":\"value.name\",\"orderBy\":\"1\",\"order\":\"desc\",\"size\":100,\"otherBucket\":false,\"otherBucketLabel\":\"Other\",\"missingBucket\":false,\"missingBucketLabel\":\"Missing\",\"customLabel\":\"variableName\"},\"schema\":\"bucket\"},{\"id\":\"3\",\"enabled\":true,\"type\":\"terms\",\"params\":{\"field\":\"value.value\",\"orderBy\":\"1\",\"order\":\"desc\",\"size\":100,\"otherBucket\":false,\"otherBucketLabel\":\"Other\",\"missingBucket\":false,\"missingBucketLabel\":\"Missing\",\"customLabel\":\"variableValue\"},\"schema\":\"bucket\"}],\"params\":{\"perPage\":20,\"showPartialRows\":false,\"showMetricsAtAllLevels\":false,\"showTotal\":false,\"showToolbar\":false,\"totalFunc\":\"sum\",\"percentageCol\":\"\"}}"},"coreMigrationVersion":"7.13.2","id":"8cf5f410-26c3-11ec-95b3-cb627b5ccd4b","migrationVersion":{"visualization":"7.13.1"},"references":[{"id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","name":"kibanaSavedObjectMeta.searchSourceJSON.index","type":"index-pattern"}],"type":"visualization","updated_at":"2022-01-18T11:55:14.105Z","version":"WzIzOTEsMTZd"} +{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[]}"},"title":"Variable Input","uiStateJSON":"{}","version":1,"visState":"{\"title\":\"Variable Input\",\"type\":\"input_control_vis\",\"aggs\":[],\"params\":{\"controls\":[{\"id\":\"1633538407315\",\"fieldName\":\"value.name\",\"parent\":\"\",\"label\":\"VariableName\",\"type\":\"list\",\"options\":{\"type\":\"terms\",\"multiselect\":true,\"dynamicOptions\":true,\"size\":5,\"order\":\"desc\"},\"indexPatternRefName\":\"control_0_index_pattern\"}],\"updateFiltersOnChange\":false,\"useTimeFilter\":false,\"pinFilters\":false}}"},"coreMigrationVersion":"7.13.2","id":"2b5132f0-26c4-11ec-95b3-cb627b5ccd4b","migrationVersion":{"visualization":"7.13.1"},"references":[{"id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","name":"control_0_index_pattern","type":"index-pattern"}],"type":"visualization","updated_at":"2022-01-18T11:55:14.105Z","version":"WzIzOTIsMTZd"} +{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[],\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\"}"},"title":"Task/State ","uiStateJSON":"{}","version":1,"visState":"{\"title\":\"Task/State \",\"type\":\"table\",\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"count\",\"params\":{},\"schema\":\"metric\"},{\"id\":\"2\",\"enabled\":true,\"type\":\"terms\",\"params\":{\"field\":\"value.type\",\"orderBy\":\"1\",\"order\":\"desc\",\"size\":20,\"otherBucket\":false,\"otherBucketLabel\":\"Other\",\"missingBucket\":false,\"missingBucketLabel\":\"Missing\",\"customLabel\":\"Task/State Name\"},\"schema\":\"bucket\"}],\"params\":{\"perPage\":10,\"showPartialRows\":false,\"showMetricsAtAllLevels\":false,\"showTotal\":false,\"showToolbar\":false,\"totalFunc\":\"sum\",\"percentageCol\":\"\"}}"},"coreMigrationVersion":"7.13.2","id":"cc282ac0-26c5-11ec-95b3-cb627b5ccd4b","migrationVersion":{"visualization":"7.13.1"},"references":[{"id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","name":"kibanaSavedObjectMeta.searchSourceJSON.index","type":"index-pattern"}],"type":"visualization","updated_at":"2022-01-18T11:55:14.105Z","version":"WzIzOTMsMTZd"} +{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"language\":\"kuery\",\"query\":\"\"},\"filter\":[]}"},"title":"Vega Visualisation 1: Time taken for each task v1","uiStateJSON":"{}","version":1,"visState":"{\"title\":\"Vega Visualisation 1: Time taken for each task v1\",\"type\":\"vega\",\"aggs\":[],\"params\":{\"spec\":\"{\\n \\\"$schema\\\": \\\"https://vega.github.io/schema/vega-lite/v5.json\\\",\\n \\\"title\\\": \\\"Event counts from all indexes\\\",\\n \\\"data\\\": {\\n \\\"url\\\": {\\n \\\"index\\\": \\\"_all\\\",\\n \\\"body\\\": {\\n \\\"aggs\\\": {\\n \\\"categories\\\": {\\n \\\"terms\\\": {\\\"field\\\": \\\"value.elementId\\\"},\\n \\\"aggs\\\": {\\n \\\"duration\\\": {\\n \\\"scripted_metric\\\": {\\n \\\"init_script\\\": \\\"state.responses = ['start':0,'stop':0]\\\",\\n \\\"map_script\\\": \\\"def intent = doc['intent'].value; def time = doc['timestamp'].value.getMillis(); if (intent.contains('ELEMENT_COMPLETED')) { state.responses.stop = time;} else if(intent.contains('ELEMENT_ACTIVATED')) {state.responses.start = time;}\\\",\\n \\\"combine_script\\\": \\\"state.responses\\\",\\n \\\"reduce_script\\\": \\\"def diff = null;for (responses in states) {diff = responses['stop'] - responses['start'];}return diff;\\\"\\n }\\n }\\n }\\n }\\n },\\n \\\"size\\\": 0,\\n \\\"query\\\": {\\n \\\"bool\\\": {\\n \\\"must\\\": [],\\n \\\"filter\\\": [\\n {\\\"match_all\\\": {}},\\n {\\\"match_phrase\\\": {\\\"value.bpmnProcessId\\\": \\\"mpesa-flow-v3-oaf\\\"}},\\n {\\\"match_phrase\\\": {\\\"value.processInstanceKey\\\": \\\"2251799817833262\\\"}}\\n ],\\n \\\"should\\\": [],\\n \\\"must_not\\\": [\\n {\\\"wildcard\\\": {\\\"value.elementId\\\": \\\"*Flow*\\\"}},\\n {\\\"wildcard\\\": {\\\"value.elementId\\\": \\\"*Gateway*\\\"}},\\n {\\\"wildcard\\\": {\\\"value.elementId\\\": \\\"*Event*\\\"}},\\n {\\\"wildcard\\\": {\\\"value.elementId\\\": \\\"*mpesa*\\\"}}\\n ]\\n }\\n }\\n }\\n },\\n \\\"format\\\": {\\\"property\\\": \\\"aggregations.categories.buckets\\\"}\\n },\\n \\\"mark\\\": \\\"bar\\\",\\n \\\"encoding\\\": {\\n \\\"x\\\": {\\n \\\"field\\\": \\\"duration.value\\\",\\n \\\"type\\\": \\\"temporal\\\",\\n \\\"timeUnit\\\": \\\"seconds\\\",\\n \\\"axis\\\": {\\\"title\\\": \\\"Time taken in seconds \\\"}\\n },\\n \\\"y\\\": {\\\"field\\\": \\\"key\\\", \\\"type\\\": \\\"nominal\\\", \\\"axis\\\": {\\\"title\\\": \\\"Tasks\\\"}},\\n \\\"color\\\": {\\\"field\\\": \\\"key\\\", \\\"type\\\": \\\"nominal\\\"}\\n },\\n \\\"layer\\\": [\\n {\\n \\\"mark\\\": \\\"rect\\\",\\n \\\"encoding\\\": {\\n \\\"color\\\": {\\n \\\"field\\\": \\\"duration.value\\\",\\n \\\"type\\\": \\\"temporal\\\",\\n \\\"timeUnit\\\": \\\"seconds\\\",\\n \\\"title\\\": \\\"Time elapsed\\\",\\n \\\"legend\\\": {\\\"direction\\\": \\\"horizontal\\\", \\\"gradientLength\\\": 120}\\n }\\n }\\n }\\n ]\\n}\"}}"},"coreMigrationVersion":"7.13.2","id":"8b628a10-829d-11ec-94f2-7f85f327d8f2","migrationVersion":{"visualization":"7.13.1"},"references":[],"type":"visualization","updated_at":"2022-02-09T11:11:37.621Z","version":"WzMxMzEsMTZd"} +{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"language\":\"lucene\",\"query\":\"\"},\"filter\":[]}"},"title":"Vega Visualisation 3: Pie chart for transactions above filter","uiStateJSON":"{}","version":1,"visState":"{\"title\":\"Vega Visualisation 3: Pie chart for transactions above filter\",\"type\":\"vega\",\"aggs\":[],\"params\":{\"spec\":\"{\\n $schema: https://vega.github.io/schema/vega-lite/v5.json\\n title: Event counts from all indexes\\n data: {\\n url: {\\n index: _all\\n body: {\\n aggs: {\\n categories: {\\n terms: {\\n field: value.processInstanceKey\\n }\\n aggs: {\\n duration: {\\n scripted_metric: {\\n init_script: state.responses = ['start':0,'stop':0]\\n map_script: def intent = doc['intent'].value; def time = doc['timestamp'].value.getMillis(); state.responses.start = time; if (intent.contains('COMPLETED') && time > state.responses['stop']) { state.responses.stop = time;} else if(intent.contains('CREATED') && time < state.responses['start'] ) {state.responses.start = time;}\\n combine_script: state.responses\\n reduce_script: def diff = null;for (responses in states) {diff = responses['stop'] - responses['start'];}return diff;\\n }\\n }\\n }\\n }\\n }\\n size: 0\\n query: {\\n bool: {\\n must: [\\n ]\\n filter: [\\n {\\n match_all: {\\n }\\n }\\n {\\n match_phrase: {\\n value.bpmnProcessId: mpesa-flow-v3\\n }\\n }\\n ]\\n should: [\\n ]\\n must_not: [\\n ]\\n }\\n }\\n }\\n }\\n format: {\\n property: aggregations.categories.buckets\\n }\\n }\\n transform: [\\n {\\n calculate: \\\"datum['duration.value'] > 120000 ? 'above 2 min' : 'below 2 min' \\\"\\n as: diff\\n }\\n ]\\n mark: arc\\n encoding: {\\n theta: {\\n field: duration.value\\n aggregate: count\\n type: quantitative\\n }\\n color: {\\n field: diff\\n type: nominal\\n axis: {\\n title: Process Instance\\n }\\n }\\n }\\n}\"}}"},"coreMigrationVersion":"7.13.2","id":"04748e40-7771-11ec-80b6-cdd557ff9b70","migrationVersion":{"visualization":"7.13.1"},"references":[],"type":"visualization","updated_at":"2022-01-18T11:55:14.105Z","version":"WzIzOTQsMTZd"} +{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[]}"},"title":"Count of Failed/Cancelled Txns","uiStateJSON":"{}","version":1,"visState":"{\"title\":\"Count of Failed/Cancelled Txns\",\"type\":\"metrics\",\"aggs\":[],\"params\":{\"time_range_mode\":\"entire_time_range\",\"id\":\"61ca57f0-469d-11e7-af02-69e470af7417\",\"type\":\"metric\",\"series\":[{\"id\":\"61ca57f1-469d-11e7-af02-69e470af7417\",\"color\":\"#68BC00\",\"split_mode\":\"filters\",\"palette\":{\"type\":\"palette\",\"name\":\"default\"},\"metrics\":[{\"id\":\"61ca57f2-469d-11e7-af02-69e470af7417\",\"type\":\"count\"}],\"separate_axis\":0,\"axis_position\":\"right\",\"formatter\":\"number\",\"chart_type\":\"line\",\"line_width\":1,\"point_size\":1,\"fill\":0.5,\"stacked\":\"none\",\"terms_field\":null,\"terms_order_by\":\"_key\",\"filter\":{\"query\":\"\",\"language\":\"kuery\"},\"split_filters\":[{\"filter\":{\"query\":\"value.bpmnElementType : \\\"PROCESS\\\" and intent : \\\"ELEMENT_TERMINATED\\\" and value.version : 3\",\"language\":\"kuery\"},\"label\":\"Failed/Cancelled Transactions\",\"color\":\"#68BC00\",\"id\":\"971242e0-8d71-11ec-bcff-f58c9e3b2a77\"}],\"label\":\"Count Of Failed/Cancelled Txns\",\"terms_direction\":\"desc\"}],\"time_field\":\"\",\"index_pattern\":\"\",\"use_kibana_indexes\":true,\"interval\":\"\",\"axis_position\":\"left\",\"axis_formatter\":\"number\",\"axis_scale\":\"normal\",\"show_legend\":1,\"show_grid\":1,\"tooltip_mode\":\"show_all\",\"background_color_rules\":[{\"id\":\"564d2540-8d71-11ec-bcff-f58c9e3b2a77\"}],\"isModelInvalid\":false,\"filter\":{\"query\":\"\",\"language\":\"kuery\"}}}"},"coreMigrationVersion":"7.13.2","id":"66e67450-8d72-11ec-92d2-2d974edf9929","migrationVersion":{"visualization":"7.13.1"},"references":[],"type":"visualization","updated_at":"2022-02-14T08:45:03.381Z","version":"WzkxOTQsMTZd"} +{"attributes":{"description":"","hits":0,"kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"language\":\"kuery\",\"query\":\"\"},\"filter\":[]}"},"optionsJSON":"{\"hidePanelTitles\":false,\"useMargins\":true}","panelsJSON":"[{\"version\":\"7.13.2\",\"type\":\"visualization\",\"gridData\":{\"x\":0,\"y\":0,\"w\":18,\"h\":7,\"i\":\"6fc4224e-00ad-4a0b-bc30-cdd7c8c26e68\"},\"panelIndex\":\"6fc4224e-00ad-4a0b-bc30-cdd7c8c26e68\",\"embeddableConfig\":{\"savedVis\":{\"title\":\"ProcessDefControl\",\"description\":\"\",\"type\":\"input_control_vis\",\"params\":{\"controls\":[{\"id\":\"1633536719626\",\"fieldName\":\"value.bpmnProcessId\",\"parent\":\"\",\"label\":\"ProcessDef\",\"type\":\"list\",\"options\":{\"type\":\"terms\",\"multiselect\":true,\"dynamicOptions\":true,\"size\":5,\"order\":\"desc\"},\"indexPatternRefName\":\"control_6fc4224e-00ad-4a0b-bc30-cdd7c8c26e68_0_index_pattern\"}],\"updateFiltersOnChange\":false,\"useTimeFilter\":false,\"pinFilters\":false},\"uiState\":{},\"data\":{\"aggs\":[],\"searchSource\":{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[]}}},\"enhancements\":{}}},{\"version\":\"7.13.2\",\"type\":\"visualization\",\"gridData\":{\"x\":18,\"y\":0,\"w\":29,\"h\":7,\"i\":\"2adee62e-ff39-4b27-899d-6acc933194f7\"},\"panelIndex\":\"2adee62e-ff39-4b27-899d-6acc933194f7\",\"embeddableConfig\":{\"vis\":{\"params\":{\"colWidth\":[{\"colIndex\":0,\"width\":364}]}},\"enhancements\":{}},\"panelRefName\":\"panel_2adee62e-ff39-4b27-899d-6acc933194f7\"},{\"version\":\"7.13.2\",\"type\":\"visualization\",\"gridData\":{\"x\":0,\"y\":7,\"w\":34,\"h\":12,\"i\":\"17035d4c-4ab4-4311-b7e9-6d60b8f532c3\"},\"panelIndex\":\"17035d4c-4ab4-4311-b7e9-6d60b8f532c3\",\"embeddableConfig\":{\"savedVis\":{\"title\":\"ProcessInstanceKeys\",\"description\":\"\",\"type\":\"table\",\"params\":{\"perPage\":10,\"showPartialRows\":false,\"showMetricsAtAllLevels\":false,\"showTotal\":false,\"showToolbar\":false,\"totalFunc\":\"sum\",\"percentageCol\":\"\"},\"uiState\":{},\"data\":{\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"count\",\"params\":{},\"schema\":\"metric\"},{\"id\":\"2\",\"enabled\":true,\"type\":\"terms\",\"params\":{\"field\":\"value.bpmnProcessId\",\"orderBy\":\"1\",\"order\":\"desc\",\"size\":1005,\"otherBucket\":false,\"otherBucketLabel\":\"Other\",\"missingBucket\":false,\"missingBucketLabel\":\"Missing\",\"customLabel\":\"ProcessDef\"},\"schema\":\"bucket\"},{\"id\":\"3\",\"enabled\":true,\"type\":\"terms\",\"params\":{\"field\":\"value.processInstanceKey\",\"orderBy\":\"1\",\"order\":\"desc\",\"size\":5,\"otherBucket\":true,\"otherBucketLabel\":\"Other\",\"missingBucket\":false,\"missingBucketLabel\":\"Missing\",\"customLabel\":\"ProcessInstanceKey\"},\"schema\":\"bucket\"}],\"searchSource\":{\"index\":\"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b\",\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[]}}},\"enhancements\":{}},\"panelRefName\":\"panel_17035d4c-4ab4-4311-b7e9-6d60b8f532c3\"},{\"version\":\"7.13.2\",\"type\":\"visualization\",\"gridData\":{\"x\":0,\"y\":19,\"w\":46,\"h\":12,\"i\":\"1a06ddb5-0b36-40e8-96be-7640d6d954b3\"},\"panelIndex\":\"1a06ddb5-0b36-40e8-96be-7640d6d954b3\",\"embeddableConfig\":{\"savedVis\":{\"title\":\"Process Variables\",\"description\":\"\",\"type\":\"table\",\"params\":{\"perPage\":20,\"showPartialRows\":false,\"showMetricsAtAllLevels\":false,\"showTotal\":false,\"showToolbar\":false,\"totalFunc\":\"sum\",\"percentageCol\":\"\"},\"uiState\":{},\"data\":{\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"count\",\"params\":{},\"schema\":\"metric\"},{\"id\":\"2\",\"enabled\":true,\"type\":\"terms\",\"params\":{\"field\":\"value.name\",\"orderBy\":\"1\",\"order\":\"desc\",\"size\":100,\"otherBucket\":false,\"otherBucketLabel\":\"Other\",\"missingBucket\":false,\"missingBucketLabel\":\"Missing\",\"customLabel\":\"variableName\"},\"schema\":\"bucket\"},{\"id\":\"3\",\"enabled\":true,\"type\":\"terms\",\"params\":{\"field\":\"value.value\",\"orderBy\":\"1\",\"order\":\"desc\",\"size\":100,\"otherBucket\":false,\"otherBucketLabel\":\"Other\",\"missingBucket\":false,\"missingBucketLabel\":\"Missing\",\"customLabel\":\"variableValue\"},\"schema\":\"bucket\"}],\"searchSource\":{\"index\":\"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b\",\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[]}}},\"vis\":{\"params\":{\"colWidth\":[{\"colIndex\":1,\"width\":1046.3333333333333},{\"colIndex\":0,\"width\":182}]}},\"table\":null,\"enhancements\":{}},\"panelRefName\":\"panel_1a06ddb5-0b36-40e8-96be-7640d6d954b3\"},{\"version\":\"7.13.2\",\"type\":\"visualization\",\"gridData\":{\"x\":0,\"y\":31,\"w\":19,\"h\":7,\"i\":\"162e25cc-3f99-48cd-ac26-c16f4c18bf6f\"},\"panelIndex\":\"162e25cc-3f99-48cd-ac26-c16f4c18bf6f\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_162e25cc-3f99-48cd-ac26-c16f4c18bf6f\"},{\"version\":\"7.13.2\",\"type\":\"visualization\",\"gridData\":{\"x\":19,\"y\":31,\"w\":28,\"h\":15,\"i\":\"38bca8ec-0692-433d-996b-1366b50ce5b2\"},\"panelIndex\":\"38bca8ec-0692-433d-996b-1366b50ce5b2\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_38bca8ec-0692-433d-996b-1366b50ce5b2\"},{\"version\":\"7.13.2\",\"type\":\"visualization\",\"gridData\":{\"x\":0,\"y\":46,\"w\":24,\"h\":15,\"i\":\"8fc4fc44-91d6-496a-af8f-444214d80872\"},\"panelIndex\":\"8fc4fc44-91d6-496a-af8f-444214d80872\",\"embeddableConfig\":{\"savedVis\":{\"title\":\"Vega Visualisation 1: Time taken for each task\",\"description\":\"\",\"type\":\"vega\",\"params\":{\"spec\":\"{\\n $schema: https://vega.github.io/schema/vega-lite/v5.json\\n title: Event counts from all indexes\\n data: {\\n url: {\\n index: _all\\n body: {\\n aggs: {\\n categories: {\\n terms: {\\n field: value.type\\n }\\n aggs: {\\n duration: {\\n scripted_metric: {\\n init_script: state.responses = ['start':0,'stop':0]\\n map_script: def intent = doc['intent'].value; def time = doc['timestamp'].value.getMillis(); if (intent.contains('COMPLETED')) { state.responses.stop += time;} else if(intent.contains('CREATED')) {state.responses.start += time;}\\n combine_script: state.responses\\n reduce_script: def diff = 0;for (responses in states) {diff = responses['stop'] - responses['start'];}return diff;\\n }\\n }\\n }\\n }\\n }\\n size: 0\\n query: {\\n bool: {\\n must: [\\n ]\\n filter: [\\n {\\n match_all: {\\n }\\n }\\n {\\n match_phrase: {\\n value.bpmnProcessId: mpesa-flow-v3-oaf\\n }\\n }\\n ]\\n should: [\\n ]\\n must_not: [\\n ]\\n }\\n }\\n }\\n }\\n format: {\\n property: aggregations.categories.buckets\\n }\\n }\\n mark: bar\\n encoding: {\\n x: {\\n field: duration.value\\n type: temporal\\n timeUnit: seconds\\n axis: {\\n title: \\\"Time taken in seconds \\\"\\n }\\n }\\n y: {\\n field: key\\n type: nominal\\n axis: {\\n title: Tasks\\n }\\n }\\n color: {\\n field: key\\n type: nominal\\n }\\n }\\n layer: [\\n {\\n mark: rect\\n encoding: {\\n color: {\\n field: duration.value\\n type: temporal\\n timeUnit: seconds\\n title: Time elapsed\\n legend: {\\n direction: horizontal\\n gradientLength: 120\\n }\\n }\\n }\\n }\\n ]\\n}\"},\"uiState\":{},\"data\":{\"aggs\":[],\"searchSource\":{\"query\":{\"language\":\"kuery\",\"query\":\"\"},\"filter\":[]}}},\"enhancements\":{}},\"panelRefName\":\"panel_8fc4fc44-91d6-496a-af8f-444214d80872\"},{\"version\":\"7.13.2\",\"type\":\"visualization\",\"gridData\":{\"x\":24,\"y\":46,\"w\":24,\"h\":15,\"i\":\"039d9f15-1fef-4e21-ab1d-cee335f2b337\"},\"panelIndex\":\"039d9f15-1fef-4e21-ab1d-cee335f2b337\",\"embeddableConfig\":{\"savedVis\":{\"title\":\"Vega Visualisation 2: All process with elapsed time per task\",\"description\":\"\",\"type\":\"vega\",\"params\":{\"spec\":\"{\\n $schema: https://vega.github.io/schema/vega-lite/v5.json\\n title: Event counts from all indexes\\n data: {\\n url: {\\n index: _all\\n body: {\\n aggs: {\\n categories: {\\n terms: {\\n field: value.processInstanceKey\\n }\\n aggs: {\\n duration: {\\n scripted_metric: {\\n init_script: state.responses = ['start':0,'stop':0]\\n map_script: def intent = doc['intent'].value; def time = doc['timestamp'].value.getMillis(); if (intent.contains('COMPLETED') && time > state.responses['stop']) { state.responses.stop = time;} else if(intent.contains('CREATED') && time < state.responses['start'] ) {state.responses.start = time;}\\n combine_script: state.responses\\n reduce_script: def diff = null;for (responses in states) {diff = responses['stop'] - responses['start'];}return diff;\\n }\\n }\\n }\\n }\\n }\\n size: 0\\n query: {\\n bool: {\\n must: [\\n ]\\n filter: [\\n {\\n match_all: {\\n }\\n }\\n {\\n match_phrase: {\\n value.bpmnProcessId: mpesa-flow-v3-oaf\\n }\\n }\\n ]\\n should: [\\n ]\\n must_not: [\\n ]\\n }\\n }\\n }\\n }\\n format: {\\n property: aggregations.categories.buckets\\n }\\n }\\n encoding: {\\n x: {\\n field: duration.value\\n type: temporal\\n timeUnit: seconds\\n axis: {\\n title: \\\"Time taken in miliseconds \\\"\\n }\\n }\\n y: {\\n field: key\\n type: nominal\\n axis: {\\n title: Process Instance\\n }\\n }\\n color: {\\n field: key\\n type: nominal\\n }\\n }\\n layer: [\\n {\\n mark: rect\\n encoding: {\\n color: {\\n field: duration.value\\n type: temporal\\n timeUnit: milliseconds\\n title: Time elapsed\\n legend: {\\n direction: horizontal\\n gradientLength: 120\\n }\\n }\\n }\\n }\\n {\\n mark: text\\n encoding: {\\n text: {\\n field: duration.value\\n type: temporal\\n timeUnit: seconds\\n }\\n color: {\\n condition: {\\n test: datum['duration.value'] > 120000\\n value: red\\n }\\n value: black\\n }\\n }\\n }\\n ]\\n config: {\\n axis: {\\n grid: true\\n tickBand: extent\\n }\\n }\\n}\"},\"uiState\":{},\"data\":{\"aggs\":[],\"searchSource\":{\"query\":{\"language\":\"kuery\",\"query\":\"\"},\"filter\":[]}}},\"enhancements\":{}}},{\"version\":\"7.13.2\",\"type\":\"visualization\",\"gridData\":{\"x\":0,\"y\":61,\"w\":24,\"h\":15,\"i\":\"5eed1959-b4a0-4cb9-80d8-16fb83199078\"},\"panelIndex\":\"5eed1959-b4a0-4cb9-80d8-16fb83199078\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_5eed1959-b4a0-4cb9-80d8-16fb83199078\"},{\"version\":\"7.13.2\",\"type\":\"visualization\",\"gridData\":{\"x\":24,\"y\":61,\"w\":24,\"h\":15,\"i\":\"65c8299f-8356-4ca6-b836-72ef3509769f\"},\"panelIndex\":\"65c8299f-8356-4ca6-b836-72ef3509769f\",\"embeddableConfig\":{\"savedVis\":{\"title\":\"Counts of Completed Txns\",\"description\":\"\",\"type\":\"metrics\",\"params\":{\"time_range_mode\":\"entire_time_range\",\"id\":\"61ca57f0-469d-11e7-af02-69e470af7417\",\"type\":\"metric\",\"series\":[{\"id\":\"61ca57f1-469d-11e7-af02-69e470af7417\",\"color\":\"#68BC00\",\"split_mode\":\"filters\",\"palette\":{\"type\":\"palette\",\"name\":\"default\"},\"metrics\":[{\"size\":1,\"agg_with\":\"noop\",\"order\":\"desc\",\"unit\":\"\",\"id\":\"61ca57f2-469d-11e7-af02-69e470af7417\",\"type\":\"count\",\"field\":null}],\"separate_axis\":0,\"axis_position\":\"right\",\"formatter\":\"number\",\"chart_type\":\"line\",\"line_width\":1,\"point_size\":1,\"fill\":0.5,\"stacked\":\"none\",\"label\":\"Count of events\",\"type\":\"timeseries\",\"filter\":{\"query\":\"\",\"language\":\"kuery\"},\"terms_order_by\":\"_key\",\"terms_field\":null,\"terms_direction\":\"desc\",\"terms_size\":\"30\",\"color_rules\":[{\"id\":\"0daa99e0-89ab-11ec-bcff-f58c9e3b2a77\"}],\"split_filters\":[{\"filter\":{\"query\":\"value.bpmnElementType : \\\"START_EVENT\\\" and intent : \\\"ELEMENT_COMPLETED\\\" \",\"language\":\"kuery\"},\"label\":\"Total Count Of Txns\",\"color\":\"#68BC00\",\"id\":\"470ed4d0-89ab-11ec-bcff-f58c9e3b2a77\"},{\"filter\":{\"query\":\"value.bpmnElementType : \\\"END_EVENT\\\" and value.elementId : \\\"End\\\" and intent : \\\"ELEMENT_COMPLETED\\\" \",\"language\":\"kuery\"},\"label\":\"End Event Failure Without notifications\",\"color\":\"#68BC00\",\"id\":\"aa8dbe10-89b3-11ec-bcff-f58c9e3b2a77\"},{\"filter\":{\"query\":\"value.bpmnElementType : \\\"END_EVENT\\\" and value.elementId : \\\"Event_1bh40y1\\\" and intent : \\\"ELEMENT_COMPLETED\\\" \",\"language\":\"kuery\"},\"label\":\"End Event Success Without notifications\",\"color\":\"#68BC00\",\"id\":\"3c52a310-89b4-11ec-bcff-f58c9e3b2a77\"},{\"filter\":{\"query\":\"value.bpmnElementType : \\\"END_EVENT\\\" and value.elementId : \\\"sucess\\\" and intent : \\\"ELEMENT_COMPLETED\\\" \",\"language\":\"kuery\"},\"label\":\"End Event Success With notifications\",\"color\":\"#68BC00\",\"id\":\"bcc962b0-8a89-11ec-bcff-f58c9e3b2a77\"},{\"filter\":{\"query\":\"value.bpmnElementType : \\\"END_EVENT\\\" and value.elementId : \\\"failure\\\" and intent : \\\"ELEMENT_COMPLETED\\\" \",\"language\":\"kuery\"},\"label\":\"End Event Failure With notifications\",\"color\":\"#68BC00\",\"id\":\"cbafa000-8a89-11ec-bcff-f58c9e3b2a77\"}]}],\"time_field\":\"\",\"index_pattern\":\"\",\"use_kibana_indexes\":true,\"interval\":\"\",\"axis_position\":\"left\",\"axis_formatter\":\"number\",\"axis_scale\":\"normal\",\"show_legend\":1,\"show_grid\":1,\"tooltip_mode\":\"show_all\",\"isModelInvalid\":false,\"background_color_rules\":[{\"id\":\"936d7d20-89a8-11ec-bcff-f58c9e3b2a77\"}],\"bar_color_rules\":[{\"id\":\"9645ca70-89a8-11ec-bcff-f58c9e3b2a77\"}],\"pivot_id\":\"value.processInstanceKey\",\"pivot_type\":\"number\"},\"uiState\":{},\"data\":{\"aggs\":[],\"searchSource\":{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[]}}},\"enhancements\":{}}},{\"version\":\"7.13.2\",\"type\":\"visualization\",\"gridData\":{\"x\":0,\"y\":76,\"w\":24,\"h\":15,\"i\":\"171816c1-0cfc-46b8-9d5c-5de061b51d12\"},\"panelIndex\":\"171816c1-0cfc-46b8-9d5c-5de061b51d12\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_171816c1-0cfc-46b8-9d5c-5de061b51d12\"}]","refreshInterval":{"pause":true,"value":0},"timeFrom":"now-1w","timeRestore":true,"timeTo":"now","title":"PHEE","version":1},"coreMigrationVersion":"7.13.2","id":"8bcc01c0-26bd-11ec-95b3-cb627b5ccd4b","migrationVersion":{"dashboard":"7.13.1"},"references":[{"id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","name":"6fc4224e-00ad-4a0b-bc30-cdd7c8c26e68:control_6fc4224e-00ad-4a0b-bc30-cdd7c8c26e68_0_index_pattern","type":"index-pattern"},{"id":"f21cb760-26bf-11ec-95b3-cb627b5ccd4b","name":"2adee62e-ff39-4b27-899d-6acc933194f7:panel_2adee62e-ff39-4b27-899d-6acc933194f7","type":"visualization"},{"id":"df1144f0-26c0-11ec-95b3-cb627b5ccd4b","name":"17035d4c-4ab4-4311-b7e9-6d60b8f532c3:panel_17035d4c-4ab4-4311-b7e9-6d60b8f532c3","type":"visualization"},{"id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","name":"17035d4c-4ab4-4311-b7e9-6d60b8f532c3:kibanaSavedObjectMeta.searchSourceJSON.index","type":"index-pattern"},{"id":"8cf5f410-26c3-11ec-95b3-cb627b5ccd4b","name":"1a06ddb5-0b36-40e8-96be-7640d6d954b3:panel_1a06ddb5-0b36-40e8-96be-7640d6d954b3","type":"visualization"},{"id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","name":"1a06ddb5-0b36-40e8-96be-7640d6d954b3:kibanaSavedObjectMeta.searchSourceJSON.index","type":"index-pattern"},{"id":"2b5132f0-26c4-11ec-95b3-cb627b5ccd4b","name":"162e25cc-3f99-48cd-ac26-c16f4c18bf6f:panel_162e25cc-3f99-48cd-ac26-c16f4c18bf6f","type":"visualization"},{"id":"cc282ac0-26c5-11ec-95b3-cb627b5ccd4b","name":"38bca8ec-0692-433d-996b-1366b50ce5b2:panel_38bca8ec-0692-433d-996b-1366b50ce5b2","type":"visualization"},{"id":"8b628a10-829d-11ec-94f2-7f85f327d8f2","name":"8fc4fc44-91d6-496a-af8f-444214d80872:panel_8fc4fc44-91d6-496a-af8f-444214d80872","type":"visualization"},{"id":"04748e40-7771-11ec-80b6-cdd557ff9b70","name":"5eed1959-b4a0-4cb9-80d8-16fb83199078:panel_5eed1959-b4a0-4cb9-80d8-16fb83199078","type":"visualization"},{"id":"66e67450-8d72-11ec-92d2-2d974edf9929","name":"171816c1-0cfc-46b8-9d5c-5de061b51d12:panel_171816c1-0cfc-46b8-9d5c-5de061b51d12","type":"visualization"}],"type":"dashboard","updated_at":"2022-02-14T08:45:33.341Z","version":"WzkyMTUsMTZd"} +{"exportedCount":10,"missingRefCount":0,"missingReferences":[]} \ No newline at end of file diff --git a/ph-ee-env-template/Kibana Visualisations/dashboard/Aggregations.ndjson b/ph-ee-env-template/Kibana Visualisations/dashboard/Aggregations.ndjson new file mode 100644 index 000000000..975f99bd2 --- /dev/null +++ b/ph-ee-env-template/Kibana Visualisations/dashboard/Aggregations.ndjson @@ -0,0 +1,13 @@ +{"attributes":{"fieldAttrs":"{\"value.bpmnProcessId\":{\"count\":6},\"value.elementId\":{\"count\":10},\"value.elementInstanceKey\":{\"count\":5},\"value.flowScopeKey\":{\"count\":2},\"value.parentElementInstanceKey\":{\"count\":4},\"value.parentProcessInstanceKey\":{\"count\":2},\"value.processDefinitionKey\":{\"count\":3},\"value.processDefinitionVersion\":{\"count\":1},\"value.processInstanceKey\":{\"count\":37},\"value.bpmnElementType\":{\"count\":11},\"intent\":{\"count\":5},\"value.value\":{\"count\":26},\"value.name\":{\"count\":14},\"partitionId\":{\"count\":1},\"valueType\":{\"count\":8},\"originDate\":{\"count\":1},\"_index\":{\"count\":1},\"accountId\":{\"count\":1},\"amount\":{\"count\":1},\"errorDescription\":{\"count\":6},\"key\":{\"count\":4},\"phoneNumber\":{\"count\":2},\"recordType\":{\"count\":1},\"processInstanceKey\":{\"count\":1},\"ams\":{\"count\":1},\"mpesaTransactionId\":{\"count\":2},\"transactionId\":{\"count\":1},\"errorCode\":{\"count\":1}}","fields":"[]","runtimeFieldMap":"{}","timeFieldName":"timestamp","title":"zeebe-*","typeMeta":"{}"},"coreMigrationVersion":"7.16.3","id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","migrationVersion":{"index-pattern":"7.11.0"},"references":[],"type":"index-pattern","updated_at":"2024-01-18T14:14:01.111Z","version":"WzM4OCw0XQ=="} +{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[]}"},"title":"Process Definition","uiStateJSON":"{}","version":1,"visState":"{\"title\":\"Process Definition\",\"type\":\"input_control_vis\",\"aggs\":[],\"params\":{\"controls\":[{\"id\":\"1633536719626\",\"fieldName\":\"value.bpmnProcessId\",\"parent\":\"\",\"label\":\"Process Def Key\",\"type\":\"list\",\"options\":{\"type\":\"terms\",\"multiselect\":true,\"dynamicOptions\":true,\"size\":5,\"order\":\"desc\"},\"indexPatternRefName\":\"control_0_index_pattern\"},{\"id\":\"1654250630610\",\"fieldName\":\"value.processDefinitionKey\",\"parent\":\"1633536719626\",\"label\":\"Process Def Value\",\"type\":\"list\",\"options\":{\"type\":\"terms\",\"multiselect\":true,\"dynamicOptions\":true,\"size\":50,\"order\":\"desc\"},\"indexPatternRefName\":\"control_1_index_pattern\"}],\"updateFiltersOnChange\":false,\"useTimeFilter\":false,\"pinFilters\":false}}"},"coreMigrationVersion":"7.16.3","id":"b66a64c0-e31f-11ec-9dd9-bb3704b858df","migrationVersion":{"visualization":"7.14.0"},"references":[{"id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","name":"control_0_index_pattern","type":"index-pattern"},{"id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","name":"control_1_index_pattern","type":"index-pattern"}],"type":"visualization","updated_at":"2024-01-25T12:11:47.406Z","version":"WzE1MDAsNF0="} +{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[]}"},"title":"Txn Count by BPMN Version","uiStateJSON":"{}","version":1,"visState":"{\"title\":\"Txn Count by BPMN Version\",\"type\":\"metrics\",\"aggs\":[],\"params\":{\"time_range_mode\":\"entire_time_range\",\"id\":\"75e7f774-7289-41d7-ad62-81936e329514\",\"type\":\"metric\",\"series\":[{\"time_range_mode\":\"entire_time_range\",\"id\":\"8f481979-dc3d-4732-830c-ad65f2385e00\",\"color\":\"#68BC00\",\"split_mode\":\"terms\",\"palette\":{\"type\":\"palette\",\"name\":\"default\"},\"metrics\":[{\"id\":\"58791b1e-a46f-47e9-9416-3f59f56ed477\",\"type\":\"cardinality\",\"field\":\"value.processInstanceKey\"}],\"separate_axis\":0,\"axis_position\":\"right\",\"formatter\":\"default\",\"chart_type\":\"line\",\"line_width\":1,\"point_size\":1,\"fill\":0.5,\"stacked\":\"none\",\"terms_field\":\"value.processDefinitionKey\",\"label\":\"Txn Count\"}],\"time_field\":\"\",\"index_pattern\":\"\",\"use_kibana_indexes\":true,\"interval\":\"\",\"axis_position\":\"left\",\"axis_formatter\":\"number\",\"axis_scale\":\"normal\",\"show_legend\":1,\"truncate_legend\":1,\"max_lines_legend\":1,\"show_grid\":1,\"tooltip_mode\":\"show_all\",\"drop_last_bucket\":0,\"background_color_rules\":[{\"id\":\"027b6950-8cf2-11ed-a61d-db16238eb812\"}]}}"},"coreMigrationVersion":"7.16.3","id":"e1111200-8cf2-11ed-9074-afdd87226beb","migrationVersion":{"visualization":"7.14.0"},"references":[],"type":"visualization","updated_at":"2024-01-18T14:02:22.488Z","version":"WzM0Miw0XQ=="} +{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[]}"},"title":"Txn State","uiStateJSON":"{}","version":1,"visState":"{\"title\":\"Txn State\",\"type\":\"metrics\",\"aggs\":[],\"params\":{\"time_range_mode\":\"entire_time_range\",\"id\":\"f65f4d7b-5772-4b8f-9683-1d65e90b10f8\",\"type\":\"timeseries\",\"series\":[{\"time_range_mode\":\"entire_time_range\",\"id\":\"94b1d2d6-7e1a-4084-a2e9-0215e255a57e\",\"color\":\"#68BC00\",\"split_mode\":\"filters\",\"palette\":{\"type\":\"palette\",\"name\":\"default\"},\"metrics\":[{\"id\":\"0e89671e-87aa-432b-8c3d-370cc21ef53f\",\"type\":\"count\"}],\"separate_axis\":0,\"axis_position\":\"right\",\"formatter\":\"default\",\"chart_type\":\"line\",\"line_width\":1,\"point_size\":1,\"fill\":0.5,\"stacked\":\"none\",\"split_filters\":[{\"filter\":{\"query\":\"value.bpmnElementType : \\\"END_EVENT\\\" and intent : \\\"ELEMENT_COMPLETED\\\" \",\"language\":\"kuery\"},\"label\":\"Completed\",\"color\":\"rgba(101,147,240,1)\",\"id\":\"2b3923f0-1970-11ed-850c-b3a4b04b67bd\"},{\"filter\":{\"query\":\"value.bpmnElementType : \\\"END_EVENT\\\" and value.elementId : \\\"Event_1bh40y1\\\" and intent : \\\"ELEMENT_COMPLETED\\\" \",\"language\":\"kuery\"},\"label\":\"Success (Without notifications)\",\"color\":\"rgba(160,243,104,1)\",\"id\":\"32023370-1970-11ed-850c-b3a4b04b67bd\"},{\"filter\":{\"query\":\"value.bpmnElementType : \\\"END_EVENT\\\" and value.elementId : \\\"End\\\" and intent : \\\"ELEMENT_COMPLETED\\\" \",\"language\":\"kuery\"},\"label\":\"Failure (Without notifications) \",\"color\":\"rgba(231,102,76,1)\",\"id\":\"32fd5c50-1970-11ed-850c-b3a4b04b67bd\"},{\"filter\":{\"query\":\"value.bpmnElementType : \\\"END_EVENT\\\" and intent : \\\"ELEMENT_COMPLETED\\\" and value.elementId : \\\"sucess\\\" \",\"language\":\"kuery\"},\"label\":\"Completed (Successful Notification)\",\"color\":\"rgba(170,101,86,1)\",\"id\":\"3393f700-1970-11ed-850c-b3a4b04b67bd\"},{\"filter\":{\"query\":\"value.bpmnElementType : \\\"END_EVENT\\\" and value.elementId : \\\"failure\\\" and intent : \\\"ELEMENT_COMPLETED\\\" \",\"language\":\"kuery\"},\"label\":\"Completed (Failed Notification)\",\"color\":\"#68BC00\",\"id\":\"34c4fcf0-1970-11ed-850c-b3a4b04b67bd\"},{\"filter\":{\"query\":\"value.bpmnElementType : \\\"END_EVENT\\\" and (value.elementId : \\\"sucess\\\" or value.elementId : \\\"failure\\\") and intent : \\\"ELEMENT_COMPLETED\\\" \",\"language\":\"kuery\"},\"label\":\"Failed Txns (Notifications Path)\",\"color\":\"rgba(185,168,136,1)\",\"id\":\"39d40060-1970-11ed-850c-b3a4b04b67bd\"}],\"label\":\"\"}],\"time_field\":\"\",\"index_pattern\":\"\",\"use_kibana_indexes\":true,\"interval\":\"\",\"axis_position\":\"left\",\"axis_formatter\":\"number\",\"axis_scale\":\"normal\",\"show_legend\":1,\"truncate_legend\":1,\"max_lines_legend\":1,\"show_grid\":1,\"tooltip_mode\":\"show_all\",\"drop_last_bucket\":0}}"},"coreMigrationVersion":"7.16.3","id":"1af053f0-1971-11ed-9d91-37684d8f5c4b","migrationVersion":{"visualization":"7.14.0"},"references":[],"type":"visualization","updated_at":"2024-01-18T14:02:22.488Z","version":"WzM0Myw0XQ=="} +{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[]}"},"title":"Error Timeline","uiStateJSON":"{}","version":1,"visState":"{\"title\":\"Error Timeline\",\"type\":\"metrics\",\"aggs\":[],\"params\":{\"time_range_mode\":\"entire_time_range\",\"id\":\"f9bdb48d-9fd0-4c71-bdd1-f0c3163622d8\",\"type\":\"timeseries\",\"series\":[{\"time_range_mode\":\"entire_time_range\",\"id\":\"6b3e48f0-159f-4e30-b929-412fd9b7f693\",\"color\":\"#68BC00\",\"split_mode\":\"terms\",\"palette\":{\"type\":\"palette\",\"name\":\"default\"},\"metrics\":[{\"id\":\"50f9cf8b-9710-485e-9b9b-54a08a025671\",\"type\":\"count\"}],\"separate_axis\":0,\"axis_position\":\"right\",\"formatter\":\"default\",\"chart_type\":\"line\",\"line_width\":1,\"point_size\":1,\"fill\":0.5,\"stacked\":\"none\",\"label\":\"Error Count\",\"terms_field\":\"value.value\",\"terms_size\":\"30\"}],\"time_field\":\"\",\"index_pattern\":\"\",\"use_kibana_indexes\":true,\"interval\":\"\",\"axis_position\":\"left\",\"axis_formatter\":\"number\",\"axis_scale\":\"normal\",\"show_legend\":1,\"truncate_legend\":1,\"max_lines_legend\":1,\"show_grid\":1,\"tooltip_mode\":\"show_all\",\"drop_last_bucket\":0,\"isModelInvalid\":false,\"filter\":{\"query\":\"value.name : \\\"errorDescription\\\" or value.name: \\\"errorInformation\\\"\",\"language\":\"kuery\"}}}"},"coreMigrationVersion":"7.16.3","id":"381ab8c0-a51e-11ec-92c9-877156a2a4e9","migrationVersion":{"visualization":"7.14.0"},"references":[],"type":"visualization","updated_at":"2024-01-25T12:40:40.963Z","version":"WzE5ODgsNF0="} +{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[]}"},"title":"Transaction Decision Gateways","uiStateJSON":"{}","version":1,"visState":"{\"title\":\"Transaction Decision Gateways\",\"type\":\"metrics\",\"aggs\":[],\"params\":{\"time_range_mode\":\"entire_time_range\",\"id\":\"0fbcb70d-785f-4bd5-8a01-5ccf2ba8b04f\",\"type\":\"metric\",\"series\":[{\"time_range_mode\":\"entire_time_range\",\"id\":\"e29c0f65-d09d-43f8-99a3-b7075234c1d9\",\"color\":\"#68BC00\",\"split_mode\":\"filters\",\"palette\":{\"type\":\"palette\",\"name\":\"default\"},\"metrics\":[{\"id\":\"55bc12ae-9f04-4fd9-bb99-402048ceb1b8\",\"type\":\"count\"}],\"separate_axis\":0,\"axis_position\":\"right\",\"formatter\":\"default\",\"chart_type\":\"line\",\"line_width\":1,\"point_size\":1,\"fill\":0.5,\"stacked\":\"none\",\"split_filters\":[{\"filter\":{\"query\":\"value.name: \\\"partyLookupFailed\\\" and value.value: \\\"true\\\" \",\"language\":\"kuery\"},\"label\":\"Count of Txns With Party Lookup Failed\",\"color\":\"#68BC00\",\"id\":\"61348740-9a01-11ec-8b98-a3ff4ce513d9\"},{\"filter\":{\"query\":\"value.name : \\\"transactionFailed\\\" and value.value : \\\"true\\\" \",\"language\":\"kuery\"},\"label\":\"Count of Txns With Transaction Failed\",\"color\":\"#68BC00\",\"id\":\"abf94e50-9a01-11ec-8b98-a3ff4ce513d9\"},{\"filter\":{\"query\":\" value.name : \\\"transferSettlementFailed\\\" and value.value : \\\"true\\\" \",\"language\":\"kuery\"},\"label\":\"Count of Txns With Settlement Failed\",\"color\":\"#68BC00\",\"id\":\"db417e30-9a01-11ec-8b98-a3ff4ce513d9\"},{\"filter\":{\"query\":\"value.name: \\\"partyLookupFailed\\\" and NOT value.value : \\\"true\\\" \",\"language\":\"kuery\"},\"label\":\"Count of Txns With Party Lookup Successful \",\"color\":\"#68BC00\",\"id\":\"f60f10b0-9a01-11ec-8b98-a3ff4ce513d9\"},{\"filter\":{\"query\":\"value.name : \\\"transactionFailed\\\" and value.value : \\\"false\\\" \",\"language\":\"kuery\"},\"label\":\"[Misleading] Count of Txns With Transaction Successful\",\"color\":\"#68BC00\",\"id\":\"29cc26e0-9a02-11ec-8b98-a3ff4ce513d9\"},{\"filter\":{\"query\":\"value.name : \\\"transferSettlementFailed\\\" and NOT value.value : \\\"true\\\" \",\"language\":\"kuery\"},\"label\":\"Count of Txns With Settlement Successful\",\"color\":\"#68BC00\",\"id\":\"7565ca20-9a02-11ec-8b98-a3ff4ce513d9\"}],\"label\":\"\"}],\"time_field\":\"\",\"index_pattern\":\"\",\"use_kibana_indexes\":true,\"interval\":\"\",\"axis_position\":\"left\",\"axis_formatter\":\"number\",\"axis_scale\":\"normal\",\"show_legend\":1,\"truncate_legend\":1,\"max_lines_legend\":1,\"show_grid\":1,\"tooltip_mode\":\"show_all\",\"drop_last_bucket\":0,\"background_color_rules\":[{\"id\":\"5c1bbfd0-9a01-11ec-8b98-a3ff4ce513d9\"}]}}"},"coreMigrationVersion":"7.16.3","id":"ef6d42d0-9a02-11ec-92c9-877156a2a4e9","migrationVersion":{"visualization":"7.14.0"},"references":[],"type":"visualization","updated_at":"2024-01-18T14:02:22.488Z","version":"WzM0NSw0XQ=="} +{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[]}"},"title":"Txn Count","uiStateJSON":"{}","version":1,"visState":"{\"title\":\"Txn Count\",\"type\":\"metrics\",\"aggs\":[],\"params\":{\"time_range_mode\":\"entire_time_range\",\"id\":\"61ca57f0-469d-11e7-af02-69e470af7417\",\"type\":\"metric\",\"series\":[{\"time_range_mode\":\"entire_time_range\",\"id\":\"61ca57f1-469d-11e7-af02-69e470af7417\",\"color\":\"#68BC00\",\"split_mode\":\"filters\",\"palette\":{\"type\":\"palette\",\"name\":\"default\"},\"metrics\":[{\"size\":1,\"agg_with\":\"noop\",\"order\":\"desc\",\"unit\":\"\",\"id\":\"61ca57f2-469d-11e7-af02-69e470af7417\",\"type\":\"count\",\"field\":null}],\"separate_axis\":0,\"axis_position\":\"right\",\"formatter\":\"number\",\"chart_type\":\"line\",\"line_width\":1,\"point_size\":1,\"fill\":0.5,\"stacked\":\"none\",\"label\":\"Count of events\",\"type\":\"timeseries\",\"filter\":{\"query\":\"\",\"language\":\"kuery\"},\"terms_order_by\":\"_key\",\"terms_field\":null,\"terms_direction\":\"desc\",\"terms_size\":\"30\",\"color_rules\":[{\"id\":\"0daa99e0-89ab-11ec-bcff-f58c9e3b2a77\"}],\"split_filters\":[{\"filter\":{\"query\":\"value.bpmnElementType : \\\"END_EVENT\\\" and intent : \\\"ELEMENT_COMPLETED\\\" \",\"language\":\"kuery\"},\"label\":\"Total Count Of Completed Workflows\",\"color\":\"#68BC00\",\"id\":\"470ed4d0-89ab-11ec-bcff-f58c9e3b2a77\"},{\"filter\":{\"query\":\"value.bpmnElementType : \\\"END_EVENT\\\" and intent : \\\"ELEMENT_COMPLETED\\\" and (value.elementId : \\\"Event_1bh40y1\\\" or value.elementId : \\\"Event_1g7s82g\\\" or value.elementId : \\\"Event_0bwq9cj\\\" or value.elementId : \\\"Event_1ucyl4y\\\" or value.elementId : \\\"Event_1sh6bqo\\\" or value.elementId : \\\"Event_0yrma7l\\\" or value.elementId : \\\"Event_0hyfpib\\\" or value.elementId : \\\"Event_08y0ck0\\\" or value.elementId : \\\"EndEvent_1y60c95\\\" or value.elementId : \\\"EndEvent_02ollka\\\" or value.elementId : \\\"EndEvent_0guxwev\\\")\",\"language\":\"kuery\"},\"label\":\"Txn Sucess (Without notifications path)\",\"color\":\"#68BC00\",\"id\":\"aa8dbe10-89b3-11ec-bcff-f58c9e3b2a77\"},{\"filter\":{\"query\":\"value.bpmnElementType : \\\"END_EVENT\\\" and (value.elementId : \\\"sucess\\\" or value.elementId : \\\"failure\\\") and intent : \\\"ELEMENT_COMPLETED\\\" \",\"language\":\"kuery\"},\"label\":\"Failed Txns (Under Notifications Path)\",\"color\":\"#68BC00\",\"id\":\"3c52a310-89b4-11ec-bcff-f58c9e3b2a77\"},{\"filter\":{\"query\":\"value.bpmnElementType : \\\"END_EVENT\\\" and intent : \\\"ELEMENT_COMPLETED\\\" and value.elementId : \\\"sucess\\\" \",\"language\":\"kuery\"},\"label\":\"Completed Workflow (With Successful Notification Delivery)\",\"color\":\"#68BC00\",\"id\":\"bcc962b0-8a89-11ec-bcff-f58c9e3b2a77\"},{\"filter\":{\"query\":\"value.bpmnElementType : \\\"END_EVENT\\\" and value.elementId : \\\"failure\\\" and intent : \\\"ELEMENT_COMPLETED\\\" \",\"language\":\"kuery\"},\"label\":\"Completed Workflow (With Failed Notification Delivery)\",\"color\":\"#68BC00\",\"id\":\"cbafa000-8a89-11ec-bcff-f58c9e3b2a77\"},{\"filter\":{\"query\":\"value.bpmnElementType : \\\"END_EVENT\\\" and intent : \\\"ELEMENT_COMPLETED\\\" and (value.elementId : \\\"End\\\" or value.elementId : \\\"Event_1rvkkk9\\\" or value.elementId : \\\"Event_1ih6ls7\\\" or value.elementId : \\\"Event_0yilwue\\\" or value.elementId : \\\"Event_1ullala\\\" or value.elementId : \\\"EndEvent_Failure_Aborted\\\" or value.elementId : \\\"EndEvent_1jaizso\\\" or value.elementId : \\\"EndEvent_02dm8z4\\\" or value.elementId : \\\"Event_0x0pgi7\\\" or value.elementId : \\\"Event_11auvb6\\\")\",\"language\":\"kuery\"},\"label\":\"Txn Failure (Without notifications path) \",\"color\":\"#68BC00\",\"id\":\"17433ae0-9bc4-11ec-a468-43f14c90e9d4\"}]}],\"time_field\":\"\",\"use_kibana_indexes\":true,\"interval\":\"\",\"axis_position\":\"left\",\"axis_formatter\":\"number\",\"axis_scale\":\"normal\",\"show_legend\":1,\"show_grid\":1,\"tooltip_mode\":\"show_all\",\"isModelInvalid\":false,\"background_color_rules\":[{\"id\":\"936d7d20-89a8-11ec-bcff-f58c9e3b2a77\"}],\"bar_color_rules\":[{\"id\":\"9645ca70-89a8-11ec-bcff-f58c9e3b2a77\"}],\"pivot_id\":\"value.processInstanceKey\",\"pivot_type\":\"number\",\"drop_last_bucket\":1,\"truncate_legend\":1,\"max_lines_legend\":1,\"index_pattern_ref_name\":\"metrics_0_index_pattern\"}}"},"coreMigrationVersion":"7.16.3","id":"6432c370-9bbf-11ec-92c9-877156a2a4e9","migrationVersion":{"visualization":"7.14.0"},"references":[{"id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","name":"metrics_0_index_pattern","type":"index-pattern"}],"type":"visualization","updated_at":"2024-01-25T12:38:47.572Z","version":"WzE4NzYsNF0="} +{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[],\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\"}"},"title":"Txn Error Counts","uiStateJSON":"{}","version":1,"visState":"{\"title\":\"Txn Error Counts\",\"type\":\"horizontal_bar\",\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"count\",\"params\":{},\"schema\":\"metric\"},{\"id\":\"3\",\"enabled\":true,\"type\":\"filters\",\"params\":{\"filters\":[{\"input\":{\"query\":\"value.name : \\\"errorDescription\\\" or value.name: \\\"errorInformation\\\"\",\"language\":\"kuery\"},\"label\":\"\"}]},\"schema\":\"group\"},{\"id\":\"2\",\"enabled\":true,\"type\":\"terms\",\"params\":{\"field\":\"value.value\",\"orderBy\":\"1\",\"order\":\"desc\",\"size\":37,\"otherBucket\":false,\"otherBucketLabel\":\"Other\",\"missingBucket\":false,\"missingBucketLabel\":\"Missing\",\"customLabel\":\"Error Description/Error Information\"},\"schema\":\"segment\"}],\"params\":{\"type\":\"histogram\",\"grid\":{\"categoryLines\":false},\"categoryAxes\":[{\"id\":\"CategoryAxis-1\",\"type\":\"category\",\"position\":\"left\",\"show\":true,\"scale\":{\"type\":\"linear\"},\"labels\":{\"show\":true,\"rotate\":0,\"filter\":false,\"truncate\":200},\"title\":{},\"style\":{}}],\"valueAxes\":[{\"id\":\"ValueAxis-1\",\"name\":\"LeftAxis-1\",\"type\":\"value\",\"position\":\"bottom\",\"show\":true,\"scale\":{\"type\":\"linear\",\"mode\":\"normal\"},\"labels\":{\"show\":true,\"rotate\":75,\"filter\":true,\"truncate\":100},\"title\":{\"text\":\"\"},\"style\":{}}],\"seriesParams\":[{\"show\":true,\"type\":\"histogram\",\"mode\":\"normal\",\"data\":{\"label\":\"Count\",\"id\":\"1\"},\"interpolate\":\"linear\",\"valueAxis\":\"ValueAxis-1\",\"drawLinesBetweenPoints\":true,\"lineWidth\":2,\"showCircles\":true,\"circlesRadius\":1}],\"addTooltip\":true,\"detailedTooltip\":true,\"palette\":{\"type\":\"palette\",\"name\":\"default\"},\"addLegend\":true,\"legendPosition\":\"right\",\"times\":[],\"addTimeMarker\":false,\"truncateLegend\":true,\"maxLegendLines\":1,\"labels\":{},\"radiusRatio\":0,\"thresholdLine\":{\"show\":false,\"value\":10,\"width\":1,\"style\":\"full\",\"color\":\"#E7664C\"}}}"},"coreMigrationVersion":"7.16.3","id":"7d954ce0-9bc2-11ec-92c9-877156a2a4e9","migrationVersion":{"visualization":"7.14.0"},"references":[{"id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","name":"kibanaSavedObjectMeta.searchSourceJSON.index","type":"index-pattern"}],"type":"visualization","updated_at":"2024-01-25T12:41:10.384Z","version":"WzIwMTMsNF0="} +{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[]}"},"title":"Txn Errors (Non-Recoverable & Recoverable but recently discovered)","uiStateJSON":"{}","version":1,"visState":"{\"title\":\"Txn Errors (Non-Recoverable & Recoverable but recently discovered)\",\"type\":\"metrics\",\"aggs\":[],\"params\":{\"time_range_mode\":\"entire_time_range\",\"id\":\"768bef68-2db5-4d77-bd9f-579081c6db3b\",\"type\":\"metric\",\"series\":[{\"time_range_mode\":\"entire_time_range\",\"id\":\"9ddc6de7-76ea-4091-8b30-f99120b6aeca\",\"color\":\"#68BC00\",\"split_mode\":\"everything\",\"palette\":{\"type\":\"palette\",\"name\":\"default\"},\"metrics\":[{\"id\":\"a9d2f7ce-efb1-497e-a3df-97120af26471\",\"type\":\"count\"}],\"separate_axis\":0,\"axis_position\":\"right\",\"formatter\":\"default\",\"chart_type\":\"line\",\"line_width\":1,\"point_size\":1,\"fill\":0.5,\"stacked\":\"none\",\"label\":\"Txn Errors \"}],\"time_field\":\"\",\"index_pattern\":\"\",\"use_kibana_indexes\":true,\"interval\":\"\",\"axis_position\":\"left\",\"axis_formatter\":\"number\",\"axis_scale\":\"normal\",\"show_legend\":1,\"truncate_legend\":1,\"max_lines_legend\":1,\"show_grid\":1,\"tooltip_mode\":\"show_all\",\"drop_last_bucket\":0,\"isModelInvalid\":false,\"filter\":{\"query\":\"value.name : \\\"deliveryErrorMessage\\\" or value.name: \\\"errorInformation\\\" \",\"language\":\"kuery\"},\"background_color_rules\":[{\"id\":\"f339f290-9bc0-11ec-a468-43f14c90e9d4\"}]}}"},"coreMigrationVersion":"7.16.3","id":"73343f00-9bc1-11ec-92c9-877156a2a4e9","migrationVersion":{"visualization":"7.14.0"},"references":[],"type":"visualization","updated_at":"2024-01-18T14:02:22.488Z","version":"WzM0OCw0XQ=="} +{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[]}"},"title":"Count Of Cancelled Workflows","uiStateJSON":"{}","version":1,"visState":"{\"title\":\"Count Of Cancelled Workflows\",\"type\":\"metrics\",\"aggs\":[],\"params\":{\"time_range_mode\":\"entire_time_range\",\"id\":\"61ca57f0-469d-11e7-af02-69e470af7417\",\"type\":\"metric\",\"series\":[{\"time_range_mode\":\"entire_time_range\",\"id\":\"61ca57f1-469d-11e7-af02-69e470af7417\",\"color\":\"#68BC00\",\"split_mode\":\"filters\",\"palette\":{\"type\":\"palette\",\"name\":\"default\"},\"metrics\":[{\"id\":\"61ca57f2-469d-11e7-af02-69e470af7417\",\"type\":\"count\"}],\"separate_axis\":0,\"axis_position\":\"right\",\"formatter\":\"number\",\"chart_type\":\"line\",\"line_width\":1,\"point_size\":1,\"fill\":0.5,\"stacked\":\"none\",\"terms_field\":null,\"terms_order_by\":\"_key\",\"filter\":{\"query\":\"\",\"language\":\"kuery\"},\"split_filters\":[{\"filter\":{\"query\":\"value.bpmnElementType : \\\"PROCESS\\\" and intent : \\\"ELEMENT_TERMINATED\\\" \",\"language\":\"kuery\"},\"label\":\"Cancelled Workflows\",\"color\":\"#68BC00\",\"id\":\"971242e0-8d71-11ec-bcff-f58c9e3b2a77\"}],\"label\":\"Count Of Cancelled Workflows\",\"terms_direction\":\"desc\"}],\"time_field\":\"\",\"use_kibana_indexes\":true,\"interval\":\"\",\"axis_position\":\"left\",\"axis_formatter\":\"number\",\"axis_scale\":\"normal\",\"show_legend\":1,\"show_grid\":1,\"tooltip_mode\":\"show_all\",\"background_color_rules\":[{\"id\":\"564d2540-8d71-11ec-bcff-f58c9e3b2a77\"}],\"isModelInvalid\":false,\"filter\":{\"query\":\"\",\"language\":\"kuery\"},\"drop_last_bucket\":1,\"truncate_legend\":1,\"max_lines_legend\":1,\"index_pattern_ref_name\":\"metrics_0_index_pattern\"}}"},"coreMigrationVersion":"7.16.3","id":"f65006c0-9a00-11ec-92c9-877156a2a4e9","migrationVersion":{"visualization":"7.14.0"},"references":[{"id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","name":"metrics_0_index_pattern","type":"index-pattern"}],"type":"visualization","updated_at":"2024-01-18T14:02:22.488Z","version":"WzM0OSw0XQ=="} +{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"lucene\"},\"filter\":[]}"},"title":"Count of Timed Out Workflows","uiStateJSON":"{}","version":1,"visState":"{\"title\":\"Count of Timed Out Workflows\",\"type\":\"metrics\",\"aggs\":[],\"params\":{\"time_range_mode\":\"entire_time_range\",\"id\":\"24013fd2-cb48-4385-907c-6547080a2b9c\",\"type\":\"metric\",\"series\":[{\"time_range_mode\":\"entire_time_range\",\"id\":\"8184665c-7bbb-4fa5-835e-f9d09ed6c313\",\"color\":\"#68BC00\",\"split_mode\":\"filters\",\"palette\":{\"type\":\"palette\",\"name\":\"default\"},\"metrics\":[{\"id\":\"1a321ec2-949a-47de-bba3-d63da366a9f5\",\"type\":\"count\"}],\"separate_axis\":0,\"axis_position\":\"right\",\"formatter\":\"default\",\"chart_type\":\"line\",\"line_width\":1,\"point_size\":1,\"fill\":0.5,\"stacked\":\"none\",\"split_filters\":[{\"filter\":{\"query\":\"value.name: \\\"mpesaTransactionStatusRetryCount\\\" or value.name: \\\"partyLookupRetryCount\\\" or value.name: \\\"accountLookupRetryCount\\\" or value.name: \\\"maxStatusRetry\\\" and value.value : \\\"4\\\" \",\"language\":\"kuery\"},\"label\":\"Count of Timed Out Txns (Running & Completed)\",\"color\":\"#68BC00\",\"id\":\"256d98a0-9a0b-11ec-953b-9d26005d8940\"},{\"filter\":{\"query\":\"value.name : \\\"callbackRetry\\\" or value.name : \\\"maxCallbackRetry\\\" and value.value : \\\"3\\\" \",\"language\":\"kuery\"},\"label\":\"Count of Timed Out Callback Deliveries (Running & Completed)\",\"color\":\"#68BC00\",\"id\":\"6f3bcab0-9a0b-11ec-953b-9d26005d8940\"}],\"label\":\"\"}],\"time_field\":\"\",\"index_pattern\":\"\",\"use_kibana_indexes\":true,\"interval\":\"\",\"axis_position\":\"left\",\"axis_formatter\":\"number\",\"axis_scale\":\"normal\",\"show_legend\":1,\"truncate_legend\":1,\"max_lines_legend\":1,\"show_grid\":1,\"tooltip_mode\":\"show_all\",\"drop_last_bucket\":0,\"background_color_rules\":[{\"id\":\"233d9940-9a0b-11ec-953b-9d26005d8940\"}]}}"},"coreMigrationVersion":"7.16.3","id":"9de94130-9a0b-11ec-92c9-877156a2a4e9","migrationVersion":{"visualization":"7.14.0"},"references":[],"type":"visualization","updated_at":"2024-01-25T12:46:30.445Z","version":"WzIyMDUsNF0="} +{"attributes":{"description":"","hits":0,"kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[]}"},"optionsJSON":"{\"useMargins\":false,\"syncColors\":false,\"hidePanelTitles\":false}","panelsJSON":"[{\"version\":\"7.16.3\",\"type\":\"visualization\",\"gridData\":{\"x\":0,\"y\":0,\"w\":23,\"h\":8,\"i\":\"2b803a94-c62b-4e30-adef-99cdcb2f6f4c\"},\"panelIndex\":\"2b803a94-c62b-4e30-adef-99cdcb2f6f4c\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_2b803a94-c62b-4e30-adef-99cdcb2f6f4c\"},{\"version\":\"7.16.3\",\"type\":\"visualization\",\"gridData\":{\"x\":23,\"y\":0,\"w\":25,\"h\":8,\"i\":\"f9f79e20-71e4-4969-86cb-7d9626c0a266\"},\"panelIndex\":\"f9f79e20-71e4-4969-86cb-7d9626c0a266\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_f9f79e20-71e4-4969-86cb-7d9626c0a266\"},{\"version\":\"7.16.3\",\"type\":\"visualization\",\"gridData\":{\"x\":0,\"y\":8,\"w\":48,\"h\":12,\"i\":\"507e2205-659d-4a81-9d77-b6367e5336e9\"},\"panelIndex\":\"507e2205-659d-4a81-9d77-b6367e5336e9\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_507e2205-659d-4a81-9d77-b6367e5336e9\"},{\"version\":\"7.16.3\",\"type\":\"visualization\",\"gridData\":{\"x\":0,\"y\":20,\"w\":48,\"h\":15,\"i\":\"331c2464-ba2e-406d-a6fc-c99aed588227\"},\"panelIndex\":\"331c2464-ba2e-406d-a6fc-c99aed588227\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_331c2464-ba2e-406d-a6fc-c99aed588227\"},{\"version\":\"7.16.3\",\"type\":\"visualization\",\"gridData\":{\"x\":0,\"y\":35,\"w\":24,\"h\":18,\"i\":\"22be9f77-2f41-440c-9e82-92fa979d48a0\"},\"panelIndex\":\"22be9f77-2f41-440c-9e82-92fa979d48a0\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_22be9f77-2f41-440c-9e82-92fa979d48a0\"},{\"version\":\"7.16.3\",\"type\":\"visualization\",\"gridData\":{\"x\":24,\"y\":35,\"w\":24,\"h\":18,\"i\":\"23de9b9f-a3ae-4fd8-93eb-473ebe74bc0a\"},\"panelIndex\":\"23de9b9f-a3ae-4fd8-93eb-473ebe74bc0a\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_23de9b9f-a3ae-4fd8-93eb-473ebe74bc0a\"},{\"version\":\"7.16.3\",\"type\":\"visualization\",\"gridData\":{\"x\":0,\"y\":53,\"w\":48,\"h\":13,\"i\":\"a0ea3f82-c257-4b2e-a4f1-809f97888e03\"},\"panelIndex\":\"a0ea3f82-c257-4b2e-a4f1-809f97888e03\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_a0ea3f82-c257-4b2e-a4f1-809f97888e03\"},{\"version\":\"7.16.3\",\"type\":\"visualization\",\"gridData\":{\"x\":0,\"y\":66,\"w\":11,\"h\":11,\"i\":\"10c64699-efae-4d73-82d5-f33bf4cd47b7\"},\"panelIndex\":\"10c64699-efae-4d73-82d5-f33bf4cd47b7\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_10c64699-efae-4d73-82d5-f33bf4cd47b7\"},{\"version\":\"7.16.3\",\"type\":\"visualization\",\"gridData\":{\"x\":11,\"y\":66,\"w\":9,\"h\":11,\"i\":\"72c81b9b-94d6-4801-bd52-6cbb2541a03c\"},\"panelIndex\":\"72c81b9b-94d6-4801-bd52-6cbb2541a03c\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_72c81b9b-94d6-4801-bd52-6cbb2541a03c\"},{\"version\":\"7.16.3\",\"type\":\"visualization\",\"gridData\":{\"x\":20,\"y\":66,\"w\":28,\"h\":11,\"i\":\"5bccec0e-99c5-4db9-a1ab-088508783b6f\"},\"panelIndex\":\"5bccec0e-99c5-4db9-a1ab-088508783b6f\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_5bccec0e-99c5-4db9-a1ab-088508783b6f\"},{\"version\":\"7.16.3\",\"type\":\"visualization\",\"gridData\":{\"x\":0,\"y\":77,\"w\":24,\"h\":15,\"i\":\"485b6446-94f5-42b8-acf1-7921b3f4778c\"},\"panelIndex\":\"485b6446-94f5-42b8-acf1-7921b3f4778c\",\"embeddableConfig\":{\"savedVis\":{\"id\":\"\",\"title\":\"Workers Count\",\"description\":\"\",\"type\":\"metrics\",\"params\":{\"time_range_mode\":\"entire_time_range\",\"id\":\"8afb4e82-192a-4e5d-860b-a02e3016e627\",\"type\":\"timeseries\",\"series\":[{\"time_range_mode\":\"entire_time_range\",\"id\":\"ebcf5956-a81d-4b2f-a95c-26e1f808e197\",\"color\":\"#68BC00\",\"split_mode\":\"terms\",\"palette\":{\"type\":\"palette\",\"name\":\"default\"},\"metrics\":[{\"id\":\"4d97c5e0-dce0-11ec-934b-6bea416e1299\",\"type\":\"count\"}],\"separate_axis\":0,\"axis_position\":\"right\",\"formatter\":\"default\",\"chart_type\":\"line\",\"line_width\":1,\"point_size\":1,\"fill\":0.5,\"stacked\":\"none\",\"terms_field\":\"value.elementId\",\"terms_include\":\"\",\"label\":\"\"},{\"id\":\"53ecb6d0-dce0-11ec-934b-6bea416e1299\",\"color\":\"rgba(211,96,134,1)\",\"split_mode\":\"terms\",\"palette\":{\"type\":\"palette\",\"name\":\"default\"},\"metrics\":[{\"id\":\"53ecb6d1-dce0-11ec-934b-6bea416e1299\",\"type\":\"count\"}],\"separate_axis\":0,\"axis_position\":\"right\",\"formatter\":\"default\",\"chart_type\":\"line\",\"line_width\":1,\"point_size\":1,\"fill\":0.5,\"stacked\":\"none\",\"terms_field\":\"intent\"}],\"time_field\":\"\",\"index_pattern\":\"\",\"use_kibana_indexes\":true,\"interval\":\"\",\"axis_position\":\"left\",\"axis_formatter\":\"number\",\"axis_scale\":\"normal\",\"show_legend\":1,\"truncate_legend\":1,\"max_lines_legend\":1,\"show_grid\":1,\"tooltip_mode\":\"show_all\",\"drop_last_bucket\":0,\"isModelInvalid\":false,\"filter\":{\"query\":\"value.elementId : \\\"get-transaction-status\\\" \",\"language\":\"kuery\"}},\"uiState\":{},\"data\":{\"aggs\":[],\"searchSource\":{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[]}}},\"enhancements\":{}}}]","timeRestore":false,"title":"Aggregations","version":1},"coreMigrationVersion":"7.16.3","id":"76cd0810-9bbf-11ec-92c9-877156a2a4e9","migrationVersion":{"dashboard":"7.16.0"},"references":[{"id":"b66a64c0-e31f-11ec-9dd9-bb3704b858df","name":"2b803a94-c62b-4e30-adef-99cdcb2f6f4c:panel_2b803a94-c62b-4e30-adef-99cdcb2f6f4c","type":"visualization"},{"id":"e1111200-8cf2-11ed-9074-afdd87226beb","name":"f9f79e20-71e4-4969-86cb-7d9626c0a266:panel_f9f79e20-71e4-4969-86cb-7d9626c0a266","type":"visualization"},{"id":"1af053f0-1971-11ed-9d91-37684d8f5c4b","name":"507e2205-659d-4a81-9d77-b6367e5336e9:panel_507e2205-659d-4a81-9d77-b6367e5336e9","type":"visualization"},{"id":"381ab8c0-a51e-11ec-92c9-877156a2a4e9","name":"331c2464-ba2e-406d-a6fc-c99aed588227:panel_331c2464-ba2e-406d-a6fc-c99aed588227","type":"visualization"},{"id":"ef6d42d0-9a02-11ec-92c9-877156a2a4e9","name":"22be9f77-2f41-440c-9e82-92fa979d48a0:panel_22be9f77-2f41-440c-9e82-92fa979d48a0","type":"visualization"},{"id":"6432c370-9bbf-11ec-92c9-877156a2a4e9","name":"23de9b9f-a3ae-4fd8-93eb-473ebe74bc0a:panel_23de9b9f-a3ae-4fd8-93eb-473ebe74bc0a","type":"visualization"},{"id":"7d954ce0-9bc2-11ec-92c9-877156a2a4e9","name":"a0ea3f82-c257-4b2e-a4f1-809f97888e03:panel_a0ea3f82-c257-4b2e-a4f1-809f97888e03","type":"visualization"},{"id":"73343f00-9bc1-11ec-92c9-877156a2a4e9","name":"10c64699-efae-4d73-82d5-f33bf4cd47b7:panel_10c64699-efae-4d73-82d5-f33bf4cd47b7","type":"visualization"},{"id":"f65006c0-9a00-11ec-92c9-877156a2a4e9","name":"72c81b9b-94d6-4801-bd52-6cbb2541a03c:panel_72c81b9b-94d6-4801-bd52-6cbb2541a03c","type":"visualization"},{"id":"9de94130-9a0b-11ec-92c9-877156a2a4e9","name":"5bccec0e-99c5-4db9-a1ab-088508783b6f:panel_5bccec0e-99c5-4db9-a1ab-088508783b6f","type":"visualization"}],"type":"dashboard","updated_at":"2024-01-18T14:02:22.488Z","version":"WzM1MSw0XQ=="} +{"excludedObjects":[],"excludedObjectsCount":0,"exportedCount":12,"missingRefCount":0,"missingReferences":[]} \ No newline at end of file diff --git a/ph-ee-env-template/Kibana Visualisations/dashboard/Debugging.ndjson b/ph-ee-env-template/Kibana Visualisations/dashboard/Debugging.ndjson new file mode 100644 index 000000000..afc7029d5 --- /dev/null +++ b/ph-ee-env-template/Kibana Visualisations/dashboard/Debugging.ndjson @@ -0,0 +1,2 @@ +{"attributes":{"description":"","hits":0,"kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[]}"},"optionsJSON":"{\"hidePanelTitles\":false,\"useMargins\":true}","panelsJSON":"[{\"version\":\"7.16.3\",\"type\":\"visualization\",\"gridData\":{\"x\":0,\"y\":0,\"w\":18,\"h\":7,\"i\":\"6fc4224e-00ad-4a0b-bc30-cdd7c8c26e68\"},\"panelIndex\":\"6fc4224e-00ad-4a0b-bc30-cdd7c8c26e68\",\"embeddableConfig\":{\"savedVis\":{\"title\":\"ProcessDefControl\",\"description\":\"\",\"type\":\"input_control_vis\",\"params\":{\"controls\":[{\"id\":\"1633536719626\",\"fieldName\":\"value.bpmnProcessId\",\"parent\":\"\",\"label\":\"ProcessDef\",\"type\":\"list\",\"options\":{\"type\":\"terms\",\"multiselect\":true,\"dynamicOptions\":true,\"size\":5,\"order\":\"desc\"},\"indexPatternRefName\":\"control_6fc4224e-00ad-4a0b-bc30-cdd7c8c26e68_0_index_pattern\"}],\"updateFiltersOnChange\":false,\"useTimeFilter\":false,\"pinFilters\":false},\"uiState\":{},\"data\":{\"aggs\":[],\"searchSource\":{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[]}}},\"enhancements\":{}}},{\"version\":\"7.16.3\",\"type\":\"visualization\",\"gridData\":{\"x\":18,\"y\":0,\"w\":29,\"h\":7,\"i\":\"2adee62e-ff39-4b27-899d-6acc933194f7\"},\"panelIndex\":\"2adee62e-ff39-4b27-899d-6acc933194f7\",\"embeddableConfig\":{\"vis\":{\"params\":{\"colWidth\":[{\"colIndex\":0,\"width\":364}]}},\"enhancements\":{}},\"panelRefName\":\"panel_2adee62e-ff39-4b27-899d-6acc933194f7\"},{\"version\":\"7.16.3\",\"type\":\"visualization\",\"gridData\":{\"x\":0,\"y\":7,\"w\":23,\"h\":12,\"i\":\"17035d4c-4ab4-4311-b7e9-6d60b8f532c3\"},\"panelIndex\":\"17035d4c-4ab4-4311-b7e9-6d60b8f532c3\",\"embeddableConfig\":{\"savedVis\":{\"title\":\"ProcessInstanceKeys\",\"description\":\"\",\"type\":\"table\",\"params\":{\"perPage\":10,\"showPartialRows\":false,\"showMetricsAtAllLevels\":false,\"showTotal\":false,\"showToolbar\":false,\"totalFunc\":\"sum\",\"percentageCol\":\"\"},\"uiState\":{},\"data\":{\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"count\",\"params\":{},\"schema\":\"metric\"},{\"id\":\"2\",\"enabled\":true,\"type\":\"terms\",\"params\":{\"field\":\"value.bpmnProcessId\",\"orderBy\":\"1\",\"order\":\"desc\",\"size\":1005,\"otherBucket\":false,\"otherBucketLabel\":\"Other\",\"missingBucket\":false,\"missingBucketLabel\":\"Missing\",\"customLabel\":\"ProcessDef\"},\"schema\":\"bucket\"},{\"id\":\"3\",\"enabled\":true,\"type\":\"terms\",\"params\":{\"field\":\"value.processInstanceKey\",\"orderBy\":\"1\",\"order\":\"desc\",\"size\":5,\"otherBucket\":true,\"otherBucketLabel\":\"Other\",\"missingBucket\":false,\"missingBucketLabel\":\"Missing\",\"customLabel\":\"ProcessInstanceKey\"},\"schema\":\"bucket\"}],\"searchSource\":{\"index\":\"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b\",\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[]}}},\"enhancements\":{}},\"panelRefName\":\"panel_17035d4c-4ab4-4311-b7e9-6d60b8f532c3\"},{\"version\":\"7.16.3\",\"type\":\"visualization\",\"gridData\":{\"x\":23,\"y\":7,\"w\":24,\"h\":12,\"i\":\"1a06ddb5-0b36-40e8-96be-7640d6d954b3\"},\"panelIndex\":\"1a06ddb5-0b36-40e8-96be-7640d6d954b3\",\"embeddableConfig\":{\"savedVis\":{\"title\":\"Process Variables\",\"description\":\"\",\"type\":\"table\",\"params\":{\"perPage\":20,\"showPartialRows\":false,\"showMetricsAtAllLevels\":false,\"showTotal\":false,\"showToolbar\":false,\"totalFunc\":\"sum\",\"percentageCol\":\"\"},\"uiState\":{},\"data\":{\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"count\",\"params\":{},\"schema\":\"metric\"},{\"id\":\"2\",\"enabled\":true,\"type\":\"terms\",\"params\":{\"field\":\"value.name\",\"orderBy\":\"1\",\"order\":\"desc\",\"size\":100,\"otherBucket\":false,\"otherBucketLabel\":\"Other\",\"missingBucket\":false,\"missingBucketLabel\":\"Missing\",\"customLabel\":\"variableName\"},\"schema\":\"bucket\"},{\"id\":\"3\",\"enabled\":true,\"type\":\"terms\",\"params\":{\"field\":\"value.value\",\"orderBy\":\"1\",\"order\":\"desc\",\"size\":100,\"otherBucket\":false,\"otherBucketLabel\":\"Other\",\"missingBucket\":false,\"missingBucketLabel\":\"Missing\",\"customLabel\":\"variableValue\"},\"schema\":\"bucket\"}],\"searchSource\":{\"index\":\"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b\",\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[]}}},\"vis\":{\"params\":{\"colWidth\":[{\"colIndex\":1,\"width\":1046.3333333333333},{\"colIndex\":0,\"width\":182}]}},\"table\":null,\"enhancements\":{}},\"panelRefName\":\"panel_1a06ddb5-0b36-40e8-96be-7640d6d954b3\"},{\"version\":\"7.16.3\",\"type\":\"visualization\",\"gridData\":{\"x\":0,\"y\":19,\"w\":19,\"h\":7,\"i\":\"162e25cc-3f99-48cd-ac26-c16f4c18bf6f\"},\"panelIndex\":\"162e25cc-3f99-48cd-ac26-c16f4c18bf6f\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_162e25cc-3f99-48cd-ac26-c16f4c18bf6f\"},{\"version\":\"7.16.3\",\"type\":\"visualization\",\"gridData\":{\"x\":19,\"y\":19,\"w\":28,\"h\":15,\"i\":\"38bca8ec-0692-433d-996b-1366b50ce5b2\"},\"panelIndex\":\"38bca8ec-0692-433d-996b-1366b50ce5b2\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_38bca8ec-0692-433d-996b-1366b50ce5b2\"}]","refreshInterval":{"pause":true,"value":0},"timeFrom":"now/d","timeRestore":true,"timeTo":"now/d","title":"Debugging","version":1},"coreMigrationVersion":"7.16.3","id":"3078ba80-9bbf-11ec-92c9-877156a2a4e9","migrationVersion":{"dashboard":"7.16.0"},"references":[{"id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","name":"6fc4224e-00ad-4a0b-bc30-cdd7c8c26e68:control_6fc4224e-00ad-4a0b-bc30-cdd7c8c26e68_0_index_pattern","type":"index-pattern"},{"id":"f21cb760-26bf-11ec-95b3-cb627b5ccd4b","name":"2adee62e-ff39-4b27-899d-6acc933194f7:panel_2adee62e-ff39-4b27-899d-6acc933194f7","type":"visualization"},{"id":"df1144f0-26c0-11ec-95b3-cb627b5ccd4b","name":"17035d4c-4ab4-4311-b7e9-6d60b8f532c3:panel_17035d4c-4ab4-4311-b7e9-6d60b8f532c3","type":"visualization"},{"id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","name":"17035d4c-4ab4-4311-b7e9-6d60b8f532c3:kibanaSavedObjectMeta.searchSourceJSON.index","type":"index-pattern"},{"id":"8cf5f410-26c3-11ec-95b3-cb627b5ccd4b","name":"1a06ddb5-0b36-40e8-96be-7640d6d954b3:panel_1a06ddb5-0b36-40e8-96be-7640d6d954b3","type":"visualization"},{"id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","name":"1a06ddb5-0b36-40e8-96be-7640d6d954b3:kibanaSavedObjectMeta.searchSourceJSON.index","type":"index-pattern"},{"id":"2b5132f0-26c4-11ec-95b3-cb627b5ccd4b","name":"162e25cc-3f99-48cd-ac26-c16f4c18bf6f:panel_162e25cc-3f99-48cd-ac26-c16f4c18bf6f","type":"visualization"},{"id":"cc282ac0-26c5-11ec-95b3-cb627b5ccd4b","name":"38bca8ec-0692-433d-996b-1366b50ce5b2:panel_38bca8ec-0692-433d-996b-1366b50ce5b2","type":"visualization"}],"type":"dashboard","updated_at":"2023-03-22T10:45:06.683Z","version":"WzY1LDFd"} +{"excludedObjects":[],"excludedObjectsCount":0,"exportedCount":1,"missingRefCount":0,"missingReferences":[]} \ No newline at end of file diff --git a/ph-ee-env-template/Kibana Visualisations/dashboard/Granular.ndjson b/ph-ee-env-template/Kibana Visualisations/dashboard/Granular.ndjson new file mode 100644 index 000000000..9a1b38cd4 --- /dev/null +++ b/ph-ee-env-template/Kibana Visualisations/dashboard/Granular.ndjson @@ -0,0 +1,2 @@ +{"attributes":{"description":"","hits":0,"kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[]}"},"optionsJSON":"{\"hidePanelTitles\":false,\"useMargins\":false}","panelsJSON":"[{\"version\":\"7.16.3\",\"type\":\"visualization\",\"gridData\":{\"x\":0,\"y\":0,\"w\":48,\"h\":8,\"i\":\"92e48ecd-0f54-43a2-82ff-1eb4ee360047\"},\"panelIndex\":\"92e48ecd-0f54-43a2-82ff-1eb4ee360047\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_92e48ecd-0f54-43a2-82ff-1eb4ee360047\"},{\"version\":\"7.16.3\",\"type\":\"search\",\"gridData\":{\"x\":0,\"y\":8,\"w\":24,\"h\":15,\"i\":\"2d515280-ed7d-492a-a4cf-0d940df659bb\"},\"panelIndex\":\"2d515280-ed7d-492a-a4cf-0d940df659bb\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_2d515280-ed7d-492a-a4cf-0d940df659bb\"},{\"version\":\"7.16.3\",\"type\":\"search\",\"gridData\":{\"x\":24,\"y\":8,\"w\":24,\"h\":15,\"i\":\"53b8c9e0-6447-4bc1-98ee-83b26a06b17c\"},\"panelIndex\":\"53b8c9e0-6447-4bc1-98ee-83b26a06b17c\",\"embeddableConfig\":{\"enhancements\":{},\"hidePanelTitles\":false},\"title\":\"Txn Failed (Running & Completed)\",\"panelRefName\":\"panel_53b8c9e0-6447-4bc1-98ee-83b26a06b17c\"},{\"version\":\"7.16.3\",\"type\":\"search\",\"gridData\":{\"x\":0,\"y\":23,\"w\":16,\"h\":18,\"i\":\"a0c04596-a885-4261-9c34-9d296637e0a6\"},\"panelIndex\":\"a0c04596-a885-4261-9c34-9d296637e0a6\",\"embeddableConfig\":{\"enhancements\":{},\"hidePanelTitles\":false},\"title\":\"Completed Workflows \",\"panelRefName\":\"panel_a0c04596-a885-4261-9c34-9d296637e0a6\"},{\"version\":\"7.16.3\",\"type\":\"search\",\"gridData\":{\"x\":16,\"y\":23,\"w\":16,\"h\":18,\"i\":\"0467e687-b5b8-4ec9-957b-bd1ca1ebf4f6\"},\"panelIndex\":\"0467e687-b5b8-4ec9-957b-bd1ca1ebf4f6\",\"embeddableConfig\":{\"enhancements\":{},\"hidePanelTitles\":false},\"title\":\"Txn Success (Without Notifications Path)\",\"panelRefName\":\"panel_0467e687-b5b8-4ec9-957b-bd1ca1ebf4f6\"},{\"version\":\"7.16.3\",\"type\":\"search\",\"gridData\":{\"x\":32,\"y\":23,\"w\":16,\"h\":18,\"i\":\"7e5883bc-700e-4ec0-baaf-e555bfd94974\"},\"panelIndex\":\"7e5883bc-700e-4ec0-baaf-e555bfd94974\",\"embeddableConfig\":{\"enhancements\":{},\"hidePanelTitles\":false},\"title\":\"Completed Workflow (With Successful Notification)\",\"panelRefName\":\"panel_7e5883bc-700e-4ec0-baaf-e555bfd94974\"},{\"version\":\"7.16.3\",\"type\":\"search\",\"gridData\":{\"x\":0,\"y\":41,\"w\":48,\"h\":18,\"i\":\"33ff30ee-1ec0-40f1-9ac2-025054125fff\"},\"panelIndex\":\"33ff30ee-1ec0-40f1-9ac2-025054125fff\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_33ff30ee-1ec0-40f1-9ac2-025054125fff\"},{\"version\":\"7.16.3\",\"type\":\"search\",\"gridData\":{\"x\":0,\"y\":59,\"w\":16,\"h\":18,\"i\":\"8b9bb5e4-d047-493b-a67f-7aea92cddb5a\"},\"panelIndex\":\"8b9bb5e4-d047-493b-a67f-7aea92cddb5a\",\"embeddableConfig\":{\"enhancements\":{},\"hidePanelTitles\":false},\"title\":\"Completed Workflow (With Failed Notifications)\",\"panelRefName\":\"panel_8b9bb5e4-d047-493b-a67f-7aea92cddb5a\"},{\"version\":\"7.16.3\",\"type\":\"search\",\"gridData\":{\"x\":16,\"y\":59,\"w\":16,\"h\":8,\"i\":\"6bc89e01-536c-41e4-81da-bc2e70738541\"},\"panelIndex\":\"6bc89e01-536c-41e4-81da-bc2e70738541\",\"embeddableConfig\":{\"enhancements\":{},\"hidePanelTitles\":false},\"title\":\"Settlement Failed (Running & Completed) \",\"panelRefName\":\"panel_6bc89e01-536c-41e4-81da-bc2e70738541\"},{\"version\":\"7.16.3\",\"type\":\"search\",\"gridData\":{\"x\":32,\"y\":59,\"w\":16,\"h\":18,\"i\":\"201dafbd-76c3-4353-a570-6746055a0c6b\"},\"panelIndex\":\"201dafbd-76c3-4353-a570-6746055a0c6b\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_201dafbd-76c3-4353-a570-6746055a0c6b\"},{\"version\":\"7.16.3\",\"type\":\"search\",\"gridData\":{\"x\":16,\"y\":67,\"w\":16,\"h\":10,\"i\":\"b077668f-c214-478f-a7bc-4c34b95a627c\"},\"panelIndex\":\"b077668f-c214-478f-a7bc-4c34b95a627c\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_b077668f-c214-478f-a7bc-4c34b95a627c\"},{\"version\":\"7.16.3\",\"type\":\"search\",\"gridData\":{\"x\":0,\"y\":77,\"w\":16,\"h\":18,\"i\":\"900545fc-a82a-4732-8110-b944f134cdb9\"},\"panelIndex\":\"900545fc-a82a-4732-8110-b944f134cdb9\",\"embeddableConfig\":{\"enhancements\":{},\"hidePanelTitles\":false},\"panelRefName\":\"panel_900545fc-a82a-4732-8110-b944f134cdb9\"},{\"version\":\"7.16.3\",\"type\":\"lens\",\"gridData\":{\"x\":16,\"y\":77,\"w\":32,\"h\":8,\"i\":\"fade4208-a8a0-4b4a-a9fb-af8adbcdb30f\"},\"panelIndex\":\"fade4208-a8a0-4b4a-a9fb-af8adbcdb30f\",\"embeddableConfig\":{\"hidePanelTitles\":false,\"enhancements\":{}},\"title\":\"Cancelled Txn Last State\",\"panelRefName\":\"panel_fade4208-a8a0-4b4a-a9fb-af8adbcdb30f\"},{\"version\":\"7.16.3\",\"type\":\"search\",\"gridData\":{\"x\":16,\"y\":85,\"w\":14,\"h\":10,\"i\":\"7d4e3a8c-41d6-4fcd-b0e7-704a38648cc6\"},\"panelIndex\":\"7d4e3a8c-41d6-4fcd-b0e7-704a38648cc6\",\"embeddableConfig\":{\"enhancements\":{},\"hidePanelTitles\":false},\"panelRefName\":\"panel_7d4e3a8c-41d6-4fcd-b0e7-704a38648cc6\"},{\"version\":\"7.16.3\",\"type\":\"search\",\"gridData\":{\"x\":30,\"y\":85,\"w\":18,\"h\":10,\"i\":\"f3dbc876-8672-417d-a01b-45a2d372b5b8\"},\"panelIndex\":\"f3dbc876-8672-417d-a01b-45a2d372b5b8\",\"embeddableConfig\":{\"enhancements\":{},\"hidePanelTitles\":false},\"panelRefName\":\"panel_f3dbc876-8672-417d-a01b-45a2d372b5b8\"},{\"version\":\"7.16.3\",\"type\":\"lens\",\"gridData\":{\"x\":0,\"y\":95,\"w\":48,\"h\":15,\"i\":\"71a085ce-a391-4ca3-b144-e5ce95bddb4f\"},\"panelIndex\":\"71a085ce-a391-4ca3-b144-e5ce95bddb4f\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_71a085ce-a391-4ca3-b144-e5ce95bddb4f\"}]","timeRestore":false,"title":"Granular","version":1},"coreMigrationVersion":"7.16.3","id":"e23c6370-9bbf-11ec-92c9-877156a2a4e9","migrationVersion":{"dashboard":"7.16.0"},"references":[{"id":"b66a64c0-e31f-11ec-9dd9-bb3704b858df","name":"92e48ecd-0f54-43a2-82ff-1eb4ee360047:panel_92e48ecd-0f54-43a2-82ff-1eb4ee360047","type":"visualization"},{"id":"b3a9e540-8a77-11ec-92d2-2d974edf9929","name":"2d515280-ed7d-492a-a4cf-0d940df659bb:panel_2d515280-ed7d-492a-a4cf-0d940df659bb","type":"search"},{"id":"131f9180-9a06-11ec-92c9-877156a2a4e9","name":"53b8c9e0-6447-4bc1-98ee-83b26a06b17c:panel_53b8c9e0-6447-4bc1-98ee-83b26a06b17c","type":"search"},{"id":"91988f00-947d-11ec-828b-0b37df2e6e57","name":"a0c04596-a885-4261-9c34-9d296637e0a6:panel_a0c04596-a885-4261-9c34-9d296637e0a6","type":"search"},{"id":"09cfcc70-8a76-11ec-92d2-2d974edf9929","name":"0467e687-b5b8-4ec9-957b-bd1ca1ebf4f6:panel_0467e687-b5b8-4ec9-957b-bd1ca1ebf4f6","type":"search"},{"id":"a7c1d480-9482-11ec-828b-0b37df2e6e57","name":"7e5883bc-700e-4ec0-baaf-e555bfd94974:panel_7e5883bc-700e-4ec0-baaf-e555bfd94974","type":"search"},{"id":"9814c8c0-8a92-11ec-92d2-2d974edf9929","name":"33ff30ee-1ec0-40f1-9ac2-025054125fff:panel_33ff30ee-1ec0-40f1-9ac2-025054125fff","type":"search"},{"id":"c20707b0-9483-11ec-828b-0b37df2e6e57","name":"8b9bb5e4-d047-493b-a67f-7aea92cddb5a:panel_8b9bb5e4-d047-493b-a67f-7aea92cddb5a","type":"search"},{"id":"10c3c730-9a06-11ec-92c9-877156a2a4e9","name":"6bc89e01-536c-41e4-81da-bc2e70738541:panel_6bc89e01-536c-41e4-81da-bc2e70738541","type":"search"},{"id":"8d413da0-9be2-11ec-92c9-877156a2a4e9","name":"201dafbd-76c3-4353-a570-6746055a0c6b:panel_201dafbd-76c3-4353-a570-6746055a0c6b","type":"search"},{"id":"9a1bc5d0-9a08-11ec-92c9-877156a2a4e9","name":"b077668f-c214-478f-a7bc-4c34b95a627c:panel_b077668f-c214-478f-a7bc-4c34b95a627c","type":"search"},{"id":"19fd2fe0-9a05-11ec-92c9-877156a2a4e9","name":"900545fc-a82a-4732-8110-b944f134cdb9:panel_900545fc-a82a-4732-8110-b944f134cdb9","type":"search"},{"id":"2ba21b00-8b3e-11ec-92d2-2d974edf9929","name":"fade4208-a8a0-4b4a-a9fb-af8adbcdb30f:panel_fade4208-a8a0-4b4a-a9fb-af8adbcdb30f","type":"lens"},{"id":"b25fe0a0-8a99-11ec-92d2-2d974edf9929","name":"7d4e3a8c-41d6-4fcd-b0e7-704a38648cc6:panel_7d4e3a8c-41d6-4fcd-b0e7-704a38648cc6","type":"search"},{"id":"ca353760-9481-11ec-828b-0b37df2e6e57","name":"f3dbc876-8672-417d-a01b-45a2d372b5b8:panel_f3dbc876-8672-417d-a01b-45a2d372b5b8","type":"search"},{"id":"1aab2b30-9407-11ec-828b-0b37df2e6e57","name":"71a085ce-a391-4ca3-b144-e5ce95bddb4f:panel_71a085ce-a391-4ca3-b144-e5ce95bddb4f","type":"lens"}],"type":"dashboard","updated_at":"2023-03-22T10:45:06.683Z","version":"WzEwMCwxXQ=="} +{"excludedObjects":[],"excludedObjectsCount":0,"exportedCount":1,"missingRefCount":0,"missingReferences":[]} \ No newline at end of file diff --git a/ph-ee-env-template/Kibana Visualisations/dashboard/Reporting .ndjson b/ph-ee-env-template/Kibana Visualisations/dashboard/Reporting .ndjson new file mode 100644 index 000000000..4fed94a6f --- /dev/null +++ b/ph-ee-env-template/Kibana Visualisations/dashboard/Reporting .ndjson @@ -0,0 +1,2 @@ +{"attributes":{"description":"","hits":0,"kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[]}"},"optionsJSON":"{\"useMargins\":true,\"syncColors\":false,\"hidePanelTitles\":false}","panelsJSON":"[{\"version\":\"7.16.3\",\"type\":\"visualization\",\"gridData\":{\"x\":0,\"y\":0,\"w\":9,\"h\":7,\"i\":\"3511906d-11c9-45ea-98c6-dd3c41b17da6\"},\"panelIndex\":\"3511906d-11c9-45ea-98c6-dd3c41b17da6\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_3511906d-11c9-45ea-98c6-dd3c41b17da6\"},{\"version\":\"7.16.3\",\"type\":\"visualization\",\"gridData\":{\"x\":9,\"y\":0,\"w\":10,\"h\":7,\"i\":\"363c0499-ca0e-4ed2-bcbd-890ee18c244b\"},\"panelIndex\":\"363c0499-ca0e-4ed2-bcbd-890ee18c244b\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_363c0499-ca0e-4ed2-bcbd-890ee18c244b\"},{\"version\":\"7.16.3\",\"type\":\"visualization\",\"gridData\":{\"x\":19,\"y\":0,\"w\":10,\"h\":7,\"i\":\"3a9dd53c-16fa-4944-af3f-65a5746f2d0e\"},\"panelIndex\":\"3a9dd53c-16fa-4944-af3f-65a5746f2d0e\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_3a9dd53c-16fa-4944-af3f-65a5746f2d0e\"},{\"version\":\"7.16.3\",\"type\":\"visualization\",\"gridData\":{\"x\":29,\"y\":0,\"w\":10,\"h\":7,\"i\":\"d88ad225-013f-4444-a9e2-59eb6c1b7cec\"},\"panelIndex\":\"d88ad225-013f-4444-a9e2-59eb6c1b7cec\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_d88ad225-013f-4444-a9e2-59eb6c1b7cec\"},{\"version\":\"7.16.3\",\"type\":\"visualization\",\"gridData\":{\"x\":39,\"y\":0,\"w\":9,\"h\":7,\"i\":\"7657f03e-06db-48cb-99d5-5e265ab14270\"},\"panelIndex\":\"7657f03e-06db-48cb-99d5-5e265ab14270\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_7657f03e-06db-48cb-99d5-5e265ab14270\"},{\"version\":\"7.16.3\",\"type\":\"visualization\",\"gridData\":{\"x\":0,\"y\":7,\"w\":48,\"h\":13,\"i\":\"fbb1cf21-3e61-443c-96c7-e6ce2ff69872\"},\"panelIndex\":\"fbb1cf21-3e61-443c-96c7-e6ce2ff69872\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_fbb1cf21-3e61-443c-96c7-e6ce2ff69872\"},{\"version\":\"7.16.3\",\"type\":\"visualization\",\"gridData\":{\"x\":0,\"y\":20,\"w\":48,\"h\":7,\"i\":\"35a3f2a6-6a05-4ae9-b10e-ca7a172f242e\"},\"panelIndex\":\"35a3f2a6-6a05-4ae9-b10e-ca7a172f242e\",\"embeddableConfig\":{\"savedVis\":{\"id\":\"\",\"title\":\"Reporting Txn Count\",\"description\":\"\",\"type\":\"metrics\",\"params\":{\"time_range_mode\":\"entire_time_range\",\"id\":\"01e68469-8704-4d41-a361-74c509b88d7b\",\"type\":\"metric\",\"series\":[{\"time_range_mode\":\"entire_time_range\",\"id\":\"90647a91-c321-4891-a57d-c3ce5d0241f0\",\"color\":\"#68BC00\",\"split_mode\":\"filters\",\"palette\":{\"type\":\"palette\",\"name\":\"default\"},\"metrics\":[{\"id\":\"136ce838-28b7-419e-b53a-057833028ac0\",\"type\":\"count\"}],\"separate_axis\":0,\"axis_position\":\"right\",\"formatter\":\"default\",\"chart_type\":\"line\",\"line_width\":1,\"point_size\":1,\"fill\":0.5,\"stacked\":\"none\",\"split_filters\":[{\"filter\":{\"query\":\"processInstanceKey : * \",\"language\":\"kuery\"},\"label\":\"Completed Txn\",\"color\":\"#68BC00\",\"id\":\"27821650-f7b9-11ec-89f0-89dda7bb322a\"},{\"filter\":{\"query\":\"transferSettlementFailed : false\",\"language\":\"kuery\"},\"label\":\"Success Txn\",\"color\":\"#68BC00\",\"id\":\"33a84940-f7b9-11ec-89f0-89dda7bb322a\"},{\"filter\":{\"query\":\"transactionFailed : true or transferCreateFailed : true or transferSettlementFailed : failed or partyLookupFailed : true\",\"language\":\"kuery\"},\"label\":\"Failure Txn\",\"color\":\"#68BC00\",\"id\":\"3c2c0110-f7b9-11ec-89f0-89dda7bb322a\"}],\"label\":\"Reporting Txn Count (Not working completely due to lack of variables)\"}],\"time_field\":\"originDate\",\"use_kibana_indexes\":true,\"interval\":\"\",\"axis_position\":\"left\",\"axis_formatter\":\"number\",\"axis_scale\":\"normal\",\"show_legend\":1,\"truncate_legend\":1,\"max_lines_legend\":1,\"show_grid\":1,\"tooltip_mode\":\"show_all\",\"drop_last_bucket\":0,\"isModelInvalid\":false,\"background_color_rules\":[{\"id\":\"06bbb210-f7b8-11ec-89f0-89dda7bb322a\"}],\"bar_color_rules\":[{\"id\":\"9931bea0-f7b8-11ec-89f0-89dda7bb322a\"}],\"index_pattern_ref_name\":\"metrics_35a3f2a6-6a05-4ae9-b10e-ca7a172f242e_0_index_pattern\"},\"uiState\":{},\"data\":{\"aggs\":[],\"searchSource\":{\"query\":{\"query\":\"\",\"language\":\"lucene\"},\"filter\":[]}}},\"enhancements\":{}},\"panelRefName\":\"panel_35a3f2a6-6a05-4ae9-b10e-ca7a172f242e\"},{\"version\":\"7.16.3\",\"type\":\"search\",\"gridData\":{\"x\":0,\"y\":27,\"w\":48,\"h\":16,\"i\":\"375bc4dc-329a-4b97-9c0e-4a62ba8333e1\"},\"panelIndex\":\"375bc4dc-329a-4b97-9c0e-4a62ba8333e1\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_375bc4dc-329a-4b97-9c0e-4a62ba8333e1\"},{\"version\":\"7.16.3\",\"type\":\"visualization\",\"gridData\":{\"x\":0,\"y\":43,\"w\":48,\"h\":14,\"i\":\"9e09ea26-1977-44da-bf99-f33514753971\"},\"panelIndex\":\"9e09ea26-1977-44da-bf99-f33514753971\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_9e09ea26-1977-44da-bf99-f33514753971\"},{\"version\":\"7.16.3\",\"type\":\"visualization\",\"gridData\":{\"x\":24,\"y\":57,\"w\":24,\"h\":15,\"i\":\"aac3edda-ad5c-4466-a37d-7e7f89246319\"},\"panelIndex\":\"aac3edda-ad5c-4466-a37d-7e7f89246319\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_aac3edda-ad5c-4466-a37d-7e7f89246319\"},{\"version\":\"7.16.3\",\"type\":\"visualization\",\"gridData\":{\"x\":0,\"y\":57,\"w\":24,\"h\":15,\"i\":\"7e4daf83-940b-4eed-b744-f3a569e4c5f3\"},\"panelIndex\":\"7e4daf83-940b-4eed-b744-f3a569e4c5f3\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_7e4daf83-940b-4eed-b744-f3a569e4c5f3\"},{\"version\":\"7.16.3\",\"type\":\"visualization\",\"gridData\":{\"x\":24,\"y\":72,\"w\":24,\"h\":15,\"i\":\"6c5dd627-9f8f-4861-a06e-a9a07d05aed9\"},\"panelIndex\":\"6c5dd627-9f8f-4861-a06e-a9a07d05aed9\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_6c5dd627-9f8f-4861-a06e-a9a07d05aed9\"},{\"version\":\"7.16.3\",\"type\":\"visualization\",\"gridData\":{\"x\":0,\"y\":72,\"w\":24,\"h\":15,\"i\":\"48c2fe4b-0c24-4d11-b4e5-6f10783662d0\"},\"panelIndex\":\"48c2fe4b-0c24-4d11-b4e5-6f10783662d0\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_48c2fe4b-0c24-4d11-b4e5-6f10783662d0\"},{\"version\":\"7.16.3\",\"type\":\"lens\",\"gridData\":{\"x\":0,\"y\":87,\"w\":48,\"h\":13,\"i\":\"4207db64-8374-4bcb-8d8e-37795ef4b971\"},\"panelIndex\":\"4207db64-8374-4bcb-8d8e-37795ef4b971\",\"embeddableConfig\":{\"attributes\":{\"title\":\"Reporting Elapsed Time(Avg, Max, Min)\",\"description\":\"\",\"visualizationType\":\"lnsXY\",\"type\":\"lens\",\"references\":[{\"type\":\"index-pattern\",\"id\":\"a7328550-f2d3-11ec-9dd9-bb3704b858df\",\"name\":\"indexpattern-datasource-current-indexpattern\"},{\"type\":\"index-pattern\",\"id\":\"a7328550-f2d3-11ec-9dd9-bb3704b858df\",\"name\":\"indexpattern-datasource-layer-d608737f-dcdb-46a3-8e89-f40889db6678\"}],\"state\":{\"visualization\":{\"title\":\"Empty XY chart\",\"legend\":{\"isVisible\":true,\"position\":\"right\"},\"valueLabels\":\"hide\",\"preferredSeriesType\":\"area_stacked\",\"layers\":[{\"layerId\":\"d608737f-dcdb-46a3-8e89-f40889db6678\",\"accessors\":[\"602f1078-07a3-4c28-867d-feba61cced73\",\"c454f00f-db41-4d42-af88-da64c7042734\",\"2a3e1719-b275-4deb-914e-c31677f1d4b8\"],\"position\":\"top\",\"seriesType\":\"area_stacked\",\"showGridlines\":false,\"layerType\":\"data\",\"xAccessor\":\"70b57b03-1329-49d3-b9a3-99fc2f9352cb\"}],\"yRightExtent\":{\"mode\":\"full\"},\"yLeftExtent\":{\"mode\":\"full\"}},\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filters\":[],\"datasourceStates\":{\"indexpattern\":{\"layers\":{\"d608737f-dcdb-46a3-8e89-f40889db6678\":{\"columns\":{\"70b57b03-1329-49d3-b9a3-99fc2f9352cb\":{\"label\":\"timestamp\",\"dataType\":\"date\",\"operationType\":\"date_histogram\",\"sourceField\":\"timestamp\",\"isBucketed\":true,\"scale\":\"interval\",\"params\":{\"interval\":\"auto\"}},\"602f1078-07a3-4c28-867d-feba61cced73\":{\"label\":\"Average of elapsedTime\",\"dataType\":\"number\",\"operationType\":\"average\",\"sourceField\":\"elapsedTime\",\"isBucketed\":false,\"scale\":\"ratio\"},\"c454f00f-db41-4d42-af88-da64c7042734\":{\"label\":\"Minimum of elapsedTime\",\"dataType\":\"number\",\"operationType\":\"min\",\"sourceField\":\"elapsedTime\",\"isBucketed\":false,\"scale\":\"ratio\"},\"2a3e1719-b275-4deb-914e-c31677f1d4b8\":{\"label\":\"Maximum of elapsedTime\",\"dataType\":\"number\",\"operationType\":\"max\",\"sourceField\":\"elapsedTime\",\"isBucketed\":false,\"scale\":\"ratio\"}},\"columnOrder\":[\"70b57b03-1329-49d3-b9a3-99fc2f9352cb\",\"602f1078-07a3-4c28-867d-feba61cced73\",\"c454f00f-db41-4d42-af88-da64c7042734\",\"2a3e1719-b275-4deb-914e-c31677f1d4b8\"],\"incompleteColumns\":{}}}}}}},\"enhancements\":{}}}]","timeRestore":false,"title":"Reporting ","version":1},"coreMigrationVersion":"7.16.3","id":"090e1ca0-f7af-11ec-9dd9-bb3704b858df","migrationVersion":{"dashboard":"7.16.0"},"references":[{"id":"bcaa7200-65e0-11ed-b142-e72429dbdfa6","name":"3511906d-11c9-45ea-98c6-dd3c41b17da6:panel_3511906d-11c9-45ea-98c6-dd3c41b17da6","type":"visualization"},{"id":"4b16d2a0-65e0-11ed-b142-e72429dbdfa6","name":"363c0499-ca0e-4ed2-bcbd-890ee18c244b:panel_363c0499-ca0e-4ed2-bcbd-890ee18c244b","type":"visualization"},{"id":"0a0c7930-65e1-11ed-b142-e72429dbdfa6","name":"3a9dd53c-16fa-4944-af3f-65a5746f2d0e:panel_3a9dd53c-16fa-4944-af3f-65a5746f2d0e","type":"visualization"},{"id":"6fdb8da0-65e1-11ed-b142-e72429dbdfa6","name":"d88ad225-013f-4444-a9e2-59eb6c1b7cec:panel_d88ad225-013f-4444-a9e2-59eb6c1b7cec","type":"visualization"},{"id":"b2bde5f0-65e1-11ed-b142-e72429dbdfa6","name":"7657f03e-06db-48cb-99d5-5e265ab14270:panel_7657f03e-06db-48cb-99d5-5e265ab14270","type":"visualization"},{"id":"4008a690-65b8-11ed-b142-e72429dbdfa6","name":"fbb1cf21-3e61-443c-96c7-e6ce2ff69872:panel_fbb1cf21-3e61-443c-96c7-e6ce2ff69872","type":"visualization"},{"id":"54e2db30-65db-11ed-b142-e72429dbdfa6","name":"35a3f2a6-6a05-4ae9-b10e-ca7a172f242e:panel_35a3f2a6-6a05-4ae9-b10e-ca7a172f242e","type":"visualization"},{"id":"a7328550-f2d3-11ec-9dd9-bb3704b858df","name":"35a3f2a6-6a05-4ae9-b10e-ca7a172f242e:metrics_35a3f2a6-6a05-4ae9-b10e-ca7a172f242e_0_index_pattern","type":"index-pattern"},{"id":"67fbb360-f2d4-11ec-9dd9-bb3704b858df","name":"375bc4dc-329a-4b97-9c0e-4a62ba8333e1:panel_375bc4dc-329a-4b97-9c0e-4a62ba8333e1","type":"search"},{"id":"8e6735d0-6cc1-11ed-9b0e-43c51521f00b","name":"9e09ea26-1977-44da-bf99-f33514753971:panel_9e09ea26-1977-44da-bf99-f33514753971","type":"visualization"},{"id":"284192f0-65dc-11ed-b142-e72429dbdfa6","name":"aac3edda-ad5c-4466-a37d-7e7f89246319:panel_aac3edda-ad5c-4466-a37d-7e7f89246319","type":"visualization"},{"id":"1f3825d0-65db-11ed-b142-e72429dbdfa6","name":"7e4daf83-940b-4eed-b744-f3a569e4c5f3:panel_7e4daf83-940b-4eed-b744-f3a569e4c5f3","type":"visualization"},{"id":"ad2fb250-65df-11ed-b142-e72429dbdfa6","name":"6c5dd627-9f8f-4861-a06e-a9a07d05aed9:panel_6c5dd627-9f8f-4861-a06e-a9a07d05aed9","type":"visualization"},{"id":"4ff593c0-65df-11ed-b142-e72429dbdfa6","name":"48c2fe4b-0c24-4d11-b4e5-6f10783662d0:panel_48c2fe4b-0c24-4d11-b4e5-6f10783662d0","type":"visualization"},{"id":"a7328550-f2d3-11ec-9dd9-bb3704b858df","name":"4207db64-8374-4bcb-8d8e-37795ef4b971:indexpattern-datasource-current-indexpattern","type":"index-pattern"},{"id":"a7328550-f2d3-11ec-9dd9-bb3704b858df","name":"4207db64-8374-4bcb-8d8e-37795ef4b971:indexpattern-datasource-layer-d608737f-dcdb-46a3-8e89-f40889db6678","type":"index-pattern"}],"type":"dashboard","updated_at":"2023-03-22T10:45:06.683Z","version":"WzQ5LDFd"} +{"excludedObjects":[],"excludedObjectsCount":0,"exportedCount":1,"missingRefCount":0,"missingReferences":[]} \ No newline at end of file diff --git a/ph-ee-env-template/Kibana Visualisations/dashboard/[DevOps Only] Aggregation Long Term.ndjson b/ph-ee-env-template/Kibana Visualisations/dashboard/[DevOps Only] Aggregation Long Term.ndjson new file mode 100644 index 000000000..bbd46df7b --- /dev/null +++ b/ph-ee-env-template/Kibana Visualisations/dashboard/[DevOps Only] Aggregation Long Term.ndjson @@ -0,0 +1,2 @@ +{"attributes":{"description":"","hits":0,"kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[]}"},"optionsJSON":"{\"useMargins\":true,\"syncColors\":false,\"hidePanelTitles\":false}","panelsJSON":"[{\"version\":\"7.16.3\",\"type\":\"visualization\",\"gridData\":{\"x\":0,\"y\":0,\"w\":47,\"h\":15,\"i\":\"7aafc12c-0f68-489b-9976-0d7133b56688\"},\"panelIndex\":\"7aafc12c-0f68-489b-9976-0d7133b56688\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_7aafc12c-0f68-489b-9976-0d7133b56688\"}]","timeRestore":false,"title":"[DevOps Only] Aggregation Long Term","version":1},"coreMigrationVersion":"7.16.3","id":"8c722400-38b5-11ed-9a31-f1f0ccd9a3df","migrationVersion":{"dashboard":"7.16.0"},"references":[{"id":"4d7c9640-38b5-11ed-9a31-f1f0ccd9a3df","name":"7aafc12c-0f68-489b-9976-0d7133b56688:panel_7aafc12c-0f68-489b-9976-0d7133b56688","type":"visualization"}],"type":"dashboard","updated_at":"2023-03-22T10:45:06.683Z","version":"Wzg0LDFd"} +{"excludedObjects":[],"excludedObjectsCount":0,"exportedCount":1,"missingRefCount":0,"missingReferences":[]} \ No newline at end of file diff --git a/ph-ee-env-template/Kibana Visualisations/export-saved-objects.py b/ph-ee-env-template/Kibana Visualisations/export-saved-objects.py new file mode 100644 index 000000000..da2b63580 --- /dev/null +++ b/ph-ee-env-template/Kibana Visualisations/export-saved-objects.py @@ -0,0 +1,104 @@ +# Steps to run the script +# 1. Create virtual environment using `python -m venv ` +# 2. Activate virtual environment using `source /bin/activate` +# 3. Run `pip install requests logger python-dotenv` +# 4. Add auth Token and Kibana URL in .env file +# 5. Run `python export-saved-objects.py` +import requests +import logging +import os +import json +from dotenv import load_dotenv + +load_dotenv() + +_logger = logging.getLogger(__name__) + + +KIBANA_URL = os.environ.get("KIBANA_URL") + +VERIFY = False + +export_types = [ + "visualization", + "index-pattern", + "dashboard", + "lens", + "search", +] + +# Getting saved objects +def get_saved_objects(type): + url = KIBANA_URL + "api/saved_objects/_find" + + params = {"type": type} + headers = { + "kbn-xsrf": "true", + "Authorization": "Basic " + os.environ.get("AUTH"), + } + try: + response = requests.request( + "GET", url, headers=headers, params=params, verify=VERIFY + ) + return response + except BaseException as e: + _logger.info(e) + + +# Exporting specific id saved object +def create_saved_objects(type, object_id): + url = KIBANA_URL + "api/saved_objects/_export" + payload = json.dumps({"objects": [{"type": type, "id": str(object_id)}]}) + headers = {"kbn-xsrf": "true", "Content-Type": "application/json"} + try: + response = requests.request( + "POST", url, headers=headers, data=payload, verify=VERIFY + ) + return response + except BaseException as e: + _logger.info(e) + + +# Creating directory +def create_dir(type): + try: + os.mkdir(type) + return type + except FileExistsError as e: + _logger.info(e) + + +# Saving saved objects to the respective directory +def save_all_objects(type, object_id, title, dir_name): + response = create_saved_objects(type, object_id) + title = title.replace("/", "") + open_file = f"{dir_name}/{title}" + try: + file = open(open_file + ".ndjson", "wb") + file.write(response.content) + finally: + file.close() + + +# Driver function +def export_saved_objects(): + for type in export_types: + response = get_saved_objects(type) + if response is not None: + try: + saved_objects = response.json()["saved_objects"] + dir_name = create_dir(type) + for obj in saved_objects: + type, object_id, title = ( + obj["type"], + obj["id"], + obj["attributes"]["title"], + ) + save_all_objects(type, object_id, title, dir_name) + except BaseException as e: + _logger.info(e) + + +if __name__ == "__main__": + _logger.info("Exporting types ", export_types) + export_saved_objects() diff --git a/ph-ee-env-template/Kibana Visualisations/index-pattern/zeebe-*.ndjson b/ph-ee-env-template/Kibana Visualisations/index-pattern/zeebe-*.ndjson new file mode 100644 index 000000000..902511f80 --- /dev/null +++ b/ph-ee-env-template/Kibana Visualisations/index-pattern/zeebe-*.ndjson @@ -0,0 +1,2 @@ +{"attributes":{"fieldAttrs":"{\"value.bpmnProcessId\":{\"count\":5},\"value.elementId\":{\"count\":7},\"value.elementInstanceKey\":{\"count\":5},\"value.flowScopeKey\":{\"count\":1},\"value.parentElementInstanceKey\":{\"count\":2},\"value.parentProcessInstanceKey\":{\"count\":2},\"value.processDefinitionKey\":{\"count\":2},\"value.processDefinitionVersion\":{\"count\":1},\"value.processInstanceKey\":{\"count\":28},\"value.bpmnElementType\":{\"count\":11},\"intent\":{\"count\":3},\"value.value\":{\"count\":20},\"value.name\":{\"count\":8},\"partitionId\":{\"count\":1},\"valueType\":{\"count\":3},\"originDate\":{\"count\":1},\"_index\":{\"count\":1},\"accountId\":{\"count\":1},\"amount\":{\"count\":1},\"errorDescription\":{\"count\":5},\"key\":{\"count\":1},\"phoneNumber\":{\"count\":1},\"recordType\":{\"count\":1},\"processInstanceKey\":{\"count\":1}}","fields":"[]","runtimeFieldMap":"{}","timeFieldName":"timestamp","title":"zeebe-*","typeMeta":"{}"},"coreMigrationVersion":"7.16.3","id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","migrationVersion":{"index-pattern":"7.11.0"},"references":[],"type":"index-pattern","updated_at":"2023-03-22T10:45:06.683Z","version":"WzUwLDFd"} +{"excludedObjects":[],"excludedObjectsCount":0,"exportedCount":1,"missingRefCount":0,"missingReferences":[]} \ No newline at end of file diff --git a/ph-ee-env-template/Kibana Visualisations/index-pattern/zeebe-payments_*.ndjson b/ph-ee-env-template/Kibana Visualisations/index-pattern/zeebe-payments_*.ndjson new file mode 100644 index 000000000..493222036 --- /dev/null +++ b/ph-ee-env-template/Kibana Visualisations/index-pattern/zeebe-payments_*.ndjson @@ -0,0 +1,2 @@ +{"attributes":{"fieldAttrs":"{\"accountId\":{\"count\":4},\"mpesaTransactionId\":{\"count\":5},\"partyLookupFailed\":{\"count\":6},\"phoneNumber\":{\"count\":3},\"processInstanceKey\":{\"count\":5},\"transactionFailed\":{\"count\":7},\"transactionId\":{\"count\":4},\"transferCreateFailed\":{\"count\":5},\"transferSettlementFailed\":{\"count\":5},\"callbackRetry\":{\"count\":1},\"isMessageDelivered\":{\"count\":2},\"initiator\":{\"count\":2},\"isNotificationsFailureEnabled\":{\"count\":2},\"isNotificationsSuccessEnabled\":{\"count\":2},\"mpesaTransactionStatusRetryCount\":{\"count\":2},\"originDate\":{\"count\":5},\"scenario\":{\"count\":2},\"tenantId\":{\"count\":2},\"timer\":{\"count\":5},\"timestamp\":{\"count\":3},\"elapsedTime\":{\"count\":999},\"errorCode\":{\"count\":1},\"externalId\":{\"count\":3},\"amount\":{\"count\":2},\"errorDescription\":{\"count\":2}}","fieldFormatMap":"{\"elapsedTime\":{\"id\":\"number\",\"params\":{\"parsedUrl\":{\"origin\":\"https://ph-kibana.oneacrefund.org\",\"pathname\":\"/app/management/kibana/indexPatterns/patterns/a7328550-f2d3-11ec-9dd9-bb3704b858df/field/elapsedTime\",\"basePath\":\"\"},\"pattern\":\"0\"}}}","fields":"[{\"count\":999,\"script\":\"def origin = doc['originDate'].size();\\nif (origin != 0 ){\\n def start = doc['originDate'].value.getMillis();\\n def end = doc['timestamp'].value.getMillis();\\n def elapsed = (end - start)/1000;\\n return elapsed;\\n}\\nelse {\\n return 0;\\n}\",\"lang\":\"painless\",\"name\":\"elapsedTime\",\"type\":\"number\",\"scripted\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":false}]","runtimeFieldMap":"{}","timeFieldName":"timestamp","title":"zeebe-payments_*","typeMeta":"{}"},"coreMigrationVersion":"7.16.3","id":"a7328550-f2d3-11ec-9dd9-bb3704b858df","migrationVersion":{"index-pattern":"7.11.0"},"references":[],"type":"index-pattern","updated_at":"2023-03-22T10:45:06.683Z","version":"WzM1LDFd"} +{"excludedObjects":[],"excludedObjectsCount":0,"exportedCount":1,"missingRefCount":0,"missingReferences":[]} \ No newline at end of file diff --git a/ph-ee-env-template/Kibana Visualisations/lens/Cancelled Txns Draft.ndjson b/ph-ee-env-template/Kibana Visualisations/lens/Cancelled Txns Draft.ndjson new file mode 100644 index 000000000..5a2a9f527 --- /dev/null +++ b/ph-ee-env-template/Kibana Visualisations/lens/Cancelled Txns Draft.ndjson @@ -0,0 +1,2 @@ +{"attributes":{"description":null,"state":{"datasourceStates":{"indexpattern":{"layers":{"23f63150-df2e-4674-985c-2e1a4671e30b":{"columnOrder":["3d0da674-c79b-4d5d-9c00-2a6c53fcdd4f","35b8c0d3-3098-4e2b-8227-fa65acfef92f"],"columns":{"35b8c0d3-3098-4e2b-8227-fa65acfef92f":{"customLabel":false,"dataType":"string","filter":{"language":"kuery","query":"NOT value.bpmnElementType : \"PROCESS\" and NOT value.bpmnElementType : \"EXCLUSIVE_GATEWAY\" and NOT value.bpmnElementType : \"SEQUENCE_FLOW\" and NOT value.bpmnElementType : \"END_EVENT\" and value.elementId : * and NOT value.bpmnElementType : \"START_EVENT\" and NOT value.bpmnElementType : \"BOUNDARY_EVENT\" "},"isBucketed":false,"label":"Last value of value.elementId","operationType":"last_value","params":{"sortField":"timestamp"},"scale":"ordinal","sourceField":"value.elementId"},"3d0da674-c79b-4d5d-9c00-2a6c53fcdd4f":{"dataType":"number","isBucketed":true,"label":"Top values of value.processInstanceKey","operationType":"terms","params":{"missingBucket":false,"orderBy":{"fallback":true,"type":"alphabetical"},"orderDirection":"desc","otherBucket":true,"size":50},"scale":"ordinal","sourceField":"value.processInstanceKey"}},"incompleteColumns":{}}}}},"filters":[],"query":{"language":"kuery","query":""},"visualization":{"columns":[{"columnId":"3d0da674-c79b-4d5d-9c00-2a6c53fcdd4f","isTransposed":false},{"alignment":"center","columnId":"35b8c0d3-3098-4e2b-8227-fa65acfef92f","isTransposed":false}],"layerId":"23f63150-df2e-4674-985c-2e1a4671e30b","layerType":"data"}},"title":"Cancelled Txns Draft","visualizationType":"lnsDatatable"},"coreMigrationVersion":"7.16.3","id":"2ba21b00-8b3e-11ec-92d2-2d974edf9929","migrationVersion":{"lens":"7.16.0"},"references":[{"id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","name":"indexpattern-datasource-current-indexpattern","type":"index-pattern"},{"id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","name":"indexpattern-datasource-layer-23f63150-df2e-4674-985c-2e1a4671e30b","type":"index-pattern"}],"type":"lens","updated_at":"2023-03-22T10:45:06.683Z","version":"WzU5LDFd"} +{"excludedObjects":[],"excludedObjectsCount":0,"exportedCount":1,"missingRefCount":0,"missingReferences":[]} \ No newline at end of file diff --git a/ph-ee-env-template/Kibana Visualisations/lens/Txn Variables.ndjson b/ph-ee-env-template/Kibana Visualisations/lens/Txn Variables.ndjson new file mode 100644 index 000000000..c7d1b2e9c --- /dev/null +++ b/ph-ee-env-template/Kibana Visualisations/lens/Txn Variables.ndjson @@ -0,0 +1,2 @@ +{"attributes":{"description":"","state":{"datasourceStates":{"indexpattern":{"layers":{"f1b1bd9f-1516-428c-88cb-a8fbbcbf8814":{"columnOrder":["acbf1b5a-c412-4c4d-b4f1-748c264e0e27","f68b8c7c-7d6d-4c86-85c2-147fcd19af92","541db045-e06b-448d-beab-fb4337bda7e7"],"columns":{"541db045-e06b-448d-beab-fb4337bda7e7":{"customLabel":true,"dataType":"string","isBucketed":false,"label":" ","operationType":"last_value","params":{"sortField":"timestamp"},"scale":"ordinal","sourceField":"value.value"},"acbf1b5a-c412-4c4d-b4f1-748c264e0e27":{"customLabel":false,"dataType":"string","isBucketed":true,"label":"Top values of value.name","operationType":"terms","params":{"missingBucket":true,"orderBy":{"fallback":false,"type":"alphabetical"},"orderDirection":"asc","otherBucket":false,"size":20},"scale":"ordinal","sourceField":"value.name"},"f68b8c7c-7d6d-4c86-85c2-147fcd19af92":{"customLabel":true,"dataType":"number","isBucketed":true,"label":"Instance ID","operationType":"terms","params":{"missingBucket":false,"orderBy":{"fallback":true,"type":"alphabetical"},"orderDirection":"desc","otherBucket":false,"size":150},"scale":"ordinal","sourceField":"value.processInstanceKey"}},"incompleteColumns":{}}}}},"filters":[{"$state":{"store":"appState"},"meta":{"alias":null,"disabled":false,"indexRefName":"filter-index-pattern-0","key":"value.name","negate":true,"params":{"query":"buyGoodsRequestBody"},"type":"phrase"},"query":{"match_phrase":{"value.name":"buyGoodsRequestBody"}}},{"$state":{"store":"appState"},"meta":{"alias":null,"disabled":false,"indexRefName":"filter-index-pattern-1","key":"value.name","negate":true,"params":{"query":"callbackRetry"},"type":"phrase"},"query":{"match_phrase":{"value.name":"callbackRetry"}}},{"$state":{"store":"appState"},"meta":{"alias":null,"disabled":false,"indexRefName":"filter-index-pattern-2","key":"value.name","negate":true,"params":{"query":"channelRequest"},"type":"phrase"},"query":{"match_phrase":{"value.name":"channelRequest"}}},{"$state":{"store":"appState"},"meta":{"alias":null,"disabled":false,"indexRefName":"filter-index-pattern-3","key":"value.name","negate":true,"params":{"query":"deliveryMessage"},"type":"phrase"},"query":{"match_phrase":{"value.name":"deliveryMessage"}}},{"$state":{"store":"appState"},"meta":{"alias":null,"disabled":false,"indexRefName":"filter-index-pattern-4","key":"value.name","negate":true,"params":{"query":"errorInformation"},"type":"phrase"},"query":{"match_phrase":{"value.name":"errorInformation"}}},{"$state":{"store":"appState"},"meta":{"alias":null,"disabled":false,"indexRefName":"filter-index-pattern-5","key":"value.name","negate":true,"params":{"query":"initiator"},"type":"phrase"},"query":{"match_phrase":{"value.name":"initiator"}}},{"$state":{"store":"appState"},"meta":{"alias":null,"disabled":false,"indexRefName":"filter-index-pattern-6","key":"value.name","negate":true,"params":{"query":"initiatorType"},"type":"phrase"},"query":{"match_phrase":{"value.name":"initiatorType"}}},{"$state":{"store":"appState"},"meta":{"alias":null,"disabled":false,"indexRefName":"filter-index-pattern-7","key":"value.name","negate":true,"params":{"query":"internalId"},"type":"phrase"},"query":{"match_phrase":{"value.name":"internalId"}}},{"$state":{"store":"appState"},"meta":{"alias":null,"disabled":false,"indexRefName":"filter-index-pattern-8","key":"value.name","negate":true,"params":{"query":"isMessageDelivered"},"type":"phrase"},"query":{"match_phrase":{"value.name":"isMessageDelivered"}}},{"$state":{"store":"appState"},"meta":{"alias":null,"disabled":false,"indexRefName":"filter-index-pattern-9","key":"value.name","negate":true,"params":{"query":"mpesaChannelRequest"},"type":"phrase"},"query":{"match_phrase":{"value.name":"mpesaChannelRequest"}}},{"$state":{"store":"appState"},"meta":{"alias":null,"disabled":false,"indexRefName":"filter-index-pattern-10","key":"value.name","negate":true,"params":{"query":"mpesaTransactionId"},"type":"phrase"},"query":{"match_phrase":{"value.name":"mpesaTransactionId"}}},{"$state":{"store":"appState"},"meta":{"alias":null,"disabled":false,"indexRefName":"filter-index-pattern-11","key":"value.name","negate":true,"params":{"query":"mpesaTransactionStatusRetryCount"},"type":"phrase"},"query":{"match_phrase":{"value.name":"mpesaTransactionStatusRetryCount"}}},{"$state":{"store":"appState"},"meta":{"alias":null,"disabled":false,"indexRefName":"filter-index-pattern-12","key":"value.name","negate":true,"params":{"query":"partyLookupFailed"},"type":"phrase"},"query":{"match_phrase":{"value.name":"partyLookupFailed"}}},{"$state":{"store":"appState"},"meta":{"alias":null,"disabled":false,"indexRefName":"filter-index-pattern-13","key":"value.name","negate":true,"params":{"query":"scenario"},"type":"phrase"},"query":{"match_phrase":{"value.name":"scenario"}}},{"$state":{"store":"appState"},"meta":{"alias":null,"disabled":false,"indexRefName":"filter-index-pattern-14","key":"value.name","negate":true,"params":{"query":"tenantId"},"type":"phrase"},"query":{"match_phrase":{"value.name":"tenantId"}}},{"$state":{"store":"appState"},"meta":{"alias":null,"disabled":false,"indexRefName":"filter-index-pattern-15","key":"value.name","negate":true,"params":{"query":"timer"},"type":"phrase"},"query":{"match_phrase":{"value.name":"timer"}}},{"$state":{"store":"appState"},"meta":{"alias":null,"disabled":false,"indexRefName":"filter-index-pattern-16","key":"value.name","negate":true,"params":{"query":"transferCreateFailed"},"type":"phrase"},"query":{"match_phrase":{"value.name":"transferCreateFailed"}}},{"$state":{"store":"appState"},"meta":{"alias":null,"disabled":false,"indexRefName":"filter-index-pattern-17","key":"value.name","negate":true,"params":{"query":"transactionFailed"},"type":"phrase"},"query":{"match_phrase":{"value.name":"transactionFailed"}}},{"$state":{"store":"appState"},"meta":{"alias":null,"disabled":false,"indexRefName":"filter-index-pattern-18","key":"value.name","negate":true,"params":{"query":"transferResponse-CREATE"},"type":"phrase"},"query":{"match_phrase":{"value.name":"transferResponse-CREATE"}}},{"$state":{"store":"appState"},"meta":{"alias":null,"disabled":false,"indexRefName":"filter-index-pattern-19","key":"value.name","negate":true,"params":{"query":"transferSettlementFailed"},"type":"phrase"},"query":{"match_phrase":{"value.name":"transferSettlementFailed"}}}],"query":{"language":"kuery","query":""},"visualization":{"columns":[{"columnId":"acbf1b5a-c412-4c4d-b4f1-748c264e0e27","isTransposed":true},{"columnId":"f68b8c7c-7d6d-4c86-85c2-147fcd19af92","isTransposed":false,"width":174},{"columnId":"541db045-e06b-448d-beab-fb4337bda7e7","isTransposed":false,"width":195}],"layerId":"f1b1bd9f-1516-428c-88cb-a8fbbcbf8814","layerType":"data"}},"title":"Txn Variables","visualizationType":"lnsDatatable"},"coreMigrationVersion":"7.16.3","id":"1aab2b30-9407-11ec-828b-0b37df2e6e57","migrationVersion":{"lens":"7.16.0"},"references":[{"id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","name":"indexpattern-datasource-current-indexpattern","type":"index-pattern"},{"id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","name":"indexpattern-datasource-layer-f1b1bd9f-1516-428c-88cb-a8fbbcbf8814","type":"index-pattern"},{"id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","name":"filter-index-pattern-0","type":"index-pattern"},{"id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","name":"filter-index-pattern-1","type":"index-pattern"},{"id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","name":"filter-index-pattern-2","type":"index-pattern"},{"id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","name":"filter-index-pattern-3","type":"index-pattern"},{"id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","name":"filter-index-pattern-4","type":"index-pattern"},{"id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","name":"filter-index-pattern-5","type":"index-pattern"},{"id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","name":"filter-index-pattern-6","type":"index-pattern"},{"id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","name":"filter-index-pattern-7","type":"index-pattern"},{"id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","name":"filter-index-pattern-8","type":"index-pattern"},{"id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","name":"filter-index-pattern-9","type":"index-pattern"},{"id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","name":"filter-index-pattern-10","type":"index-pattern"},{"id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","name":"filter-index-pattern-11","type":"index-pattern"},{"id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","name":"filter-index-pattern-12","type":"index-pattern"},{"id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","name":"filter-index-pattern-13","type":"index-pattern"},{"id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","name":"filter-index-pattern-14","type":"index-pattern"},{"id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","name":"filter-index-pattern-15","type":"index-pattern"},{"id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","name":"filter-index-pattern-16","type":"index-pattern"},{"id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","name":"filter-index-pattern-17","type":"index-pattern"},{"id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","name":"filter-index-pattern-18","type":"index-pattern"},{"id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","name":"filter-index-pattern-19","type":"index-pattern"}],"type":"lens","updated_at":"2023-03-22T10:45:06.683Z","version":"WzU1LDFd"} +{"excludedObjects":[],"excludedObjectsCount":0,"exportedCount":1,"missingRefCount":0,"missingReferences":[]} \ No newline at end of file diff --git a/ph-ee-env-template/Kibana Visualisations/search/Completed Txn Failure (With Notifications).ndjson b/ph-ee-env-template/Kibana Visualisations/search/Completed Txn Failure (With Notifications).ndjson new file mode 100644 index 000000000..744e406b5 --- /dev/null +++ b/ph-ee-env-template/Kibana Visualisations/search/Completed Txn Failure (With Notifications).ndjson @@ -0,0 +1,2 @@ +{"attributes":{"columns":["value.processInstanceKey"],"description":"","grid":{},"hideChart":false,"kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[{\"meta\":{\"alias\":null,\"negate\":false,\"disabled\":false,\"type\":\"phrase\",\"key\":\"value.bpmnElementType\",\"params\":{\"query\":\"END_EVENT\"},\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index\"},\"query\":{\"match_phrase\":{\"value.bpmnElementType\":\"END_EVENT\"}},\"$state\":{\"store\":\"appState\"}},{\"meta\":{\"alias\":null,\"negate\":false,\"disabled\":false,\"type\":\"phrase\",\"key\":\"intent\",\"params\":{\"query\":\"ELEMENT_COMPLETED\"},\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.filter[1].meta.index\"},\"query\":{\"match_phrase\":{\"intent\":\"ELEMENT_COMPLETED\"}},\"$state\":{\"store\":\"appState\"}},{\"meta\":{\"alias\":null,\"negate\":false,\"disabled\":false,\"type\":\"phrase\",\"key\":\"value.elementId\",\"params\":{\"query\":\"failure\"},\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.filter[2].meta.index\"},\"query\":{\"match_phrase\":{\"value.elementId\":\"failure\"}},\"$state\":{\"store\":\"appState\"}}],\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\"}"},"sort":[["timestamp","desc"]],"title":"Completed Txn Failure (With Notifications)"},"coreMigrationVersion":"7.16.3","id":"c20707b0-9483-11ec-828b-0b37df2e6e57","migrationVersion":{"search":"7.9.3"},"references":[{"id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","name":"kibanaSavedObjectMeta.searchSourceJSON.index","type":"index-pattern"},{"id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","name":"kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index","type":"index-pattern"},{"id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","name":"kibanaSavedObjectMeta.searchSourceJSON.filter[1].meta.index","type":"index-pattern"},{"id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","name":"kibanaSavedObjectMeta.searchSourceJSON.filter[2].meta.index","type":"index-pattern"}],"type":"search","updated_at":"2023-03-22T10:45:06.683Z","version":"Wzk2LDFd"} +{"excludedObjects":[],"excludedObjectsCount":0,"exportedCount":1,"missingRefCount":0,"missingReferences":[]} \ No newline at end of file diff --git a/ph-ee-env-template/Kibana Visualisations/search/Completed Txn Failure (Without Notifications).ndjson b/ph-ee-env-template/Kibana Visualisations/search/Completed Txn Failure (Without Notifications).ndjson new file mode 100644 index 000000000..0d2c3bb53 --- /dev/null +++ b/ph-ee-env-template/Kibana Visualisations/search/Completed Txn Failure (Without Notifications).ndjson @@ -0,0 +1,2 @@ +{"attributes":{"columns":["value.processInstanceKey"],"description":"","grid":{},"hideChart":false,"kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[{\"meta\":{\"alias\":null,\"negate\":false,\"disabled\":false,\"type\":\"phrase\",\"key\":\"value.bpmnElementType\",\"params\":{\"query\":\"END_EVENT\"},\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index\"},\"query\":{\"match_phrase\":{\"value.bpmnElementType\":\"END_EVENT\"}},\"$state\":{\"store\":\"appState\"}},{\"meta\":{\"alias\":null,\"negate\":false,\"disabled\":false,\"type\":\"phrase\",\"key\":\"intent\",\"params\":{\"query\":\"ELEMENT_COMPLETED\"},\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.filter[1].meta.index\"},\"query\":{\"match_phrase\":{\"intent\":\"ELEMENT_COMPLETED\"}},\"$state\":{\"store\":\"appState\"}},{\"meta\":{\"alias\":null,\"negate\":false,\"disabled\":false,\"type\":\"phrase\",\"key\":\"value.elementId\",\"params\":{\"query\":\"End\"},\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.filter[2].meta.index\"},\"query\":{\"match_phrase\":{\"value.elementId\":\"End\"}},\"$state\":{\"store\":\"appState\"}}],\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\"}"},"sort":[["timestamp","desc"]],"title":"Completed Txn Failure (Without Notifications)"},"coreMigrationVersion":"7.16.3","id":"ca353760-9481-11ec-828b-0b37df2e6e57","migrationVersion":{"search":"7.9.3"},"references":[{"id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","name":"kibanaSavedObjectMeta.searchSourceJSON.index","type":"index-pattern"},{"id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","name":"kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index","type":"index-pattern"},{"id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","name":"kibanaSavedObjectMeta.searchSourceJSON.filter[1].meta.index","type":"index-pattern"},{"id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","name":"kibanaSavedObjectMeta.searchSourceJSON.filter[2].meta.index","type":"index-pattern"}],"type":"search","updated_at":"2023-03-22T10:45:06.683Z","version":"Wzk3LDFd"} +{"excludedObjects":[],"excludedObjectsCount":0,"exportedCount":1,"missingRefCount":0,"missingReferences":[]} \ No newline at end of file diff --git a/ph-ee-env-template/Kibana Visualisations/search/Completed Txn Success (With Notification).ndjson b/ph-ee-env-template/Kibana Visualisations/search/Completed Txn Success (With Notification).ndjson new file mode 100644 index 000000000..7448cd48f --- /dev/null +++ b/ph-ee-env-template/Kibana Visualisations/search/Completed Txn Success (With Notification).ndjson @@ -0,0 +1,2 @@ +{"attributes":{"columns":["value.processInstanceKey"],"description":"","grid":{},"hideChart":false,"kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[{\"meta\":{\"alias\":null,\"negate\":false,\"disabled\":false,\"type\":\"phrase\",\"key\":\"value.bpmnElementType\",\"params\":{\"query\":\"END_EVENT\"},\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index\"},\"query\":{\"match_phrase\":{\"value.bpmnElementType\":\"END_EVENT\"}},\"$state\":{\"store\":\"appState\"}},{\"meta\":{\"alias\":null,\"negate\":false,\"disabled\":false,\"type\":\"phrase\",\"key\":\"intent\",\"params\":{\"query\":\"ELEMENT_COMPLETED\"},\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.filter[1].meta.index\"},\"query\":{\"match_phrase\":{\"intent\":\"ELEMENT_COMPLETED\"}},\"$state\":{\"store\":\"appState\"}},{\"meta\":{\"alias\":null,\"negate\":false,\"disabled\":false,\"type\":\"phrase\",\"key\":\"value.elementId\",\"params\":{\"query\":\"sucess\"},\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.filter[2].meta.index\"},\"query\":{\"match_phrase\":{\"value.elementId\":\"sucess\"}},\"$state\":{\"store\":\"appState\"}}],\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\"}"},"sort":[["timestamp","desc"]],"title":"Completed Txn Success (With Notification)"},"coreMigrationVersion":"7.16.3","id":"a7c1d480-9482-11ec-828b-0b37df2e6e57","migrationVersion":{"search":"7.9.3"},"references":[{"id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","name":"kibanaSavedObjectMeta.searchSourceJSON.index","type":"index-pattern"},{"id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","name":"kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index","type":"index-pattern"},{"id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","name":"kibanaSavedObjectMeta.searchSourceJSON.filter[1].meta.index","type":"index-pattern"},{"id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","name":"kibanaSavedObjectMeta.searchSourceJSON.filter[2].meta.index","type":"index-pattern"}],"type":"search","updated_at":"2023-03-22T10:45:06.683Z","version":"WzkxLDFd"} +{"excludedObjects":[],"excludedObjectsCount":0,"exportedCount":1,"missingRefCount":0,"missingReferences":[]} \ No newline at end of file diff --git a/ph-ee-env-template/Kibana Visualisations/search/Completed Txn Success (Without Notification).ndjson b/ph-ee-env-template/Kibana Visualisations/search/Completed Txn Success (Without Notification).ndjson new file mode 100644 index 000000000..2ebcce150 --- /dev/null +++ b/ph-ee-env-template/Kibana Visualisations/search/Completed Txn Success (Without Notification).ndjson @@ -0,0 +1,2 @@ +{"attributes":{"columns":["value.processInstanceKey"],"description":"","grid":{},"hideChart":false,"hits":0,"kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[{\"meta\":{\"alias\":null,\"negate\":false,\"disabled\":false,\"type\":\"phrase\",\"key\":\"intent\",\"params\":{\"query\":\"ELEMENT_COMPLETED\"},\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index\"},\"query\":{\"match_phrase\":{\"intent\":\"ELEMENT_COMPLETED\"}},\"$state\":{\"store\":\"appState\"}},{\"meta\":{\"alias\":null,\"negate\":false,\"disabled\":false,\"type\":\"phrase\",\"key\":\"value.bpmnElementType\",\"params\":{\"query\":\"END_EVENT\"},\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.filter[1].meta.index\"},\"query\":{\"match_phrase\":{\"value.bpmnElementType\":\"END_EVENT\"}},\"$state\":{\"store\":\"appState\"}},{\"meta\":{\"alias\":null,\"negate\":false,\"disabled\":false,\"type\":\"phrase\",\"key\":\"value.elementId\",\"params\":{\"query\":\"Event_1bh40y1\"},\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.filter[2].meta.index\"},\"query\":{\"match_phrase\":{\"value.elementId\":\"Event_1bh40y1\"}},\"$state\":{\"store\":\"appState\"}}],\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\"}"},"sort":[["timestamp","desc"]],"title":"Completed Txn Success (Without Notification)","version":1},"coreMigrationVersion":"7.16.3","id":"09cfcc70-8a76-11ec-92d2-2d974edf9929","migrationVersion":{"search":"7.9.3"},"references":[{"id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","name":"kibanaSavedObjectMeta.searchSourceJSON.index","type":"index-pattern"},{"id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","name":"kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index","type":"index-pattern"},{"id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","name":"kibanaSavedObjectMeta.searchSourceJSON.filter[1].meta.index","type":"index-pattern"},{"id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","name":"kibanaSavedObjectMeta.searchSourceJSON.filter[2].meta.index","type":"index-pattern"}],"type":"search","updated_at":"2023-03-22T10:45:06.683Z","version":"WzUxLDFd"} +{"excludedObjects":[],"excludedObjectsCount":0,"exportedCount":1,"missingRefCount":0,"missingReferences":[]} \ No newline at end of file diff --git a/ph-ee-env-template/Kibana Visualisations/search/Completed Txns .ndjson b/ph-ee-env-template/Kibana Visualisations/search/Completed Txns .ndjson new file mode 100644 index 000000000..0c6e11144 --- /dev/null +++ b/ph-ee-env-template/Kibana Visualisations/search/Completed Txns .ndjson @@ -0,0 +1,2 @@ +{"attributes":{"columns":["value.processInstanceKey"],"description":"","grid":{},"hideChart":false,"kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[{\"meta\":{\"alias\":null,\"negate\":false,\"disabled\":false,\"type\":\"phrase\",\"key\":\"value.bpmnElementType\",\"params\":{\"query\":\"END_EVENT\"},\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index\"},\"query\":{\"match_phrase\":{\"value.bpmnElementType\":\"END_EVENT\"}},\"$state\":{\"store\":\"appState\"}},{\"meta\":{\"alias\":null,\"negate\":false,\"disabled\":false,\"type\":\"phrase\",\"key\":\"intent\",\"params\":{\"query\":\"ELEMENT_COMPLETED\"},\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.filter[1].meta.index\"},\"query\":{\"match_phrase\":{\"intent\":\"ELEMENT_COMPLETED\"}},\"$state\":{\"store\":\"appState\"}}],\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\"}"},"sort":[["timestamp","desc"]],"title":"Completed Txns "},"coreMigrationVersion":"7.16.3","id":"91988f00-947d-11ec-828b-0b37df2e6e57","migrationVersion":{"search":"7.9.3"},"references":[{"id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","name":"kibanaSavedObjectMeta.searchSourceJSON.index","type":"index-pattern"},{"id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","name":"kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index","type":"index-pattern"},{"id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","name":"kibanaSavedObjectMeta.searchSourceJSON.filter[1].meta.index","type":"index-pattern"}],"type":"search","updated_at":"2023-03-22T10:45:06.683Z","version":"Wzg2LDFd"} +{"excludedObjects":[],"excludedObjectsCount":0,"exportedCount":1,"missingRefCount":0,"missingReferences":[]} \ No newline at end of file diff --git a/ph-ee-env-template/Kibana Visualisations/search/Error Code exhaustive list.ndjson b/ph-ee-env-template/Kibana Visualisations/search/Error Code exhaustive list.ndjson new file mode 100644 index 000000000..298299a1a --- /dev/null +++ b/ph-ee-env-template/Kibana Visualisations/search/Error Code exhaustive list.ndjson @@ -0,0 +1,2 @@ +{"attributes":{"columns":["value.value"],"description":"","grid":{},"hideChart":false,"kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[{\"meta\":{\"alias\":null,\"negate\":false,\"disabled\":false,\"type\":\"phrase\",\"key\":\"value.name\",\"params\":{\"query\":\"errorCode\"},\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index\"},\"query\":{\"match_phrase\":{\"value.name\":\"errorCode\"}},\"$state\":{\"store\":\"appState\"}}],\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\"}"},"sort":[["timestamp","desc"]],"title":"Error Code exhaustive list"},"coreMigrationVersion":"7.16.3","id":"21dd3770-9278-11ed-9074-afdd87226beb","migrationVersion":{"search":"7.9.3"},"references":[{"id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","name":"kibanaSavedObjectMeta.searchSourceJSON.index","type":"index-pattern"},{"id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","name":"kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index","type":"index-pattern"}],"type":"search","updated_at":"2023-03-22T10:45:06.683Z","version":"WzU3LDFd"} +{"excludedObjects":[],"excludedObjectsCount":0,"exportedCount":1,"missingRefCount":0,"missingReferences":[]} \ No newline at end of file diff --git a/ph-ee-env-template/Kibana Visualisations/search/Incidents [All].ndjson b/ph-ee-env-template/Kibana Visualisations/search/Incidents [All].ndjson new file mode 100644 index 000000000..b354b50e5 --- /dev/null +++ b/ph-ee-env-template/Kibana Visualisations/search/Incidents [All].ndjson @@ -0,0 +1,2 @@ +{"attributes":{"columns":["value.processInstanceKey","value.errorMessage","value.elementId","value.bpmnProcessId","value.errorType"],"description":"","hits":0,"kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[{\"meta\":{\"alias\":null,\"negate\":false,\"disabled\":false,\"type\":\"exists\",\"key\":\"value.errorType\",\"value\":\"exists\",\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index\"},\"exists\":{\"field\":\"value.errorType\"},\"$state\":{\"store\":\"appState\"}}],\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\"}"},"sort":[["timestamp","desc"]],"title":"Incidents [All]","version":1},"coreMigrationVersion":"7.16.3","id":"9814c8c0-8a92-11ec-92d2-2d974edf9929","migrationVersion":{"search":"7.9.3"},"references":[{"id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","name":"kibanaSavedObjectMeta.searchSourceJSON.index","type":"index-pattern"},{"id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","name":"kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index","type":"index-pattern"}],"type":"search","updated_at":"2023-03-22T10:45:06.683Z","version":"Wzg3LDFd"} +{"excludedObjects":[],"excludedObjectsCount":0,"exportedCount":1,"missingRefCount":0,"missingReferences":[]} \ No newline at end of file diff --git a/ph-ee-env-template/Kibana Visualisations/search/IncompleteCancelled Txns.ndjson b/ph-ee-env-template/Kibana Visualisations/search/IncompleteCancelled Txns.ndjson new file mode 100644 index 000000000..90bf44465 --- /dev/null +++ b/ph-ee-env-template/Kibana Visualisations/search/IncompleteCancelled Txns.ndjson @@ -0,0 +1,2 @@ +{"attributes":{"columns":["value.processInstanceKey"],"description":"","hits":0,"kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[{\"meta\":{\"alias\":null,\"negate\":false,\"disabled\":false,\"type\":\"phrase\",\"key\":\"intent\",\"params\":{\"query\":\"ELEMENT_TERMINATED\"},\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index\"},\"query\":{\"match_phrase\":{\"intent\":\"ELEMENT_TERMINATED\"}},\"$state\":{\"store\":\"appState\"}},{\"meta\":{\"alias\":null,\"negate\":false,\"disabled\":false,\"type\":\"phrase\",\"key\":\"value.elementId\",\"params\":{\"query\":\"mpesa-flow-v3-oaf\"},\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.filter[1].meta.index\"},\"query\":{\"match_phrase\":{\"value.elementId\":\"mpesa-flow-v3-oaf\"}},\"$state\":{\"store\":\"appState\"}},{\"meta\":{\"alias\":null,\"negate\":false,\"disabled\":false,\"type\":\"phrase\",\"key\":\"value.version\",\"params\":{\"query\":3},\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.filter[2].meta.index\"},\"query\":{\"match_phrase\":{\"value.version\":3}},\"$state\":{\"store\":\"appState\"}}],\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\"}"},"sort":[["timestamp","desc"]],"title":"Incomplete/Cancelled Txns","version":1},"coreMigrationVersion":"7.16.3","id":"b25fe0a0-8a99-11ec-92d2-2d974edf9929","migrationVersion":{"search":"7.9.3"},"references":[{"id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","name":"kibanaSavedObjectMeta.searchSourceJSON.index","type":"index-pattern"},{"id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","name":"kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index","type":"index-pattern"},{"id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","name":"kibanaSavedObjectMeta.searchSourceJSON.filter[1].meta.index","type":"index-pattern"},{"id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","name":"kibanaSavedObjectMeta.searchSourceJSON.filter[2].meta.index","type":"index-pattern"}],"type":"search","updated_at":"2023-03-22T10:45:06.683Z","version":"WzkzLDFd"} +{"excludedObjects":[],"excludedObjectsCount":0,"exportedCount":1,"missingRefCount":0,"missingReferences":[]} \ No newline at end of file diff --git a/ph-ee-env-template/Kibana Visualisations/search/Party Lookup Failed (Running & Completed).ndjson b/ph-ee-env-template/Kibana Visualisations/search/Party Lookup Failed (Running & Completed).ndjson new file mode 100644 index 000000000..5f732f14b --- /dev/null +++ b/ph-ee-env-template/Kibana Visualisations/search/Party Lookup Failed (Running & Completed).ndjson @@ -0,0 +1,2 @@ +{"attributes":{"columns":["value.processInstanceKey"],"description":"","grid":{},"hideChart":false,"kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[{\"meta\":{\"alias\":null,\"negate\":false,\"disabled\":false,\"type\":\"phrase\",\"key\":\"value.name\",\"params\":{\"query\":\"partyLookupFailed\"},\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index\"},\"query\":{\"match_phrase\":{\"value.name\":\"partyLookupFailed\"}},\"$state\":{\"store\":\"appState\"}},{\"meta\":{\"alias\":null,\"negate\":false,\"disabled\":false,\"type\":\"phrase\",\"key\":\"value.value\",\"params\":{\"query\":\"true\"},\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.filter[1].meta.index\"},\"query\":{\"match_phrase\":{\"value.value\":\"true\"}},\"$state\":{\"store\":\"appState\"}}],\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\"}"},"sort":[["timestamp","desc"]],"title":"Party Lookup Failed (Running & Completed)"},"coreMigrationVersion":"7.16.3","id":"19fd2fe0-9a05-11ec-92c9-877156a2a4e9","migrationVersion":{"search":"7.9.3"},"references":[{"id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","name":"kibanaSavedObjectMeta.searchSourceJSON.index","type":"index-pattern"},{"id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","name":"kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index","type":"index-pattern"},{"id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","name":"kibanaSavedObjectMeta.searchSourceJSON.filter[1].meta.index","type":"index-pattern"}],"type":"search","updated_at":"2023-03-22T10:45:06.683Z","version":"WzU0LDFd"} +{"excludedObjects":[],"excludedObjectsCount":0,"exportedCount":1,"missingRefCount":0,"missingReferences":[]} \ No newline at end of file diff --git a/ph-ee-env-template/Kibana Visualisations/search/Reporting Variables.ndjson b/ph-ee-env-template/Kibana Visualisations/search/Reporting Variables.ndjson new file mode 100644 index 000000000..5abc9acb7 --- /dev/null +++ b/ph-ee-env-template/Kibana Visualisations/search/Reporting Variables.ndjson @@ -0,0 +1,2 @@ +{"attributes":{"columns":["originDate","accountId","amount","phoneNumber","elapsedTime","timestamp","errorDescription","externalId","processInstanceKey","transactionId","transactionFailed","transferCreateFailed","transferSettlementFailed","partyLookupFailed","mpesaTransactionId","timer","errorCode","errorInformation","getTransactionStatusHttpCode","getTransactionStatusResponse","initiator","isCallbackReceived","isNotificationsFailureEnabled","isNotificationsSuccessEnabled","mpesaReceiptNumber","mpesaTransactionStatusRetryCount","scenario","tenantId","transferResponse-CREATE"],"description":"","grid":{},"hideChart":false,"kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"language\":\"lucene\",\"query\":\"\"},\"filter\":[],\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\"}"},"sort":[["timestamp","desc"]],"title":"Reporting Variables"},"coreMigrationVersion":"7.16.3","id":"67fbb360-f2d4-11ec-9dd9-bb3704b858df","migrationVersion":{"search":"7.9.3"},"references":[{"id":"a7328550-f2d3-11ec-9dd9-bb3704b858df","name":"kibanaSavedObjectMeta.searchSourceJSON.index","type":"index-pattern"}],"type":"search","updated_at":"2023-03-22T10:45:06.683Z","version":"WzQzLDFd"} +{"excludedObjects":[],"excludedObjectsCount":0,"exportedCount":1,"missingRefCount":0,"missingReferences":[]} \ No newline at end of file diff --git a/ph-ee-env-template/Kibana Visualisations/search/Settlement Failed (Running & Completed).ndjson b/ph-ee-env-template/Kibana Visualisations/search/Settlement Failed (Running & Completed).ndjson new file mode 100644 index 000000000..5260c5d24 --- /dev/null +++ b/ph-ee-env-template/Kibana Visualisations/search/Settlement Failed (Running & Completed).ndjson @@ -0,0 +1,2 @@ +{"attributes":{"columns":["value.processInstanceKey"],"description":"","grid":{},"hideChart":false,"kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[{\"meta\":{\"alias\":null,\"negate\":false,\"disabled\":false,\"type\":\"phrase\",\"key\":\"value.name\",\"params\":{\"query\":\"transferSettlementFailed\"},\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index\"},\"query\":{\"match_phrase\":{\"value.name\":\"transferSettlementFailed\"}},\"$state\":{\"store\":\"appState\"}},{\"meta\":{\"alias\":null,\"negate\":false,\"disabled\":false,\"type\":\"phrase\",\"key\":\"value.value\",\"params\":{\"query\":\"true\"},\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.filter[1].meta.index\"},\"query\":{\"match_phrase\":{\"value.value\":\"true\"}},\"$state\":{\"store\":\"appState\"}}],\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\"}"},"sort":[["timestamp","desc"]],"title":"Settlement Failed (Running & Completed)"},"coreMigrationVersion":"7.16.3","id":"10c3c730-9a06-11ec-92c9-877156a2a4e9","migrationVersion":{"search":"7.9.3"},"references":[{"id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","name":"kibanaSavedObjectMeta.searchSourceJSON.index","type":"index-pattern"},{"id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","name":"kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index","type":"index-pattern"},{"id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","name":"kibanaSavedObjectMeta.searchSourceJSON.filter[1].meta.index","type":"index-pattern"}],"type":"search","updated_at":"2023-03-22T10:45:06.683Z","version":"WzUyLDFd"} +{"excludedObjects":[],"excludedObjectsCount":0,"exportedCount":1,"missingRefCount":0,"missingReferences":[]} \ No newline at end of file diff --git a/ph-ee-env-template/Kibana Visualisations/search/Timed Out Txns (Exhausted Retries).ndjson b/ph-ee-env-template/Kibana Visualisations/search/Timed Out Txns (Exhausted Retries).ndjson new file mode 100644 index 000000000..5f533400f --- /dev/null +++ b/ph-ee-env-template/Kibana Visualisations/search/Timed Out Txns (Exhausted Retries).ndjson @@ -0,0 +1,2 @@ +{"attributes":{"columns":["value.processInstanceKey"],"description":"","grid":{},"hideChart":false,"kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[{\"meta\":{\"alias\":null,\"negate\":false,\"disabled\":false,\"type\":\"phrase\",\"key\":\"value.name\",\"params\":{\"query\":\"mpesaTransactionStatusRetryCount\"},\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index\"},\"query\":{\"match_phrase\":{\"value.name\":\"mpesaTransactionStatusRetryCount\"}},\"$state\":{\"store\":\"appState\"}},{\"meta\":{\"alias\":null,\"negate\":false,\"disabled\":false,\"type\":\"phrase\",\"key\":\"value.value\",\"params\":{\"query\":\"4\"},\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.filter[1].meta.index\"},\"query\":{\"match_phrase\":{\"value.value\":\"4\"}},\"$state\":{\"store\":\"appState\"}}],\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\"}"},"sort":[["timestamp","desc"]],"title":"Timed Out Txns (Exhausted Retries)"},"coreMigrationVersion":"7.16.3","id":"9a1bc5d0-9a08-11ec-92c9-877156a2a4e9","migrationVersion":{"search":"7.9.3"},"references":[{"id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","name":"kibanaSavedObjectMeta.searchSourceJSON.index","type":"index-pattern"},{"id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","name":"kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index","type":"index-pattern"},{"id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","name":"kibanaSavedObjectMeta.searchSourceJSON.filter[1].meta.index","type":"index-pattern"}],"type":"search","updated_at":"2023-03-22T10:45:06.683Z","version":"Wzg4LDFd"} +{"excludedObjects":[],"excludedObjectsCount":0,"exportedCount":1,"missingRefCount":0,"missingReferences":[]} \ No newline at end of file diff --git a/ph-ee-env-template/Kibana Visualisations/search/Timeout (Insufficient Balance).ndjson b/ph-ee-env-template/Kibana Visualisations/search/Timeout (Insufficient Balance).ndjson new file mode 100644 index 000000000..eb65fdfaa --- /dev/null +++ b/ph-ee-env-template/Kibana Visualisations/search/Timeout (Insufficient Balance).ndjson @@ -0,0 +1,2 @@ +{"attributes":{"columns":["value.processInstanceKey"],"description":"","grid":{},"hideChart":false,"kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[{\"query\":{\"bool\":{\"should\":[{\"wildcard\":{\"value.value\":\"*insufficient*\"}}]}},\"meta\":{\"type\":\"custom\",\"disabled\":false,\"negate\":false,\"alias\":null,\"key\":\"query\",\"value\":\"{\\\"bool\\\":{\\\"should\\\":[{\\\"wildcard\\\":{\\\"value.value\\\":\\\"*insufficient*\\\"}}]}}\",\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index\"},\"$state\":{\"store\":\"appState\"}}],\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\"}"},"sort":[["timestamp","desc"]],"title":"Timeout (Insufficient Balance)"},"coreMigrationVersion":"7.16.3","id":"2d711570-9be3-11ec-92c9-877156a2a4e9","migrationVersion":{"search":"7.9.3"},"references":[{"id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","name":"kibanaSavedObjectMeta.searchSourceJSON.index","type":"index-pattern"},{"id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","name":"kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index","type":"index-pattern"}],"type":"search","updated_at":"2023-03-22T10:45:06.683Z","version":"WzYwLDFd"} +{"excludedObjects":[],"excludedObjectsCount":0,"exportedCount":1,"missingRefCount":0,"missingReferences":[]} \ No newline at end of file diff --git a/ph-ee-env-template/Kibana Visualisations/search/Transaction Errors.ndjson b/ph-ee-env-template/Kibana Visualisations/search/Transaction Errors.ndjson new file mode 100644 index 000000000..d5119696c --- /dev/null +++ b/ph-ee-env-template/Kibana Visualisations/search/Transaction Errors.ndjson @@ -0,0 +1,2 @@ +{"attributes":{"columns":["value.processInstanceKey","value.value"],"description":"","hits":0,"kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[{\"meta\":{\"type\":\"phrases\",\"key\":\"value.name\",\"value\":\"deliveryErrorMessage, errorInformation\",\"params\":[\"deliveryErrorMessage\",\"errorInformation\"],\"alias\":null,\"negate\":false,\"disabled\":false,\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index\"},\"query\":{\"bool\":{\"should\":[{\"match_phrase\":{\"value.name\":\"deliveryErrorMessage\"}},{\"match_phrase\":{\"value.name\":\"errorInformation\"}}],\"minimum_should_match\":1}},\"$state\":{\"store\":\"appState\"}}],\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\"}"},"sort":[["timestamp","desc"]],"title":"Transaction Errors","version":1},"coreMigrationVersion":"7.16.3","id":"b3a9e540-8a77-11ec-92d2-2d974edf9929","migrationVersion":{"search":"7.9.3"},"references":[{"id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","name":"kibanaSavedObjectMeta.searchSourceJSON.index","type":"index-pattern"},{"id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","name":"kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index","type":"index-pattern"}],"type":"search","updated_at":"2023-03-22T10:45:06.683Z","version":"Wzk0LDFd"} +{"excludedObjects":[],"excludedObjectsCount":0,"exportedCount":1,"missingRefCount":0,"missingReferences":[]} \ No newline at end of file diff --git a/ph-ee-env-template/Kibana Visualisations/search/Txn Failed (Running & Completed) .ndjson b/ph-ee-env-template/Kibana Visualisations/search/Txn Failed (Running & Completed) .ndjson new file mode 100644 index 000000000..fddaf9707 --- /dev/null +++ b/ph-ee-env-template/Kibana Visualisations/search/Txn Failed (Running & Completed) .ndjson @@ -0,0 +1,2 @@ +{"attributes":{"columns":["value.processInstanceKey"],"description":"","grid":{},"hideChart":false,"kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[{\"meta\":{\"alias\":null,\"negate\":false,\"disabled\":false,\"type\":\"phrase\",\"key\":\"value.name\",\"params\":{\"query\":\"transactionFailed\"},\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index\"},\"query\":{\"match_phrase\":{\"value.name\":\"transactionFailed\"}},\"$state\":{\"store\":\"appState\"}},{\"meta\":{\"alias\":null,\"negate\":false,\"disabled\":false,\"type\":\"phrase\",\"key\":\"value.value\",\"params\":{\"query\":\"true\"},\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.filter[1].meta.index\"},\"query\":{\"match_phrase\":{\"value.value\":\"true\"}},\"$state\":{\"store\":\"appState\"}}],\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\"}"},"sort":[["timestamp","desc"]],"title":"Txn Failed (Running & Completed) "},"coreMigrationVersion":"7.16.3","id":"131f9180-9a06-11ec-92c9-877156a2a4e9","migrationVersion":{"search":"7.9.3"},"references":[{"id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","name":"kibanaSavedObjectMeta.searchSourceJSON.index","type":"index-pattern"},{"id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","name":"kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index","type":"index-pattern"},{"id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","name":"kibanaSavedObjectMeta.searchSourceJSON.filter[1].meta.index","type":"index-pattern"}],"type":"search","updated_at":"2023-03-22T10:45:06.683Z","version":"WzUzLDFd"} +{"excludedObjects":[],"excludedObjectsCount":0,"exportedCount":1,"missingRefCount":0,"missingReferences":[]} \ No newline at end of file diff --git a/ph-ee-env-template/Kibana Visualisations/search/Txn Timeout.ndjson b/ph-ee-env-template/Kibana Visualisations/search/Txn Timeout.ndjson new file mode 100644 index 000000000..860c48b76 --- /dev/null +++ b/ph-ee-env-template/Kibana Visualisations/search/Txn Timeout.ndjson @@ -0,0 +1,2 @@ +{"attributes":{"columns":["value.processInstanceKey"],"description":"","grid":{},"hideChart":false,"kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[{\"meta\":{\"alias\":null,\"negate\":false,\"disabled\":false,\"type\":\"phrase\",\"key\":\"value.value\",\"params\":{\"query\":\"\\\"DS timeout.\\\"\"},\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index\"},\"query\":{\"match_phrase\":{\"value.value\":\"\\\"DS timeout.\\\"\"}},\"$state\":{\"store\":\"appState\"}}],\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\"}"},"sort":[["timestamp","desc"]],"title":"Txn Timeout"},"coreMigrationVersion":"7.16.3","id":"8d413da0-9be2-11ec-92c9-877156a2a4e9","migrationVersion":{"search":"7.9.3"},"references":[{"id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","name":"kibanaSavedObjectMeta.searchSourceJSON.index","type":"index-pattern"},{"id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","name":"kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index","type":"index-pattern"}],"type":"search","updated_at":"2023-03-22T10:45:06.683Z","version":"Wzg1LDFd"} +{"excludedObjects":[],"excludedObjectsCount":0,"exportedCount":1,"missingRefCount":0,"missingReferences":[]} \ No newline at end of file diff --git a/ph-ee-env-template/Kibana Visualisations/txn-decision-gateway.ndjson b/ph-ee-env-template/Kibana Visualisations/txn-decision-gateway.ndjson new file mode 100644 index 000000000..3e0275e04 --- /dev/null +++ b/ph-ee-env-template/Kibana Visualisations/txn-decision-gateway.ndjson @@ -0,0 +1,2 @@ +{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[]}"},"title":"Transaction Decision Gateways","uiStateJSON":"{}","version":1,"visState":"{\"title\":\"Transaction Decision Gateways\",\"type\":\"metrics\",\"aggs\":[],\"params\":{\"time_range_mode\":\"entire_time_range\",\"id\":\"0fbcb70d-785f-4bd5-8a01-5ccf2ba8b04f\",\"type\":\"metric\",\"series\":[{\"time_range_mode\":\"entire_time_range\",\"id\":\"e29c0f65-d09d-43f8-99a3-b7075234c1d9\",\"color\":\"#68BC00\",\"split_mode\":\"filters\",\"palette\":{\"type\":\"palette\",\"name\":\"default\"},\"metrics\":[{\"id\":\"55bc12ae-9f04-4fd9-bb99-402048ceb1b8\",\"type\":\"count\"}],\"separate_axis\":0,\"axis_position\":\"right\",\"formatter\":\"default\",\"chart_type\":\"line\",\"line_width\":1,\"point_size\":1,\"fill\":0.5,\"stacked\":\"none\",\"split_filters\":[{\"filter\":{\"query\":\"value.name: \\\"partyLookupFailed\\\" and value.value: \\\"true\\\" \",\"language\":\"kuery\"},\"label\":\"Count of Txns With Party Lookup Failed\",\"color\":\"#68BC00\",\"id\":\"61348740-9a01-11ec-8b98-a3ff4ce513d9\"},{\"filter\":{\"query\":\"value.name : \\\"transactionFailed\\\" and value.value : \\\"true\\\" \",\"language\":\"kuery\"},\"label\":\"Count of Txns With Transaction Failed\",\"color\":\"#68BC00\",\"id\":\"abf94e50-9a01-11ec-8b98-a3ff4ce513d9\"},{\"filter\":{\"query\":\" value.name : \\\"transferSettlementFailed\\\" and value.value : \\\"true\\\" \",\"language\":\"kuery\"},\"label\":\"Count of Txns With Settlement Failed\",\"color\":\"#68BC00\",\"id\":\"db417e30-9a01-11ec-8b98-a3ff4ce513d9\"},{\"filter\":{\"query\":\"value.name: \\\"partyLookupFailed\\\" and NOT value.value : \\\"true\\\" \",\"language\":\"kuery\"},\"label\":\"Count of Txns With Party Lookup Successful \",\"color\":\"#68BC00\",\"id\":\"f60f10b0-9a01-11ec-8b98-a3ff4ce513d9\"},{\"filter\":{\"query\":\"value.name : \\\"transactionFailed\\\" and value.value : \\\"false\\\" \",\"language\":\"kuery\"},\"label\":\"[Misleading] Count of Txns With Transaction Successful\",\"color\":\"#68BC00\",\"id\":\"29cc26e0-9a02-11ec-8b98-a3ff4ce513d9\"},{\"filter\":{\"query\":\"value.name : \\\"transferSettlementFailed\\\" and NOT value.value : \\\"true\\\" \",\"language\":\"kuery\"},\"label\":\"Count of Txns With Settlement Successful\",\"color\":\"#68BC00\",\"id\":\"7565ca20-9a02-11ec-8b98-a3ff4ce513d9\"},{\"filter\":{\"query\":\"value.name : \\\"confirmationReceived\\\" and value.value : \\\"true\\\"\",\"language\":\"kuery\"},\"label\":\"Count of Txns with Settlement Request Received\",\"color\":\"#68BC00\",\"id\":\"4d02f350-be55-11ed-b5d6-5b7e9bb356ac\"}],\"label\":\"\"}],\"time_field\":\"\",\"index_pattern\":\"\",\"use_kibana_indexes\":true,\"interval\":\"\",\"axis_position\":\"left\",\"axis_formatter\":\"number\",\"axis_scale\":\"normal\",\"show_legend\":1,\"truncate_legend\":1,\"max_lines_legend\":1,\"show_grid\":1,\"tooltip_mode\":\"show_all\",\"drop_last_bucket\":0,\"background_color_rules\":[{\"id\":\"5c1bbfd0-9a01-11ec-8b98-a3ff4ce513d9\"}]}}"},"coreMigrationVersion":"7.16.3","id":"ef6d42d0-9a02-11ec-92c9-877156a2a4e9","migrationVersion":{"visualization":"7.14.0"},"references":[],"sort":[1678351055117,257],"type":"visualization","updated_at":"2023-03-09T08:37:35.117Z","version":"WzM1ODMsM10="} +{"excludedObjects":[],"excludedObjectsCount":0,"exportedCount":1,"missingRefCount":0,"missingReferences":[]} \ No newline at end of file diff --git a/ph-ee-env-template/Kibana Visualisations/visualization/Count Of Cancelled Workflows.ndjson b/ph-ee-env-template/Kibana Visualisations/visualization/Count Of Cancelled Workflows.ndjson new file mode 100644 index 000000000..715c197ec --- /dev/null +++ b/ph-ee-env-template/Kibana Visualisations/visualization/Count Of Cancelled Workflows.ndjson @@ -0,0 +1,2 @@ +{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[]}"},"title":"Count Of Cancelled Workflows","uiStateJSON":"{}","version":1,"visState":"{\"title\":\"Count Of Cancelled Workflows\",\"type\":\"metrics\",\"aggs\":[],\"params\":{\"time_range_mode\":\"entire_time_range\",\"id\":\"61ca57f0-469d-11e7-af02-69e470af7417\",\"type\":\"metric\",\"series\":[{\"time_range_mode\":\"entire_time_range\",\"id\":\"61ca57f1-469d-11e7-af02-69e470af7417\",\"color\":\"#68BC00\",\"split_mode\":\"filters\",\"palette\":{\"type\":\"palette\",\"name\":\"default\"},\"metrics\":[{\"id\":\"61ca57f2-469d-11e7-af02-69e470af7417\",\"type\":\"count\"}],\"separate_axis\":0,\"axis_position\":\"right\",\"formatter\":\"number\",\"chart_type\":\"line\",\"line_width\":1,\"point_size\":1,\"fill\":0.5,\"stacked\":\"none\",\"terms_field\":null,\"terms_order_by\":\"_key\",\"filter\":{\"query\":\"\",\"language\":\"kuery\"},\"split_filters\":[{\"filter\":{\"query\":\"value.bpmnElementType : \\\"PROCESS\\\" and intent : \\\"ELEMENT_TERMINATED\\\" \",\"language\":\"kuery\"},\"label\":\"Cancelled Workflows\",\"color\":\"#68BC00\",\"id\":\"971242e0-8d71-11ec-bcff-f58c9e3b2a77\"}],\"label\":\"Count Of Cancelled Workflows\",\"terms_direction\":\"desc\"}],\"time_field\":\"\",\"use_kibana_indexes\":true,\"interval\":\"\",\"axis_position\":\"left\",\"axis_formatter\":\"number\",\"axis_scale\":\"normal\",\"show_legend\":1,\"show_grid\":1,\"tooltip_mode\":\"show_all\",\"background_color_rules\":[{\"id\":\"564d2540-8d71-11ec-bcff-f58c9e3b2a77\"}],\"isModelInvalid\":false,\"filter\":{\"query\":\"\",\"language\":\"kuery\"},\"drop_last_bucket\":1,\"truncate_legend\":1,\"max_lines_legend\":1,\"index_pattern_ref_name\":\"metrics_0_index_pattern\"}}"},"coreMigrationVersion":"7.16.3","id":"f65006c0-9a00-11ec-92c9-877156a2a4e9","migrationVersion":{"visualization":"7.14.0"},"references":[{"id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","name":"metrics_0_index_pattern","type":"index-pattern"}],"type":"visualization","updated_at":"2023-03-22T10:45:06.683Z","version":"Wzc5LDFd"} +{"excludedObjects":[],"excludedObjectsCount":0,"exportedCount":1,"missingRefCount":0,"missingReferences":[]} \ No newline at end of file diff --git a/ph-ee-env-template/Kibana Visualisations/visualization/Count of FailedCancelled Txns.ndjson b/ph-ee-env-template/Kibana Visualisations/visualization/Count of FailedCancelled Txns.ndjson new file mode 100644 index 000000000..f0e88f0c5 --- /dev/null +++ b/ph-ee-env-template/Kibana Visualisations/visualization/Count of FailedCancelled Txns.ndjson @@ -0,0 +1,2 @@ +{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[]}"},"title":"Count of Failed/Cancelled Txns","uiStateJSON":"{}","version":1,"visState":"{\"title\":\"Count of Failed/Cancelled Txns\",\"type\":\"metrics\",\"aggs\":[],\"params\":{\"time_range_mode\":\"entire_time_range\",\"id\":\"61ca57f0-469d-11e7-af02-69e470af7417\",\"type\":\"metric\",\"series\":[{\"time_range_mode\":\"entire_time_range\",\"id\":\"61ca57f1-469d-11e7-af02-69e470af7417\",\"color\":\"#68BC00\",\"split_mode\":\"filters\",\"palette\":{\"type\":\"palette\",\"name\":\"default\"},\"metrics\":[{\"id\":\"61ca57f2-469d-11e7-af02-69e470af7417\",\"type\":\"count\"}],\"separate_axis\":0,\"axis_position\":\"right\",\"formatter\":\"number\",\"chart_type\":\"line\",\"line_width\":1,\"point_size\":1,\"fill\":0.5,\"stacked\":\"none\",\"terms_field\":null,\"terms_order_by\":\"_key\",\"filter\":{\"query\":\"\",\"language\":\"kuery\"},\"split_filters\":[{\"filter\":{\"query\":\"value.bpmnElementType : \\\"PROCESS\\\" and intent : \\\"ELEMENT_TERMINATED\\\" \",\"language\":\"kuery\"},\"label\":\"Cancelled Workflows\",\"color\":\"#68BC00\",\"id\":\"971242e0-8d71-11ec-bcff-f58c9e3b2a77\"}],\"label\":\"Count Of Cancelled Workflows\",\"terms_direction\":\"desc\"}],\"time_field\":\"\",\"use_kibana_indexes\":true,\"interval\":\"\",\"axis_position\":\"left\",\"axis_formatter\":\"number\",\"axis_scale\":\"normal\",\"show_legend\":1,\"show_grid\":1,\"tooltip_mode\":\"show_all\",\"background_color_rules\":[{\"id\":\"564d2540-8d71-11ec-bcff-f58c9e3b2a77\"}],\"isModelInvalid\":false,\"filter\":{\"query\":\"\",\"language\":\"kuery\"},\"drop_last_bucket\":1,\"truncate_legend\":1,\"max_lines_legend\":1,\"index_pattern_ref_name\":\"metrics_0_index_pattern\"}}"},"coreMigrationVersion":"7.16.3","id":"66e67450-8d72-11ec-92d2-2d974edf9929","migrationVersion":{"visualization":"7.14.0"},"references":[{"id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","name":"metrics_0_index_pattern","type":"index-pattern"}],"type":"visualization","updated_at":"2023-03-22T10:45:06.683Z","version":"WzcxLDFd"} +{"excludedObjects":[],"excludedObjectsCount":0,"exportedCount":1,"missingRefCount":0,"missingReferences":[]} \ No newline at end of file diff --git a/ph-ee-env-template/Kibana Visualisations/visualization/Count of Timed Out Workflows.ndjson b/ph-ee-env-template/Kibana Visualisations/visualization/Count of Timed Out Workflows.ndjson new file mode 100644 index 000000000..8c48ce449 --- /dev/null +++ b/ph-ee-env-template/Kibana Visualisations/visualization/Count of Timed Out Workflows.ndjson @@ -0,0 +1,2 @@ +{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"lucene\"},\"filter\":[]}"},"title":"Count of Timed Out Workflows","uiStateJSON":"{}","version":1,"visState":"{\"title\":\"Count of Timed Out Workflows\",\"type\":\"metrics\",\"aggs\":[],\"params\":{\"time_range_mode\":\"entire_time_range\",\"id\":\"24013fd2-cb48-4385-907c-6547080a2b9c\",\"type\":\"metric\",\"series\":[{\"time_range_mode\":\"entire_time_range\",\"id\":\"8184665c-7bbb-4fa5-835e-f9d09ed6c313\",\"color\":\"#68BC00\",\"split_mode\":\"filters\",\"palette\":{\"type\":\"palette\",\"name\":\"default\"},\"metrics\":[{\"id\":\"1a321ec2-949a-47de-bba3-d63da366a9f5\",\"type\":\"count\"}],\"separate_axis\":0,\"axis_position\":\"right\",\"formatter\":\"default\",\"chart_type\":\"line\",\"line_width\":1,\"point_size\":1,\"fill\":0.5,\"stacked\":\"none\",\"split_filters\":[{\"filter\":{\"query\":\"value.name: \\\"mpesaTransactionStatusRetryCount\\\" and value.value : \\\"4\\\" \",\"language\":\"kuery\"},\"label\":\"Count of Timed Out Txns (Running & Completed)\",\"color\":\"#68BC00\",\"id\":\"256d98a0-9a0b-11ec-953b-9d26005d8940\"},{\"filter\":{\"query\":\"value.name : \\\"callbackRetry\\\" and value.value : \\\"3\\\" \",\"language\":\"kuery\"},\"label\":\"Count of Timed Out Deliveries (Running & Completed)\",\"color\":\"#68BC00\",\"id\":\"6f3bcab0-9a0b-11ec-953b-9d26005d8940\"}],\"label\":\"\"}],\"time_field\":\"\",\"index_pattern\":\"\",\"use_kibana_indexes\":true,\"interval\":\"\",\"axis_position\":\"left\",\"axis_formatter\":\"number\",\"axis_scale\":\"normal\",\"show_legend\":1,\"truncate_legend\":1,\"max_lines_legend\":1,\"show_grid\":1,\"tooltip_mode\":\"show_all\",\"drop_last_bucket\":0,\"background_color_rules\":[{\"id\":\"233d9940-9a0b-11ec-953b-9d26005d8940\"}]}}"},"coreMigrationVersion":"7.16.3","id":"9de94130-9a0b-11ec-92c9-877156a2a4e9","migrationVersion":{"visualization":"7.14.0"},"references":[],"type":"visualization","updated_at":"2023-03-22T10:45:06.683Z","version":"WzgwLDFd"} +{"excludedObjects":[],"excludedObjectsCount":0,"exportedCount":1,"missingRefCount":0,"missingReferences":[]} \ No newline at end of file diff --git a/ph-ee-env-template/Kibana Visualisations/visualization/Error Timeline.ndjson b/ph-ee-env-template/Kibana Visualisations/visualization/Error Timeline.ndjson new file mode 100644 index 000000000..bfe78c496 --- /dev/null +++ b/ph-ee-env-template/Kibana Visualisations/visualization/Error Timeline.ndjson @@ -0,0 +1,2 @@ +{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[]}"},"title":"Error Timeline","uiStateJSON":"{}","version":1,"visState":"{\"title\":\"Error Timeline\",\"type\":\"metrics\",\"aggs\":[],\"params\":{\"time_range_mode\":\"entire_time_range\",\"id\":\"f9bdb48d-9fd0-4c71-bdd1-f0c3163622d8\",\"type\":\"timeseries\",\"series\":[{\"time_range_mode\":\"entire_time_range\",\"id\":\"6b3e48f0-159f-4e30-b929-412fd9b7f693\",\"color\":\"#68BC00\",\"split_mode\":\"terms\",\"palette\":{\"type\":\"palette\",\"name\":\"default\"},\"metrics\":[{\"id\":\"50f9cf8b-9710-485e-9b9b-54a08a025671\",\"type\":\"count\"}],\"separate_axis\":0,\"axis_position\":\"right\",\"formatter\":\"default\",\"chart_type\":\"line\",\"line_width\":1,\"point_size\":1,\"fill\":0.5,\"stacked\":\"none\",\"label\":\"Error Count\",\"terms_field\":\"value.value\",\"terms_size\":\"30\"}],\"time_field\":\"\",\"index_pattern\":\"\",\"use_kibana_indexes\":true,\"interval\":\"\",\"axis_position\":\"left\",\"axis_formatter\":\"number\",\"axis_scale\":\"normal\",\"show_legend\":1,\"truncate_legend\":1,\"max_lines_legend\":1,\"show_grid\":1,\"tooltip_mode\":\"show_all\",\"drop_last_bucket\":0,\"isModelInvalid\":false,\"filter\":{\"query\":\"value.name : \\\"errorDescription\\\" \",\"language\":\"kuery\"}}}"},"coreMigrationVersion":"7.16.3","id":"381ab8c0-a51e-11ec-92c9-877156a2a4e9","migrationVersion":{"visualization":"7.14.0"},"references":[],"type":"visualization","updated_at":"2023-03-22T10:45:06.683Z","version":"WzY3LDFd"} +{"excludedObjects":[],"excludedObjectsCount":0,"exportedCount":1,"missingRefCount":0,"missingReferences":[]} \ No newline at end of file diff --git a/ph-ee-env-template/Kibana Visualisations/visualization/Less than 30 sec - Txn Count %.ndjson b/ph-ee-env-template/Kibana Visualisations/visualization/Less than 30 sec - Txn Count %.ndjson new file mode 100644 index 000000000..9a5e2461d --- /dev/null +++ b/ph-ee-env-template/Kibana Visualisations/visualization/Less than 30 sec - Txn Count %.ndjson @@ -0,0 +1,2 @@ +{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[]}"},"title":"Less than 30 sec - Txn Count %","uiStateJSON":"{}","version":1,"visState":"{\"title\":\"Less than 30 sec - Txn Count %\",\"type\":\"metrics\",\"aggs\":[],\"params\":{\"time_range_mode\":\"entire_time_range\",\"axis_formatter\":\"number\",\"axis_position\":\"left\",\"axis_scale\":\"normal\",\"background_color_rules\":[{\"id\":\"95fd8820-65b5-11ed-8896-159c2aed0123\"}],\"bar_color_rules\":[{\"id\":\"92469aa0-65b5-11ed-8896-159c2aed0123\"}],\"drop_last_bucket\":0,\"id\":\"ad242e2d-b209-444c-8126-5a25fd3cf9e5\",\"interval\":\"\",\"isModelInvalid\":false,\"max_lines_legend\":1,\"series\":[{\"time_range_mode\":\"entire_time_range\",\"axis_position\":\"right\",\"chart_type\":\"line\",\"color\":\"rgba(112,184,112,1)\",\"fill\":0.5,\"filter\":{\"language\":\"kuery\",\"query\":\"\"},\"formatter\":\"percent\",\"id\":\"971b5d43-4e4f-43ed-a60f-1ec33107244a\",\"label\":\"Elapsed Time(less than 30 sec)\",\"line_width\":1,\"metrics\":[{\"id\":\"984467e2-c860-4be4-aa41-353a69a98368\",\"type\":\"filter_ratio\",\"numerator\":{\"query\":\"elapsedTime <= 30\",\"language\":\"kuery\"},\"denominator\":{\"query\":\"elapsedTime > -1\",\"language\":\"kuery\"},\"metric_agg\":\"count\"}],\"palette\":{\"name\":\"default\",\"type\":\"palette\"},\"point_size\":1,\"separate_axis\":0,\"split_filters\":[{\"filter\":{\"query\":\"elapsedTime <= 60 and elapsedTime > 30\",\"language\":\"kuery\"},\"label\":\"30sec-1min\",\"color\":\"rgba(145,112,184,1)\",\"id\":\"bb90fa40-65b5-11ed-8896-159c2aed0123\"},{\"filter\":{\"language\":\"kuery\",\"query\":\"elapsedTime > 60 and elapsedTime <= 120\"},\"label\":\"1min-2mins\",\"color\":\"rgba(218,139,69,1)\",\"id\":\"f28e2040-65b5-11ed-8896-159c2aed0123\"},{\"filter\":{\"language\":\"kuery\",\"query\":\"elapsedTime > 120 and elapsedTime <= 300\"},\"label\":\"2mins-5mins\",\"color\":\"rgba(96,146,192,1)\",\"id\":\"fd6712b0-65b5-11ed-8896-159c2aed0123\"},{\"filter\":{\"language\":\"kuery\",\"query\":\"elapsedTime > 300\"},\"label\":\">5mins\",\"color\":\"rgba(214,191,87,1)\",\"id\":\"0fedf660-65b6-11ed-8896-159c2aed0123\"},{\"filter\":{\"query\":\" elapsedTime <=30\",\"language\":\"kuery\"},\"label\":\"<30sec\",\"color\":\"rgba(112,184,112,1)\",\"id\":\"5a322650-65b7-11ed-8896-159c2aed0123\"},{\"filter\":{\"query\":\"processInstanceKey : * \",\"language\":\"kuery\"},\"label\":\"Total Count\",\"color\":\"rgba(185,168,136,1)\",\"id\":\"0936d650-65b8-11ed-8896-159c2aed0123\"}],\"split_mode\":\"everything\",\"stacked\":\"none\"}],\"show_grid\":1,\"show_legend\":1,\"time_field\":\"\",\"tooltip_mode\":\"show_all\",\"truncate_legend\":1,\"type\":\"metric\",\"use_kibana_indexes\":true,\"index_pattern_ref_name\":\"metrics_0_index_pattern\"}}"},"coreMigrationVersion":"7.16.3","id":"30b7d5e0-65df-11ed-b142-e72429dbdfa6","migrationVersion":{"visualization":"7.14.0"},"references":[{"id":"a7328550-f2d3-11ec-9dd9-bb3704b858df","name":"metrics_0_index_pattern","type":"index-pattern"}],"type":"visualization","updated_at":"2023-03-22T10:45:06.683Z","version":"WzY2LDFd"} +{"excludedObjects":[],"excludedObjectsCount":0,"exportedCount":1,"missingRefCount":0,"missingReferences":[]} \ No newline at end of file diff --git a/ph-ee-env-template/Kibana Visualisations/visualization/Process Definition.ndjson b/ph-ee-env-template/Kibana Visualisations/visualization/Process Definition.ndjson new file mode 100644 index 000000000..664260780 --- /dev/null +++ b/ph-ee-env-template/Kibana Visualisations/visualization/Process Definition.ndjson @@ -0,0 +1,2 @@ +{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[]}"},"title":"Process Definition","uiStateJSON":"{}","version":1,"visState":"{\"title\":\"Process Definition\",\"type\":\"input_control_vis\",\"aggs\":[],\"params\":{\"controls\":[{\"id\":\"1633536719626\",\"fieldName\":\"value.bpmnProcessId\",\"parent\":\"\",\"label\":\"Process Def Key\",\"type\":\"list\",\"options\":{\"type\":\"terms\",\"multiselect\":true,\"dynamicOptions\":true,\"size\":5,\"order\":\"desc\"},\"indexPatternRefName\":\"control_0_index_pattern\"},{\"id\":\"1654250630610\",\"fieldName\":\"value.processDefinitionKey\",\"parent\":\"1633536719626\",\"label\":\"Process Def Value\",\"type\":\"list\",\"options\":{\"type\":\"terms\",\"multiselect\":true,\"dynamicOptions\":true,\"size\":10,\"order\":\"desc\"},\"indexPatternRefName\":\"control_1_index_pattern\"}],\"updateFiltersOnChange\":false,\"useTimeFilter\":false,\"pinFilters\":false}}"},"coreMigrationVersion":"7.16.3","id":"b66a64c0-e31f-11ec-9dd9-bb3704b858df","migrationVersion":{"visualization":"7.14.0"},"references":[{"id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","name":"control_0_index_pattern","type":"index-pattern"},{"id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","name":"control_1_index_pattern","type":"index-pattern"}],"type":"visualization","updated_at":"2023-03-22T10:45:06.683Z","version":"Wzc1LDFd"} +{"excludedObjects":[],"excludedObjectsCount":0,"exportedCount":1,"missingRefCount":0,"missingReferences":[]} \ No newline at end of file diff --git a/ph-ee-env-template/Kibana Visualisations/visualization/Process Variables.ndjson b/ph-ee-env-template/Kibana Visualisations/visualization/Process Variables.ndjson new file mode 100644 index 000000000..060d18697 --- /dev/null +++ b/ph-ee-env-template/Kibana Visualisations/visualization/Process Variables.ndjson @@ -0,0 +1,2 @@ +{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[],\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\"}"},"title":"Process Variables","uiStateJSON":"{}","version":1,"visState":"{\"title\":\"Process Variables\",\"type\":\"table\",\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"count\",\"params\":{},\"schema\":\"metric\"},{\"id\":\"2\",\"enabled\":true,\"type\":\"terms\",\"params\":{\"field\":\"value.name\",\"orderBy\":\"1\",\"order\":\"desc\",\"size\":100,\"otherBucket\":false,\"otherBucketLabel\":\"Other\",\"missingBucket\":false,\"missingBucketLabel\":\"Missing\",\"customLabel\":\"variableName\"},\"schema\":\"bucket\"},{\"id\":\"3\",\"enabled\":true,\"type\":\"terms\",\"params\":{\"field\":\"value.value\",\"orderBy\":\"1\",\"order\":\"desc\",\"size\":100,\"otherBucket\":false,\"otherBucketLabel\":\"Other\",\"missingBucket\":false,\"missingBucketLabel\":\"Missing\",\"customLabel\":\"variableValue\"},\"schema\":\"bucket\"}],\"params\":{\"perPage\":20,\"showPartialRows\":false,\"showMetricsAtAllLevels\":false,\"showTotal\":false,\"showToolbar\":false,\"totalFunc\":\"sum\",\"percentageCol\":\"\"}}"},"coreMigrationVersion":"7.16.3","id":"8cf5f410-26c3-11ec-95b3-cb627b5ccd4b","migrationVersion":{"visualization":"7.14.0"},"references":[{"id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","name":"kibanaSavedObjectMeta.searchSourceJSON.index","type":"index-pattern"}],"type":"visualization","updated_at":"2023-03-22T10:45:06.683Z","version":"WzYzLDFd"} +{"excludedObjects":[],"excludedObjectsCount":0,"exportedCount":1,"missingRefCount":0,"missingReferences":[]} \ No newline at end of file diff --git a/ph-ee-env-template/Kibana Visualisations/visualization/ProcessInstanceCount.ndjson b/ph-ee-env-template/Kibana Visualisations/visualization/ProcessInstanceCount.ndjson new file mode 100644 index 000000000..e99911fb7 --- /dev/null +++ b/ph-ee-env-template/Kibana Visualisations/visualization/ProcessInstanceCount.ndjson @@ -0,0 +1,2 @@ +{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[],\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\"}"},"title":"ProcessInstanceCount","uiStateJSON":"{}","version":1,"visState":"{\"title\":\"ProcessInstanceCount\",\"type\":\"table\",\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"cardinality\",\"params\":{\"field\":\"value.processInstanceKey\",\"customLabel\":\"processInstanceCount\"},\"schema\":\"metric\"},{\"id\":\"2\",\"enabled\":true,\"type\":\"terms\",\"params\":{\"field\":\"value.bpmnProcessId\",\"orderBy\":\"1\",\"order\":\"desc\",\"size\":10,\"otherBucket\":false,\"otherBucketLabel\":\"Other\",\"missingBucket\":false,\"missingBucketLabel\":\"Missing\",\"customLabel\":\"processDefinition\"},\"schema\":\"bucket\"}],\"params\":{\"perPage\":10,\"showPartialRows\":false,\"showMetricsAtAllLevels\":false,\"showTotal\":false,\"showToolbar\":false,\"totalFunc\":\"sum\",\"percentageCol\":\"\"}}"},"coreMigrationVersion":"7.16.3","id":"f21cb760-26bf-11ec-95b3-cb627b5ccd4b","migrationVersion":{"visualization":"7.14.0"},"references":[{"id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","name":"kibanaSavedObjectMeta.searchSourceJSON.index","type":"index-pattern"}],"type":"visualization","updated_at":"2023-03-22T10:45:06.683Z","version":"WzYxLDFd"} +{"excludedObjects":[],"excludedObjectsCount":0,"exportedCount":1,"missingRefCount":0,"missingReferences":[]} \ No newline at end of file diff --git a/ph-ee-env-template/Kibana Visualisations/visualization/ProcessInstanceKeys.ndjson b/ph-ee-env-template/Kibana Visualisations/visualization/ProcessInstanceKeys.ndjson new file mode 100644 index 000000000..239ecd025 --- /dev/null +++ b/ph-ee-env-template/Kibana Visualisations/visualization/ProcessInstanceKeys.ndjson @@ -0,0 +1,2 @@ +{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[],\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\"}"},"title":"ProcessInstanceKeys","uiStateJSON":"{}","version":1,"visState":"{\"title\":\"ProcessInstanceKeys\",\"type\":\"table\",\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"count\",\"params\":{},\"schema\":\"metric\"},{\"id\":\"2\",\"enabled\":true,\"type\":\"terms\",\"params\":{\"field\":\"value.bpmnProcessId\",\"orderBy\":\"1\",\"order\":\"desc\",\"size\":100,\"otherBucket\":false,\"otherBucketLabel\":\"Other\",\"missingBucket\":false,\"missingBucketLabel\":\"Missing\",\"customLabel\":\"ProcessDef\"},\"schema\":\"bucket\"},{\"id\":\"3\",\"enabled\":true,\"type\":\"terms\",\"params\":{\"field\":\"value.processInstanceKey\",\"orderBy\":\"1\",\"order\":\"desc\",\"size\":100,\"otherBucket\":true,\"otherBucketLabel\":\"Other\",\"missingBucket\":false,\"missingBucketLabel\":\"Missing\",\"customLabel\":\"ProcessInstanceKey\"},\"schema\":\"bucket\"}],\"params\":{\"perPage\":10,\"showPartialRows\":false,\"showMetricsAtAllLevels\":false,\"showTotal\":false,\"showToolbar\":false,\"totalFunc\":\"sum\",\"percentageCol\":\"\",\"autoFitRowToContent\":false}}"},"coreMigrationVersion":"7.16.3","id":"df1144f0-26c0-11ec-95b3-cb627b5ccd4b","migrationVersion":{"visualization":"7.14.0"},"references":[{"id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","name":"kibanaSavedObjectMeta.searchSourceJSON.index","type":"index-pattern"}],"type":"visualization","updated_at":"2023-03-22T10:45:06.683Z","version":"WzYyLDFd"} +{"excludedObjects":[],"excludedObjectsCount":0,"exportedCount":1,"missingRefCount":0,"missingReferences":[]} \ No newline at end of file diff --git a/ph-ee-env-template/Kibana Visualisations/visualization/Settlement Failed-False Negative .ndjson b/ph-ee-env-template/Kibana Visualisations/visualization/Settlement Failed-False Negative .ndjson new file mode 100644 index 000000000..8d66c1bdf --- /dev/null +++ b/ph-ee-env-template/Kibana Visualisations/visualization/Settlement Failed-False Negative .ndjson @@ -0,0 +1,2 @@ +{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"lucene\"},\"filter\":[],\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\"}"},"title":"Settlement Failed-False Negative ","uiStateJSON":"{}","version":1,"visState":"{\"title\":\"Settlement Failed-False Negative \",\"type\":\"table\",\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"count\",\"params\":{},\"schema\":\"metric\"},{\"id\":\"2\",\"enabled\":true,\"type\":\"terms\",\"params\":{\"field\":\"value.processInstanceKey\",\"orderBy\":\"1\",\"order\":\"desc\",\"size\":1000,\"otherBucket\":false,\"otherBucketLabel\":\"Other\",\"missingBucket\":false,\"missingBucketLabel\":\"Missing\"},\"schema\":\"bucket\"},{\"id\":\"3\",\"enabled\":true,\"type\":\"filters\",\"params\":{\"filters\":[{\"input\":{\"query\":\"value.name : \\\"errorInformation\\\" and value.value : \\\"{\\\\\\\"status\\\\\\\":\\\\\\\"CONFIRMED\\\\\\\"}\\\"\",\"language\":\"kuery\"},\"label\":\"\"}]},\"schema\":\"bucket\"}],\"params\":{\"perPage\":1000,\"showPartialRows\":false,\"showMetricsAtAllLevels\":false,\"showTotal\":false,\"showToolbar\":false,\"totalFunc\":\"sum\",\"percentageCol\":\"\",\"autoFitRowToContent\":false,\"row\":false}}"},"coreMigrationVersion":"7.16.3","id":"44180df0-9b0d-11ec-92c9-877156a2a4e9","migrationVersion":{"visualization":"7.14.0"},"references":[{"id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","name":"kibanaSavedObjectMeta.searchSourceJSON.index","type":"index-pattern"}],"type":"visualization","updated_at":"2023-03-22T10:45:06.683Z","version":"WzY4LDFd"} +{"excludedObjects":[],"excludedObjectsCount":0,"exportedCount":1,"missingRefCount":0,"missingReferences":[]} \ No newline at end of file diff --git a/ph-ee-env-template/Kibana Visualisations/visualization/TaskState .ndjson b/ph-ee-env-template/Kibana Visualisations/visualization/TaskState .ndjson new file mode 100644 index 000000000..5f89ef345 --- /dev/null +++ b/ph-ee-env-template/Kibana Visualisations/visualization/TaskState .ndjson @@ -0,0 +1,2 @@ +{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[],\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\"}"},"title":"Task/State ","uiStateJSON":"{}","version":1,"visState":"{\"title\":\"Task/State \",\"type\":\"table\",\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"max\",\"params\":{\"field\":\"timestamp\"},\"schema\":\"metric\"},{\"id\":\"2\",\"enabled\":true,\"type\":\"terms\",\"params\":{\"field\":\"value.elementId\",\"orderBy\":\"1\",\"order\":\"desc\",\"size\":30,\"otherBucket\":false,\"otherBucketLabel\":\"Other\",\"missingBucket\":false,\"missingBucketLabel\":\"Missing\",\"customLabel\":\"Task/State Name\"},\"schema\":\"bucket\"},{\"id\":\"3\",\"enabled\":true,\"type\":\"count\",\"params\":{\"customLabel\":\"TaskCount\"},\"schema\":\"metric\"}],\"params\":{\"perPage\":30,\"showPartialRows\":false,\"showMetricsAtAllLevels\":false,\"showTotal\":false,\"showToolbar\":false,\"totalFunc\":\"sum\",\"percentageCol\":\"\",\"autoFitRowToContent\":false}}"},"coreMigrationVersion":"7.16.3","id":"cc282ac0-26c5-11ec-95b3-cb627b5ccd4b","migrationVersion":{"visualization":"7.14.0"},"references":[{"id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","name":"kibanaSavedObjectMeta.searchSourceJSON.index","type":"index-pattern"}],"type":"visualization","updated_at":"2023-03-22T10:45:06.683Z","version":"WzY0LDFd"} +{"excludedObjects":[],"excludedObjectsCount":0,"exportedCount":1,"missingRefCount":0,"missingReferences":[]} \ No newline at end of file diff --git a/ph-ee-env-template/Kibana Visualisations/visualization/Transaction Decision Gateways.ndjson b/ph-ee-env-template/Kibana Visualisations/visualization/Transaction Decision Gateways.ndjson new file mode 100644 index 000000000..75bb836a0 --- /dev/null +++ b/ph-ee-env-template/Kibana Visualisations/visualization/Transaction Decision Gateways.ndjson @@ -0,0 +1,2 @@ +{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[]}"},"title":"Transaction Decision Gateways","uiStateJSON":"{}","version":1,"visState":"{\"title\":\"Transaction Decision Gateways\",\"type\":\"metrics\",\"aggs\":[],\"params\":{\"time_range_mode\":\"entire_time_range\",\"id\":\"0fbcb70d-785f-4bd5-8a01-5ccf2ba8b04f\",\"type\":\"metric\",\"series\":[{\"time_range_mode\":\"entire_time_range\",\"id\":\"e29c0f65-d09d-43f8-99a3-b7075234c1d9\",\"color\":\"#68BC00\",\"split_mode\":\"filters\",\"palette\":{\"type\":\"palette\",\"name\":\"default\"},\"metrics\":[{\"id\":\"55bc12ae-9f04-4fd9-bb99-402048ceb1b8\",\"type\":\"count\"}],\"separate_axis\":0,\"axis_position\":\"right\",\"formatter\":\"default\",\"chart_type\":\"line\",\"line_width\":1,\"point_size\":1,\"fill\":0.5,\"stacked\":\"none\",\"split_filters\":[{\"filter\":{\"query\":\"value.name: \\\"partyLookupFailed\\\" and value.value: \\\"true\\\" \",\"language\":\"kuery\"},\"label\":\"Count of Txns With Party Lookup Failed\",\"color\":\"#68BC00\",\"id\":\"61348740-9a01-11ec-8b98-a3ff4ce513d9\"},{\"filter\":{\"query\":\"value.name : \\\"transactionFailed\\\" and value.value : \\\"true\\\" \",\"language\":\"kuery\"},\"label\":\"Count of Txns With Transaction Failed\",\"color\":\"#68BC00\",\"id\":\"abf94e50-9a01-11ec-8b98-a3ff4ce513d9\"},{\"filter\":{\"query\":\" value.name : \\\"transferSettlementFailed\\\" and value.value : \\\"true\\\" \",\"language\":\"kuery\"},\"label\":\"Count of Txns With Settlement Failed\",\"color\":\"#68BC00\",\"id\":\"db417e30-9a01-11ec-8b98-a3ff4ce513d9\"},{\"filter\":{\"query\":\"value.name: \\\"partyLookupFailed\\\" and NOT value.value : \\\"true\\\" \",\"language\":\"kuery\"},\"label\":\"Count of Txns With Party Lookup Successful \",\"color\":\"#68BC00\",\"id\":\"f60f10b0-9a01-11ec-8b98-a3ff4ce513d9\"},{\"filter\":{\"query\":\"value.name : \\\"transactionFailed\\\" and value.value : \\\"false\\\" \",\"language\":\"kuery\"},\"label\":\"[Misleading] Count of Txns With Transaction Successful\",\"color\":\"#68BC00\",\"id\":\"29cc26e0-9a02-11ec-8b98-a3ff4ce513d9\"},{\"filter\":{\"query\":\"value.name : \\\"transferSettlementFailed\\\" and NOT value.value : \\\"true\\\" \",\"language\":\"kuery\"},\"label\":\"Count of Txns With Settlement Successful\",\"color\":\"#68BC00\",\"id\":\"7565ca20-9a02-11ec-8b98-a3ff4ce513d9\"}],\"label\":\"\"}],\"time_field\":\"\",\"index_pattern\":\"\",\"use_kibana_indexes\":true,\"interval\":\"\",\"axis_position\":\"left\",\"axis_formatter\":\"number\",\"axis_scale\":\"normal\",\"show_legend\":1,\"truncate_legend\":1,\"max_lines_legend\":1,\"show_grid\":1,\"tooltip_mode\":\"show_all\",\"drop_last_bucket\":0,\"background_color_rules\":[{\"id\":\"5c1bbfd0-9a01-11ec-8b98-a3ff4ce513d9\"}]}}"},"coreMigrationVersion":"7.16.3","id":"ef6d42d0-9a02-11ec-92c9-877156a2a4e9","migrationVersion":{"visualization":"7.14.0"},"references":[],"type":"visualization","updated_at":"2023-03-22T10:45:06.683Z","version":"Wzc3LDFd"} +{"excludedObjects":[],"excludedObjectsCount":0,"exportedCount":1,"missingRefCount":0,"missingReferences":[]} \ No newline at end of file diff --git a/ph-ee-env-template/Kibana Visualisations/visualization/Txn Count by BPMN Version.ndjson b/ph-ee-env-template/Kibana Visualisations/visualization/Txn Count by BPMN Version.ndjson new file mode 100644 index 000000000..790ecd79f --- /dev/null +++ b/ph-ee-env-template/Kibana Visualisations/visualization/Txn Count by BPMN Version.ndjson @@ -0,0 +1,2 @@ +{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[]}"},"title":"Txn Count by BPMN Version","uiStateJSON":"{}","version":1,"visState":"{\"title\":\"Txn Count by BPMN Version\",\"type\":\"metrics\",\"aggs\":[],\"params\":{\"time_range_mode\":\"entire_time_range\",\"id\":\"75e7f774-7289-41d7-ad62-81936e329514\",\"type\":\"metric\",\"series\":[{\"time_range_mode\":\"entire_time_range\",\"id\":\"8f481979-dc3d-4732-830c-ad65f2385e00\",\"color\":\"#68BC00\",\"split_mode\":\"terms\",\"palette\":{\"type\":\"palette\",\"name\":\"default\"},\"metrics\":[{\"id\":\"58791b1e-a46f-47e9-9416-3f59f56ed477\",\"type\":\"cardinality\",\"field\":\"value.processInstanceKey\"}],\"separate_axis\":0,\"axis_position\":\"right\",\"formatter\":\"default\",\"chart_type\":\"line\",\"line_width\":1,\"point_size\":1,\"fill\":0.5,\"stacked\":\"none\",\"terms_field\":\"value.processDefinitionKey\",\"label\":\"Txn Count\"}],\"time_field\":\"\",\"index_pattern\":\"\",\"use_kibana_indexes\":true,\"interval\":\"\",\"axis_position\":\"left\",\"axis_formatter\":\"number\",\"axis_scale\":\"normal\",\"show_legend\":1,\"truncate_legend\":1,\"max_lines_legend\":1,\"show_grid\":1,\"tooltip_mode\":\"show_all\",\"drop_last_bucket\":0,\"background_color_rules\":[{\"id\":\"027b6950-8cf2-11ed-a61d-db16238eb812\"}]}}"},"coreMigrationVersion":"7.16.3","id":"e1111200-8cf2-11ed-9074-afdd87226beb","migrationVersion":{"visualization":"7.14.0"},"references":[],"type":"visualization","updated_at":"2023-03-22T10:45:06.683Z","version":"Wzc2LDFd"} +{"excludedObjects":[],"excludedObjectsCount":0,"exportedCount":1,"missingRefCount":0,"missingReferences":[]} \ No newline at end of file diff --git a/ph-ee-env-template/Kibana Visualisations/visualization/Txn Count.ndjson b/ph-ee-env-template/Kibana Visualisations/visualization/Txn Count.ndjson new file mode 100644 index 000000000..85a739ca4 --- /dev/null +++ b/ph-ee-env-template/Kibana Visualisations/visualization/Txn Count.ndjson @@ -0,0 +1,2 @@ +{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[]}"},"title":"Txn Count","uiStateJSON":"{}","version":1,"visState":"{\"title\":\"Txn Count\",\"type\":\"metrics\",\"aggs\":[],\"params\":{\"time_range_mode\":\"entire_time_range\",\"id\":\"61ca57f0-469d-11e7-af02-69e470af7417\",\"type\":\"metric\",\"series\":[{\"time_range_mode\":\"entire_time_range\",\"id\":\"61ca57f1-469d-11e7-af02-69e470af7417\",\"color\":\"#68BC00\",\"split_mode\":\"filters\",\"palette\":{\"type\":\"palette\",\"name\":\"default\"},\"metrics\":[{\"size\":1,\"agg_with\":\"noop\",\"order\":\"desc\",\"unit\":\"\",\"id\":\"61ca57f2-469d-11e7-af02-69e470af7417\",\"type\":\"count\",\"field\":null}],\"separate_axis\":0,\"axis_position\":\"right\",\"formatter\":\"number\",\"chart_type\":\"line\",\"line_width\":1,\"point_size\":1,\"fill\":0.5,\"stacked\":\"none\",\"label\":\"Count of events\",\"type\":\"timeseries\",\"filter\":{\"query\":\"\",\"language\":\"kuery\"},\"terms_order_by\":\"_key\",\"terms_field\":null,\"terms_direction\":\"desc\",\"terms_size\":\"30\",\"color_rules\":[{\"id\":\"0daa99e0-89ab-11ec-bcff-f58c9e3b2a77\"}],\"split_filters\":[{\"filter\":{\"query\":\"value.bpmnElementType : \\\"END_EVENT\\\" and intent : \\\"ELEMENT_COMPLETED\\\" \",\"language\":\"kuery\"},\"label\":\"Total Count Of Completed Workflows\",\"color\":\"#68BC00\",\"id\":\"470ed4d0-89ab-11ec-bcff-f58c9e3b2a77\"},{\"filter\":{\"query\":\"value.bpmnElementType : \\\"END_EVENT\\\" and value.elementId : \\\"Event_1bh40y1\\\" and intent : \\\"ELEMENT_COMPLETED\\\" \",\"language\":\"kuery\"},\"label\":\"Txn Sucess (Without notifications path)\",\"color\":\"#68BC00\",\"id\":\"aa8dbe10-89b3-11ec-bcff-f58c9e3b2a77\"},{\"filter\":{\"query\":\"value.bpmnElementType : \\\"END_EVENT\\\" and (value.elementId : \\\"sucess\\\" or value.elementId : \\\"failure\\\") and intent : \\\"ELEMENT_COMPLETED\\\" \",\"language\":\"kuery\"},\"label\":\"Failed Txns (Under Notifications Path)\",\"color\":\"#68BC00\",\"id\":\"3c52a310-89b4-11ec-bcff-f58c9e3b2a77\"},{\"filter\":{\"query\":\"value.bpmnElementType : \\\"END_EVENT\\\" and intent : \\\"ELEMENT_COMPLETED\\\" and value.elementId : \\\"sucess\\\" \",\"language\":\"kuery\"},\"label\":\"Completed Workflow (With Successful Notification Delivery)\",\"color\":\"#68BC00\",\"id\":\"bcc962b0-8a89-11ec-bcff-f58c9e3b2a77\"},{\"filter\":{\"query\":\"value.bpmnElementType : \\\"END_EVENT\\\" and value.elementId : \\\"failure\\\" and intent : \\\"ELEMENT_COMPLETED\\\" \",\"language\":\"kuery\"},\"label\":\"Completed Workflow (With Failed Notification Delivery)\",\"color\":\"#68BC00\",\"id\":\"cbafa000-8a89-11ec-bcff-f58c9e3b2a77\"},{\"filter\":{\"query\":\"value.bpmnElementType : \\\"END_EVENT\\\" and value.elementId : \\\"End\\\" and intent : \\\"ELEMENT_COMPLETED\\\" \",\"language\":\"kuery\"},\"label\":\"Txn Failure (Without notifications path) \",\"color\":\"#68BC00\",\"id\":\"17433ae0-9bc4-11ec-a468-43f14c90e9d4\"}]}],\"time_field\":\"\",\"use_kibana_indexes\":true,\"interval\":\"\",\"axis_position\":\"left\",\"axis_formatter\":\"number\",\"axis_scale\":\"normal\",\"show_legend\":1,\"show_grid\":1,\"tooltip_mode\":\"show_all\",\"isModelInvalid\":false,\"background_color_rules\":[{\"id\":\"936d7d20-89a8-11ec-bcff-f58c9e3b2a77\"}],\"bar_color_rules\":[{\"id\":\"9645ca70-89a8-11ec-bcff-f58c9e3b2a77\"}],\"pivot_id\":\"value.processInstanceKey\",\"pivot_type\":\"number\",\"drop_last_bucket\":1,\"truncate_legend\":1,\"max_lines_legend\":1,\"index_pattern_ref_name\":\"metrics_0_index_pattern\"}}"},"coreMigrationVersion":"7.16.3","id":"6432c370-9bbf-11ec-92c9-877156a2a4e9","migrationVersion":{"visualization":"7.14.0"},"references":[{"id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","name":"metrics_0_index_pattern","type":"index-pattern"}],"type":"visualization","updated_at":"2023-03-22T10:45:06.683Z","version":"WzcwLDFd"} +{"excludedObjects":[],"excludedObjectsCount":0,"exportedCount":1,"missingRefCount":0,"missingReferences":[]} \ No newline at end of file diff --git a/ph-ee-env-template/Kibana Visualisations/visualization/Txn Error Counts.ndjson b/ph-ee-env-template/Kibana Visualisations/visualization/Txn Error Counts.ndjson new file mode 100644 index 000000000..6e4f9e8c1 --- /dev/null +++ b/ph-ee-env-template/Kibana Visualisations/visualization/Txn Error Counts.ndjson @@ -0,0 +1,2 @@ +{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[],\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\"}"},"title":"Txn Error Counts","uiStateJSON":"{}","version":1,"visState":"{\"title\":\"Txn Error Counts\",\"type\":\"horizontal_bar\",\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"count\",\"params\":{},\"schema\":\"metric\"},{\"id\":\"3\",\"enabled\":true,\"type\":\"filters\",\"params\":{\"filters\":[{\"input\":{\"query\":\"value.name : \\\"errorDescription\\\" \",\"language\":\"kuery\"},\"label\":\"\"}]},\"schema\":\"group\"},{\"id\":\"2\",\"enabled\":true,\"type\":\"terms\",\"params\":{\"field\":\"value.value\",\"orderBy\":\"1\",\"order\":\"desc\",\"size\":37,\"otherBucket\":false,\"otherBucketLabel\":\"Other\",\"missingBucket\":false,\"missingBucketLabel\":\"Missing\",\"customLabel\":\"Error Description\"},\"schema\":\"segment\"}],\"params\":{\"type\":\"histogram\",\"grid\":{\"categoryLines\":false},\"categoryAxes\":[{\"id\":\"CategoryAxis-1\",\"type\":\"category\",\"position\":\"left\",\"show\":true,\"scale\":{\"type\":\"linear\"},\"labels\":{\"show\":true,\"rotate\":0,\"filter\":false,\"truncate\":200},\"title\":{},\"style\":{}}],\"valueAxes\":[{\"id\":\"ValueAxis-1\",\"name\":\"LeftAxis-1\",\"type\":\"value\",\"position\":\"bottom\",\"show\":true,\"scale\":{\"type\":\"linear\",\"mode\":\"normal\"},\"labels\":{\"show\":true,\"rotate\":75,\"filter\":true,\"truncate\":100},\"title\":{\"text\":\"\"},\"style\":{}}],\"seriesParams\":[{\"show\":true,\"type\":\"histogram\",\"mode\":\"normal\",\"data\":{\"label\":\"Count\",\"id\":\"1\"},\"interpolate\":\"linear\",\"valueAxis\":\"ValueAxis-1\",\"drawLinesBetweenPoints\":true,\"lineWidth\":2,\"showCircles\":true,\"circlesRadius\":1}],\"addTooltip\":true,\"detailedTooltip\":true,\"palette\":{\"type\":\"palette\",\"name\":\"default\"},\"addLegend\":true,\"legendPosition\":\"right\",\"times\":[],\"addTimeMarker\":false,\"truncateLegend\":true,\"maxLegendLines\":1,\"labels\":{},\"radiusRatio\":0,\"thresholdLine\":{\"show\":false,\"value\":10,\"width\":1,\"style\":\"full\",\"color\":\"#E7664C\"}}}"},"coreMigrationVersion":"7.16.3","id":"7d954ce0-9bc2-11ec-92c9-877156a2a4e9","migrationVersion":{"visualization":"7.14.0"},"references":[{"id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","name":"kibanaSavedObjectMeta.searchSourceJSON.index","type":"index-pattern"}],"type":"visualization","updated_at":"2023-03-22T10:45:06.683Z","version":"Wzc4LDFd"} +{"excludedObjects":[],"excludedObjectsCount":0,"exportedCount":1,"missingRefCount":0,"missingReferences":[]} \ No newline at end of file diff --git a/ph-ee-env-template/Kibana Visualisations/visualization/Txn Errors (Non-Recoverable & Recoverable but recently discovered).ndjson b/ph-ee-env-template/Kibana Visualisations/visualization/Txn Errors (Non-Recoverable & Recoverable but recently discovered).ndjson new file mode 100644 index 000000000..1b5a82f7c --- /dev/null +++ b/ph-ee-env-template/Kibana Visualisations/visualization/Txn Errors (Non-Recoverable & Recoverable but recently discovered).ndjson @@ -0,0 +1,2 @@ +{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[]}"},"title":"Txn Errors (Non-Recoverable & Recoverable but recently discovered)","uiStateJSON":"{}","version":1,"visState":"{\"title\":\"Txn Errors (Non-Recoverable & Recoverable but recently discovered)\",\"type\":\"metrics\",\"aggs\":[],\"params\":{\"time_range_mode\":\"entire_time_range\",\"id\":\"768bef68-2db5-4d77-bd9f-579081c6db3b\",\"type\":\"metric\",\"series\":[{\"time_range_mode\":\"entire_time_range\",\"id\":\"9ddc6de7-76ea-4091-8b30-f99120b6aeca\",\"color\":\"#68BC00\",\"split_mode\":\"everything\",\"palette\":{\"type\":\"palette\",\"name\":\"default\"},\"metrics\":[{\"id\":\"a9d2f7ce-efb1-497e-a3df-97120af26471\",\"type\":\"count\"}],\"separate_axis\":0,\"axis_position\":\"right\",\"formatter\":\"default\",\"chart_type\":\"line\",\"line_width\":1,\"point_size\":1,\"fill\":0.5,\"stacked\":\"none\",\"label\":\"Txn Errors \"}],\"time_field\":\"\",\"index_pattern\":\"\",\"use_kibana_indexes\":true,\"interval\":\"\",\"axis_position\":\"left\",\"axis_formatter\":\"number\",\"axis_scale\":\"normal\",\"show_legend\":1,\"truncate_legend\":1,\"max_lines_legend\":1,\"show_grid\":1,\"tooltip_mode\":\"show_all\",\"drop_last_bucket\":0,\"isModelInvalid\":false,\"filter\":{\"query\":\"value.name : \\\"deliveryErrorMessage\\\" or value.name: \\\"errorInformation\\\" \",\"language\":\"kuery\"},\"background_color_rules\":[{\"id\":\"f339f290-9bc0-11ec-a468-43f14c90e9d4\"}]}}"},"coreMigrationVersion":"7.16.3","id":"73343f00-9bc1-11ec-92c9-877156a2a4e9","migrationVersion":{"visualization":"7.14.0"},"references":[],"type":"visualization","updated_at":"2023-03-22T10:45:06.683Z","version":"Wzc0LDFd"} +{"excludedObjects":[],"excludedObjectsCount":0,"exportedCount":1,"missingRefCount":0,"missingReferences":[]} \ No newline at end of file diff --git a/ph-ee-env-template/Kibana Visualisations/visualization/Txn State.ndjson b/ph-ee-env-template/Kibana Visualisations/visualization/Txn State.ndjson new file mode 100644 index 000000000..86be56446 --- /dev/null +++ b/ph-ee-env-template/Kibana Visualisations/visualization/Txn State.ndjson @@ -0,0 +1,2 @@ +{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[]}"},"title":"Txn State","uiStateJSON":"{}","version":1,"visState":"{\"title\":\"Txn State\",\"type\":\"metrics\",\"aggs\":[],\"params\":{\"time_range_mode\":\"entire_time_range\",\"id\":\"f65f4d7b-5772-4b8f-9683-1d65e90b10f8\",\"type\":\"timeseries\",\"series\":[{\"time_range_mode\":\"entire_time_range\",\"id\":\"94b1d2d6-7e1a-4084-a2e9-0215e255a57e\",\"color\":\"#68BC00\",\"split_mode\":\"filters\",\"palette\":{\"type\":\"palette\",\"name\":\"default\"},\"metrics\":[{\"id\":\"0e89671e-87aa-432b-8c3d-370cc21ef53f\",\"type\":\"count\"}],\"separate_axis\":0,\"axis_position\":\"right\",\"formatter\":\"default\",\"chart_type\":\"line\",\"line_width\":1,\"point_size\":1,\"fill\":0.5,\"stacked\":\"none\",\"split_filters\":[{\"filter\":{\"query\":\"value.bpmnElementType : \\\"END_EVENT\\\" and intent : \\\"ELEMENT_COMPLETED\\\" \",\"language\":\"kuery\"},\"label\":\"Completed\",\"color\":\"rgba(101,147,240,1)\",\"id\":\"2b3923f0-1970-11ed-850c-b3a4b04b67bd\"},{\"filter\":{\"query\":\"value.bpmnElementType : \\\"END_EVENT\\\" and value.elementId : \\\"Event_1bh40y1\\\" and intent : \\\"ELEMENT_COMPLETED\\\" \",\"language\":\"kuery\"},\"label\":\"Success (Without notifications)\",\"color\":\"rgba(160,243,104,1)\",\"id\":\"32023370-1970-11ed-850c-b3a4b04b67bd\"},{\"filter\":{\"query\":\"value.bpmnElementType : \\\"END_EVENT\\\" and value.elementId : \\\"End\\\" and intent : \\\"ELEMENT_COMPLETED\\\" \",\"language\":\"kuery\"},\"label\":\"Failure (Without notifications) \",\"color\":\"rgba(231,102,76,1)\",\"id\":\"32fd5c50-1970-11ed-850c-b3a4b04b67bd\"},{\"filter\":{\"query\":\"value.bpmnElementType : \\\"END_EVENT\\\" and intent : \\\"ELEMENT_COMPLETED\\\" and value.elementId : \\\"sucess\\\" \",\"language\":\"kuery\"},\"label\":\"Completed (Successful Notification)\",\"color\":\"rgba(170,101,86,1)\",\"id\":\"3393f700-1970-11ed-850c-b3a4b04b67bd\"},{\"filter\":{\"query\":\"value.bpmnElementType : \\\"END_EVENT\\\" and value.elementId : \\\"failure\\\" and intent : \\\"ELEMENT_COMPLETED\\\" \",\"language\":\"kuery\"},\"label\":\"Completed (Failed Notification)\",\"color\":\"#68BC00\",\"id\":\"34c4fcf0-1970-11ed-850c-b3a4b04b67bd\"},{\"filter\":{\"query\":\"value.bpmnElementType : \\\"END_EVENT\\\" and (value.elementId : \\\"sucess\\\" or value.elementId : \\\"failure\\\") and intent : \\\"ELEMENT_COMPLETED\\\" \",\"language\":\"kuery\"},\"label\":\"Failed Txns (Notifications Path)\",\"color\":\"rgba(185,168,136,1)\",\"id\":\"39d40060-1970-11ed-850c-b3a4b04b67bd\"}],\"label\":\"\"}],\"time_field\":\"\",\"index_pattern\":\"\",\"use_kibana_indexes\":true,\"interval\":\"\",\"axis_position\":\"left\",\"axis_formatter\":\"number\",\"axis_scale\":\"normal\",\"show_legend\":1,\"truncate_legend\":1,\"max_lines_legend\":1,\"show_grid\":1,\"tooltip_mode\":\"show_all\",\"drop_last_bucket\":0}}"},"coreMigrationVersion":"7.16.3","id":"1af053f0-1971-11ed-9d91-37684d8f5c4b","migrationVersion":{"visualization":"7.14.0"},"references":[],"type":"visualization","updated_at":"2023-03-22T10:45:06.683Z","version":"WzU2LDFd"} +{"excludedObjects":[],"excludedObjectsCount":0,"exportedCount":1,"missingRefCount":0,"missingReferences":[]} \ No newline at end of file diff --git a/ph-ee-env-template/Kibana Visualisations/visualization/Variable Input.ndjson b/ph-ee-env-template/Kibana Visualisations/visualization/Variable Input.ndjson new file mode 100644 index 000000000..603460c98 --- /dev/null +++ b/ph-ee-env-template/Kibana Visualisations/visualization/Variable Input.ndjson @@ -0,0 +1,2 @@ +{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[]}"},"title":"Variable Input","uiStateJSON":"{}","version":1,"visState":"{\"title\":\"Variable Input\",\"type\":\"input_control_vis\",\"aggs\":[],\"params\":{\"controls\":[{\"id\":\"1633538407315\",\"fieldName\":\"value.name\",\"parent\":\"\",\"label\":\"VariableName\",\"type\":\"list\",\"options\":{\"type\":\"terms\",\"multiselect\":true,\"dynamicOptions\":true,\"size\":5,\"order\":\"desc\"},\"indexPatternRefName\":\"control_0_index_pattern\"}],\"updateFiltersOnChange\":false,\"useTimeFilter\":false,\"pinFilters\":false}}"},"coreMigrationVersion":"7.16.3","id":"2b5132f0-26c4-11ec-95b3-cb627b5ccd4b","migrationVersion":{"visualization":"7.14.0"},"references":[{"id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","name":"control_0_index_pattern","type":"index-pattern"}],"type":"visualization","updated_at":"2023-03-22T10:45:06.683Z","version":"WzU4LDFd"} +{"excludedObjects":[],"excludedObjectsCount":0,"exportedCount":1,"missingRefCount":0,"missingReferences":[]} \ No newline at end of file diff --git a/ph-ee-env-template/Kibana Visualisations/visualization/Vega Visualisation Draft.ndjson b/ph-ee-env-template/Kibana Visualisations/visualization/Vega Visualisation Draft.ndjson new file mode 100644 index 000000000..cabc675d8 --- /dev/null +++ b/ph-ee-env-template/Kibana Visualisations/visualization/Vega Visualisation Draft.ndjson @@ -0,0 +1,2 @@ +{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"language\":\"kuery\",\"query\":\"\"},\"filter\":[]}"},"title":"Vega Visualisation Draft","uiStateJSON":"{}","version":1,"visState":"{\"title\":\"Vega Visualisation Draft\",\"type\":\"vega\",\"aggs\":[],\"params\":{\"spec\":\"{\\n \\\"$schema\\\": \\\"https://vega.github.io/schema/vega-lite/v5.json\\\",\\n \\\"title\\\": \\\"Event counts from all indexes\\\",\\n \\\"data\\\": {\\n \\\"url\\\": {\\n \\\"index\\\": \\\"zeebe-payments\\\",\\n \\\"body\\\": {\\n \\\"aggs\\\": {\\n \\\"terms\\\": {\\\"field\\\": \\\"processInstanceKey\\\"},\\n \\\"categories\\\": {\\n \\\"aggs\\\": {\\n \\\"duration\\\": {\\n \\\"scripted_metric\\\": {\\n \\\"init_script\\\": \\\"def startTime = doc['originDate'].value.getMillis();def stopTime = doc['timestamp'].value.getMillis();\\\",\\n \\\"map_script\\\": \\\"def time = stopTime-startTime\\\",\\n \\\"combine_script\\\": \\\"time\\\",\\n \\\"reduce_script\\\": \\\"return time;\\\"\\n }\\n }\\n }\\n }\\n },\\n \\\"size\\\": 0,\\n \\\"query\\\": {\\\"bool\\\": {\\\"must\\\": [], \\\"filter\\\": [], \\\"should\\\": []}}\\n }\\n },\\n \\\"format\\\": {\\\"property\\\": \\\"aggregations.categories.buckets\\\"}\\n },\\n \\\"mark\\\": \\\"bar\\\",\\n \\\"encoding\\\": {\\n \\\"x\\\": {\\n \\\"field\\\": \\\"duration.value\\\",\\n \\\"type\\\": \\\"temporal\\\",\\n \\\"timeUnit\\\": \\\"seconds\\\",\\n \\\"axis\\\": {\\\"title\\\": \\\"Time taken in seconds \\\"}\\n },\\n \\\"y\\\": {\\\"field\\\": \\\"key\\\", \\\"type\\\": \\\"nominal\\\", \\\"axis\\\": {\\\"title\\\": \\\"Tasks\\\"}},\\n \\\"color\\\": {\\\"field\\\": \\\"key\\\", \\\"type\\\": \\\"nominal\\\"}\\n },\\n \\\"layer\\\": [\\n {\\n \\\"mark\\\": \\\"rect\\\",\\n \\\"encoding\\\": {\\n \\\"color\\\": {\\n \\\"field\\\": \\\"duration.value\\\",\\n \\\"type\\\": \\\"temporal\\\",\\n \\\"timeUnit\\\": \\\"seconds\\\",\\n \\\"title\\\": \\\"Time elapsed\\\",\\n \\\"legend\\\": {\\\"direction\\\": \\\"horizontal\\\", \\\"gradientLength\\\": 120}\\n }\\n }\\n }\\n ]\\n}\"}}"},"coreMigrationVersion":"7.16.3","id":"8b628a10-829d-11ec-94f2-7f85f327d8f2","migrationVersion":{"visualization":"7.14.0"},"references":[],"type":"visualization","updated_at":"2023-03-22T10:45:06.683Z","version":"WzgzLDFd"} +{"excludedObjects":[],"excludedObjectsCount":0,"exportedCount":1,"missingRefCount":0,"missingReferences":[]} \ No newline at end of file diff --git a/ph-ee-env-template/Kibana Visualisations/visualization/Weekly Spillover.ndjson b/ph-ee-env-template/Kibana Visualisations/visualization/Weekly Spillover.ndjson new file mode 100644 index 000000000..777a73954 --- /dev/null +++ b/ph-ee-env-template/Kibana Visualisations/visualization/Weekly Spillover.ndjson @@ -0,0 +1,2 @@ +{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[]}"},"title":"Weekly Spillover","uiStateJSON":"{}","version":1,"visState":"{\"title\":\"Weekly Spillover\",\"type\":\"metrics\",\"aggs\":[],\"params\":{\"time_range_mode\":\"entire_time_range\",\"id\":\"397400b6-7c61-4325-a120-72d2c30e9c1a\",\"type\":\"timeseries\",\"series\":[{\"time_range_mode\":\"entire_time_range\",\"id\":\"d91a77ae-ac23-46f9-a619-0e734301dc9d\",\"color\":\"#68BC00\",\"split_mode\":\"terms\",\"palette\":{\"type\":\"palette\",\"name\":\"default\"},\"metrics\":[{\"id\":\"89800a22-25d7-4b6e-b0b9-5139b624bb30\",\"type\":\"count\"}],\"separate_axis\":0,\"axis_position\":\"right\",\"formatter\":\"default\",\"chart_type\":\"line\",\"line_width\":1,\"point_size\":1,\"fill\":0.5,\"stacked\":\"none\",\"label\":\"Weekly Spillover\",\"terms_field\":\"value.bpmnElementType\"}],\"time_field\":\"\",\"index_pattern\":\"\",\"use_kibana_indexes\":true,\"interval\":\"1w\",\"axis_position\":\"left\",\"axis_formatter\":\"number\",\"axis_scale\":\"normal\",\"show_legend\":1,\"truncate_legend\":1,\"max_lines_legend\":1,\"show_grid\":1,\"tooltip_mode\":\"show_all\",\"drop_last_bucket\":0,\"isModelInvalid\":false,\"filter\":{\"query\":\"(value.bpmnElementType : \\\"END_EVENT\\\" or value.bpmnElementType : \\\"START_EVENT\\\" ) and intent : \\\"ELEMENT_ACTIVATED\\\" \",\"language\":\"kuery\"}}}"},"coreMigrationVersion":"7.16.3","id":"4d7c9640-38b5-11ed-9a31-f1f0ccd9a3df","migrationVersion":{"visualization":"7.14.0"},"references":[],"type":"visualization","updated_at":"2023-03-22T10:45:06.683Z","version":"WzY5LDFd"} +{"excludedObjects":[],"excludedObjectsCount":0,"exportedCount":1,"missingRefCount":0,"missingReferences":[]} \ No newline at end of file diff --git a/ph-ee-env-template/LICENSE b/ph-ee-env-template/LICENSE new file mode 100644 index 000000000..a612ad981 --- /dev/null +++ b/ph-ee-env-template/LICENSE @@ -0,0 +1,373 @@ +Mozilla Public License Version 2.0 +================================== + +1. Definitions +-------------- + +1.1. "Contributor" + means each individual or legal entity that creates, contributes to + the creation of, or owns Covered Software. + +1.2. "Contributor Version" + means the combination of the Contributions of others (if any) used + by a Contributor and that particular Contributor's Contribution. + +1.3. "Contribution" + means Covered Software of a particular Contributor. + +1.4. "Covered Software" + means Source Code Form to which the initial Contributor has attached + the notice in Exhibit A, the Executable Form of such Source Code + Form, and Modifications of such Source Code Form, in each case + including portions thereof. + +1.5. "Incompatible With Secondary Licenses" + means + + (a) that the initial Contributor has attached the notice described + in Exhibit B to the Covered Software; or + + (b) that the Covered Software was made available under the terms of + version 1.1 or earlier of the License, but not also under the + terms of a Secondary License. + +1.6. "Executable Form" + means any form of the work other than Source Code Form. + +1.7. "Larger Work" + means a work that combines Covered Software with other material, in + a separate file or files, that is not Covered Software. + +1.8. "License" + means this document. + +1.9. "Licensable" + means having the right to grant, to the maximum extent possible, + whether at the time of the initial grant or subsequently, any and + all of the rights conveyed by this License. + +1.10. "Modifications" + means any of the following: + + (a) any file in Source Code Form that results from an addition to, + deletion from, or modification of the contents of Covered + Software; or + + (b) any new file in Source Code Form that contains any Covered + Software. + +1.11. "Patent Claims" of a Contributor + means any patent claim(s), including without limitation, method, + process, and apparatus claims, in any patent Licensable by such + Contributor that would be infringed, but for the grant of the + License, by the making, using, selling, offering for sale, having + made, import, or transfer of either its Contributions or its + Contributor Version. + +1.12. "Secondary License" + means either the GNU General Public License, Version 2.0, the GNU + Lesser General Public License, Version 2.1, the GNU Affero General + Public License, Version 3.0, or any later versions of those + licenses. + +1.13. "Source Code Form" + means the form of the work preferred for making modifications. + +1.14. "You" (or "Your") + means an individual or a legal entity exercising rights under this + License. For legal entities, "You" includes any entity that + controls, is controlled by, or is under common control with You. For + purposes of this definition, "control" means (a) the power, direct + or indirect, to cause the direction or management of such entity, + whether by contract or otherwise, or (b) ownership of more than + fifty percent (50%) of the outstanding shares or beneficial + ownership of such entity. + +2. License Grants and Conditions +-------------------------------- + +2.1. Grants + +Each Contributor hereby grants You a world-wide, royalty-free, +non-exclusive license: + +(a) under intellectual property rights (other than patent or trademark) + Licensable by such Contributor to use, reproduce, make available, + modify, display, perform, distribute, and otherwise exploit its + Contributions, either on an unmodified basis, with Modifications, or + as part of a Larger Work; and + +(b) under Patent Claims of such Contributor to make, use, sell, offer + for sale, have made, import, and otherwise transfer either its + Contributions or its Contributor Version. + +2.2. Effective Date + +The licenses granted in Section 2.1 with respect to any Contribution +become effective for each Contribution on the date the Contributor first +distributes such Contribution. + +2.3. Limitations on Grant Scope + +The licenses granted in this Section 2 are the only rights granted under +this License. No additional rights or licenses will be implied from the +distribution or licensing of Covered Software under this License. +Notwithstanding Section 2.1(b) above, no patent license is granted by a +Contributor: + +(a) for any code that a Contributor has removed from Covered Software; + or + +(b) for infringements caused by: (i) Your and any other third party's + modifications of Covered Software, or (ii) the combination of its + Contributions with other software (except as part of its Contributor + Version); or + +(c) under Patent Claims infringed by Covered Software in the absence of + its Contributions. + +This License does not grant any rights in the trademarks, service marks, +or logos of any Contributor (except as may be necessary to comply with +the notice requirements in Section 3.4). + +2.4. Subsequent Licenses + +No Contributor makes additional grants as a result of Your choice to +distribute the Covered Software under a subsequent version of this +License (see Section 10.2) or under the terms of a Secondary License (if +permitted under the terms of Section 3.3). + +2.5. Representation + +Each Contributor represents that the Contributor believes its +Contributions are its original creation(s) or it has sufficient rights +to grant the rights to its Contributions conveyed by this License. + +2.6. Fair Use + +This License is not intended to limit any rights You have under +applicable copyright doctrines of fair use, fair dealing, or other +equivalents. + +2.7. Conditions + +Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted +in Section 2.1. + +3. Responsibilities +------------------- + +3.1. Distribution of Source Form + +All distribution of Covered Software in Source Code Form, including any +Modifications that You create or to which You contribute, must be under +the terms of this License. You must inform recipients that the Source +Code Form of the Covered Software is governed by the terms of this +License, and how they can obtain a copy of this License. You may not +attempt to alter or restrict the recipients' rights in the Source Code +Form. + +3.2. Distribution of Executable Form + +If You distribute Covered Software in Executable Form then: + +(a) such Covered Software must also be made available in Source Code + Form, as described in Section 3.1, and You must inform recipients of + the Executable Form how they can obtain a copy of such Source Code + Form by reasonable means in a timely manner, at a charge no more + than the cost of distribution to the recipient; and + +(b) You may distribute such Executable Form under the terms of this + License, or sublicense it under different terms, provided that the + license for the Executable Form does not attempt to limit or alter + the recipients' rights in the Source Code Form under this License. + +3.3. Distribution of a Larger Work + +You may create and distribute a Larger Work under terms of Your choice, +provided that You also comply with the requirements of this License for +the Covered Software. If the Larger Work is a combination of Covered +Software with a work governed by one or more Secondary Licenses, and the +Covered Software is not Incompatible With Secondary Licenses, this +License permits You to additionally distribute such Covered Software +under the terms of such Secondary License(s), so that the recipient of +the Larger Work may, at their option, further distribute the Covered +Software under the terms of either this License or such Secondary +License(s). + +3.4. Notices + +You may not remove or alter the substance of any license notices +(including copyright notices, patent notices, disclaimers of warranty, +or limitations of liability) contained within the Source Code Form of +the Covered Software, except that You may alter any license notices to +the extent required to remedy known factual inaccuracies. + +3.5. Application of Additional Terms + +You may choose to offer, and to charge a fee for, warranty, support, +indemnity or liability obligations to one or more recipients of Covered +Software. However, You may do so only on Your own behalf, and not on +behalf of any Contributor. You must make it absolutely clear that any +such warranty, support, indemnity, or liability obligation is offered by +You alone, and You hereby agree to indemnify every Contributor for any +liability incurred by such Contributor as a result of warranty, support, +indemnity or liability terms You offer. You may include additional +disclaimers of warranty and limitations of liability specific to any +jurisdiction. + +4. Inability to Comply Due to Statute or Regulation +--------------------------------------------------- + +If it is impossible for You to comply with any of the terms of this +License with respect to some or all of the Covered Software due to +statute, judicial order, or regulation then You must: (a) comply with +the terms of this License to the maximum extent possible; and (b) +describe the limitations and the code they affect. Such description must +be placed in a text file included with all distributions of the Covered +Software under this License. Except to the extent prohibited by statute +or regulation, such description must be sufficiently detailed for a +recipient of ordinary skill to be able to understand it. + +5. Termination +-------------- + +5.1. The rights granted under this License will terminate automatically +if You fail to comply with any of its terms. However, if You become +compliant, then the rights granted under this License from a particular +Contributor are reinstated (a) provisionally, unless and until such +Contributor explicitly and finally terminates Your grants, and (b) on an +ongoing basis, if such Contributor fails to notify You of the +non-compliance by some reasonable means prior to 60 days after You have +come back into compliance. Moreover, Your grants from a particular +Contributor are reinstated on an ongoing basis if such Contributor +notifies You of the non-compliance by some reasonable means, this is the +first time You have received notice of non-compliance with this License +from such Contributor, and You become compliant prior to 30 days after +Your receipt of the notice. + +5.2. If You initiate litigation against any entity by asserting a patent +infringement claim (excluding declaratory judgment actions, +counter-claims, and cross-claims) alleging that a Contributor Version +directly or indirectly infringes any patent, then the rights granted to +You by any and all Contributors for the Covered Software under Section +2.1 of this License shall terminate. + +5.3. In the event of termination under Sections 5.1 or 5.2 above, all +end user license agreements (excluding distributors and resellers) which +have been validly granted by You or Your distributors under this License +prior to termination shall survive termination. + +************************************************************************ +* * +* 6. Disclaimer of Warranty * +* ------------------------- * +* * +* Covered Software is provided under this License on an "as is" * +* basis, without warranty of any kind, either expressed, implied, or * +* statutory, including, without limitation, warranties that the * +* Covered Software is free of defects, merchantable, fit for a * +* particular purpose or non-infringing. The entire risk as to the * +* quality and performance of the Covered Software is with You. * +* Should any Covered Software prove defective in any respect, You * +* (not any Contributor) assume the cost of any necessary servicing, * +* repair, or correction. This disclaimer of warranty constitutes an * +* essential part of this License. No use of any Covered Software is * +* authorized under this License except under this disclaimer. * +* * +************************************************************************ + +************************************************************************ +* * +* 7. Limitation of Liability * +* -------------------------- * +* * +* Under no circumstances and under no legal theory, whether tort * +* (including negligence), contract, or otherwise, shall any * +* Contributor, or anyone who distributes Covered Software as * +* permitted above, be liable to You for any direct, indirect, * +* special, incidental, or consequential damages of any character * +* including, without limitation, damages for lost profits, loss of * +* goodwill, work stoppage, computer failure or malfunction, or any * +* and all other commercial damages or losses, even if such party * +* shall have been informed of the possibility of such damages. This * +* limitation of liability shall not apply to liability for death or * +* personal injury resulting from such party's negligence to the * +* extent applicable law prohibits such limitation. Some * +* jurisdictions do not allow the exclusion or limitation of * +* incidental or consequential damages, so this exclusion and * +* limitation may not apply to You. * +* * +************************************************************************ + +8. Litigation +------------- + +Any litigation relating to this License may be brought only in the +courts of a jurisdiction where the defendant maintains its principal +place of business and such litigation shall be governed by laws of that +jurisdiction, without reference to its conflict-of-law provisions. +Nothing in this Section shall prevent a party's ability to bring +cross-claims or counter-claims. + +9. Miscellaneous +---------------- + +This License represents the complete agreement concerning the subject +matter hereof. If any provision of this License is held to be +unenforceable, such provision shall be reformed only to the extent +necessary to make it enforceable. Any law or regulation which provides +that the language of a contract shall be construed against the drafter +shall not be used to construe this License against a Contributor. + +10. Versions of the License +--------------------------- + +10.1. New Versions + +Mozilla Foundation is the license steward. Except as provided in Section +10.3, no one other than the license steward has the right to modify or +publish new versions of this License. Each version will be given a +distinguishing version number. + +10.2. Effect of New Versions + +You may distribute the Covered Software under the terms of the version +of the License under which You originally received the Covered Software, +or under the terms of any subsequent version published by the license +steward. + +10.3. Modified Versions + +If you create software not governed by this License, and you want to +create a new license for such software, you may create and use a +modified version of this License if you rename the license and remove +any references to the name of the license steward (except to note that +such modified license differs from this License). + +10.4. Distributing Source Code Form that is Incompatible With Secondary +Licenses + +If You choose to distribute Source Code Form that is Incompatible With +Secondary Licenses under the terms of this version of the License, the +notice described in Exhibit B of this License must be attached. + +Exhibit A - Source Code Form License Notice +------------------------------------------- + + This Source Code Form is subject to the terms of the Mozilla Public + License, v. 2.0. If a copy of the MPL was not distributed with this + file, You can obtain one at http://mozilla.org/MPL/2.0/. + +If it is not possible or desirable to put the notice in a particular +file, then You may include the notice in a location (such as a LICENSE +file in a relevant directory) where a recipient would be likely to look +for such a notice. + +You may add additional accurate notices of copyright ownership. + +Exhibit B - "Incompatible With Secondary Licenses" Notice +--------------------------------------------------------- + + This Source Code Form is "Incompatible With Secondary Licenses", as + defined by the Mozilla Public License, v. 2.0. diff --git a/ph-ee-env-template/PostmanCollections/CoDevelop Sandbox_env b/ph-ee-env-template/PostmanCollections/CoDevelop Sandbox_env new file mode 100644 index 000000000..ba57388b8 --- /dev/null +++ b/ph-ee-env-template/PostmanCollections/CoDevelop Sandbox_env @@ -0,0 +1,93 @@ +{ + "id": "f03f5d87-7f98-42c7-98c4-3e49c6b9edc1", + "name": "CoDevelop Sandbox", + "values": [ + { + "key": "ChannelHostName", + "value": "channel.mifos.g2pconnect.io", + "type": "default", + "enabled": true + }, + { + "key": "OperationsHostName", + "value": "ops-bk.mifos.g2pconnect.io", + "type": "default", + "enabled": true + }, + { + "key": "BulkHostName", + "value": "bulk-connector.mifos.g2pconnect.io", + "type": "default", + "enabled": true + }, + { + "key": "batchId", + "value": "d7a87db1-e925-4ac0-b8ec-6af87c6110d4", + "type": "default", + "enabled": true + }, + { + "key": "ZeebeOpsHostName", + "value": "https://zeebeops.mifos.g2pconnect.io", + "type": "default", + "enabled": true + }, + { + "key": "PlatformTenant", + "value": "rhino", + "type": "default", + "enabled": true + }, + { + "key": "pageNo", + "value": "1", + "type": "default", + "enabled": true + }, + { + "key": "status", + "value": "ALL", + "type": "default", + "enabled": true + }, + { + "key": "TenantName", + "value": "gorilla", + "type": "default", + "enabled": true + }, + { + "key": "pageSize", + "value": "20", + "type": "default", + "enabled": true + }, + { + "key": "messagegateway", + "value": "messagegateway.mifos.g2pconnect.io", + "type": "default", + "enabled": true + }, + { + "key": "communityapp", + "value": "communityapp.mifos.g2pconnect.io", + "type": "default", + "enabled": true + }, + { + "key": "kibana", + "value": "analytics.mifos.g2pconnect.io", + "type": "default", + "enabled": true + }, + { + "key": "fineractserver", + "value": "rhino.mifos.g2pconnect.io", + "type": "default", + "enabled": true + } + ], + "_postman_variable_scope": "environment", + "_postman_exported_at": "2022-09-23T09:29:02.223Z", + "_postman_exported_using": "Postman/9.31.9" +} diff --git a/ph-ee-env-template/PostmanCollections/Collection OAF.postman_collection.json b/ph-ee-env-template/PostmanCollections/Collection OAF.postman_collection.json new file mode 100644 index 000000000..94a749ac0 --- /dev/null +++ b/ph-ee-env-template/PostmanCollections/Collection OAF.postman_collection.json @@ -0,0 +1,64 @@ +{ + "info": { + "_postman_id": "ca4a575d-03b8-4873-898d-8a7cf6e2e46e", + "name": "Collection OAF", + "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json", + "_exporter_id": "18201748" + }, + "item": [ + { + "name": "channel request", + "request": { + "auth": { + "type": "apikey", + "apikey": [ + { + "key": "key", + "value": "api-key", + "type": "string" + }, + { + "key": "value", + "value": "{{channelApiKey}}", + "type": "string" + }, + { + "key": "in", + "value": "header", + "type": "string" + } + ] + }, + "method": "POST", + "header": [ + { + "key": "Platform-TenantId", + "value": "{{TenantName}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"payer\": [\n {\n \"key\": \"MSISDN\",\n \"value\": \"254708374149\"\n },\n {\n \"key\": \"ACCOUNTID\",\n \"value\": \"24450523\"\n }\n ],\n \"amount\": {\n \"amount\": \"1\",\n \"currency\": \"USD\"\n },\n \"transactionType\": {\n \"scenario\": \"MPESA\",\n \"subScenario\": \"BUYGOODS\",\n \"initiator\": \"PAYEE\",\n \"initiatorType\": \"BUSINESS\"\n }\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{ChannelHostName}}/channel/collection", + "host": [ + "{{ChannelHostName}}" + ], + "path": [ + "channel", + "collection" + ] + }, + "description": "Cloud API" + }, + "response": [] + } + ] +} \ No newline at end of file diff --git a/ph-ee-env-template/PostmanCollections/ES ILM Policy and Snapshot Register API.json b/ph-ee-env-template/PostmanCollections/ES ILM Policy and Snapshot Register API.json new file mode 100644 index 000000000..a6e6f1f9e --- /dev/null +++ b/ph-ee-env-template/PostmanCollections/ES ILM Policy and Snapshot Register API.json @@ -0,0 +1,151 @@ +{ + "info": { + "_postman_id": "afde8ff7-69e1-4187-b3a9-4fa6d0693cb6", + "name": "Elastic Search Audit Trial", + "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json", + "_exporter_id": "21253421" + }, + "item": [ + { + "name": "Create/Update ILM Policy", + "request": { + "method": "PUT", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"policy\": {\n \"_meta\": {\n \"description\": {{PolicyDescription}}\n },\n \"phases\": {\n \"hot\": {\n \"min_age\": {{HotMinAge}},\n \"actions\": {\n \"rollover\": {\n \"max_age\": {{HotRolloverMaxAge}},\n \"max_size\": {{HotRolloverMaxSize}}\n },\n \"forcemerge\": {\n \"max_num_segments\": {{MaxNumSegments}}\n }\n }\n },\n \"warm\": {\n \"min_age\": {{WarmMinAge}},\n \"actions\": {\n \"forcemerge\": {\n }\n }\n },\n \"cold\": {\n \"min_age\": {{ColdMinAge}},\n \"actions\": {\n \"freeze\": {}\n }\n },\n \"delete\": {\n \"min_age\": {{DeleteMinAge}},\n \"actions\": {\n \"delete\": {}\n }\n }\n }\n }\n}\n" + }, + "url": { + "raw": "{{ElasticSearchHost}}/_ilm/policy/{{PolicyName}}", + "host": [ + "{{ElasticSearchHost}}" + ], + "path": [ + "_ilm", + "policy", + "{{PolicyName}}" + ] + } + }, + "response": [] + }, + { + "name": "Cluster Settings", + "request": { + "method": "PUT", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"persistent\": {\n \"cloud.aws.access_key\": {{AccessKey}},\n \"cloud.aws.secret_key\": {{SecretKey}}\n }\n}" + }, + "url": { + "raw": "{{ElasticSearchHost}}/_cluster/settings", + "host": [ + "{{ElasticSearchHost}}" + ], + "path": [ + "_cluster", + "settings" + ] + } + }, + "response": [] + }, + { + "name": "Register Snapshot", + "request": { + "method": "PUT", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"type\": \"s3\",\n \"settings\": {\n \"bucket\": {{BucketName}},\n \"region\": {{AWSRegion}},\n \"access_key\": {{AccessKey}},\n \"secret_key\": {{SecretKey}},\n \"base_path\": {{BasePath}},\n \"compress\": true\n }\n}" + }, + "url": { + "raw": "{{ElasticSearchHost}}/_snapshot/{{SnapshotRepoName}}", + "host": [ + "{{ElasticSearchHost}}" + ], + "path": [ + "_snapshot", + "{{SnapshotRepoName}}" + ] + } + }, + "response": [] + }, + { + "name": "Create a Snapshot", + "request": { + "method": "PUT", + "header": [], + "url": { + "raw": "{{ElasticSearchHost}}/_snapshot/{{SnapshotRepoName}}/{{SnapshotName}}?wait_for_completion=true", + "host": [ + "{{ElasticSearchHost}}" + ], + "path": [ + "_snapshot", + "{{SnapshotRepoName}}", + "{{SnapshotName}}" + ], + "query": [ + { + "key": "wait_for_completion", + "value": "true" + } + ] + } + }, + "response": [] + }, + { + "name": "Backup Snapshot", + "request": { + "method": "PUT", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"schedule\": \"0 30 1 * * ?\", \n \"name\": \"\", \n \"repository\": \"my_repository\", \n \"config\": {\n \"indices\": \"*\", \n \"include_global_state\": true \n },\n \"retention\": { \n \"expire_after\": \"30d\",\n \"min_count\": 5,\n \"max_count\": 50\n }\n}" + }, + "url": { + "raw": "{{ElasticSearchHost}}/_slm/policy/{{SnapshotName}}?pretty", + "host": [ + "{{ElasticSearchHost}}" + ], + "path": [ + "_slm", + "policy", + "{{SnapshotName}}" + ], + "query": [ + { + "key": "pretty", + "value": null + } + ] + } + }, + "response": [] + } + ] +} \ No newline at end of file diff --git a/ph-ee-env-template/PostmanCollections/Environment/ES_ILM_Policy_Snapshot_enviroment.json b/ph-ee-env-template/PostmanCollections/Environment/ES_ILM_Policy_Snapshot_enviroment.json new file mode 100644 index 000000000..adb456eac --- /dev/null +++ b/ph-ee-env-template/PostmanCollections/Environment/ES_ILM_Policy_Snapshot_enviroment.json @@ -0,0 +1,111 @@ +{ + "id": "338e33f6-d3f9-44d5-b12e-215cbc0ff997", + "name": "ES ILM Plicy and Snapshot", + "values": [ + { + "key": "ElasticSearchHost", + "value": "http://localhost:9200", + "type": "default", + "enabled": true + }, + { + "key": "PolicyName", + "value": "Test", + "type": "default", + "enabled": true + }, + { + "key": "PolicyDescription", + "value": "Test", + "type": "default", + "enabled": true + }, + { + "key": "HotMinAge", + "value": "30", + "type": "default", + "enabled": true + }, + { + "key": "HotRolloverMaxAge", + "value": "1", + "type": "default", + "enabled": true + }, + { + "key": "HotRolloverMaxSize", + "value": "5", + "type": "default", + "enabled": true + }, + { + "key": "MaxNumSegments", + "value": "10", + "type": "default", + "enabled": true + }, + { + "key": "WarmMinAge", + "value": "10", + "type": "default", + "enabled": true + }, + { + "key": "ColdMinAge", + "value": "10", + "type": "default", + "enabled": true + }, + { + "key": "DeleteMinAge", + "value": "30", + "type": "default", + "enabled": true + }, + { + "key": "BucketName", + "value": "", + "type": "default", + "enabled": true + }, + { + "key": "AWSRegion", + "value": "", + "type": "default", + "enabled": true + }, + { + "key": "AccessKey", + "value": "", + "type": "default", + "enabled": true + }, + { + "key": "SecretKey", + "value": "", + "type": "default", + "enabled": true + }, + { + "key": "BasePath", + "value": "", + "type": "default", + "enabled": true + }, + { + "key": "SnapshotRepoName", + "value": "", + "type": "default", + "enabled": true + }, + { + "key": "SnapshotName", + "value": "", + "type": "default", + "enabled": true + } + ], + "_postman_variable_scope": "environment", + "_postman_exported_at": "2023-05-17T10:45:43.889Z", + "_postman_exported_using": "Postman/10.13.3" +} \ No newline at end of file diff --git a/ph-ee-env-template/PostmanCollections/Environment/FineractCoDevelop_environment.json b/ph-ee-env-template/PostmanCollections/Environment/FineractCoDevelop_environment.json new file mode 100644 index 000000000..ada316666 --- /dev/null +++ b/ph-ee-env-template/PostmanCollections/Environment/FineractCoDevelop_environment.json @@ -0,0 +1,177 @@ +{ + "id": "3fac2892-b718-45bd-9637-71f3b675182e", + "name": "FineractCoDevelop Sandbox", + "values": [ + { + "key": "fineract-provider", + "value": "", + "type": "default", + "enabled": false + }, + { + "key": "Host1", + "value": "fynams.mifos.g2pconnect.io/fineract-provider/api/v1", + "type": "default", + "enabled": true + }, + { + "key": "Host2", + "value": "fynams.mifos.g2pconnect.io/fineract-provider/api/v1", + "type": "default", + "enabled": true + }, + { + "key": "Tenant1", + "value": "rhino", + "type": "default", + "enabled": true + }, + { + "key": "Tenant2", + "value": "gorilla", + "type": "default", + "enabled": true + }, + { + "key": "authToken", + "value": "Basic bWlmb3M6cGFzc3dvcmQ=", + "type": "default", + "enabled": true + }, + { + "key": "submissionDate", + "value": "02 January 2023", + "type": "default", + "enabled": true + }, + { + "key": "approvedDate", + "value": "01 December 2022", + "type": "default", + "enabled": true + }, + { + "key": "activationDate", + "value": "01 December 2022", + "type": "default", + "enabled": true + }, + { + "key": "savingsProductId1", + "value": "1", + "type": "default", + "enabled": true + }, + { + "key": "savingsProductId2", + "value": "1", + "type": "default", + "enabled": true + }, + { + "key": "firstname", + "value": "Geetha", + "type": "default", + "enabled": true + }, + { + "key": "lastname", + "value": "bai", + "type": "default", + "enabled": true + }, + { + "key": "payerClientId", + "value": "1", + "type": "default", + "enabled": true + }, + { + "key": "payeeClientId", + "value": "1", + "type": "default", + "enabled": true + }, + { + "key": "savingsAccId", + "value": "1", + "type": "default", + "enabled": true + }, + { + "key": "savingsAccId2", + "value": "1", + "type": "default", + "enabled": true + }, + { + "key": "identifierType", + "value": "MSISDN", + "type": "default", + "enabled": true + }, + { + "key": "payer_identifier", + "value": "123", + "type": "default", + "enabled": true + }, + { + "key": "payee_identifier", + "value": "123", + "type": "default", + "enabled": true + }, + { + "key": "transactionDate", + "value": "01 December 2022", + "type": "default", + "enabled": true + }, + { + "key": "name", + "value": "meera", + "type": "default", + "enabled": true + }, + { + "key": "shortName", + "value": "1", + "type": "default", + "enabled": true + }, + { + "key": "externalId1", + "value": "s", + "type": "default", + "enabled": true + }, + { + "key": "externalId2", + "value": "s", + "type": "default", + "enabled": true + }, + { + "key": "name2", + "value": "jack", + "type": "default", + "enabled": true + }, + { + "key": "shortName2", + "value": "1", + "type": "default", + "enabled": true + }, + { + "key": "{{externalId1}}", + "value": "", + "type": "any", + "enabled": true + } + ], + "_postman_variable_scope": "environment", + "_postman_exported_at": "2023-01-23T12:28:57.929Z", + "_postman_exported_using": "Postman/10.8.3" +} diff --git a/ph-ee-env-template/PostmanCollections/Environment/Mojaloop-SIT_environment.json b/ph-ee-env-template/PostmanCollections/Environment/Mojaloop-SIT_environment.json new file mode 100644 index 000000000..45181d537 --- /dev/null +++ b/ph-ee-env-template/PostmanCollections/Environment/Mojaloop-SIT_environment.json @@ -0,0 +1,964 @@ +{ + "id": "42580f76-98d3-40d3-a4e5-531a1f1b3f23", + "name": "Mojaloop-Local", + "values": [ + { + "key": "BASE_CENTRAL_LEDGER_ADMIN", + "value": "", + "enabled": true + }, + { + "key": "BASE_CENTRAL_LEDGER_API", + "value": "", + "enabled": true + }, + { + "key": "BASE_CENTRAL_SETTLEMENT", + "value": "/v1", + "enabled": true + }, + { + "key": "BASE_ML_API", + "value": "", + "enabled": true + }, + { + "key": "BASE_MOJALOOP", + "value": "", + "enabled": true + }, + { + "key": "BASE_PATH_SWITCH_TRANSFERS", + "value": "", + "enabled": true + }, + { + "key": "blockTransferAmount", + "value": "7494", + "enabled": true + }, + { + "key": "closedWindowID", + "value": "1", + "enabled": true + }, + { + "key": "completedTimestamp", + "value": "", + "enabled": true + }, + { + "key": "condition", + "value": "HOr22-H3AfTDHrSkPjJtVPRdKouuMkDXTR4ejlQa8Ks", + "enabled": true + }, + { + "key": "CONFIG_GENERATE_NEW_PREPARE_DATE", + "value": "true", + "enabled": true + }, + { + "key": "CONFIG_GENERATE_NEW_QUOTE_DATE", + "value": "true", + "enabled": true + }, + { + "key": "CONFIG_GENERATE_NEW_QUOTE_UUID_ON_QUOTE", + "value": "true", + "enabled": true + }, + { + "key": "CONFIG_GENERATE_NEW_TIMESTAMP", + "value": "true", + "enabled": true + }, + { + "key": "CONFIG_GENERATE_NEW_TRANSACTION_UUID_ON_QUOTE", + "value": "true", + "enabled": true + }, + { + "key": "CONFIG_GENERATE_NEW_TRANSFER_UUID_ON_PREPARE", + "value": "true", + "enabled": true + }, + { + "key": "CONFIG_GENERATE_NEW_TRANSFER_UUID_ON_QUOTE\n", + "value": "true", + "enabled": true + }, + { + "key": "currency", + "value": "USD", + "enabled": true + }, + { + "key": "currentTimestamp", + "value": "2018-12-06T17:09:56.386Z", + "enabled": true + }, + { + "key": "dateHeader", + "value": "Thu, 24 Jan 2019 10:22:12 GMT", + "enabled": true + }, + { + "key": "dob", + "value": "1973-03-03", + "enabled": true + }, + { + "key": "env_prefix", + "value": "test", + "enabled": true + }, + { + "key": "expectedDOB", + "value": "1973-03-03", + "enabled": true + }, + { + "key": "expectedFirstName", + "value": "Siabelo", + "enabled": true + }, + { + "key": "expectedFullName", + "value": "Siabelo Maroka", + "enabled": true + }, + { + "key": "expectedLastName", + "value": "Maroka", + "enabled": true + }, + { + "key": "firstName", + "value": "Siabelo", + "enabled": true + }, + { + "key": "fspiop-signature", + "value": "{\"signature\":\"iU4GBXSfY8twZMj1zXX1CTe3LDO8Zvgui53icrriBxCUF_wltQmnjgWLWI4ZUEueVeOeTbDPBZazpBWYvBYpl5WJSUoXi14nVlangcsmu2vYkQUPmHtjOW-yb2ng6_aPfwd7oHLWrWzcsjTF-S4dW7GZRPHEbY_qCOhEwmmMOnE1FWF1OLvP0dM0r4y7FlnrZNhmuVIFhk_pMbEC44rtQmMFv4pm4EVGqmIm3eyXz0GkX8q_O1kGBoyIeV_P6RRcZ0nL6YUVMhPFSLJo6CIhL2zPm54Qdl2nVzDFWn_shVyV0Cl5vpcMJxJ--O_Zcbmpv6lxqDdygTC782Ob3CNMvg\\\",\\\"protectedHeader\\\":\\\"eyJhbGciOiJSUzI1NiIsIkZTUElPUC1VUkkiOiIvdHJhbnNmZXJzIiwiRlNQSU9QLUhUVFAtTWV0aG9kIjoiUE9TVCIsIkZTUElPUC1Tb3VyY2UiOiJPTUwiLCJGU1BJT1AtRGVzdGluYXRpb24iOiJNVE5Nb2JpbGVNb25leSIsIkRhdGUiOiIifQ\"}", + "enabled": true + }, + { + "key": "fspName", + "value": "payerfsp", + "enabled": true + }, + { + "key": "fulfilment", + "value": "uU0nuZNNPgilLlLX2n2r-sSE7-N6U4DukIj3rOLvzek", + "enabled": true + }, + { + "key": "fullName", + "value": "Siabelo Maroka", + "enabled": true + }, + { + "key": "fundsInPrepareAmount", + "value": "500", + "enabled": true + }, + { + "key": "fundsInPrepareTransferId", + "value": "b79a979e-9605-4db4-a052-85bc948be414", + "enabled": true + }, + { + "key": "fundsOutCommitAmount", + "value": "", + "enabled": true + }, + { + "key": "fundsOutCommitTransferId", + "value": "", + "enabled": true + }, + { + "key": "fundsOutPrepareAmount", + "value": "", + "enabled": true + }, + { + "key": "fundsOutPrepareReserveAmount", + "value": "", + "enabled": true + }, + { + "key": "fundsOutPrepareReserveTransferId", + "value": "", + "enabled": true + }, + { + "key": "fundsOutPrepareTransferId", + "value": "f60c555f-72a7-44c7-a3a8-1f4a4df4b100", + "enabled": true + }, + { + "key": "get_transfer_ID", + "value": "7e19ae5f-7db6-4612-ab99-7538a56b4c25", + "enabled": true + }, + { + "key": "HOST_ACCOUNT_LOOKUP_ADMIN", + "value": "http://account-lookup-service-admin.sandbox.fynarfin.io", + "enabled": true + }, + { + "key": "HOST_ACCOUNT_LOOKUP_SERVICE", + "value": "http://account-lookup-service.sandbox.fynarfin.io", + "enabled": true + }, + { + "key": "HOST_BULK_API_ADAPTER", + "value": "http://localhost:3003", + "enabled": true + }, + { + "key": "HOST_CENTRAL_LEDGER", + "value": "http://central-ledger.sandbox.fynarfin.io", + "enabled": true + }, + { + "key": "HOST_CENTRAL_SETTLEMENT", + "value": "http://central-settlement-service.sandbox.fynarfin.io", + "enabled": true + }, + { + "key": "HOST_EFK_SEARCH", + "value": "http://elastic-search.local/_all/_search?pretty", + "enabled": true + }, + { + "key": "HOST_ML_API", + "value": "http://ml-api-adapter.sandbox.fynarfin.io", + "enabled": true + }, + { + "key": "HOST_ML_API_ADAPTER", + "value": "http://ml-api-adapter.sandbox.fynarfin.io", + "enabled": true + }, + { + "key": "HOST_MOJALOOP", + "value": "localhost:4000", + "enabled": true + }, + { + "key": "HOST_QUOTING_SERVICE", + "value": "http://quoting-service.sandbox.fynarfin.io", + "enabled": true + }, + { + "key": "HOST_SIMULATOR", + "value": "http://moja-simulator.sandbox.fynarfin.io", + "enabled": true + }, + { + "key": "HOST_SIMULATOR_K8S_CLUSTER", + "value": "http://moja-simulator", + "enabled": true + }, + { + "key": "HOST_SWITCH_TRANSFERS", + "value": "http://ml-api-adapter.sandbox.fynarfin.io", + "enabled": true + }, + { + "key": "hub_operator", + "value": "NOT_APPLICABLE", + "enabled": true + }, + { + "key": "HUBOPERATOR_BEARER_TOKEN", + "value": "NOT_APPLICABLE", + "enabled": true + }, + { + "key": "hubReconAccountBalance", + "value": "4800", + "enabled": true + }, + { + "key": "hubReconAccountBalanceBeforeFundsIn", + "value": "", + "enabled": true + }, + { + "key": "hubReconAccountBalanceBeforeFundsInReserve", + "value": "", + "enabled": true + }, + { + "key": "hubReconAccountBalanceBeforeFundsOutAbort", + "value": "", + "enabled": true + }, + { + "key": "hubReconAccountBalanceBeforeFundsOutCommit", + "value": "", + "enabled": true + }, + { + "key": "hubReconAccountBalanceBeforeFundsOutPrepare", + "value": "", + "enabled": true + }, + { + "key": "ilpPacket", + "value": "AQAAAAAAAADIEHByaXZhdGUucGF5ZWVmc3CCAiB7InRyYW5zYWN0aW9uSWQiOiIyZGY3NzRlMi1mMWRiLTRmZjctYTQ5NS0yZGRkMzdhZjdjMmMiLCJxdW90ZUlkIjoiMDNhNjA1NTAtNmYyZi00NTU2LThlMDQtMDcwM2UzOWI4N2ZmIiwicGF5ZWUiOnsicGFydHlJZEluZm8iOnsicGFydHlJZFR5cGUiOiJNU0lTRE4iLCJwYXJ0eUlkZW50aWZpZXIiOiIyNzcxMzgwMzkxMyIsImZzcElkIjoicGF5ZWVmc3AifSwicGVyc29uYWxJbmZvIjp7ImNvbXBsZXhOYW1lIjp7fX19LCJwYXllciI6eyJwYXJ0eUlkSW5mbyI6eyJwYXJ0eUlkVHlwZSI6Ik1TSVNETiIsInBhcnR5SWRlbnRpZmllciI6IjI3NzEzODAzOTExIiwiZnNwSWQiOiJwYXllcmZzcCJ9LCJwZXJzb25hbEluZm8iOnsiY29tcGxleE5hbWUiOnt9fX0sImFtb3VudCI6eyJjdXJyZW5jeSI6IlVTRCIsImFtb3VudCI6IjIwMCJ9LCJ0cmFuc2FjdGlvblR5cGUiOnsic2NlbmFyaW8iOiJERVBPU0lUIiwic3ViU2NlbmFyaW8iOiJERVBPU0lUIiwiaW5pdGlhdG9yIjoiUEFZRVIiLCJpbml0aWF0b3JUeXBlIjoiQ09OU1VNRVIiLCJyZWZ1bmRJbmZvIjp7fX19", + "enabled": true + }, + { + "key": "invalidFulfillment", + "value": "_3cco-YN5OGpRKVWV3n6x6uNpBTH9tYUdOYmHA", + "enabled": true + }, + { + "key": "lastName", + "value": "Maroka", + "enabled": true + }, + { + "key": "newOpenWindowID", + "value": "2", + "enabled": true + }, + { + "key": "openWindowID", + "value": "1", + "enabled": true + }, + { + "key": "participant", + "value": "testfsp4", + "enabled": true + }, + { + "key": "pathfinderMSISDN", + "value": "27713803912", + "enabled": true + }, + { + "key": "payeefsp", + "value": "payeefsp", + "enabled": true + }, + { + "key": "payeefsp_fspiop_signature", + "value": "{\"signature\":\"abcJjvNrkyK2KBieDUbGfhaBUn75aDUATNF4joqA8OLs4QgSD7i6EO8BIdy6Crph3LnXnTM20Ai1Z6nt0zliS_qPPLU9_vi6qLb15FOkl64DQs9hnfoGeo2tcjZJ88gm19uLY_s27AJqC1GH1B8E2emLrwQMDMikwQcYvXoyLrL7LL3CjaLMKdzR7KTcQi1tCK4sNg0noIQLpV3eA61kess\",\"protectedHeader\":\"eyJhbGciOiJSUzI1NiIsIkZTUElPUC1Tb3VyY2UiOiJwYXllZWZzcCIsIkZTUElPUC1EZXN0aW5hdGlvbiI6InBheWVyZnNwIiwiRlNQSU9QLVVSSSI6Ii90cmFuc2ZlcnMvZDY3MGI1OTAtZjc5ZC00YWU5LThjNmUtMTVjZjZjNWMzODk5IiwiRlNQSU9QLUhUVFAtTWV0aG9kIjoiUFVUIiwiRGF0ZSI6IiJ9\"}", + "enabled": true + }, + { + "key": "payeefsp_signature", + "value": "abcJjvNrkyK2KBieDUbGfhaBUn75aDUATNF4joqA8OLs4QgSD7i6EO8BIdy6Crph3LnXnTM20Ai1Z6nt0zliS_qPPLU9_vi6qLb15FOkl64DQs9hnfoGeo2tcjZJ88gm19uLY_s27AJqC1GH1B8E2emLrwQMDMikwQcYvXoyLrL7LL3CjaLMKdzR7KTcQi1tCK4sNg0noIQLpV3eA61kess", + "enabled": true + }, + { + "key": "payeefspAccountBalanceBeforeSettlement", + "value": "0", + "enabled": true + }, + { + "key": "payeeFspAccountId", + "value": "5", + "enabled": true + }, + { + "key": "payeeFspId", + "value": "4", + "enabled": true + }, + { + "key": "payeefspNDCBeforePrepare", + "value": "", + "enabled": true + }, + { + "key": "payeefspNetSettlementAmount", + "value": "-198", + "enabled": true + }, + { + "key": "payeefspPositionAccountId", + "value": "3", + "enabled": true + }, + { + "key": "payeefspPositionAfterTransfer", + "value": "0", + "enabled": true + }, + { + "key": "payeefspPositionBeforePrepare", + "value": "", + "enabled": true + }, + { + "key": "payeefspPositionBeforeTransfer", + "value": "0", + "enabled": true + }, + { + "key": "payeefspSettlementAccountId", + "value": "4", + "enabled": true + }, + { + "key": "payeeNDC", + "value": "1000", + "enabled": true + }, + { + "key": "payerfsp", + "value": "payerfsp", + "enabled": true + }, + { + "key": "payerfspAccountBalanceBeforeSettlement", + "value": "0", + "enabled": true + }, + { + "key": "payerFspAccountId", + "value": "3", + "enabled": true + }, + { + "key": "payerfspBeforePosition", + "value": "-1782", + "enabled": true + }, + { + "key": "payerFspId", + "value": "3", + "enabled": true + }, + { + "key": "payerfspNDCBeforePrepare", + "value": "", + "enabled": true + }, + { + "key": "payerfspNetSettlementAmount", + "value": "198", + "enabled": true + }, + { + "key": "payerfspPositionAccountId", + "value": "7", + "enabled": true + }, + { + "key": "payerfspPositionAfterPrepare", + "value": "", + "enabled": true + }, + { + "key": "payerfspPositionAfterTransfer", + "value": "0", + "enabled": true + }, + { + "key": "payerfspPositionAfterTransferBeforeExpiry", + "value": "1596", + "enabled": true + }, + { + "key": "payerfspPositionBeforePrepare", + "value": "", + "enabled": true + }, + { + "key": "payerfspPositionBeforeTransfer", + "value": "0", + "enabled": true + }, + { + "key": "payerfspSettlementAccountBalance", + "value": "-4800", + "enabled": true + }, + { + "key": "payerfspSettlementAccountBalanceBeforeFundsIn", + "value": "", + "enabled": true + }, + { + "key": "payerfspSettlementAccountBalanceBeforeFundsInReserve", + "value": "", + "enabled": true + }, + { + "key": "payerfspSettlementAccountBalanceBeforeFundsOutAbort", + "value": "", + "enabled": true + }, + { + "key": "payerfspSettlementAccountBalanceBeforeFundsOutCommit", + "value": "", + "enabled": true + }, + { + "key": "payerfspSettlementAccountBalanceBeforeFundsOutPrepare", + "value": "", + "enabled": true + }, + { + "key": "payerfspSettlementAccountId", + "value": "8", + "enabled": true + }, + { + "key": "payerNDC", + "value": "1000", + "enabled": true + }, + { + "key": "quoteDate", + "value": "Fri, 21 Dec 2018 12:19:49 GMT", + "enabled": true + }, + { + "key": "quoteExpiration", + "value": "2018-11-08T21:31:00.534+01:00", + "enabled": true + }, + { + "key": "quoteId", + "value": "ddaa67b3-5bf8-45c1-bfcf-1e8781177c37", + "enabled": true + }, + { + "key": "reportEndDate", + "value": "2018-10-31", + "enabled": true + }, + { + "key": "reportFSPID", + "value": "payerfsp", + "enabled": true + }, + { + "key": "reportStartDate", + "value": "2018-10-01", + "enabled": true + }, + { + "key": "settlementAccountId", + "value": "3", + "enabled": true + }, + { + "key": "settlementId", + "value": "1", + "enabled": true + }, + { + "key": "testfsp1", + "value": "testfsp1", + "enabled": true + }, + { + "key": "testfsp1Id", + "value": "13", + "enabled": true + }, + { + "key": "testfsp1PositionAccountBalance", + "value": "", + "enabled": true + }, + { + "key": "testfsp1PositionAccountBalanceAfterTransfer", + "value": "", + "enabled": true + }, + { + "key": "testfsp1PositionAccountBalanceBeforeTransfer", + "value": "", + "enabled": true + }, + { + "key": "testfsp1PositionAccountId", + "value": "25", + "enabled": true + }, + { + "key": "testfsp1SettleAccountBalance", + "value": "", + "enabled": true + }, + { + "key": "testfsp1SettleAccountBalanceAfterTransfer", + "value": "", + "enabled": true + }, + { + "key": "testfsp1SettleAccountBalanceBeforeTransfer", + "value": "", + "enabled": true + }, + { + "key": "testfsp1SettlementAccountId", + "value": "26", + "enabled": true + }, + { + "key": "testfsp2", + "value": "testfsp2", + "enabled": true + }, + { + "key": "testfsp2Id", + "value": "14", + "enabled": true + }, + { + "key": "testfsp2PositionAccountBalance", + "value": "", + "enabled": true + }, + { + "key": "testfsp2PositionAccountBalanceAfterTransfer", + "value": "", + "enabled": true + }, + { + "key": "testfsp2PositionAccountId", + "value": "29", + "enabled": true + }, + { + "key": "testfsp2SettleAccountBalance", + "value": "", + "enabled": true + }, + { + "key": "testfsp2SettleAccountBalanceAfterTransfer", + "value": "", + "enabled": true + }, + { + "key": "testfsp2SettlementAccountId", + "value": "30", + "enabled": true + }, + { + "key": "testfsp3", + "value": "testfsp3", + "enabled": true + }, + { + "key": "testfsp3PositionAccountBalance", + "value": "", + "enabled": true + }, + { + "key": "testfsp3PositionAccountBalanceAfterTransfer", + "value": "", + "enabled": true + }, + { + "key": "testfsp3SettleAccountBalance", + "value": "", + "enabled": true + }, + { + "key": "testfsp3SettleAccountBalanceAfterTransfer", + "value": "", + "enabled": true + }, + { + "key": "testfsp3SettlementAccountBalanceBeforeFundsIn", + "value": "", + "enabled": true + }, + { + "key": "testfsp3SettlementAccountId", + "value": "", + "enabled": true + }, + { + "key": "testfsp4", + "value": "testfsp4", + "enabled": true + }, + { + "key": "testfsp4PositionAccountBalance", + "value": "", + "enabled": true + }, + { + "key": "testfsp4PositionAccountBalanceAfterTransfer", + "value": "", + "enabled": true + }, + { + "key": "testfsp4SettleAccountBalance", + "value": "", + "enabled": true + }, + { + "key": "testfsp4SettleAccountBalanceAfterTransfer", + "value": "", + "enabled": true + }, + { + "key": "testfsp4SettlementAccountBalanceBeforeFundsIn", + "value": "", + "enabled": true + }, + { + "key": "testfsp4SettlementAccountId", + "value": "", + "enabled": true + }, + { + "key": "testfspId3", + "value": "15", + "enabled": true + }, + { + "key": "testfspId4", + "value": "16", + "enabled": true + }, + { + "key": "transactionId", + "value": "97f3f215-37a0-4755-a17c-c39313aa2f98", + "enabled": true + }, + { + "key": "transactionRequestId", + "value": "25a00155-c777-4629-a6b7-61cf0d16f499", + "enabled": true + }, + { + "key": "transfer_ID", + "value": "e7b43799-e69e-4578-bd26-2a4b9a22e92e", + "enabled": true + }, + { + "key": "transferAmount", + "value": "99", + "enabled": true + }, + { + "key": "transferDate", + "value": "Fri, 21 Dec 2018 12:17:01 GMT", + "enabled": true + }, + { + "key": "transferExpiration", + "value": "2019-05-27T15:44:53.292Z", + "enabled": true + }, + { + "key": "transferExpiredExpiration", + "value": "2018-08-31T15:26:01.870Z", + "enabled": true + }, + { + "key": "validCondition", + "value": "GRzLaTP7DJ9t4P-a_BA0WA9wzzlsugf00-Tn6kESAfM", + "enabled": true + }, + { + "key": "validFulfillment", + "value": "UNlJ98hZTY_dsw0cAqw4i_UN3v4utt7CZFB4yfLbVFA", + "enabled": true + }, + { + "key": "HOST_TRANSACTION_REQUESTS_SERVICE", + "value": "http://transaction-request-service.local", + "enabled": true + }, + { + "key": "payerFsp", + "value": "payerfsp", + "enabled": true + }, + { + "key": "payeeFsp", + "value": "payeefsp", + "enabled": true + }, + { + "key": "amount", + "value": "1", + "enabled": true + }, + { + "key": "contentType", + "value": "application/vnd.interoperability.transfers+json;version=1.0", + "enabled": true + }, + { + "key": "individualTransfers", + "value": "", + "enabled": true + }, + { + "key": "bulkQuoteId", + "value": "", + "enabled": true + }, + { + "key": "bulkTransferId", + "value": "", + "enabled": true + }, + { + "key": "expirationDate", + "value": "", + "enabled": true + }, + { + "key": "headerDate", + "value": "", + "enabled": true + }, + { + "key": "transferId2", + "value": "", + "enabled": true + }, + { + "key": "amount2", + "value": "1", + "enabled": true + }, + { + "key": "currency2", + "value": "USD", + "enabled": true + }, + { + "key": "extKey1", + "value": "test", + "enabled": true + }, + { + "key": "extValue1", + "value": "test", + "enabled": true + }, + { + "key": "extKey2", + "value": "test2", + "enabled": true + }, + { + "key": "extValue2", + "value": "test2", + "enabled": true + }, + { + "key": "transferId", + "value": "", + "enabled": true + }, + { + "key": "condition2", + "value": "HOr22-H3AfTDHrSkPjJtVPRdKouuMkDXTR4ejlQa8Ks", + "enabled": true + }, + { + "key": "ilpPacket2", + "value": "AQAAAAAAAADIEHByaXZhdGUucGF5ZWVmc3CCAiB7InRyYW5zYWN0aW9uSWQiOiIyZGY3NzRlMi1mMWRiLTRmZjctYTQ5NS0yZGRkMzdhZjdjMmMiLCJxdW90ZUlkIjoiMDNhNjA1NTAtNmYyZi00NTU2LThlMDQtMDcwM2UzOWI4N2ZmIiwicGF5ZWUiOnsicGFydHlJZEluZm8iOnsicGFydHlJZFR5cGUiOiJNU0lTRE4iLCJwYXJ0eUlkZW50aWZpZXIiOiIyNzcxMzgwMzkxMyIsImZzcElkIjoicGF5ZWVmc3AifSwicGVyc29uYWxJbmZvIjp7ImNvbXBsZXhOYW1lIjp7fX19LCJwYXllciI6eyJwYXJ0eUlkSW5mbyI6eyJwYXJ0eUlkVHlwZSI6Ik1TSVNETiIsInBhcnR5SWRlbnRpZmllciI6IjI3NzEzODAzOTExIiwiZnNwSWQiOiJwYXllcmZzcCJ9LCJwZXJzb25hbEluZm8iOnsiY29tcGxleE5hbWUiOnt9fX0sImFtb3VudCI6eyJjdXJyZW5jeSI6IlVTRCIsImFtb3VudCI6IjIwMCJ9LCJ0cmFuc2FjdGlvblR5cGUiOnsic2NlbmFyaW8iOiJERVBPU0lUIiwic3ViU2NlbmFyaW8iOiJERVBPU0lUIiwiaW5pdGlhdG9yIjoiUEFZRVIiLCJpbml0aWF0b3JUeXBlIjoiQ09OU1VNRVIiLCJyZWZ1bmRJbmZvIjp7fX19", + "enabled": true + }, + { + "key": "MSISDN_ORACLE_URL", + "value": "http://localhost:8444", + "enabled": true + }, + { + "key": "ON_US_TRANSFERS_ENABLED", + "value": "false", + "enabled": true + }, + { + "key": "contentTypeParties", + "value": "application/vnd.interoperability.parties+json;version=1.0", + "enabled": true + }, + { + "key": "contentTypeQuotes", + "value": "application/vnd.interoperability.quotes+json;version=1.0", + "enabled": true + }, + { + "key": "contentTypeTransfers", + "value": "application/vnd.interoperability.transfers+json;version=1.1", + "enabled": true + }, + { + "key": "contentTypePartiesRequest", + "value": "application/vnd.interoperability.parties+json;version=1.0", + "type": "default", + "enabled": true + }, + { + "key": "contentTypeQuotesRequest", + "value": "application/vnd.interoperability.quotes+json;version=1.0", + "type": "default", + "enabled": true + }, + { + "key": "contentTypeTransfersRequest", + "value": "application/vnd.interoperability.transfers+json;version=1.0", + "type": "default", + "enabled": true + }, + { + "key": "acceptPartiesRequest", + "value": "application/vnd.interoperability.parties+json;version=1", + "type": "default", + "enabled": true + }, + { + "key": "acceptQuotesRequest", + "value": "application/vnd.interoperability.quotes+json;version=1.0", + "type": "default", + "enabled": true + }, + { + "key": "acceptTransfersRequest", + "value": "application/vnd.interoperability.transfers+json;version=1.0", + "type": "default", + "enabled": true + }, + { + "key": "payerMSISDN", + "value": "449999999", + "type": "default", + "enabled": true + }, + { + "key": "payeeMSISDN", + "value": "27713803912", + "type": "default", + "enabled": true + }, + { + "key": "txnId", + "value": "cf1f9731-d248-4cc9-be4c-7937f2ed6c18", + "type": "default", + "enabled": true + }, + { + "key": "PAYER_CALLBACK_HOST", + "value": "http://mojaloop.sandbox.fynarfin.io", + "type": "default", + "enabled": true + } + ], + "_postman_variable_scope": "environment", + "_postman_exported_at": "2023-02-21T10:25:31.028Z", + "_postman_exported_using": "Postman/10.10.5" +} \ No newline at end of file diff --git a/ph-ee-env-template/PostmanCollections/Environment/OAF UAT.postman_environment.json b/ph-ee-env-template/PostmanCollections/Environment/OAF UAT.postman_environment.json new file mode 100644 index 000000000..7ad9c221b --- /dev/null +++ b/ph-ee-env-template/PostmanCollections/Environment/OAF UAT.postman_environment.json @@ -0,0 +1,45 @@ +{ + "id": "5c4afa28-900f-4061-8327-2e17980753cf", + "name": "OAF UAT", + "values": [ + { + "key": "ChannelHostName", + "value": "https://paymenthub.qa.oneacrefund.org/channel", + "type": "default", + "enabled": true + }, + { + "key": "ZeebeOpsHostName", + "value": "https://paymenthub.qa.oneacrefund.org/zeebeops", + "type": "default", + "enabled": true + }, + { + "key": "MpesaHostName", + "value": "https://paymenthub.qa.oneacrefund.org/mpesa", + "type": "default", + "enabled": true + }, + { + "key": "MessagegatewayHostName", + "value": "https://paymenthub.qa.oneacrefund.org/messages", + "type": "default", + "enabled": true + }, + { + "key": "channelApiKey", + "value": "b2AoZ8yz5yQNGtyjTms5XgV6e2CtsVHX", + "type": "secret", + "enabled": true + }, + { + "key": "TenantName", + "value": "oaf", + "type": "default", + "enabled": true + } + ], + "_postman_variable_scope": "environment", + "_postman_exported_at": "2022-10-13T12:05:34.935Z", + "_postman_exported_using": "Postman/9.31.18" +} \ No newline at end of file diff --git a/ph-ee-env-template/PostmanCollections/Environment/PHEE_G2P_Demo.postman_environment.json b/ph-ee-env-template/PostmanCollections/Environment/PHEE_G2P_Demo.postman_environment.json new file mode 100644 index 000000000..1eb4069f3 --- /dev/null +++ b/ph-ee-env-template/PostmanCollections/Environment/PHEE_G2P_Demo.postman_environment.json @@ -0,0 +1,266 @@ +{ + "id": "3d4b13d6-1c13-465c-83be-caeb0fbc7fe1", + "name": "Demo-NS", + "values": [ + { + "key": "ChannelHostName", + "value": "channel-demo.sandbox.fynarfin.io", + "type": "default", + "enabled": true + }, + { + "key": "OperationsHostName", + "value": "ops-bk-demo.sandbox.fynarfin.io", + "type": "default", + "enabled": true + }, + { + "key": "BulkHostName", + "value": "bulk-connector-demo.sandbox.fynarfin.io", + "type": "default", + "enabled": true + }, + { + "key": "batchId", + "value": "6bdd4e23-9357-481b-b814-b678b146a01b", + "type": "default", + "enabled": true + }, + { + "key": "pageNo", + "value": "1", + "enabled": true + }, + { + "key": "pageSize", + "value": "20", + "enabled": true + }, + { + "key": "status", + "value": "ALL", + "enabled": true + }, + { + "key": "ZeebeOpsHostName", + "value": "https://zeebeops-demo.sandbox.fynarfin.io", + "type": "default", + "enabled": true + }, + { + "key": "TenantName", + "value": "gorilla", + "enabled": true + }, + { + "key": "access_token", + "value": "operations-app access token", + "type": "default", + "enabled": true + }, + { + "key": "transactionId", + "value": "123", + "enabled": true + }, + { + "key": "MpesaHostName", + "value": "https://mpesa-demo.sandbox.fynarfin.io", + "enabled": true + }, + { + "key": "MessagegatewayHostName", + "value": "https://messagegateway-demo.sandbox.fynarfin.io", + "enabled": true + }, + { + "key": "TestApiList", + "value": "[\"Authorization\",\"Batch Summary\",\"Batch Details\",\"Batch Lookup Details\",\"Get All Batches\",\"Batch Transactions JSON\"]", + "type": "default", + "enabled": true + }, + { + "key": "NextTestIndex", + "value": "1", + "type": "default", + "enabled": true + }, + { + "key": "AutoTest", + "value": "true", + "type": "default", + "enabled": true + }, + { + "key": "accountId", + "value": "organisationid@1234$accountid@3333", + "type": "default", + "enabled": true + }, + { + "key": "billReference", + "value": "123", + "type": "default", + "enabled": true + }, + { + "key": "identifierType", + "value": "msisdn", + "type": "default", + "enabled": true + }, + { + "key": "identifier", + "value": "123", + "type": "default", + "enabled": true + }, + { + "key": "debitMandateReference", + "value": "123", + "type": "default", + "enabled": true + }, + { + "key": "linkReference", + "value": "123", + "type": "default", + "enabled": true + }, + { + "key": "authorisationCode", + "value": "123", + "type": "default", + "enabled": true + }, + { + "key": "transactionReference", + "value": "123", + "type": "default", + "enabled": true + }, + { + "key": "clientCorrelationId", + "value": "12345678-6897-6798-6798-098765432134", + "type": "default", + "enabled": true + }, + { + "key": "serverCorrelationId", + "value": "12345678-6897-6798-6798-098765432134", + "type": "default", + "enabled": true + }, + { + "key": "quotationReference", + "value": "123", + "type": "default", + "enabled": true + }, + { + "key": "serviceProvider", + "value": "provider", + "type": "default", + "enabled": true + }, + { + "key": "ChannelGSMAHostName", + "value": "https://channel-gsma-demo.sandbox.fynarfin.io", + "type": "default", + "enabled": true + }, + { + "key": "batchFilePath", + "value": "ph-ee-bulk-demo-6.csv", + "type": "default", + "enabled": true + }, + { + "key": "PayeeTenantName", + "value": "lion", + "type": "default", + "enabled": true + }, + { + "key": "NotificationsHostName", + "value": "https://notifications-demo.sandbox.fynarfin.io", + "type": "default", + "enabled": true + }, + { + "key": "MSISDN", + "value": "+44999911", + "type": "default", + "enabled": true + }, + { + "key": "accountHoldingInstitutionId", + "value": "gorilla", + "type": "default", + "enabled": true + }, + { + "key": "amsName", + "value": "mifos", + "type": "default", + "enabled": true + }, + { + "key": "X-Registering-Institution-ID", + "value": "123", + "type": "default", + "enabled": true + }, + { + "key": "X-CallbackURL", + "value": "https://webhook.site/e41af4b6-a371-4c05-a360-3c28984d3014", + "type": "default", + "enabled": true + }, + { + "key": "privateKey", + "value": "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC07fxdEQlsvWvggBgrork401cdyZ9MqV6FF/RgX6+Om23gP/rME5sE5//OoG61KU3dEj9phcHH845TuyNEyc4Vhqxe1gzl4VIZkOj+/2qxYvCsP1Sv3twTs+fDfFv5NA1ZXqiswTlgjR2Lpf1tevFQEOzB9WYvH/Bu9kgr2AlHMPV6+b7gcJij/7W1hndiCk2ahbi7oXjjODF4yEU9yNAhopibe4zzMX+FO4eFYpUmrjS5wvv6aAanfoeIMTwhF81Gj9V3rHf4UsD3VEx773q7GPuXlZSLyiNrUCdvxITh+dW8Y9ICuCTy3bFbp1/HzoPdzkkUlzPNKLlLiV2w4EcxAgMBAAECggEAMjqHfwbFyQxlMHQfQa3xIdd6LejVcqDqfqSB0Wd/A2YfAMyCQbmHpbsKh0B+u4h191OjixX5EBuLfa9MQUKNFejHXaSq+/6rnjFenbwm0IwZKJiEWDbUfhvJ0blqhypuMktXJG6YETfb5fL1AjnJWGL6d3Y7IgYJ56QzsQhOuxZidSqw468xc4sIF0CoTeJdrSC2yDCVuVlLNifm/2SXBJD8mgc1WCz0rkJhvvpW4k5G9rRSkS5f0013ZNfsfiDXoqiKkafoYNEbk7TZQNInqSuONm/UECn5GLm6IXdXSGfm1O2Lt0Kk7uxW/3W00mIPeZD+hiOObheRm/2HoOEKiQKBgQDreVFQihXAEDviIB2s6fphvPcMw/IonE8tX565i3303ubQMDIyZmsi3apN5pqSjm1TKq1KIgY2D4vYTu6vO5x9MhEO2CCZWNwC+awrIYa32FwiT8D8eZ9g+DJ4/IwXyz1fG38RCz/eIsJ0NsS9z8RKBIbfMmM+WnXRez3Fq+cbRwKBgQDEs35qXThbbFUYo1QkO0vIo85iczu9NllRxo1nAqQkfu1oTYQQobxcGk/aZk0B02r9kt2eob8zfG+X3LadIhQ0/LalnGNKI9jWLkdW4dxi7xMU99MYc3NRXmR49xGxgOVkLzKyGMisUvkTnE5v/S1nhu5uFr3JPkWcCScLOTjVxwKBgHNWsDq3+GFkUkC3pHF/BhJ7wbLyA5pavfmmnZOavO6FhB8zjFLdkdq5IuMXcl0ZAHm9LLZkJhCy2rfwKb+RflxgerR/rrAOM24Np4RU3q0MgEyaLhg85pFT4T0bzu8UsRH14O6TSQxgkEjmTsX+j9IFl56aCryPCKi8Kgy53/CfAoGAdV2kUFLPDb3WCJ1r1zKKRW1398ZKHtwO73xJYu1wg1Y40cNuyX23pj0M6IOh7zT24dZ/5ecc7tuQukw3qgprhDJFyQtHMzWwbBuw9WZO2blM6XX1vuEkLajkykihhggi12RSG3IuSqQ3ejwJkUi/jsYz/fwTwcAmSLQtV8UM5IECgYEAh4h1EkMx3NXzVFmLsb4QLMXw8+Rnn9oG+NGObldQ+nmknUPu7iz5kl9lTJy+jWtqHlHL8ZtV1cZZSZnFxX5WQH5/lcz/UD+GqWoSlWuTU34PPTJqLKSYgkoOJQDEZVMVphLySS9tuo+K/h10lRS1r9KDm3RZASa1JnnWopBZIz4=", + "type": "default", + "enabled": true + }, + { + "key": "IdentityAccountMapperHostName", + "value": "https://identity-mapper-demo.sandbox.fynarfin.io", + "type": "default", + "enabled": true + }, + { + "key": "VoucherManagementHostName", + "value": "https://vouchers-demo.sandbox.fynarfin.io", + "type": "default", + "enabled": true + }, + { + "key": "voucherNumber", + "value": "17086925111782", + "type": "default", + "enabled": true + }, + { + "key": "BillPayHostName", + "value": "https://bill-pay-demo.sandbox.fynarfin.io", + "type": "default", + "enabled": true + }, + { + "key": "connector-mock-payment-schema", + "value": "mockpaymentschema-demo.sandbox.fynarfin.io", + "type": "default", + "enabled": true + }, + { + "key": "connector-crm", + "value": "connector-crm-demo.sandbox.fynarfin.io", + "type": "default", + "enabled": true + } + ], + "_postman_variable_scope": "environment", + "_postman_exported_at": "2024-03-04T07:09:25.401Z", + "_postman_exported_using": "Postman/10.23.5" +} \ No newline at end of file diff --git a/ph-ee-env-template/PostmanCollections/Environment/SIT.json b/ph-ee-env-template/PostmanCollections/Environment/SIT.json new file mode 100644 index 000000000..84c9db80c --- /dev/null +++ b/ph-ee-env-template/PostmanCollections/Environment/SIT.json @@ -0,0 +1,264 @@ +{ + "id": "af77afa1-631c-4dbd-8fd0-bc6151c48338", + "name": "SIT", + "values": [ + { + "key": "ChannelHostName", + "value": "channel.sandbox.fynarfin.io", + "type": "default", + "enabled": true + }, + { + "key": "OperationsHostName", + "value": "ops-bk.sandbox.fynarfin.io", + "type": "default", + "enabled": true + }, + { + "key": "BulkHostName", + "value": "bulk-connector.sandbox.fynarfin.io", + "type": "default", + "enabled": true + }, + { + "key": "batchId", + "value": "6bdd4e23-9357-481b-b814-b678b146a01b", + "type": "default", + "enabled": true + }, + { + "key": "pageNo", + "value": "1", + "enabled": true + }, + { + "key": "pageSize", + "value": "20", + "enabled": true + }, + { + "key": "status", + "value": "ALL", + "enabled": true + }, + { + "key": "ZeebeOpsHostName", + "value": "https://zeebeops.sandbox.fynarfin.io", + "type": "default", + "enabled": true + }, + { + "key": "TenantName", + "value": "gorilla", + "enabled": true + }, + { + "key": "access_token", + "value": "operations-app access token", + "type": "default", + "enabled": true + }, + { + "key": "transactionId", + "value": "123", + "enabled": true + }, + { + "key": "MpesaHostName", + "value": "https://mpesa.sandbox.fynarfin.io", + "enabled": true + }, + { + "key": "MessagegatewayHostName", + "value": "https://messagegateway.sandbox.fynarfin.io", + "enabled": true + }, + { + "key": "TestApiList", + "value": "[\"Authorization\",\"Batch Summary\",\"Batch Details\",\"Batch Lookup Details\",\"Get All Batches\",\"Batch Transactions JSON\"]", + "type": "default", + "enabled": true + }, + { + "key": "NextTestIndex", + "value": "1", + "type": "default", + "enabled": true + }, + { + "key": "AutoTest", + "value": "true", + "type": "default", + "enabled": true + }, + { + "key": "accountId", + "value": "organisationid@1234$accountid@3333", + "type": "default", + "enabled": true + }, + { + "key": "billReference", + "value": "123", + "type": "default", + "enabled": true + }, + { + "key": "identifierType", + "value": "msisdn", + "type": "default", + "enabled": true + }, + { + "key": "identifier", + "value": "123", + "type": "default", + "enabled": true + }, + { + "key": "debitMandateReference", + "value": "123", + "type": "default", + "enabled": true + }, + { + "key": "linkReference", + "value": "123", + "type": "default", + "enabled": true + }, + { + "key": "authorisationCode", + "value": "123", + "type": "default", + "enabled": true + }, + { + "key": "transactionReference", + "value": "123", + "type": "default", + "enabled": true + }, + { + "key": "clientCorrelationId", + "value": "123456", + "type": "default", + "enabled": true + }, + { + "key": "serverCorrelationId", + "value": "12345678-6897-6798-6798-098765432134", + "type": "default", + "enabled": true + }, + { + "key": "quotationReference", + "value": "123", + "type": "default", + "enabled": true + }, + { + "key": "serviceProvider", + "value": "provider", + "type": "default", + "enabled": true + }, + { + "key": "ChannelGSMAHostName", + "value": "https://channel-gsma.sandbox.fynarfin.io", + "type": "default", + "enabled": true + }, + { + "key": "batchFilePath", + "value": "ph-ee-bulk-demo-6.csv", + "type": "default", + "enabled": true + }, + { + "key": "PayeeTenantName", + "value": "lion", + "type": "default", + "enabled": true + }, + { + "key": "NotificationsHostName", + "value": "https://notifications.sandbox.fynarfin.io", + "type": "default", + "enabled": true + }, + { + "key": "MSISDN", + "value": "+44999911", + "type": "default", + "enabled": true + }, + { + "key": "accountHoldingInstitutionId", + "value": "gorilla", + "type": "default", + "enabled": true + }, + { + "key": "amsName", + "value": "mifos", + "type": "default", + "enabled": true + }, + { + "key": "IdentityAccountMapperHostName", + "value": "https://identity-mapper.sandbox.fynarfin.io", + "type": "default", + "enabled": true + }, + { + "key": "X-Registering-Institution-ID", + "value": "123", + "type": "default", + "enabled": true + }, + { + "key": "X-CallbackURL", + "value": "https://webhook.site/e5fc2440-03a6-4125-be88-88c97674e899", + "type": "default", + "enabled": true + }, + { + "key": "VoucherManagementHostName", + "value": "https://vouchers.sandbox.fynarfin.io", + "enabled": true + }, + { + "key": "voucherNumber", + "value": "17094479138838", + "type": "default", + "enabled": true + }, + { + "key": "BillPayHostName", + "value": "https://bill-pay.sandbox.fynarfin.io", + "type": "default", + "enabled": true + }, + { + "key": "billId", + "value": "001", + "enabled": true + }, + { + "key": "ConnectorCRMHostName", + "value": "https://connector-crm.sandbox.fynarfin.io", + "type": "default", + "enabled": true + }, + { + "key": "ConnectorBulkHostName", + "value": "https://connector.sandbox.fynarfin.io", + "type": "default", + "enabled": true + } + ], + "_postman_variable_scope": "environment", + "_postman_exported_at": "2024-05-16T19:44:05.790Z", + "_postman_exported_using": "Postman/10.24.24" +} \ No newline at end of file diff --git a/ph-ee-env-template/PostmanCollections/Environment/SLCB.json b/ph-ee-env-template/PostmanCollections/Environment/SLCB.json new file mode 100644 index 000000000..605c246c7 --- /dev/null +++ b/ph-ee-env-template/PostmanCollections/Environment/SLCB.json @@ -0,0 +1,93 @@ +{ + "id": "ed531699-3016-462b-a9c3-c5915082d4eb", + "name": "SLCB", + "values": [ + { + "key": "test-host", + "value": "https://g2p-test.slcb.com:8443", + "type": "default", + "enabled": true + }, + { + "key": "auth-endpoint", + "value": "api/auth", + "type": "default", + "enabled": true + }, + { + "key": "txnrequest-endpoint", + "value": "api/transactionRequest", + "type": "default", + "enabled": true + }, + { + "key": "auth-url", + "value": "{{test-host}}/{{auth-endpoint}}", + "type": "default", + "enabled": true + }, + { + "key": "txnrequest-url", + "value": "{{test-host}}/{{txnrequest-endpoint}}", + "type": "default", + "enabled": true + }, + { + "key": "accountbalance-endpoint", + "value": "api/accountBalance", + "type": "default", + "enabled": true + }, + { + "key": "accountbalance-url", + "value": "{{test-host}}/{{accountbalance-endpoint}}", + "type": "default", + "enabled": true + }, + { + "key": "recon-endpoint", + "value": "api/ReconciliationRequest", + "type": "default", + "enabled": true + }, + { + "key": "recon-url", + "value": "{{test-host}}/{{recon-endpoint}}", + "type": "default", + "enabled": true + }, + { + "key": "micr-base-url", + "value": "http://localhost:5001", + "type": "default", + "enabled": true + }, + { + "key": "micr-txn-request-endpoint", + "value": "test/transferRequest", + "type": "default", + "enabled": true + }, + { + "key": "micr-txn-request-url", + "value": "{{micr-base-url}}/{{micr-txn-request-endpoint}}", + "type": "default", + "enabled": true + }, + { + "key": "access_token", + "value": "", + "type": "default", + "enabled": true + }, + { + "key": "token", + "value": "", + "type": "any", + "enabled": true + } + ], + "_postman_variable_scope": "environment", + "_postman_exported_at": "2022-10-04T07:38:34.072Z", + "_postman_exported_using": "Postman/9.31.13" +} \ No newline at end of file diff --git a/ph-ee-env-template/PostmanCollections/Environment/fineract-transfer-demo-prep.csv b/ph-ee-env-template/PostmanCollections/Environment/fineract-transfer-demo-prep.csv new file mode 100644 index 000000000..a6dedd510 --- /dev/null +++ b/ph-ee-env-template/PostmanCollections/Environment/fineract-transfer-demo-prep.csv @@ -0,0 +1,6 @@ +payer_identifierType,payer_identifier,payer-activationDate,payer-submissionDate,payer_externalId,payer-approvedDate,payer-acc-activationDate,payer-transactionDate,payee_identifierType,payee_identifier,payee-activationDate,payee-submissionDate,payee_externalId,payee-approvedDate,payee-acc-activationDate,payee-transactionDate +MSISDN,855881222,01 December 2022,02 January 2023,ext_pay_55,02 January 2023,02 January 2023,02 January 2023,MSISDN,112242543,01 December 2022,02 January 2023,ext_pay_67,02 January 2023,02 January 2023,02 January 2023 +MSISDN,855881223,01 December 2022,02 January 2023,ext_pay_56,02 January 2023,02 January 2023,02 January 2023,MSISDN,112242544,01 December 2022,02 January 2023,ext_pay_68,02 January 2023,02 January 2023,02 January 2023 +MSISDN,855881224,01 December 2022,02 January 2023,ext_pay_57,02 January 2023,02 January 2023,02 January 2023,MSISDN,112242545,01 December 2022,02 January 2023,ext_pay_69,02 January 2023,02 January 2023,02 January 2023 +MSISDN,855881225,01 December 2022,02 January 2023,ext_pay_58,02 January 2023,02 January 2023,02 January 2023,MSISDN,112242546,01 December 2022,02 January 2023,ext_pay_70,02 January 2023,02 January 2023,02 January 2023 +MSISDN,855881226,01 December 2022,02 January 2023,ext_pay_59,02 January 2023,02 January 2023,02 January 2023,MSISDN,112242547,01 December 2022,02 January 2023,ext_pay_71,02 January 2023,02 January 2023,02 January 2023 \ No newline at end of file diff --git a/ph-ee-env-template/PostmanCollections/External APIs.json b/ph-ee-env-template/PostmanCollections/External APIs.json new file mode 100644 index 000000000..158f84607 --- /dev/null +++ b/ph-ee-env-template/PostmanCollections/External APIs.json @@ -0,0 +1,594 @@ +{ + "info": { + "_postman_id": "c78d870c-1fde-445a-bade-b6d06c7590b7", + "name": "External APIs", + "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json", + "_exporter_id": "17902615" + }, + "item": [ + { + "name": "Payment Schema", + "item": [ + { + "name": "SLCB", + "item": [ + { + "name": "Auth", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "var jsonData = JSON.parse(responseBody);", + "postman.setEnvironmentVariable(\"access_token\", jsonData.token);" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"username\": \"DSTI01\",\n \"password\": \"y,T$XG4\",\n \"expiresIn\": 0\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{auth-url}}", + "host": [ + "{{auth-url}}" + ] + } + }, + "response": [ + { + "name": "Sucessful Auth", + "originalRequest": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{ \"Username\":\"DSTI01\", \"Password\":\"Cuu)!!7\" }", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "https://g2p-test.slcb.com:8443/api/auth", + "protocol": "https", + "host": [ + "g2p-test", + "slcb", + "com" + ], + "port": "8443", + "path": [ + "api", + "auth" + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Transfer-Encoding", + "value": "chunked" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "key": "Server", + "value": "Microsoft-IIS/10.0" + }, + { + "key": "X-Powered-By", + "value": "ASP.NET" + }, + { + "key": "Date", + "value": "Fri, 20 May 2022 11:10:39 GMT" + } + ], + "cookie": [], + "body": "{\n \"username\": \"DSTI01\",\n \"token\": \"eyJhbGciOiJSUzI1NiIsImtpZCI6IjdBQjQ5NjgxMDdBMzAyQjcxQzc3QTU1MDdENEM5NjQ5IiwidHlwIjoiYXQrand0In0.eyJuYmYiOjE2NTMwNDUwMzksImV4cCI6MTY1NjY0NTAzOSwiaXNzIjoiaHR0cHM6Ly9nMnAtdGVzdC5zbGNiLmNvbTo4NDQzIiwiYXVkIjoiZVRyYXgiLCJjbGllbnRfaWQiOiJlVHJheF9BcHAiLCJzdWIiOiI5NjVlNzA4ZC1hN2I2LTQ5Y2YtOGEzOC1jMGM4MzExMDhhNmMiLCJhdXRoX3RpbWUiOjE2NTMwNDUwMzksImlkcCI6ImxvY2FsIiwicGhvbmVfbnVtYmVyX3ZlcmlmaWVkIjoiRmFsc2UiLCJlbWFpbCI6ImF2aWtAZnluYXJmaW4uaW8iLCJlbWFpbF92ZXJpZmllZCI6IkZhbHNlIiwibmFtZSI6IkRTVEkwMSIsImlhdCI6MTY1MzA0NTAzOSwic2NvcGUiOlsiZVRyYXgiXSwiYW1yIjpbInB3ZCJdfQ.HVihulps0nJgS1Gsg4O_7m2FoFI3nFpnQR9MtFcZmokkZ_5qWR5FtFtGsMb1Hn68Qaj3HHTaXUVVHfNQSDNIFrmlwW_EN1UreojM7imB2CWTNWiM2TZDnmItPBaMvB2pH1fraLANqm9KuryzeNbNbGhFi19eCB1e2cLWPUlufnjHsWMbAB2hweahbVNsIVCNvZLInKSP339X45RxsTp7SHNvw56VbDyTDL-MrCjZTUN0fxJS38r91wO-IkcwzfmpAS-OJJXSusByilnLphRQvIJq4ianX8p15IxWSIF5RpBigJklZzC3N5pp6SkyYy_0VXYOayzqSkDK5mXg0d9vvQ\",\n \"expiresIn\": 3600000\n}" + } + ] + }, + { + "name": "Transaction Request", + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "{{access_token}}", + "type": "string" + } + ] + }, + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"ID\": null,\n \"AccountType\": 0,\n \"AuthorizationCode\": \"yoWYLKjSPl4C746p+pzEFl9hQ6ZZpq2JcvNItmC9ZowWRTB1V4Cx+bk0YkTLBSHc\",\n \"BatchID\": \"987\",\n \"InstitutionCode\": \"SLCB\",\n \"Purpose\": \"Test Payment\",\n \"RequestDate\": \"2022-10-03T06:03:30.45+05:30\",\n \"SourceAccount\": \"003001003879112168\",\n \"Status\": null,\n \"TotalAmountPaid\": 0.0,\n \"TotalAmountToBePaid\": 500.00,\n \"Payees\": [\n {\n \"ID\": null,\n \"Account\": \"003001003873110196\",\n \"AccountType\": 0,\n \"Amount\": 250.00,\n \"ExternalTransactionId\": 0,\n \"FirstName\": \"Test\",\n \"LastName\": \"Account 4\",\n \"Purpose\": \"Test Payee Payment\",\n \"Status\": {\n \"Code\": 0,\n \"Description\": null\n },\n \"StatusMessage\": null,\n \"TransactionId\": null\n },\n {\n \"ID\": null,\n \"Account\": \"003001003874120160\",\n \"AccountType\": 0,\n \"Amount\": 250.00,\n \"ExternalTransactionId\": 1,\n \"FirstName\": \"Test\",\n \"LastName\": \"Account\",\n \"Purpose\": \"Test Payee Payment 2\",\n \"Status\": {\n \"Code\": 0,\n \"Description\": null\n },\n \"StatusMessage\": null,\n \"TransactionId\": null\n }\n ]\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{txnrequest-url}}", + "host": [ + "{{txnrequest-url}}" + ] + } + }, + "response": [ + { + "name": "Transaction Request Success", + "originalRequest": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"ID\": null,\n \"AccountType\": 0,\n \"AuthorizationCode\": \"y7mDYZ34xLUzuIifRa7B/2CRoETLOoSb+QIQlVHPqwQGGLYL9hWY61oS1hooXMz4TuhG8HtrHxEevOr9Dio+kSfoJZFxroYNmm5Icww3rIfonMPIH5ovYYXdOAP8wy/ISN7HLor0pV/rhmCPMmpMROByid4+EFK85rXH6pXr5tzF6RyRYAcu1wCiASGMTiIZedpV11VJp1vH3whmBHWhfE5fo2NP7FiJ8Uv3Aw3sCcCj7hQ1OKkq9lMLV1F8YrjoKbMbdBEnTPWxwdTrGN8MWTS/j0ofiE3Thyog/fmAwfsDNN2MNEz/GvVGABZALkQ9tc/4UACx4iQBu0JqfKVT9wYKd3LojvEFXDaeLXORyRH/gdxhG+UQq+2JtUjNNOP6fs/VrBwizMRkuG3qg/wDhoOeVnq1mtIcTUCPEO54t2caMGvHnvMcPK1kBlYryliIbcfRTsoserCsg5clZWfs0IBB6evmWDSN+PXJ9+VDvBheecaXLHeTgv7vZPjVp00oGJDGA63pH1XONWRBSZKo5FnidTzQs6/53QthEFfJSmPY45NV/e7OLjp2FVoV7Lutuc+aT4m5AsuYISsNX+Zlqm8K/KcnODokrP/gCjNWnAOvlRiUKfMw1tp2PxtFqDDUC1Sr25w8E0qhMd/HwfuRc7NHZYy+ez4tpFVRj2EvqRGA76G+tl/hMMCpsr0dZavEjBSOInGcDxhDdzT+QMLYtjgOEzLTn+6AFxwMC0FU+7Srxg3f8ljkYH5US2Pn0+oZ05OmDSgefsYRhjcKmU96owCPSNXdEfTT6PYz9JMBBPhoCGTAzlnK3lU4GawtT7fLI5QD+wS3OYYKOrjubRQ4tFx4Qlb3amqri/FckS9GMfnk1wUwhjdPhxC+7W6UvfHrXrfe4QmC8fWzOENUWXA4JlRxezylEG7wUHB7+d9c90cgqAzOEEHL1FGEB+uPqfljI6NjE2VFFahskD3mFEEuUprsmNyvAzTBN2LLt11nwjPku3IMoHj9NZcMTexlr9HyJUjC5xEPui3rQ5FUdLM5mcOm9NQQBGSkGgwHGVInoXdWUH/oVwhWBPwB+dnR9gMrP29rkJ1JlOsNDDmHdxRJQRlSQe937CiSzL4T5d/uZvFxqbTl/GFFxv65TCGsxGVNM64Nyp0xZtGh/jafhcwvSRq/xDuWss0Uin3c5nSkoOb8IwS01uNO4J1/j2vFXDCBHRRYSmh8HtFuOvaRVQcX6bSxd6d3Indsy//T+IsFZmk/wMOPM3fnLUeFhDx57LpP72/qonB0XZspNUN4tif2vORWUEU3DpP8bzw5saaSk2RqBDNeosMaqAAPo9lwrYeyfPIJ69F2iqiaP0XUNpzaQqSGhP50fL92DfXiHpJxRfBhXdH5Eu8OjqdqwewZEZHkqi20vQm02yGfXJZ8peQPmLIJQg84v8TVbEqM9KWHJrSjaIjTFxxAaIqDVkjElSSz8uDMr40HbDUlKnwNJUoMIwTKfypr60em3k1lDoOs4bFbG2Zl+NXt5WmyhBJNPHKuAyUdaQBEx7eDR7fptLjo8oo9W29EIlridVSPO1scH5Q9xECjs4GwfcfWp2Optk/g\",\n \"BatchID\": \"1\",\n \"InstitutionCode\": \"SLCB\",\n \"Purpose\": \"Test Payment\",\n \"RequestDate\": \"2022-05-30T07:20:09.9260323-04:00\",\n \"SourceAccount\": \"003001003878112195\",\n \"Status\": null,\n \"TotalAmountPaid\": 0.0,\n \"TotalAmountToBePaid\": 350000.00,\n \"Payees\": [\n {\n \"ID\": null,\n \"Account\": \"003001003873110196\",\n \"AccountType\": 0,\n \"Amount\": 100000.00,\n \"ExternalTransactionId\": 0,\n \"FirstName\": \"Test\",\n \"LastName\": \"Account 4\",\n \"Purpose\": \"Test Payee Payment\",\n \"Status\": {\n \"Code\": 0,\n \"Description\": null\n },\n \"StatusMessage\": null,\n \"TransactionId\": null\n },\n {\n \"ID\": null,\n \"Account\": \"003001003874120160\",\n \"AccountType\": 0,\n \"Amount\": 250000.00,\n \"ExternalTransactionId\": 0,\n \"FirstName\": \"Test\",\n \"LastName\": \"Account\",\n \"Purpose\": \"Test Payee Payment 2\",\n \"Status\": {\n \"Code\": 0,\n \"Description\": null\n },\n \"StatusMessage\": null,\n \"TransactionId\": null\n }\n \n ]\n}\n", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{txnrequest-url}}", + "host": [ + "{{txnrequest-url}}" + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Transfer-Encoding", + "value": "chunked" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "key": "Server", + "value": "Microsoft-IIS/10.0" + }, + { + "key": "X-Powered-By", + "value": "ASP.NET" + }, + { + "key": "Date", + "value": "Tue, 24 May 2022 15:03:35 GMT" + } + ], + "cookie": [], + "body": "{\n \"id\": null,\n \"accountType\": 0,\n \"authorizationCode\": \"y7mDYZ34xLUzuIifRa7B/2CRoETLOoSb+QIQlVHPqwQGGLYL9hWY61oS1hooXMz4TuhG8HtrHxEevOr9Dio+kSfoJZFxroYNmm5Icww3rIfonMPIH5ovYYXdOAP8wy/ISN7HLor0pV/rhmCPMmpMROByid4+EFK85rXH6pXr5tzF6RyRYAcu1wCiASGMTiIZedpV11VJp1vH3whmBHWhfE5fo2NP7FiJ8Uv3Aw3sCcCj7hQ1OKkq9lMLV1F8YrjoKbMbdBEnTPWxwdTrGN8MWTS/j0ofiE3Thyog/fmAwfsDNN2MNEz/GvVGABZALkQ9tc/4UACx4iQBu0JqfKVT9wYKd3LojvEFXDaeLXORyRH/gdxhG+UQq+2JtUjNNOP6fs/VrBwizMRkuG3qg/wDhoOeVnq1mtIcTUCPEO54t2caMGvHnvMcPK1kBlYryliIbcfRTsoserCsg5clZWfs0IBB6evmWDSN+PXJ9+VDvBheecaXLHeTgv7vZPjVp00oGJDGA63pH1XONWRBSZKo5FnidTzQs6/53QthEFfJSmPY45NV/e7OLjp2FVoV7Lutuc+aT4m5AsuYISsNX+Zlqm8K/KcnODokrP/gCjNWnAOvlRiUKfMw1tp2PxtFqDDUC1Sr25w8E0qhMd/HwfuRc7NHZYy+ez4tpFVRj2EvqRGA76G+tl/hMMCpsr0dZavEjBSOInGcDxhDdzT+QMLYtjgOEzLTn+6AFxwMC0FU+7Srxg3f8ljkYH5US2Pn0+oZ05OmDSgefsYRhjcKmU96owCPSNXdEfTT6PYz9JMBBPhoCGTAzlnK3lU4GawtT7fLI5QD+wS3OYYKOrjubRQ4tFx4Qlb3amqri/FckS9GMfnk1wUwhjdPhxC+7W6UvfHrXrfe4QmC8fWzOENUWXA4JlRxezylEG7wUHB7+d9c90cgqAzOEEHL1FGEB+uPqfljI6NjE2VFFahskD3mFEEuUprsmNyvAzTBN2LLt11nwjPku3IMoHj9NZcMTexlr9HyJUjC5xEPui3rQ5FUdLM5mcOm9NQQBGSkGgwHGVInoXdWUH/oVwhWBPwB+dnR9gMrP29rkJ1JlOsNDDmHdxRJQRlSQe937CiSzL4T5d/uZvFxqbTl/GFFxv65TCGsxGVNM64Nyp0xZtGh/jafhcwvSRq/xDuWss0Uin3c5nSkoOb8IwS01uNO4J1/j2vFXDCBHRRYSmh8HtFuOvaRVQcX6bSxd6d3Indsy//T+IsFZmk/wMOPM3fnLUeFhDx57LpP72/qonB0XZspNUN4tif2vORWUEU3DpP8bzw5saaSk2RqBDNeosMaqAAPo9lwrYeyfPIJ69F2iqiaP0XUNpzaQqSGhP50fL92DfXiHpJxRfBhXdH5Eu8OjqdqwewZEZHkqi20vQm02yGfXJZ8peQPmLIJQg84v8TVbEqM9KWHJrSjaIjTFxxAaIqDVkjElSSz8uDMr40HbDUlKnwNJUoMIwTKfypr60em3k1lDoOs4bFbG2Zl+NXt5WmyhBJNPHKuAyUdaQBEx7eDR7fptLjo8oo9W29EIlridVSPO1scH5Q9xECjs4GwfcfWp2Optk/g\",\n \"batchID\": \"1\",\n \"institutionCode\": \"SLCB\",\n \"purpose\": \"Test Payment\",\n \"requestDate\": \"2022-05-30T11:20:09.9260323+00:00\",\n \"sourceAccount\": \"003001003878112195\",\n \"status\": {\n \"code\": 0,\n \"description\": \"The operation completed successfully\"\n },\n \"totalAmountPaid\": 350000,\n \"totalAmountToBePaid\": 350000,\n \"payees\": [\n {\n \"id\": \"50\",\n \"account\": \"003001003873110196\",\n \"accountType\": 0,\n \"amount\": 100000,\n \"externalTransactionId\": 0,\n \"firstName\": \"Test\",\n \"lastName\": \"Account 4\",\n \"purpose\": \"Test Payee Payment\",\n \"status\": {\n \"code\": 0,\n \"description\": \"The operation completed successfully\"\n },\n \"statusMessage\": \"The operation completed successfully\",\n \"transactionId\": \"1847142054\"\n },\n {\n \"id\": \"52\",\n \"account\": \"003001003874120160\",\n \"accountType\": 0,\n \"amount\": 250000,\n \"externalTransactionId\": 0,\n \"firstName\": \"Test\",\n \"lastName\": \"Account\",\n \"purpose\": \"Test Payee Payment 2\",\n \"status\": {\n \"code\": 0,\n \"description\": \"The operation completed successfully\"\n },\n \"statusMessage\": \"The operation completed successfully\",\n \"transactionId\": \"2468598674\"\n }\n ]\n}" + }, + { + "name": "Transaction Request strange 003001003879112168", + "originalRequest": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"ID\": null,\n \"AccountType\": 0,\n \"AuthorizationCode\": \"NoXFMivy98TASCZOhVUidG75uCM3N+/l3+7FkxH8BZjZYysROYSdRMgQ0vATHP5rK8c8w0BRw9mbBS3cX1X7wYz5teSzZ75P5IS+kWsrAO+ZGKIhi60SL5eICFfees47bVCHwxm5jDiLn1eN/PgM6GTpGK0OwtxxLDkm79wcjyTHZHaxHpezmmuJWbziWTo84zFHuHxREtX/6mI6sRh1qOrC9P0az0IrgeNNrG7CLgBKjgTI5bIAqfU2Eer4hE7hCBVfFFEIF+JxGcVneNujubB2gcVhLNLVQK+AqfJWaVrOZydIlYa6G70a745J1DiAnmNOIdGHdN6Ad8WWFUwJ2g==\",\n \"BatchID\": \"1\",\n \"InstitutionCode\": \"SLCB\",\n \"Purpose\": \"Test Payment\",\n \"RequestDate\": \"2022-07-26T07:20:09.9260323-04:00\",\n \"SourceAccount\": \"003001003879112168\",\n \"Status\": null,\n \"TotalAmountPaid\": 0.0,\n \"TotalAmountToBePaid\": 350000.00,\n \"Payees\": [\n {\n \"ID\": null,\n \"Account\": \"003001003873110196\",\n \"AccountType\": 0,\n \"Amount\": 100000.00,\n \"ExternalTransactionId\": 0,\n \"FirstName\": \"Test\",\n \"LastName\": \"Account 4\",\n \"Purpose\": \"Test Payee Payment\",\n \"Status\": {\n \"Code\": 0,\n \"Description\": null\n },\n \"StatusMessage\": null,\n \"TransactionId\": null\n },\n {\n \"ID\": null,\n \"Account\": \"003001003874120160\",\n \"AccountType\": 0,\n \"Amount\": 250000.00,\n \"ExternalTransactionId\": 0,\n \"FirstName\": \"Test\",\n \"LastName\": \"Account\",\n \"Purpose\": \"Test Payee Payment 2\",\n \"Status\": {\n \"Code\": 0,\n \"Description\": null\n },\n \"StatusMessage\": null,\n \"TransactionId\": null\n }\n ]\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{txnrequest-url}}", + "host": [ + "{{txnrequest-url}}" + ] + } + }, + "status": "Bad Request", + "code": 400, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Cache-Control", + "value": "no-cache" + }, + { + "key": "Pragma", + "value": "no-cache" + }, + { + "key": "Transfer-Encoding", + "value": "chunked" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "key": "Expires", + "value": "-1" + }, + { + "key": "Server", + "value": "Microsoft-IIS/10.0" + }, + { + "key": "X-Powered-By", + "value": "ASP.NET" + }, + { + "key": "Date", + "value": "Fri, 29 Jul 2022 10:42:01 GMT" + } + ], + "cookie": [], + "body": "{\"Message\":\"Error Code:-23 - Description: Insufficient funds\",\"StatusCode\":\"400\"}{\"Message\":\"Insufficient funds\",\"StatusCode\":\"-23\"}" + }, + { + "name": "Transaction Request Internal error", + "originalRequest": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"ID\": null,\n \"AccountType\": 0,\n \"AuthorizationCode\": \"yoWYLKjSPl4C746p+pzEFl9hQ6ZZpq2JcvNItmC9ZowWRTB1V4Cx+bk0YkTLBSHc\",\n \"BatchID\": \"1\",\n \"InstitutionCode\": \"SLCB\",\n \"Purpose\": \"Test Payment\",\n \"RequestDate\": \"2022-08-08T05:56:48+05:30\",\n \"SourceAccount\": \"003001003873110196\",\n \"Status\": null,\n \"TotalAmountPaid\": 0.0,\n \"TotalAmountToBePaid\": 500.00,\n \"Payees\": [\n {\n \"ID\": null,\n \"Account\": \"003001003873110196\",\n \"AccountType\": 0,\n \"Amount\": 250.00,\n \"ExternalTransactionId\": 0,\n \"FirstName\": \"Test\",\n \"LastName\": \"Account 4\",\n \"Purpose\": \"Test Payee Payment\",\n \"Status\": {\n \"Code\": 0,\n \"Description\": null\n },\n \"StatusMessage\": null,\n \"TransactionId\": null\n },\n {\n \"ID\": null,\n \"Account\": \"003001003874120160\",\n \"AccountType\": 0,\n \"Amount\": 250.00,\n \"ExternalTransactionId\": 1,\n \"FirstName\": \"Test\",\n \"LastName\": \"Account\",\n \"Purpose\": \"Test Payee Payment 2\",\n \"Status\": {\n \"Code\": 0,\n \"Description\": null\n },\n \"StatusMessage\": null,\n \"TransactionId\": null\n }\n ]\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{txnrequest-url}}", + "host": [ + "{{txnrequest-url}}" + ] + } + }, + "status": "Internal Server Error", + "code": 500, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Transfer-Encoding", + "value": "chunked" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "key": "Server", + "value": "Microsoft-IIS/10.0" + }, + { + "key": "_AbpErrorFormat", + "value": "true" + }, + { + "key": "X-Powered-By", + "value": "ASP.NET" + }, + { + "key": "Date", + "value": "Thu, 01 Sep 2022 11:03:52 GMT" + } + ], + "cookie": [], + "body": "{\n \"error\": {\n \"code\": null,\n \"message\": \"An internal error occurred during your request!\",\n \"details\": null,\n \"data\": {},\n \"validationErrors\": null\n }\n}" + }, + { + "name": "Transaction Request -999", + "originalRequest": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"ID\": null,\n \"AccountType\": 0,\n \"AuthorizationCode\": \"yoWYLKjSPl4C746p+pzEFl9hQ6ZZpq2JcvNItmC9ZowWRTB1V4Cx+bk0YkTLBSHc\",\n \"BatchID\": \"1\",\n \"InstitutionCode\": \"SLCB\",\n \"Purpose\": \"Test Payment\",\n \"RequestDate\": \"2022-08-08T05:56:48+05:30\",\n \"SourceAccount\": \"003001003873110196\",\n \"Status\": null,\n \"TotalAmountPaid\": 0.0,\n \"TotalAmountToBePaid\": 500.00,\n \"Payees\": [\n {\n \"ID\": null,\n \"Account\": \"003001003873110196\",\n \"AccountType\": 0,\n \"Amount\": 250.00,\n \"ExternalTransactionId\": 0,\n \"FirstName\": \"Test\",\n \"LastName\": \"Account 4\",\n \"Purpose\": \"Test Payee Payment\",\n \"Status\": {\n \"Code\": 0,\n \"Description\": null\n },\n \"StatusMessage\": null,\n \"TransactionId\": null\n },\n {\n \"ID\": null,\n \"Account\": \"003001003874120160\",\n \"AccountType\": 0,\n \"Amount\": 250.00,\n \"ExternalTransactionId\": 1,\n \"FirstName\": \"Test\",\n \"LastName\": \"Account\",\n \"Purpose\": \"Test Payee Payment 2\",\n \"Status\": {\n \"Code\": 0,\n \"Description\": null\n },\n \"StatusMessage\": null,\n \"TransactionId\": null\n }\n ]\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{txnrequest-url}}", + "host": [ + "{{txnrequest-url}}" + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Transfer-Encoding", + "value": "chunked" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "key": "Server", + "value": "Microsoft-IIS/10.0" + }, + { + "key": "X-Powered-By", + "value": "ASP.NET" + }, + { + "key": "Date", + "value": "Fri, 02 Sep 2022 11:14:06 GMT" + } + ], + "cookie": [], + "body": "{\n \"id\": null,\n \"accountType\": 0,\n \"authorizationCode\": \"yoWYLKjSPl4C746p+pzEFl9hQ6ZZpq2JcvNItmC9ZowWRTB1V4Cx+bk0YkTLBSHc\",\n \"batchID\": \"1\",\n \"institutionCode\": \"SLCB\",\n \"purpose\": \"Test Payment\",\n \"requestDate\": \"2022-08-08T00:26:48+00:00\",\n \"sourceAccount\": \"003001003873110196\",\n \"status\": {\n \"code\": -999,\n \"description\": \"There was an error while processing the request. Processing aborted.\"\n },\n \"totalAmountPaid\": 0,\n \"totalAmountToBePaid\": 500,\n \"payees\": [\n {\n \"id\": null,\n \"account\": \"003001003873110196\",\n \"accountType\": 0,\n \"amount\": 250,\n \"externalTransactionId\": 0,\n \"firstName\": \"Test\",\n \"lastName\": \"Account 4\",\n \"purpose\": \"Test Payee Payment\",\n \"status\": {\n \"code\": 0,\n \"description\": null\n },\n \"statusMessage\": null,\n \"transactionId\": null\n },\n {\n \"id\": null,\n \"account\": \"003001003874120160\",\n \"accountType\": 0,\n \"amount\": 250,\n \"externalTransactionId\": 1,\n \"firstName\": \"Test\",\n \"lastName\": \"Account\",\n \"purpose\": \"Test Payee Payment 2\",\n \"status\": {\n \"code\": 0,\n \"description\": null\n },\n \"statusMessage\": null,\n \"transactionId\": null\n }\n ]\n}" + } + ] + }, + { + "name": "Reconcoliation", + "protocolProfileBehavior": { + "disableBodyPruning": true + }, + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "{{access_token}}", + "type": "string" + } + ] + }, + "method": "GET", + "header": [], + "body": { + "mode": "urlencoded", + "urlencoded": [ + { + "key": "from", + "value": "2022-09-21T05:56:47+05:30", + "description": "2022-09-21T15:03:47.9773109", + "type": "text" + }, + { + "key": "to", + "value": "2022-09-22T05:56:48+05:30", + "description": "2022-09-21T15:03:47.9793763", + "type": "text" + }, + { + "key": "authorizationCode", + "value": "yoWYLKjSPl4C746p+pzEFl9hQ6ZZpq2JcvNItmC9ZowWRTB1V4Cx+bk0YkTLBSHc", + "type": "text" + }, + { + "key": "bban", + "value": "003001003879112168", + "type": "text" + }, + { + "key": "pageNumber", + "value": "1", + "type": "text" + }, + { + "key": "pageSize", + "value": "20", + "type": "text" + } + ] + }, + "url": { + "raw": "{{recon-url}}", + "host": [ + "{{recon-url}}" + ] + } + }, + "response": [ + { + "name": "Reconconciliation Success", + "originalRequest": { + "method": "GET", + "header": [], + "url": { + "raw": "{{recon-url}}", + "host": [ + "{{recon-url}}" + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Transfer-Encoding", + "value": "chunked" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "key": "Server", + "value": "Microsoft-IIS/10.0" + }, + { + "key": "X-Powered-By", + "value": "ASP.NET" + }, + { + "key": "Date", + "value": "Sun, 07 Aug 2022 16:59:09 GMT" + } + ], + "cookie": [], + "body": "{\n \"from\": \"2022-07-26T11:20:09.9260323Z\",\n \"to\": \"2022-07-27T11:20:09.9260323Z\",\n \"pageSize\": 200,\n \"pageCount\": 1,\n \"pageNumber\": 0,\n \"totalCount\": 12,\n \"bban\": \"003001003879112168\",\n \"transactions\": [\n {\n \"id\": 220,\n \"batchId\": \"1\",\n \"transactionDate\": \"2022-08-05T20:21:37.7514429\",\n \"credit\": 1000,\n \"debit\": 0,\n \"eTraxReferenceNumber\": 0,\n \"externalReferenceNumber\": 0,\n \"cbsDocumentNumber\": null,\n \"crossReferenceNumber\": 0,\n \"postedBy\": \"7a9e783c-0756-4754-9753-fb3c10c4bff9\",\n \"postedFrom\": \"102.176.189.6\",\n \"accountNumber\": \"003001003879112168\",\n \"ipAddress\": \"102.176.189.6\",\n \"notes\": \"eTrax: Transaction Request\",\n \"userId\": \"7a9e783c-0756-4754-9753-fb3c10c4bff9\",\n \"username\": \"falcoln\"\n },\n {\n \"id\": 218,\n \"batchId\": \"1\",\n \"transactionDate\": \"2022-08-05T20:05:05.3600922\",\n \"credit\": 1000,\n \"debit\": 0,\n \"eTraxReferenceNumber\": 0,\n \"externalReferenceNumber\": 0,\n \"cbsDocumentNumber\": null,\n \"crossReferenceNumber\": 0,\n \"postedBy\": \"7a9e783c-0756-4754-9753-fb3c10c4bff9\",\n \"postedFrom\": \"102.176.189.6\",\n \"accountNumber\": \"003001003879112168\",\n \"ipAddress\": \"102.176.189.6\",\n \"notes\": \"eTrax: Transaction Request\",\n \"userId\": \"7a9e783c-0756-4754-9753-fb3c10c4bff9\",\n \"username\": \"falcoln\"\n },\n {\n \"id\": 214,\n \"batchId\": \"1\",\n \"transactionDate\": \"2022-08-05T16:52:25.0407673\",\n \"credit\": 0,\n \"debit\": 250,\n \"eTraxReferenceNumber\": 0,\n \"externalReferenceNumber\": 0,\n \"cbsDocumentNumber\": null,\n \"crossReferenceNumber\": 0,\n \"postedBy\": \"965e708d-a7b6-49cf-8a38-c0c831108a6c\",\n \"postedFrom\": \"103.121.204.133\",\n \"accountNumber\": \"003001003879112168\",\n \"ipAddress\": \"103.121.204.133\",\n \"notes\": \"eTrax: Transaction Request\",\n \"userId\": \"965e708d-a7b6-49cf-8a38-c0c831108a6c\",\n \"username\": \"DSTI01\"\n },\n {\n \"id\": 212,\n \"batchId\": \"1\",\n \"transactionDate\": \"2022-08-05T16:52:24.7821909\",\n \"credit\": 0,\n \"debit\": 250,\n \"eTraxReferenceNumber\": 0,\n \"externalReferenceNumber\": 0,\n \"cbsDocumentNumber\": null,\n \"crossReferenceNumber\": 0,\n \"postedBy\": \"965e708d-a7b6-49cf-8a38-c0c831108a6c\",\n \"postedFrom\": \"103.121.204.133\",\n \"accountNumber\": \"003001003879112168\",\n \"ipAddress\": \"103.121.204.133\",\n \"notes\": \"eTrax: Transaction Request\",\n \"userId\": \"965e708d-a7b6-49cf-8a38-c0c831108a6c\",\n \"username\": \"DSTI01\"\n },\n {\n \"id\": 210,\n \"batchId\": \"1\",\n \"transactionDate\": \"2022-08-01T13:40:33.9013463\",\n \"credit\": 0,\n \"debit\": 250,\n \"eTraxReferenceNumber\": 0,\n \"externalReferenceNumber\": 0,\n \"cbsDocumentNumber\": null,\n \"crossReferenceNumber\": 0,\n \"postedBy\": \"965e708d-a7b6-49cf-8a38-c0c831108a6c\",\n \"postedFrom\": \"103.121.204.133\",\n \"accountNumber\": \"003001003879112168\",\n \"ipAddress\": \"103.121.204.133\",\n \"notes\": \"eTrax: Transaction Request\",\n \"userId\": \"965e708d-a7b6-49cf-8a38-c0c831108a6c\",\n \"username\": \"DSTI01\"\n },\n {\n \"id\": 208,\n \"batchId\": \"1\",\n \"transactionDate\": \"2022-08-01T13:40:33.8874229\",\n \"credit\": 0,\n \"debit\": 250,\n \"eTraxReferenceNumber\": 0,\n \"externalReferenceNumber\": 0,\n \"cbsDocumentNumber\": null,\n \"crossReferenceNumber\": 0,\n \"postedBy\": \"965e708d-a7b6-49cf-8a38-c0c831108a6c\",\n \"postedFrom\": \"103.121.204.133\",\n \"accountNumber\": \"003001003879112168\",\n \"ipAddress\": \"103.121.204.133\",\n \"notes\": \"eTrax: Transaction Request\",\n \"userId\": \"965e708d-a7b6-49cf-8a38-c0c831108a6c\",\n \"username\": \"DSTI01\"\n },\n {\n \"id\": 206,\n \"batchId\": \"1\",\n \"transactionDate\": \"2022-08-01T13:40:14.810255\",\n \"credit\": 0,\n \"debit\": 250000,\n \"eTraxReferenceNumber\": 0,\n \"externalReferenceNumber\": 0,\n \"cbsDocumentNumber\": null,\n \"crossReferenceNumber\": 0,\n \"postedBy\": \"965e708d-a7b6-49cf-8a38-c0c831108a6c\",\n \"postedFrom\": \"103.121.204.133\",\n \"accountNumber\": \"003001003879112168\",\n \"ipAddress\": \"103.121.204.133\",\n \"notes\": \"eTrax: Transaction Request\",\n \"userId\": \"965e708d-a7b6-49cf-8a38-c0c831108a6c\",\n \"username\": \"DSTI01\"\n },\n {\n \"id\": 204,\n \"batchId\": \"1\",\n \"transactionDate\": \"2022-08-01T13:40:14.6400784\",\n \"credit\": 0,\n \"debit\": 100000,\n \"eTraxReferenceNumber\": 0,\n \"externalReferenceNumber\": 0,\n \"cbsDocumentNumber\": null,\n \"crossReferenceNumber\": 0,\n \"postedBy\": \"965e708d-a7b6-49cf-8a38-c0c831108a6c\",\n \"postedFrom\": \"103.121.204.133\",\n \"accountNumber\": \"003001003879112168\",\n \"ipAddress\": \"103.121.204.133\",\n \"notes\": \"eTrax: Transaction Request\",\n \"userId\": \"965e708d-a7b6-49cf-8a38-c0c831108a6c\",\n \"username\": \"DSTI01\"\n },\n {\n \"id\": 202,\n \"batchId\": \"1\",\n \"transactionDate\": \"2022-07-29T14:48:04.4982544\",\n \"credit\": 0,\n \"debit\": 250000,\n \"eTraxReferenceNumber\": 0,\n \"externalReferenceNumber\": 0,\n \"cbsDocumentNumber\": null,\n \"crossReferenceNumber\": 0,\n \"postedBy\": \"965e708d-a7b6-49cf-8a38-c0c831108a6c\",\n \"postedFrom\": \"103.121.204.133\",\n \"accountNumber\": \"003001003879112168\",\n \"ipAddress\": \"103.121.204.133\",\n \"notes\": \"eTrax: Transaction Request\",\n \"userId\": \"965e708d-a7b6-49cf-8a38-c0c831108a6c\",\n \"username\": \"DSTI01\"\n },\n {\n \"id\": 200,\n \"batchId\": \"1\",\n \"transactionDate\": \"2022-07-29T14:48:04.2474515\",\n \"credit\": 0,\n \"debit\": 100000,\n \"eTraxReferenceNumber\": 0,\n \"externalReferenceNumber\": 0,\n \"cbsDocumentNumber\": null,\n \"crossReferenceNumber\": 0,\n \"postedBy\": \"965e708d-a7b6-49cf-8a38-c0c831108a6c\",\n \"postedFrom\": \"103.121.204.133\",\n \"accountNumber\": \"003001003879112168\",\n \"ipAddress\": \"103.121.204.133\",\n \"notes\": \"eTrax: Transaction Request\",\n \"userId\": \"965e708d-a7b6-49cf-8a38-c0c831108a6c\",\n \"username\": \"DSTI01\"\n },\n {\n \"id\": 199,\n \"batchId\": null,\n \"transactionDate\": \"2022-07-29T11:38:49.0708892\",\n \"credit\": 5000000,\n \"debit\": 0,\n \"eTraxReferenceNumber\": 0,\n \"externalReferenceNumber\": 0,\n \"cbsDocumentNumber\": null,\n \"crossReferenceNumber\": 0,\n \"postedBy\": \"eb85fa53-0d7e-a585-b2b3-3a03a6a76323\",\n \"postedFrom\": null,\n \"accountNumber\": \"003001003879112168\",\n \"ipAddress\": null,\n \"notes\": null,\n \"userId\": \"eb85fa53-0d7e-a585-b2b3-3a03a6a76323\",\n \"username\": \"admin\"\n },\n {\n \"id\": 197,\n \"batchId\": null,\n \"transactionDate\": \"2022-07-29T11:37:36.2823965\",\n \"credit\": 5000000,\n \"debit\": 0,\n \"eTraxReferenceNumber\": 0,\n \"externalReferenceNumber\": 0,\n \"cbsDocumentNumber\": null,\n \"crossReferenceNumber\": 0,\n \"postedBy\": \"eb85fa53-0d7e-a585-b2b3-3a03a6a76323\",\n \"postedFrom\": null,\n \"accountNumber\": \"003001003879112168\",\n \"ipAddress\": null,\n \"notes\": null,\n \"userId\": \"eb85fa53-0d7e-a585-b2b3-3a03a6a76323\",\n \"username\": \"admin\"\n }\n ]\n}" + }, + { + "name": "Reconcoliation", + "originalRequest": { + "method": "GET", + "header": [], + "url": { + "raw": "{{recon-url}}", + "host": [ + "{{recon-url}}" + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Transfer-Encoding", + "value": "chunked" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "key": "Server", + "value": "Microsoft-IIS/10.0" + }, + { + "key": "X-Powered-By", + "value": "ASP.NET" + }, + { + "key": "Date", + "value": "Fri, 02 Sep 2022 12:01:21 GMT" + } + ], + "cookie": [], + "body": "{\n \"from\": \"2022-08-08T00:00:00\",\n \"to\": \"2022-09-08T00:00:00\",\n \"pageSize\": 20,\n \"pageCount\": 2,\n \"pageNumber\": 1,\n \"totalCount\": 32,\n \"bban\": \"003001003879112168\",\n \"comment\": null,\n \"isError\": false,\n \"transactions\": [\n {\n \"id\": 60,\n \"batchId\": \"1\",\n \"transactionDate\": \"2022-09-02T11:35:16.9948387\",\n \"credit\": 2000,\n \"debit\": 0,\n \"eTraxReferenceNumber\": 0,\n \"externalReferenceNumber\": 0,\n \"cbsDocumentNumber\": \"N/A\",\n \"crossReferenceNumber\": 59,\n \"postedBy\": \"7f95c766-6681-4cff-acde-8f4aab6bed53\",\n \"postedFrom\": \"102.176.189.6\",\n \"accountNumber\": \"003001003874120160\",\n \"ipAddress\": \"102.176.189.6\",\n \"notes\": \"eTrax: Internal Transaction Request (CREDIT)\",\n \"userId\": \"7f95c766-6681-4cff-acde-8f4aab6bed53\",\n \"username\": \"DSTI01\"\n },\n {\n \"id\": 59,\n \"batchId\": \"1\",\n \"transactionDate\": \"2022-09-02T11:35:16.9920637\",\n \"credit\": 0,\n \"debit\": 2000,\n \"eTraxReferenceNumber\": 0,\n \"externalReferenceNumber\": 0,\n \"cbsDocumentNumber\": \"N/A\",\n \"crossReferenceNumber\": 59,\n \"postedBy\": \"7f95c766-6681-4cff-acde-8f4aab6bed53\",\n \"postedFrom\": \"102.176.189.6\",\n \"accountNumber\": \"003001003879112168\",\n \"ipAddress\": \"102.176.189.6\",\n \"notes\": \"eTrax: Internal Transaction Request (DEBIT)\",\n \"userId\": \"7f95c766-6681-4cff-acde-8f4aab6bed53\",\n \"username\": \"DSTI01\"\n },\n {\n \"id\": 59,\n \"batchId\": \"1\",\n \"transactionDate\": \"2022-09-02T11:35:16.9920637\",\n \"credit\": 0,\n \"debit\": 2000,\n \"eTraxReferenceNumber\": 0,\n \"externalReferenceNumber\": 0,\n \"cbsDocumentNumber\": \"N/A\",\n \"crossReferenceNumber\": 59,\n \"postedBy\": \"7f95c766-6681-4cff-acde-8f4aab6bed53\",\n \"postedFrom\": \"102.176.189.6\",\n \"accountNumber\": \"003001003879112168\",\n \"ipAddress\": \"102.176.189.6\",\n \"notes\": \"eTrax: Internal Transaction Request (DEBIT)\",\n \"userId\": \"7f95c766-6681-4cff-acde-8f4aab6bed53\",\n \"username\": \"DSTI01\"\n },\n {\n \"id\": 58,\n \"batchId\": \"1\",\n \"transactionDate\": \"2022-09-02T11:34:58.1952072\",\n \"credit\": 1000,\n \"debit\": 0,\n \"eTraxReferenceNumber\": 0,\n \"externalReferenceNumber\": 0,\n \"cbsDocumentNumber\": \"N/A\",\n \"crossReferenceNumber\": 57,\n \"postedBy\": \"7f95c766-6681-4cff-acde-8f4aab6bed53\",\n \"postedFrom\": \"102.176.189.6\",\n \"accountNumber\": \"003001003874120160\",\n \"ipAddress\": \"102.176.189.6\",\n \"notes\": \"eTrax: Internal Transaction Request (CREDIT)\",\n \"userId\": \"7f95c766-6681-4cff-acde-8f4aab6bed53\",\n \"username\": \"DSTI01\"\n },\n {\n \"id\": 57,\n \"batchId\": \"1\",\n \"transactionDate\": \"2022-09-02T11:34:58.1918194\",\n \"credit\": 0,\n \"debit\": 1000,\n \"eTraxReferenceNumber\": 0,\n \"externalReferenceNumber\": 0,\n \"cbsDocumentNumber\": \"N/A\",\n \"crossReferenceNumber\": 57,\n \"postedBy\": \"7f95c766-6681-4cff-acde-8f4aab6bed53\",\n \"postedFrom\": \"102.176.189.6\",\n \"accountNumber\": \"003001003879112168\",\n \"ipAddress\": \"102.176.189.6\",\n \"notes\": \"eTrax: Internal Transaction Request (DEBIT)\",\n \"userId\": \"7f95c766-6681-4cff-acde-8f4aab6bed53\",\n \"username\": \"DSTI01\"\n },\n {\n \"id\": 57,\n \"batchId\": \"1\",\n \"transactionDate\": \"2022-09-02T11:34:58.1918194\",\n \"credit\": 0,\n \"debit\": 1000,\n \"eTraxReferenceNumber\": 0,\n \"externalReferenceNumber\": 0,\n \"cbsDocumentNumber\": \"N/A\",\n \"crossReferenceNumber\": 57,\n \"postedBy\": \"7f95c766-6681-4cff-acde-8f4aab6bed53\",\n \"postedFrom\": \"102.176.189.6\",\n \"accountNumber\": \"003001003879112168\",\n \"ipAddress\": \"102.176.189.6\",\n \"notes\": \"eTrax: Internal Transaction Request (DEBIT)\",\n \"userId\": \"7f95c766-6681-4cff-acde-8f4aab6bed53\",\n \"username\": \"DSTI01\"\n },\n {\n \"id\": 56,\n \"batchId\": \"1\",\n \"transactionDate\": \"2022-09-02T11:30:43.9429779\",\n \"credit\": 1000,\n \"debit\": 0,\n \"eTraxReferenceNumber\": 0,\n \"externalReferenceNumber\": 0,\n \"cbsDocumentNumber\": \"N/A\",\n \"crossReferenceNumber\": 55,\n \"postedBy\": \"7f95c766-6681-4cff-acde-8f4aab6bed53\",\n \"postedFrom\": \"102.176.189.6\",\n \"accountNumber\": \"003001003879112168\",\n \"ipAddress\": \"102.176.189.6\",\n \"notes\": \"eTrax: Internal Transaction Request (CREDIT)\",\n \"userId\": \"7f95c766-6681-4cff-acde-8f4aab6bed53\",\n \"username\": \"DSTI01\"\n },\n {\n \"id\": 56,\n \"batchId\": \"1\",\n \"transactionDate\": \"2022-09-02T11:30:43.9429779\",\n \"credit\": 1000,\n \"debit\": 0,\n \"eTraxReferenceNumber\": 0,\n \"externalReferenceNumber\": 0,\n \"cbsDocumentNumber\": \"N/A\",\n \"crossReferenceNumber\": 55,\n \"postedBy\": \"7f95c766-6681-4cff-acde-8f4aab6bed53\",\n \"postedFrom\": \"102.176.189.6\",\n \"accountNumber\": \"003001003879112168\",\n \"ipAddress\": \"102.176.189.6\",\n \"notes\": \"eTrax: Internal Transaction Request (CREDIT)\",\n \"userId\": \"7f95c766-6681-4cff-acde-8f4aab6bed53\",\n \"username\": \"DSTI01\"\n },\n {\n \"id\": 55,\n \"batchId\": \"1\",\n \"transactionDate\": \"2022-09-02T11:30:43.9397666\",\n \"credit\": 0,\n \"debit\": 1000,\n \"eTraxReferenceNumber\": 0,\n \"externalReferenceNumber\": 0,\n \"cbsDocumentNumber\": \"N/A\",\n \"crossReferenceNumber\": 55,\n \"postedBy\": \"7f95c766-6681-4cff-acde-8f4aab6bed53\",\n \"postedFrom\": \"102.176.189.6\",\n \"accountNumber\": \"003001003879112168\",\n \"ipAddress\": \"102.176.189.6\",\n \"notes\": \"eTrax: Internal Transaction Request (DEBIT)\",\n \"userId\": \"7f95c766-6681-4cff-acde-8f4aab6bed53\",\n \"username\": \"DSTI01\"\n },\n {\n \"id\": 55,\n \"batchId\": \"1\",\n \"transactionDate\": \"2022-09-02T11:30:43.9397666\",\n \"credit\": 0,\n \"debit\": 1000,\n \"eTraxReferenceNumber\": 0,\n \"externalReferenceNumber\": 0,\n \"cbsDocumentNumber\": \"N/A\",\n \"crossReferenceNumber\": 55,\n \"postedBy\": \"7f95c766-6681-4cff-acde-8f4aab6bed53\",\n \"postedFrom\": \"102.176.189.6\",\n \"accountNumber\": \"003001003879112168\",\n \"ipAddress\": \"102.176.189.6\",\n \"notes\": \"eTrax: Internal Transaction Request (DEBIT)\",\n \"userId\": \"7f95c766-6681-4cff-acde-8f4aab6bed53\",\n \"username\": \"DSTI01\"\n },\n {\n \"id\": 54,\n \"batchId\": \"1\",\n \"transactionDate\": \"2022-09-02T11:20:40.7743261\",\n \"credit\": 250,\n \"debit\": 0,\n \"eTraxReferenceNumber\": 0,\n \"externalReferenceNumber\": 0,\n \"cbsDocumentNumber\": \"N/A\",\n \"crossReferenceNumber\": 53,\n \"postedBy\": \"7f95c766-6681-4cff-acde-8f4aab6bed53\",\n \"postedFrom\": \"203.81.242.121\",\n \"accountNumber\": \"003001003874120160\",\n \"ipAddress\": \"203.81.242.121\",\n \"notes\": \"eTrax: Internal Transaction Request (CREDIT)\",\n \"userId\": \"7f95c766-6681-4cff-acde-8f4aab6bed53\",\n \"username\": \"DSTI01\"\n },\n {\n \"id\": 53,\n \"batchId\": \"1\",\n \"transactionDate\": \"2022-09-02T11:20:40.7719825\",\n \"credit\": 0,\n \"debit\": 250,\n \"eTraxReferenceNumber\": 0,\n \"externalReferenceNumber\": 0,\n \"cbsDocumentNumber\": \"N/A\",\n \"crossReferenceNumber\": 53,\n \"postedBy\": \"7f95c766-6681-4cff-acde-8f4aab6bed53\",\n \"postedFrom\": \"203.81.242.121\",\n \"accountNumber\": \"003001003879112168\",\n \"ipAddress\": \"203.81.242.121\",\n \"notes\": \"eTrax: Internal Transaction Request (DEBIT)\",\n \"userId\": \"7f95c766-6681-4cff-acde-8f4aab6bed53\",\n \"username\": \"DSTI01\"\n },\n {\n \"id\": 53,\n \"batchId\": \"1\",\n \"transactionDate\": \"2022-09-02T11:20:40.7719825\",\n \"credit\": 0,\n \"debit\": 250,\n \"eTraxReferenceNumber\": 0,\n \"externalReferenceNumber\": 0,\n \"cbsDocumentNumber\": \"N/A\",\n \"crossReferenceNumber\": 53,\n \"postedBy\": \"7f95c766-6681-4cff-acde-8f4aab6bed53\",\n \"postedFrom\": \"203.81.242.121\",\n \"accountNumber\": \"003001003879112168\",\n \"ipAddress\": \"203.81.242.121\",\n \"notes\": \"eTrax: Internal Transaction Request (DEBIT)\",\n \"userId\": \"7f95c766-6681-4cff-acde-8f4aab6bed53\",\n \"username\": \"DSTI01\"\n },\n {\n \"id\": 52,\n \"batchId\": \"1\",\n \"transactionDate\": \"2022-09-02T11:20:40.7170309\",\n \"credit\": 250,\n \"debit\": 0,\n \"eTraxReferenceNumber\": 0,\n \"externalReferenceNumber\": 0,\n \"cbsDocumentNumber\": \"N/A\",\n \"crossReferenceNumber\": 51,\n \"postedBy\": \"7f95c766-6681-4cff-acde-8f4aab6bed53\",\n \"postedFrom\": \"203.81.242.121\",\n \"accountNumber\": \"003001003873110196\",\n \"ipAddress\": \"203.81.242.121\",\n \"notes\": \"eTrax: Internal Transaction Request (CREDIT)\",\n \"userId\": \"7f95c766-6681-4cff-acde-8f4aab6bed53\",\n \"username\": \"DSTI01\"\n },\n {\n \"id\": 51,\n \"batchId\": \"1\",\n \"transactionDate\": \"2022-09-02T11:20:40.5814167\",\n \"credit\": 0,\n \"debit\": 250,\n \"eTraxReferenceNumber\": 0,\n \"externalReferenceNumber\": 0,\n \"cbsDocumentNumber\": \"N/A\",\n \"crossReferenceNumber\": 51,\n \"postedBy\": \"7f95c766-6681-4cff-acde-8f4aab6bed53\",\n \"postedFrom\": \"203.81.242.121\",\n \"accountNumber\": \"003001003879112168\",\n \"ipAddress\": \"203.81.242.121\",\n \"notes\": \"eTrax: Internal Transaction Request (DEBIT)\",\n \"userId\": \"7f95c766-6681-4cff-acde-8f4aab6bed53\",\n \"username\": \"DSTI01\"\n },\n {\n \"id\": 51,\n \"batchId\": \"1\",\n \"transactionDate\": \"2022-09-02T11:20:40.5814167\",\n \"credit\": 0,\n \"debit\": 250,\n \"eTraxReferenceNumber\": 0,\n \"externalReferenceNumber\": 0,\n \"cbsDocumentNumber\": \"N/A\",\n \"crossReferenceNumber\": 51,\n \"postedBy\": \"7f95c766-6681-4cff-acde-8f4aab6bed53\",\n \"postedFrom\": \"203.81.242.121\",\n \"accountNumber\": \"003001003879112168\",\n \"ipAddress\": \"203.81.242.121\",\n \"notes\": \"eTrax: Internal Transaction Request (DEBIT)\",\n \"userId\": \"7f95c766-6681-4cff-acde-8f4aab6bed53\",\n \"username\": \"DSTI01\"\n },\n {\n \"id\": 50,\n \"batchId\": \"1\",\n \"transactionDate\": \"2022-09-02T02:46:18.9079563\",\n \"credit\": 1000,\n \"debit\": 0,\n \"eTraxReferenceNumber\": 0,\n \"externalReferenceNumber\": 0,\n \"cbsDocumentNumber\": \"N/A\",\n \"crossReferenceNumber\": 49,\n \"postedBy\": \"7a9e783c-0756-4754-9753-fb3c10c4bff9\",\n \"postedFrom\": \"102.176.189.6\",\n \"accountNumber\": \"003001003879112168\",\n \"ipAddress\": \"102.176.189.6\",\n \"notes\": \"eTrax: Internal Transaction Request (CREDIT)\",\n \"userId\": \"7a9e783c-0756-4754-9753-fb3c10c4bff9\",\n \"username\": \"falcoln\"\n },\n {\n \"id\": 48,\n \"batchId\": \"13340d58-a2f3-4641-869d-5edf74fb6cf9\",\n \"transactionDate\": \"2022-08-31T13:44:02.5427481\",\n \"credit\": 100,\n \"debit\": 0,\n \"eTraxReferenceNumber\": 0,\n \"externalReferenceNumber\": 0,\n \"cbsDocumentNumber\": \"N/A\",\n \"crossReferenceNumber\": 47,\n \"postedBy\": \"7f95c766-6681-4cff-acde-8f4aab6bed53\",\n \"postedFrom\": \"102.223.155.55\",\n \"accountNumber\": \"003001003873110196\",\n \"ipAddress\": \"102.223.155.55\",\n \"notes\": \"eTrax: Internal Transaction Request (CREDIT)\",\n \"userId\": \"7f95c766-6681-4cff-acde-8f4aab6bed53\",\n \"username\": \"DSTI01\"\n },\n {\n \"id\": 47,\n \"batchId\": \"13340d58-a2f3-4641-869d-5edf74fb6cf9\",\n \"transactionDate\": \"2022-08-31T13:44:02.3553769\",\n \"credit\": 0,\n \"debit\": 100,\n \"eTraxReferenceNumber\": 0,\n \"externalReferenceNumber\": 0,\n \"cbsDocumentNumber\": \"N/A\",\n \"crossReferenceNumber\": 47,\n \"postedBy\": \"7f95c766-6681-4cff-acde-8f4aab6bed53\",\n \"postedFrom\": \"102.223.155.55\",\n \"accountNumber\": \"003001003879112168\",\n \"ipAddress\": \"102.223.155.55\",\n \"notes\": \"eTrax: Internal Transaction Request (DEBIT)\",\n \"userId\": \"7f95c766-6681-4cff-acde-8f4aab6bed53\",\n \"username\": \"DSTI01\"\n },\n {\n \"id\": 47,\n \"batchId\": \"13340d58-a2f3-4641-869d-5edf74fb6cf9\",\n \"transactionDate\": \"2022-08-31T13:44:02.3553769\",\n \"credit\": 0,\n \"debit\": 100,\n \"eTraxReferenceNumber\": 0,\n \"externalReferenceNumber\": 0,\n \"cbsDocumentNumber\": \"N/A\",\n \"crossReferenceNumber\": 47,\n \"postedBy\": \"7f95c766-6681-4cff-acde-8f4aab6bed53\",\n \"postedFrom\": \"102.223.155.55\",\n \"accountNumber\": \"003001003879112168\",\n \"ipAddress\": \"102.223.155.55\",\n \"notes\": \"eTrax: Internal Transaction Request (DEBIT)\",\n \"userId\": \"7f95c766-6681-4cff-acde-8f4aab6bed53\",\n \"username\": \"DSTI01\"\n }\n ]\n}" + } + ] + }, + { + "name": "Get Auth Code", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n\n \"SimplePhrase\":\"This is a test\",\n\n \"PublicKey\":\"-----BEGIN PUBLIC KEY-----MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA50JDuWUMXEyyE0a6PdOVFLU7xRv9lOrWQXKj1K/eseoFMU1jgrx5rdQOVeNmU0N4cbd7h02Ml++As1VzhW2xeArbsdrtXiPFXEBeHvywdLHD7oF2Ox0FqiO7VMbLm+eAc1URh2yveo7VWxOqB1f8maj2rdcguVsR29ccOKqY+rgJ85EN77/hJE6WH7De4MFI/gn3aXz9mBcmg7O+CRGFqRH4IiIEhXQ5XEaj2LWs/LkQSmrZA5J+uonUqIWsuqUCG0JuErbEXCXffMyjb4kxSaE3CW7y1cYznmcC2dyWTCNcfYpM0hyqXQGQl5eVPnvr9mJVc1KH51M4uJ5wYvDOOwIDAQAB-----END PUBLIC KEY-----\",\n\n \"AuthorizationCode\":\"\"\n\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{authCodeUrl}}", + "host": [ + "{{authCodeUrl}}" + ] + } + }, + "response": [ + { + "name": "Get Auth Code 200", + "originalRequest": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n\n \"SimplePhrase\":\"This is a test\",\n\n \"PublicKey\":\"-----BEGIN PUBLIC KEY-----MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA50JDuWUMXEyyE0a6PdOVFLU7xRv9lOrWQXKj1K/eseoFMU1jgrx5rdQOVeNmU0N4cbd7h02Ml++As1VzhW2xeArbsdrtXiPFXEBeHvywdLHD7oF2Ox0FqiO7VMbLm+eAc1URh2yveo7VWxOqB1f8maj2rdcguVsR29ccOKqY+rgJ85EN77/hJE6WH7De4MFI/gn3aXz9mBcmg7O+CRGFqRH4IiIEhXQ5XEaj2LWs/LkQSmrZA5J+uonUqIWsuqUCG0JuErbEXCXffMyjb4kxSaE3CW7y1cYznmcC2dyWTCNcfYpM0hyqXQGQl5eVPnvr9mJVc1KH51M4uJ5wYvDOOwIDAQAB-----END PUBLIC KEY-----\",\n\n \"AuthorizationCode\":\"\"\n\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{authCodeUrl}}", + "host": [ + "{{authCodeUrl}}" + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Transfer-Encoding", + "value": "chunked" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "key": "Server", + "value": "Microsoft-IIS/10.0" + }, + { + "key": "X-Powered-By", + "value": "ASP.NET" + }, + { + "key": "Date", + "value": "Fri, 28 Oct 2022 10:19:50 GMT" + } + ], + "cookie": [], + "body": "{\n \"simplePhrase\": \"This is a test\",\n \"publicKey\": \"-----BEGIN PUBLIC KEY-----MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA50JDuWUMXEyyE0a6PdOVFLU7xRv9lOrWQXKj1K/eseoFMU1jgrx5rdQOVeNmU0N4cbd7h02Ml++As1VzhW2xeArbsdrtXiPFXEBeHvywdLHD7oF2Ox0FqiO7VMbLm+eAc1URh2yveo7VWxOqB1f8maj2rdcguVsR29ccOKqY+rgJ85EN77/hJE6WH7De4MFI/gn3aXz9mBcmg7O+CRGFqRH4IiIEhXQ5XEaj2LWs/LkQSmrZA5J+uonUqIWsuqUCG0JuErbEXCXffMyjb4kxSaE3CW7y1cYznmcC2dyWTCNcfYpM0hyqXQGQl5eVPnvr9mJVc1KH51M4uJ5wYvDOOwIDAQAB-----END PUBLIC KEY-----\",\n \"authorizationCode\": \"D9A1A0042DBFB0E4011535095C4975D2FA27BAF6E1FE3BDC7E05F11D2A9D9C732ABFCD9384703993E3A33F44B1F255786F44CEFE2C15BA37FC4921DB9D94AE31955BA60F85F01ACCC3BA1E3C367AE093707311B4CBC3B940174EBE07DE302DBBB53FC7CD637BE6C46C8CD3539B58DCF919D85245BA6995285D3DE851E263F20A06FDDEA45EA1D74429FAC7506C061AB894BCC9CB893122675F2BBB42764DF286A85C0B926CEBA51441FAD5034EBA053E1BC9AA259A014ADEBCBF0189C465B0C67B56F925A7F41D29515C01BE49AFEE968BC3E9DE84F460874661E881CA786ED794646990CFABFF14E45A9854A95CF2EB5E3EF02837BE31B084F87F14125678F7\"\n}" + } + ] + } + ] + }, + { + "name": "MPESA", + "item": [] + } + ] + }, + { + "name": "AMS", + "item": [ + { + "name": "Paygops", + "item": [] + }, + { + "name": "Roaster", + "item": [] + } + ] + } + ] +} \ No newline at end of file diff --git a/ph-ee-env-template/PostmanCollections/External/Kong CE Admin API V2.0.postman_collection.json b/ph-ee-env-template/PostmanCollections/External/Kong CE Admin API V2.0.postman_collection.json new file mode 100644 index 000000000..0736505d2 --- /dev/null +++ b/ph-ee-env-template/PostmanCollections/External/Kong CE Admin API V2.0.postman_collection.json @@ -0,0 +1,10483 @@ +{ + "info": { + "_postman_id": "4f0308dc-bf79-4976-8752-29dd949122ec", + "name": "Kong CE Admin API V2.0", + "description": "\"Kong\n
\n\nThis Postman Collection refers to the [Kong Community Edition Admin API](https://docs.konghq.com/2.0.x/admin-api/) for running Kong configured with a database (Postgres or Cassandra). For using the Admin API for Kong in DB-less mode, please refer to the Admin API for DB-less Mode [konghq](https://docs.konghq.com/2.0.x/db-less-admin-api/).
\n\n**Disclaimer**: Collection not hardened by development AToW [George Jeffcock](https://www.linkedin.com/in/georgejeffcock/)\n\nKong comes with an internal RESTful Admin API for administration purposes. Requests to the Admin API can be sent to any node in the cluster, and Kong will keep the configuration consistent across all nodes.\n\n* **8001** is the default port on which the Admin API listens.\n* **8444** is the default port for HTTPS traffic to the Admin API.\n\nThis API is designed for internal use and provides full control over Kong, so care should be taken when setting up Kong environments to avoid undue public exposure of this API. See this [document](https://docs.konghq.com/2.0.x/secure-admin-api/) for a discussion of methods to secure the Admin API.\n\n# Supported Content Types\n* The Admin API accepts 2 content types on every endpoint:\n* application/x-www-form-urlencoded\n * Simple enough for basic request bodies, you will probably use it most of the time. Note that when sending nested values, Kong expects nested objects to be referenced with dotted keys\n * Example: config.limit=10&config.period=seconds\n* application/json\n * Handy for complex bodies (ex: complex plugin configuration), in that case simply send a JSON representation of the data you want to send.\n * Example:\n {\"config\": {\"limit\": 10, \"period\": \"seconds\"}}", + "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json", + "_exporter_id": "17902615", + "_collection_link": "https://martian-firefly-704030.postman.co/workspace/Fynarfin~cbeb07e6-89cb-4850-a0f6-5647e70b83e2/collection/17902615-4f0308dc-bf79-4976-8752-29dd949122ec?action=share&creator=17902615&source=collection_link" + }, + "item": [ + { + "name": "Information Routes ", + "item": [ + { + "name": "Retrieve Node Information", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{gateway}}/", + "host": [ + "{{gateway}}" + ], + "path": [ + "" + ] + }, + "description": "## Retieve generic details about a node [konghq](https://docs.konghq.com/2.0.x/admin-api/#retrieve-node-information)\n\n* node_id: A UUID representing the running Kong node. This UUID is randomly generated when Kong starts, so the node will have a different node_id each time it is restarted.\n* available_on_server: Names of plugins that are installed on the node.\n* nabled_in_cluster: Names of plugins that are enabled/configured. That is, the plugins configurations currently in the datastore shared by all Kong nodes." + }, + "response": [ + { + "name": "Retrieve Node Information - 200", + "originalRequest": { + "method": "GET", + "header": [], + "url": { + "raw": "https://localhost:8444/", + "protocol": "https", + "host": [ + "localhost" + ], + "port": "8444", + "path": [ + "" + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "Text", + "header": [ + { + "key": "Date", + "value": "Fri, 06 Mar 2020 15:13:42 GMT" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "Server", + "value": "kong/2.0.1" + }, + { + "key": "Content-Length", + "value": "8664" + }, + { + "key": "X-Kong-Admin-Latency", + "value": "1" + } + ], + "cookie": [], + "body": "{\n \"plugins\": {\n \"enabled_in_cluster\": [],\n \"available_on_server\": {\n \"correlation-id\": true,\n \"pre-function\": true,\n \"cors\": true,\n \"ldap-auth\": true,\n \"loggly\": true,\n \"hmac-auth\": true,\n \"zipkin\": true,\n \"request-size-limiting\": true,\n \"azure-functions\": true,\n \"request-transformer\": true,\n \"oauth2\": true,\n \"response-transformer\": true,\n \"ip-restriction\": true,\n \"statsd\": true,\n \"jwt\": true,\n \"proxy-cache\": true,\n \"basic-auth\": true,\n \"key-auth\": true,\n \"http-log\": true,\n \"datadog\": true,\n \"tcp-log\": true,\n \"post-function\": true,\n \"prometheus\": true,\n \"acl\": true,\n \"syslog\": true,\n \"file-log\": true,\n \"session\": true,\n \"udp-log\": true,\n \"response-ratelimiting\": true,\n \"aws-lambda\": true,\n \"bot-detection\": true,\n \"rate-limiting\": true,\n \"request-termination\": true\n }\n },\n \"tagline\": \"Welcome to kong\",\n \"configuration\": {\n \"plugins\": [\n \"bundled\"\n ],\n \"admin_listen\": [\n \"0.0.0.0:8001\",\n \"0.0.0.0:8444 ssl\"\n ],\n \"lua_ssl_verify_depth\": 1,\n \"prefix\": \"/usr/local/kong\",\n \"nginx_conf\": \"/usr/local/kong/nginx.conf\",\n \"cassandra_username\": \"kong\",\n \"nginx_events_directives\": [\n {\n \"value\": \"auto\",\n \"name\": \"worker_connections\"\n },\n {\n \"value\": \"on\",\n \"name\": \"multi_accept\"\n }\n ],\n \"admin_ssl_cert_key\": \"/usr/local/kong/ssl/admin-kong-default.key\",\n \"dns_resolver\": {},\n \"nginx_upstream_keepalive_requests\": \"100\",\n \"nginx_http_upstream_directives\": [\n {\n \"value\": \"100\",\n \"name\": \"keepalive_requests\"\n },\n {\n \"value\": \"60s\",\n \"name\": \"keepalive_timeout\"\n },\n {\n \"value\": \"60\",\n \"name\": \"keepalive\"\n }\n ],\n \"nginx_main_daemon\": \"off\",\n \"stream_proxy_ssl_enabled\": false,\n \"nginx_acc_logs\": \"/usr/local/kong/logs/access.log\",\n \"pg_semaphore_timeout\": 60000,\n \"proxy_listen\": [\n \"0.0.0.0:8000 reuseport backlog=16384\",\n \"0.0.0.0:8443 http2 ssl reuseport backlog=16384\"\n ],\n \"client_ssl_cert_default\": \"/usr/local/kong/ssl/kong-default.crt\",\n \"go_pluginserver_exe\": \"/usr/local/bin/go-pluginserver\",\n \"dns_no_sync\": false,\n \"db_update_propagation\": 0,\n \"stream_listen\": [\n \"off\"\n ],\n \"nginx_err_logs\": \"/usr/local/kong/logs/error.log\",\n \"cassandra_port\": 9042,\n \"headers\": [\n \"server_tokens\",\n \"latency_tokens\"\n ],\n \"nginx_http_client_max_body_size\": \"0\",\n \"status_listen\": [\n \"off\"\n ],\n \"nginx_status_directives\": {},\n \"cluster_control_plane\": \"127.0.0.1:8005\",\n \"nginx_http_ssl_prefer_server_ciphers\": \"off\",\n \"pg_database\": \"kong\",\n \"nginx_http_client_body_buffer_size\": \"8k\",\n \"admin_acc_logs\": \"/usr/local/kong/logs/admin_access.log\",\n \"cassandra_refresh_frequency\": 60,\n \"nginx_pid\": \"/usr/local/kong/pids/nginx.pid\",\n \"nginx_main_worker_rlimit_nofile\": \"auto\",\n \"admin_access_log\": \"/dev/stdout\",\n \"proxy_listeners\": [\n {\n \"listener\": \"0.0.0.0:8000 reuseport backlog=16384\",\n \"proxy_protocol\": false,\n \"reuseport\": true,\n \"deferred\": false,\n \"ssl\": false,\n \"ip\": \"0.0.0.0\",\n \"backlog=16384\": true,\n \"http2\": false,\n \"port\": 8000,\n \"bind\": false\n },\n {\n \"listener\": \"0.0.0.0:8443 ssl http2 reuseport backlog=16384\",\n \"proxy_protocol\": false,\n \"reuseport\": true,\n \"deferred\": false,\n \"ssl\": true,\n \"ip\": \"0.0.0.0\",\n \"backlog=16384\": true,\n \"http2\": true,\n \"port\": 8443,\n \"bind\": false\n }\n ],\n \"db_cache_warmup_entities\": [\n \"services\",\n \"plugins\"\n ],\n \"enabled_headers\": {\n \"latency_tokens\": true,\n \"X-Kong-Response-Latency\": true,\n \"Server\": true,\n \"X-Kong-Admin-Latency\": true,\n \"X-Kong-Upstream-Status\": false,\n \"Via\": true,\n \"X-Kong-Proxy-Latency\": true,\n \"server_tokens\": true,\n \"X-Kong-Upstream-Latency\": true\n },\n \"nginx_http_ssl_protocols\": \"TLSv1.2 TLSv1.3\",\n \"db_cache_ttl\": 0,\n \"nginx_events_multi_accept\": \"on\",\n \"admin_ssl_cert_default\": \"/usr/local/kong/ssl/admin-kong-default.crt\",\n \"pg_ssl\": false,\n \"status_access_log\": \"off\",\n \"cluster_listeners\": [\n {\n \"listener\": \"0.0.0.0:8005\",\n \"proxy_protocol\": false,\n \"reuseport\": false,\n \"backlog=%d+\": false,\n \"deferred\": false,\n \"ssl\": false,\n \"ip\": \"0.0.0.0\",\n \"port\": 8005,\n \"http2\": false,\n \"bind\": false\n }\n ],\n \"kong_env\": \"/usr/local/kong/.kong_env\",\n \"cassandra_schema_consensus_timeout\": 10000,\n \"log_level\": \"notice\",\n \"admin_ssl_cert_key_default\": \"/usr/local/kong/ssl/admin-kong-default.key\",\n \"real_ip_recursive\": \"off\",\n \"proxy_error_log\": \"/dev/stderr\",\n \"ssl_cipher_suite\": \"intermediate\",\n \"router_consistency\": \"strict\",\n \"pg_port\": 5432,\n \"cassandra_keyspace\": \"kong\",\n \"ssl_cert_default\": \"/usr/local/kong/ssl/kong-default.crt\",\n \"nginx_http_ssl_session_timeout\": \"1d\",\n \"nginx_upstream_directives\": [\n {\n \"value\": \"100\",\n \"name\": \"keepalive_requests\"\n },\n {\n \"value\": \"60s\",\n \"name\": \"keepalive_timeout\"\n },\n {\n \"value\": \"60\",\n \"name\": \"keepalive\"\n }\n ],\n \"role\": \"traditional\",\n \"admin_ssl_enabled\": true,\n \"trusted_ips\": {},\n \"loaded_plugins\": {\n \"correlation-id\": true,\n \"pre-function\": true,\n \"cors\": true,\n \"rate-limiting\": true,\n \"loggly\": true,\n \"hmac-auth\": true,\n \"zipkin\": true,\n \"bot-detection\": true,\n \"azure-functions\": true,\n \"request-transformer\": true,\n \"oauth2\": true,\n \"response-transformer\": true,\n \"syslog\": true,\n \"statsd\": true,\n \"jwt\": true,\n \"proxy-cache\": true,\n \"basic-auth\": true,\n \"key-auth\": true,\n \"http-log\": true,\n \"datadog\": true,\n \"tcp-log\": true,\n \"post-function\": true,\n \"ldap-auth\": true,\n \"acl\": true,\n \"ip-restriction\": true,\n \"file-log\": true,\n \"prometheus\": true,\n \"udp-log\": true,\n \"response-ratelimiting\": true,\n \"aws-lambda\": true,\n \"request-size-limiting\": true,\n \"session\": true,\n \"request-termination\": true\n },\n \"nginx_supstream_directives\": {},\n \"ssl_cert_key\": \"/usr/local/kong/ssl/kong-default.key\",\n \"pg_user\": \"kong\",\n \"pg_password\": \"******\",\n \"cassandra_data_centers\": [\n \"dc1:2\",\n \"dc2:3\"\n ],\n \"nginx_admin_directives\": {},\n \"nginx_upstream_keepalive_timeout\": \"60s\",\n \"nginx_http_directives\": [\n {\n \"value\": \"0\",\n \"name\": \"client_max_body_size\"\n },\n {\n \"value\": \"off\",\n \"name\": \"ssl_prefer_server_ciphers\"\n },\n {\n \"value\": \"8k\",\n \"name\": \"client_body_buffer_size\"\n },\n {\n \"value\": \"TLSv1.2 TLSv1.3\",\n \"name\": \"ssl_protocols\"\n },\n {\n \"value\": \"on\",\n \"name\": \"ssl_session_tickets\"\n },\n {\n \"value\": \"1d\",\n \"name\": \"ssl_session_timeout\"\n },\n {\n \"value\": \"prometheus_metrics 5m\",\n \"name\": \"lua_shared_dict\"\n }\n ],\n \"pg_host\": \"kong-database\",\n \"nginx_kong_stream_conf\": \"/usr/local/kong/nginx-kong-stream.conf\",\n \"cassandra_ssl\": false,\n \"go_plugins_dir\": \"off\",\n \"cluster_listen\": [\n \"0.0.0.0:8005\"\n ],\n \"dns_order\": [\n \"LAST\",\n \"SRV\",\n \"A\",\n \"CNAME\"\n ],\n \"dns_error_ttl\": 1,\n \"nginx_sproxy_directives\": {},\n \"nginx_http_upstream_keepalive_timeout\": \"60s\",\n \"pg_timeout\": 5000,\n \"nginx_http_upstream_keepalive_requests\": \"100\",\n \"database\": \"postgres\",\n \"nginx_upstream_keepalive\": \"60\",\n \"nginx_worker_processes\": \"auto\",\n \"nginx_http_status_directives\": {},\n \"lua_package_path\": \"./?.lua;./?/init.lua;\",\n \"router_update_frequency\": 1,\n \"upstream_keepalive\": 60,\n \"pg_max_concurrent_queries\": 0,\n \"proxy_ssl_enabled\": true,\n \"nginx_http_upstream_keepalive\": \"60\",\n \"lua_socket_pool_size\": 30,\n \"nginx_proxy_real_ip_header\": \"X-Real-IP\",\n \"db_resurrect_ttl\": 30,\n \"mem_cache_size\": \"128m\",\n \"cassandra_consistency\": \"ONE\",\n \"client_max_body_size\": \"0\",\n \"admin_error_log\": \"/dev/stderr\",\n \"nginx_main_directives\": [\n {\n \"value\": \"off\",\n \"name\": \"daemon\"\n },\n {\n \"value\": \"auto\",\n \"name\": \"worker_rlimit_nofile\"\n },\n {\n \"value\": \"auto\",\n \"name\": \"worker_processes\"\n }\n ],\n \"dns_not_found_ttl\": 30,\n \"nginx_http_ssl_session_tickets\": \"on\",\n \"ssl_ciphers\": \"ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384\",\n \"client_ssl\": false,\n \"cassandra_repl_strategy\": \"SimpleStrategy\",\n \"status_error_log\": \"logs/status_error.log\",\n \"ssl_cert_key_default\": \"/usr/local/kong/ssl/kong-default.key\",\n \"dns_stale_ttl\": 4,\n \"nginx_main_worker_processes\": \"auto\",\n \"nginx_kong_conf\": \"/usr/local/kong/nginx-kong.conf\",\n \"real_ip_header\": \"X-Real-IP\",\n \"dns_hostsfile\": \"/etc/hosts\",\n \"admin_listeners\": [\n {\n \"listener\": \"0.0.0.0:8001\",\n \"proxy_protocol\": false,\n \"reuseport\": false,\n \"backlog=%d+\": false,\n \"deferred\": false,\n \"ssl\": false,\n \"ip\": \"0.0.0.0\",\n \"port\": 8001,\n \"http2\": false,\n \"bind\": false\n },\n {\n \"listener\": \"0.0.0.0:8444 ssl\",\n \"proxy_protocol\": false,\n \"reuseport\": false,\n \"backlog=%d+\": false,\n \"deferred\": false,\n \"ssl\": true,\n \"ip\": \"0.0.0.0\",\n \"port\": 8444,\n \"http2\": false,\n \"bind\": false\n }\n ],\n \"cassandra_contact_points\": [\n \"kong-database\"\n ],\n \"ssl_cert\": \"/usr/local/kong/ssl/kong-default.crt\",\n \"nginx_proxy_real_ip_recursive\": \"off\",\n \"proxy_access_log\": \"/dev/stdout\",\n \"cassandra_ssl_verify\": false,\n \"admin_ssl_cert\": \"/usr/local/kong/ssl/admin-kong-default.crt\",\n \"cassandra_repl_factor\": 1,\n \"db_update_frequency\": 5,\n \"nginx_optimizations\": true,\n \"nginx_proxy_directives\": [\n {\n \"value\": \"X-Real-IP\",\n \"name\": \"real_ip_header\"\n },\n {\n \"value\": \"off\",\n \"name\": \"real_ip_recursive\"\n }\n ],\n \"nginx_daemon\": \"off\",\n \"anonymous_reports\": true,\n \"cassandra_timeout\": 5000,\n \"status_listeners\": {},\n \"client_ssl_cert_key_default\": \"/usr/local/kong/ssl/kong-default.key\",\n \"pg_ssl_verify\": false,\n \"client_body_buffer_size\": \"8k\",\n \"nginx_events_worker_connections\": \"auto\",\n \"stream_listeners\": {},\n \"error_default_type\": \"text/plain\",\n \"lua_package_cpath\": \"\",\n \"cassandra_lb_policy\": \"RequestRoundRobin\",\n \"nginx_stream_directives\": [\n {\n \"value\": \"stream_prometheus_metrics 5m\",\n \"name\": \"lua_shared_dict\"\n }\n ],\n \"ssl_cert_csr_default\": \"/usr/local/kong/ssl/kong-default.csr\"\n },\n \"version\": \"2.0.1\",\n \"node_id\": \"60d82979-75a1-4c56-aceb-e99d637265c9\",\n \"lua_version\": \"LuaJIT 2.1.0-beta3\",\n \"prng_seeds\": {\n \"pid: 23\": 181234361471,\n \"pid: 22\": 351146012690,\n \"pid: 1\": 145823120472\n },\n \"timers\": {\n \"pending\": 7,\n \"running\": 0\n },\n \"hostname\": \"cb1b9b178042\"\n}" + } + ] + } + ], + "description": "https://docs.konghq.com/2.0.x/admin-api/#information-routes" + }, + { + "name": "Health Routes", + "item": [ + { + "name": "Retrieve Node Status", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{gateway}}/status", + "host": [ + "{{gateway}}" + ], + "path": [ + "status" + ] + }, + "description": "## Retrieve Node Status [konghq](https://docs.konghq.com/2.0.x/admin-api/#retrieve-node-status)\n\n* Retrieve usage information about a node, with some basic information about the connections being processed by the underlying nginx process, the status of the database connection, and node’s memory usage.\n* If you want to monitor the Kong process, since Kong is built on top of nginx, every existing nginx monitoring tool or agent can be used.\n\n* memory: Metrics about the memory usage.\n\t* workers_lua_vms: An array with all workers of the Kong node, where each entry contains:\n\t* http_allocated_gc: HTTP submodule’s Lua virtual machine’s memory usage information, as reported by collectgarbage(\"count\"), for every active worker, i.e. a worker that received a proxy call in the last 10 seconds.\n\t* pid: worker’s process identification number.\nlua_shared_dicts: An array of information about dictionaries that are shared with all workers in a Kong node, where each array node contains how much memory is dedicated for the specific shared dictionary (capacity) and how much of said memory is in use (allocated_slabs). These shared dictionaries have least recent used (LRU) eviction capabilities, so a full dictionary, where allocated_slabs == capacity, will work properly. However for some dictionaries, e.g. cache HIT/MISS shared dictionaries, increasing their size can be beneficial for the overall performance of a Kong node.\n\t* The memory usage unit and precision can be changed using the querystring arguments unit and scale:\n\t\t* unit: one of b/B, k/K, m/M, g/G, which will return results in bytes, kibibytes, mebibytes, or gibibytes, respectively. When “bytes” are requested, the memory values in the response will have a number type instead of string. Defaults to m.\n\t\t* scale: the number of digits to the right of the decimal points when values are given in human-readable memory strings (unit other than “bytes”). Defaults to 2. You can get the shared dictionaries memory usage in kibibytes with 4 digits of precision by doing: GET /status?unit=k&scale=4\n* server: Metrics about the nginx HTTP/S server.\n\t* total_requests: The total number of client requests.\n\t* connections_active: The current number of active client connections including Waiting connections.\n\t* connections_accepted: The total number of accepted client connections.\n\t* connections_handled: The total number of handled connections. Generally, the parameter value is the same as accepts unless some resource limits have been reached.\n\t* connections_reading: The current number of connections where Kong is reading the request header.\n\t* connections_writing: The current number of connections where nginx is writing the response back to the client.\n\t* connections_waiting: The current number of idle client connections waiting for a request.\n* database: Metrics about the database.\n\t* reachable: A boolean value reflecting the state of the database connection. Please note that this flag does not reflect the health of the database itself." + }, + "response": [ + { + "name": "Retrieve Node Status - 200", + "originalRequest": { + "method": "GET", + "header": [], + "url": { + "raw": "https://localhost:8444/status", + "protocol": "https", + "host": [ + "localhost" + ], + "port": "8444", + "path": [ + "status" + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "Text", + "header": [ + { + "key": "Date", + "value": "Thu, 12 Mar 2020 00:40:05 GMT" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "Server", + "value": "kong/2.0.1" + }, + { + "key": "Content-Length", + "value": "1153" + }, + { + "key": "X-Kong-Admin-Latency", + "value": "913" + } + ], + "cookie": [], + "body": "{\n \"database\": {\n \"reachable\": true\n },\n \"memory\": {\n \"workers_lua_vms\": [\n {\n \"http_allocated_gc\": \"0.03 MiB\",\n \"pid\": 22\n },\n {\n \"http_allocated_gc\": \"0.03 MiB\",\n \"pid\": 23\n }\n ],\n \"lua_shared_dicts\": {\n \"kong_locks\": {\n \"allocated_slabs\": \"0.06 MiB\",\n \"capacity\": \"8.00 MiB\"\n },\n \"kong\": {\n \"allocated_slabs\": \"0.04 MiB\",\n \"capacity\": \"5.00 MiB\"\n },\n \"kong_process_events\": {\n \"allocated_slabs\": \"0.04 MiB\",\n \"capacity\": \"5.00 MiB\"\n },\n \"kong_db_cache_miss\": {\n \"allocated_slabs\": \"0.08 MiB\",\n \"capacity\": \"12.00 MiB\"\n },\n \"kong_healthchecks\": {\n \"allocated_slabs\": \"0.04 MiB\",\n \"capacity\": \"5.00 MiB\"\n },\n \"kong_cluster_events\": {\n \"allocated_slabs\": \"0.04 MiB\",\n \"capacity\": \"5.00 MiB\"\n },\n \"kong_core_db_cache_miss\": {\n \"allocated_slabs\": \"0.08 MiB\",\n \"capacity\": \"12.00 MiB\"\n },\n \"kong_core_db_cache\": {\n \"allocated_slabs\": \"0.77 MiB\",\n \"capacity\": \"128.00 MiB\"\n },\n \"prometheus_metrics\": {\n \"allocated_slabs\": \"0.04 MiB\",\n \"capacity\": \"5.00 MiB\"\n },\n \"kong_db_cache\": {\n \"allocated_slabs\": \"0.76 MiB\",\n \"capacity\": \"128.00 MiB\"\n },\n \"kong_rate_limiting_counters\": {\n \"allocated_slabs\": \"0.08 MiB\",\n \"capacity\": \"12.00 MiB\"\n }\n }\n },\n \"server\": {\n \"connections_writing\": 1,\n \"total_requests\": 21,\n \"connections_handled\": 15,\n \"connections_accepted\": 15,\n \"connections_reading\": 0,\n \"connections_active\": 4,\n \"connections_waiting\": 3\n }\n}" + } + ] + } + ], + "description": "https://docs.konghq.com/2.0.x/admin-api/#health-routes" + }, + { + "name": "Tags", + "item": [ + { + "name": "List All Tags", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{gateway}}/tags", + "host": [ + "{{gateway}}" + ], + "path": [ + "tags" + ] + }, + "description": "## Retrieve Node Status [konghq](https://docs.konghq.com/2.0.x/admin-api/#list-all-tags)\n\n\n* Returns a paginated list of all the tags in the system.\n* The list of entities will not be restricted to a single entity type: all the entities tagged with tags will be present on this list.\n* If an entity is tagged with more than one tag, the entity_id for that entity will appear more than once in the resulting list. Similarly, if several entities have been tagged with the same tag, the tag will appear in several items of this list." + }, + "response": [ + { + "name": "List All Tags - 200", + "originalRequest": { + "method": "GET", + "header": [], + "url": { + "raw": "https://localhost:8444/tags", + "protocol": "https", + "host": [ + "localhost" + ], + "port": "8444", + "path": [ + "tags" + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "Text", + "header": [ + { + "key": "Date", + "value": "Fri, 13 Mar 2020 01:04:37 GMT" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "Server", + "value": "kong/2.0.1" + }, + { + "key": "Content-Length", + "value": "1002" + }, + { + "key": "X-Kong-Admin-Latency", + "value": "3" + } + ], + "cookie": [], + "body": "{\n \"next\": null,\n \"data\": [\n {\n \"entity_id\": \"626169e4-6cd7-4952-85b1-3fda70fd5333\",\n \"entity_name\": \"consumers\",\n \"tag\": \"user-level\"\n },\n {\n \"entity_id\": \"626169e4-6cd7-4952-85b1-3fda70fd5333\",\n \"entity_name\": \"consumers\",\n \"tag\": \"low-priority\"\n },\n {\n \"entity_id\": \"875973fd-ba3f-4c7b-8301-e9263013e6d2\",\n \"entity_name\": \"routes\",\n \"tag\": \"user-level\"\n },\n {\n \"entity_id\": \"875973fd-ba3f-4c7b-8301-e9263013e6d2\",\n \"entity_name\": \"routes\",\n \"tag\": \"low-priority\"\n },\n {\n \"entity_id\": \"c883d8e7-0a33-4153-9d18-0741a3412125\",\n \"entity_name\": \"consumers\",\n \"tag\": \"user-level\"\n },\n {\n \"entity_id\": \"c883d8e7-0a33-4153-9d18-0741a3412125\",\n \"entity_name\": \"consumers\",\n \"tag\": \"low-priority\"\n },\n {\n \"entity_id\": \"e080cdd2-cdf4-4634-9d5d-1668c6929697\",\n \"entity_name\": \"plugins\",\n \"tag\": \"user-level\"\n },\n {\n \"entity_id\": \"e080cdd2-cdf4-4634-9d5d-1668c6929697\",\n \"entity_name\": \"plugins\",\n \"tag\": \"low-priority\"\n },\n {\n \"entity_id\": \"f8d38987-1eb6-4cb2-a7c8-6b11a17de911\",\n \"entity_name\": \"upstreams\",\n \"tag\": \"user-level\"\n },\n {\n \"entity_id\": \"f8d38987-1eb6-4cb2-a7c8-6b11a17de911\",\n \"entity_name\": \"upstreams\",\n \"tag\": \"low-priority\"\n }\n ]\n}" + } + ] + }, + { + "name": "List Entity Ids by Tag", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{gateway}}/tags/:tags", + "host": [ + "{{gateway}}" + ], + "path": [ + "tags", + ":tags" + ], + "variable": [ + { + "key": "tags", + "value": "{{tags}}", + "description": "Returns the entities that have been tagged with the specified tag." + } + ] + }, + "description": "## List Entity Ids by Tag [konghq](https://docs.konghq.com/2.0.x/admin-api/#list-entity-ids-by-tag)\n\n* Returns the entities that have been tagged with the specified tag.\n* The list of entities will not be restricted to a single entity type: all the entities tagged with tags will be present on this list." + }, + "response": [ + { + "name": "List Entity Ids by Tag - 200", + "originalRequest": { + "method": "GET", + "header": [], + "url": { + "raw": "https://localhost:8444/tags/:tags", + "protocol": "https", + "host": [ + "localhost" + ], + "port": "8444", + "path": [ + "tags", + ":tags" + ], + "variable": [ + { + "key": "tags", + "value": "user-level", + "description": "Returns the entities that have been tagged with the specified tag." + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "Text", + "header": [ + { + "key": "Date", + "value": "Fri, 13 Mar 2020 01:32:19 GMT" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "Server", + "value": "kong/2.0.1" + }, + { + "key": "Content-Length", + "value": "507" + }, + { + "key": "X-Kong-Admin-Latency", + "value": "2" + } + ], + "cookie": [], + "body": "{\n \"next\": null,\n \"data\": [\n {\n \"entity_id\": \"626169e4-6cd7-4952-85b1-3fda70fd5333\",\n \"entity_name\": \"consumers\",\n \"tag\": \"user-level\"\n },\n {\n \"entity_id\": \"875973fd-ba3f-4c7b-8301-e9263013e6d2\",\n \"entity_name\": \"routes\",\n \"tag\": \"user-level\"\n },\n {\n \"entity_id\": \"c883d8e7-0a33-4153-9d18-0741a3412125\",\n \"entity_name\": \"consumers\",\n \"tag\": \"user-level\"\n },\n {\n \"entity_id\": \"e080cdd2-cdf4-4634-9d5d-1668c6929697\",\n \"entity_name\": \"plugins\",\n \"tag\": \"user-level\"\n },\n {\n \"entity_id\": \"f8d38987-1eb6-4cb2-a7c8-6b11a17de911\",\n \"entity_name\": \"upstreams\",\n \"tag\": \"user-level\"\n }\n ]\n}" + }, + { + "name": "List Entity Ids by Tag - 400", + "originalRequest": { + "method": "GET", + "header": [], + "url": { + "raw": "{{gateway}}/tags/:tags", + "host": [ + "{{gateway}}" + ], + "path": [ + "tags", + ":tags" + ], + "variable": [ + { + "key": "tags", + "value": "user-level,low-priority", + "description": "Returns the entities that have been tagged with the specified tag." + } + ] + } + }, + "status": "Bad Request", + "code": 400, + "_postman_previewlanguage": "Text", + "header": [ + { + "key": "Date", + "value": "Fri, 13 Mar 2020 01:33:47 GMT" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "Server", + "value": "kong/2.0.1" + }, + { + "key": "Content-Length", + "value": "90" + }, + { + "key": "X-Kong-Admin-Latency", + "value": "0" + } + ], + "cookie": [], + "body": "{\n \"name\": \"invalid unique tag\",\n \"message\": \"invalid value: user-level,low-priority\",\n \"code\": 10\n}" + } + ] + } + ], + "description": "https://docs.konghq.com/2.0.x/admin-api/#tags\n\n* Tags are strings associated to entities in Kong. Each tag must be composed of one or more alphanumeric characters, _, -, . or ~.\n* Most core entities can be tagged via their tags attribute, upon creation or edition.\n* Tags can be used to filter core entities as well, via the ?tags query string parameter.\n * For example: if you normally get a list of all the Services by doing:\n
GET /services
\n * You can get the list of all the Services tagged example by doing:\n
GET /services?tags=example
\n * Similarly, if you want to filter Services so that you only get the ones tagged example and admin, you can do that like so:\n
GET /services?tags=example,admin
\n * Finally, if you wanted to filter the Services tagged example or admin, you could use:\n
GET /services?tags=example/admin
\n* Some notes:\n * A maximum of 5 tags can be queried simultaneously in a single request with , or /\nMixing operators is not supported: if you try to mix , with / in the same querystring, you will receive an error.\n * You may need to quote and/or escape some characters when using them from the command line.\n * Filtering by tags is not supported in foreign key relationship endpoints. For example, the tags parameter will be ignored in a request such as\n
GET /services/foo/routes?tags=a,b
\n * offset parameters are not guaranteed to work if the tags parameter is altered or removed", + "event": [ + { + "listen": "prerequest", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + }, + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + } + ] + }, + { + "name": "Service Object", + "item": [ + { + "name": "Add Service", + "item": [ + { + "name": "Create Service", + "request": { + "method": "POST", + "header": [ + { + "name": "Content-Type", + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"host\": \"httpbin.org\",\n \"connect_timeout\": 60000,\n \"protocol\": \"https\",\n \"name\": \"httpbin-api\",\n \"read_timeout\": 60000,\n \"port\": 443,\n \"path\": \"/\",\n \"retries\": 5,\n \"write_timeout\": 60000,\n \"tags\": null,\n \"client_certificate\": null\n}" + }, + "url": { + "raw": "{{gateway}}/services", + "host": [ + "{{gateway}}" + ], + "path": [ + "services" + ] + }, + "description": "## Create Service [konghq](https://docs.konghq.com/2.0.x/admin-api/#create-service)\n\n* Service entities, as the name implies, are abstractions of each of your own upstream services. Examples of Services would be a data transformation microservice, a billing API, etc.\n* The main attribute of a Service is its URL (where Kong should proxy traffic to), which can be set as a single string or by specifying its protocol, host, port and path individually.\n*Services are associated to Routes (a Service can have many Routes associated with it). Routes are entry-points in Kong and define rules to match client requests. Once a Route is matched, Kong proxies the request to its associated Service. See the Proxy Reference for a detailed explanation of how Kong proxies traffic.\n\n## Request Body\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
AttributesMandatoryDescription
nameoptionalThe Service name
retriesoptionalThe number of retries to execute upon failure to proxy. Defaults to 5
protocolrequiredThe protocol used to communicate with the upstream. Accepted values are: \"grpc\", \"grpcs\", \"http\", \"https\", \"tcp\", \"tls\". Defaults to \"http\"
hostrequiredThe host of the upstream server
portrequiredThe upstream server port. Defaults to 80
pathoptionalThe path to be used in requests to the upstream server.
connect_timeoutoptionalThe timeout in milliseconds for establishing a connection to the upstream server. Defaults to 60000.
write_timeoutoptionalThe timeout in milliseconds between two successive write operations for transmitting a request to the upstream server. Defaults to 60000.
read_timeoutoptionalThe timeout in milliseconds between two successive read operations for transmitting a request to the upstream server. Defaults to 60000.
tagsoptionalAn optional set of strings associated with the Service, for grouping and filtering.
client_certificateoptionalCertificate to be used as client certificate while TLS handshaking to the upstream server. With form-encoded, the notation is client_certificate.id=. With JSON, use “\"client_certificate\":{\"id\":\"\"}.
urlrequiredShorthand attribute to set protocol, host, port and path at once. This attribute is write-only (the Admin API never “returns” the url).
" + }, + "response": [ + { + "name": "Create Service - 201", + "originalRequest": { + "method": "POST", + "header": [ + { + "name": "Content-Type", + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"host\": \"httpbin.org\",\n \"connect_timeout\": 60000,\n \"protocol\": \"https\",\n \"name\": \"httpbin-api\",\n \"read_timeout\": 60000,\n \"port\": 443,\n \"path\": \"/\",\n \"retries\": 5,\n \"write_timeout\": 60000,\n \"tags\": null,\n \"client_certificate\": null\n}" + }, + "url": { + "raw": "https://localhost:8444/services", + "protocol": "https", + "host": [ + "localhost" + ], + "port": "8444", + "path": [ + "services" + ] + } + }, + "status": "Created", + "code": 201, + "_postman_previewlanguage": "Text", + "header": [ + { + "key": "Date", + "value": "Fri, 13 Mar 2020 01:57:34 GMT" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "Server", + "value": "kong/2.0.1" + }, + { + "key": "Content-Length", + "value": "294" + }, + { + "key": "X-Kong-Admin-Latency", + "value": "8" + } + ], + "cookie": [], + "body": "{\n \"host\": \"httpbin.org\",\n \"created_at\": 1584064654,\n \"connect_timeout\": 60000,\n \"id\": \"0022319a-a0b7-49d9-9eba-f2794f461de8\",\n \"protocol\": \"https\",\n \"name\": \"httpbin-api\",\n \"read_timeout\": 60000,\n \"port\": 443,\n \"path\": \"/\",\n \"updated_at\": 1584064654,\n \"retries\": 5,\n \"write_timeout\": 60000,\n \"tags\": null,\n \"client_certificate\": null\n}" + }, + { + "name": "Create Service - 409", + "originalRequest": { + "method": "POST", + "header": [ + { + "name": "Content-Type", + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"name\": \"httpbin-api\",\n\t\"url\": \"https://httpbin.org/\"\n}" + }, + "url": { + "raw": "{{gateway}}/services", + "host": [ + "{{gateway}}" + ], + "path": [ + "services" + ] + } + }, + "status": "Conflict", + "code": 409, + "_postman_previewlanguage": "Text", + "header": [ + { + "key": "Date", + "value": "Sat, 07 Mar 2020 23:04:28 GMT" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "Server", + "value": "kong/2.0.1" + }, + { + "key": "Content-Length", + "value": "145" + }, + { + "key": "X-Kong-Admin-Latency", + "value": "5" + } + ], + "cookie": [], + "body": "{\n \"message\": \"UNIQUE violation detected on '{name=\\\"httpbin-api\\\"}'\",\n \"name\": \"unique constraint violation\",\n \"fields\": {\n \"name\": \"httpbin-api\"\n },\n \"code\": 5\n}" + } + ] + }, + { + "name": "Create Service Associated to a Specific Certificate", + "request": { + "method": "POST", + "header": [ + { + "name": "Content-Type", + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"name\": \"httpbin-api\",\n\t\"url\": \"https://httpbin.org/\"\n}" + }, + "url": { + "raw": "{{gateway}}/certificates/:certificateIdorName/services", + "host": [ + "{{gateway}}" + ], + "path": [ + "certificates", + ":certificateIdorName", + "services" + ], + "variable": [ + { + "key": "certificateIdorName", + "value": "" + } + ] + }, + "description": "## Create Service Associated to a Specific Certificate [konghq](https://docs.konghq.com/2.0.x/admin-api/#create-service-associated-to-a-specific-certificate)\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n
AttributesMandatoryTypeDescription
certificate name or idrequiredpathThe unique identifier or the name attribute of the Certificate that should be associated to the newly-created Service.
\n\n## Request Body\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
AttributesMandatoryDescription
nameoptionalThe Service name
retriesoptionalThe number of retries to execute upon failure to proxy. Defaults to 5
protocolrequiredThe protocol used to communicate with the upstream. Accepted values are: \"grpc\", \"grpcs\", \"http\", \"https\", \"tcp\", \"tls\". Defaults to \"http\"
hostrequiredThe host of the upstream server
portrequiredThe upstream server port. Defaults to 80
pathoptionalThe path to be used in requests to the upstream server.
connect_timeoutoptionalThe timeout in milliseconds for establishing a connection to the upstream server. Defaults to 60000.
write_timeoutoptionalThe timeout in milliseconds between two successive write operations for transmitting a request to the upstream server. Defaults to 60000.
read_timeoutoptionalThe timeout in milliseconds between two successive read operations for transmitting a request to the upstream server. Defaults to 60000.
tagsoptionalAn optional set of strings associated with the Service, for grouping and filtering.
client_certificateoptionalCertificate to be used as client certificate while TLS handshaking to the upstream server. With form-encoded, the notation is client_certificate.id=. With JSON, use “\"client_certificate\":{\"id\":\"\"}.
urlrequiredShorthand attribute to set protocol, host, port and path at once. This attribute is write-only (the Admin API never “returns” the url).
" + }, + "response": [ + { + "name": "Create Service Associated to a Specific Certificate", + "originalRequest": { + "method": "POST", + "header": [ + { + "name": "Content-Type", + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"name\": \"httpbin-api\",\n\t\"url\": \"https://httpbin.org/\"\n}" + }, + "url": { + "raw": "https://localhost:8444/certificates/:certificateIdorName/services", + "protocol": "https", + "host": [ + "localhost" + ], + "port": "8444", + "path": [ + "certificates", + ":certificateIdorName", + "services" + ], + "variable": [ + { + "key": "certificateIdorName", + "value": "" + } + ] + } + }, + "_postman_previewlanguage": "Text", + "header": [], + "cookie": [], + "body": "{\n \"id\": \"9748f662-7711-4a90-8186-dc02f10eb0f5\",\n \"created_at\": 1422386534,\n \"updated_at\": 1422386534,\n \"name\": \"my-service\",\n \"retries\": 5,\n \"protocol\": \"http\",\n \"host\": \"example.com\",\n \"port\": 80,\n \"path\": \"/some_api\",\n \"connect_timeout\": 60000,\n \"write_timeout\": 60000,\n \"read_timeout\": 60000,\n \"tags\": [\n \"user-level\",\n \"low-priority\"\n ],\n \"client_certificate\": {\n \"id\": \"4e3ad2e4-0bc4-4638-8e34-c84a417ba39b\"\n }\n}" + }, + { + "name": "Create Service", + "originalRequest": { + "method": "POST", + "header": [ + { + "name": "Content-Type", + "description": "https://docs.konghq.com/2.0.x/admin-api/#supported-content-types", + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"name\": \"httpbin-api\",\n\t\"url\": \"https://httpbin.org/\"\n}" + }, + "url": { + "raw": "{{gateway}}/services", + "host": [ + "{{gateway}}" + ], + "path": [ + "services" + ] + } + }, + "status": "Created", + "code": 201, + "_postman_previewlanguage": "Text", + "header": [ + { + "key": "Date", + "value": "Fri, 06 Mar 2020 19:57:47 GMT" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "Server", + "value": "kong/2.0.1" + }, + { + "key": "Content-Length", + "value": "294" + }, + { + "key": "X-Kong-Admin-Latency", + "value": "19" + } + ], + "cookie": [], + "body": "{\n \"host\": \"httpbin.org\",\n \"created_at\": 1583524667,\n \"connect_timeout\": 60000,\n \"id\": \"ebcbaad6-797f-435c-be22-63051db717c3\",\n \"protocol\": \"https\",\n \"name\": \"httpbin-api\",\n \"read_timeout\": 60000,\n \"port\": 443,\n \"path\": \"/\",\n \"updated_at\": 1583524667,\n \"retries\": 5,\n \"write_timeout\": 60000,\n \"tags\": null,\n \"client_certificate\": null\n}" + } + ] + } + ], + "description": "https://docs.konghq.com/2.0.x/admin-api/#add-service" + }, + { + "name": "List Services", + "item": [ + { + "name": "List all services", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{gateway}}/services", + "host": [ + "{{gateway}}" + ], + "path": [ + "services" + ], + "query": [ + { + "key": "tags", + "value": "{{tags}}", + "disabled": true + } + ] + }, + "description": "## List all services [konghq](https://docs.konghq.com/2.0.x/admin-api/#list-all-services)\n* Services can be both tagged and filtered by [tags](https://docs.konghq.com/2.0.x/admin-api/#tags)\n\n \n \n \n \n \n \n \n \n \n \n \n \n
AttributesMandatoryTypeDescription
tagsoptionalqueryTags can be used to filter core entities as well, via the ?tags querystring parameter. See https://docs.konghq.com/2.0.x/admin-api/#tags
" + }, + "response": [ + { + "name": "List all services - 200", + "originalRequest": { + "method": "GET", + "header": [], + "url": { + "raw": "https://localhost:8444/services", + "protocol": "https", + "host": [ + "localhost" + ], + "port": "8444", + "path": [ + "services" + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "Text", + "header": [ + { + "key": "Date", + "value": "Sat, 07 Mar 2020 23:07:29 GMT" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "Server", + "value": "kong/2.0.1" + }, + { + "key": "Content-Length", + "value": "317" + }, + { + "key": "X-Kong-Admin-Latency", + "value": "1" + } + ], + "cookie": [], + "body": "{\n\t\"data\": [\n\t\t{\n\t\t\t\"id\": \"a5fb8d9b-a99d-40e9-9d35-72d42a62d83a\",\n\t\t\t\"created_at\": 1422386534,\n\t\t\t\"updated_at\": 1422386534,\n\t\t\t\"name\": \"my-service\",\n\t\t\t\"retries\": 5,\n\t\t\t\"protocol\": \"http\",\n\t\t\t\"host\": \"example.com\",\n\t\t\t\"port\": 80,\n\t\t\t\"path\": \"/some_api\",\n\t\t\t\"connect_timeout\": 60000,\n\t\t\t\"write_timeout\": 60000,\n\t\t\t\"read_timeout\": 60000,\n\t\t\t\"tags\": [\n\t\t\t\t\"user-level\",\n\t\t\t\t\"low-priority\"\n\t\t\t],\n\t\t\t\"client_certificate\": {\n\t\t\t\t\"id\": \"51e77dc2-8f3e-4afa-9d0e-0e3bbbcfd515\"\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"id\": \"fc73f2af-890d-4f9b-8363-af8945001f7f\",\n\t\t\t\"created_at\": 1422386534,\n\t\t\t\"updated_at\": 1422386534,\n\t\t\t\"name\": \"my-service\",\n\t\t\t\"retries\": 5,\n\t\t\t\"protocol\": \"http\",\n\t\t\t\"host\": \"example.com\",\n\t\t\t\"port\": 80,\n\t\t\t\"path\": \"/another_api\",\n\t\t\t\"connect_timeout\": 60000,\n\t\t\t\"write_timeout\": 60000,\n\t\t\t\"read_timeout\": 60000,\n\t\t\t\"tags\": [\n\t\t\t\t\"admin\",\n\t\t\t\t\"high-priority\",\n\t\t\t\t\"critical\"\n\t\t\t],\n\t\t\t\"client_certificate\": {\n\t\t\t\t\"id\": \"4506673d-c825-444c-a25b-602e3c2ec16e\"\n\t\t\t}\n\t\t}\n\t],\n\t\"next\": \"http://localhost:8001/services?offset=6378122c-a0a1-438d-a5c6-efabae9fb969\"\n}" + }, + { + "name": "List all services - 200", + "originalRequest": { + "method": "GET", + "header": [], + "url": { + "raw": "{{gateway}}/services?tags={{tags}}", + "host": [ + "{{gateway}}" + ], + "path": [ + "services" + ], + "query": [ + { + "key": "tags", + "value": "{{tags}}" + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "Text", + "header": [ + { + "key": "Date", + "value": "Fri, 13 Mar 2020 02:11:46 GMT" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "Server", + "value": "kong/2.0.1" + }, + { + "key": "Content-Length", + "value": "343" + }, + { + "key": "X-Kong-Admin-Latency", + "value": "1" + } + ], + "cookie": [], + "body": "{\n \"next\": \"sed pariatur Ut veniam do\",\n \"data\": [\n {\n \"host\": \"httpbin.org\",\n \"created_at\": 1584064654,\n \"connect_timeout\": 60000,\n \"id\": \"0022319a-a0b7-49d9-9eba-f2794f461de8\",\n \"protocol\": \"https\",\n \"name\": \"httpbin-apil\",\n \"read_timeout\": 60000,\n \"port\": 443,\n \"path\": \"/\",\n \"updated_at\": 1584065489,\n \"retries\": 5,\n \"write_timeout\": 60000,\n \"tags\": [\n \"user-level\",\n \"low-priority\"\n ],\n \"client_certificate\": {\n \"id\": \"ut\"\n }\n }\n ]\n}" + } + ] + }, + { + "name": "List Services Associated to a Specific Certificate", + "request": { + "method": "GET", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "url": { + "raw": "{{gateway}}/certificates/:certificateNameOrId/services", + "host": [ + "{{gateway}}" + ], + "path": [ + "certificates", + ":certificateNameOrId", + "services" + ], + "variable": [ + { + "key": "certificateNameOrId" + } + ] + }, + "description": "## List Services Associated to a Specific Certificate [konghq](https://docs.konghq.com/2.0.x/admin-api/#list-services-associated-to-a-specific-certificate)\n\n \n \n \n \n \n \n \n \n \n \n \n " + }, + "response": [ + { + "name": "List Services Associated to a Specific Certificate - 404", + "originalRequest": { + "method": "GET", + "header": [ + { + "name": "Content-Type", + "key": "Content-Type", + "value": "application/json" + } + ], + "url": { + "raw": "https://localhost:8444/certificates/:certificateNameOrId/services", + "protocol": "https", + "host": [ + "localhost" + ], + "port": "8444", + "path": [ + "certificates", + ":certificateNameOrId", + "services" + ], + "variable": [ + { + "key": "certificateNameOrId", + "value": "" + } + ] + } + }, + "status": "Not Found", + "code": 404, + "_postman_previewlanguage": "Text", + "header": [ + { + "key": "Date", + "value": "Thu, 12 Mar 2020 01:07:47 GMT" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "Server", + "value": "kong/2.0.1" + }, + { + "key": "Content-Length", + "value": "23" + }, + { + "key": "X-Kong-Admin-Latency", + "value": "0" + } + ], + "cookie": [], + "body": "{\n \"message\": \"Not found\"\n}" + } + ] + } + ], + "description": "https://docs.konghq.com/2.0.x/admin-api/#list-services" + }, + { + "name": "Retrieve Service", + "item": [ + { + "name": "Retrieve Service", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{gateway}}/services/:serviceNameOrID", + "host": [ + "{{gateway}}" + ], + "path": [ + "services", + ":serviceNameOrID" + ], + "variable": [ + { + "key": "serviceNameOrID", + "value": "{{serviceNameOrID}}" + } + ] + }, + "description": "## Retrieve Service [konghq](https://docs.konghq.com/2.0.x/admin-api/#retrieve-service-1)\n
AttributesMandatoryTypeDescription
certificate name or idrequiredpathThe unique identifier or the name attribute of the Certificate whose Services are to be retrieved. When using this endpoint, only Services associated to the specified Certificate will be listed.
\n \n \n \n \n \n \n \n \n \n \n \n \n
AttributesMandatoryTypeDescription
Service name or idrequiredpathThe unique identifier or the name of the Service to retrieve.
" + }, + "response": [ + { + "name": "Retrieve Service - 404", + "originalRequest": { + "method": "GET", + "header": [], + "url": { + "raw": "https://localhost:8444/services/:serviceNameOrID", + "protocol": "https", + "host": [ + "localhost" + ], + "port": "8444", + "path": [ + "services", + ":serviceNameOrID" + ], + "variable": [ + { + "key": "serviceNameOrID", + "value": "{{serviceNameOrID}}b" + } + ] + } + }, + "status": "Not Found", + "code": 404, + "_postman_previewlanguage": "Text", + "header": [ + { + "key": "Date", + "value": "Fri, 13 Mar 2020 02:06:03 GMT" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "Server", + "value": "kong/2.0.1" + }, + { + "key": "Content-Length", + "value": "23" + }, + { + "key": "X-Kong-Admin-Latency", + "value": "1" + } + ], + "cookie": [], + "body": "{\n \"message\": \"Not found\"\n}" + }, + { + "name": "Retrieve Service - 200", + "originalRequest": { + "method": "GET", + "header": [], + "url": { + "raw": "{{gateway}}/services/:serviceNameOrID", + "host": [ + "{{gateway}}" + ], + "path": [ + "services", + ":serviceNameOrID" + ], + "variable": [ + { + "key": "serviceNameOrID", + "value": "{{serviceNameOrID}}" + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "Text", + "header": [ + { + "key": "Date", + "value": "Fri, 13 Mar 2020 02:05:23 GMT" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "Server", + "value": "kong/2.0.1" + }, + { + "key": "Content-Length", + "value": "294" + }, + { + "key": "X-Kong-Admin-Latency", + "value": "2" + } + ], + "cookie": [], + "body": "{\n \"host\": \"httpbin.org\",\n \"created_at\": 1584064654,\n \"connect_timeout\": 60000,\n \"id\": \"0022319a-a0b7-49d9-9eba-f2794f461de8\",\n \"protocol\": \"https\",\n \"name\": \"httpbin-api\",\n \"read_timeout\": 60000,\n \"port\": 443,\n \"path\": \"/\",\n \"updated_at\": 1584064654,\n \"retries\": 5,\n \"write_timeout\": 60000,\n \"tags\": null,\n \"client_certificate\": null\n}" + } + ] + }, + { + "name": "Retrieve Service Associated to a Specific Certificate", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{gateway}}/certificates/:certificateId/services/:serviceNameOrId", + "host": [ + "{{gateway}}" + ], + "path": [ + "certificates", + ":certificateId", + "services", + ":serviceNameOrId" + ], + "variable": [ + { + "key": "certificateId", + "value": "" + }, + { + "key": "serviceNameOrId", + "value": "" + } + ] + }, + "description": "## Retrieve Service Associated to a Specific Certificate [konghq](https://docs.konghq.com/2.0.x/admin-api/#retrieve-service-associated-to-a-specific-certificate)\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
AttributesMandatoryTypeDescription
certificate idrequiredpathThe unique identifier of the Certificate to retrieve.
service name or idrequiredpathThe unique identifier or the name of the Service to retrieve.
" + }, + "response": [] + }, + { + "name": "Retrieve Service Associated to a Specific Route", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{gateway}}/routes/:routeNameOrId/service", + "host": [ + "{{gateway}}" + ], + "path": [ + "routes", + ":routeNameOrId", + "service" + ], + "variable": [ + { + "key": "routeNameOrId", + "value": "" + } + ] + }, + "description": "## Retrieve Service Associated to a Specific Route [konghq](https://docs.konghq.com/2.0.x/admin-api/#retrieve-service-associated-to-a-specific-route)\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n
AttributesMandatoryTypeDescription
route name or idrequiredpathThe unique identifier or the name of the Route associated to the Service to be retrieved.
" + }, + "response": [] + }, + { + "name": "Retrieve Service Associated to a Specific Plugin", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{gateway}}/plugins/:pluginId/service", + "host": [ + "{{gateway}}" + ], + "path": [ + "plugins", + ":pluginId", + "service" + ], + "variable": [ + { + "key": "pluginId", + "value": "" + } + ] + }, + "description": "## Retrieve Service Associated to a Specific Plugin [konghq](https://docs.konghq.com/2.0.x/admin-api/#retrieve-service-associated-to-a-specific-plugin)\n\n \n \n \n \n \n \n \n \n \n \n \n \n
AttributesMandatoryTypeDescription
plugin idrequiredpathThe unique identifier of the Plugin associated to the Service to be retrieved.
" + }, + "response": [] + } + ], + "description": "https://docs.konghq.com/2.0.x/admin-api/#retrieve-service", + "event": [ + { + "listen": "prerequest", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + }, + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + } + ] + }, + { + "name": "Update Service", + "item": [ + { + "name": "Update Service", + "request": { + "method": "PATCH", + "header": [ + { + "name": "Content-Type", + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"host\": \"httpbin.org\",\n\t\"name\": \"httpbin-api\",\n\t\"retries\": 5,\n\t\"protocol\": \"https\",\n\t\"port\": 443,\n\t\"path\": \"/\",\n\t\"connect_timeout\": 60000,\n\t\"write_timeout\": 60000,\n\t\"read_timeout\": 60000,\n\t\"tags\": [\"user-level\", \"low-priority\"],\n\t\"client_certificate\": null\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{gateway}}/services/:serviceNameOrId", + "host": [ + "{{gateway}}" + ], + "path": [ + "services", + ":serviceNameOrId" + ], + "variable": [ + { + "key": "serviceNameOrId", + "value": "httpbin-api" + } + ] + }, + "description": "## Update Service [konghq](https://docs.konghq.com/2.0.x/admin-api/#update-service)\n\n \n \n \n \n \n \n \n \n \n \n \n \n
AttributesMandatoryTypeDescription
service name or idrequiredpathThe unique identifier or the name of the Service to update.
\n\n## Request Body\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
AttributesMandatoryDescription
nameoptionalThe Service name
retriesoptionalThe number of retries to execute upon failure to proxy. Defaults to 5
protocolrequiredThe protocol used to communicate with the upstream. Accepted values are: \"grpc\", \"grpcs\", \"http\", \"https\", \"tcp\", \"tls\". Defaults to \"http\"
hostrequiredThe host of the upstream server
portrequiredThe upstream server port. Defaults to 80
pathoptionalThe path to be used in requests to the upstream server.
connect_timeoutoptionalThe timeout in milliseconds for establishing a connection to the upstream server. Defaults to 60000.
write_timeoutoptionalThe timeout in milliseconds between two successive write operations for transmitting a request to the upstream server. Defaults to 60000.
read_timeoutoptionalThe timeout in milliseconds between two successive read operations for transmitting a request to the upstream server. Defaults to 60000.
tagsoptionalAn optional set of strings associated with the Service, for grouping and filtering.
client_certificateoptionalCertificate to be used as client certificate while TLS handshaking to the upstream server. With form-encoded, the notation is client_certificate.id=. With JSON, use “\"client_certificate\":{\"id\":\"\"}.
urlrequiredShorthand attribute to set protocol, host, port and path at once. This attribute is write-only (the Admin API never “returns” the url).
" + }, + "response": [ + { + "name": "Update Service - 200", + "originalRequest": { + "method": "PATCH", + "header": [ + { + "name": "Content-Type", + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"host\": \"httpbin.org\",\n\t\"name\": \"httpbin-api\",\n\t\"retries\": 5,\n\t\"protocol\": \"https\",\n\t\"port\": 443,\n\t\"path\": \"/\",\n\t\"connect_timeout\": 60000,\n\t\"write_timeout\": 60000,\n\t\"read_timeout\": 60000,\n\t\"tags\": [\"user-level\", \"low-priority\"],\n\t\"client_certificate\": null\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{gateway}}/services/:serviceNameOrId", + "host": [ + "{{gateway}}" + ], + "path": [ + "services", + ":serviceNameOrId" + ], + "variable": [ + { + "key": "serviceNameOrId", + "value": "httpbin-api" + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "Text", + "header": [ + { + "key": "Date", + "value": "Fri, 13 Mar 2020 02:10:35 GMT" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "Server", + "value": "kong/2.0.1" + }, + { + "key": "Content-Length", + "value": "319" + }, + { + "key": "X-Kong-Admin-Latency", + "value": "16" + } + ], + "cookie": [], + "body": "{\n \"host\": \"httpbin.org\",\n \"created_at\": 1584064654,\n \"connect_timeout\": 60000,\n \"id\": \"0022319a-a0b7-49d9-9eba-f2794f461de8\",\n \"protocol\": \"https\",\n \"name\": \"httpbin-api\",\n \"read_timeout\": 60000,\n \"port\": 443,\n \"path\": \"/\",\n \"updated_at\": 1584065435,\n \"retries\": 5,\n \"write_timeout\": 60000,\n \"tags\": [\n \"user-level\",\n \"low-priority\"\n ],\n \"client_certificate\": null\n}" + } + ] + }, + { + "name": "Update Service Associated to a Specific Certificate", + "request": { + "method": "PATCH", + "header": [ + { + "name": "Content-Type", + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"host\": \"httpbin.org\",\n\t\"name\": \"httpbin-api\",\n\t\"retries\": 5,\n\t\"protocol\": \"https\",\n\t\"port\": 443,\n\t\"path\": \"/\",\n\t\"connect_timeout\": 60000,\n\t\"write_timeout\": 60000,\n\t\"read_timeout\": 60000,\n\t\"tags\": null,\n\t\"client_certificate\": null\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{gateway}}/certificates/:certificateId/services/:serviceNameOrId", + "host": [ + "{{gateway}}" + ], + "path": [ + "certificates", + ":certificateId", + "services", + ":serviceNameOrId" + ], + "variable": [ + { + "key": "certificateId", + "value": "" + }, + { + "key": "serviceNameOrId", + "value": "" + } + ] + }, + "description": "## Update Service [konghq](https://docs.konghq.com/2.0.x/admin-api/#update-service-associated-to-a-specific-certificate)\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
AttributesMandatoryTypeDescription
certificate idrequiredpathThe unique identifier of the Certificate to update
service name or idrequiredpathThe unique identifier or the name of the Service to update.
\n\n## Request Body\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
AttributesMandatoryDescription
nameoptionalThe Service name
retriesoptionalThe number of retries to execute upon failure to proxy. Defaults to 5
protocolrequiredThe protocol used to communicate with the upstream. Accepted values are: \"grpc\", \"grpcs\", \"http\", \"https\", \"tcp\", \"tls\". Defaults to \"http\"
hostrequiredThe host of the upstream server
portrequiredThe upstream server port. Defaults to 80
pathoptionalThe path to be used in requests to the upstream server.
connect_timeoutoptionalThe timeout in milliseconds for establishing a connection to the upstream server. Defaults to 60000.
write_timeoutoptionalThe timeout in milliseconds between two successive write operations for transmitting a request to the upstream server. Defaults to 60000.
read_timeoutoptionalThe timeout in milliseconds between two successive read operations for transmitting a request to the upstream server. Defaults to 60000.
tagsoptionalAn optional set of strings associated with the Service, for grouping and filtering.
client_certificateoptionalCertificate to be used as client certificate while TLS handshaking to the upstream server. With form-encoded, the notation is client_certificate.id=. With JSON, use “\"client_certificate\":{\"id\":\"\"}.
urlrequiredShorthand attribute to set protocol, host, port and path at once. This attribute is write-only (the Admin API never “returns” the url).
" + }, + "response": [] + }, + { + "name": "Update Service Associated to a Specific Route", + "request": { + "method": "PATCH", + "header": [ + { + "name": "Content-Type", + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"host\": \"httpbin.org\",\n\t\"name\": \"httpbin-api\",\n\t\"retries\": 5,\n\t\"protocol\": \"https\",\n\t\"port\": 443,\n\t\"path\": \"/\",\n\t\"connect_timeout\": 60000,\n\t\"write_timeout\": 60000,\n\t\"read_timeout\": 60000,\n\t\"tags\": null,\n\t\"client_certificate\": null\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{gateway}}/routes/:routeNameOrId/service", + "host": [ + "{{gateway}}" + ], + "path": [ + "routes", + ":routeNameOrId", + "service" + ], + "variable": [ + { + "key": "routeNameOrId", + "value": "" + } + ] + }, + "description": "## Update Service Associated to a Specific Route [konghq](https://docs.konghq.com/2.0.x/admin-api/#update-service-associated-to-a-specific-route)\n\n \n \n \n \n \n \n \n \n \n \n \n \n
AttributesMandatoryTypeDescription
route name or idrequiredpathThe unique identifier or the name of the Route associated to the Service to be updated
\n\n## Request Body\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
AttributesMandatoryDescription
nameoptionalThe Service name
retriesoptionalThe number of retries to execute upon failure to proxy. Defaults to 5
protocolrequiredThe protocol used to communicate with the upstream. Accepted values are: \"grpc\", \"grpcs\", \"http\", \"https\", \"tcp\", \"tls\". Defaults to \"http\"
hostrequiredThe host of the upstream server
portrequiredThe upstream server port. Defaults to 80
pathoptionalThe path to be used in requests to the upstream server.
connect_timeoutoptionalThe timeout in milliseconds for establishing a connection to the upstream server. Defaults to 60000.
write_timeoutoptionalThe timeout in milliseconds between two successive write operations for transmitting a request to the upstream server. Defaults to 60000.
read_timeoutoptionalThe timeout in milliseconds between two successive read operations for transmitting a request to the upstream server. Defaults to 60000.
tagsoptionalAn optional set of strings associated with the Service, for grouping and filtering.
client_certificateoptionalCertificate to be used as client certificate while TLS handshaking to the upstream server. With form-encoded, the notation is client_certificate.id=. With JSON, use “\"client_certificate\":{\"id\":\"\"}.
urlrequiredShorthand attribute to set protocol, host, port and path at once. This attribute is write-only (the Admin API never “returns” the url).
" + }, + "response": [] + }, + { + "name": "Update Service Associated to a Specific Plugin", + "request": { + "method": "PATCH", + "header": [ + { + "name": "Content-Type", + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"host\": \"httpbin.org\",\n\t\"name\": \"httpbin-api\",\n\t\"retries\": 5,\n\t\"protocol\": \"https\",\n\t\"port\": 443,\n\t\"path\": \"/\",\n\t\"connect_timeout\": 60000,\n\t\"write_timeout\": 60000,\n\t\"read_timeout\": 60000,\n\t\"tags\": null,\n\t\"client_certificate\": null\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{gateway}}/plugins/:pluginId/service", + "host": [ + "{{gateway}}" + ], + "path": [ + "plugins", + ":pluginId", + "service" + ], + "variable": [ + { + "key": "pluginId", + "value": "" + } + ] + }, + "description": "## Update Service Associated to a Specific Plugin [konghq](https://docs.konghq.com/2.0.x/admin-api/#update-service-associated-to-a-specific-plugin)\n\n \n \n \n \n \n \n \n \n \n \n \n \n
AttributesMandatoryTypeDescription
plugin idrequiredpathThe unique identifier of the Plugin associated to the Service to be updated
\n\n## Request Body\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
AttributesMandatoryDescription
nameoptionalThe Service name
retriesoptionalThe number of retries to execute upon failure to proxy. Defaults to 5
protocolrequiredThe protocol used to communicate with the upstream. Accepted values are: \"grpc\", \"grpcs\", \"http\", \"https\", \"tcp\", \"tls\". Defaults to \"http\"
hostrequiredThe host of the upstream server
portrequiredThe upstream server port. Defaults to 80
pathoptionalThe path to be used in requests to the upstream server.
connect_timeoutoptionalThe timeout in milliseconds for establishing a connection to the upstream server. Defaults to 60000.
write_timeoutoptionalThe timeout in milliseconds between two successive write operations for transmitting a request to the upstream server. Defaults to 60000.
read_timeoutoptionalThe timeout in milliseconds between two successive read operations for transmitting a request to the upstream server. Defaults to 60000.
tagsoptionalAn optional set of strings associated with the Service, for grouping and filtering.
client_certificateoptionalCertificate to be used as client certificate while TLS handshaking to the upstream server. With form-encoded, the notation is client_certificate.id=. With JSON, use “\"client_certificate\":{\"id\":\"\"}.
urlrequiredShorthand attribute to set protocol, host, port and path at once. This attribute is write-only (the Admin API never “returns” the url).
" + }, + "response": [] + } + ], + "description": "https://docs.konghq.com/2.0.x/admin-api/#update-service" + }, + { + "name": "Upsert Service", + "item": [ + { + "name": "Create Or Update Service", + "request": { + "method": "PUT", + "header": [ + { + "name": "Content-Type", + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"host\": \"httpbin.org\",\n\t\"name\": \"httpbin-api\",\n\t\"retries\": 5,\n\t\"protocol\": \"https\",\n\t\"port\": 443,\n\t\"path\": \"/\",\n\t\"connect_timeout\": 60000,\n\t\"write_timeout\": 60000,\n\t\"read_timeout\": 60000,\n\t\"tags\": null,\n\t\"client_certificate\": null\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{gateway}}/services/:serviceNameOrId", + "host": [ + "{{gateway}}" + ], + "path": [ + "services", + ":serviceNameOrId" + ], + "variable": [ + { + "key": "serviceNameOrId", + "value": "httpbin-api" + } + ] + }, + "description": "## Create Or Update Service [konghq](https://docs.konghq.com/2.0.x/admin-api/#create-or-update-service)\n\n* Inserts (or replaces) the Service under the requested resource with the definition specified in the body. The Service will be identified via the name or id attribute.\n* When the name or id attribute has the structure of a UUID, the Service being inserted/replaced will be identified by its id. Otherwise it will be identified by its name.\n* When creating a new Service without specifying id (neither in the URL nor in the body), then it will be auto-generated.\n* Notice that specifying a name in the URL and a different one in the request body is not allowed.\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n
AttributesMandatoryTypeDescription
service name or idrequiredpathThe unique identifier or the name of the Service to update.
\n\n## Request Body\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
AttributesMandatoryDescription
nameoptionalThe Service name
retriesoptionalThe number of retries to execute upon failure to proxy. Defaults to 5
protocolrequiredThe protocol used to communicate with the upstream. Accepted values are: \"grpc\", \"grpcs\", \"http\", \"https\", \"tcp\", \"tls\". Defaults to \"http\"
hostrequiredThe host of the upstream server
portrequiredThe upstream server port. Defaults to 80
pathoptionalThe path to be used in requests to the upstream server.
connect_timeoutoptionalThe timeout in milliseconds for establishing a connection to the upstream server. Defaults to 60000.
write_timeoutoptionalThe timeout in milliseconds between two successive write operations for transmitting a request to the upstream server. Defaults to 60000.
read_timeoutoptionalThe timeout in milliseconds between two successive read operations for transmitting a request to the upstream server. Defaults to 60000.
tagsoptionalAn optional set of strings associated with the Service, for grouping and filtering.
client_certificateoptionalCertificate to be used as client certificate while TLS handshaking to the upstream server. With form-encoded, the notation is client_certificate.id=. With JSON, use “\"client_certificate\":{\"id\":\"\"}.
urlrequiredShorthand attribute to set protocol, host, port and path at once. This attribute is write-only (the Admin API never “returns” the url).
" + }, + "response": [ + { + "name": "Update Service_Error", + "originalRequest": { + "method": "PUT", + "header": [ + { + "name": "Content-Type", + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"name\": \"httpbin-api\",\n\t\"retries\": 5,\n\t\"protocol\": \"https\",\n\t\"host\": \"httpbin.org\",\n\t\"port\": 443,\n\t\"path\": \"/\",\n\t\"connect_timeout\": 60000,\n\t\"write_timeout\": 60000,\n\t\"read_timeout\": 60000,\n\t\"tags\": null,\n\t\"client_certificate\": null,\n\t\"url\": null\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{gateway}}/services/:serviceNameOrId", + "host": [ + "{{gateway}}" + ], + "path": [ + "services", + ":serviceNameOrId" + ], + "variable": [ + { + "key": "serviceNameOrId", + "value": "httpbin-api" + } + ] + } + }, + "status": "Bad Request", + "code": 400, + "_postman_previewlanguage": "Text", + "header": [ + { + "key": "Date", + "value": "Sun, 08 Mar 2020 01:20:52 GMT" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "Server", + "value": "kong/2.0.1" + }, + { + "key": "Content-Length", + "value": "330" + }, + { + "key": "X-Kong-Admin-Latency", + "value": "1" + } + ], + "cookie": [], + "body": "{\n \"message\": \"3 schema violations (host: required field missing; path: should start with: /; protocol: expected one of: grpc, grpcs, http, https, tcp, tls)\",\n \"name\": \"schema violation\",\n \"fields\": {\n \"host\": \"required field missing\",\n \"path\": \"should start with: /\",\n \"protocol\": \"expected one of: grpc, grpcs, http, https, tcp, tls\"\n },\n \"code\": 2\n}" + }, + { + "name": "Update Service", + "originalRequest": { + "method": "PUT", + "header": [ + { + "name": "Content-Type", + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"host\": \"httpbin.org\",\n\t\"name\": \"httpbin-api\",\n\t\"retries\": 5,\n\t\"protocol\": \"https\",\n\t\"port\": 443,\n\t\"path\": \"/\",\n\t\"connect_timeout\": 60000,\n\t\"write_timeout\": 60000,\n\t\"read_timeout\": 60000,\n\t\"tags\": null,\n\t\"client_certificate\": null\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{gateway}}/services/:serviceNameOrId", + "host": [ + "{{gateway}}" + ], + "path": [ + "services", + ":serviceNameOrId" + ], + "variable": [ + { + "key": "serviceNameOrId", + "value": "httpbin-api" + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "Text", + "header": [ + { + "key": "Date", + "value": "Sun, 08 Mar 2020 01:25:47 GMT" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "Server", + "value": "kong/2.0.1" + }, + { + "key": "Content-Length", + "value": "294" + }, + { + "key": "X-Kong-Admin-Latency", + "value": "11" + } + ], + "cookie": [], + "body": "{\r\n \"host\": \"httpbin.org\",\r\n \"created_at\": 1583630747,\r\n \"connect_timeout\": 60000,\r\n \"id\": \"c8b8f724-7e73-4df6-b1a8-8df19642d388\",\r\n \"protocol\": \"https\",\r\n \"name\": \"httpbin-api\",\r\n \"read_timeout\": 60000,\r\n \"port\": 443,\r\n \"path\": \"/\",\r\n \"updated_at\": 1583630747,\r\n \"retries\": 5,\r\n \"write_timeout\": 60000,\r\n \"tags\": null,\r\n \"client_certificate\": null\r\n}" + } + ] + }, + { + "name": "Create Or Update Service Associated to a Specific Certificate", + "request": { + "method": "PUT", + "header": [ + { + "name": "Content-Type", + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"host\": \"httpbin.org\",\n\t\"name\": \"httpbin-api\",\n\t\"retries\": 5,\n\t\"protocol\": \"https\",\n\t\"port\": 443,\n\t\"path\": \"/\",\n\t\"connect_timeout\": 60000,\n\t\"write_timeout\": 60000,\n\t\"read_timeout\": 60000,\n\t\"tags\": null,\n\t\"client_certificate\": null\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{gateway}}/certificates/:certificateId/services/:serviceNameOrId", + "host": [ + "{{gateway}}" + ], + "path": [ + "certificates", + ":certificateId", + "services", + ":serviceNameOrId" + ], + "variable": [ + { + "key": "certificateId", + "value": "" + }, + { + "key": "serviceNameOrId", + "value": "" + } + ] + }, + "description": "## Create Or Update Service Associated to a Specific Certificate [konghq](https://docs.konghq.com/2.0.x/admin-api/#create-or-update-service-associated-to-a-specific-certificate)\n* Inserts (or replaces) the Service under the requested resource with the definition specified in the body. The Service will be identified via the name or id attribute.\n* When the name or id attribute has the structure of a UUID, the Service being inserted/replaced will be identified by its id. Otherwise it will be identified by its name.\n* When creating a new Service without specifying id (neither in the URL nor in the body), then it will be auto-generated.\n* Notice that specifying a name in the URL and a different one in the request body is not allowed.\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
AttributesMandatoryTypeDescription
certificate idrequiredpathThe unique identifier of the Certificate to update
service name or idrequiredpathThe unique identifier or the name of the Service to update.
\n\n## Request Body\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
AttributesMandatoryDescription
nameoptionalThe Service name
retriesoptionalThe number of retries to execute upon failure to proxy. Defaults to 5
protocolrequiredThe protocol used to communicate with the upstream. Accepted values are: \"grpc\", \"grpcs\", \"http\", \"https\", \"tcp\", \"tls\". Defaults to \"http\"
hostrequiredThe host of the upstream server
portrequiredThe upstream server port. Defaults to 80
pathoptionalThe path to be used in requests to the upstream server.
connect_timeoutoptionalThe timeout in milliseconds for establishing a connection to the upstream server. Defaults to 60000.
write_timeoutoptionalThe timeout in milliseconds between two successive write operations for transmitting a request to the upstream server. Defaults to 60000.
read_timeoutoptionalThe timeout in milliseconds between two successive read operations for transmitting a request to the upstream server. Defaults to 60000.
tagsoptionalAn optional set of strings associated with the Service, for grouping and filtering.
client_certificateoptionalCertificate to be used as client certificate while TLS handshaking to the upstream server. With form-encoded, the notation is client_certificate.id=. With JSON, use “\"client_certificate\":{\"id\":\"\"}.
urlrequiredShorthand attribute to set protocol, host, port and path at once. This attribute is write-only (the Admin API never “returns” the url).
" + }, + "response": [] + }, + { + "name": "Create Or Update Service Associated to a Specific Route", + "request": { + "method": "PUT", + "header": [ + { + "name": "Content-Type", + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"host\": \"httpbin.org\",\n\t\"name\": \"httpbin-api\",\n\t\"retries\": 5,\n\t\"protocol\": \"https\",\n\t\"port\": 443,\n\t\"path\": \"/\",\n\t\"connect_timeout\": 60000,\n\t\"write_timeout\": 60000,\n\t\"read_timeout\": 60000,\n\t\"tags\": null,\n\t\"client_certificate\": null\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{gateway}}/routes/:routeNameOrId/service", + "host": [ + "{{gateway}}" + ], + "path": [ + "routes", + ":routeNameOrId", + "service" + ], + "variable": [ + { + "key": "routeNameOrId", + "value": "" + } + ] + }, + "description": "## Create Or Update Service Associated to a Specific Route [konghq](https://docs.konghq.com/2.0.x/admin-api/#create-or-update-service-associated-to-a-specific-route)\n* Inserts (or replaces) the Service under the requested resource with the definition specified in the body. The Service will be identified via the name or id attribute.\n* When the name or id attribute has the structure of a UUID, the Service being inserted/replaced will be identified by its id. Otherwise it will be identified by its name.\n* When creating a new Service without specifying id (neither in the URL nor in the body), then it will be auto-generated.\n* Notice that specifying a name in the URL and a different one in the request body is not allowed.\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n
AttributesMandatoryTypeDescription
route name or idrequiredpathThe unique identifier or the name of the Route associated to the Service to be updated
\n\n## Request Body\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
AttributesMandatoryDescription
nameoptionalThe Service name
retriesoptionalThe number of retries to execute upon failure to proxy. Defaults to 5
protocolrequiredThe protocol used to communicate with the upstream. Accepted values are: \"grpc\", \"grpcs\", \"http\", \"https\", \"tcp\", \"tls\". Defaults to \"http\"
hostrequiredThe host of the upstream server
portrequiredThe upstream server port. Defaults to 80
pathoptionalThe path to be used in requests to the upstream server.
connect_timeoutoptionalThe timeout in milliseconds for establishing a connection to the upstream server. Defaults to 60000.
write_timeoutoptionalThe timeout in milliseconds between two successive write operations for transmitting a request to the upstream server. Defaults to 60000.
read_timeoutoptionalThe timeout in milliseconds between two successive read operations for transmitting a request to the upstream server. Defaults to 60000.
tagsoptionalAn optional set of strings associated with the Service, for grouping and filtering.
client_certificateoptionalCertificate to be used as client certificate while TLS handshaking to the upstream server. With form-encoded, the notation is client_certificate.id=. With JSON, use “\"client_certificate\":{\"id\":\"\"}.
urlrequiredShorthand attribute to set protocol, host, port and path at once. This attribute is write-only (the Admin API never “returns” the url).
" + }, + "response": [] + }, + { + "name": "Create Or Update Service Associated to a Specific Plugin", + "request": { + "method": "PUT", + "header": [ + { + "name": "Content-Type", + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"host\": \"httpbin.org\",\n\t\"name\": \"httpbin-api\",\n\t\"retries\": 5,\n\t\"protocol\": \"https\",\n\t\"port\": 443,\n\t\"path\": \"/\",\n\t\"connect_timeout\": 60000,\n\t\"write_timeout\": 60000,\n\t\"read_timeout\": 60000,\n\t\"tags\": null,\n\t\"client_certificate\": null\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{gateway}}/plugins/:pluginId/service", + "host": [ + "{{gateway}}" + ], + "path": [ + "plugins", + ":pluginId", + "service" + ], + "variable": [ + { + "key": "pluginId", + "value": "" + } + ] + }, + "description": "## Create Or Update Service Associated to a Specific Plugin [konghq](https://docs.konghq.com/2.0.x/admin-api/#create-or-update-service-associated-to-a-specific-plugin)\n* Inserts (or replaces) the Service under the requested resource with the definition specified in the body. The Service will be identified via the name or id attribute.\n* When the name or id attribute has the structure of a UUID, the Service being inserted/replaced will be identified by its id. Otherwise it will be identified by its name.\n* When creating a new Service without specifying id (neither in the URL nor in the body), then it will be auto-generated.\n* Notice that specifying a name in the URL and a different one in the request body is not allowed.\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n
AttributesMandatoryTypeDescription
plugin idrequiredpathThe unique identifier of the Plugin associated to the Service to be updated
\n\n## Request Body\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
AttributesMandatoryDescription
nameoptionalThe Service name
retriesoptionalThe number of retries to execute upon failure to proxy. Defaults to 5
protocolrequiredThe protocol used to communicate with the upstream. Accepted values are: \"grpc\", \"grpcs\", \"http\", \"https\", \"tcp\", \"tls\". Defaults to \"http\"
hostrequiredThe host of the upstream server
portrequiredThe upstream server port. Defaults to 80
pathoptionalThe path to be used in requests to the upstream server.
connect_timeoutoptionalThe timeout in milliseconds for establishing a connection to the upstream server. Defaults to 60000.
write_timeoutoptionalThe timeout in milliseconds between two successive write operations for transmitting a request to the upstream server. Defaults to 60000.
read_timeoutoptionalThe timeout in milliseconds between two successive read operations for transmitting a request to the upstream server. Defaults to 60000.
tagsoptionalAn optional set of strings associated with the Service, for grouping and filtering.
client_certificateoptionalCertificate to be used as client certificate while TLS handshaking to the upstream server. With form-encoded, the notation is client_certificate.id=. With JSON, use “\"client_certificate\":{\"id\":\"\"}.
urlrequiredShorthand attribute to set protocol, host, port and path at once. This attribute is write-only (the Admin API never “returns” the url).
" + }, + "response": [] + } + ], + "description": "https://docs.konghq.com/2.0.x/admin-api/#update-or-create-service", + "event": [ + { + "listen": "prerequest", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + }, + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + } + ] + }, + { + "name": "Delete Service", + "item": [ + { + "name": "Delete Service", + "request": { + "method": "DELETE", + "header": [], + "url": { + "raw": "{{gateway}}/services/:ServiceNameOrID", + "host": [ + "{{gateway}}" + ], + "path": [ + "services", + ":ServiceNameOrID" + ], + "variable": [ + { + "key": "ServiceNameOrID", + "value": "" + } + ] + }, + "description": "## Delete Service [konghq](https://docs.konghq.com/2.0.x/admin-api/#delete-service-1)\n\n \n \n \n \n \n \n \n \n \n \n \n \n
AttributesMandatoryTypeDescription
Service name or idrequiredpathThe unique identifier or the name of the Service to delete
" + }, + "response": [ + { + "name": "Delete Service - 204", + "originalRequest": { + "method": "DELETE", + "header": [], + "url": { + "raw": "https://localhost:8444/services/:ServiceNameOrID", + "protocol": "https", + "host": [ + "localhost" + ], + "port": "8444", + "path": [ + "services", + ":ServiceNameOrID" + ], + "variable": [ + { + "key": "ServiceNameOrID", + "value": "httpbin-api" + } + ] + } + }, + "status": "No Content", + "code": 204, + "_postman_previewlanguage": "Text", + "header": [ + { + "key": "Date", + "value": "Fri, 13 Mar 2020 01:57:04 GMT" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "Server", + "value": "kong/2.0.1" + }, + { + "key": "X-Kong-Admin-Latency", + "value": "11" + } + ], + "cookie": [], + "body": "" + }, + { + "name": "Delete Service - 400", + "originalRequest": { + "method": "DELETE", + "header": [], + "url": { + "raw": "{{gateway}}/services/:ServiceNameOrID", + "host": [ + "{{gateway}}" + ], + "path": [ + "services", + ":ServiceNameOrID" + ], + "variable": [ + { + "key": "ServiceNameOrID", + "value": "httpbin-api" + } + ] + } + }, + "status": "Bad Request", + "code": 400, + "_postman_previewlanguage": "Text", + "header": [ + { + "key": "Date", + "value": "Fri, 13 Mar 2020 01:55:50 GMT" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "Server", + "value": "kong/2.0.1" + }, + { + "key": "Content-Length", + "value": "152" + }, + { + "key": "X-Kong-Admin-Latency", + "value": "8" + } + ], + "cookie": [], + "body": "{\n \"message\": \"an existing 'routes' entity references this 'services' entity\",\n \"name\": \"foreign key violation\",\n \"fields\": {\n \"@referenced_by\": \"routes\"\n },\n \"code\": 4\n}" + } + ] + }, + { + "name": "Delete Service Associated to a Specific Certificate", + "request": { + "method": "DELETE", + "header": [], + "url": { + "raw": "{{gateway}}/certificates/:certificateId/services/:serviceNameOrId", + "host": [ + "{{gateway}}" + ], + "path": [ + "certificates", + ":certificateId", + "services", + ":serviceNameOrId" + ], + "variable": [ + { + "key": "certificateId", + "value": "" + }, + { + "key": "serviceNameOrId", + "value": "" + } + ] + }, + "description": "## Delete Service Associated to a Specific Certificate [konghq](https://docs.konghq.com/2.0.x/admin-api/#delete-service-associated-to-a-specific-certificate)\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
AttributesMandatoryTypeDescription
certificate idrequiredpathThe unique identifier of the Certificate to delete.
service name or idrequiredpathThe unique identifier or the name of the Service to delete.
" + }, + "response": [] + }, + { + "name": "Delete Service Associated to a Specific Route", + "request": { + "method": "DELETE", + "header": [], + "url": { + "raw": "{{gateway}}/routes/:routeNameOrId/service", + "host": [ + "{{gateway}}" + ], + "path": [ + "routes", + ":routeNameOrId", + "service" + ], + "variable": [ + { + "key": "routeNameOrId", + "value": "" + } + ] + }, + "description": "## Delete Service Associated to a Specific Route [konghq](https://docs.konghq.com/2.0.x/admin-api/#delete-service-associated-to-a-specific-route)\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n
AttributesMandatoryTypeDescription
route name or idrequiredpathThe unique identifier or the name of the Route associated to the Service to be deleted
" + }, + "response": [] + } + ], + "description": "https://docs.konghq.com/2.0.x/admin-api/#delete-service" + } + ], + "description": "https://docs.konghq.com/2.0.x/admin-api/#service-object\n\n* Service entities, as the name implies, are abstractions of each of your own upstream services. Examples of Services would be a data transformation microservice, a billing API, etc.\n\n* The main attribute of a Service is its URL (where Kong should proxy traffic to), which can be set as a single string or by specifying its protocol, host, port and path individually.\n\n* Services are associated to Routes (a Service can have many Routes associated with it). Routes are entry-points in Kong and define rules to match client requests. Once a Route is matched, Kong proxies the request to its associated Service. See the Proxy Reference for a detailed explanation of how Kong proxies traffic.\n\n* Services can be both tagged and filtered by [tags](https://docs.konghq.com/2.0.x/admin-api/#tags)", + "event": [ + { + "listen": "prerequest", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + }, + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + } + ] + }, + { + "name": "Consumer Object", + "item": [ + { + "name": "Add Consumer", + "item": [ + { + "name": "Create Consumer", + "request": { + "method": "POST", + "header": [ + { + "name": "Content-Type", + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"username\": \"my-username\",\r\n \"custom_id\": \"my-custom-id\",\r\n \"tags\": [\"user-level\", \"low-priority\"]\r\n}" + }, + "url": { + "raw": "{{gateway}}/consumers", + "host": [ + "{{gateway}}" + ], + "path": [ + "consumers" + ] + }, + "description": "## Create Consumer [konghq](https://docs.konghq.com/2.0.x/admin-api/#create-consumer)\n\n\n## Request Body\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
AttributesMandatoryDescription
usernamesemi-optionalThe unique username of the consumer. You must send either this field or custom_id with the request.
custom_idsemi-optionalField for storing an existing unique ID for the consumer - useful for mapping Kong with users in your existing database. You must send either this field or username with the request.
tagsoptionalAn optional set of strings associated with the Consumer, for grouping and filtering.
" + }, + "response": [ + { + "name": "Create Consumer", + "originalRequest": { + "method": "POST", + "header": [ + { + "name": "Content-Type", + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"username\": \"my-username\",\r\n \"custom_id\": \"my-custom-id\",\r\n \"tags\": [\"user-level\", \"low-priority\"]\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "https://localhost:8444/consumers", + "protocol": "https", + "host": [ + "localhost" + ], + "port": "8444", + "path": [ + "consumers" + ] + } + }, + "status": "Created", + "code": 201, + "_postman_previewlanguage": "Text", + "header": [ + { + "key": "Date", + "value": "Thu, 12 Mar 2020 05:32:53 GMT" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "Server", + "value": "kong/2.0.1" + }, + { + "key": "Content-Length", + "value": "158" + }, + { + "key": "X-Kong-Admin-Latency", + "value": "11" + } + ], + "cookie": [], + "body": "{\n \"custom_id\": \"my-custom-id\",\n \"created_at\": 1583991173,\n \"id\": \"626169e4-6cd7-4952-85b1-3fda70fd5333\",\n \"tags\": [\n \"user-level\",\n \"low-priority\"\n ],\n \"username\": \"my-username\"\n}" + } + ] + } + ], + "description": "https://docs.konghq.com/2.0.x/admin-api/#add-consumer", + "event": [ + { + "listen": "prerequest", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + }, + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + } + ] + }, + { + "name": "List Consumers", + "item": [ + { + "name": "List All Consumers", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{gateway}}/consumers", + "host": [ + "{{gateway}}" + ], + "path": [ + "consumers" + ] + }, + "description": "## List All Consumers [konghq](https://docs.konghq.com/2.0.x/admin-api/#list-all-consumers)" + }, + "response": [ + { + "name": "List All Routes", + "originalRequest": { + "method": "GET", + "header": [], + "url": { + "raw": "https://localhost:8444/routes", + "protocol": "https", + "host": [ + "localhost" + ], + "port": "8444", + "path": [ + "routes" + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "Text", + "header": [ + { + "key": "Date", + "value": "Thu, 12 Mar 2020 01:21:59 GMT" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "Server", + "value": "kong/2.0.1" + }, + { + "key": "Content-Length", + "value": "23" + }, + { + "key": "X-Kong-Admin-Latency", + "value": "2" + } + ], + "cookie": [], + "body": "{\n\t\"data\": [\n\t\t{\n\t\t\t\"id\": \"a9daa3ba-8186-4a0d-96e8-00d80ce7240b\",\n\t\t\t\"created_at\": 1422386534,\n\t\t\t\"updated_at\": 1422386534,\n\t\t\t\"name\": \"my-route\",\n\t\t\t\"protocols\": [\n\t\t\t\t\"http\",\n\t\t\t\t\"https\"\n\t\t\t],\n\t\t\t\"methods\": [\n\t\t\t\t\"GET\",\n\t\t\t\t\"POST\"\n\t\t\t],\n\t\t\t\"hosts\": [\n\t\t\t\t\"example.com\",\n\t\t\t\t\"foo.test\"\n\t\t\t],\n\t\t\t\"paths\": [\n\t\t\t\t\"/foo\",\n\t\t\t\t\"/bar\"\n\t\t\t],\n\t\t\t\"headers\": {\n\t\t\t\t\"x-another-header\": [\n\t\t\t\t\t\"bla\"\n\t\t\t\t],\n\t\t\t\t\"x-my-header\": [\n\t\t\t\t\t\"foo\",\n\t\t\t\t\t\"bar\"\n\t\t\t\t]\n\t\t\t},\n\t\t\t\"https_redirect_status_code\": 426,\n\t\t\t\"regex_priority\": 0,\n\t\t\t\"strip_path\": true,\n\t\t\t\"path_handling\": \"v0\",\n\t\t\t\"preserve_host\": false,\n\t\t\t\"tags\": [\n\t\t\t\t\"user-level\",\n\t\t\t\t\"low-priority\"\n\t\t\t],\n\t\t\t\"service\": {\n\t\t\t\t\"id\": \"127dfc88-ed57-45bf-b77a-a9d3a152ad31\"\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"id\": \"9aa116fd-ef4a-4efa-89bf-a0b17c4be982\",\n\t\t\t\"created_at\": 1422386534,\n\t\t\t\"updated_at\": 1422386534,\n\t\t\t\"name\": \"my-route\",\n\t\t\t\"protocols\": [\n\t\t\t\t\"tcp\",\n\t\t\t\t\"tls\"\n\t\t\t],\n\t\t\t\"https_redirect_status_code\": 426,\n\t\t\t\"regex_priority\": 0,\n\t\t\t\"strip_path\": true,\n\t\t\t\"path_handling\": \"v0\",\n\t\t\t\"preserve_host\": false,\n\t\t\t\"snis\": [\n\t\t\t\t\"foo.test\",\n\t\t\t\t\"example.com\"\n\t\t\t],\n\t\t\t\"sources\": [\n\t\t\t\t{\n\t\t\t\t\t\"ip\": \"10.1.0.0/16\",\n\t\t\t\t\t\"port\": 1234\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"ip\": \"10.2.2.2\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"port\": 9123\n\t\t\t\t}\n\t\t\t],\n\t\t\t\"destinations\": [\n\t\t\t\t{\n\t\t\t\t\t\"ip\": \"10.1.0.0/16\",\n\t\t\t\t\t\"port\": 1234\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"ip\": \"10.2.2.2\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"port\": 9123\n\t\t\t\t}\n\t\t\t],\n\t\t\t\"tags\": [\n\t\t\t\t\"admin\",\n\t\t\t\t\"high-priority\",\n\t\t\t\t\"critical\"\n\t\t\t],\n\t\t\t\"service\": {\n\t\t\t\t\"id\": \"ba641b07-e74a-430a-ab46-94b61e5ea66b\"\n\t\t\t}\n\t\t}\n\t],\n\t\"next\": \"http://localhost:8001/routes?offset=6378122c-a0a1-438d-a5c6-efabae9fb969\"\n}" + }, + { + "name": "List All Consumers", + "originalRequest": { + "method": "GET", + "header": [], + "url": { + "raw": "{{gateway}}/consumers", + "host": [ + "{{gateway}}" + ], + "path": [ + "consumers" + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "Text", + "header": [ + { + "key": "Date", + "value": "Thu, 12 Mar 2020 05:35:59 GMT" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "Server", + "value": "kong/2.0.1" + }, + { + "key": "Content-Length", + "value": "305" + }, + { + "key": "X-Kong-Admin-Latency", + "value": "2" + } + ], + "cookie": [], + "body": "{\n \"next\": \"http://localhost:8001/consumers?offset=6378122c-a0a1-438d-a5c6-efabae9fb969\",\n \"data\": [\n {\n \"custom_id\": \"my-custom-id\",\n \"created_at\": 1583991173,\n \"id\": \"626169e4-6cd7-4952-85b1-3fda70fd5333\",\n \"tags\": [\n \"user-level\",\n \"low-priority\"\n ],\n \"username\": \"my-username\",\n \"updated_at\": 96342876,\n \"name\": \"pariatur occaecat\",\n \"protocols\": [\n \"elit sunt\",\n \"sit est\",\n \"tempor id\"\n ],\n \"https_redirect_status_code\": 7940952,\n \"regex_priority\": -84514160,\n \"strip_path\": false,\n \"path_handling\": \"commodo Excepteur anim officia\",\n \"preserve_host\": true,\n \"service\": {\n \"id\": \"sunt est\"\n }\n },\n {\n \"custom_id\": null,\n \"created_at\": 1583991062,\n \"id\": \"67775de2-2f2e-4eb1-90c8-967490e7b6c5\",\n \"tags\": [\n \"ullamco magna\",\n \"sint officia ullamco sit\",\n \"deserunt consectetur\",\n \"qui enim sit veniam\"\n ],\n \"username\": \"my-consumer\",\n \"updated_at\": 64497866,\n \"name\": \"occaecat incididunt qui aliqua comm\",\n \"protocols\": [\n \"eu elit\",\n \"minim velit enim\",\n \"est sit fugiat commodo\"\n ],\n \"https_redirect_status_code\": -26417144,\n \"regex_priority\": -51823528,\n \"strip_path\": false,\n \"path_handling\": \"deserunt sit\",\n \"preserve_host\": false,\n \"service\": {\n \"id\": \"esse\"\n }\n }\n ]\n}" + } + ] + } + ], + "description": "https://docs.konghq.com/2.0.x/admin-api/#list-consumers", + "event": [ + { + "listen": "prerequest", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + }, + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + } + ] + }, + { + "name": "Retrieve Consumer", + "item": [ + { + "name": "Retrieve Consumer", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{gateway}}/consumers/:consumerUsernameOrID", + "host": [ + "{{gateway}}" + ], + "path": [ + "consumers", + ":consumerUsernameOrID" + ], + "variable": [ + { + "key": "consumerUsernameOrID", + "value": "my-username", + "description": "The unique identifier or the username of the Consumer to retrieve." + } + ] + }, + "description": "## Retrieve Consumer [konghq](https://docs.konghq.com/2.0.x/admin-api/#retrieve-consumer-1)\n\n \n \n \n \n \n \n \n \n \n \n \n \n
AttributesMandatoryTypeDescription
consumer username or idrequiredpathThe unique identifier or the username of the Consumer to retrieve.
" + }, + "response": [ + { + "name": "Retrieve Consumer - 200", + "originalRequest": { + "method": "GET", + "header": [], + "url": { + "raw": "{{gateway}}/consumers/:consumerUsernameOrID", + "host": [ + "{{gateway}}" + ], + "path": [ + "consumers", + ":consumerUsernameOrID" + ], + "variable": [ + { + "key": "consumerUsernameOrID", + "value": "my-username", + "description": "The unique identifier or the username of the Consumer to retrieve." + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "Text", + "header": [ + { + "key": "Date", + "value": "Thu, 12 Mar 2020 06:16:23 GMT" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "Server", + "value": "kong/2.0.1" + }, + { + "key": "Content-Length", + "value": "158" + }, + { + "key": "X-Kong-Admin-Latency", + "value": "2" + } + ], + "cookie": [], + "body": "{\n \"custom_id\": \"my-custom-id\",\n \"created_at\": 1583991173,\n \"id\": \"626169e4-6cd7-4952-85b1-3fda70fd5333\",\n \"tags\": [\n \"user-level\",\n \"low-priority\"\n ],\n \"username\": \"my-username\"\n}" + }, + { + "name": "Retrieve Consumer - 404", + "originalRequest": { + "method": "GET", + "header": [], + "url": { + "raw": "{{gateway}}/consumers/:consumerUsernameOrID", + "host": [ + "{{gateway}}" + ], + "path": [ + "consumers", + ":consumerUsernameOrID" + ], + "variable": [ + { + "key": "consumerUsernameOrID", + "value": "my-usernamel", + "description": "The unique identifier or the username of the Consumer to retrieve." + } + ] + } + }, + "status": "Not Found", + "code": 404, + "_postman_previewlanguage": "Text", + "header": [ + { + "key": "Date", + "value": "Thu, 12 Mar 2020 06:17:18 GMT" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "Server", + "value": "kong/2.0.1" + }, + { + "key": "Content-Length", + "value": "23" + }, + { + "key": "X-Kong-Admin-Latency", + "value": "1" + } + ], + "cookie": [], + "body": "{\n \"message\": \"Not found\"\n}" + } + ] + }, + { + "name": "Retrieve Consumer Associated to a Specific Plugin", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{gateway}}/plugins/:pluginId/consumer", + "host": [ + "{{gateway}}" + ], + "path": [ + "plugins", + ":pluginId", + "consumer" + ], + "variable": [ + { + "key": "pluginId", + "value": "", + "description": "The unique identifier or the username of the Consumer to retrieve" + } + ] + }, + "description": "## Retrieve Consumer Associated to a Specific Plugin [konghq](https://docs.konghq.com/2.0.x/admin-api/#retrieve-consumer-associated-to-a-specific-plugin)\n\n \n \n \n \n \n \n \n \n \n \n \n \n
AttributesMandatoryTypeDescription
https://docs.konghq.com/2.0.x/admin-api/#retrieve-consumer-associated-to-a-specific-pluginrequiredpathThe unique identifier or the username of the Consumer to retrieve.
" + }, + "response": [] + } + ], + "description": "https://docs.konghq.com/2.0.x/admin-api/#retrieve-consumer", + "event": [ + { + "listen": "prerequest", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + }, + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + } + ] + }, + { + "name": "Update Consumer", + "item": [ + { + "name": "Update Consumer", + "request": { + "method": "PATCH", + "header": [ + { + "name": "Content-Type", + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"username\": \"my-username\",\r\n \"custom_id\": \"my-custom-id\",\r\n \"tags\": [\"user-level\", \"low-priority\"]\r\n}" + }, + "url": { + "raw": "{{gateway}}/consumers/:consumerUsernameOrId", + "host": [ + "{{gateway}}" + ], + "path": [ + "consumers", + ":consumerUsernameOrId" + ], + "variable": [ + { + "key": "consumerUsernameOrId", + "value": "my-username", + "description": "The unique identifier or the username of the Consumer to retrieve" + } + ] + }, + "description": "## Update Consumer [konghq](https://docs.konghq.com/2.0.x/admin-api/#update-consumer-1)\n\n \n \n \n \n \n \n \n \n \n \n \n \n
AttributesMandatoryTypeDescription
consumer username or idrequiredpathThe unique identifier or the username of the Consumer to retrieve.
\n\n## Request Body\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
AttributesMandatoryDescription
usernamesemi-optionalThe unique username of the consumer. You must send either this field or custom_id with the request.
custom_idsemi-optionalField for storing an existing unique ID for the consumer - useful for mapping Kong with users in your existing database. You must send either this field or username with the request.
tagsoptionalAn optional set of strings associated with the Consumer, for grouping and filtering.
" + }, + "response": [ + { + "name": "Update Consumer - 200", + "originalRequest": { + "method": "PATCH", + "header": [ + { + "name": "Content-Type", + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"username\": \"my-username\",\r\n \"custom_id\": \"my-custom-id\",\r\n \"tags\": [\"user-level\", \"low-priority\"]\r\n}" + }, + "url": { + "raw": "{{gateway}}/consumers/:consumerUsernameOrId", + "host": [ + "{{gateway}}" + ], + "path": [ + "consumers", + ":consumerUsernameOrId" + ], + "variable": [ + { + "key": "consumerUsernameOrId", + "value": "my-username", + "description": "The unique identifier or the username of the Consumer to retrieve" + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "Text", + "header": [ + { + "key": "Date", + "value": "Thu, 12 Mar 2020 06:27:20 GMT" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "Server", + "value": "kong/2.0.1" + }, + { + "key": "Content-Length", + "value": "158" + }, + { + "key": "X-Kong-Admin-Latency", + "value": "11" + } + ], + "cookie": [], + "body": "{\n \"custom_id\": \"my-custom-id\",\n \"created_at\": 1583991173,\n \"id\": \"626169e4-6cd7-4952-85b1-3fda70fd5333\",\n \"tags\": [\n \"user-level\",\n \"low-priority\"\n ],\n \"username\": \"my-username\"\n}" + } + ] + }, + { + "name": "Update Consumer Associated to a Specific Plugin", + "request": { + "method": "PATCH", + "header": [ + { + "name": "Content-Type", + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"username\": \"my-username\",\r\n \"custom_id\": \"my-custom-id\",\r\n \"tags\": [\"user-level\", \"low-priority\"]\r\n}" + }, + "url": { + "raw": "{{gateway}}/plugins/:pluginId/consumer", + "host": [ + "{{gateway}}" + ], + "path": [ + "plugins", + ":pluginId", + "consumer" + ], + "variable": [ + { + "key": "pluginId", + "value": "", + "description": "The unique identifier of the Plugin associated to the Consumer to be updated." + } + ] + }, + "description": "## Update Consumer Associated to a Specific Plugin [konghq](https://docs.konghq.com/2.0.x/admin-api/#update-consumer-associated-to-a-specific-plugin)\n\n \n \n \n \n \n \n \n \n \n \n \n \n
AttributesMandatoryTypeDescription
plugin idrequiredpathThe unique identifier of the Plugin associated to the Consumer to be updated.
\n\n## Request Body\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
AttributesMandatoryDescription
usernamesemi-optionalThe unique username of the consumer. You must send either this field or custom_id with the request.
custom_idsemi-optionalField for storing an existing unique ID for the consumer - useful for mapping Kong with users in your existing database. You must send either this field or username with the request.
tagsoptionalAn optional set of strings associated with the Consumer, for grouping and filtering.
" + }, + "response": [] + } + ], + "description": "https://docs.konghq.com/2.0.x/admin-api/#update-consumer", + "event": [ + { + "listen": "prerequest", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + }, + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + } + ] + }, + { + "name": "Update Or Create Consumer", + "item": [ + { + "name": "Create Or Update Consumer", + "request": { + "method": "PUT", + "header": [ + { + "name": "Content-Type", + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"username\": \"my-username1\",\r\n \"custom_id\": \"my-custom-id1\",\r\n \"tags\": [\"user-level\", \"low-priority\"]\r\n}" + }, + "url": { + "raw": "{{gateway}}/consumers/:consumerUsernameOrId", + "host": [ + "{{gateway}}" + ], + "path": [ + "consumers", + ":consumerUsernameOrId" + ], + "variable": [ + { + "key": "consumerUsernameOrId", + "value": "my-username1", + "description": "The unique identifier or the username of the Consumer to retrieve" + } + ] + }, + "description": "## Create Or Update Consumer [konghq](https://docs.konghq.com/2.0.x/admin-api/#create-or-update-consumer)\n\n* Inserts (or replaces) the Consumer under the requested resource with the definition specified in the body. The Consumer will be identified via the username or id attribute.\n* When the username or id attribute has the structure of a UUID, the Consumer being inserted/replaced will be identified by its id. Otherwise it will be identified by its username.\n* When creating a new Consumer without specifying id (neither in the URL nor in the body), then it will be auto-generated.\n* Notice that specifying a username in the URL and a different one in the request body is not allowed.\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n
AttributesMandatoryTypeDescription
consumer username or idrequiredpathThe unique identifier or the username of the Consumer to retrieve.
\n\n## Request Body\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
AttributesMandatoryDescription
usernamesemi-optionalThe unique username of the consumer. You must send either this field or custom_id with the request.
custom_idsemi-optionalField for storing an existing unique ID for the consumer - useful for mapping Kong with users in your existing database. You must send either this field or username with the request.
tagsoptionalAn optional set of strings associated with the Consumer, for grouping and filtering.
" + }, + "response": [ + { + "name": "Create Or Update Consumer - 200", + "originalRequest": { + "method": "PUT", + "header": [ + { + "name": "Content-Type", + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"username\": \"my-username1\",\r\n \"custom_id\": \"my-custom-id1\",\r\n \"tags\": [\"user-level\", \"low-priority\"]\r\n}" + }, + "url": { + "raw": "{{gateway}}/consumers/:consumerUsernameOrId", + "host": [ + "{{gateway}}" + ], + "path": [ + "consumers", + ":consumerUsernameOrId" + ], + "variable": [ + { + "key": "consumerUsernameOrId", + "value": "my-username1", + "description": "The unique identifier or the username of the Consumer to retrieve" + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "Text", + "header": [ + { + "key": "Date", + "value": "Thu, 12 Mar 2020 06:37:32 GMT" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "Server", + "value": "kong/2.0.1" + }, + { + "key": "Content-Length", + "value": "160" + }, + { + "key": "X-Kong-Admin-Latency", + "value": "7" + } + ], + "cookie": [], + "body": "{\n \"custom_id\": \"my-custom-id1\",\n \"created_at\": 1583995052,\n \"id\": \"c883d8e7-0a33-4153-9d18-0741a3412125\",\n \"tags\": [\n \"user-level\",\n \"low-priority\"\n ],\n \"username\": \"my-username1\"\n}" + }, + { + "name": "Create Or Update Consumer - 409", + "originalRequest": { + "method": "PUT", + "header": [ + { + "name": "Content-Type", + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"username\": \"my-username2\",\r\n \"custom_id\": \"my-custom-id\",\r\n \"tags\": [\"user-level\", \"low-priority\"]\r\n}" + }, + "url": { + "raw": "{{gateway}}/consumers/:consumerUsernameOrId", + "host": [ + "{{gateway}}" + ], + "path": [ + "consumers", + ":consumerUsernameOrId" + ], + "variable": [ + { + "key": "consumerUsernameOrId", + "value": "my-username", + "description": "The unique identifier or the username of the Consumer to retrieve" + } + ] + } + }, + "status": "Conflict", + "code": 409, + "_postman_previewlanguage": "Text", + "header": [ + { + "key": "Date", + "value": "Thu, 12 Mar 2020 06:36:37 GMT" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "Server", + "value": "kong/2.0.1" + }, + { + "key": "Content-Length", + "value": "157" + }, + { + "key": "X-Kong-Admin-Latency", + "value": "2" + } + ], + "cookie": [], + "body": "{\n \"message\": \"UNIQUE violation detected on '{custom_id=\\\"my-custom-id\\\"}'\",\n \"name\": \"unique constraint violation\",\n \"fields\": {\n \"custom_id\": \"my-custom-id\"\n },\n \"code\": 5\n}" + } + ] + }, + { + "name": "Create Or Update Consumer Associated to a Specific Plugin", + "request": { + "method": "PUT", + "header": [ + { + "name": "Content-Type", + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"username\": \"my-username1\",\r\n \"custom_id\": \"my-custom-id1\",\r\n \"tags\": [\"user-level\", \"low-priority\"]\r\n}" + }, + "url": { + "raw": "{{gateway}}/plugins/:pluginId/consumer", + "host": [ + "{{gateway}}" + ], + "path": [ + "plugins", + ":pluginId", + "consumer" + ], + "variable": [ + { + "key": "pluginId", + "value": "", + "description": "The unique identifier of the Plugin associated to the Consumer to be created or updated." + } + ] + }, + "description": "## Create Or Update Consumer Associated to a Specific Plugin [konghq](https://docs.konghq.com/2.0.x/admin-api/#create-or-update-consumer-associated-to-a-specific-plugin)\n\n* Inserts (or replaces) the Consumer under the requested resource with the definition specified in the body. The Consumer will be identified via the username or id attribute.\n* When the username or id attribute has the structure of a UUID, the Consumer being inserted/replaced will be identified by its id. Otherwise it will be identified by its username.\n* When creating a new Consumer without specifying id (neither in the URL nor in the body), then it will be auto-generated.\n* Notice that specifying a username in the URL and a different one in the request body is not allowed.\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n
AttributesMandatoryTypeDescription
plugin idrequiredpathThe unique identifier of the Plugin associated to the Consumer to be created or updated.
\n\n## Request Body\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
AttributesMandatoryDescription
usernamesemi-optionalThe unique username of the consumer. You must send either this field or custom_id with the request.
custom_idsemi-optionalField for storing an existing unique ID for the consumer - useful for mapping Kong with users in your existing database. You must send either this field or username with the request.
tagsoptionalAn optional set of strings associated with the Consumer, for grouping and filtering.
" + }, + "response": [] + } + ], + "description": "https://docs.konghq.com/2.0.x/admin-api/#update-or-create-consumer", + "event": [ + { + "listen": "prerequest", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + }, + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + } + ] + }, + { + "name": "Delete Consumer", + "item": [ + { + "name": "Delete Consumer", + "request": { + "method": "DELETE", + "header": [], + "url": { + "raw": "{{gateway}}/consumers/:consumerUsernameOrId", + "host": [ + "{{gateway}}" + ], + "path": [ + "consumers", + ":consumerUsernameOrId" + ], + "variable": [ + { + "key": "consumerUsernameOrId", + "value": "", + "description": "The unique identifier or the username of the Consumer to delete." + } + ] + }, + "description": "## Delete Consumer [konghq](https://docs.konghq.com/2.0.x/admin-api/#delete-consumer-1)\n\n \n \n \n \n \n \n \n \n \n \n \n \n
AttributesMandatoryTypeDescription
consumer username or idrequiredpathThe unique identifier or the username of the Consumer to delete.
" + }, + "response": [] + } + ], + "description": "https://docs.konghq.com/2.0.x/admin-api/#delete-consumer", + "event": [ + { + "listen": "prerequest", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + }, + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + } + ] + } + ], + "description": "https://docs.konghq.com/2.0.x/admin-api/#consumer-object\n\n* The Consumer object represents a consumer - or a user - of a Service. You can either rely on Kong as the primary datastore, or you can map the consumer list with your database to keep consistency between Kong and your existing primary datastore.\n\n* Consumers can be both tagged and filtered by tags.\n\n{\n \"id\": \"ec1a1f6f-2aa4-4e58-93ff-b56368f19b27\",\n \"created_at\": 1422386534,\n \"username\": \"my-username\",\n \"custom_id\": \"my-custom-id\",\n \"tags\": [\"user-level\", \"low-priority\"]\n}\n", + "event": [ + { + "listen": "prerequest", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + }, + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + } + ] + }, + { + "name": "Route Object", + "item": [ + { + "name": "Add Route", + "item": [ + { + "name": "Create Route", + "request": { + "method": "POST", + "header": [ + { + "name": "Content-Type", + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"name\": \"httpbin-api\",\n\t\"url\": \"https://httpbin.org/\"\n}" + }, + "url": { + "raw": "{{gateway}}/routes", + "host": [ + "{{gateway}}" + ], + "path": [ + "routes" + ] + }, + "description": "## Create Route [konghq](https://docs.konghq.com/2.0.x/admin-api/#create-route)\n\n* See also [konghq](https://docs.konghq.com/2.0.x/admin-api/#route-object)\n\n## Request Body\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
AttributesMandatoryDescription
nameoptionalThe Route name
protocolsrequiredA list of the protocols this Route should allow. When set to [\"https\"], HTTP requests are answered with a request to upgrade to HTTPS. Defaults to [\"http\", \"https\"]
methodssemi-optionalA list of HTTP methods that match this Route
hostssemi-optionalA list of domain names that match this Route. With form-encoded, the notation is hosts[]=example.com&hosts[]=foo.test. With JSON, use an Array.
pathssemi-optionalA list of paths that match this Route. With form-encoded, the notation is paths[]=/foo&paths[]=/bar. With JSON, use an Array.
headerssemi-optionalOne or more lists of values indexed by header name that will cause this Route to match if present in the request. The Host header cannot be used with this attribute: hosts should be specified using the hosts attribute.
https_redirect_status_coderequiredThe status code Kong responds with when all properties of a Route match except the protocol i.e. if the protocol of the request is HTTP instead of HTTPS. Location header is injected by Kong if the field is set to 301, 302, 307 or 308. Accepted values are: 426, 301, 302, 307, 308. Defaults to 426.
regex_priorityoptionalA number used to choose which route resolves a given request when several routes match it using regexes simultaneously. When two routes match the path and have the same regex_priority, the older one (lowest created_at) is used. Note that the priority for non-regex routes is different (longer non-regex routes are matched before shorter ones). Defaults to 0.
strip_pathoptionalWhen matching a Route via one of the paths, strip the matching prefix from the upstream request URL. Defaults to true.
path_handlingoptionalControls how the Service path, Route path and requested path are combined when sending a request to the upstream. See above for a detailed description of each behavior. Accepted values are: \"v0\", \"v1\". Defaults to \"v0\".
preserve_hostoptionalWhen matching a Route via one of the hosts domain names, use the request Host header in the upstream request headers. If set to false, the upstream Host header will be that of the Service’s host.
snissemi-optionalA list of SNIs that match this Route when using stream routing.
sourcessemi-optionalA list of IP sources of incoming connections that match this Route when using stream routing. Each entry is an object with fields “ip” (optionally in CIDR range notation) and/or “port”.
preserve_hostoptionalWhen matching a Route via one of the hosts domain names, use the request Host header in the upstream request headers. If set to false, the upstream Host header will be that of the Service’s host.
destinationssemi-optionalA list of IP destinations of incoming connections that match this Route when using stream routing. Each entry is an object with fields “ip” (optionally in CIDR range notation) and/or “port”.
tagsoptionalAn optional set of strings associated with the Route, for grouping and filtering.
serviceoptionalThe Service this Route is associated to. This is where the Route proxies traffic to. With form-encoded, the notation is service.id= or service.name=. With JSON, use “\"service\":{\"id\":\"\"} or \"service\":{\"name\":\"\"}
" + }, + "response": [ + { + "name": "Create Route - 201", + "originalRequest": { + "method": "POST", + "header": [ + { + "name": "Content-Type", + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"name\": \"my-route\",\n\t\"protocols\": [\n\t\t\"http\",\n\t\t\"https\"\n\t],\n\t\"methods\": [\n\t\t\"GET\",\n\t\t\"POST\"\n\t],\n\t\"hosts\": [\n\t\t\"example.com\",\n\t\t\"foo.test\"\n\t],\n\t\"paths\": [\n\t\t\"/foo\",\n\t\t\"/bar\"\n\t],\n\t\"headers\": {\n\t\t\"x-another-header\": [\n\t\t\t\"bla\"\n\t\t],\n\t\t\"x-my-header\": [\n\t\t\t\"foo\",\n\t\t\t\"bar\"\n\t\t]\n\t},\n\t\"https_redirect_status_code\": 426,\n\t\"regex_priority\": 0,\n\t\"strip_path\": true,\n\t\"path_handling\": \"v0\",\n\t\"preserve_host\": false,\n\t\"tags\": [\n\t\t\"user-level\",\n\t\t\"low-priority\"\n\t],\n\t\"service\": {\n\t\t\"id\": \"c8b8f724-7e73-4df6-b1a8-8df19642d388\"\n\t}\n}" + }, + "url": { + "raw": "{{gateway}}/routes", + "host": [ + "{{gateway}}" + ], + "path": [ + "routes" + ] + } + }, + "status": "Created", + "code": 201, + "_postman_previewlanguage": "Text", + "header": [ + { + "key": "Date", + "value": "Thu, 12 Mar 2020 01:51:19 GMT" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "Server", + "value": "kong/2.0.1" + }, + { + "key": "Content-Length", + "value": "546" + }, + { + "key": "X-Kong-Admin-Latency", + "value": "25" + } + ], + "cookie": [], + "body": "{\n \"id\": \"875973fd-ba3f-4c7b-8301-e9263013e6d2\",\n \"path_handling\": \"v0\",\n \"paths\": [\n \"/foo\",\n \"/bar\"\n ],\n \"destinations\": null,\n \"headers\": {\n \"x-another-header\": [\n \"bla\"\n ],\n \"x-my-header\": [\n \"foo\",\n \"bar\"\n ]\n },\n \"protocols\": [\n \"http\",\n \"https\"\n ],\n \"methods\": [\n \"GET\",\n \"POST\"\n ],\n \"snis\": null,\n \"service\": {\n \"id\": \"c8b8f724-7e73-4df6-b1a8-8df19642d388\"\n },\n \"name\": \"my-route\",\n \"strip_path\": true,\n \"preserve_host\": false,\n \"regex_priority\": 0,\n \"updated_at\": 1583977879,\n \"sources\": null,\n \"hosts\": [\n \"example.com\",\n \"foo.test\"\n ],\n \"https_redirect_status_code\": 426,\n \"tags\": [\n \"user-level\",\n \"low-priority\"\n ],\n \"created_at\": 1583977879\n}" + }, + { + "name": "Create Route - 400", + "originalRequest": { + "method": "POST", + "header": [ + { + "name": "Content-Type", + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"id\": \"d35165e2-d03e-461a-bdeb-dad0a112abfe\",\n\t\"created_at\": 1422386534,\n\t\"updated_at\": 1422386534,\n\t\"name\": \"my-route\",\n\t\"protocols\": [\n\t\t\"http\",\n\t\t\"https\"\n\t],\n\t\"methods\": [\n\t\t\"GET\",\n\t\t\"POST\"\n\t],\n\t\"hosts\": [\n\t\t\"example.com\",\n\t\t\"foo.test\"\n\t],\n\t\"paths\": [\n\t\t\"/foo\",\n\t\t\"/bar\"\n\t],\n\t\"headers\": {\n\t\t\"x-another-header\": [\n\t\t\t\"bla\"\n\t\t],\n\t\t\"x-my-header\": [\n\t\t\t\"foo\",\n\t\t\t\"bar\"\n\t\t]\n\t},\n\t\"https_redirect_status_code\": 426,\n\t\"regex_priority\": 0,\n\t\"strip_path\": true,\n\t\"path_handling\": \"v0\",\n\t\"preserve_host\": false,\n\t\"tags\": [\n\t\t\"user-level\",\n\t\t\"low-priority\"\n\t],\n\t\"service\": {\n\t\t\"id\": \"af8330d3-dbdc-48bd-b1be-55b98608834b\"\n\t}\n}" + }, + "url": { + "raw": "{{gateway}}/routes", + "host": [ + "{{gateway}}" + ], + "path": [ + "routes" + ] + } + }, + "status": "Bad Request", + "code": 400, + "_postman_previewlanguage": "Text", + "header": [ + { + "key": "Date", + "value": "Thu, 12 Mar 2020 01:49:26 GMT" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "Server", + "value": "kong/2.0.1" + }, + { + "key": "Content-Length", + "value": "234" + }, + { + "key": "X-Kong-Admin-Latency", + "value": "7" + } + ], + "cookie": [], + "body": "{\n \"message\": \"the foreign key '{id=\\\"af8330d3-dbdc-48bd-b1be-55b98608834b\\\"}' does not reference an existing 'services' entity.\",\n \"name\": \"foreign key violation\",\n \"fields\": {\n \"service\": {\n \"id\": \"af8330d3-dbdc-48bd-b1be-55b98608834b\"\n }\n },\n \"code\": 4\n}" + } + ] + }, + { + "name": "Create Route Associated to a Specific Service", + "request": { + "method": "POST", + "header": [ + { + "name": "Content-Type", + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"name\": \"httpbin-api\",\n\t\"url\": \"https://httpbin.org/\"\n}" + }, + "url": { + "raw": "{{gateway}}/services/:serviceNameOrId/routes", + "host": [ + "{{gateway}}" + ], + "path": [ + "services", + ":serviceNameOrId", + "routes" + ], + "variable": [ + { + "key": "serviceNameOrId", + "value": "" + } + ] + }, + "description": "## Create Route Associated to a Specific Service [konghq](https://docs.konghq.com/2.0.x/admin-api/#create-route-associated-to-a-specific-service)\n\n* See also [konghq](https://docs.konghq.com/2.0.x/admin-api/#route-object)\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n
AttributesMandatoryTypeDescription
service name or idrequiredpathThe unique identifier or the name attribute of the Service that should be associated to the newly-created Route.
\n\n## Request Body\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
AttributesMandatoryDescription
nameoptionalThe Route name
protocolsrequiredA list of the protocols this Route should allow. When set to [\"https\"], HTTP requests are answered with a request to upgrade to HTTPS. Defaults to [\"http\", \"https\"]
methodssemi-optionalA list of HTTP methods that match this Route
hostssemi-optionalA list of domain names that match this Route. With form-encoded, the notation is hosts[]=example.com&hosts[]=foo.test. With JSON, use an Array.
pathssemi-optionalA list of paths that match this Route. With form-encoded, the notation is paths[]=/foo&paths[]=/bar. With JSON, use an Array.
headerssemi-optionalOne or more lists of values indexed by header name that will cause this Route to match if present in the request. The Host header cannot be used with this attribute: hosts should be specified using the hosts attribute.
https_redirect_status_coderequiredThe status code Kong responds with when all properties of a Route match except the protocol i.e. if the protocol of the request is HTTP instead of HTTPS. Location header is injected by Kong if the field is set to 301, 302, 307 or 308. Accepted values are: 426, 301, 302, 307, 308. Defaults to 426.
regex_priorityoptionalA number used to choose which route resolves a given request when several routes match it using regexes simultaneously. When two routes match the path and have the same regex_priority, the older one (lowest created_at) is used. Note that the priority for non-regex routes is different (longer non-regex routes are matched before shorter ones). Defaults to 0.
strip_pathoptionalWhen matching a Route via one of the paths, strip the matching prefix from the upstream request URL. Defaults to true.
path_handlingoptionalControls how the Service path, Route path and requested path are combined when sending a request to the upstream. See above for a detailed description of each behavior. Accepted values are: \"v0\", \"v1\". Defaults to \"v0\".
preserve_hostoptionalWhen matching a Route via one of the hosts domain names, use the request Host header in the upstream request headers. If set to false, the upstream Host header will be that of the Service’s host.
snissemi-optionalA list of SNIs that match this Route when using stream routing.
sourcessemi-optionalA list of IP sources of incoming connections that match this Route when using stream routing. Each entry is an object with fields “ip” (optionally in CIDR range notation) and/or “port”.
preserve_hostoptionalWhen matching a Route via one of the hosts domain names, use the request Host header in the upstream request headers. If set to false, the upstream Host header will be that of the Service’s host.
destinationssemi-optionalA list of IP destinations of incoming connections that match this Route when using stream routing. Each entry is an object with fields “ip” (optionally in CIDR range notation) and/or “port”.
tagsoptionalAn optional set of strings associated with the Route, for grouping and filtering.
serviceoptionalThe Service this Route is associated to. This is where the Route proxies traffic to. With form-encoded, the notation is service.id= or service.name=. With JSON, use “\"service\":{\"id\":\"\"} or \"service\":{\"name\":\"\"}
" + }, + "response": [] + } + ], + "description": "https://docs.konghq.com/2.0.x/admin-api/#add-route", + "event": [ + { + "listen": "prerequest", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + }, + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + } + ] + }, + { + "name": "List Routes", + "item": [ + { + "name": "List All Routes", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{gateway}}/routes", + "host": [ + "{{gateway}}" + ], + "path": [ + "routes" + ] + }, + "description": "## List All Routes [konghq](https://docs.konghq.com/2.0.x/admin-api/#list-all-routes)" + }, + "response": [ + { + "name": "List All Routes", + "originalRequest": { + "method": "GET", + "header": [], + "url": { + "raw": "{{gateway}}/routes", + "host": [ + "{{gateway}}" + ], + "path": [ + "routes" + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "Text", + "header": [ + { + "key": "Date", + "value": "Thu, 12 Mar 2020 01:21:59 GMT" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "Server", + "value": "kong/2.0.1" + }, + { + "key": "Content-Length", + "value": "23" + }, + { + "key": "X-Kong-Admin-Latency", + "value": "2" + } + ], + "cookie": [], + "body": "{\n\t\"data\": [\n\t\t{\n\t\t\t\"id\": \"a9daa3ba-8186-4a0d-96e8-00d80ce7240b\",\n\t\t\t\"created_at\": 1422386534,\n\t\t\t\"updated_at\": 1422386534,\n\t\t\t\"name\": \"my-route\",\n\t\t\t\"protocols\": [\n\t\t\t\t\"http\",\n\t\t\t\t\"https\"\n\t\t\t],\n\t\t\t\"methods\": [\n\t\t\t\t\"GET\",\n\t\t\t\t\"POST\"\n\t\t\t],\n\t\t\t\"hosts\": [\n\t\t\t\t\"example.com\",\n\t\t\t\t\"foo.test\"\n\t\t\t],\n\t\t\t\"paths\": [\n\t\t\t\t\"/foo\",\n\t\t\t\t\"/bar\"\n\t\t\t],\n\t\t\t\"headers\": {\n\t\t\t\t\"x-another-header\": [\n\t\t\t\t\t\"bla\"\n\t\t\t\t],\n\t\t\t\t\"x-my-header\": [\n\t\t\t\t\t\"foo\",\n\t\t\t\t\t\"bar\"\n\t\t\t\t]\n\t\t\t},\n\t\t\t\"https_redirect_status_code\": 426,\n\t\t\t\"regex_priority\": 0,\n\t\t\t\"strip_path\": true,\n\t\t\t\"path_handling\": \"v0\",\n\t\t\t\"preserve_host\": false,\n\t\t\t\"tags\": [\n\t\t\t\t\"user-level\",\n\t\t\t\t\"low-priority\"\n\t\t\t],\n\t\t\t\"service\": {\n\t\t\t\t\"id\": \"127dfc88-ed57-45bf-b77a-a9d3a152ad31\"\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"id\": \"9aa116fd-ef4a-4efa-89bf-a0b17c4be982\",\n\t\t\t\"created_at\": 1422386534,\n\t\t\t\"updated_at\": 1422386534,\n\t\t\t\"name\": \"my-route\",\n\t\t\t\"protocols\": [\n\t\t\t\t\"tcp\",\n\t\t\t\t\"tls\"\n\t\t\t],\n\t\t\t\"https_redirect_status_code\": 426,\n\t\t\t\"regex_priority\": 0,\n\t\t\t\"strip_path\": true,\n\t\t\t\"path_handling\": \"v0\",\n\t\t\t\"preserve_host\": false,\n\t\t\t\"snis\": [\n\t\t\t\t\"foo.test\",\n\t\t\t\t\"example.com\"\n\t\t\t],\n\t\t\t\"sources\": [\n\t\t\t\t{\n\t\t\t\t\t\"ip\": \"10.1.0.0/16\",\n\t\t\t\t\t\"port\": 1234\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"ip\": \"10.2.2.2\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"port\": 9123\n\t\t\t\t}\n\t\t\t],\n\t\t\t\"destinations\": [\n\t\t\t\t{\n\t\t\t\t\t\"ip\": \"10.1.0.0/16\",\n\t\t\t\t\t\"port\": 1234\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"ip\": \"10.2.2.2\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"port\": 9123\n\t\t\t\t}\n\t\t\t],\n\t\t\t\"tags\": [\n\t\t\t\t\"admin\",\n\t\t\t\t\"high-priority\",\n\t\t\t\t\"critical\"\n\t\t\t],\n\t\t\t\"service\": {\n\t\t\t\t\"id\": \"ba641b07-e74a-430a-ab46-94b61e5ea66b\"\n\t\t\t}\n\t\t}\n\t],\n\t\"next\": \"http://localhost:8001/routes?offset=6378122c-a0a1-438d-a5c6-efabae9fb969\"\n}" + } + ] + }, + { + "name": "List Routes Associated to a Specific Service", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{gateway}}/services/:serviceNameOrId/routes", + "host": [ + "{{gateway}}" + ], + "path": [ + "services", + ":serviceNameOrId", + "routes" + ], + "variable": [ + { + "key": "serviceNameOrId", + "value": "httpbin-api", + "description": "The unique identifier or the name attribute of the Service whose Routes are to be retrieved. When using this endpoint, only Routes associated to the specified Service will be listed." + } + ] + }, + "description": "## List Routes Associated to a Specific Service [konghq](https://docs.konghq.com/2.0.x/admin-api/#list-routes-associated-to-a-specific-service)\n\n \n \n \n \n \n \n \n \n \n \n \n " + }, + "response": [ + { + "name": "List Routes Associated to a Specific Service", + "originalRequest": { + "method": "GET", + "header": [], + "url": { + "raw": "{{gateway}}/services/:serviceNameOrId/routes", + "host": [ + "{{gateway}}" + ], + "path": [ + "services", + ":serviceNameOrId", + "routes" + ], + "variable": [ + { + "key": "serviceNameOrId", + "value": "httpbin-api", + "description": "The unique identifier or the name attribute of the Service whose Routes are to be retrieved. When using this endpoint, only Routes associated to the specified Service will be listed." + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "Text", + "header": [ + { + "key": "Date", + "value": "Thu, 12 Mar 2020 01:53:37 GMT" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "Server", + "value": "kong/2.0.1" + }, + { + "key": "Content-Length", + "value": "569" + }, + { + "key": "X-Kong-Admin-Latency", + "value": "3" + } + ], + "cookie": [], + "body": "{\n \"next\": null,\n \"data\": [\n {\n \"id\": \"875973fd-ba3f-4c7b-8301-e9263013e6d2\",\n \"path_handling\": \"v0\",\n \"paths\": [\n \"/foo\",\n \"/bar\"\n ],\n \"destinations\": null,\n \"headers\": {\n \"x-another-header\": [\n \"bla\"\n ],\n \"x-my-header\": [\n \"foo\",\n \"bar\"\n ]\n },\n \"protocols\": [\n \"http\",\n \"https\"\n ],\n \"methods\": [\n \"GET\",\n \"POST\"\n ],\n \"snis\": null,\n \"service\": {\n \"id\": \"c8b8f724-7e73-4df6-b1a8-8df19642d388\"\n },\n \"name\": \"my-route\",\n \"strip_path\": true,\n \"preserve_host\": false,\n \"regex_priority\": 0,\n \"updated_at\": 1583977879,\n \"sources\": null,\n \"hosts\": [\n \"example.com\",\n \"foo.test\"\n ],\n \"https_redirect_status_code\": 426,\n \"tags\": [\n \"user-level\",\n \"low-priority\"\n ],\n \"created_at\": 1583977879\n }\n ]\n}" + } + ] + } + ], + "description": "https://docs.konghq.com/2.0.x/admin-api/#list-routes", + "event": [ + { + "listen": "prerequest", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + }, + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + } + ] + }, + { + "name": "Retrieve Route", + "item": [ + { + "name": "Retrieve Route", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{gateway}}/routes/:routeNameOrID", + "host": [ + "{{gateway}}" + ], + "path": [ + "routes", + ":routeNameOrID" + ], + "variable": [ + { + "key": "routeNameOrID", + "value": "my-route", + "description": "The unique identifier or the name of the Route to retrieve." + } + ] + }, + "description": "## Retrieve Route [konghq](https://docs.konghq.com/2.0.x/admin-api/#retrieve-route-1)\n
AttributesMandatoryTypeDescription
service name or idrequiredpathThe unique identifier or the name attribute of the Service whose Routes are to be retrieved. When using this endpoint, only Routes associated to the specified Service will be listed.
\n \n \n \n \n \n \n \n \n \n \n \n \n
AttributesMandatoryTypeDescription
Route name or idrequiredpathThe unique identifier or the name of the Route to retrieve.
" + }, + "response": [ + { + "name": "Retrieve Route", + "originalRequest": { + "method": "GET", + "header": [], + "url": { + "raw": "{{gateway}}/routes/:routeNameOrID", + "host": [ + "{{gateway}}" + ], + "path": [ + "routes", + ":routeNameOrID" + ], + "variable": [ + { + "key": "routeNameOrID", + "value": "my-route", + "description": "The unique identifier or the name of the Route to retrieve." + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "Text", + "header": [ + { + "key": "Date", + "value": "Thu, 12 Mar 2020 01:55:07 GMT" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "Server", + "value": "kong/2.0.1" + }, + { + "key": "Content-Length", + "value": "546" + }, + { + "key": "X-Kong-Admin-Latency", + "value": "1" + } + ], + "cookie": [], + "body": "{\n \"id\": \"875973fd-ba3f-4c7b-8301-e9263013e6d2\",\n \"path_handling\": \"v0\",\n \"paths\": [\n \"/foo\",\n \"/bar\"\n ],\n \"destinations\": null,\n \"headers\": {\n \"x-another-header\": [\n \"bla\"\n ],\n \"x-my-header\": [\n \"foo\",\n \"bar\"\n ]\n },\n \"protocols\": [\n \"http\",\n \"https\"\n ],\n \"methods\": [\n \"GET\",\n \"POST\"\n ],\n \"snis\": null,\n \"service\": {\n \"id\": \"c8b8f724-7e73-4df6-b1a8-8df19642d388\"\n },\n \"name\": \"my-route\",\n \"strip_path\": true,\n \"preserve_host\": false,\n \"regex_priority\": 0,\n \"updated_at\": 1583977879,\n \"sources\": null,\n \"hosts\": [\n \"example.com\",\n \"foo.test\"\n ],\n \"https_redirect_status_code\": 426,\n \"tags\": [\n \"user-level\",\n \"low-priority\"\n ],\n \"created_at\": 1583977879\n}" + }, + { + "name": "Retrieve Route - 404", + "originalRequest": { + "method": "GET", + "header": [], + "url": { + "raw": "{{gateway}}/routes/:routeNameOrID", + "host": [ + "{{gateway}}" + ], + "path": [ + "routes", + ":routeNameOrID" + ], + "variable": [ + { + "key": "routeNameOrID", + "value": "my-route", + "description": "The unique identifier or the name of the Route to retrieve." + } + ] + } + }, + "status": "Not Found", + "code": 404, + "_postman_previewlanguage": "Text", + "header": [ + { + "key": "Date", + "value": "Thu, 12 Mar 2020 01:48:17 GMT" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "Server", + "value": "kong/2.0.1" + }, + { + "key": "Content-Length", + "value": "23" + }, + { + "key": "X-Kong-Admin-Latency", + "value": "1" + } + ], + "cookie": [], + "body": "{\n \"message\": \"Not found\"\n}" + }, + { + "name": "Retrieve Route", + "originalRequest": { + "method": "GET", + "header": [], + "url": { + "raw": "{{gateway}}/routes/:routeNameOrID", + "host": [ + "{{gateway}}" + ], + "path": [ + "routes", + ":routeNameOrID" + ], + "variable": [ + { + "key": "routeNameOrID", + "value": "my-route", + "description": "The unique identifier or the name of the Route to retrieve." + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "Text", + "header": [ + { + "key": "Date", + "value": "Thu, 12 Mar 2020 01:46:14 GMT" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "Server", + "value": "kong/2.0.1" + }, + { + "key": "Content-Length", + "value": "23" + }, + { + "key": "X-Kong-Admin-Latency", + "value": "2" + } + ], + "cookie": [], + "body": "{\n \"id\": \"d35165e2-d03e-461a-bdeb-dad0a112abfe\",\n \"created_at\": 1422386534,\n \"updated_at\": 1422386534,\n \"name\": \"my-route\",\n \"protocols\": [\n \"http\",\n \"https\"\n ],\n \"methods\": [\n \"GET\",\n \"POST\"\n ],\n \"hosts\": [\n \"example.com\",\n \"foo.test\"\n ],\n \"paths\": [\n \"/foo\",\n \"/bar\"\n ],\n \"headers\": {\n \"x-another-header\": [\n \"bla\"\n ],\n \"x-my-header\": [\n \"foo\",\n \"bar\"\n ]\n },\n \"https_redirect_status_code\": 426,\n \"regex_priority\": 0,\n \"strip_path\": true,\n \"path_handling\": \"v0\",\n \"preserve_host\": false,\n \"tags\": [\n \"user-level\",\n \"low-priority\"\n ],\n \"service\": {\n \"id\": \"af8330d3-dbdc-48bd-b1be-55b98608834b\"\n },\n \"destinations\": \"Excepteur magna\",\n \"snis\": \"eu fugiat\",\n \"sources\": \"irure\"\n}" + } + ] + }, + { + "name": "Retrieve Route Associated to a Specific Service", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{gateway}}/services/:serviceNameOrId/routes/:routeNameOrId", + "host": [ + "{{gateway}}" + ], + "path": [ + "services", + ":serviceNameOrId", + "routes", + ":routeNameOrId" + ], + "variable": [ + { + "key": "serviceNameOrId", + "value": "httpbin-api", + "description": "The unique identifier or the name of the Service to retrieve." + }, + { + "key": "routeNameOrId", + "value": "my-route", + "description": "The unique identifier or the name of the Route to retrieve." + } + ] + }, + "description": "## Retrieve Route Associated to a Specific Service [konghq](https://docs.konghq.com/2.0.x/admin-api/#retrieve-route-associated-to-a-specific-service)\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
AttributesMandatoryTypeDescription
Service name or idrequiredpathThe unique identifier or the name of the Service to retrieve
Route name or idrequiredpathThe unique identifier or the name of the Route to retrieve.
" + }, + "response": [ + { + "name": "Retrieve Route - 404", + "originalRequest": { + "method": "GET", + "header": [], + "url": { + "raw": "{{gateway}}/routes/:routeNameOrID", + "host": [ + "{{gateway}}" + ], + "path": [ + "routes", + ":routeNameOrID" + ], + "variable": [ + { + "key": "routeNameOrID", + "value": "my-route", + "description": "The unique identifier or the name of the Route to retrieve." + } + ] + } + }, + "status": "Not Found", + "code": 404, + "_postman_previewlanguage": "Text", + "header": [ + { + "key": "Date", + "value": "Thu, 12 Mar 2020 01:48:17 GMT" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "Server", + "value": "kong/2.0.1" + }, + { + "key": "Content-Length", + "value": "23" + }, + { + "key": "X-Kong-Admin-Latency", + "value": "1" + } + ], + "cookie": [], + "body": "{\n \"message\": \"Not found\"\n}" + }, + { + "name": "Retrieve Route Associated to a Specific Service", + "originalRequest": { + "method": "GET", + "header": [], + "url": { + "raw": "{{gateway}}/services/:serviceNameOrId/routes/:routeNameOrId", + "host": [ + "{{gateway}}" + ], + "path": [ + "services", + ":serviceNameOrId", + "routes", + ":routeNameOrId" + ], + "variable": [ + { + "key": "serviceNameOrId", + "value": "httpbin-api", + "description": "The unique identifier or the name of the Service to retrieve." + }, + { + "key": "routeNameOrId", + "value": "my-route", + "description": "The unique identifier or the name of the Route to retrieve." + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "Text", + "header": [ + { + "key": "Date", + "value": "Thu, 12 Mar 2020 02:22:24 GMT" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "Server", + "value": "kong/2.0.1" + }, + { + "key": "Content-Length", + "value": "546" + }, + { + "key": "X-Kong-Admin-Latency", + "value": "4" + } + ], + "cookie": [], + "body": "{\n \"id\": \"875973fd-ba3f-4c7b-8301-e9263013e6d2\",\n \"path_handling\": \"v0\",\n \"paths\": [\n \"/foo\",\n \"/bar\"\n ],\n \"destinations\": null,\n \"headers\": {\n \"x-another-header\": [\n \"bla\"\n ],\n \"x-my-header\": [\n \"foo\",\n \"bar\"\n ]\n },\n \"protocols\": [\n \"http\",\n \"https\"\n ],\n \"methods\": [\n \"GET\",\n \"POST\"\n ],\n \"snis\": null,\n \"service\": {\n \"id\": \"c8b8f724-7e73-4df6-b1a8-8df19642d388\"\n },\n \"name\": \"my-route\",\n \"strip_path\": true,\n \"preserve_host\": false,\n \"regex_priority\": 0,\n \"updated_at\": 1583977879,\n \"sources\": null,\n \"hosts\": [\n \"example.com\",\n \"foo.test\"\n ],\n \"https_redirect_status_code\": 426,\n \"tags\": [\n \"user-level\",\n \"low-priority\"\n ],\n \"created_at\": 1583977879\n}" + }, + { + "name": "Retrieve Route", + "originalRequest": { + "method": "GET", + "header": [], + "url": { + "raw": "{{gateway}}/routes/:routeNameOrID", + "host": [ + "{{gateway}}" + ], + "path": [ + "routes", + ":routeNameOrID" + ], + "variable": [ + { + "key": "routeNameOrID", + "value": "my-route", + "description": "The unique identifier or the name of the Route to retrieve." + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "Text", + "header": [ + { + "key": "Date", + "value": "Thu, 12 Mar 2020 01:55:07 GMT" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "Server", + "value": "kong/2.0.1" + }, + { + "key": "Content-Length", + "value": "546" + }, + { + "key": "X-Kong-Admin-Latency", + "value": "1" + } + ], + "cookie": [], + "body": "{\n \"id\": \"875973fd-ba3f-4c7b-8301-e9263013e6d2\",\n \"path_handling\": \"v0\",\n \"paths\": [\n \"/foo\",\n \"/bar\"\n ],\n \"destinations\": null,\n \"headers\": {\n \"x-another-header\": [\n \"bla\"\n ],\n \"x-my-header\": [\n \"foo\",\n \"bar\"\n ]\n },\n \"protocols\": [\n \"http\",\n \"https\"\n ],\n \"methods\": [\n \"GET\",\n \"POST\"\n ],\n \"snis\": null,\n \"service\": {\n \"id\": \"c8b8f724-7e73-4df6-b1a8-8df19642d388\"\n },\n \"name\": \"my-route\",\n \"strip_path\": true,\n \"preserve_host\": false,\n \"regex_priority\": 0,\n \"updated_at\": 1583977879,\n \"sources\": null,\n \"hosts\": [\n \"example.com\",\n \"foo.test\"\n ],\n \"https_redirect_status_code\": 426,\n \"tags\": [\n \"user-level\",\n \"low-priority\"\n ],\n \"created_at\": 1583977879\n}" + }, + { + "name": "Retrieve Route", + "originalRequest": { + "method": "GET", + "header": [], + "url": { + "raw": "{{gateway}}/routes/:routeNameOrID", + "host": [ + "{{gateway}}" + ], + "path": [ + "routes", + ":routeNameOrID" + ], + "variable": [ + { + "key": "routeNameOrID", + "value": "my-route", + "description": "The unique identifier or the name of the Route to retrieve." + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "Text", + "header": [ + { + "key": "Date", + "value": "Thu, 12 Mar 2020 01:46:14 GMT" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "Server", + "value": "kong/2.0.1" + }, + { + "key": "Content-Length", + "value": "23" + }, + { + "key": "X-Kong-Admin-Latency", + "value": "2" + } + ], + "cookie": [], + "body": "{\n \"id\": \"d35165e2-d03e-461a-bdeb-dad0a112abfe\",\n \"created_at\": 1422386534,\n \"updated_at\": 1422386534,\n \"name\": \"my-route\",\n \"protocols\": [\n \"http\",\n \"https\"\n ],\n \"methods\": [\n \"GET\",\n \"POST\"\n ],\n \"hosts\": [\n \"example.com\",\n \"foo.test\"\n ],\n \"paths\": [\n \"/foo\",\n \"/bar\"\n ],\n \"headers\": {\n \"x-another-header\": [\n \"bla\"\n ],\n \"x-my-header\": [\n \"foo\",\n \"bar\"\n ]\n },\n \"https_redirect_status_code\": 426,\n \"regex_priority\": 0,\n \"strip_path\": true,\n \"path_handling\": \"v0\",\n \"preserve_host\": false,\n \"tags\": [\n \"user-level\",\n \"low-priority\"\n ],\n \"service\": {\n \"id\": \"af8330d3-dbdc-48bd-b1be-55b98608834b\"\n },\n \"destinations\": \"anim id esse\",\n \"snis\": \"in magna\",\n \"sources\": \"aliquip anim\"\n}" + } + ] + }, + { + "name": "Retrieve Route Associated to a Specific Plugin", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{gateway}}/plugins/:pluginId/route", + "host": [ + "{{gateway}}" + ], + "path": [ + "plugins", + ":pluginId", + "route" + ], + "variable": [ + { + "key": "pluginId", + "value": "", + "description": "The unique identifier of the Plugin associated to the Route to be retrieved." + } + ] + }, + "description": "## Retrieve Route Associated to a Specific Plugin [konghq](https://docs.konghq.com/2.0.x/admin-api/#retrieve-route-associated-to-a-specific-plugin)\n\n \n \n \n \n \n \n \n \n \n \n \n \n
AttributesMandatoryTypeDescription
Plugin idrequiredpathThe unique identifier of the Plugin associated to the Route to be retrieved.
" + }, + "response": [ + { + "name": "Retrieve Route Associated to a Specific Service", + "originalRequest": { + "method": "GET", + "header": [], + "url": { + "raw": "{{gateway}}/services/:serviceNameOrId/routes/:routeNameOrId", + "host": [ + "{{gateway}}" + ], + "path": [ + "services", + ":serviceNameOrId", + "routes", + ":routeNameOrId" + ], + "variable": [ + { + "key": "serviceNameOrId", + "value": "httpbin-api", + "description": "The unique identifier or the name of the Service to retrieve." + }, + { + "key": "routeNameOrId", + "value": "my-route", + "description": "The unique identifier or the name of the Route to retrieve." + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "Text", + "header": [ + { + "key": "Date", + "value": "Thu, 12 Mar 2020 02:22:24 GMT" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "Server", + "value": "kong/2.0.1" + }, + { + "key": "Content-Length", + "value": "546" + }, + { + "key": "X-Kong-Admin-Latency", + "value": "4" + } + ], + "cookie": [], + "body": "{\n \"id\": \"875973fd-ba3f-4c7b-8301-e9263013e6d2\",\n \"path_handling\": \"v0\",\n \"paths\": [\n \"/foo\",\n \"/bar\"\n ],\n \"destinations\": null,\n \"headers\": {\n \"x-another-header\": [\n \"bla\"\n ],\n \"x-my-header\": [\n \"foo\",\n \"bar\"\n ]\n },\n \"protocols\": [\n \"http\",\n \"https\"\n ],\n \"methods\": [\n \"GET\",\n \"POST\"\n ],\n \"snis\": null,\n \"service\": {\n \"id\": \"c8b8f724-7e73-4df6-b1a8-8df19642d388\"\n },\n \"name\": \"my-route\",\n \"strip_path\": true,\n \"preserve_host\": false,\n \"regex_priority\": 0,\n \"updated_at\": 1583977879,\n \"sources\": null,\n \"hosts\": [\n \"example.com\",\n \"foo.test\"\n ],\n \"https_redirect_status_code\": 426,\n \"tags\": [\n \"user-level\",\n \"low-priority\"\n ],\n \"created_at\": 1583977879\n}" + }, + { + "name": "Retrieve Route - 404", + "originalRequest": { + "method": "GET", + "header": [], + "url": { + "raw": "{{gateway}}/routes/:routeNameOrID", + "host": [ + "{{gateway}}" + ], + "path": [ + "routes", + ":routeNameOrID" + ], + "variable": [ + { + "key": "routeNameOrID", + "value": "my-route", + "description": "The unique identifier or the name of the Route to retrieve." + } + ] + } + }, + "status": "Not Found", + "code": 404, + "_postman_previewlanguage": "Text", + "header": [ + { + "key": "Date", + "value": "Thu, 12 Mar 2020 01:48:17 GMT" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "Server", + "value": "kong/2.0.1" + }, + { + "key": "Content-Length", + "value": "23" + }, + { + "key": "X-Kong-Admin-Latency", + "value": "1" + } + ], + "cookie": [], + "body": "{\n \"message\": \"Not found\"\n}" + }, + { + "name": "Retrieve Route", + "originalRequest": { + "method": "GET", + "header": [], + "url": { + "raw": "{{gateway}}/routes/:routeNameOrID", + "host": [ + "{{gateway}}" + ], + "path": [ + "routes", + ":routeNameOrID" + ], + "variable": [ + { + "key": "routeNameOrID", + "value": "my-route", + "description": "The unique identifier or the name of the Route to retrieve." + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "Text", + "header": [ + { + "key": "Date", + "value": "Thu, 12 Mar 2020 01:55:07 GMT" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "Server", + "value": "kong/2.0.1" + }, + { + "key": "Content-Length", + "value": "546" + }, + { + "key": "X-Kong-Admin-Latency", + "value": "1" + } + ], + "cookie": [], + "body": "{\n \"id\": \"875973fd-ba3f-4c7b-8301-e9263013e6d2\",\n \"path_handling\": \"v0\",\n \"paths\": [\n \"/foo\",\n \"/bar\"\n ],\n \"destinations\": null,\n \"headers\": {\n \"x-another-header\": [\n \"bla\"\n ],\n \"x-my-header\": [\n \"foo\",\n \"bar\"\n ]\n },\n \"protocols\": [\n \"http\",\n \"https\"\n ],\n \"methods\": [\n \"GET\",\n \"POST\"\n ],\n \"snis\": null,\n \"service\": {\n \"id\": \"c8b8f724-7e73-4df6-b1a8-8df19642d388\"\n },\n \"name\": \"my-route\",\n \"strip_path\": true,\n \"preserve_host\": false,\n \"regex_priority\": 0,\n \"updated_at\": 1583977879,\n \"sources\": null,\n \"hosts\": [\n \"example.com\",\n \"foo.test\"\n ],\n \"https_redirect_status_code\": 426,\n \"tags\": [\n \"user-level\",\n \"low-priority\"\n ],\n \"created_at\": 1583977879\n}" + }, + { + "name": "Retrieve Route", + "originalRequest": { + "method": "GET", + "header": [], + "url": { + "raw": "{{gateway}}/routes/:routeNameOrID", + "host": [ + "{{gateway}}" + ], + "path": [ + "routes", + ":routeNameOrID" + ], + "variable": [ + { + "key": "routeNameOrID", + "value": "my-route", + "description": "The unique identifier or the name of the Route to retrieve." + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "Text", + "header": [ + { + "key": "Date", + "value": "Thu, 12 Mar 2020 01:46:14 GMT" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "Server", + "value": "kong/2.0.1" + }, + { + "key": "Content-Length", + "value": "23" + }, + { + "key": "X-Kong-Admin-Latency", + "value": "2" + } + ], + "cookie": [], + "body": "{\n \"id\": \"d35165e2-d03e-461a-bdeb-dad0a112abfe\",\n \"created_at\": 1422386534,\n \"updated_at\": 1422386534,\n \"name\": \"my-route\",\n \"protocols\": [\n \"http\",\n \"https\"\n ],\n \"methods\": [\n \"GET\",\n \"POST\"\n ],\n \"hosts\": [\n \"example.com\",\n \"foo.test\"\n ],\n \"paths\": [\n \"/foo\",\n \"/bar\"\n ],\n \"headers\": {\n \"x-another-header\": [\n \"bla\"\n ],\n \"x-my-header\": [\n \"foo\",\n \"bar\"\n ]\n },\n \"https_redirect_status_code\": 426,\n \"regex_priority\": 0,\n \"strip_path\": true,\n \"path_handling\": \"v0\",\n \"preserve_host\": false,\n \"tags\": [\n \"user-level\",\n \"low-priority\"\n ],\n \"service\": {\n \"id\": \"af8330d3-dbdc-48bd-b1be-55b98608834b\"\n },\n \"destinations\": \"anim id esse\",\n \"snis\": \"in magna\",\n \"sources\": \"aliquip anim\"\n}" + } + ] + } + ], + "description": "https://docs.konghq.com/2.0.x/admin-api/#retrieve-route", + "event": [ + { + "listen": "prerequest", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + }, + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + } + ] + }, + { + "name": "Update Route", + "item": [ + { + "name": "Update Route", + "request": { + "method": "PATCH", + "header": [ + { + "name": "Content-Type", + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"host\": \"httpbin.org\",\n\t\"name\": \"httpbin-api\",\n\t\"retries\": 5,\n\t\"protocol\": \"https\",\n\t\"port\": 443,\n\t\"path\": \"/\",\n\t\"connect_timeout\": 60000,\n\t\"write_timeout\": 60000,\n\t\"read_timeout\": 60000,\n\t\"tags\": null,\n\t\"client_certificate\": null\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{gateway}}/routes/:routeNameOrId", + "host": [ + "{{gateway}}" + ], + "path": [ + "routes", + ":routeNameOrId" + ], + "variable": [ + { + "key": "routeNameOrId", + "value": "", + "description": "The unique identifier or the name of the Route to update." + } + ] + }, + "description": "## Update Service [konghq](https://docs.konghq.com/2.0.x/admin-api/#update-route-1)\n\n \n \n \n \n \n \n \n \n \n \n \n \n
AttributesMandatoryTypeDescription
route name or idrequiredpathThe unique identifier or the name of the Route to update.
\n\n## Request Body\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
AttributesMandatoryDescription
nameoptionalThe Service name
protocolsrequiredA list of the protocols this Route should allow. When set to [\"https\"], HTTP requests are answered with a request to upgrade to HTTPS. Defaults to [\"http\", \"https\"].
methodssemi-optionalA list of HTTP methods that match this Route.
hostssemi-optionalA list of domain names that match this Route. With form-encoded, the notation is hosts[]=example.com&hosts[]=foo.test. With JSON, use an Array.
pathssemi-optionalA list of paths that match this Route. With form-encoded, the notation is paths[]=/foo&paths[]=/bar. With JSON, use an Array.
headerssemi-optionalOne or more lists of values indexed by header name that will cause this Route to match if present in the request. The Host header cannot be used with this attribute: hosts should be specified using the hosts attribute.
https_redirect_status_coderequiredThe status code Kong responds with when all properties of a Route match except the protocol i.e. if the protocol of the request is HTTP instead of HTTPS. Location header is injected by Kong if the field is set to 301, 302, 307 or 308. Accepted values are: 426, 301, 302, 307, 308. Defaults to 426.
regex_priorityoptionalA number used to choose which route resolves a given request when several routes match it using regexes simultaneously. When two routes match the path and have the same regex_priority, the older one (lowest created_at) is used. Note that the priority for non-regex routes is different (longer non-regex routes are matched before shorter ones). Defaults to 0.
strip_pathoptionalWhen matching a Route via one of the paths, strip the matching prefix from the upstream request URL. Defaults to true.
path_handlingoptionalControls how the Service path, Route path and requested path are combined when sending a request to the upstream. See above for a detailed description of each behavior. Accepted values are: \"v0\", \"v1\". Defaults to \"v0\".
preserve_hostoptionalWhen matching a Route via one of the hosts domain names, use the request Host header in the upstream request headers. If set to false, the upstream Host header will be that of the Service’s host.
preserve_hostoptionalWhen matching a Route via one of the hosts domain names, use the request Host header in the upstream request headers. If set to false, the upstream Host header will be that of the Service’s host.
snissemi-optionalA list of SNIs that match this Route when using stream routing.
sourcessemi-optionalA list of IP sources of incoming connections that match this Route when using stream routing. Each entry is an object with fields “ip” (optionally in CIDR range notation) and/or “port”.
destinationssemi-optionalA list of IP destinations of incoming connections that match this Route when using stream routing. Each entry is an object with fields “ip” (optionally in CIDR range notation) and/or “port”.
tagsoptionalAn optional set of strings associated with the Route, for grouping and filtering.
serviceoptionalThe Service this Route is associated to. This is where the Route proxies traffic to. With form-encoded, the notation is service.id= or service.name=. With JSON, use “\"service\":{\"id\":\"\"} or \"service\":{\"name\":\"\"}.
" + }, + "response": [ + { + "name": "Update Service", + "originalRequest": { + "method": "PUT", + "header": [ + { + "name": "Content-Type", + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"host\": \"httpbin.org\",\n\t\"name\": \"httpbin-api\",\n\t\"retries\": 5,\n\t\"protocol\": \"https\",\n\t\"port\": 443,\n\t\"path\": \"/\",\n\t\"connect_timeout\": 60000,\n\t\"write_timeout\": 60000,\n\t\"read_timeout\": 60000,\n\t\"tags\": null,\n\t\"client_certificate\": null\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{gateway}}/services/:serviceNameOrId", + "host": [ + "{{gateway}}" + ], + "path": [ + "services", + ":serviceNameOrId" + ], + "variable": [ + { + "key": "serviceNameOrId", + "value": "httpbin-api" + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "Text", + "header": [ + { + "key": "Date", + "value": "Sun, 08 Mar 2020 01:25:47 GMT" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "Server", + "value": "kong/2.0.1" + }, + { + "key": "Content-Length", + "value": "294" + }, + { + "key": "X-Kong-Admin-Latency", + "value": "11" + } + ], + "cookie": [], + "body": "{\r\n \"host\": \"httpbin.org\",\r\n \"created_at\": 1583630747,\r\n \"connect_timeout\": 60000,\r\n \"id\": \"c8b8f724-7e73-4df6-b1a8-8df19642d388\",\r\n \"protocol\": \"https\",\r\n \"name\": \"httpbin-api\",\r\n \"read_timeout\": 60000,\r\n \"port\": 443,\r\n \"path\": \"/\",\r\n \"updated_at\": 1583630747,\r\n \"retries\": 5,\r\n \"write_timeout\": 60000,\r\n \"tags\": null,\r\n \"client_certificate\": null\r\n}" + }, + { + "name": "Update Service_Error", + "originalRequest": { + "method": "PUT", + "header": [ + { + "name": "Content-Type", + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"name\": \"httpbin-api\",\n\t\"retries\": 5,\n\t\"protocol\": \"https\",\n\t\"host\": \"httpbin.org\",\n\t\"port\": 443,\n\t\"path\": \"/\",\n\t\"connect_timeout\": 60000,\n\t\"write_timeout\": 60000,\n\t\"read_timeout\": 60000,\n\t\"tags\": null,\n\t\"client_certificate\": null,\n\t\"url\": null\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{gateway}}/services/:serviceNameOrId", + "host": [ + "{{gateway}}" + ], + "path": [ + "services", + ":serviceNameOrId" + ], + "variable": [ + { + "key": "serviceNameOrId", + "value": "httpbin-api" + } + ] + } + }, + "status": "Bad Request", + "code": 400, + "_postman_previewlanguage": "Text", + "header": [ + { + "key": "Date", + "value": "Sun, 08 Mar 2020 01:20:52 GMT" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "Server", + "value": "kong/2.0.1" + }, + { + "key": "Content-Length", + "value": "330" + }, + { + "key": "X-Kong-Admin-Latency", + "value": "1" + } + ], + "cookie": [], + "body": "{\n \"message\": \"3 schema violations (host: required field missing; path: should start with: /; protocol: expected one of: grpc, grpcs, http, https, tcp, tls)\",\n \"name\": \"schema violation\",\n \"fields\": {\n \"host\": \"required field missing\",\n \"path\": \"should start with: /\",\n \"protocol\": \"expected one of: grpc, grpcs, http, https, tcp, tls\"\n },\n \"code\": 2\n}" + } + ] + }, + { + "name": "Update Service Associated to a Specific Certificate", + "request": { + "method": "PATCH", + "header": [ + { + "name": "Content-Type", + "key": "Content-Type", + "value": "application/json" + } + ], + "url": { + "raw": "{{gateway}}/certificates/:certificateId/services/:serviceNameOrId", + "host": [ + "{{gateway}}" + ], + "path": [ + "certificates", + ":certificateId", + "services", + ":serviceNameOrId" + ], + "variable": [ + { + "key": "certificateId" + }, + { + "key": "serviceNameOrId" + } + ] + }, + "description": "## Update Service [konghq](https://docs.konghq.com/2.0.x/admin-api/#update-service-associated-to-a-specific-certificate)\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
AttributesMandatoryTypeDescription
certificate idrequiredpathThe unique identifier of the Certificate to update
service name or idrequiredpathThe unique identifier or the name of the Service to update.
\n\n## Request Body\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
AttributesMandatoryDescription
nameoptionalThe Service name
retriesoptionalThe number of retries to execute upon failure to proxy. Defaults to 5
protocolrequiredThe protocol used to communicate with the upstream. Accepted values are: \"grpc\", \"grpcs\", \"http\", \"https\", \"tcp\", \"tls\". Defaults to \"http\"
hostrequiredThe host of the upstream server
portrequiredThe upstream server port. Defaults to 80
pathoptionalThe path to be used in requests to the upstream server.
connect_timeoutoptionalThe timeout in milliseconds for establishing a connection to the upstream server. Defaults to 60000.
write_timeoutoptionalThe timeout in milliseconds between two successive write operations for transmitting a request to the upstream server. Defaults to 60000.
read_timeoutoptionalThe timeout in milliseconds between two successive read operations for transmitting a request to the upstream server. Defaults to 60000.
tagsoptionalAn optional set of strings associated with the Service, for grouping and filtering.
client_certificateoptionalCertificate to be used as client certificate while TLS handshaking to the upstream server. With form-encoded, the notation is client_certificate.id=. With JSON, use “\"client_certificate\":{\"id\":\"\"}.
urlrequiredShorthand attribute to set protocol, host, port and path at once. This attribute is write-only (the Admin API never “returns” the url).
" + }, + "response": [] + }, + { + "name": "Update Service Associated to a Specific Route", + "request": { + "method": "PATCH", + "header": [ + { + "name": "Content-Type", + "key": "Content-Type", + "value": "application/json" + } + ], + "url": { + "raw": "{{gateway}}/routes/:routeNameOrId/service", + "host": [ + "{{gateway}}" + ], + "path": [ + "routes", + ":routeNameOrId", + "service" + ], + "variable": [ + { + "key": "routeNameOrId" + } + ] + }, + "description": "## Update Service Associated to a Specific Route [konghq](https://docs.konghq.com/2.0.x/admin-api/#update-service-associated-to-a-specific-route)\n\n \n \n \n \n \n \n \n \n \n \n \n \n
AttributesMandatoryTypeDescription
route name or idrequiredpathThe unique identifier or the name of the Route associated to the Service to be updated
\n\n## Request Body\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
AttributesMandatoryDescription
nameoptionalThe Service name
retriesoptionalThe number of retries to execute upon failure to proxy. Defaults to 5
protocolrequiredThe protocol used to communicate with the upstream. Accepted values are: \"grpc\", \"grpcs\", \"http\", \"https\", \"tcp\", \"tls\". Defaults to \"http\"
hostrequiredThe host of the upstream server
portrequiredThe upstream server port. Defaults to 80
pathoptionalThe path to be used in requests to the upstream server.
connect_timeoutoptionalThe timeout in milliseconds for establishing a connection to the upstream server. Defaults to 60000.
write_timeoutoptionalThe timeout in milliseconds between two successive write operations for transmitting a request to the upstream server. Defaults to 60000.
read_timeoutoptionalThe timeout in milliseconds between two successive read operations for transmitting a request to the upstream server. Defaults to 60000.
tagsoptionalAn optional set of strings associated with the Service, for grouping and filtering.
client_certificateoptionalCertificate to be used as client certificate while TLS handshaking to the upstream server. With form-encoded, the notation is client_certificate.id=. With JSON, use “\"client_certificate\":{\"id\":\"\"}.
urlrequiredShorthand attribute to set protocol, host, port and path at once. This attribute is write-only (the Admin API never “returns” the url).
" + }, + "response": [] + }, + { + "name": "Update Service Associated to a Specific Plugin", + "request": { + "method": "PATCH", + "header": [ + { + "name": "Content-Type", + "key": "Content-Type", + "value": "application/json" + } + ], + "url": { + "raw": "{{gateway}}/plugins/:pluginId/service", + "host": [ + "{{gateway}}" + ], + "path": [ + "plugins", + ":pluginId", + "service" + ], + "variable": [ + { + "key": "pluginId" + } + ] + }, + "description": "## Update Service Associated to a Specific Plugin [konghq](https://docs.konghq.com/2.0.x/admin-api/#update-service-associated-to-a-specific-plugin)\n\n \n \n \n \n \n \n \n \n \n \n \n \n
AttributesMandatoryTypeDescription
plugin idrequiredpathThe unique identifier of the Plugin associated to the Service to be updated
\n\n## Request Body\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
AttributesMandatoryDescription
nameoptionalThe Service name
retriesoptionalThe number of retries to execute upon failure to proxy. Defaults to 5
protocolrequiredThe protocol used to communicate with the upstream. Accepted values are: \"grpc\", \"grpcs\", \"http\", \"https\", \"tcp\", \"tls\". Defaults to \"http\"
hostrequiredThe host of the upstream server
portrequiredThe upstream server port. Defaults to 80
pathoptionalThe path to be used in requests to the upstream server.
connect_timeoutoptionalThe timeout in milliseconds for establishing a connection to the upstream server. Defaults to 60000.
write_timeoutoptionalThe timeout in milliseconds between two successive write operations for transmitting a request to the upstream server. Defaults to 60000.
read_timeoutoptionalThe timeout in milliseconds between two successive read operations for transmitting a request to the upstream server. Defaults to 60000.
tagsoptionalAn optional set of strings associated with the Service, for grouping and filtering.
client_certificateoptionalCertificate to be used as client certificate while TLS handshaking to the upstream server. With form-encoded, the notation is client_certificate.id=. With JSON, use “\"client_certificate\":{\"id\":\"\"}.
urlrequiredShorthand attribute to set protocol, host, port and path at once. This attribute is write-only (the Admin API never “returns” the url).
" + }, + "response": [] + } + ], + "description": "https://docs.konghq.com/2.0.x/admin-api/#update-route", + "event": [ + { + "listen": "prerequest", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + }, + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + } + ] + }, + { + "name": "Update Or Create Route", + "item": [ + { + "name": "Create Or Update Route", + "request": { + "method": "PUT", + "header": [ + { + "name": "Content-Type", + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"host\": \"httpbin.org\",\n\t\"name\": \"httpbin-api\",\n\t\"retries\": 5,\n\t\"protocol\": \"https\",\n\t\"port\": 443,\n\t\"path\": \"/\",\n\t\"connect_timeout\": 60000,\n\t\"write_timeout\": 60000,\n\t\"read_timeout\": 60000,\n\t\"tags\": null,\n\t\"client_certificate\": null\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{gateway}}/routes/:routeNameOrId", + "host": [ + "{{gateway}}" + ], + "path": [ + "routes", + ":routeNameOrId" + ], + "variable": [ + { + "key": "routeNameOrId", + "value": "", + "description": "The unique identifier or the name of the Route to update." + } + ] + }, + "description": "## Create Or Update Route [konghq](https://docs.konghq.com/2.0.x/admin-api/#create-or-update-route)\n\n* Inserts (or replaces) the Route under the requested resource with the definition specified in the body. The Route will be identified via the name or id attribute.\n* When the name or id attribute has the structure of a UUID, the Route being inserted/replaced will be identified by its id. Otherwise it will be identified by its name.\n* When creating a new Route without specifying id (neither in the URL nor in the body), then it will be auto-generated.\n*Notice that specifying a name in the URL and a different one in the request body is not allowed.\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n
AttributesMandatoryTypeDescription
route name or idrequiredpathThe unique identifier or the name of the Route to create or update.
\n\n## Request Body\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
AttributesMandatoryDescription
nameoptionalThe Route name
protocolsrequiredA list of the protocols this Route should allow. When set to [\"https\"], HTTP requests are answered with a request to upgrade to HTTPS. Defaults to [\"http\", \"https\"].
methodssemi-optionalA list of HTTP methods that match this Route.
hostssemi-optionalA list of domain names that match this Route. With form-encoded, the notation is hosts[]=example.com&hosts[]=foo.test. With JSON, use an Array.
pathssemi-optionalA list of paths that match this Route. With form-encoded, the notation is paths[]=/foo&paths[]=/bar. With JSON, use an Array.
headerssemi-optionalOne or more lists of values indexed by header name that will cause this Route to match if present in the request. The Host header cannot be used with this attribute: hosts should be specified using the hosts attribute.
https_redirect_status_coderequiredThe status code Kong responds with when all properties of a Route match except the protocol i.e. if the protocol of the request is HTTP instead of HTTPS. Location header is injected by Kong if the field is set to 301, 302, 307 or 308. Accepted values are: 426, 301, 302, 307, 308. Defaults to 426.
regex_priorityoptionalA number used to choose which route resolves a given request when several routes match it using regexes simultaneously. When two routes match the path and have the same regex_priority, the older one (lowest created_at) is used. Note that the priority for non-regex routes is different (longer non-regex routes are matched before shorter ones). Defaults to 0.
strip_pathoptionalWhen matching a Route via one of the paths, strip the matching prefix from the upstream request URL. Defaults to true.
path_handlingoptionalControls how the Service path, Route path and requested path are combined when sending a request to the upstream. See above for a detailed description of each behavior. Accepted values are: \"v0\", \"v1\". Defaults to \"v0\".
preserve_hostoptionalWhen matching a Route via one of the hosts domain names, use the request Host header in the upstream request headers. If set to false, the upstream Host header will be that of the Service’s host.
preserve_hostoptionalWhen matching a Route via one of the hosts domain names, use the request Host header in the upstream request headers. If set to false, the upstream Host header will be that of the Service’s host.
snissemi-optionalA list of SNIs that match this Route when using stream routing.
sourcessemi-optionalA list of IP sources of incoming connections that match this Route when using stream routing. Each entry is an object with fields “ip” (optionally in CIDR range notation) and/or “port”.
destinationssemi-optionalA list of IP destinations of incoming connections that match this Route when using stream routing. Each entry is an object with fields “ip” (optionally in CIDR range notation) and/or “port”.
tagsoptionalAn optional set of strings associated with the Route, for grouping and filtering.
serviceoptionalThe Service this Route is associated to. This is where the Route proxies traffic to. With form-encoded, the notation is service.id= or service.name=. With JSON, use “\"service\":{\"id\":\"\"} or \"service\":{\"name\":\"\"}.
\n\n## Response\n* HTTP 201 Created or HTTP 200 OK\n* See POST and PATCH responses." + }, + "response": [] + }, + { + "name": "Create Or Update Route Associated to a Specific Service", + "request": { + "method": "PUT", + "header": [ + { + "name": "Content-Type", + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"host\": \"httpbin.org\",\n\t\"name\": \"httpbin-api\",\n\t\"retries\": 5,\n\t\"protocol\": \"https\",\n\t\"port\": 443,\n\t\"path\": \"/\",\n\t\"connect_timeout\": 60000,\n\t\"write_timeout\": 60000,\n\t\"read_timeout\": 60000,\n\t\"tags\": null,\n\t\"client_certificate\": null\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{gateway}}/services/:serviceNameOrId/routes/:routeNameOrId", + "host": [ + "{{gateway}}" + ], + "path": [ + "services", + ":serviceNameOrId", + "routes", + ":routeNameOrId" + ], + "variable": [ + { + "key": "serviceNameOrId", + "value": "", + "description": "The unique identifier or the name of the Service to create or update." + }, + { + "key": "routeNameOrId", + "value": "", + "description": "The unique identifier or the name of the Route to create or update." + } + ] + }, + "description": "## Create Or Update Route Associated to a Specific Service [konghq](https://docs.konghq.com/2.0.x/admin-api/#create-or-update-route-associated-to-a-specific-service)\n\n* Inserts (or replaces) the Route under the requested resource with the definition specified in the body. The Route will be identified via the name or id attribute.\n* When the name or id attribute has the structure of a UUID, the Route being inserted/replaced will be identified by its id. Otherwise it will be identified by its name.\n* When creating a new Route without specifying id (neither in the URL nor in the body), then it will be auto-generated.\n*Notice that specifying a name in the URL and a different one in the request body is not allowed.\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
AttributesMandatoryTypeDescription
service name or idrequiredpathThe unique identifier or the name of the Service to create or update.
route name or idrequiredpathThe unique identifier or the name of the Route to create or update.
\n\n## Request Body\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
AttributesMandatoryDescription
nameoptionalThe Route name
protocolsrequiredA list of the protocols this Route should allow. When set to [\"https\"], HTTP requests are answered with a request to upgrade to HTTPS. Defaults to [\"http\", \"https\"].
methodssemi-optionalA list of HTTP methods that match this Route.
hostssemi-optionalA list of domain names that match this Route. With form-encoded, the notation is hosts[]=example.com&hosts[]=foo.test. With JSON, use an Array.
pathssemi-optionalA list of paths that match this Route. With form-encoded, the notation is paths[]=/foo&paths[]=/bar. With JSON, use an Array.
headerssemi-optionalOne or more lists of values indexed by header name that will cause this Route to match if present in the request. The Host header cannot be used with this attribute: hosts should be specified using the hosts attribute.
https_redirect_status_coderequiredThe status code Kong responds with when all properties of a Route match except the protocol i.e. if the protocol of the request is HTTP instead of HTTPS. Location header is injected by Kong if the field is set to 301, 302, 307 or 308. Accepted values are: 426, 301, 302, 307, 308. Defaults to 426.
regex_priorityoptionalA number used to choose which route resolves a given request when several routes match it using regexes simultaneously. When two routes match the path and have the same regex_priority, the older one (lowest created_at) is used. Note that the priority for non-regex routes is different (longer non-regex routes are matched before shorter ones). Defaults to 0.
strip_pathoptionalWhen matching a Route via one of the paths, strip the matching prefix from the upstream request URL. Defaults to true.
path_handlingoptionalControls how the Service path, Route path and requested path are combined when sending a request to the upstream. See above for a detailed description of each behavior. Accepted values are: \"v0\", \"v1\". Defaults to \"v0\".
preserve_hostoptionalWhen matching a Route via one of the hosts domain names, use the request Host header in the upstream request headers. If set to false, the upstream Host header will be that of the Service’s host.
preserve_hostoptionalWhen matching a Route via one of the hosts domain names, use the request Host header in the upstream request headers. If set to false, the upstream Host header will be that of the Service’s host.
snissemi-optionalA list of SNIs that match this Route when using stream routing.
sourcessemi-optionalA list of IP sources of incoming connections that match this Route when using stream routing. Each entry is an object with fields “ip” (optionally in CIDR range notation) and/or “port”.
destinationssemi-optionalA list of IP destinations of incoming connections that match this Route when using stream routing. Each entry is an object with fields “ip” (optionally in CIDR range notation) and/or “port”.
tagsoptionalAn optional set of strings associated with the Route, for grouping and filtering.
serviceoptionalThe Service this Route is associated to. This is where the Route proxies traffic to. With form-encoded, the notation is service.id= or service.name=. With JSON, use “\"service\":{\"id\":\"\"} or \"service\":{\"name\":\"\"}.
\n\n## Response\n* HTTP 201 Created or HTTP 200 OK\n* See POST and PATCH responses." + }, + "response": [] + }, + { + "name": "Create Or Update Route Associated to a Specific Plugin", + "request": { + "method": "PUT", + "header": [ + { + "name": "Content-Type", + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"host\": \"httpbin.org\",\n\t\"name\": \"httpbin-api\",\n\t\"retries\": 5,\n\t\"protocol\": \"https\",\n\t\"port\": 443,\n\t\"path\": \"/\",\n\t\"connect_timeout\": 60000,\n\t\"write_timeout\": 60000,\n\t\"read_timeout\": 60000,\n\t\"tags\": null,\n\t\"client_certificate\": null\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{gateway}}/plugins/:pluginId/route", + "host": [ + "{{gateway}}" + ], + "path": [ + "plugins", + ":pluginId", + "route" + ], + "variable": [ + { + "key": "pluginId", + "value": "", + "description": "The unique identifier of the Plugin associated to the Route to be created or updated." + } + ] + }, + "description": "## Create Or Update Route Associated to a Specific Plugin [konghq](https://docs.konghq.com/2.0.x/admin-api/#create-or-update-route-associated-to-a-specific-plugin)\n\n* Inserts (or replaces) the Route under the requested resource with the definition specified in the body. The Route will be identified via the name or id attribute.\n* When the name or id attribute has the structure of a UUID, the Route being inserted/replaced will be identified by its id. Otherwise it will be identified by its name.\n* When creating a new Route without specifying id (neither in the URL nor in the body), then it will be auto-generated.\n*Notice that specifying a name in the URL and a different one in the request body is not allowed.\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n
AttributesMandatoryTypeDescription
plugin idrequiredpathThe unique identifier of the Plugin associated to the Route to be created or updated.
\n\n## Request Body\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
AttributesMandatoryDescription
nameoptionalThe Route name
protocolsrequiredA list of the protocols this Route should allow. When set to [\"https\"], HTTP requests are answered with a request to upgrade to HTTPS. Defaults to [\"http\", \"https\"].
methodssemi-optionalA list of HTTP methods that match this Route.
hostssemi-optionalA list of domain names that match this Route. With form-encoded, the notation is hosts[]=example.com&hosts[]=foo.test. With JSON, use an Array.
pathssemi-optionalA list of paths that match this Route. With form-encoded, the notation is paths[]=/foo&paths[]=/bar. With JSON, use an Array.
headerssemi-optionalOne or more lists of values indexed by header name that will cause this Route to match if present in the request. The Host header cannot be used with this attribute: hosts should be specified using the hosts attribute.
https_redirect_status_coderequiredThe status code Kong responds with when all properties of a Route match except the protocol i.e. if the protocol of the request is HTTP instead of HTTPS. Location header is injected by Kong if the field is set to 301, 302, 307 or 308. Accepted values are: 426, 301, 302, 307, 308. Defaults to 426.
regex_priorityoptionalA number used to choose which route resolves a given request when several routes match it using regexes simultaneously. When two routes match the path and have the same regex_priority, the older one (lowest created_at) is used. Note that the priority for non-regex routes is different (longer non-regex routes are matched before shorter ones). Defaults to 0.
strip_pathoptionalWhen matching a Route via one of the paths, strip the matching prefix from the upstream request URL. Defaults to true.
path_handlingoptionalControls how the Service path, Route path and requested path are combined when sending a request to the upstream. See above for a detailed description of each behavior. Accepted values are: \"v0\", \"v1\". Defaults to \"v0\".
preserve_hostoptionalWhen matching a Route via one of the hosts domain names, use the request Host header in the upstream request headers. If set to false, the upstream Host header will be that of the Service’s host.
preserve_hostoptionalWhen matching a Route via one of the hosts domain names, use the request Host header in the upstream request headers. If set to false, the upstream Host header will be that of the Service’s host.
snissemi-optionalA list of SNIs that match this Route when using stream routing.
sourcessemi-optionalA list of IP sources of incoming connections that match this Route when using stream routing. Each entry is an object with fields “ip” (optionally in CIDR range notation) and/or “port”.
destinationssemi-optionalA list of IP destinations of incoming connections that match this Route when using stream routing. Each entry is an object with fields “ip” (optionally in CIDR range notation) and/or “port”.
tagsoptionalAn optional set of strings associated with the Route, for grouping and filtering.
serviceoptionalThe Service this Route is associated to. This is where the Route proxies traffic to. With form-encoded, the notation is service.id= or service.name=. With JSON, use “\"service\":{\"id\":\"\"} or \"service\":{\"name\":\"\"}.
\n\n## Response\n* HTTP 201 Created or HTTP 200 OK\n* See POST and PATCH responses." + }, + "response": [] + } + ], + "description": "https://docs.konghq.com/2.0.x/admin-api/#update-or-create-route", + "event": [ + { + "listen": "prerequest", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + }, + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + } + ] + }, + { + "name": "Delete Route", + "item": [ + { + "name": "Delete Route", + "request": { + "method": "DELETE", + "header": [], + "url": { + "raw": "{{gateway}}/routes/:routeNameOrId", + "host": [ + "{{gateway}}" + ], + "path": [ + "routes", + ":routeNameOrId" + ], + "variable": [ + { + "key": "routeNameOrId", + "value": "", + "description": "The unique identifier or the name of the Route to delete." + } + ] + }, + "description": "## Delete Route [konghq](https://docs.konghq.com/2.0.x/admin-api/#delete-route-1)\n\n \n \n \n \n \n \n \n \n \n \n \n \n
AttributesMandatoryTypeDescription
Route name or idrequiredpathThe unique identifier or the name of the Route to delete.
" + }, + "response": [ + { + "name": "Delete Route - 204", + "originalRequest": { + "method": "DELETE", + "header": [], + "url": { + "raw": "{{gateway}}/routes/:routeNameOrId", + "host": [ + "{{gateway}}" + ], + "path": [ + "routes", + ":routeNameOrId" + ], + "variable": [ + { + "key": "routeNameOrId", + "value": "my-route", + "description": "The unique identifier or the name of the Route to delete." + } + ] + } + }, + "status": "No Content", + "code": 204, + "_postman_previewlanguage": "Text", + "header": [ + { + "key": "Date", + "value": "Fri, 13 Mar 2020 01:56:42 GMT" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "Server", + "value": "kong/2.0.1" + }, + { + "key": "X-Kong-Admin-Latency", + "value": "18" + } + ], + "cookie": [], + "body": "" + } + ] + }, + { + "name": "Delete Route Associated to a Specific Service", + "request": { + "method": "DELETE", + "header": [], + "url": { + "raw": "{{gateway}}/services/:serviceNameOrId/routes/:routeNameOrId", + "host": [ + "{{gateway}}" + ], + "path": [ + "services", + ":serviceNameOrId", + "routes", + ":routeNameOrId" + ], + "variable": [ + { + "key": "serviceNameOrId", + "value": "", + "description": "The unique identifier or the name of the Service to delete." + }, + { + "key": "routeNameOrId", + "value": "", + "description": "The unique identifier or the name of the Route to delete." + } + ] + }, + "description": "## Delete Service Associated to a Specific Certificate [konghq](https://docs.konghq.com/2.0.x/admin-api/#delete-service-associated-to-a-specific-certificate)\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
AttributesMandatoryTypeDescription
service name or idrequiredpathThe unique identifier or the name of the Service to delete.
route name or idrequiredpathThe unique identifier or the name of the Route to delete.
" + }, + "response": [] + } + ], + "description": "https://docs.konghq.com/2.0.x/admin-api/#delete-route", + "event": [ + { + "listen": "prerequest", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + }, + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + } + ] + } + ], + "description": "https://docs.konghq.com/2.0.x/admin-api/#route-object\n\nRoute entities define rules to match client requests. Each Route is associated with a Service, and a Service may have multiple Routes associated to it. Every request matching a given Route will be proxied to its associated Service.\n\nThe combination of Routes and Services (and the separation of concerns between them) offers a powerful routing mechanism with which it is possible to define fine-grained entry-points in Kong leading to different upstream services of your infrastructure.\n\nYou need at least one matching rule that applies to the protocol being matched by the Route. Depending on the protocols configured to be matched by the Route (as defined with the protocols field), this means that at least one of the following attributes must be set:\n\n* For http, at least one of methods, hosts, headers or paths;\n* For https, at least one of methods, hosts, headers, paths or snis;\n* For tcp, at least one of sources or destinations;\n* For tls, at least one of sources, destinations or snis;\n* For grpc, at least one of hosts, headers or paths;\n* For grpcs, at least one of hosts, headers, paths or snis.\n \n## Path handling algorithms https://docs.konghq.com/2.0.x/admin-api/#path-handling-algorithms\n\"v0\" is the behavior used in Kong 0.x and 2.x. It treats service.path, route.path and request path as segments of a url. It will always join them via slashes. Given a service path /s, route path /r and request path /re, the concatenated path will be /s/re. If the resulting path is a single slash, no further transformation is done to it. If it’s longer, then the trailing slash is removed.\n\n\"v1\" is the behavior used in Kong 1.x. It treats service.path as a prefix, and ignores the initial slashes of the request and route paths. Given service path /s, route path /r and request path /re, the concatenated path will be /sre.\n\nBoth versions of the algorithm detect “double slashes” when combining paths, replacing them by single slashes.", + "event": [ + { + "listen": "prerequest", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + }, + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + } + ] + }, + { + "name": "Plugin Object", + "item": [ + { + "name": "Add Plugin", + "item": [ + { + "name": "Create Plugin", + "request": { + "method": "POST", + "header": [ + { + "name": "Content-Type", + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"name\": \"rate-limiting\",\r\n \"route\": null,\r\n \"service\": null,\r\n \"consumer\": null,\r\n \"config\": {\"hour\":500, \"minute\":20},\r\n \"protocols\": [\"grpc\", \"grpcs\"],\r\n \"enabled\": true,\r\n \"tags\": [\"admin\", \"high-priority\", \"critical\"]\r\n}" + }, + "url": { + "raw": "{{gateway}}/plugins", + "host": [ + "{{gateway}}" + ], + "path": [ + "plugins" + ] + }, + "description": "# Create Plugin [konghq](https://docs.konghq.com/2.0.x/admin-api/#create-plugin)\n\n\n# Request Body\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
AttributesMandatoryDescription
namerequiredThe name of the Plugin that’s going to be added. Currently the Plugin must be installed in every Kong instance separately.
routeoptionalIf set, the plugin will only activate when receiving requests via the specified route. Leave unset for the plugin to activate regardless of the Route being used. Defaults to null.With form-encoded, the notation is route.id= or route.name=. With JSON, use “\"route\":{\"id\":\"\"} or \"route\":{\"name\":\"\"}.
serviceoptionalIf set, the plugin will only activate when receiving requests via one of the routes belonging to the specified Service. Leave unset for the plugin to activate regardless of the Service being matched. Defaults to null.With form-encoded, the notation is service.id= or service.name=. With JSON, use “\"service\":{\"id\":\"\"} or \"service\":{\"name\":\"\"}.
consumeroptionalIf set, the plugin will activate only for requests where the specified has been authenticated. (Note that some plugins can not be restricted to consumers this way.). Leave unset for the plugin to activate regardless of the authenticated consumer. Defaults to null.With form-encoded, the notation is consumer.id= or consumer.username=. With JSON, use “\"consumer\":{\"id\":\"\"} or \"consumer\":{\"username\":\"\"}.
configoptionalThe configuration properties for the Plugin which can be found on the plugins documentation page in the Kong Hub.
protocolsrequiredA list of the request protocols that will trigger this plugin. The default value, as well as the possible values allowed on this field, may change depending on the plugin type. For example, plugins that only work in stream mode will only support \"tcp\" and \"tls\". Defaults to [\"grpc\", \"grpcs\", \"http\", \"https\"].
enabledoptionalWhether the plugin is applied. Defaults to true.
tagsoptionalAn optional set of strings associated with the Plugin, for grouping and filtering.
" + }, + "response": [] + }, + { + "name": "Create Plugin Associated to a Specific Route", + "request": { + "method": "POST", + "header": [ + { + "name": "Content-Type", + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"name\": \"rate-limiting\",\r\n \"service\": null,\r\n \"consumer\": null,\r\n \"config\": {\"hour\":500, \"minute\":20},\r\n \"protocols\": [\"https\", \"http\"],\r\n \"enabled\": true,\r\n \"tags\": [\"admin\", \"high-priority\", \"critical\"]\r\n}" + }, + "url": { + "raw": "{{gateway}}/routes/:routeId/plugins", + "host": [ + "{{gateway}}" + ], + "path": [ + "routes", + ":routeId", + "plugins" + ], + "variable": [ + { + "key": "routeId", + "value": "my-route", + "description": "The unique identifier of the Route that should be associated to the newly-created Plugin." + } + ] + }, + "description": "# Create Plugin Associated to a Specific Route [konghq](https://docs.konghq.com/2.0.x/admin-api/#create-plugin-associated-to-a-specific-route)\n\n \n \n \n \n \n \n \n \n \n \n \n \n
AttributesMandatoryTypeDescription
route idrequiredpathThe unique identifier of the Route that should be associated to the newly-created Plugin.
\n\n# Request Body\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
AttributesMandatoryDescription
namerequiredThe name of the Plugin that’s going to be added. Currently the Plugin must be installed in every Kong instance separately.
routeoptionalIf set, the plugin will only activate when receiving requests via the specified route. Leave unset for the plugin to activate regardless of the Route being used. Defaults to null.With form-encoded, the notation is route.id= or route.name=. With JSON, use “\"route\":{\"id\":\"\"} or \"route\":{\"name\":\"\"}.
serviceoptionalIf set, the plugin will only activate when receiving requests via one of the routes belonging to the specified Service. Leave unset for the plugin to activate regardless of the Service being matched. Defaults to null.With form-encoded, the notation is service.id= or service.name=. With JSON, use “\"service\":{\"id\":\"\"} or \"service\":{\"name\":\"\"}.
consumeroptionalIf set, the plugin will activate only for requests where the specified has been authenticated. (Note that some plugins can not be restricted to consumers this way.). Leave unset for the plugin to activate regardless of the authenticated consumer. Defaults to null.With form-encoded, the notation is consumer.id= or consumer.username=. With JSON, use “\"consumer\":{\"id\":\"\"} or \"consumer\":{\"username\":\"\"}.
configoptionalThe configuration properties for the Plugin which can be found on the plugins documentation page in the Kong Hub.
protocolsrequiredA list of the request protocols that will trigger this plugin. The default value, as well as the possible values allowed on this field, may change depending on the plugin type. For example, plugins that only work in stream mode will only support \"tcp\" and \"tls\". Defaults to [\"grpc\", \"grpcs\", \"http\", \"https\"].
enabledoptionalWhether the plugin is applied. Defaults to true.
tagsoptionalAn optional set of strings associated with the Plugin, for grouping and filtering.
" + }, + "response": [ + { + "name": "Create Plugin Associated to a Specific Route", + "originalRequest": { + "method": "POST", + "header": [ + { + "name": "Content-Type", + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"name\": \"rate-limiting\",\r\n \"service\": null,\r\n \"consumer\": null,\r\n \"config\": {\"hour\":500, \"minute\":20},\r\n \"protocols\": [\"https\", \"http\"],\r\n \"enabled\": true,\r\n \"tags\": [\"admin\", \"high-priority\", \"critical\"]\r\n}" + }, + "url": { + "raw": "{{gateway}}/routes/:routeId/plugins", + "host": [ + "{{gateway}}" + ], + "path": [ + "routes", + ":routeId", + "plugins" + ], + "variable": [ + { + "key": "routeId", + "value": "my-route", + "description": "The unique identifier of the Route that should be associated to the newly-created Plugin." + } + ] + } + }, + "status": "Created", + "code": 201, + "_postman_previewlanguage": "Text", + "header": [ + { + "key": "Date", + "value": "Thu, 12 Mar 2020 07:40:23 GMT" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "Server", + "value": "kong/2.0.1" + }, + { + "key": "Content-Length", + "value": "538" + }, + { + "key": "X-Kong-Admin-Latency", + "value": "15" + } + ], + "cookie": [], + "body": "{\n \"created_at\": 1583998823,\n \"config\": {\n \"minute\": 20,\n \"policy\": \"cluster\",\n \"month\": null,\n \"redis_timeout\": 2000,\n \"limit_by\": \"consumer\",\n \"hide_client_headers\": false,\n \"second\": null,\n \"day\": null,\n \"redis_password\": null,\n \"year\": null,\n \"redis_database\": 0,\n \"hour\": 500,\n \"redis_port\": 6379,\n \"redis_host\": null,\n \"fault_tolerant\": true\n },\n \"id\": \"9175fd5b-e364-4759-bbe2-e7d00da5edd2\",\n \"service\": null,\n \"enabled\": true,\n \"protocols\": [\n \"https\",\n \"http\"\n ],\n \"name\": \"rate-limiting\",\n \"consumer\": null,\n \"route\": {\n \"id\": \"875973fd-ba3f-4c7b-8301-e9263013e6d2\"\n },\n \"tags\": [\n \"admin\",\n \"high-priority\",\n \"critical\"\n ]\n}" + } + ] + }, + { + "name": "Create Plugin Associated to a Specific Service", + "request": { + "method": "POST", + "header": [ + { + "name": "Content-Type", + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"name\": \"rate-limiting\",\r\n \"service\": null,\r\n \"consumer\": null,\r\n \"config\": {\"hour\":500, \"minute\":20},\r\n \"protocols\": [\"https\", \"http\"],\r\n \"enabled\": true,\r\n \"tags\": [\"admin\", \"high-priority\", \"critical\"]\r\n}" + }, + "url": { + "raw": "{{gateway}}/services/:serviceId/plugins", + "host": [ + "{{gateway}}" + ], + "path": [ + "services", + ":serviceId", + "plugins" + ], + "variable": [ + { + "key": "serviceId", + "value": "", + "description": "The unique identifier of the Service that should be associated to the newly-created Plugin." + } + ] + }, + "description": "# Create Plugin Associated to a Specific Service [konghq](https://docs.konghq.com/2.0.x/admin-api/#create-plugin-associated-to-a-specific-service)\n\n \n \n \n \n \n \n \n \n \n \n \n \n
AttributesMandatoryTypeDescription
service idrequiredpathThe unique identifier of the Service that should be associated to the newly-created Plugin.
\n\n# Request Body\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
AttributesMandatoryDescription
namerequiredThe name of the Plugin that’s going to be added. Currently the Plugin must be installed in every Kong instance separately.
routeoptionalIf set, the plugin will only activate when receiving requests via the specified route. Leave unset for the plugin to activate regardless of the Route being used. Defaults to null.With form-encoded, the notation is route.id= or route.name=. With JSON, use “\"route\":{\"id\":\"\"} or \"route\":{\"name\":\"\"}.
serviceoptionalIf set, the plugin will only activate when receiving requests via one of the routes belonging to the specified Service. Leave unset for the plugin to activate regardless of the Service being matched. Defaults to null.With form-encoded, the notation is service.id= or service.name=. With JSON, use “\"service\":{\"id\":\"\"} or \"service\":{\"name\":\"\"}.
consumeroptionalIf set, the plugin will activate only for requests where the specified has been authenticated. (Note that some plugins can not be restricted to consumers this way.). Leave unset for the plugin to activate regardless of the authenticated consumer. Defaults to null.With form-encoded, the notation is consumer.id= or consumer.username=. With JSON, use “\"consumer\":{\"id\":\"\"} or \"consumer\":{\"username\":\"\"}.
configoptionalThe configuration properties for the Plugin which can be found on the plugins documentation page in the Kong Hub.
protocolsrequiredA list of the request protocols that will trigger this plugin. The default value, as well as the possible values allowed on this field, may change depending on the plugin type. For example, plugins that only work in stream mode will only support \"tcp\" and \"tls\". Defaults to [\"grpc\", \"grpcs\", \"http\", \"https\"].
enabledoptionalWhether the plugin is applied. Defaults to true.
tagsoptionalAn optional set of strings associated with the Plugin, for grouping and filtering.
" + }, + "response": [] + }, + { + "name": "Create Plugin Associated to a Specific Service", + "request": { + "method": "POST", + "header": [ + { + "name": "Content-Type", + "key": "Content-Type", + "value": "application/json" + } + ], + "url": { + "raw": "{{gateway}}/services/:consumerId/plugins", + "host": [ + "{{gateway}}" + ], + "path": [ + "services", + ":consumerId", + "plugins" + ], + "variable": [ + { + "key": "consumerId" + } + ] + }, + "description": "# Create Plugin Associated to a Specific Service [konghq](https://docs.konghq.com/2.0.x/admin-api/#create-plugin-associated-to-a-specific-service)\n\n \n \n \n \n \n \n \n \n \n \n \n \n
AttributesMandatoryTypeDescription
service idrequiredpathThe unique identifier of the Service that should be associated to the newly-created Plugin.
\n\n# Request Body\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
AttributesMandatoryDescription
namerequiredThe name of the Plugin that’s going to be added. Currently the Plugin must be installed in every Kong instance separately.
routeoptionalIf set, the plugin will only activate when receiving requests via the specified route. Leave unset for the plugin to activate regardless of the Route being used. Defaults to null.With form-encoded, the notation is route.id= or route.name=. With JSON, use “\"route\":{\"id\":\"\"} or \"route\":{\"name\":\"\"}.
serviceoptionalIf set, the plugin will only activate when receiving requests via one of the routes belonging to the specified Service. Leave unset for the plugin to activate regardless of the Service being matched. Defaults to null.With form-encoded, the notation is service.id= or service.name=. With JSON, use “\"service\":{\"id\":\"\"} or \"service\":{\"name\":\"\"}.
consumeroptionalIf set, the plugin will activate only for requests where the specified has been authenticated. (Note that some plugins can not be restricted to consumers this way.). Leave unset for the plugin to activate regardless of the authenticated consumer. Defaults to null.With form-encoded, the notation is consumer.id= or consumer.username=. With JSON, use “\"consumer\":{\"id\":\"\"} or \"consumer\":{\"username\":\"\"}.
configoptionalThe configuration properties for the Plugin which can be found on the plugins documentation page in the Kong Hub.
protocolsrequiredA list of the request protocols that will trigger this plugin. The default value, as well as the possible values allowed on this field, may change depending on the plugin type. For example, plugins that only work in stream mode will only support \"tcp\" and \"tls\". Defaults to [\"grpc\", \"grpcs\", \"http\", \"https\"].
enabledoptionalWhether the plugin is applied. Defaults to true.
tagsoptionalAn optional set of strings associated with the Plugin, for grouping and filtering.
" + }, + "response": [] + } + ], + "description": "https://docs.konghq.com/2.0.x/admin-api/#add-plugin", + "event": [ + { + "listen": "prerequest", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + }, + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + } + ] + }, + { + "name": "List Plugins", + "item": [ + { + "name": "List All Plugins", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{gateway}}/plugins", + "host": [ + "{{gateway}}" + ], + "path": [ + "plugins" + ] + }, + "description": "# List All Plugins [konghq](https://docs.konghq.com/2.0.x/admin-api/#list-all-plugins)" + }, + "response": [ + { + "name": "List All Plugins", + "originalRequest": { + "method": "GET", + "header": [], + "url": { + "raw": "{{gateway}}/plugins", + "host": [ + "{{gateway}}" + ], + "path": [ + "plugins" + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "Text", + "header": [ + { + "key": "Date", + "value": "Thu, 12 Mar 2020 10:13:50 GMT" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "Server", + "value": "kong/2.0.1" + }, + { + "key": "Content-Length", + "value": "1052" + }, + { + "key": "X-Kong-Admin-Latency", + "value": "2" + } + ], + "cookie": [], + "body": "{\n \"next\": null,\n \"data\": [\n {\n \"created_at\": 1583998823,\n \"config\": {\n \"minute\": 20,\n \"policy\": \"cluster\",\n \"month\": null,\n \"redis_timeout\": 2000,\n \"limit_by\": \"consumer\",\n \"hide_client_headers\": false,\n \"second\": null,\n \"day\": null,\n \"redis_password\": null,\n \"year\": null,\n \"redis_database\": 0,\n \"hour\": 500,\n \"redis_port\": 6379,\n \"redis_host\": null,\n \"fault_tolerant\": true\n },\n \"id\": \"9175fd5b-e364-4759-bbe2-e7d00da5edd2\",\n \"service\": null,\n \"enabled\": true,\n \"protocols\": [\n \"https\",\n \"http\"\n ],\n \"name\": \"rate-limiting\",\n \"consumer\": null,\n \"route\": {\n \"id\": \"875973fd-ba3f-4c7b-8301-e9263013e6d2\"\n },\n \"tags\": [\n \"admin\",\n \"high-priority\",\n \"critical\"\n ]\n },\n {\n \"created_at\": 1422386534,\n \"config\": {\n \"minute\": 20,\n \"policy\": \"cluster\",\n \"month\": null,\n \"redis_timeout\": 2000,\n \"limit_by\": \"consumer\",\n \"hide_client_headers\": false,\n \"second\": null,\n \"day\": null,\n \"redis_password\": null,\n \"year\": null,\n \"redis_database\": 0,\n \"hour\": 500,\n \"redis_port\": 6379,\n \"redis_host\": null,\n \"fault_tolerant\": true\n },\n \"id\": \"e080cdd2-cdf4-4634-9d5d-1668c6929697\",\n \"service\": null,\n \"enabled\": true,\n \"protocols\": [\n \"http\",\n \"https\"\n ],\n \"name\": \"rate-limiting\",\n \"consumer\": null,\n \"route\": {},\n \"tags\": [\n \"user-level\",\n \"low-priority\"\n ]\n }\n ]\n}" + } + ] + }, + { + "name": "List Plugins Associated to a Specific Route", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{gateway}}/routes/:routeId/plugins", + "host": [ + "{{gateway}}" + ], + "path": [ + "routes", + ":routeId", + "plugins" + ], + "variable": [ + { + "key": "routeId", + "value": "", + "description": "The unique identifier of the Route whose Plugins are to be retrieved. When using this endpoint, only Plugins associated to the specified Route will be listed." + } + ] + }, + "description": "# List Plugins Associated to a Specific Route [konghq](https://docs.konghq.com/2.0.x/admin-api/#list-plugins-associated-to-a-specific-route)\n\n \n \n \n \n \n \n \n \n \n \n \n \n
AttributesMandatoryTypeDescription
route idrequiredpathThe unique identifier of the Route whose Plugins are to be retrieved. When using this endpoint, only Plugins associated to the specified Route will be listed.
" + }, + "response": [ + { + "name": "List Plugins Associated to a Specific Route", + "originalRequest": { + "method": "GET", + "header": [], + "url": { + "raw": "{{gateway}}/routes/:routeId/plugins", + "host": [ + "{{gateway}}" + ], + "path": [ + "routes", + ":routeId", + "plugins" + ], + "variable": [ + { + "key": "routeId", + "value": "875973fd-ba3f-4c7b-8301-e9263013e6d2", + "description": "The unique identifier of the Route whose Plugins are to be retrieved. When using this endpoint, only Plugins associated to the specified Route will be listed." + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "Text", + "header": [ + { + "key": "Date", + "value": "Thu, 12 Mar 2020 10:14:36 GMT" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "Server", + "value": "kong/2.0.1" + }, + { + "key": "Content-Length", + "value": "561" + }, + { + "key": "X-Kong-Admin-Latency", + "value": "3" + } + ], + "cookie": [], + "body": "{\n \"next\": null,\n \"data\": [\n {\n \"created_at\": 1583998823,\n \"config\": {\n \"minute\": 20,\n \"policy\": \"cluster\",\n \"month\": null,\n \"redis_timeout\": 2000,\n \"limit_by\": \"consumer\",\n \"hide_client_headers\": false,\n \"second\": null,\n \"day\": null,\n \"redis_password\": null,\n \"year\": null,\n \"redis_database\": 0,\n \"hour\": 500,\n \"redis_port\": 6379,\n \"redis_host\": null,\n \"fault_tolerant\": true\n },\n \"id\": \"9175fd5b-e364-4759-bbe2-e7d00da5edd2\",\n \"service\": null,\n \"enabled\": true,\n \"protocols\": [\n \"https\",\n \"http\"\n ],\n \"name\": \"rate-limiting\",\n \"consumer\": null,\n \"route\": {\n \"id\": \"875973fd-ba3f-4c7b-8301-e9263013e6d2\"\n },\n \"tags\": [\n \"admin\",\n \"high-priority\",\n \"critical\"\n ]\n }\n ]\n}" + } + ] + }, + { + "name": "List Plugins Associated to a Specific Service", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{gateway}}/services/:serviceId/plugins", + "host": [ + "{{gateway}}" + ], + "path": [ + "services", + ":serviceId", + "plugins" + ], + "variable": [ + { + "key": "serviceId", + "value": "", + "description": "The unique identifier of the Service whose Plugins are to be retrieved. When using this endpoint, only Plugins associated to the specified Service will be listed." + } + ] + }, + "description": "# List Plugins Associated to a Specific Service [konghq](https://docs.konghq.com/2.0.x/admin-api/#list-plugins-associated-to-a-specific-service)\n\n \n \n \n \n \n \n \n \n \n \n \n \n
AttributesMandatoryTypeDescription
service idrequiredpathThe unique identifier of the Service whose Plugins are to be retrieved. When using this endpoint, only Plugins associated to the specified Service will be listed.
" + }, + "response": [] + }, + { + "name": "List Plugins Associated to a Specific Consumer", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{gateway}}/consumers/:consumerId/plugins", + "host": [ + "{{gateway}}" + ], + "path": [ + "consumers", + ":consumerId", + "plugins" + ], + "variable": [ + { + "key": "consumerId", + "value": "", + "description": "The unique identifier of the Consumer whose Plugins are to be retrieved. When using this endpoint, only Plugins associated to the specified Consumer will be listed." + } + ] + }, + "description": "# List Plugins Associated to a Specific Consumer [konghq](https://docs.konghq.com/2.0.x/admin-api/#list-plugins-associated-to-a-specific-consumer)\n\n \n \n \n \n \n \n \n \n \n \n \n \n
AttributesMandatoryTypeDescription
consumer idrequiredpathThe unique identifier of the Consumer whose Plugins are to be retrieved. When using this endpoint, only Plugins associated to the specified Consumer will be listed.
" + }, + "response": [] + } + ], + "description": "https://docs.konghq.com/2.0.x/admin-api/#list-plugins", + "event": [ + { + "listen": "prerequest", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + }, + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + } + ] + }, + { + "name": "Retrieve Plugin", + "item": [ + { + "name": "Retrieve Enabled Plugins", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{gateway}}/plugins/:pluginId", + "host": [ + "{{gateway}}" + ], + "path": [ + "plugins", + ":pluginId" + ], + "variable": [ + { + "key": "pluginId" + } + ] + }, + "description": "# Retrieve Enabled Plugins [konghq](https://docs.konghq.com/2.0.x/admin-api/#retrieve-enabled-plugins)\n\nRetrieve a list of all installed plugins on the Kong node" + }, + "response": [ + { + "name": "Retrieve Plugin", + "originalRequest": { + "method": "GET", + "header": [], + "url": { + "raw": "{{gateway}}/plugins/:pluginId", + "host": [ + "{{gateway}}" + ], + "path": [ + "plugins", + ":pluginId" + ], + "variable": [ + { + "key": "pluginId", + "value": "9175fd5b-e364-4759-bbe2-e7d00da5edd2", + "description": "The unique identifier of the Plugin to retrieve." + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "Text", + "header": [ + { + "key": "Date", + "value": "Thu, 12 Mar 2020 10:33:31 GMT" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "Server", + "value": "kong/2.0.1" + }, + { + "key": "Content-Length", + "value": "538" + }, + { + "key": "X-Kong-Admin-Latency", + "value": "2" + } + ], + "cookie": [], + "body": "{\n \"created_at\": 1583998823,\n \"config\": {\n \"minute\": 20,\n \"policy\": \"cluster\",\n \"month\": null,\n \"redis_timeout\": 2000,\n \"limit_by\": \"consumer\",\n \"hide_client_headers\": false,\n \"second\": null,\n \"day\": null,\n \"redis_password\": null,\n \"year\": null,\n \"redis_database\": 0,\n \"hour\": 500,\n \"redis_port\": 6379,\n \"redis_host\": null,\n \"fault_tolerant\": true\n },\n \"id\": \"9175fd5b-e364-4759-bbe2-e7d00da5edd2\",\n \"service\": null,\n \"enabled\": true,\n \"protocols\": [\n \"https\",\n \"http\"\n ],\n \"name\": \"rate-limiting\",\n \"consumer\": null,\n \"route\": {\n \"id\": \"875973fd-ba3f-4c7b-8301-e9263013e6d2\"\n },\n \"tags\": [\n \"admin\",\n \"high-priority\",\n \"critical\"\n ],\n \"enabled_plugins\": [\n \"correlation-id\",\n \"pre-function\",\n \"cors\",\n \"ldap-auth\",\n \"loggly\",\n \"hmac-auth\",\n \"zipkin\",\n \"request-size-limiting\",\n \"azure-functions\",\n \"request-transformer\",\n \"oauth2\",\n \"response-transformer\",\n \"ip-restriction\",\n \"statsd\",\n \"jwt\",\n \"proxy-cache\",\n \"basic-auth\",\n \"key-auth\",\n \"http-log\",\n \"datadog\",\n \"tcp-log\",\n \"post-function\",\n \"prometheus\",\n \"acl\",\n \"syslog\",\n \"file-log\",\n \"session\",\n \"udp-log\",\n \"response-ratelimiting\",\n \"aws-lambda\",\n \"bot-detection\",\n \"rate-limiting\",\n \"request-termination\"\n ]\n}" + } + ] + }, + { + "name": "Retrieve Plugin Associated to a Specific Route", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{gateway}}/routes/:routeNameOrId/plugins/:pluginId", + "host": [ + "{{gateway}}" + ], + "path": [ + "routes", + ":routeNameOrId", + "plugins", + ":pluginId" + ], + "variable": [ + { + "key": "routeNameOrId", + "value": "", + "description": "The unique identifier or the name of the Route to retrieve" + }, + { + "key": "pluginId", + "value": "", + "description": "The unique identifier of the Plugin to retrieve." + } + ] + }, + "description": "# Retrieve Plugin Associated to a Specific Route [konghq](https://docs.konghq.com/2.0.x/admin-api/#retrieve-plugin-associated-to-a-specific-route)\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
AttributesMandatoryTypeDescription
route name or idrequiredpathThe unique identifier or the name of the Route to retrieve.
plugin idrequiredpathThe unique identifier of the Plugin to retrieve.
" + }, + "response": [] + }, + { + "name": "Retrieve Plugin Associated to a Specific Service", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{gateway}}/services/:serviceNameOrId/plugins/:pluginId", + "host": [ + "{{gateway}}" + ], + "path": [ + "services", + ":serviceNameOrId", + "plugins", + ":pluginId" + ], + "variable": [ + { + "key": "serviceNameOrId", + "value": "", + "description": "The unique identifier or the name of the Service to retrieve" + }, + { + "key": "pluginId", + "value": "", + "description": "The unique identifier of the Plugin to retrieve" + } + ] + }, + "description": "# Retrieve Plugin Associated to a Specific Service [konghq](https://docs.konghq.com/2.0.x/admin-api/#retrieve-plugin-associated-to-a-specific-service)\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
AttributesMandatoryTypeDescription
service name or idrequiredpathThe unique identifier or the name of the Service to retrieve.
plugin idrequiredpathThe unique identifier of the Plugin to retrieve.
" + }, + "response": [] + }, + { + "name": "Retrieve Plugin Associated to a Specific Consumer", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{gateway}}/consumers/:consumerUsernameOrId/plugins/:pluginId", + "host": [ + "{{gateway}}" + ], + "path": [ + "consumers", + ":consumerUsernameOrId", + "plugins", + ":pluginId" + ], + "variable": [ + { + "key": "consumerUsernameOrId", + "value": "", + "description": "The unique identifier or the username of the Consumer to retriev" + }, + { + "key": "pluginId", + "value": "", + "description": "The unique identifier of the Plugin to retrieve" + } + ] + }, + "description": "# Retrieve Plugin Associated to a Specific Consumer [konghq](https://docs.konghq.com/2.0.x/admin-api/#retrieve-plugin-associated-to-a-specific-consumer)\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
AttributesMandatoryTypeDescription
consumer username or idrequiredpathThe unique identifier or the username of the Consumer to retrieve
plugin idrequiredpathThe unique identifier of the Plugin to retrieve.
" + }, + "response": [] + } + ], + "description": "https://docs.konghq.com/2.0.x/admin-api/#retrieve-plugin", + "event": [ + { + "listen": "prerequest", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + }, + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + } + ] + }, + { + "name": "Update Plugin", + "item": [ + { + "name": "Update Plugin", + "request": { + "method": "PATCH", + "header": [ + { + "name": "Content-Type", + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"config\": {\n \"minute\": 20,\n \"policy\": \"cluster\",\n \"month\": null,\n \"redis_timeout\": 2000,\n \"limit_by\": \"consumer\",\n \"hide_client_headers\": false,\n \"second\": null,\n \"day\": null,\n \"redis_password\": null,\n \"year\": null,\n \"redis_database\": 0,\n \"hour\": 500,\n \"redis_port\": 6379,\n \"redis_host\": null,\n \"fault_tolerant\": true\n },\n \"service\": null,\n \"enabled\": true,\n \"protocols\": [\n \"https\",\n \"http\"\n ],\n \"name\": \"rate-limiting\",\n \"consumer\": null,\n \"route\": {\n \"id\": \"875973fd-ba3f-4c7b-8301-e9263013e6d2\"\n },\n \"tags\": [\n \"admin\",\n \"high-priority\",\n \"critical\"\n ]\n}" + }, + "url": { + "raw": "{{gateway}}/plugins/:pluginId", + "host": [ + "{{gateway}}" + ], + "path": [ + "plugins", + ":pluginId" + ], + "variable": [ + { + "key": "pluginId", + "value": "9175fd5b-e364-4759-bbe2-e7d00da5edd2", + "description": "The unique identifier of the Plugin to update." + } + ] + }, + "description": "# Update Plugin [konghq](https://docs.konghq.com/2.0.x/admin-api/#update-plugin)\n\n\n \n \n \n \n \n \n \n \n \n \n
AttributesMandatoryDescription
plugin idrequiredThe unique identifier of the Plugin to update.
\n\n# Request Body\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
AttributesMandatoryDescription
namerequiredThe name of the Plugin that’s going to be added. Currently the Plugin must be installed in every Kong instance separately.
routeoptionalIf set, the plugin will only activate when receiving requests via the specified route. Leave unset for the plugin to activate regardless of the Route being used. Defaults to null.With form-encoded, the notation is route.id= or route.name=. With JSON, use “\"route\":{\"id\":\"\"} or \"route\":{\"name\":\"\"}.
serviceoptionalIf set, the plugin will only activate when receiving requests via one of the routes belonging to the specified Service. Leave unset for the plugin to activate regardless of the Service being matched. Defaults to null.With form-encoded, the notation is service.id= or service.name=. With JSON, use “\"service\":{\"id\":\"\"} or \"service\":{\"name\":\"\"}.
consumeroptionalIf set, the plugin will activate only for requests where the specified has been authenticated. (Note that some plugins can not be restricted to consumers this way.). Leave unset for the plugin to activate regardless of the authenticated consumer. Defaults to null.With form-encoded, the notation is consumer.id= or consumer.username=. With JSON, use “\"consumer\":{\"id\":\"\"} or \"consumer\":{\"username\":\"\"}.
configoptionalThe configuration properties for the Plugin which can be found on the plugins documentation page in the Kong Hub.
protocolsrequiredA list of the request protocols that will trigger this plugin. The default value, as well as the possible values allowed on this field, may change depending on the plugin type. For example, plugins that only work in stream mode will only support \"tcp\" and \"tls\". Defaults to [\"grpc\", \"grpcs\", \"http\", \"https\"].
enabledoptionalWhether the plugin is applied. Defaults to true.
tagsoptionalAn optional set of strings associated with the Plugin, for grouping and filtering.
" + }, + "response": [ + { + "name": "Update Plugin - 400", + "originalRequest": { + "method": "PATCH", + "header": [ + { + "name": "Content-Type", + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"config\": {\n \"minute\": 20,\n \"policy\": \"cluster\",\n \"month\": null,\n \"redis_timeout\": 2000,\n \"limit_by\": \"consumer\",\n \"hide_client_headers\": false,\n \"second\": null,\n \"day\": null,\n \"redis_password\": null,\n \"year\": null,\n \"redis_database\": 0,\n \"hour\": 500,\n \"redis_port\": 6379,\n \"redis_host\": null,\n \"fault_tolerant\": true\n },\n \"service\": null,\n \"enabled\": true,\n \"protocols\": [\n \"https\",\n \"http\"\n ],\n \"name\": \"rate-limiting\",\n \"consumer\": null,\n \"route\": {\n \"id\": \"875973fd-ba3f-4c7b-8301-e9263013e6d2\"\n },\n \"tags\": [\n \"admin\",\n \"high-priority\",\n \"critical\"\n ]\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{gateway}}/plugins/:pluginId", + "host": [ + "{{gateway}}" + ], + "path": [ + "plugins", + ":pluginId" + ], + "variable": [ + { + "key": "pluginId", + "value": "xxxxxxxxxx", + "description": "The unique identifier of the Plugin to update." + } + ] + } + }, + "status": "Bad Request", + "code": 400, + "_postman_previewlanguage": "Text", + "header": [ + { + "key": "Date", + "value": "Thu, 12 Mar 2020 11:06:03 GMT" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "Server", + "value": "kong/2.0.1" + }, + { + "key": "Content-Length", + "value": "145" + }, + { + "key": "X-Kong-Admin-Latency", + "value": "1" + } + ], + "cookie": [], + "body": "{\n \"message\": \"invalid primary key: '{id=\\\"expected a valid UUID\\\"}'\",\n \"name\": \"invalid primary key\",\n \"fields\": {\n \"id\": \"expected a valid UUID\"\n },\n \"code\": 1\n}" + }, + { + "name": "Update Plugin - 200", + "originalRequest": { + "method": "PATCH", + "header": [ + { + "name": "Content-Type", + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"config\": {\n\t\t\"minute\": 20,\n\t\t\"policy\": \"cluster\",\n\t\t\"month\": null,\n\t\t\"redis_timeout\": 2000,\n\t\t\"limit_by\": \"consumer\",\n\t\t\"hide_client_headers\": false,\n\t\t\"second\": null,\n\t\t\"day\": null,\n\t\t\"redis_password\": null,\n\t\t\"year\": null,\n\t\t\"redis_database\": 0,\n\t\t\"hour\": 500,\n\t\t\"redis_port\": 6379,\n\t\t\"redis_host\": null,\n\t\t\"fault_tolerant\": true\n\t},\n\t\"service\": null,\n\t\"enabled\": true,\n\t\"protocols\": [\n\t\t\"https\",\n\t\t\"http\"\n\t],\n\t\"name\": \"rate-limiting\",\n\t\"consumer\": null,\n\t\"route\": {\n\t\t\"id\": \"875973fd-ba3f-4c7b-8301-e9263013e6d2\"\n\t},\n\t\"tags\": [\n\t\t\"admin\",\n\t\t\"high-priority\",\n\t\t\"critical\"\n\t]\n}" + }, + "url": { + "raw": "{{gateway}}/plugins/:pluginId", + "host": [ + "{{gateway}}" + ], + "path": [ + "plugins", + ":pluginId" + ], + "variable": [ + { + "key": "pluginId", + "value": "9175fd5b-e364-4759-bbe2-e7d00da5edd2", + "description": "The unique identifier of the Plugin to update." + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "Text", + "header": [ + { + "key": "Date", + "value": "Thu, 12 Mar 2020 11:10:55 GMT" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "Server", + "value": "kong/2.0.1" + }, + { + "key": "Content-Length", + "value": "538" + }, + { + "key": "X-Kong-Admin-Latency", + "value": "14" + } + ], + "cookie": [], + "body": "{\n \"config\": {\n \"minute\": 20,\n \"policy\": \"cluster\",\n \"month\": null,\n \"redis_timeout\": 2000,\n \"limit_by\": \"consumer\",\n \"hide_client_headers\": false,\n \"second\": null,\n \"day\": null,\n \"redis_password\": null,\n \"year\": null,\n \"redis_database\": 0,\n \"hour\": 500,\n \"redis_port\": 6379,\n \"redis_host\": null,\n \"fault_tolerant\": true\n },\n \"service\": null,\n \"enabled\": true,\n \"protocols\": [\n \"https\",\n \"http\"\n ],\n \"name\": \"rate-limiting\",\n \"consumer\": null,\n \"route\": {\n \"id\": \"875973fd-ba3f-4c7b-8301-e9263013e6d2\"\n },\n \"tags\": [\n \"admin\",\n \"high-priority\",\n \"critical\"\n ]\n}" + } + ] + }, + { + "name": "Update Plugin Associated to a Specific Route", + "request": { + "method": "PATCH", + "header": [ + { + "name": "Content-Type", + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"config\": {\n \"minute\": 20,\n \"policy\": \"cluster\",\n \"month\": null,\n \"redis_timeout\": 2000,\n \"limit_by\": \"consumer\",\n \"hide_client_headers\": false,\n \"second\": null,\n \"day\": null,\n \"redis_password\": null,\n \"year\": null,\n \"redis_database\": 0,\n \"hour\": 500,\n \"redis_port\": 6379,\n \"redis_host\": null,\n \"fault_tolerant\": true\n },\n \"service\": null,\n \"enabled\": true,\n \"protocols\": [\n \"https\",\n \"http\"\n ],\n \"name\": \"rate-limiting\",\n \"consumer\": null,\n \"route\": {\n \"id\": \"875973fd-ba3f-4c7b-8301-e9263013e6d2\"\n },\n \"tags\": [\n \"admin\",\n \"high-priority\",\n \"critical\"\n ]\n}" + }, + "url": { + "raw": "{{gateway}}/routes/:routeNameOrId/plugins/:pluginId", + "host": [ + "{{gateway}}" + ], + "path": [ + "routes", + ":routeNameOrId", + "plugins", + ":pluginId" + ], + "variable": [ + { + "key": "routeNameOrId", + "value": "875973fd-ba3f-4c7b-8301-e9263013e6d2", + "description": "The unique identifier or the name of the Route to update." + }, + { + "key": "pluginId", + "value": "9175fd5b-e364-4759-bbe2-e7d00da5edd2", + "description": "The unique identifier of the Plugin to update." + } + ] + }, + "description": "# Update Plugin Associated to a Specific Route [konghq](https://docs.konghq.com/2.0.x/admin-api/#update-plugin-associated-to-a-specific-route)\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
AttributesMandatoryDescription
route name or idrequiredThe unique identifier or the name of the Route to update.
plugin idrequiredThe unique identifier of the Plugin to update.
\n\n# Request Body\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
AttributesMandatoryDescription
namerequiredThe name of the Plugin that’s going to be added. Currently the Plugin must be installed in every Kong instance separately.
routeoptionalIf set, the plugin will only activate when receiving requests via the specified route. Leave unset for the plugin to activate regardless of the Route being used. Defaults to null.With form-encoded, the notation is route.id= or route.name=. With JSON, use “\"route\":{\"id\":\"\"} or \"route\":{\"name\":\"\"}.
serviceoptionalIf set, the plugin will only activate when receiving requests via one of the routes belonging to the specified Service. Leave unset for the plugin to activate regardless of the Service being matched. Defaults to null.With form-encoded, the notation is service.id= or service.name=. With JSON, use “\"service\":{\"id\":\"\"} or \"service\":{\"name\":\"\"}.
consumeroptionalIf set, the plugin will activate only for requests where the specified has been authenticated. (Note that some plugins can not be restricted to consumers this way.). Leave unset for the plugin to activate regardless of the authenticated consumer. Defaults to null.With form-encoded, the notation is consumer.id= or consumer.username=. With JSON, use “\"consumer\":{\"id\":\"\"} or \"consumer\":{\"username\":\"\"}.
configoptionalThe configuration properties for the Plugin which can be found on the plugins documentation page in the Kong Hub.
protocolsrequiredA list of the request protocols that will trigger this plugin. The default value, as well as the possible values allowed on this field, may change depending on the plugin type. For example, plugins that only work in stream mode will only support \"tcp\" and \"tls\". Defaults to [\"grpc\", \"grpcs\", \"http\", \"https\"].
enabledoptionalWhether the plugin is applied. Defaults to true.
tagsoptionalAn optional set of strings associated with the Plugin, for grouping and filtering.
" + }, + "response": [ + { + "name": "Update Plugin Associated to a Specific Route", + "originalRequest": { + "method": "PATCH", + "header": [ + { + "name": "Content-Type", + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"created_at\": 1583998823,\n \"config\": {\n \"minute\": 20,\n \"policy\": \"cluster\",\n \"month\": null,\n \"redis_timeout\": 2000,\n \"limit_by\": \"consumer\",\n \"hide_client_headers\": false,\n \"second\": null,\n \"day\": null,\n \"redis_password\": null,\n \"year\": null,\n \"redis_database\": 0,\n \"hour\": 500,\n \"redis_port\": 6379,\n \"redis_host\": null,\n \"fault_tolerant\": true\n },\n \"id\": \"9175fd5b-e364-4759-bbe2-e7d00da5edd2\",\n \"service\": null,\n \"enabled\": true,\n \"protocols\": [\n \"https\",\n \"http\"\n ],\n \"name\": \"rate-limiting\",\n \"consumer\": null,\n \"route\": {\n \"id\": \"875973fd-ba3f-4c7b-8301-e9263013e6d2\"\n },\n \"tags\": [\n \"admin\",\n \"high-priority\",\n \"critical\"\n ]\n}" + }, + "url": { + "raw": "{{gateway}}/routes/:routeNameOrId/plugins/:pluginId", + "host": [ + "{{gateway}}" + ], + "path": [ + "routes", + ":routeNameOrId", + "plugins", + ":pluginId" + ], + "variable": [ + { + "key": "routeNameOrId", + "value": "875973fd-ba3f-4c7b-8301-e9263013e6d2", + "description": "The unique identifier or the name of the Route to update." + }, + { + "key": "pluginId", + "value": "9175fd5b-e364-4759-bbe2-e7d00da5edd2", + "description": "The unique identifier of the Plugin to update." + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "Text", + "header": [ + { + "key": "Date", + "value": "Thu, 12 Mar 2020 11:23:03 GMT" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "Server", + "value": "kong/2.0.1" + }, + { + "key": "Content-Length", + "value": "538" + }, + { + "key": "X-Kong-Admin-Latency", + "value": "15" + } + ], + "cookie": [], + "body": "{\n \"config\": {\n \"minute\": 20,\n \"policy\": \"cluster\",\n \"month\": null,\n \"redis_timeout\": 2000,\n \"limit_by\": \"consumer\",\n \"hide_client_headers\": false,\n \"second\": null,\n \"day\": null,\n \"redis_password\": null,\n \"year\": null,\n \"redis_database\": 0,\n \"hour\": 500,\n \"redis_port\": 6379,\n \"redis_host\": null,\n \"fault_tolerant\": true\n },\n \"service\": null,\n \"enabled\": true,\n \"protocols\": [\n \"https\",\n \"http\"\n ],\n \"name\": \"rate-limiting\",\n \"consumer\": null,\n \"route\": {\n \"id\": \"875973fd-ba3f-4c7b-8301-e9263013e6d2\"\n },\n \"tags\": [\n \"admin\",\n \"high-priority\",\n \"critical\"\n ]\n}" + } + ] + }, + { + "name": "Update Plugin Associated to a Specific Service", + "request": { + "method": "PATCH", + "header": [ + { + "name": "Content-Type", + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"config\": {\n \"minute\": 20,\n \"policy\": \"cluster\",\n \"month\": null,\n \"redis_timeout\": 2000,\n \"limit_by\": \"consumer\",\n \"hide_client_headers\": false,\n \"second\": null,\n \"day\": null,\n \"redis_password\": null,\n \"year\": null,\n \"redis_database\": 0,\n \"hour\": 500,\n \"redis_port\": 6379,\n \"redis_host\": null,\n \"fault_tolerant\": true\n },\n \"service\": null,\n \"enabled\": true,\n \"protocols\": [\n \"https\",\n \"http\"\n ],\n \"name\": \"rate-limiting\",\n \"consumer\": null,\n \"route\": {\n \"id\": \"875973fd-ba3f-4c7b-8301-e9263013e6d2\"\n },\n \"tags\": [\n \"admin\",\n \"high-priority\",\n \"critical\"\n ]\n}" + }, + "url": { + "raw": "{{gateway}}/services/:serviceNameOrId/plugins/:pluginId", + "host": [ + "{{gateway}}" + ], + "path": [ + "services", + ":serviceNameOrId", + "plugins", + ":pluginId" + ], + "variable": [ + { + "key": "serviceNameOrId", + "value": "", + "description": "The unique identifier or the name of the Service to update." + }, + { + "key": "pluginId", + "value": "", + "description": "The unique identifier of the Plugin to update." + } + ] + }, + "description": "# Update Plugin Associated to a Specific Service [konghq](https://docs.konghq.com/2.0.x/admin-api/#update-plugin-associated-to-a-specific-service)\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
AttributesMandatoryDescription
service name or idrequiredThe unique identifier or the name of the Service to update.
plugin idrequiredThe unique identifier of the Plugin to update.
\n\n# Request Body\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
AttributesMandatoryDescription
namerequiredThe name of the Plugin that’s going to be added. Currently the Plugin must be installed in every Kong instance separately.
routeoptionalIf set, the plugin will only activate when receiving requests via the specified route. Leave unset for the plugin to activate regardless of the Route being used. Defaults to null.With form-encoded, the notation is route.id= or route.name=. With JSON, use “\"route\":{\"id\":\"\"} or \"route\":{\"name\":\"\"}.
serviceoptionalIf set, the plugin will only activate when receiving requests via one of the routes belonging to the specified Service. Leave unset for the plugin to activate regardless of the Service being matched. Defaults to null.With form-encoded, the notation is service.id= or service.name=. With JSON, use “\"service\":{\"id\":\"\"} or \"service\":{\"name\":\"\"}.
consumeroptionalIf set, the plugin will activate only for requests where the specified has been authenticated. (Note that some plugins can not be restricted to consumers this way.). Leave unset for the plugin to activate regardless of the authenticated consumer. Defaults to null.With form-encoded, the notation is consumer.id= or consumer.username=. With JSON, use “\"consumer\":{\"id\":\"\"} or \"consumer\":{\"username\":\"\"}.
configoptionalThe configuration properties for the Plugin which can be found on the plugins documentation page in the Kong Hub.
protocolsrequiredA list of the request protocols that will trigger this plugin. The default value, as well as the possible values allowed on this field, may change depending on the plugin type. For example, plugins that only work in stream mode will only support \"tcp\" and \"tls\". Defaults to [\"grpc\", \"grpcs\", \"http\", \"https\"].
enabledoptionalWhether the plugin is applied. Defaults to true.
tagsoptionalAn optional set of strings associated with the Plugin, for grouping and filtering.
" + }, + "response": [] + }, + { + "name": "Update Plugin Associated to a Specific Consumer", + "request": { + "method": "PATCH", + "header": [ + { + "name": "Content-Type", + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"config\": {\n \"minute\": 20,\n \"policy\": \"cluster\",\n \"month\": null,\n \"redis_timeout\": 2000,\n \"limit_by\": \"consumer\",\n \"hide_client_headers\": false,\n \"second\": null,\n \"day\": null,\n \"redis_password\": null,\n \"year\": null,\n \"redis_database\": 0,\n \"hour\": 500,\n \"redis_port\": 6379,\n \"redis_host\": null,\n \"fault_tolerant\": true\n },\n \"service\": null,\n \"enabled\": true,\n \"protocols\": [\n \"https\",\n \"http\"\n ],\n \"name\": \"rate-limiting\",\n \"consumer\": null,\n \"route\": {\n \"id\": \"875973fd-ba3f-4c7b-8301-e9263013e6d2\"\n },\n \"tags\": [\n \"admin\",\n \"high-priority\",\n \"critical\"\n ]\n}" + }, + "url": { + "raw": "{{gateway}}/consumers/:consumerUsernameOrd}/plugins/:pluginId", + "host": [ + "{{gateway}}" + ], + "path": [ + "consumers", + ":consumerUsernameOrd}", + "plugins", + ":pluginId" + ], + "variable": [ + { + "key": "consumerUsernameOrd}", + "value": "", + "description": "The unique identifier or the username of the Consumer to update" + }, + { + "key": "pluginId", + "value": "", + "description": "The unique identifier of the Plugin to update." + } + ] + }, + "description": "# Update Plugin Associated to a Specific Consumer [konghq](https://docs.konghq.com/2.0.x/admin-api/#update-plugin-associated-to-a-specific-consumer)\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
AttributesMandatoryDescription
consumer username or idrequiredThe unique identifier or the username of the Consumer to update.
plugin idrequiredThe unique identifier of the Plugin to update.
\n\n# Request Body\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
AttributesMandatoryDescription
namerequiredThe name of the Plugin that’s going to be added. Currently the Plugin must be installed in every Kong instance separately.
routeoptionalIf set, the plugin will only activate when receiving requests via the specified route. Leave unset for the plugin to activate regardless of the Route being used. Defaults to null.With form-encoded, the notation is route.id= or route.name=. With JSON, use “\"route\":{\"id\":\"\"} or \"route\":{\"name\":\"\"}.
serviceoptionalIf set, the plugin will only activate when receiving requests via one of the routes belonging to the specified Service. Leave unset for the plugin to activate regardless of the Service being matched. Defaults to null.With form-encoded, the notation is service.id= or service.name=. With JSON, use “\"service\":{\"id\":\"\"} or \"service\":{\"name\":\"\"}.
consumeroptionalIf set, the plugin will activate only for requests where the specified has been authenticated. (Note that some plugins can not be restricted to consumers this way.). Leave unset for the plugin to activate regardless of the authenticated consumer. Defaults to null.With form-encoded, the notation is consumer.id= or consumer.username=. With JSON, use “\"consumer\":{\"id\":\"\"} or \"consumer\":{\"username\":\"\"}.
configoptionalThe configuration properties for the Plugin which can be found on the plugins documentation page in the Kong Hub.
protocolsrequiredA list of the request protocols that will trigger this plugin. The default value, as well as the possible values allowed on this field, may change depending on the plugin type. For example, plugins that only work in stream mode will only support \"tcp\" and \"tls\". Defaults to [\"grpc\", \"grpcs\", \"http\", \"https\"].
enabledoptionalWhether the plugin is applied. Defaults to true.
tagsoptionalAn optional set of strings associated with the Plugin, for grouping and filtering.
" + }, + "response": [] + } + ], + "description": "https://docs.konghq.com/2.0.x/admin-api/#update-plugin", + "event": [ + { + "listen": "prerequest", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + }, + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + } + ] + }, + { + "name": "Update or Create Plugin", + "item": [ + { + "name": "Create Or Update Plugin", + "request": { + "method": "PUT", + "header": [ + { + "name": "Content-Type", + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"config\": {\n \"minute\": 20,\n \"policy\": \"cluster\",\n \"month\": null,\n \"redis_timeout\": 2000,\n \"limit_by\": \"consumer\",\n \"hide_client_headers\": false,\n \"second\": null,\n \"day\": null,\n \"redis_password\": null,\n \"year\": null,\n \"redis_database\": 0,\n \"hour\": 500,\n \"redis_port\": 6379,\n \"redis_host\": null,\n \"fault_tolerant\": true\n },\n \"service\": null,\n \"enabled\": true,\n \"protocols\": [\n \"https\",\n \"http\"\n ],\n \"name\": \"rate-limiting\",\n \"consumer\": null,\n \"route\": {\n \"id\": \"875973fd-ba3f-4c7b-8301-e9263013e6d2\"\n },\n \"tags\": [\n \"admin\",\n \"high-priority\",\n \"critical\"\n ]\n}" + }, + "url": { + "raw": "{{gateway}}/plugins/:pluginId", + "host": [ + "{{gateway}}" + ], + "path": [ + "plugins", + ":pluginId" + ], + "variable": [ + { + "key": "pluginId", + "value": "9175fd5b-e364-4759-bbe2-e7d00da5edd2", + "description": "The unique identifier of the Plugin to update." + } + ] + }, + "description": "# Create Or Update Plugin [konghq](https://docs.konghq.com/2.0.x/admin-api/#create-or-update-plugin)\n* Inserts (or replaces) the Plugin under the requested resource with the definition specified in the body. The Plugin will be identified via the name or id attribute.\n* When the name or id attribute has the structure of a UUID, the Plugin being inserted/replaced will be identified by its id. Otherwise it will be identified by its name.\n* When creating a new Plugin without specifying id (neither in the URL nor in the body), then it will be auto-generated.\n* Notice that specifying a name in the URL and a different one in the request body is not allowed.\n\n\n \n \n \n \n \n \n \n \n \n \n
AttributesMandatoryDescription
plugin idrequiredThe unique identifier of the Plugin to update.
\n\n# Request Body\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
AttributesMandatoryDescription
namerequiredThe name of the Plugin that’s going to be added. Currently the Plugin must be installed in every Kong instance separately.
routeoptionalIf set, the plugin will only activate when receiving requests via the specified route. Leave unset for the plugin to activate regardless of the Route being used. Defaults to null.With form-encoded, the notation is route.id= or route.name=. With JSON, use “\"route\":{\"id\":\"\"} or \"route\":{\"name\":\"\"}.
serviceoptionalIf set, the plugin will only activate when receiving requests via one of the routes belonging to the specified Service. Leave unset for the plugin to activate regardless of the Service being matched. Defaults to null.With form-encoded, the notation is service.id= or service.name=. With JSON, use “\"service\":{\"id\":\"\"} or \"service\":{\"name\":\"\"}.
consumeroptionalIf set, the plugin will activate only for requests where the specified has been authenticated. (Note that some plugins can not be restricted to consumers this way.). Leave unset for the plugin to activate regardless of the authenticated consumer. Defaults to null.With form-encoded, the notation is consumer.id= or consumer.username=. With JSON, use “\"consumer\":{\"id\":\"\"} or \"consumer\":{\"username\":\"\"}.
configoptionalThe configuration properties for the Plugin which can be found on the plugins documentation page in the Kong Hub.
protocolsrequiredA list of the request protocols that will trigger this plugin. The default value, as well as the possible values allowed on this field, may change depending on the plugin type. For example, plugins that only work in stream mode will only support \"tcp\" and \"tls\". Defaults to [\"grpc\", \"grpcs\", \"http\", \"https\"].
enabledoptionalWhether the plugin is applied. Defaults to true.
tagsoptionalAn optional set of strings associated with the Plugin, for grouping and filtering.
" + }, + "response": [ + { + "name": "Create Or Update Plugin", + "originalRequest": { + "method": "PUT", + "header": [ + { + "name": "Content-Type", + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"config\": {\n \"minute\": 20,\n \"policy\": \"cluster\",\n \"month\": null,\n \"redis_timeout\": 2000,\n \"limit_by\": \"consumer\",\n \"hide_client_headers\": false,\n \"second\": null,\n \"day\": null,\n \"redis_password\": null,\n \"year\": null,\n \"redis_database\": 0,\n \"hour\": 500,\n \"redis_port\": 6379,\n \"redis_host\": null,\n \"fault_tolerant\": true\n },\n \"service\": null,\n \"enabled\": true,\n \"protocols\": [\n \"https\",\n \"http\"\n ],\n \"name\": \"rate-limiting\",\n \"consumer\": null,\n \"route\": {\n \"id\": \"875973fd-ba3f-4c7b-8301-e9263013e6d2\"\n },\n \"tags\": [\n \"admin\",\n \"high-priority\",\n \"critical\"\n ]\n}" + }, + "url": { + "raw": "{{gateway}}/plugins/:pluginId", + "host": [ + "{{gateway}}" + ], + "path": [ + "plugins", + ":pluginId" + ], + "variable": [ + { + "key": "pluginId", + "value": "9175fd5b-e364-4759-bbe2-e7d00da5edd2", + "description": "The unique identifier of the Plugin to update." + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "Text", + "header": [ + { + "key": "Date", + "value": "Thu, 12 Mar 2020 11:37:53 GMT" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "Server", + "value": "kong/2.0.1" + }, + { + "key": "Content-Length", + "value": "538" + }, + { + "key": "X-Kong-Admin-Latency", + "value": "11" + } + ], + "cookie": [], + "body": "{\n \"created_at\": 1584013073,\n \"config\": {\n \"minute\": 20,\n \"policy\": \"cluster\",\n \"month\": null,\n \"redis_timeout\": 2000,\n \"limit_by\": \"consumer\",\n \"hide_client_headers\": false,\n \"second\": null,\n \"day\": null,\n \"redis_password\": null,\n \"year\": null,\n \"redis_database\": 0,\n \"hour\": 500,\n \"redis_port\": 6379,\n \"redis_host\": null,\n \"fault_tolerant\": true\n },\n \"id\": \"9175fd5b-e364-4759-bbe2-e7d00da5edd2\",\n \"service\": null,\n \"enabled\": true,\n \"protocols\": [\n \"https\",\n \"http\"\n ],\n \"name\": \"rate-limiting\",\n \"consumer\": null,\n \"route\": {\n \"id\": \"875973fd-ba3f-4c7b-8301-e9263013e6d2\"\n },\n \"tags\": [\n \"admin\",\n \"high-priority\",\n \"critical\"\n ]\n}" + } + ] + }, + { + "name": "Create Or Update Plugin Associated to a Specific Route", + "request": { + "method": "PUT", + "header": [ + { + "name": "Content-Type", + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"config\": {\n \"minute\": 20,\n \"policy\": \"cluster\",\n \"month\": null,\n \"redis_timeout\": 2000,\n \"limit_by\": \"consumer\",\n \"hide_client_headers\": false,\n \"second\": null,\n \"day\": null,\n \"redis_password\": null,\n \"year\": null,\n \"redis_database\": 0,\n \"hour\": 500,\n \"redis_port\": 6379,\n \"redis_host\": null,\n \"fault_tolerant\": true\n },\n \"service\": null,\n \"enabled\": true,\n \"protocols\": [\n \"https\",\n \"http\"\n ],\n \"name\": \"rate-limiting\",\n \"consumer\": null,\n \"route\": {\n \"id\": \"875973fd-ba3f-4c7b-8301-e9263013e6d2\"\n },\n \"tags\": [\n \"admin\",\n \"high-priority\",\n \"critical\"\n ]\n}" + }, + "url": { + "raw": "{{gateway}}/routes/:routeNameOrId/plugins/:pluginId", + "host": [ + "{{gateway}}" + ], + "path": [ + "routes", + ":routeNameOrId", + "plugins", + ":pluginId" + ], + "variable": [ + { + "key": "routeNameOrId", + "value": "875973fd-ba3f-4c7b-8301-e9263013e6d2", + "description": "The unique identifier or the name of the Route to update." + }, + { + "key": "pluginId", + "value": "9175fd5b-e364-4759-bbe2-e7d00da5edd2", + "description": "The unique identifier of the Plugin to update." + } + ] + }, + "description": "# Create Or Update Plugin Associated to a Specific Route [konghq](https://docs.konghq.com/2.0.x/admin-api/#create-or-update-plugin-associated-to-a-specific-route)\n* Inserts (or replaces) the Plugin under the requested resource with the definition specified in the body. The Plugin will be identified via the name or id attribute.\n* When the name or id attribute has the structure of a UUID, the Plugin being inserted/replaced will be identified by its id. Otherwise it will be identified by its name.\n* When creating a new Plugin without specifying id (neither in the URL nor in the body), then it will be auto-generated.\n* Notice that specifying a name in the URL and a different one in the request body is not allowed.\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
AttributesMandatoryDescription
route name or idrequiredThe unique identifier or the name of the Route to update.
plugin idrequiredThe unique identifier of the Plugin to update.
\n\n# Request Body\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
AttributesMandatoryDescription
namerequiredThe name of the Plugin that’s going to be added. Currently the Plugin must be installed in every Kong instance separately.
routeoptionalIf set, the plugin will only activate when receiving requests via the specified route. Leave unset for the plugin to activate regardless of the Route being used. Defaults to null.With form-encoded, the notation is route.id= or route.name=. With JSON, use “\"route\":{\"id\":\"\"} or \"route\":{\"name\":\"\"}.
serviceoptionalIf set, the plugin will only activate when receiving requests via one of the routes belonging to the specified Service. Leave unset for the plugin to activate regardless of the Service being matched. Defaults to null.With form-encoded, the notation is service.id= or service.name=. With JSON, use “\"service\":{\"id\":\"\"} or \"service\":{\"name\":\"\"}.
consumeroptionalIf set, the plugin will activate only for requests where the specified has been authenticated. (Note that some plugins can not be restricted to consumers this way.). Leave unset for the plugin to activate regardless of the authenticated consumer. Defaults to null.With form-encoded, the notation is consumer.id= or consumer.username=. With JSON, use “\"consumer\":{\"id\":\"\"} or \"consumer\":{\"username\":\"\"}.
configoptionalThe configuration properties for the Plugin which can be found on the plugins documentation page in the Kong Hub.
protocolsrequiredA list of the request protocols that will trigger this plugin. The default value, as well as the possible values allowed on this field, may change depending on the plugin type. For example, plugins that only work in stream mode will only support \"tcp\" and \"tls\". Defaults to [\"grpc\", \"grpcs\", \"http\", \"https\"].
enabledoptionalWhether the plugin is applied. Defaults to true.
tagsoptionalAn optional set of strings associated with the Plugin, for grouping and filtering.
" + }, + "response": [ + { + "name": "Update Plugin Associated to a Specific Route", + "originalRequest": { + "method": "PATCH", + "header": [ + { + "name": "Content-Type", + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"created_at\": 1583998823,\n \"config\": {\n \"minute\": 20,\n \"policy\": \"cluster\",\n \"month\": null,\n \"redis_timeout\": 2000,\n \"limit_by\": \"consumer\",\n \"hide_client_headers\": false,\n \"second\": null,\n \"day\": null,\n \"redis_password\": null,\n \"year\": null,\n \"redis_database\": 0,\n \"hour\": 500,\n \"redis_port\": 6379,\n \"redis_host\": null,\n \"fault_tolerant\": true\n },\n \"id\": \"9175fd5b-e364-4759-bbe2-e7d00da5edd2\",\n \"service\": null,\n \"enabled\": true,\n \"protocols\": [\n \"https\",\n \"http\"\n ],\n \"name\": \"rate-limiting\",\n \"consumer\": null,\n \"route\": {\n \"id\": \"875973fd-ba3f-4c7b-8301-e9263013e6d2\"\n },\n \"tags\": [\n \"admin\",\n \"high-priority\",\n \"critical\"\n ]\n}" + }, + "url": { + "raw": "{{gateway}}/routes/:routeNameOrId/plugins/:pluginId", + "host": [ + "{{gateway}}" + ], + "path": [ + "routes", + ":routeNameOrId", + "plugins", + ":pluginId" + ], + "variable": [ + { + "key": "routeNameOrId", + "value": "875973fd-ba3f-4c7b-8301-e9263013e6d2", + "description": "The unique identifier or the name of the Route to update." + }, + { + "key": "pluginId", + "value": "9175fd5b-e364-4759-bbe2-e7d00da5edd2", + "description": "The unique identifier of the Plugin to update." + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "Text", + "header": [ + { + "key": "Date", + "value": "Thu, 12 Mar 2020 11:23:03 GMT" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "Server", + "value": "kong/2.0.1" + }, + { + "key": "Content-Length", + "value": "538" + }, + { + "key": "X-Kong-Admin-Latency", + "value": "15" + } + ], + "cookie": [], + "body": "{\n \"config\": {\n \"minute\": 20,\n \"policy\": \"cluster\",\n \"month\": null,\n \"redis_timeout\": 2000,\n \"limit_by\": \"consumer\",\n \"hide_client_headers\": false,\n \"second\": null,\n \"day\": null,\n \"redis_password\": null,\n \"year\": null,\n \"redis_database\": 0,\n \"hour\": 500,\n \"redis_port\": 6379,\n \"redis_host\": null,\n \"fault_tolerant\": true\n },\n \"service\": null,\n \"enabled\": true,\n \"protocols\": [\n \"https\",\n \"http\"\n ],\n \"name\": \"rate-limiting\",\n \"consumer\": null,\n \"route\": {\n \"id\": \"875973fd-ba3f-4c7b-8301-e9263013e6d2\"\n },\n \"tags\": [\n \"admin\",\n \"high-priority\",\n \"critical\"\n ]\n}" + } + ] + }, + { + "name": "Create Or Update Plugin Associated to a Specific Service", + "request": { + "method": "PUT", + "header": [ + { + "name": "Content-Type", + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"config\": {\n \"minute\": 20,\n \"policy\": \"cluster\",\n \"month\": null,\n \"redis_timeout\": 2000,\n \"limit_by\": \"consumer\",\n \"hide_client_headers\": false,\n \"second\": null,\n \"day\": null,\n \"redis_password\": null,\n \"year\": null,\n \"redis_database\": 0,\n \"hour\": 500,\n \"redis_port\": 6379,\n \"redis_host\": null,\n \"fault_tolerant\": true\n },\n \"service\": null,\n \"enabled\": true,\n \"protocols\": [\n \"https\",\n \"http\"\n ],\n \"name\": \"rate-limiting\",\n \"consumer\": null,\n \"route\": {\n \"id\": \"875973fd-ba3f-4c7b-8301-e9263013e6d2\"\n },\n \"tags\": [\n \"admin\",\n \"high-priority\",\n \"critical\"\n ]\n}" + }, + "url": { + "raw": "{{gateway}}/services/:serviceNameOrId/plugins/:pluginId", + "host": [ + "{{gateway}}" + ], + "path": [ + "services", + ":serviceNameOrId", + "plugins", + ":pluginId" + ], + "variable": [ + { + "key": "serviceNameOrId", + "value": "", + "description": "The unique identifier or the name of the Service to update." + }, + { + "key": "pluginId", + "value": "", + "description": "The unique identifier of the Plugin to update." + } + ] + }, + "description": "# Create Or Update Plugin Associated to a Specific Service [konghq](https://docs.konghq.com/2.0.x/admin-api/#create-or-update-plugin-associated-to-a-specific-service)\n* Inserts (or replaces) the Plugin under the requested resource with the definition specified in the body. The Plugin will be identified via the name or id attribute.\n* When the name or id attribute has the structure of a UUID, the Plugin being inserted/replaced will be identified by its id. Otherwise it will be identified by its name.\n* When creating a new Plugin without specifying id (neither in the URL nor in the body), then it will be auto-generated.\n* Notice that specifying a name in the URL and a different one in the request body is not allowed.\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
AttributesMandatoryDescription
service name or idrequiredThe unique identifier or the name of the Service to update.
plugin idrequiredThe unique identifier of the Plugin to update.
\n\n# Request Body\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
AttributesMandatoryDescription
namerequiredThe name of the Plugin that’s going to be added. Currently the Plugin must be installed in every Kong instance separately.
routeoptionalIf set, the plugin will only activate when receiving requests via the specified route. Leave unset for the plugin to activate regardless of the Route being used. Defaults to null.With form-encoded, the notation is route.id= or route.name=. With JSON, use “\"route\":{\"id\":\"\"} or \"route\":{\"name\":\"\"}.
serviceoptionalIf set, the plugin will only activate when receiving requests via one of the routes belonging to the specified Service. Leave unset for the plugin to activate regardless of the Service being matched. Defaults to null.With form-encoded, the notation is service.id= or service.name=. With JSON, use “\"service\":{\"id\":\"\"} or \"service\":{\"name\":\"\"}.
consumeroptionalIf set, the plugin will activate only for requests where the specified has been authenticated. (Note that some plugins can not be restricted to consumers this way.). Leave unset for the plugin to activate regardless of the authenticated consumer. Defaults to null.With form-encoded, the notation is consumer.id= or consumer.username=. With JSON, use “\"consumer\":{\"id\":\"\"} or \"consumer\":{\"username\":\"\"}.
configoptionalThe configuration properties for the Plugin which can be found on the plugins documentation page in the Kong Hub.
protocolsrequiredA list of the request protocols that will trigger this plugin. The default value, as well as the possible values allowed on this field, may change depending on the plugin type. For example, plugins that only work in stream mode will only support \"tcp\" and \"tls\". Defaults to [\"grpc\", \"grpcs\", \"http\", \"https\"].
enabledoptionalWhether the plugin is applied. Defaults to true.
tagsoptionalAn optional set of strings associated with the Plugin, for grouping and filtering.
" + }, + "response": [] + }, + { + "name": "Create Or Update Plugin Associated to a Specific Consumer", + "request": { + "method": "PUT", + "header": [ + { + "name": "Content-Type", + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"config\": {\n \"minute\": 20,\n \"policy\": \"cluster\",\n \"month\": null,\n \"redis_timeout\": 2000,\n \"limit_by\": \"consumer\",\n \"hide_client_headers\": false,\n \"second\": null,\n \"day\": null,\n \"redis_password\": null,\n \"year\": null,\n \"redis_database\": 0,\n \"hour\": 500,\n \"redis_port\": 6379,\n \"redis_host\": null,\n \"fault_tolerant\": true\n },\n \"service\": null,\n \"enabled\": true,\n \"protocols\": [\n \"https\",\n \"http\"\n ],\n \"name\": \"rate-limiting\",\n \"consumer\": null,\n \"route\": {\n \"id\": \"875973fd-ba3f-4c7b-8301-e9263013e6d2\"\n },\n \"tags\": [\n \"admin\",\n \"high-priority\",\n \"critical\"\n ]\n}" + }, + "url": { + "raw": "{{gateway}}/consumers/:consumerUsernameOrd}/plugins/:pluginId", + "host": [ + "{{gateway}}" + ], + "path": [ + "consumers", + ":consumerUsernameOrd}", + "plugins", + ":pluginId" + ], + "variable": [ + { + "key": "consumerUsernameOrd}", + "value": "", + "description": "The unique identifier or the username of the Consumer to update" + }, + { + "key": "pluginId", + "value": "", + "description": "The unique identifier of the Plugin to update." + } + ] + }, + "description": "# Create Or Update Plugin Associated to a Specific Consumer [konghq](https://docs.konghq.com/2.0.x/admin-api/#create-or-update-plugin-associated-to-a-specific-consumer)\n* Inserts (or replaces) the Plugin under the requested resource with the definition specified in the body. The Plugin will be identified via the name or id attribute.\n* When the name or id attribute has the structure of a UUID, the Plugin being inserted/replaced will be identified by its id. Otherwise it will be identified by its name.\n* When creating a new Plugin without specifying id (neither in the URL nor in the body), then it will be auto-generated.\n* Notice that specifying a name in the URL and a different one in the request body is not allowed.\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
AttributesMandatoryDescription
consumer username or idrequiredThe unique identifier or the username of the Consumer to update.
plugin idrequiredThe unique identifier of the Plugin to update.
\n\n# Request Body\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
AttributesMandatoryDescription
namerequiredThe name of the Plugin that’s going to be added. Currently the Plugin must be installed in every Kong instance separately.
routeoptionalIf set, the plugin will only activate when receiving requests via the specified route. Leave unset for the plugin to activate regardless of the Route being used. Defaults to null.With form-encoded, the notation is route.id= or route.name=. With JSON, use “\"route\":{\"id\":\"\"} or \"route\":{\"name\":\"\"}.
serviceoptionalIf set, the plugin will only activate when receiving requests via one of the routes belonging to the specified Service. Leave unset for the plugin to activate regardless of the Service being matched. Defaults to null.With form-encoded, the notation is service.id= or service.name=. With JSON, use “\"service\":{\"id\":\"\"} or \"service\":{\"name\":\"\"}.
consumeroptionalIf set, the plugin will activate only for requests where the specified has been authenticated. (Note that some plugins can not be restricted to consumers this way.). Leave unset for the plugin to activate regardless of the authenticated consumer. Defaults to null.With form-encoded, the notation is consumer.id= or consumer.username=. With JSON, use “\"consumer\":{\"id\":\"\"} or \"consumer\":{\"username\":\"\"}.
configoptionalThe configuration properties for the Plugin which can be found on the plugins documentation page in the Kong Hub.
protocolsrequiredA list of the request protocols that will trigger this plugin. The default value, as well as the possible values allowed on this field, may change depending on the plugin type. For example, plugins that only work in stream mode will only support \"tcp\" and \"tls\". Defaults to [\"grpc\", \"grpcs\", \"http\", \"https\"].
enabledoptionalWhether the plugin is applied. Defaults to true.
tagsoptionalAn optional set of strings associated with the Plugin, for grouping and filtering.
" + }, + "response": [] + } + ], + "description": "https://docs.konghq.com/2.0.x/admin-api/#update-or-create-plugin\n\n* Inserts (or replaces) the Plugin under the requested resource with the definition specified in the body. The Plugin will be identified via the name or id attribute.\n\n* When the name or id attribute has the structure of a UUID, the Plugin being inserted/replaced will be identified by its id. Otherwise it will be identified by its name.\n\n* When creating a new Plugin without specifying id (neither in the URL nor in the body), then it will be auto-generated.\n\n* Notice that specifying a name in the URL and a different one in the request body is not allowed.", + "event": [ + { + "listen": "prerequest", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + }, + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + } + ] + }, + { + "name": "Delete Plugin", + "item": [ + { + "name": "Delete Plugin", + "request": { + "method": "DELETE", + "header": [], + "body": { + "mode": "raw", + "raw": "" + }, + "url": { + "raw": "{{gateway}}/plugins/:pluginId", + "host": [ + "{{gateway}}" + ], + "path": [ + "plugins", + ":pluginId" + ], + "variable": [ + { + "key": "pluginId", + "value": "9175fd5b-e364-4759-bbe2-e7d00da5edd2", + "description": "The unique identifier of the Plugin to delete" + } + ] + }, + "description": "# Delete Plugin [konghq](https://docs.konghq.com/2.0.x/admin-api/#delete-plugin-1)\n\n\n \n \n \n \n \n \n \n \n \n \n
AttributesMandatoryDescription
plugin idrequiredThe unique identifier of the Plugin to delete.
" + }, + "response": [ + { + "name": "Delete Plugin - 204", + "originalRequest": { + "method": "DELETE", + "header": [], + "body": { + "mode": "raw", + "raw": "" + }, + "url": { + "raw": "{{gateway}}/plugins/:pluginId", + "host": [ + "{{gateway}}" + ], + "path": [ + "plugins", + ":pluginId" + ], + "variable": [ + { + "key": "pluginId", + "value": "9175fd5b-e364-4759-bbe2-e7d00da5edd2", + "description": "The unique identifier of the Plugin to delete" + } + ] + } + }, + "status": "No Content", + "code": 204, + "_postman_previewlanguage": "Text", + "header": [ + { + "key": "Date", + "value": "Thu, 12 Mar 2020 12:14:32 GMT" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "Server", + "value": "kong/2.0.1" + }, + { + "key": "X-Kong-Admin-Latency", + "value": "17" + } + ], + "cookie": [], + "body": "" + } + ] + }, + { + "name": "Delete Plugin Associated to a Specific Route", + "request": { + "method": "DELETE", + "header": [], + "body": { + "mode": "raw", + "raw": "" + }, + "url": { + "raw": "{{gateway}}/routes/:routeNameOrId/plugins/:pluginId", + "host": [ + "{{gateway}}" + ], + "path": [ + "routes", + ":routeNameOrId", + "plugins", + ":pluginId" + ], + "variable": [ + { + "key": "routeNameOrId", + "value": "875973fd-ba3f-4c7b-8301-e9263013e6d2", + "description": "The unique identifier or the name of the Route to delete." + }, + { + "key": "pluginId", + "value": "9175fd5b-e364-4759-bbe2-e7d00da5edd2", + "description": "The unique identifier of the Plugin to delete." + } + ] + }, + "description": "# Delete Plugin Associated to a Specific Route [konghq](https://docs.konghq.com/2.0.x/admin-api/#delete-plugin-associated-to-a-specific-route)\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
AttributesMandatoryDescription
route name or idrequiredThe unique identifier or the name of the Route to delete.
plugin idrequiredThe unique identifier of the Plugin to delete.
" + }, + "response": [ + { + "name": "Update Plugin Associated to a Specific Route", + "originalRequest": { + "method": "PATCH", + "header": [ + { + "name": "Content-Type", + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"created_at\": 1583998823,\n \"config\": {\n \"minute\": 20,\n \"policy\": \"cluster\",\n \"month\": null,\n \"redis_timeout\": 2000,\n \"limit_by\": \"consumer\",\n \"hide_client_headers\": false,\n \"second\": null,\n \"day\": null,\n \"redis_password\": null,\n \"year\": null,\n \"redis_database\": 0,\n \"hour\": 500,\n \"redis_port\": 6379,\n \"redis_host\": null,\n \"fault_tolerant\": true\n },\n \"id\": \"9175fd5b-e364-4759-bbe2-e7d00da5edd2\",\n \"service\": null,\n \"enabled\": true,\n \"protocols\": [\n \"https\",\n \"http\"\n ],\n \"name\": \"rate-limiting\",\n \"consumer\": null,\n \"route\": {\n \"id\": \"875973fd-ba3f-4c7b-8301-e9263013e6d2\"\n },\n \"tags\": [\n \"admin\",\n \"high-priority\",\n \"critical\"\n ]\n}" + }, + "url": { + "raw": "{{gateway}}/routes/:routeNameOrId/plugins/:pluginId", + "host": [ + "{{gateway}}" + ], + "path": [ + "routes", + ":routeNameOrId", + "plugins", + ":pluginId" + ], + "variable": [ + { + "key": "routeNameOrId", + "value": "875973fd-ba3f-4c7b-8301-e9263013e6d2", + "description": "The unique identifier or the name of the Route to update." + }, + { + "key": "pluginId", + "value": "9175fd5b-e364-4759-bbe2-e7d00da5edd2", + "description": "The unique identifier of the Plugin to update." + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "Text", + "header": [ + { + "key": "Date", + "value": "Thu, 12 Mar 2020 11:23:03 GMT" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "Server", + "value": "kong/2.0.1" + }, + { + "key": "Content-Length", + "value": "538" + }, + { + "key": "X-Kong-Admin-Latency", + "value": "15" + } + ], + "cookie": [], + "body": "{\n \"config\": {\n \"minute\": 20,\n \"policy\": \"cluster\",\n \"month\": null,\n \"redis_timeout\": 2000,\n \"limit_by\": \"consumer\",\n \"hide_client_headers\": false,\n \"second\": null,\n \"day\": null,\n \"redis_password\": null,\n \"year\": null,\n \"redis_database\": 0,\n \"hour\": 500,\n \"redis_port\": 6379,\n \"redis_host\": null,\n \"fault_tolerant\": true\n },\n \"service\": null,\n \"enabled\": true,\n \"protocols\": [\n \"https\",\n \"http\"\n ],\n \"name\": \"rate-limiting\",\n \"consumer\": null,\n \"route\": {\n \"id\": \"875973fd-ba3f-4c7b-8301-e9263013e6d2\"\n },\n \"tags\": [\n \"admin\",\n \"high-priority\",\n \"critical\"\n ]\n}" + } + ] + }, + { + "name": "Delete Plugin Associated to a Specific Service", + "request": { + "method": "DELETE", + "header": [], + "body": { + "mode": "raw", + "raw": "" + }, + "url": { + "raw": "{{gateway}}/services/:serviceNameOrId/plugins/:pluginId", + "host": [ + "{{gateway}}" + ], + "path": [ + "services", + ":serviceNameOrId", + "plugins", + ":pluginId" + ], + "variable": [ + { + "key": "serviceNameOrId", + "value": "", + "description": "The unique identifier or the name of the Service to delete" + }, + { + "key": "pluginId", + "value": "", + "description": "The unique identifier of the Plugin to delete" + } + ] + }, + "description": "# Delete Plugin Associated to a Specific Service [konghq](https://docs.konghq.com/2.0.x/admin-api/#delete-plugin-associated-to-a-specific-service)\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
AttributesMandatoryDescription
service name or idrequiredThe unique identifier or the name of the Service to delete.
plugin idrequiredThe unique identifier of the Plugin to delete.
" + }, + "response": [] + }, + { + "name": "Delete Plugin Associated to a Specific Consumer", + "request": { + "method": "DELETE", + "header": [], + "body": { + "mode": "raw", + "raw": "" + }, + "url": { + "raw": "{{gateway}}/consumers/:consumerUsernameOrd}/plugins/:pluginId", + "host": [ + "{{gateway}}" + ], + "path": [ + "consumers", + ":consumerUsernameOrd}", + "plugins", + ":pluginId" + ], + "variable": [ + { + "key": "consumerUsernameOrd}", + "value": "", + "description": "The unique identifier or the username of the Consumer to delete" + }, + { + "key": "pluginId", + "value": "", + "description": "The unique identifier of the Plugin to delete" + } + ] + }, + "description": "# Delete Plugin Associated to a Specific Consumer [konghq](https://docs.konghq.com/2.0.x/admin-api/#delete-plugin-associated-to-a-specific-consumer)\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
AttributesMandatoryDescription
consumer username or idrequiredThe unique identifier or the username of the Consumer to delete.
plugin idrequiredThe unique identifier of the Plugin to delete.
" + }, + "response": [] + } + ], + "description": "https://docs.konghq.com/2.0.x/admin-api/#delete-plugin", + "event": [ + { + "listen": "prerequest", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + }, + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + } + ] + }, + { + "name": "Retrieve Plugin", + "item": [ + { + "name": "Retrieve Enabled Plugins", + "protocolProfileBehavior": { + "disableBodyPruning": true + }, + "request": { + "method": "GET", + "header": [], + "body": { + "mode": "raw", + "raw": "" + }, + "url": { + "raw": "{{gateway}}/plugins/enabled", + "host": [ + "{{gateway}}" + ], + "path": [ + "plugins", + "enabled" + ] + }, + "description": "# Retrieve Enabled Plugins [konghq](https://docs.konghq.com/2.0.x/admin-api/#retrieve-enabled-plugins)\n\nRetrieve a list of all installed plugins on the Kong node" + }, + "response": [ + { + "name": "Retrieve Enabled Plugins", + "originalRequest": { + "method": "GET", + "header": [], + "url": { + "raw": "{{gateway}}/plugins/enabled", + "host": [ + "{{gateway}}" + ], + "path": [ + "plugins", + "enabled" + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "Text", + "header": [ + { + "key": "Date", + "value": "Thu, 12 Mar 2020 13:05:38 GMT" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "Server", + "value": "kong/2.0.1" + }, + { + "key": "Content-Length", + "value": "465" + }, + { + "key": "X-Kong-Admin-Latency", + "value": "1" + } + ], + "cookie": [], + "body": "{\n \"enabled_plugins\": [\n \"correlation-id\",\n \"pre-function\",\n \"cors\",\n \"ldap-auth\",\n \"loggly\",\n \"hmac-auth\",\n \"zipkin\",\n \"request-size-limiting\",\n \"azure-functions\",\n \"request-transformer\",\n \"oauth2\",\n \"response-transformer\",\n \"ip-restriction\",\n \"statsd\",\n \"jwt\",\n \"proxy-cache\",\n \"basic-auth\",\n \"key-auth\",\n \"http-log\",\n \"datadog\",\n \"tcp-log\",\n \"post-function\",\n \"prometheus\",\n \"acl\",\n \"syslog\",\n \"file-log\",\n \"session\",\n \"udp-log\",\n \"response-ratelimiting\",\n \"aws-lambda\",\n \"bot-detection\",\n \"rate-limiting\",\n \"request-termination\"\n ]\n}" + } + ] + }, + { + "name": "Retrieve Plugin Schema", + "protocolProfileBehavior": { + "disableBodyPruning": true + }, + "request": { + "method": "GET", + "header": [], + "body": { + "mode": "raw", + "raw": "" + }, + "url": { + "raw": "{{gateway}}/plugins/schema/:pluginName", + "host": [ + "{{gateway}}" + ], + "path": [ + "plugins", + "schema", + ":pluginName" + ], + "variable": [ + { + "key": "pluginName", + "value": "basic-auth" + } + ] + }, + "description": "# Retrieve Plugin Schema [konghq](https://docs.konghq.com/2.0.x/admin-api/#retrieve-plugin-schema)\n* Retrieve the schema of a plugin’s configuration. This is useful to understand what fields a plugin accepts, and can be used for building third-party integrations to the Kong’s plugin system.\n\n\n \n \n \n \n \n \n \n \n \n \n
AttributesMandatoryDescription
plugin namerequiredThe Plugin name to retrieve
" + }, + "response": [ + { + "name": "Delete Plugin - 204", + "originalRequest": { + "method": "DELETE", + "header": [], + "body": { + "mode": "raw", + "raw": "" + }, + "url": { + "raw": "{{gateway}}/plugins/:pluginId", + "host": [ + "{{gateway}}" + ], + "path": [ + "plugins", + ":pluginId" + ], + "variable": [ + { + "key": "pluginId", + "value": "9175fd5b-e364-4759-bbe2-e7d00da5edd2", + "description": "The unique identifier of the Plugin to delete" + } + ] + } + }, + "status": "No Content", + "code": 204, + "_postman_previewlanguage": "Text", + "header": [ + { + "key": "Date", + "value": "Thu, 12 Mar 2020 12:14:32 GMT" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "Server", + "value": "kong/2.0.1" + }, + { + "key": "X-Kong-Admin-Latency", + "value": "17" + } + ], + "cookie": [], + "body": "" + }, + { + "name": "Retrieve Plugin Schema", + "originalRequest": { + "method": "GET", + "header": [], + "url": { + "raw": "{{gateway}}/plugins/schema/:pluginName", + "host": [ + "{{gateway}}" + ], + "path": [ + "plugins", + "schema", + ":pluginName" + ], + "variable": [ + { + "key": "pluginName", + "value": "basic-auth" + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "Text", + "header": [ + { + "key": "Date", + "value": "Thu, 12 Mar 2020 13:11:45 GMT" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "Server", + "value": "kong/2.0.1" + }, + { + "key": "Content-Length", + "value": "126" + }, + { + "key": "X-Kong-Admin-Latency", + "value": "0" + } + ], + "cookie": [], + "body": "{\r\n \"fields\": {\r\n \"hide_credentials\": {\r\n \"default\": false,\r\n \"type\": \"boolean\"\r\n },\r\n \"key_names\": {\r\n \"default\": \"function\",\r\n \"required\": true,\r\n \"type\": \"array\"\r\n }\r\n }\r\n}" + } + ] + } + ] + } + ], + "description": "https://docs.konghq.com/2.0.x/admin-api/#plugin-object\n\n* A Plugin entity represents a plugin configuration that will be executed during the HTTP request/response lifecycle. It is how you can add functionalities to Services that run behind Kong, like Authentication or Rate Limiting for example. You can find more information about how to install and what values each plugin takes by visiting the Kong Hub.\n\n* When adding a Plugin Configuration to a Service, every request made by a client to that Service will run said Plugin. If a Plugin needs to be tuned to different values for some specific Consumers, you can do so by creating a separate plugin instance that specifies both the Service and the Consumer, through the service and consumer fields.\n\n* Plugins can be both tagged and filtered by tags.\n\n{\n \"id\": \"ce44eef5-41ed-47f6-baab-f725cecf98c7\",\n \"name\": \"rate-limiting\",\n \"created_at\": 1422386534,\n \"route\": null,\n \"service\": null,\n \"consumer\": null,\n \"config\": {\"hour\":500, \"minute\":20},\n \"protocols\": [\"http\", \"https\"],\n \"enabled\": true,\n \"tags\": [\"user-level\", \"low-priority\"]\n}\n\n# Precedence\n\n* A plugin will always be run once and only once per request. But the configuration with which it will run depends on the entities it has been configured for.\n\n* Plugins can be configured for various entities, combination of entities, or even globally. This is useful, for example, when you wish to configure a plugin a certain way for most requests, but make authenticated requests behave slightly differently.\n\n* Therefore, there exists an order of precedence for running a plugin when it has been applied to different entities with different configurations. The rule of thumb is: the more specific a plugin is with regards to how many entities it has been configured on, the higher its priority.\n\n* The complete order of precedence when a plugin has been configured multiple times is:\n\n\t* Plugins configured on a combination of: a Route, a Service, and a Consumer. (Consumer means the request must be authenticated).\n\t* Plugins configured on a combination of a Route and a Consumer. (Consumer means the request must be authenticated).\n\t* Plugins configured on a combination of a Service and a Consumer. (Consumer means the request must be authenticated).\n\t* Plugins configured on a combination of a Route and a Service.\n\t*Plugins configured on a Consumer. (Consumer means the request must be authenticated).\n\t* Plugins configured on a Route.\n\t* Plugins configured on a Service.\n\t* Plugins configured to run globally.\n\n* Example: if the rate-limiting plugin is applied twice (with different configurations): for a Service (Plugin config A), and for a Consumer (Plugin config B), then requests authenticating this Consumer will run Plugin config B and ignore A. However, requests that do not authenticate this Consumer will fallback to running Plugin config A. Note that if config B is disabled (its enabled flag is set to false), config A will apply to requests that would have otherwise matched config B.", + "event": [ + { + "listen": "prerequest", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + }, + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + } + ] + }, + { + "name": "Certificate Object", + "item": [ + { + "name": "Add Certificate", + "item": [ + { + "name": "Create Certificate", + "request": { + "method": "POST", + "header": [ + { + "name": "Content-Type", + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"cert\": \"-----BEGIN CERTIFICATE-----...\",\n \"key\": \"-----BEGIN RSA PRIVATE KEY-----...\",\n \"tags\": [\n \"user-level\",\n \"low-priority\"\n ]\n}" + }, + "url": { + "raw": "{{gateway}}/certificates", + "host": [ + "{{gateway}}" + ], + "path": [ + "certificates" + ] + }, + "description": "# Create Certificate [konghq](https://docs.konghq.com/2.0.x/admin-api/#create-certificate)\n* A certificate object represents a public certificate, and can be optionally paired with the corresponding private key. These objects are used by Kong to handle SSL/TLS termination for encrypted requests, or for use as a trusted CA store when validating peer certificate of client/service. Certificates are optionally associated with SNI objects to tie a cert/key pair to one or more hostnames.\n* If intermediate certificates are required in addition to the main certificate, they should be concatenated together into one string according to the following order: main certificate on the top, followed by any intermediates.\n* Certificates can be both tagged and filtered by tags.\n\n\n# Request Body\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
AttributesMandatoryTypeDescription
certrequiredbodyPEM-encoded public certificate chain of the SSL key pair.
keyrequiredbodyPEM-encoded private key of the SSL key pair.
tagsoptionalbodyAn optional set of strings associated with the Certificate, for grouping and filtering.
snisoptionalbodyAn array of zero or more hostnames to associate with this certificate as SNIs. This is a sugar parameter that will, under the hood, create an SNI object and associate it with this certificate for your convenience. To set this attribute this certificate must have a valid private key associated with it.
" + }, + "response": [] + } + ], + "description": "https://docs.konghq.com/2.0.x/admin-api/#add-certificate", + "event": [ + { + "listen": "prerequest", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + }, + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + } + ] + }, + { + "name": "List Certificates", + "item": [ + { + "name": "List All Certificates", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{gateway}}/certificates", + "host": [ + "{{gateway}}" + ], + "path": [ + "certificates" + ] + }, + "description": "# List All Certificates [konghq](https://docs.konghq.com/2.0.x/admin-api/#list-all-certificates)" + }, + "response": [ + { + "name": "List All Certificates", + "originalRequest": { + "method": "GET", + "header": [], + "url": { + "raw": "{{gateway}}/certificates", + "host": [ + "{{gateway}}" + ], + "path": [ + "certificates" + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "Text", + "header": [ + { + "key": "Date", + "value": "Thu, 12 Mar 2020 15:08:32 GMT" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "Server", + "value": "kong/2.0.1" + }, + { + "key": "Content-Length", + "value": "23" + }, + { + "key": "X-Kong-Admin-Latency", + "value": "1" + } + ], + "cookie": [], + "body": "{\n\t\"data\": [\n\t\t{\n\t\t\t\"id\": \"d044b7d4-3dc2-4bbc-8e9f-6b7a69416df6\",\n\t\t\t\"created_at\": 1422386534,\n\t\t\t\"cert\": \"-----BEGIN CERTIFICATE-----...\",\n\t\t\t\"key\": \"-----BEGIN RSA PRIVATE KEY-----...\",\n\t\t\t\"tags\": [\n\t\t\t\t\"user-level\",\n\t\t\t\t\"low-priority\"\n\t\t\t]\n\t\t},\n\t\t{\n\t\t\t\"id\": \"a9b2107f-a214-47b3-add4-46b942187924\",\n\t\t\t\"created_at\": 1422386534,\n\t\t\t\"cert\": \"-----BEGIN CERTIFICATE-----...\",\n\t\t\t\"key\": \"-----BEGIN RSA PRIVATE KEY-----...\",\n\t\t\t\"tags\": [\n\t\t\t\t\"admin\",\n\t\t\t\t\"high-priority\",\n\t\t\t\t\"critical\"\n\t\t\t]\n\t\t}\n\t],\n\t\"next\": \"http://localhost:8001/certificates?offset=6378122c-a0a1-438d-a5c6-efabae9fb969\"\n}" + } + ] + } + ], + "description": "https://docs.konghq.com/2.0.x/admin-api/#list-certificates" + }, + { + "name": "Retrieve Certificate", + "item": [ + { + "name": "Retrieve Certificate", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{gateway}}/certificates/:certificateId", + "host": [ + "{{gateway}}" + ], + "path": [ + "certificates", + ":certificateId" + ], + "variable": [ + { + "key": "certificateId", + "value": "", + "description": "The unique identifier of the Certificate to retrieve." + } + ] + }, + "description": "# Retrieve Certificate [konghq](https://docs.konghq.com/2.0.x/admin-api/#retrieve-certificate-1)\n\n \n \n \n \n \n \n \n \n \n \n \n \n
AttributesMandatoryTypeDescription
certificate idrequiredpathThe unique identifier of the Certificate to retrieve.
" + }, + "response": [ + { + "name": "Retrieve Certificate", + "originalRequest": { + "method": "GET", + "header": [], + "url": { + "raw": "{{gateway}}/certificates/:certificateId", + "host": [ + "{{gateway}}" + ], + "path": [ + "certificates", + ":certificateId" + ], + "variable": [ + { + "key": "certificateId", + "value": "", + "description": "The unique identifier of the Certificate to retrieve." + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "Text", + "header": [ + { + "key": "Date", + "value": "Thu, 12 Mar 2020 15:17:18 GMT" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "Server", + "value": "kong/2.0.1" + }, + { + "key": "Content-Length", + "value": "23" + }, + { + "key": "X-Kong-Admin-Latency", + "value": "1" + } + ], + "cookie": [], + "body": "{\r\n \"id\": \"7fca84d6-7d37-4a74-a7b0-93e576089a41\",\r\n \"created_at\": 1422386534,\r\n \"cert\": \"-----BEGIN CERTIFICATE-----...\",\r\n \"key\": \"-----BEGIN RSA PRIVATE KEY-----...\",\r\n \"tags\": [\"user-level\", \"low-priority\"]\r\n}" + } + ] + } + ], + "description": "https://docs.konghq.com/2.0.x/admin-api/#retrieve-certificate", + "event": [ + { + "listen": "prerequest", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + }, + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + } + ] + }, + { + "name": "Update Certificate", + "item": [ + { + "name": "Update Certificate", + "request": { + "method": "POST", + "header": [ + { + "name": "Content-Type", + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"cert\": \"-----BEGIN CERTIFICATE-----...\",\n \"key\": \"-----BEGIN RSA PRIVATE KEY-----...\",\n \"tags\": [\n \"user-level\",\n \"low-priority\"\n ]\n}" + }, + "url": { + "raw": "{{gateway}}/certificates/:certificateId", + "host": [ + "{{gateway}}" + ], + "path": [ + "certificates", + ":certificateId" + ], + "variable": [ + { + "key": "certificateId", + "value": "", + "description": "The unique identifier of the Certificate to update." + } + ] + }, + "description": "# Update Certificate [konghq](https://docs.konghq.com/2.0.x/admin-api/#update-certificate-1)\n* A certificate object represents a public certificate, and can be optionally paired with the corresponding private key. These objects are used by Kong to handle SSL/TLS termination for encrypted requests, or for use as a trusted CA store when validating peer certificate of client/service. Certificates are optionally associated with SNI objects to tie a cert/key pair to one or more hostnames.\n* If intermediate certificates are required in addition to the main certificate, they should be concatenated together into one string according to the following order: main certificate on the top, followed by any intermediates.\n* Certificates can be both tagged and filtered by tags.\n\n# Path parameters\n\n \n \n \n \n \n \n \n \n \n \n \n \n
AttributesMandatoryTypeDescription
certificate idrequiredpathThe unique identifier of the Certificate to update.
\n\n# Request Body\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
AttributesMandatoryTypeDescription
certrequiredbodyPEM-encoded public certificate chain of the SSL key pair.
keyrequiredbodyPEM-encoded private key of the SSL key pair.
tagsoptionalbodyAn optional set of strings associated with the Certificate, for grouping and filtering.
snisoptionalbodyAn array of zero or more hostnames to associate with this certificate as SNIs. This is a sugar parameter that will, under the hood, create an SNI object and associate it with this certificate for your convenience. To set this attribute this certificate must have a valid private key associated with it.
" + }, + "response": [] + } + ], + "description": "https://docs.konghq.com/2.0.x/admin-api/#update-certificate", + "event": [ + { + "listen": "prerequest", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + }, + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + } + ] + }, + { + "name": "Update Or Create Certificate", + "item": [ + { + "name": "Create Or Update Certificate", + "request": { + "method": "PUT", + "header": [ + { + "name": "Content-Type", + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"cert\": \"-----BEGIN CERTIFICATE-----...\",\n \"key\": \"-----BEGIN RSA PRIVATE KEY-----...\",\n \"tags\": [\n \"user-level\",\n \"low-priority\"\n ]\n}" + }, + "url": { + "raw": "{{gateway}}/certificates/:certificateId", + "host": [ + "{{gateway}}" + ], + "path": [ + "certificates", + ":certificateId" + ], + "variable": [ + { + "key": "certificateId", + "value": "", + "description": "The unique identifier of the Certificate to update." + } + ] + }, + "description": "# Create Or Update Certificate [konghq](https://docs.konghq.com/2.0.x/admin-api/#create-or-update-certificate)\n* A certificate object represents a public certificate, and can be optionally paired with the corresponding private key. These objects are used by Kong to handle SSL/TLS termination for encrypted requests, or for use as a trusted CA store when validating peer certificate of client/service. Certificates are optionally associated with SNI objects to tie a cert/key pair to one or more hostnames.\n* If intermediate certificates are required in addition to the main certificate, they should be concatenated together into one string according to the following order: main certificate on the top, followed by any intermediates.\n* Certificates can be both tagged and filtered by tags.\n\n* Inserts (or replaces) the Certificate under the requested resource with the definition specified in the body. The Certificate will be identified via the name or id attribute.\n* When the name or id attribute has the structure of a UUID, the Certificate being inserted/replaced will be identified by its id. Otherwise it will be identified by its name.\n* When creating a new Certificate without specifying id (neither in the URL nor in the body), then it will be auto-generated.\n* Notice that specifying a name in the URL and a different one in the request body is not allowed.\n\n# Path parameters\n\n \n \n \n \n \n \n \n \n \n \n \n \n
AttributesMandatoryTypeDescription
certificate idrequiredpathThe unique identifier of the Certificate to create or update.
\n\n# Request Body\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
AttributesMandatoryTypeDescription
certrequiredbodyPEM-encoded public certificate chain of the SSL key pair.
keyrequiredbodyPEM-encoded private key of the SSL key pair.
tagsoptionalbodyAn optional set of strings associated with the Certificate, for grouping and filtering.
snisoptionalbodyAn array of zero or more hostnames to associate with this certificate as SNIs. This is a sugar parameter that will, under the hood, create an SNI object and associate it with this certificate for your convenience. To set this attribute this certificate must have a valid private key associated with it.
" + }, + "response": [] + } + ], + "description": "https://docs.konghq.com/2.0.x/admin-api/#update-or-create-certificate", + "event": [ + { + "listen": "prerequest", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + }, + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + } + ] + }, + { + "name": "Delete Certificate", + "item": [ + { + "name": "Delete Certificate", + "request": { + "method": "DELETE", + "header": [], + "body": { + "mode": "raw", + "raw": "" + }, + "url": { + "raw": "{{gateway}}/certificates/:certificateId", + "host": [ + "{{gateway}}" + ], + "path": [ + "certificates", + ":certificateId" + ], + "variable": [ + { + "key": "certificateId", + "value": "", + "description": "The unique identifier of the Certificate to delete" + } + ] + }, + "description": "# Delete Certificate [konghq](https://docs.konghq.com/2.0.x/admin-api/#delete-certificate-1)\n\n# Path parameters\n\n \n \n \n \n \n \n \n \n \n \n \n \n
AttributesMandatoryTypeDescription
certificate idrequiredpathThe unique identifier of the Certificate to delete
" + }, + "response": [ + { + "name": "Delete Certificate - 404", + "originalRequest": { + "method": "DELETE", + "header": [], + "body": { + "mode": "raw", + "raw": "" + }, + "url": { + "raw": "{{gateway}}/certificates/:certificateId", + "host": [ + "{{gateway}}" + ], + "path": [ + "certificates", + ":certificateId" + ], + "variable": [ + { + "key": "certificateId", + "value": "kkkkk", + "description": "The unique identifier of the Certificate to delete" + } + ] + } + }, + "status": "Not Found", + "code": 404, + "_postman_previewlanguage": "Text", + "header": [ + { + "key": "Date", + "value": "Thu, 12 Mar 2020 15:49:31 GMT" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "Server", + "value": "kong/2.0.1" + }, + { + "key": "Content-Length", + "value": "27" + }, + { + "key": "X-Kong-Admin-Latency", + "value": "2" + } + ], + "cookie": [], + "body": "{\n \"message\": \"SNI not found\"\n}" + } + ] + } + ], + "description": "https://docs.konghq.com/2.0.x/admin-api/#delete-certificate", + "event": [ + { + "listen": "prerequest", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + }, + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + } + ] + } + ], + "description": "https://docs.konghq.com/2.0.x/admin-api/#certificate-object\n\nA certificate object represents a public certificate, and can be optionally paired with the corresponding private key. These objects are used by Kong to handle SSL/TLS termination for encrypted requests, or for use as a trusted CA store when validating peer certificate of client/service. Certificates are optionally associated with SNI objects to tie a cert/key pair to one or more hostnames.\n\nIf intermediate certificates are required in addition to the main certificate, they should be concatenated together into one string according to the following order: main certificate on the top, followed by any intermediates.\n\nCertificates can be both tagged and filtered by tags.\n\n{\n \"id\": \"7fca84d6-7d37-4a74-a7b0-93e576089a41\",\n \"created_at\": 1422386534,\n \"cert\": \"-----BEGIN CERTIFICATE-----...\",\n \"key\": \"-----BEGIN RSA PRIVATE KEY-----...\",\n \"tags\": [\"user-level\", \"low-priority\"]\n}", + "event": [ + { + "listen": "prerequest", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + }, + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + } + ] + }, + { + "name": "CA Certificate Object", + "item": [ + { + "name": "Add CA Certificate", + "item": [ + { + "name": "Create CA Certificate", + "request": { + "method": "POST", + "header": [ + { + "name": "Content-Type", + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"cert\": \"-----BEGIN CERTIFICATE----------END CERTIFICATE-----\",\n \"tags\": [\n \"user-level\",\n \"low-priority\"\n ]\n}" + }, + "url": { + "raw": "{{gateway}}/ca_certificates", + "host": [ + "{{gateway}}" + ], + "path": [ + "ca_certificates" + ] + }, + "description": "# Create CA Certificate [konghq](https://docs.konghq.com/2.0.x/admin-api/#create-ca-certificate)\n\n# Request Body\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
AttributesMandatoryTypeDescription
certrequiredbodyPEM-encoded public certificate of the CA.
tagsoptionalbodyAn optional set of strings associated with the Certificate, for grouping and filtering.
" + }, + "response": [ + { + "name": "Create CA Certificate - 201", + "originalRequest": { + "method": "POST", + "header": [ + { + "name": "Content-Type", + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"cert\": \"-----BEGIN CERTIFICATE----------END CERTIFICATE-----\",\n \"tags\": [\n \"user-level\",\n \"low-priority\"\n ]\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{gateway}}/ca_certificates", + "host": [ + "{{gateway}}" + ], + "path": [ + "ca_certificates" + ] + } + }, + "status": "Created", + "code": 201, + "_postman_previewlanguage": "Text", + "header": [ + { + "key": "Date", + "value": "Thu, 12 Mar 2020 16:02:47 GMT" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "Server", + "value": "kong/2.0.1" + }, + { + "key": "Content-Length", + "value": "315" + }, + { + "key": "X-Kong-Admin-Latency", + "value": "0" + } + ], + "cookie": [], + "body": "{\r\n \"id\": \"04fbeacf-a9f1-4a5d-ae4a-b0407445db3f\",\r\n \"created_at\": 1422386534,\r\n \"cert\": \"-----BEGIN CERTIFICATE-----...\",\r\n \"tags\": [\"user-level\", \"low-priority\"]\r\n}" + }, + { + "name": "Create CA Certificate - 400", + "originalRequest": { + "method": "POST", + "header": [ + { + "name": "Content-Type", + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"cert\": \"-----BEGIN CERTIFICATE-----dsfdfad-----END CERTIFICATE-----\",\n \"tags\": [\n \"user-level\",\n \"low-priority\"\n ]\n}" + }, + "url": { + "raw": "{{gateway}}/ca_certificates", + "host": [ + "{{gateway}}" + ], + "path": [ + "ca_certificates" + ] + } + }, + "status": "Bad Request", + "code": 400, + "_postman_previewlanguage": "Text", + "header": [ + { + "key": "Date", + "value": "Thu, 12 Mar 2020 16:00:21 GMT" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "Server", + "value": "kong/2.0.1" + }, + { + "key": "Content-Length", + "value": "315" + }, + { + "key": "X-Kong-Admin-Latency", + "value": "0" + } + ], + "cookie": [], + "body": "{\n \"message\": \"schema violation (cert: invalid certificate: x509.new: pem/pem_lib.c:812:error:0908F070:PEM routines:get_header_and_data:short header)\",\n \"name\": \"schema violation\",\n \"fields\": {\n \"cert\": \"invalid certificate: x509.new: pem/pem_lib.c:812:error:0908F070:PEM routines:get_header_and_data:short header\"\n },\n \"code\": 2\n}" + } + ] + } + ], + "description": "https://docs.konghq.com/2.0.x/admin-api/#add-ca-certificate", + "event": [ + { + "listen": "prerequest", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + }, + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + } + ] + }, + { + "name": "List CA Certificates", + "item": [ + { + "name": "List All CA Certificates", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{gateway}}/ca_certificates", + "host": [ + "{{gateway}}" + ], + "path": [ + "ca_certificates" + ] + }, + "description": "# List All CA Certificates [konghq](https://docs.konghq.com/2.0.x/admin-api/#list-all-ca-certificates)" + }, + "response": [ + { + "name": "List All CA Certificates", + "originalRequest": { + "method": "GET", + "header": [], + "url": { + "raw": "{{gateway}}/ca_certificates", + "host": [ + "{{gateway}}" + ], + "path": [ + "ca_certificates" + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "Text", + "header": [ + { + "key": "Date", + "value": "Thu, 12 Mar 2020 15:53:48 GMT" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "Server", + "value": "kong/2.0.1" + }, + { + "key": "Content-Length", + "value": "23" + }, + { + "key": "X-Kong-Admin-Latency", + "value": "3" + } + ], + "cookie": [], + "body": "{\n\t\"data\": [\n\t\t{\n\t\t\t\"id\": \"43429efd-b3a5-4048-94cb-5cc4029909bb\",\n\t\t\t\"created_at\": 1422386534,\n\t\t\t\"cert\": \"-----BEGIN CERTIFICATE-----...\",\n\t\t\t\"tags\": [\n\t\t\t\t\"user-level\",\n\t\t\t\t\"low-priority\"\n\t\t\t]\n\t\t},\n\t\t{\n\t\t\t\"id\": \"d26761d5-83a4-4f24-ac6c-cff276f2b79c\",\n\t\t\t\"created_at\": 1422386534,\n\t\t\t\"cert\": \"-----BEGIN CERTIFICATE-----...\",\n\t\t\t\"tags\": [\n\t\t\t\t\"admin\",\n\t\t\t\t\"high-priority\",\n\t\t\t\t\"critical\"\n\t\t\t]\n\t\t}\n\t],\n\t\"next\": \"http://localhost:8001/ca_certificates?offset=6378122c-a0a1-438d-a5c6-efabae9fb969\"\n}" + } + ] + } + ], + "description": "https://docs.konghq.com/2.0.x/admin-api/#list-ca-certificates", + "event": [ + { + "listen": "prerequest", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + }, + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + } + ] + }, + { + "name": "Retrieve CA Certificate", + "item": [ + { + "name": "Retrieve CA Certificate", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{gateway}}/ca_certificates/:ca_certificateId", + "host": [ + "{{gateway}}" + ], + "path": [ + "ca_certificates", + ":ca_certificateId" + ], + "variable": [ + { + "key": "ca_certificateId", + "value": "" + } + ] + }, + "description": "# Retrieve CA Certificate [konghq](https://docs.konghq.com/2.0.x/admin-api/#retrieve-ca-certificate-1)\n\n \n \n \n \n \n \n \n \n \n \n \n \n
AttributesMandatoryTypeDescription
ca_certificate idrequiredpathThe unique identifier of the CA Certificate to retrieve.
" + }, + "response": [ + { + "name": "Retrieve CA Certificate - 400", + "originalRequest": { + "method": "GET", + "header": [], + "url": { + "raw": "{{gateway}} /ca_certificates/:ca_certificateId", + "host": [ + "{{gateway}} " + ], + "path": [ + "ca_certificates", + ":ca_certificateId" + ], + "variable": [ + { + "key": "ca_certificateId", + "value": "as", + "description": "The unique identifier of the CA Certificate to retrieve." + } + ] + } + }, + "status": "Bad Request", + "code": 400, + "_postman_previewlanguage": "Text", + "header": [ + { + "key": "Server", + "value": "openresty" + }, + { + "key": "Date", + "value": "Thu, 12 Mar 2020 16:07:38 GMT" + }, + { + "key": "Content-Type", + "value": "text/html; charset=UTF-8" + }, + { + "key": "Content-Length", + "value": "122" + }, + { + "key": "Connection", + "value": "close" + } + ], + "cookie": [], + "body": "\n \n 400 Bad Request\n \n \n

\n

400 Bad Request

\n
\n \n" + }, + { + "name": "Retrieve Certificate", + "originalRequest": { + "method": "GET", + "header": [], + "url": { + "raw": "{{gateway}}/certificates/:certificateId", + "host": [ + "{{gateway}}" + ], + "path": [ + "certificates", + ":certificateId" + ], + "variable": [ + { + "key": "certificateId", + "value": "", + "description": "The unique identifier of the Certificate to retrieve." + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "Text", + "header": [ + { + "key": "Date", + "value": "Thu, 12 Mar 2020 15:17:18 GMT" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "Server", + "value": "kong/2.0.1" + }, + { + "key": "Content-Length", + "value": "23" + }, + { + "key": "X-Kong-Admin-Latency", + "value": "1" + } + ], + "cookie": [], + "body": "{\r\n \"id\": \"7fca84d6-7d37-4a74-a7b0-93e576089a41\",\r\n \"created_at\": 1422386534,\r\n \"cert\": \"-----BEGIN CERTIFICATE-----...\",\r\n \"key\": \"-----BEGIN RSA PRIVATE KEY-----...\",\r\n \"tags\": [\"user-level\", \"low-priority\"]\r\n}" + }, + { + "name": "Retrieve CA Certificate - 200", + "originalRequest": { + "method": "GET", + "header": [], + "url": { + "raw": "{{gateway}}/ca_certificates/:ca_certificateId", + "host": [ + "{{gateway}}" + ], + "path": [ + "ca_certificates", + ":ca_certificateId" + ], + "variable": [ + { + "key": "ca_certificateId", + "value": "" + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "Text", + "header": [ + { + "key": "Date", + "value": "Thu, 12 Mar 2020 16:10:31 GMT" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "Server", + "value": "kong/2.0.1" + }, + { + "key": "Content-Length", + "value": "23" + }, + { + "key": "X-Kong-Admin-Latency", + "value": "0" + } + ], + "cookie": [], + "body": "{\n \"id\": \"04fbeacf-a9f1-4a5d-ae4a-b0407445db3f\",\n \"created_at\": 1422386534,\n \"cert\": \"-----BEGIN CERTIFICATE-----...\",\n \"tags\": [\n \"user-level\",\n \"low-priority\"\n ],\n \"key\": \"incididunt Lorem elit\"\n}" + } + ] + } + ], + "description": "https://docs.konghq.com/2.0.x/admin-api/#retrieve-ca-certificate", + "event": [ + { + "listen": "prerequest", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + }, + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + } + ] + }, + { + "name": "Update CA Certificate", + "item": [ + { + "name": "Update CA Certificate", + "request": { + "method": "PATCH", + "header": [ + { + "name": "Content-Type", + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"cert\": \"-----BEGIN CERTIFICATE----------END CERTIFICATE-----\",\n \"tags\": [\n \"user-level\",\n \"low-priority\"\n ]\n}" + }, + "url": { + "raw": "{{gateway}}/ca_certificates/:ca_certificateId", + "host": [ + "{{gateway}}" + ], + "path": [ + "ca_certificates", + ":ca_certificateId" + ], + "variable": [ + { + "key": "ca_certificateId", + "value": "" + } + ] + }, + "description": "# Update CA Certificate [konghq](https://docs.konghq.com/2.0.x/admin-api/#update-ca-certificate-1)\n\n \n \n \n \n \n \n \n \n \n \n \n \n
AttributesMandatoryTypeDescription
ca_certificate idrequiredpathThe unique identifier of the CA Certificate to update.
\n\n# Request Body\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
AttributesMandatoryTypeDescription
certrequiredbodyPEM-encoded public certificate of the CA.
tagsoptionalbodyAn optional set of strings associated with the Certificate, for grouping and filtering.
" + }, + "response": [] + } + ], + "description": "https://docs.konghq.com/2.0.x/admin-api/#update-ca-certificate", + "event": [ + { + "listen": "prerequest", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + }, + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + } + ] + }, + { + "name": "Update Or Create CA Certificate", + "item": [ + { + "name": "Create Or Update CA Certificate", + "request": { + "method": "PUT", + "header": [ + { + "name": "Content-Type", + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"cert\": \"-----BEGIN CERTIFICATE-----...\",\n \"tags\": [\n \"user-level\",\n \"low-priority\"\n ]\n}" + }, + "url": { + "raw": "{{gateway}}/ca_certificates/:ca_certificateId", + "host": [ + "{{gateway}}" + ], + "path": [ + "ca_certificates", + ":ca_certificateId" + ], + "variable": [ + { + "key": "ca_certificateId", + "value": "", + "description": "The unique identifier of the CA Certificate to create or update." + } + ] + }, + "description": "# Create Or Update CA Certificate [konghq](https://docs.konghq.com/2.0.x/admin-api/#create-or-update-ca-certificate)\n* Inserts (or replaces) the CA Certificate under the requested resource with the definition specified in the body. The CA Certificate will be identified via the name or id attribute.\n* When the name or id attribute has the structure of a UUID, the CA Certificate being inserted/replaced will be identified by its id. Otherwise it will be identified by its name.\n* When creating a new CA Certificate without specifying id (neither in the URL nor in the body), then it will be auto-generated.\n* Notice that specifying a name in the URL and a different one in the request body is not allowed.\n\n# Path parameters\n\n \n \n \n \n \n \n \n \n \n \n \n \n
AttributesMandatoryTypeDescription
ca certificate idrequiredpathThe unique identifier of the CA Certificate to create or update.
\n\n# Request Body\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
AttributesMandatoryTypeDescription
certrequiredbodyPEM-encoded public certificate of the CA.
tagsoptionalbodyAn optional set of strings associated with the Certificate, for grouping and filtering.
" + }, + "response": [] + } + ], + "description": "https://docs.konghq.com/2.0.x/admin-api/#update-or-create-ca-certificate", + "event": [ + { + "listen": "prerequest", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + }, + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + } + ] + }, + { + "name": "Delete CA Certificate", + "item": [ + { + "name": "Delete Certificate", + "request": { + "method": "DELETE", + "header": [], + "url": { + "raw": "{{gateway}}ca_/certificates/:ca_certificateId", + "host": [ + "{{gateway}}ca_" + ], + "path": [ + "certificates", + ":ca_certificateId" + ], + "variable": [ + { + "key": "ca_certificateId" + } + ] + }, + "description": "# Delete Certificate [konghq](https://docs.konghq.com/2.0.x/admin-api/#delete-certificate-1)\n\n# Path parameters\n\n \n \n \n \n \n \n \n \n \n \n \n \n
AttributesMandatoryTypeDescription
certificate idrequiredpathThe unique identifier of the Certificate to delete
" + }, + "response": [ + { + "name": "Delete Certificate - 404", + "originalRequest": { + "method": "DELETE", + "header": [], + "body": { + "mode": "raw", + "raw": "" + }, + "url": { + "raw": "{{gateway}}/certificates/:certificateId", + "host": [ + "{{gateway}}" + ], + "path": [ + "certificates", + ":certificateId" + ], + "variable": [ + { + "key": "certificateId", + "value": "kkkkk", + "description": "The unique identifier of the Certificate to delete" + } + ] + } + }, + "status": "Not Found", + "code": 404, + "_postman_previewlanguage": "Text", + "header": [ + { + "key": "Date", + "value": "Thu, 12 Mar 2020 15:49:31 GMT" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "Server", + "value": "kong/2.0.1" + }, + { + "key": "Content-Length", + "value": "27" + }, + { + "key": "X-Kong-Admin-Latency", + "value": "2" + } + ], + "cookie": [], + "body": "{\n \"message\": \"SNI not found\"\n}" + } + ] + } + ], + "description": "https://docs.konghq.com/2.0.x/admin-api/#delete-ca-certificate", + "event": [ + { + "listen": "prerequest", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + }, + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + } + ] + } + ], + "description": "https://docs.konghq.com/2.0.x/admin-api/#ca-certificate-object\n\n* A CA certificate object represents a trusted CA. These objects are used by Kong to verify the validity of a client or server certificate.\n\n* CA Certificates can be both tagged and filtered by tags.\n\n{\n \"id\": \"04fbeacf-a9f1-4a5d-ae4a-b0407445db3f\",\n \"created_at\": 1422386534,\n \"cert\": \"-----BEGIN CERTIFICATE-----...\",\n \"tags\": [\"user-level\", \"low-priority\"]\n}", + "event": [ + { + "listen": "prerequest", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + }, + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + } + ] + }, + { + "name": "SNI Object", + "item": [ + { + "name": "Add SNI", + "item": [ + { + "name": "Create SNI", + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"name\": \"my-sni\",\n \"tags\": [\n \"user-level\",\n \"low-priority\"\n ],\n \"certificate\": {\n \"id\": \"a2e013e8-7623-4494-a347-6d29108ff68b\"\n }\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{gateway}}/snis", + "host": [ + "{{gateway}}" + ], + "path": [ + "snis" + ] + }, + "description": "# Create SNI [konghq](https://docs.konghq.com/2.0.x/admin-api/#create-sni)\n* An SNI object represents a many-to-one mapping of hostnames to a certificate. That is, a certificate object can have many hostnames associated with it; when Kong receives an SSL request, it uses the SNI field in the Client Hello to lookup the certificate object based on the SNI associated with the certificate.\n* SNIs can be both tagged and filtered by tags.\n\n# Request Body\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
AttributesMandatoryTypeDescription
namerequiredbodyThe SNI name to associate with the given certificate.
tagsoptionalbodyAn optional set of strings associated with the SNIs, for grouping and filtering.
certificaterequiredbodyThe id (a UUID) of the certificate with which to associate the SNI hostname. The Certificate must have a valid private key associated with it to be used by the SNI object. With form-encoded, the notation is certificate.id=. With JSON, use “\"certificate\":{\"id\":\"\"}.
" + }, + "response": [ + { + "name": "Create SNI - 201", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"name\": \"my-sni\",\n \"tags\": [\n \"user-level\",\n \"low-priority\"\n ],\n \"certificate\": {\n \"id\": \"a2e013e8-7623-4494-a347-6d29108ff68b\"\n }\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{gateway}}/snis", + "host": [ + "{{gateway}}" + ], + "path": [ + "snis" + ] + } + }, + "status": "Created", + "code": 201, + "_postman_previewlanguage": "Text", + "header": [ + { + "key": "Date", + "value": "Thu, 12 Mar 2020 17:05:06 GMT" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "Server", + "value": "kong/2.0.1" + }, + { + "key": "Content-Length", + "value": "23" + }, + { + "key": "X-Kong-Admin-Latency", + "value": "0" + } + ], + "cookie": [], + "body": "{\r\n \"id\": \"91020192-062d-416f-a275-9addeeaffaf2\",\r\n \"name\": \"my-sni\",\r\n \"created_at\": 1422386534,\r\n \"tags\": [\"user-level\", \"low-priority\"],\r\n \"certificate\": {\"id\":\"a2e013e8-7623-4494-a347-6d29108ff68b\"}\r\n}\r\n" + } + ] + }, + { + "name": "Create SNI Associated to a Specific Certificate", + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"name\": \"my-sni\",\n \"tags\": [\n \"user-level\",\n \"low-priority\"\n ],\n \"certificate\": {\n \"id\": \"a2e013e8-7623-4494-a347-6d29108ff68b\"\n }\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{gateway}}/certificates/:certificateNameOrId/snis", + "host": [ + "{{gateway}}" + ], + "path": [ + "certificates", + ":certificateNameOrId", + "snis" + ], + "variable": [ + { + "key": "certificateNameOrId", + "value": "", + "description": "The unique identifier or the name attribute of the Certificate that should be associated to the newly-created SNI." + } + ] + }, + "description": "# Create SNI Associated to a Specific Certificate [konghq](https://docs.konghq.com/2.0.x/admin-api/#create-sni-associated-to-a-specific-certificate)\n* An SNI object represents a many-to-one mapping of hostnames to a certificate. That is, a certificate object can have many hostnames associated with it; when Kong receives an SSL request, it uses the SNI field in the Client Hello to lookup the certificate object based on the SNI associated with the certificate.\n* SNIs can be both tagged and filtered by tags.\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n
AttributesMandatoryTypeDescription
certificate name or idrequiredpathThe unique identifier or the name attribute of the Certificate that should be associated to the newly-created SNI.
\n\n# Request Body\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
AttributesMandatoryTypeDescription
namerequiredbodyThe SNI name to associate with the given certificate.
tagsoptionalbodyAn optional set of strings associated with the SNIs, for grouping and filtering.
certificaterequiredbodyThe id (a UUID) of the certificate with which to associate the SNI hostname. The Certificate must have a valid private key associated with it to be used by the SNI object. With form-encoded, the notation is certificate.id=. With JSON, use “\"certificate\":{\"id\":\"\"}.
" + }, + "response": [] + } + ], + "description": "https://docs.konghq.com/2.0.x/admin-api/#add-sni" + }, + { + "name": "List SNIs", + "item": [ + { + "name": "List All SNIs", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{gateway}}/snis", + "host": [ + "{{gateway}}" + ], + "path": [ + "snis" + ] + }, + "description": "# List All SNIs [konghq](https://docs.konghq.com/2.0.x/admin-api/#list-all-snis)\n* An SNI object represents a many-to-one mapping of hostnames to a certificate. That is, a certificate object can have many hostnames associated with it; when Kong receives an SSL request, it uses the SNI field in the Client Hello to lookup the certificate object based on the SNI associated with the certificate.\n* SNIs can be both tagged and filtered by tags." + }, + "response": [ + { + "name": "List All SNIs", + "originalRequest": { + "method": "GET", + "header": [], + "url": { + "raw": "{{gateway}}/snis", + "host": [ + "{{gateway}}" + ], + "path": [ + "snis" + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "Text", + "header": [ + { + "key": "Date", + "value": "Thu, 12 Mar 2020 17:15:59 GMT" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "Server", + "value": "kong/2.0.1" + }, + { + "key": "Content-Length", + "value": "23" + }, + { + "key": "X-Kong-Admin-Latency", + "value": "1" + } + ], + "cookie": [], + "body": "{\n\t\"data\": [\n\t\t{\n\t\t\t\"id\": \"147f5ef0-1ed6-4711-b77f-489262f8bff7\",\n\t\t\t\"name\": \"my-sni\",\n\t\t\t\"created_at\": 1422386534,\n\t\t\t\"tags\": [\n\t\t\t\t\"user-level\",\n\t\t\t\t\"low-priority\"\n\t\t\t],\n\t\t\t\"certificate\": {\n\t\t\t\t\"id\": \"a3ad71a8-6685-4b03-a101-980a953544f6\"\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"id\": \"b87eb55d-69a1-41d2-8653-8d706eecefc0\",\n\t\t\t\"name\": \"my-sni\",\n\t\t\t\"created_at\": 1422386534,\n\t\t\t\"tags\": [\n\t\t\t\t\"admin\",\n\t\t\t\t\"high-priority\",\n\t\t\t\t\"critical\"\n\t\t\t],\n\t\t\t\"certificate\": {\n\t\t\t\t\"id\": \"4e8d95d4-40f2-4818-adcb-30e00c349618\"\n\t\t\t}\n\t\t}\n\t],\n\t\"next\": \"http://localhost:8001/snis?offset=6378122c-a0a1-438d-a5c6-efabae9fb969\"\n}" + } + ] + }, + { + "name": "List SNIs Associated to a Specific Certificate", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{gateway}}/certificates/:certificateNameOrId/snis", + "host": [ + "{{gateway}}" + ], + "path": [ + "certificates", + ":certificateNameOrId", + "snis" + ], + "variable": [ + { + "key": "certificateNameOrId", + "value": "", + "description": "The unique identifier or the name attribute of the Certificate whose SNIs are to be retrieved. When using this endpoint, only SNIs associated to the specified Certificate will be listed." + } + ] + }, + "description": "# List SNIs Associated to a Specific Certificate [konghq](https://docs.konghq.com/2.0.x/admin-api/#list-snis-associated-to-a-specific-certificate)\n* An SNI object represents a many-to-one mapping of hostnames to a certificate. That is, a certificate object can have many hostnames associated with it; when Kong receives an SSL request, it uses the SNI field in the Client Hello to lookup the certificate object based on the SNI associated with the certificate.\n* SNIs can be both tagged and filtered by tags.\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n
AttributesMandatoryTypeDescription
certificate name or idrequiredpathThe unique identifier or the name attribute of the Certificate whose SNIs are to be retrieved. When using this endpoint, only SNIs associated to the specified Certificate will be listed.
" + }, + "response": [ + { + "name": "List All SNIs", + "originalRequest": { + "method": "GET", + "header": [], + "url": { + "raw": "{{gateway}}/snis", + "host": [ + "{{gateway}}" + ], + "path": [ + "snis" + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "Text", + "header": [ + { + "key": "Date", + "value": "Thu, 12 Mar 2020 17:15:59 GMT" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "Server", + "value": "kong/2.0.1" + }, + { + "key": "Content-Length", + "value": "23" + }, + { + "key": "X-Kong-Admin-Latency", + "value": "1" + } + ], + "cookie": [], + "body": "{\n\t\"data\": [\n\t\t{\n\t\t\t\"id\": \"147f5ef0-1ed6-4711-b77f-489262f8bff7\",\n\t\t\t\"name\": \"my-sni\",\n\t\t\t\"created_at\": 1422386534,\n\t\t\t\"tags\": [\n\t\t\t\t\"user-level\",\n\t\t\t\t\"low-priority\"\n\t\t\t],\n\t\t\t\"certificate\": {\n\t\t\t\t\"id\": \"a3ad71a8-6685-4b03-a101-980a953544f6\"\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"id\": \"b87eb55d-69a1-41d2-8653-8d706eecefc0\",\n\t\t\t\"name\": \"my-sni\",\n\t\t\t\"created_at\": 1422386534,\n\t\t\t\"tags\": [\n\t\t\t\t\"admin\",\n\t\t\t\t\"high-priority\",\n\t\t\t\t\"critical\"\n\t\t\t],\n\t\t\t\"certificate\": {\n\t\t\t\t\"id\": \"4e8d95d4-40f2-4818-adcb-30e00c349618\"\n\t\t\t}\n\t\t}\n\t],\n\t\"next\": \"http://localhost:8001/snis?offset=6378122c-a0a1-438d-a5c6-efabae9fb969\"\n}" + } + ] + } + ], + "description": "https://docs.konghq.com/2.0.x/admin-api/#list-snis" + }, + { + "name": "Retrieve SNI", + "item": [ + { + "name": "Retrieve SNI", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{gateway}}/snis/:sniNameOrId", + "host": [ + "{{gateway}}" + ], + "path": [ + "snis", + ":sniNameOrId" + ], + "variable": [ + { + "key": "sniNameOrId", + "value": "my-sni", + "description": "The unique identifier or the name of the SNI to retrieve" + } + ] + }, + "description": "# Retrieve SNI [konghq](https://docs.konghq.com/2.0.x/admin-api/#list-all-snis)\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n
AttributesMandatoryTypeDescription
sni name or idrequiredpathThe unique identifier or the name of the SNI to retrieve
" + }, + "response": [ + { + "name": "Retrieve SNI - 200", + "originalRequest": { + "method": "GET", + "header": [], + "url": { + "raw": "{{gateway}}/snis/:sniNameOrId", + "host": [ + "{{gateway}}" + ], + "path": [ + "snis", + ":sniNameOrId" + ], + "variable": [ + { + "key": "sniNameOrId", + "value": "my-sni", + "description": "The unique identifier or the name of the SNI to retrieve" + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "Text", + "header": [ + { + "key": "Date", + "value": "Thu, 12 Mar 2020 17:25:48 GMT" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "Server", + "value": "kong/2.0.1" + }, + { + "key": "Content-Length", + "value": "23" + }, + { + "key": "X-Kong-Admin-Latency", + "value": "1" + } + ], + "cookie": [], + "body": "{\r\n \"id\": \"91020192-062d-416f-a275-9addeeaffaf2\",\r\n \"name\": \"my-sni\",\r\n \"created_at\": 1422386534,\r\n \"tags\": [\"user-level\", \"low-priority\"],\r\n \"certificate\": {\"id\":\"a2e013e8-7623-4494-a347-6d29108ff68b\"}\r\n}" + } + ] + }, + { + "name": "Retrieve SNI Associated to a Specific Certificate", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{gateway}}/certificates/:certificateId/snis/:sniNameOrId", + "host": [ + "{{gateway}}" + ], + "path": [ + "certificates", + ":certificateId", + "snis", + ":sniNameOrId" + ], + "variable": [ + { + "key": "certificateId", + "value": "", + "description": "The unique identifier of the Certificate to retrieve" + }, + { + "key": "sniNameOrId", + "value": "", + "description": "The unique identifier or the name of the SNI to retrieve" + } + ] + }, + "description": "# Retrieve SNI Associated to a Specific Certificate [konghq](https://docs.konghq.com/2.0.x/admin-api/#retrieve-sni-associated-to-a-specific-certificate)\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
AttributesMandatoryTypeDescription
certificate idrequiredpathThe unique identifier of the Certificate to retrieve.
sni name or idrequiredpathThe unique identifier or the name of the SNI to retrieve.
" + }, + "response": [] + } + ], + "description": "https://docs.konghq.com/2.0.x/admin-api/#retrieve-sni", + "event": [ + { + "listen": "prerequest", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + }, + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + } + ] + }, + { + "name": "Update SNI", + "item": [ + { + "name": "Update SNI", + "request": { + "method": "PATCH", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"name\": \"my-sni\",\n \"tags\": [\n \"user-level\",\n \"low-priority\"\n ],\n \"certificate\": {\n \"id\": \"a2e013e8-7623-4494-a347-6d29108ff68b\"\n }\n}" + }, + "url": { + "raw": "{{gateway}}/snis/:sniNameOrId", + "host": [ + "{{gateway}}" + ], + "path": [ + "snis", + ":sniNameOrId" + ], + "variable": [ + { + "key": "sniNameOrId", + "value": "my-sni", + "description": "The unique identifier or the name of the SNI to update" + } + ] + }, + "description": "# Update SNI [konghq](https://docs.konghq.com/2.0.x/admin-api/#update-sni-1)\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n
AttributesMandatoryTypeDescription
sni name or idrequiredpathThe unique identifier or the name of the SNI to update
\n\n# Request Body\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
AttributesMandatoryTypeDescription
namerequiredbodyThe SNI name to associate with the given certificate.
tagsoptionalbodyAn optional set of strings associated with the SNIs, for grouping and filtering.
certificaterequiredbodyThe id (a UUID) of the certificate with which to associate the SNI hostname. The Certificate must have a valid private key associated with it to be used by the SNI object. With form-encoded, the notation is certificate.id=. With JSON, use “\"certificate\":{\"id\":\"\"}.
" + }, + "response": [ + { + "name": "Update SNI - 404", + "originalRequest": { + "method": "PATCH", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"name\": \"my-sni\",\n \"tags\": [\n \"user-level\",\n \"low-priority\"\n ],\n \"certificate\": {\n \"id\": \"a2e013e8-7623-4494-a347-6d29108ff68b\"\n }\n}" + }, + "url": { + "raw": "{{gateway}}/snis/:sniNameOrId", + "host": [ + "{{gateway}}" + ], + "path": [ + "snis", + ":sniNameOrId" + ], + "variable": [ + { + "key": "sniNameOrId", + "value": "my-sni", + "description": "The unique identifier or the name of the SNI to update" + } + ] + } + }, + "status": "Not Found", + "code": 404, + "_postman_previewlanguage": "Text", + "header": [ + { + "key": "Date", + "value": "Thu, 12 Mar 2020 18:34:09 GMT" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "Server", + "value": "kong/2.0.1" + }, + { + "key": "Content-Length", + "value": "119" + }, + { + "key": "X-Kong-Admin-Latency", + "value": "2" + } + ], + "cookie": [], + "body": "{\n \"message\": \"could not find the entity with '{name=\\\"my-sni\\\"}'\",\n \"name\": \"not found\",\n \"fields\": {\n \"name\": \"my-sni\"\n },\n \"code\": 6\n}" + } + ] + }, + { + "name": "Update SNI Associated to a Specific Certificate", + "request": { + "method": "PATCH", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"name\": \"my-sni\",\n \"tags\": [\n \"user-level\",\n \"low-priority\"\n ],\n \"certificate\": {\n \"id\": \"a2e013e8-7623-4494-a347-6d29108ff68b\"\n }\n}" + }, + "url": { + "raw": "{{gateway}}/certificates/:certificateId/snis/:sniNameOrId", + "host": [ + "{{gateway}}" + ], + "path": [ + "certificates", + ":certificateId", + "snis", + ":sniNameOrId" + ], + "variable": [ + { + "key": "certificateId", + "value": "", + "description": "The unique identifier of the Certificate to update" + }, + { + "key": "sniNameOrId", + "value": "", + "description": "The unique identifier or the name of the SNI to update" + } + ] + }, + "description": "# Update SNI Associated to a Specific Certificate [konghq](https://docs.konghq.com/2.0.x/admin-api/#update-sni-associated-to-a-specific-certificate)\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
AttributesMandatoryTypeDescription
certificate idrequiredpathThe unique identifier of the Certificate to update.
sni name or idrequiredpathThe unique identifier or the name of the SNI to update.
\n\n# Request Body\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
AttributesMandatoryTypeDescription
namerequiredbodyThe SNI name to associate with the given certificate.
tagsoptionalbodyAn optional set of strings associated with the SNIs, for grouping and filtering.
certificaterequiredbodyThe id (a UUID) of the certificate with which to associate the SNI hostname. The Certificate must have a valid private key associated with it to be used by the SNI object. With form-encoded, the notation is certificate.id=. With JSON, use “\"certificate\":{\"id\":\"\"}.
" + }, + "response": [] + } + ], + "description": "https://docs.konghq.com/2.0.x/admin-api/#update-sni", + "event": [ + { + "listen": "prerequest", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + }, + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + } + ] + }, + { + "name": "Update Or Create SNI", + "item": [ + { + "name": "Create Or Update SNI", + "request": { + "method": "PUT", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"name\": \"my-sni\",\n \"tags\": [\n \"user-level\",\n \"low-priority\"\n ],\n \"certificate\": {\n \"id\": \"a2e013e8-7623-4494-a347-6d29108ff68b\"\n }\n}" + }, + "url": { + "raw": "{{gateway}}/snis/:sniNameOrId", + "host": [ + "{{gateway}}" + ], + "path": [ + "snis", + ":sniNameOrId" + ], + "variable": [ + { + "key": "sniNameOrId", + "value": "my-sni", + "description": "The unique identifier or the name of the SNI to create or update" + } + ] + }, + "description": "# Create Or Update SNI [konghq](https://docs.konghq.com/2.0.x/admin-api/#create-or-update-sni)\n* Inserts (or replaces) the SNI under the requested resource with the definition specified in the body. The SNI will be identified via the name or id attribute.\n* When the name or id attribute has the structure of a UUID, the SNI being inserted/replaced will be identified by its id. Otherwise it will be identified by its name.\n* When creating a new SNI without specifying id (neither in the URL nor in the body), then it will be auto-generated.\n* Notice that specifying a name in the URL and a different one in the request body is not allowed.\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n
AttributesMandatoryTypeDescription
sni name or idrequiredpathThe unique identifier or the name of the SNI to create or update
\n\n# Request Body\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
AttributesMandatoryTypeDescription
namerequiredbodyThe SNI name to associate with the given certificate.
tagsoptionalbodyAn optional set of strings associated with the SNIs, for grouping and filtering.
certificaterequiredbodyThe id (a UUID) of the certificate with which to associate the SNI hostname. The Certificate must have a valid private key associated with it to be used by the SNI object. With form-encoded, the notation is certificate.id=. With JSON, use “\"certificate\":{\"id\":\"\"}.
" + }, + "response": [] + }, + { + "name": "Create Or Update SNI Associated to a Specific Certificate", + "request": { + "method": "PUT", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"name\": \"my-sni\",\n \"tags\": [\n \"user-level\",\n \"low-priority\"\n ],\n \"certificate\": {\n \"id\": \"a2e013e8-7623-4494-a347-6d29108ff68b\"\n }\n}" + }, + "url": { + "raw": "{{gateway}}/certificates/:certificateId/snis/:sniNameOrId", + "host": [ + "{{gateway}}" + ], + "path": [ + "certificates", + ":certificateId", + "snis", + ":sniNameOrId" + ], + "variable": [ + { + "key": "certificateId", + "value": "", + "description": "The unique identifier of the Certificate to update" + }, + { + "key": "sniNameOrId", + "value": "", + "description": "The unique identifier or the name of the SNI to update" + } + ] + }, + "description": "# Update SNI Associated to a Specific Certificate [konghq](https://docs.konghq.com/2.0.x/admin-api/#update-sni-associated-to-a-specific-certificate)\n* Inserts (or replaces) the SNI under the requested resource with the definition specified in the body. The SNI will be identified via the name or id attribute.\n* When the name or id attribute has the structure of a UUID, the SNI being inserted/replaced will be identified by its id. Otherwise it will be identified by its name.\n* When creating a new SNI without specifying id (neither in the URL nor in the body), then it will be auto-generated.\n* Notice that specifying a name in the URL and a different one in the request body is not allowed.\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
AttributesMandatoryTypeDescription
certificate idrequiredpathThe unique identifier of the Certificate to update.
sni name or idrequiredpathThe unique identifier or the name of the SNI to update.
\n\n# Request Body\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
AttributesMandatoryTypeDescription
namerequiredbodyThe SNI name to associate with the given certificate.
tagsoptionalbodyAn optional set of strings associated with the SNIs, for grouping and filtering.
certificaterequiredbodyThe id (a UUID) of the certificate with which to associate the SNI hostname. The Certificate must have a valid private key associated with it to be used by the SNI object. With form-encoded, the notation is certificate.id=. With JSON, use “\"certificate\":{\"id\":\"\"}.
" + }, + "response": [] + } + ], + "description": "https://docs.konghq.com/2.0.x/admin-api/#update-or-create-sni", + "event": [ + { + "listen": "prerequest", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + }, + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + } + ] + }, + { + "name": "Retrieve SNI Copy", + "item": [ + { + "name": "Delete SNI", + "request": { + "method": "DELETE", + "header": [], + "url": { + "raw": "{{gateway}}/snis/:sniNameOrId", + "host": [ + "{{gateway}}" + ], + "path": [ + "snis", + ":sniNameOrId" + ], + "variable": [ + { + "key": "sniNameOrId", + "value": "my-sni", + "description": "The unique identifier or the name of the SNI to retrieve" + } + ] + }, + "description": "# Delete SNI [konghq](https://docs.konghq.com/2.0.x/admin-api/#delete-sni-1)\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n
AttributesMandatoryTypeDescription
sni name or idrequiredpathThe unique identifier or the name of the SNI to delete
" + }, + "response": [ + { + "name": "Retrieve SNI - 200", + "originalRequest": { + "method": "GET", + "header": [], + "url": { + "raw": "{{gateway}}/snis/:sniNameOrId", + "host": [ + "{{gateway}}" + ], + "path": [ + "snis", + ":sniNameOrId" + ], + "variable": [ + { + "key": "sniNameOrId", + "value": "my-sni", + "description": "The unique identifier or the name of the SNI to retrieve" + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "Text", + "header": [ + { + "key": "Date", + "value": "Thu, 12 Mar 2020 17:25:48 GMT" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "Server", + "value": "kong/2.0.1" + }, + { + "key": "Content-Length", + "value": "23" + }, + { + "key": "X-Kong-Admin-Latency", + "value": "1" + } + ], + "cookie": [], + "body": "{\r\n \"id\": \"91020192-062d-416f-a275-9addeeaffaf2\",\r\n \"name\": \"my-sni\",\r\n \"created_at\": 1422386534,\r\n \"tags\": [\"user-level\", \"low-priority\"],\r\n \"certificate\": {\"id\":\"a2e013e8-7623-4494-a347-6d29108ff68b\"}\r\n}" + } + ] + }, + { + "name": "Delete SNI Associated to a Specific Certificate", + "request": { + "method": "DELETE", + "header": [], + "url": { + "raw": "{{gateway}}/certificates/:certificateId/snis/:sniNameOrId", + "host": [ + "{{gateway}}" + ], + "path": [ + "certificates", + ":certificateId", + "snis", + ":sniNameOrId" + ], + "variable": [ + { + "key": "certificateId", + "value": "", + "description": "The unique identifier of the Certificate to delete" + }, + { + "key": "sniNameOrId", + "value": "", + "description": "The unique identifier or the name of the SNI to delete" + } + ] + }, + "description": "# Delete SNI Associated to a Specific Certificate [konghq](https://docs.konghq.com/2.0.x/admin-api/#delete-sni-associated-to-a-specific-certificate)\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
AttributesMandatoryTypeDescription
certificate idrequiredpathThe unique identifier of the Certificate to delete.
sni name or idrequiredpathThe unique identifier or the name of the SNI to delete.
" + }, + "response": [] + } + ], + "description": "https://docs.konghq.com/2.0.x/admin-api/#retrieve-sni", + "event": [ + { + "listen": "prerequest", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + }, + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + } + ] + } + ], + "description": "https://docs.konghq.com/2.0.x/admin-api/#sni-object\n\nAn SNI object represents a many-to-one mapping of hostnames to a certificate. That is, a certificate object can have many hostnames associated with it; when Kong receives an SSL request, it uses the SNI field in the Client Hello to lookup the certificate object based on the SNI associated with the certificate.\n\nSNIs can be both tagged and filtered by tags.\n\n{\n \"id\": \"91020192-062d-416f-a275-9addeeaffaf2\",\n \"name\": \"my-sni\",\n \"created_at\": 1422386534,\n \"tags\": [\"user-level\", \"low-priority\"],\n \"certificate\": {\"id\":\"a2e013e8-7623-4494-a347-6d29108ff68b\"}\n}" + }, + { + "name": "Upstream Object", + "item": [ + { + "name": "Add Upstream", + "item": [ + { + "name": "Create Upstream", + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"created_at\": 1584044267,\n \"hash_on\": \"none\",\n \"id\": \"f8d38987-1eb6-4cb2-a7c8-6b11a17de911\",\n \"algorithm\": \"round-robin\",\n \"name\": \"my-upstream\",\n \"tags\": [\n \"user-level\",\n \"low-priority\"\n ],\n \"hash_fallback_header\": null,\n \"hash_fallback\": \"none\",\n \"hash_on_cookie\": null,\n \"host_header\": \"example.com\",\n \"hash_on_cookie_path\": \"/\",\n \"healthchecks\": {\n \"threshold\": 0,\n \"active\": {\n \"unhealthy\": {\n \"http_statuses\": [\n 429,\n 404,\n 500,\n 501,\n 502,\n 503,\n 504,\n 505\n ],\n \"tcp_failures\": 0,\n \"timeouts\": 0,\n \"http_failures\": 0,\n \"interval\": 0\n },\n \"type\": \"http\",\n \"http_path\": \"/\",\n \"timeout\": 1,\n \"healthy\": {\n \"successes\": 0,\n \"interval\": 0,\n \"http_statuses\": [\n 200,\n 302\n ]\n },\n \"https_sni\": \"example.com\",\n \"https_verify_certificate\": true,\n \"concurrency\": 10\n },\n \"passive\": {\n \"unhealthy\": {\n \"http_failures\": 0,\n \"http_statuses\": [\n 429,\n 500,\n 503\n ],\n \"tcp_failures\": 0,\n \"timeouts\": 0\n },\n \"healthy\": {\n \"http_statuses\": [\n 200,\n 201,\n 202,\n 203,\n 204,\n 205,\n 206,\n 207,\n 208,\n 226,\n 300,\n 301,\n 302,\n 303,\n 304,\n 305,\n 306,\n 307,\n 308\n ],\n \"successes\": 0\n },\n \"type\": \"http\"\n }\n },\n \"hash_on_header\": null,\n \"slots\": 10000\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{gateway}}/upstreams", + "host": [ + "{{gateway}}" + ], + "path": [ + "upstreams" + ] + }, + "description": "# Create Upstream [konghq](https://docs.konghq.com/2.0.x/admin-api/#create-upstream)\n* The upstream object represents a virtual hostname and can be used to loadbalance incoming requests over multiple services (targets). So for example an upstream named service.v1.xyz for a Service object whose host is service.v1.xyz. Requests for this Service would be proxied to the targets defined within the upstream.\n\n* An upstream also includes a health checker, which is able to enable and disable targets based on their ability or inability to serve requests. The configuration for the health checker is stored in the upstream object, and applies to all of its targets.\n\n* Upstreams can be both tagged and filtered by tags.\n\n# Request Body\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
AttributesMandatoryTypeDescription
namerequiredbodyThis is a hostname, which must be equal to the host of a Service.
algorithmoptionalbodyWhich load balancing algorithm to use. Accepted values are: \"consistent-hashing\", \"least-connections\", \"round-robin\". Defaults to \"round-robin\".
hash_onoptionalbodyWhat to use as hashing input. Using none results in a weighted-round-robin scheme with no hashing. Accepted values are: \"none\", \"consumer\", \"ip\", \"header\", \"cookie\". Defaults to \"none\".
hash_fallbackoptionalbodyWhat to use as hashing input if the primary hash_on does not return a hash (eg. header is missing, or no consumer identified). Not available if hash_on is set to cookie. Accepted values are: \"none\", \"consumer\", \"ip\", \"header\", \"cookie\". Defaults to \"none\".
hash_on_headersemi-optionalbodyThe header name to take the value from as hash input. Only required when hash_on is set to header.
hash_fallback_headersemi-optionalbodyThe header name to take the value from as hash input. Only required when hash_fallback is set to header.
hash_on_cookiesemi-optionalbodyThe cookie name to take the value from as hash input. Only required when hash_on or hash_fallback is set to cookie. If the specified cookie is not in the request, Kong will generate a value and set the cookie in the response.
hash_on_cookie_pathsemi-optionalbodyThe cookie path to set in the response headers. Only required when hash_on or hash_fallback is set to cookie. Defaults to \"/\".
slotsoptionalbodyThe number of slots in the loadbalancer algorithm (10-65536). Defaults to 10000.
healthchecks.active.https_verify_certificateoptionalbodyWhether to check the validity of the SSL certificate of the remote host when performing active health checks using HTTPS. Defaults to true.
healthchecks.active.unhealthy.http_statusesoptionalbodyAn array of HTTP statuses to consider a failure, indicating unhealthiness, when returned by a probe in active health checks. Defaults to [429, 404, 500, 501, 502, 503, 504, 505]. With form-encoded, the notation is http_statuses[]=429&http_statuses[]=404. With JSON, use an Array.
healthchecks.active.unhealthy.tcp_failuresoptionalbodyNumber of TCP failures in active probes to consider a target unhealthy. Defaults to 0.
healthchecks.active.unhealthy.timeoutsoptionalbodyNumber of timeouts in active probes to consider a target unhealthy. Defaults to 0.
healthchecks.active.unhealthy.http_failuresoptionalbodyNumber of HTTP failures in active probes (as defined by healthchecks.active.unhealthy.http_statuses) to consider a target unhealthy. Defaults to 0.
healthchecks.active.unhealthy.intervaloptionalbodyInterval between active health checks for unhealthy targets (in seconds). A value of zero indicates that active probes for unhealthy targets should not be performed. Defaults to 0.
healthchecks.active.http_pathoptionalbodyPath to use in GET HTTP request to run as a probe on active health checks. Defaults to \"/\".
healthchecks.active.timeoutoptionalbodySocket timeout for active health checks (in seconds). Defaults to 1.
healthchecks.active.healthy.http_statusesoptionalbodyAn array of HTTP statuses to consider a success, indicating healthiness, when returned by a probe in active health checks. Defaults to [200, 302]. With form-encoded, the notation is http_statuses[]=200&http_statuses[]=302. With JSON, use an Array.
healthchecks.active.healthy.intervaloptionalbodyInterval between active health checks for healthy targets (in seconds). A value of zero indicates that active probes for healthy targets should not be performed. Defaults to 0.
healthchecks.active.healthy.successesoptionalbodyNumber of successes in active probes (as defined by healthchecks.active.healthy.http_statuses) to consider a target healthy. Defaults to 0.
healthchecks.active.https_snioptionalbodyThe hostname to use as an SNI (Server Name Identification) when performing active health checks using HTTPS. This is particularly useful when Targets are configured using IPs, so that the target host’s certificate can be verified with the proper SNI.
healthchecks.active.concurrencyoptionalbodyNumber of targets to check concurrently in active health checks. Defaults to 10.
healthchecks.active.typeoptionalbodyWhether to perform active health checks using HTTP or HTTPS, or just attempt a TCP connection. Accepted values are: \"tcp\", \"http\", \"https\", \"grpc\", \"grpcs\". Defaults to \"http\".
healthchecks.passive.unhealthy.http_failuresoptionalbodyNumber of HTTP failures in proxied traffic (as defined by healthchecks.passive.unhealthy.http_statuses) to consider a target unhealthy, as observed by passive health checks. Defaults to 0.
healthchecks.passive.unhealthy.http_statusesoptionalbodyAn array of HTTP statuses which represent unhealthiness when produced by proxied traffic, as observed by passive health checks. Defaults to [429, 500, 503]. With form-encoded, the notation is http_statuses[]=429&http_statuses[]=500. With JSON, use an Array.
healthchecks.passive.unhealthy.tcp_failuresoptionalbodyNumber of TCP failures in proxied traffic to consider a target unhealthy, as observed by passive health checks. Defaults to 0.
healthchecks.passive.unhealthy.timeoutsoptionalbodyNumber of timeouts in proxied traffic to consider a target unhealthy, as observed by passive health checks. Defaults to 0.
healthchecks.passive.typeoptionalbodyWhether to perform passive health checks interpreting HTTP/HTTPS statuses, or just check for TCP connection success. In passive checks, http and https options are equivalent. Accepted values are: \"tcp\", \"http\", \"https\", \"grpc\", \"grpcs\". Defaults to \"http\".
healthchecks.passive.healthy.successesoptionalbodyNumber of successes in proxied traffic (as defined by healthchecks.passive.healthy.http_statuses) to consider a target healthy, as observed by passive health checks. Defaults to 0.
healthchecks.passive.healthy.http_statusesoptionalbodyAn array of HTTP statuses which represent healthiness when produced by proxied traffic, as observed by passive health checks. Defaults to [200, 201, 202, 203, 204, 205, 206, 207, 208, 226, 300, 301, 302, 303, 304, 305, 306, 307, 308]. With form-encoded, the notation is http_statuses[]=200&http_statuses[]=201. With JSON, use an Array.
healthchecks.thresholdoptionalbodyThe minimum percentage of the upstream’s targets’ weight that must be available for the whole upstream to be considered healthy. Defaults to 0.
tagsoptionalbodyAn optional set of strings associated with the Upstream, for grouping and filtering.
host_headeroptionalbodyThe hostname to be used as Host header when proxying requests through Kong.
" + }, + "response": [ + { + "name": "Create Upstream-201", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"name\": \"my-upstream\",\n \"algorithm\": \"round-robin\",\n \"hash_on\": \"none\",\n \"hash_fallback\": \"none\",\n \"hash_on_cookie_path\": \"/\",\n \"slots\": 10000,\n \"healthchecks\": {\n \"active\": {\n \"https_verify_certificate\": true,\n \"unhealthy\": {\n \"http_statuses\": [\n 429,\n 404,\n 500,\n 501,\n 502,\n 503,\n 504,\n 505\n ],\n \"tcp_failures\": 0,\n \"timeouts\": 0,\n \"http_failures\": 0,\n \"interval\": 0\n },\n \"http_path\": \"/\",\n \"timeout\": 1,\n \"healthy\": {\n \"http_statuses\": [\n 200,\n 302\n ],\n \"interval\": 0,\n \"successes\": 0\n },\n \"https_sni\": \"example.com\",\n \"concurrency\": 10,\n \"type\": \"http\"\n },\n \"passive\": {\n \"unhealthy\": {\n \"http_failures\": 0,\n \"http_statuses\": [\n 429,\n 500,\n 503\n ],\n \"tcp_failures\": 0,\n \"timeouts\": 0\n },\n \"type\": \"http\",\n \"healthy\": {\n \"successes\": 0,\n \"http_statuses\": [\n 200,\n 201,\n 202,\n 203,\n 204,\n 205,\n 206,\n 207,\n 208,\n 226,\n 300,\n 301,\n 302,\n 303,\n 304,\n 305,\n 306,\n 307,\n 308\n ]\n }\n },\n \"threshold\": 0\n },\n \"tags\": [\n \"user-level\",\n \"low-priority\"\n ],\n \"host_header\": \"example.com\"\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{gateway}}/upstreams", + "host": [ + "{{gateway}}" + ], + "path": [ + "upstreams" + ] + } + }, + "status": "Created", + "code": 201, + "_postman_previewlanguage": "Text", + "header": [ + { + "key": "Date", + "value": "Thu, 12 Mar 2020 20:17:47 GMT" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "Server", + "value": "kong/2.0.1" + }, + { + "key": "Content-Length", + "value": "922" + }, + { + "key": "X-Kong-Admin-Latency", + "value": "32" + } + ], + "cookie": [], + "body": "{\n \"created_at\": 1584044267,\n \"hash_on\": \"none\",\n \"id\": \"f8d38987-1eb6-4cb2-a7c8-6b11a17de911\",\n \"algorithm\": \"round-robin\",\n \"name\": \"my-upstream\",\n \"tags\": [\n \"user-level\",\n \"low-priority\"\n ],\n \"hash_fallback_header\": null,\n \"hash_fallback\": \"none\",\n \"hash_on_cookie\": null,\n \"host_header\": \"example.com\",\n \"hash_on_cookie_path\": \"/\",\n \"healthchecks\": {\n \"threshold\": 0,\n \"active\": {\n \"unhealthy\": {\n \"http_statuses\": [\n 429,\n 404,\n 500,\n 501,\n 502,\n 503,\n 504,\n 505\n ],\n \"tcp_failures\": 0,\n \"timeouts\": 0,\n \"http_failures\": 0,\n \"interval\": 0\n },\n \"type\": \"http\",\n \"http_path\": \"/\",\n \"timeout\": 1,\n \"healthy\": {\n \"successes\": 0,\n \"interval\": 0,\n \"http_statuses\": [\n 200,\n 302\n ]\n },\n \"https_sni\": \"example.com\",\n \"https_verify_certificate\": true,\n \"concurrency\": 10\n },\n \"passive\": {\n \"unhealthy\": {\n \"http_failures\": 0,\n \"http_statuses\": [\n 429,\n 500,\n 503\n ],\n \"tcp_failures\": 0,\n \"timeouts\": 0\n },\n \"healthy\": {\n \"http_statuses\": [\n 200,\n 201,\n 202,\n 203,\n 204,\n 205,\n 206,\n 207,\n 208,\n 226,\n 300,\n 301,\n 302,\n 303,\n 304,\n 305,\n 306,\n 307,\n 308\n ],\n \"successes\": 0\n },\n \"type\": \"http\"\n }\n },\n \"hash_on_header\": null,\n \"slots\": 10000\n}" + } + ] + } + ], + "description": "https://docs.konghq.com/2.0.x/admin-api/#add-upstream" + }, + { + "name": "List All Upstreams", + "item": [ + { + "name": "List All Upstreams", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{gateway}}/upstreams", + "host": [ + "{{gateway}}" + ], + "path": [ + "upstreams" + ] + }, + "description": "# List All Upstreams [konghq](https://docs.konghq.com/2.0.x/admin-api/#list-all-upstreams)" + }, + "response": [ + { + "name": "List All Upstreams-200", + "originalRequest": { + "method": "GET", + "header": [], + "url": { + "raw": "{{gateway}}/upstreams", + "host": [ + "{{gateway}}" + ], + "path": [ + "upstreams" + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "Text", + "header": [ + { + "key": "Date", + "value": "Thu, 12 Mar 2020 20:21:55 GMT" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "Server", + "value": "kong/2.0.1" + }, + { + "key": "Content-Length", + "value": "945" + }, + { + "key": "X-Kong-Admin-Latency", + "value": "1" + } + ], + "cookie": [], + "body": "{\n\t\"data\": [\n\t\t{\n\t\t\t\"id\": \"ea29aaa3-3b2d-488c-b90c-56df8e0dd8c6\",\n\t\t\t\"created_at\": 1422386534,\n\t\t\t\"name\": \"my-upstream\",\n\t\t\t\"algorithm\": \"round-robin\",\n\t\t\t\"hash_on\": \"none\",\n\t\t\t\"hash_fallback\": \"none\",\n\t\t\t\"hash_on_cookie_path\": \"/\",\n\t\t\t\"slots\": 10000,\n\t\t\t\"healthchecks\": {\n\t\t\t\t\"active\": {\n\t\t\t\t\t\"https_verify_certificate\": true,\n\t\t\t\t\t\"unhealthy\": {\n\t\t\t\t\t\t\"http_statuses\": [\n\t\t\t\t\t\t\t429,\n\t\t\t\t\t\t\t404,\n\t\t\t\t\t\t\t500,\n\t\t\t\t\t\t\t501,\n\t\t\t\t\t\t\t502,\n\t\t\t\t\t\t\t503,\n\t\t\t\t\t\t\t504,\n\t\t\t\t\t\t\t505\n\t\t\t\t\t\t],\n\t\t\t\t\t\t\"tcp_failures\": 0,\n\t\t\t\t\t\t\"timeouts\": 0,\n\t\t\t\t\t\t\"http_failures\": 0,\n\t\t\t\t\t\t\"interval\": 0\n\t\t\t\t\t},\n\t\t\t\t\t\"http_path\": \"/\",\n\t\t\t\t\t\"timeout\": 1,\n\t\t\t\t\t\"healthy\": {\n\t\t\t\t\t\t\"http_statuses\": [\n\t\t\t\t\t\t\t200,\n\t\t\t\t\t\t\t302\n\t\t\t\t\t\t],\n\t\t\t\t\t\t\"interval\": 0,\n\t\t\t\t\t\t\"successes\": 0\n\t\t\t\t\t},\n\t\t\t\t\t\"https_sni\": \"example.com\",\n\t\t\t\t\t\"concurrency\": 10,\n\t\t\t\t\t\"type\": \"http\"\n\t\t\t\t},\n\t\t\t\t\"passive\": {\n\t\t\t\t\t\"unhealthy\": {\n\t\t\t\t\t\t\"http_failures\": 0,\n\t\t\t\t\t\t\"http_statuses\": [\n\t\t\t\t\t\t\t429,\n\t\t\t\t\t\t\t500,\n\t\t\t\t\t\t\t503\n\t\t\t\t\t\t],\n\t\t\t\t\t\t\"tcp_failures\": 0,\n\t\t\t\t\t\t\"timeouts\": 0\n\t\t\t\t\t},\n\t\t\t\t\t\"type\": \"http\",\n\t\t\t\t\t\"healthy\": {\n\t\t\t\t\t\t\"successes\": 0,\n\t\t\t\t\t\t\"http_statuses\": [\n\t\t\t\t\t\t\t200,\n\t\t\t\t\t\t\t201,\n\t\t\t\t\t\t\t202,\n\t\t\t\t\t\t\t203,\n\t\t\t\t\t\t\t204,\n\t\t\t\t\t\t\t205,\n\t\t\t\t\t\t\t206,\n\t\t\t\t\t\t\t207,\n\t\t\t\t\t\t\t208,\n\t\t\t\t\t\t\t226,\n\t\t\t\t\t\t\t300,\n\t\t\t\t\t\t\t301,\n\t\t\t\t\t\t\t302,\n\t\t\t\t\t\t\t303,\n\t\t\t\t\t\t\t304,\n\t\t\t\t\t\t\t305,\n\t\t\t\t\t\t\t306,\n\t\t\t\t\t\t\t307,\n\t\t\t\t\t\t\t308\n\t\t\t\t\t\t]\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"threshold\": 0\n\t\t\t},\n\t\t\t\"tags\": [\n\t\t\t\t\"user-level\",\n\t\t\t\t\"low-priority\"\n\t\t\t],\n\t\t\t\"host_header\": \"example.com\"\n\t\t},\n\t\t{\n\t\t\t\"id\": \"4fe14415-73d5-4f00-9fbc-c72a0fccfcb2\",\n\t\t\t\"created_at\": 1422386534,\n\t\t\t\"name\": \"my-upstream\",\n\t\t\t\"algorithm\": \"round-robin\",\n\t\t\t\"hash_on\": \"none\",\n\t\t\t\"hash_fallback\": \"none\",\n\t\t\t\"hash_on_cookie_path\": \"/\",\n\t\t\t\"slots\": 10000,\n\t\t\t\"healthchecks\": {\n\t\t\t\t\"active\": {\n\t\t\t\t\t\"https_verify_certificate\": true,\n\t\t\t\t\t\"unhealthy\": {\n\t\t\t\t\t\t\"http_statuses\": [\n\t\t\t\t\t\t\t429,\n\t\t\t\t\t\t\t404,\n\t\t\t\t\t\t\t500,\n\t\t\t\t\t\t\t501,\n\t\t\t\t\t\t\t502,\n\t\t\t\t\t\t\t503,\n\t\t\t\t\t\t\t504,\n\t\t\t\t\t\t\t505\n\t\t\t\t\t\t],\n\t\t\t\t\t\t\"tcp_failures\": 0,\n\t\t\t\t\t\t\"timeouts\": 0,\n\t\t\t\t\t\t\"http_failures\": 0,\n\t\t\t\t\t\t\"interval\": 0\n\t\t\t\t\t},\n\t\t\t\t\t\"http_path\": \"/\",\n\t\t\t\t\t\"timeout\": 1,\n\t\t\t\t\t\"healthy\": {\n\t\t\t\t\t\t\"http_statuses\": [\n\t\t\t\t\t\t\t200,\n\t\t\t\t\t\t\t302\n\t\t\t\t\t\t],\n\t\t\t\t\t\t\"interval\": 0,\n\t\t\t\t\t\t\"successes\": 0\n\t\t\t\t\t},\n\t\t\t\t\t\"https_sni\": \"example.com\",\n\t\t\t\t\t\"concurrency\": 10,\n\t\t\t\t\t\"type\": \"http\"\n\t\t\t\t},\n\t\t\t\t\"passive\": {\n\t\t\t\t\t\"unhealthy\": {\n\t\t\t\t\t\t\"http_failures\": 0,\n\t\t\t\t\t\t\"http_statuses\": [\n\t\t\t\t\t\t\t429,\n\t\t\t\t\t\t\t500,\n\t\t\t\t\t\t\t503\n\t\t\t\t\t\t],\n\t\t\t\t\t\t\"tcp_failures\": 0,\n\t\t\t\t\t\t\"timeouts\": 0\n\t\t\t\t\t},\n\t\t\t\t\t\"type\": \"http\",\n\t\t\t\t\t\"healthy\": {\n\t\t\t\t\t\t\"successes\": 0,\n\t\t\t\t\t\t\"http_statuses\": [\n\t\t\t\t\t\t\t200,\n\t\t\t\t\t\t\t201,\n\t\t\t\t\t\t\t202,\n\t\t\t\t\t\t\t203,\n\t\t\t\t\t\t\t204,\n\t\t\t\t\t\t\t205,\n\t\t\t\t\t\t\t206,\n\t\t\t\t\t\t\t207,\n\t\t\t\t\t\t\t208,\n\t\t\t\t\t\t\t226,\n\t\t\t\t\t\t\t300,\n\t\t\t\t\t\t\t301,\n\t\t\t\t\t\t\t302,\n\t\t\t\t\t\t\t303,\n\t\t\t\t\t\t\t304,\n\t\t\t\t\t\t\t305,\n\t\t\t\t\t\t\t306,\n\t\t\t\t\t\t\t307,\n\t\t\t\t\t\t\t308\n\t\t\t\t\t\t]\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"threshold\": 0\n\t\t\t},\n\t\t\t\"tags\": [\n\t\t\t\t\"admin\",\n\t\t\t\t\"high-priority\",\n\t\t\t\t\"critical\"\n\t\t\t],\n\t\t\t\"host_header\": \"example.com\"\n\t\t}\n\t],\n\t\"next\": \"http://localhost:8001/upstreams?offset=6378122c-a0a1-438d-a5c6-efabae9fb969\"\n}" + } + ] + } + ], + "description": "https://docs.konghq.com/2.0.x/admin-api/#list-upstreams" + }, + { + "name": "Retrieve Upstream", + "item": [ + { + "name": "Retrieve Upstream", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{gateway}}/upstreams/:upstreamNameOrId", + "host": [ + "{{gateway}}" + ], + "path": [ + "upstreams", + ":upstreamNameOrId" + ], + "variable": [ + { + "key": "upstreamNameOrId", + "value": "my-upstream", + "description": "The unique identifier or the name of the Upstream to retrieve." + } + ] + }, + "description": "# Retrieve Upstream [konghq](https://docs.konghq.com/2.0.x/admin-api/#retrieve-upstream-1)\n\n \n \n \n \n \n \n \n \n \n \n \n \n
AttributesMandatoryTypeDescription
upstream name or idrequiredpathThe unique identifier or the name of the Upstream to retrieve.
" + }, + "response": [ + { + "name": "Retrieve Upstream-200", + "originalRequest": { + "method": "GET", + "header": [], + "url": { + "raw": "{{gateway}}/upstreams/:upstreamNameOrId", + "host": [ + "{{gateway}}" + ], + "path": [ + "upstreams", + ":upstreamNameOrId" + ], + "variable": [ + { + "key": "upstreamNameOrId", + "value": "my-upstream", + "description": "The unique identifier or the name of the Upstream to retrieve." + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "Text", + "header": [ + { + "key": "Date", + "value": "Thu, 12 Mar 2020 20:39:05 GMT" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "Server", + "value": "kong/2.0.1" + }, + { + "key": "Content-Length", + "value": "922" + }, + { + "key": "X-Kong-Admin-Latency", + "value": "1" + } + ], + "cookie": [], + "body": "{\n \"created_at\": 1584044267,\n \"hash_on\": \"none\",\n \"id\": \"f8d38987-1eb6-4cb2-a7c8-6b11a17de911\",\n \"algorithm\": \"round-robin\",\n \"name\": \"my-upstream\",\n \"tags\": [\n \"user-level\",\n \"low-priority\"\n ],\n \"hash_fallback_header\": null,\n \"hash_fallback\": \"none\",\n \"hash_on_cookie\": null,\n \"host_header\": \"example.com\",\n \"hash_on_cookie_path\": \"/\",\n \"healthchecks\": {\n \"threshold\": 0,\n \"active\": {\n \"unhealthy\": {\n \"http_statuses\": [\n 429,\n 404,\n 500,\n 501,\n 502,\n 503,\n 504,\n 505\n ],\n \"tcp_failures\": 0,\n \"timeouts\": 0,\n \"http_failures\": 0,\n \"interval\": 0\n },\n \"type\": \"http\",\n \"http_path\": \"/\",\n \"timeout\": 1,\n \"healthy\": {\n \"successes\": 0,\n \"interval\": 0,\n \"http_statuses\": [\n 200,\n 302\n ]\n },\n \"https_sni\": \"example.com\",\n \"https_verify_certificate\": true,\n \"concurrency\": 10\n },\n \"passive\": {\n \"unhealthy\": {\n \"http_failures\": 0,\n \"http_statuses\": [\n 429,\n 500,\n 503\n ],\n \"tcp_failures\": 0,\n \"timeouts\": 0\n },\n \"healthy\": {\n \"http_statuses\": [\n 200,\n 201,\n 202,\n 203,\n 204,\n 205,\n 206,\n 207,\n 208,\n 226,\n 300,\n 301,\n 302,\n 303,\n 304,\n 305,\n 306,\n 307,\n 308\n ],\n \"successes\": 0\n },\n \"type\": \"http\"\n }\n },\n \"hash_on_header\": null,\n \"slots\": 10000\n}" + } + ] + }, + { + "name": "Retrieve Upstream Associated to a Specific Target", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{gateway}}/targets/:targetHost:portOrId/upstream", + "host": [ + "{{gateway}}" + ], + "path": [ + "targets", + ":targetHost:portOrId", + "upstream" + ], + "variable": [ + { + "key": "targetHost:portOrId", + "value": "", + "description": "The unique identifier or the host:port of the Target associated to the Upstream to be retrieved." + } + ] + }, + "description": "# Retrieve Upstream Associated to a Specific Target [konghq](https://docs.konghq.com/2.0.x/admin-api/#retrieve-upstream-associated-to-a-specific-target)\n\n \n \n \n \n \n \n \n \n \n \n \n \n
AttributesMandatoryTypeDescription
target host:port or idrequiredpathThe unique identifier or the host:port of the Target associated to the Upstream to be retrieved.
" + }, + "response": [] + } + ], + "description": "https://docs.konghq.com/2.0.x/admin-api/#retrieve-upstream", + "event": [ + { + "listen": "prerequest", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + }, + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + } + ] + }, + { + "name": "Update Upstream", + "item": [ + { + "name": "Update Upstream", + "request": { + "method": "PATCH", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"hash_on\": \"none\",\r\n \"algorithm\": \"round-robin\",\r\n \"name\": \"my-upstream\",\r\n \"tags\": [\r\n \"user-level\",\r\n \"low-priority\"\r\n ],\r\n \"hash_fallback_header\": null,\r\n \"hash_fallback\": \"none\",\r\n \"hash_on_cookie\": null,\r\n \"host_header\": \"example.com\",\r\n \"hash_on_cookie_path\": \"/\",\r\n \"healthchecks\": {\r\n \"threshold\": 0,\r\n \"active\": {\r\n \"unhealthy\": {\r\n \"http_statuses\": [\r\n 429,\r\n 404,\r\n 500,\r\n 501,\r\n 502,\r\n 503,\r\n 504,\r\n 505\r\n ],\r\n \"tcp_failures\": 0,\r\n \"timeouts\": 0,\r\n \"http_failures\": 0,\r\n \"interval\": 0\r\n },\r\n \"type\": \"http\",\r\n \"http_path\": \"/\",\r\n \"timeout\": 1,\r\n \"healthy\": {\r\n \"successes\": 0,\r\n \"interval\": 0,\r\n \"http_statuses\": [\r\n 200,\r\n 302\r\n ]\r\n },\r\n \"https_sni\": \"example.com\",\r\n \"https_verify_certificate\": true,\r\n \"concurrency\": 10\r\n },\r\n \"passive\": {\r\n \"unhealthy\": {\r\n \"http_failures\": 0,\r\n \"http_statuses\": [\r\n 429,\r\n 500,\r\n 503\r\n ],\r\n \"tcp_failures\": 0,\r\n \"timeouts\": 0\r\n },\r\n \"healthy\": {\r\n \"http_statuses\": [\r\n 200,\r\n 201,\r\n 202,\r\n 203,\r\n 204,\r\n 205,\r\n 206,\r\n 207,\r\n 208,\r\n 226,\r\n 300,\r\n 301,\r\n 302,\r\n 303,\r\n 304,\r\n 305,\r\n 306,\r\n 307,\r\n 308\r\n ],\r\n \"successes\": 0\r\n },\r\n \"type\": \"http\"\r\n }\r\n },\r\n \"hash_on_header\": null,\r\n \"slots\": 10000\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{gateway}}/upstreams/:upstreamNameOrId", + "host": [ + "{{gateway}}" + ], + "path": [ + "upstreams", + ":upstreamNameOrId" + ], + "variable": [ + { + "key": "upstreamNameOrId", + "value": "my-upstream" + } + ] + }, + "description": "# Update Upstream [konghq](https://docs.konghq.com/2.0.x/admin-api/#update-upstream-1)\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n
AttributesMandatoryTypeDescription
upstream name or idrequiredpathThe unique identifier or the name of the Upstream to update.
\n\n# Request Body\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
AttributesMandatoryTypeDescription
namerequiredbodyThis is a hostname, which must be equal to the host of a Service.
algorithmoptionalbodyWhich load balancing algorithm to use. Accepted values are: \"consistent-hashing\", \"least-connections\", \"round-robin\". Defaults to \"round-robin\".
hash_onoptionalbodyWhat to use as hashing input. Using none results in a weighted-round-robin scheme with no hashing. Accepted values are: \"none\", \"consumer\", \"ip\", \"header\", \"cookie\". Defaults to \"none\".
hash_fallbackoptionalbodyWhat to use as hashing input if the primary hash_on does not return a hash (eg. header is missing, or no consumer identified). Not available if hash_on is set to cookie. Accepted values are: \"none\", \"consumer\", \"ip\", \"header\", \"cookie\". Defaults to \"none\".
hash_on_headersemi-optionalbodyThe header name to take the value from as hash input. Only required when hash_on is set to header.
hash_fallback_headersemi-optionalbodyThe header name to take the value from as hash input. Only required when hash_fallback is set to header.
hash_on_cookiesemi-optionalbodyThe cookie name to take the value from as hash input. Only required when hash_on or hash_fallback is set to cookie. If the specified cookie is not in the request, Kong will generate a value and set the cookie in the response.
hash_on_cookie_pathsemi-optionalbodyThe cookie path to set in the response headers. Only required when hash_on or hash_fallback is set to cookie. Defaults to \"/\".
slotsoptionalbodyThe number of slots in the loadbalancer algorithm (10-65536). Defaults to 10000.
healthchecks.active.https_verify_certificateoptionalbodyWhether to check the validity of the SSL certificate of the remote host when performing active health checks using HTTPS. Defaults to true.
healthchecks.active.unhealthy.http_statusesoptionalbodyAn array of HTTP statuses to consider a failure, indicating unhealthiness, when returned by a probe in active health checks. Defaults to [429, 404, 500, 501, 502, 503, 504, 505]. With form-encoded, the notation is http_statuses[]=429&http_statuses[]=404. With JSON, use an Array.
healthchecks.active.unhealthy.tcp_failuresoptionalbodyNumber of TCP failures in active probes to consider a target unhealthy. Defaults to 0.
healthchecks.active.unhealthy.timeoutsoptionalbodyNumber of timeouts in active probes to consider a target unhealthy. Defaults to 0.
healthchecks.active.unhealthy.http_failuresoptionalbodyNumber of HTTP failures in active probes (as defined by healthchecks.active.unhealthy.http_statuses) to consider a target unhealthy. Defaults to 0.
healthchecks.active.unhealthy.intervaloptionalbodyInterval between active health checks for unhealthy targets (in seconds). A value of zero indicates that active probes for unhealthy targets should not be performed. Defaults to 0.
healthchecks.active.http_pathoptionalbodyPath to use in GET HTTP request to run as a probe on active health checks. Defaults to \"/\".
healthchecks.active.timeoutoptionalbodySocket timeout for active health checks (in seconds). Defaults to 1.
healthchecks.active.healthy.http_statusesoptionalbodyAn array of HTTP statuses to consider a success, indicating healthiness, when returned by a probe in active health checks. Defaults to [200, 302]. With form-encoded, the notation is http_statuses[]=200&http_statuses[]=302. With JSON, use an Array.
healthchecks.active.healthy.intervaloptionalbodyInterval between active health checks for healthy targets (in seconds). A value of zero indicates that active probes for healthy targets should not be performed. Defaults to 0.
healthchecks.active.healthy.successesoptionalbodyNumber of successes in active probes (as defined by healthchecks.active.healthy.http_statuses) to consider a target healthy. Defaults to 0.
healthchecks.active.https_snioptionalbodyThe hostname to use as an SNI (Server Name Identification) when performing active health checks using HTTPS. This is particularly useful when Targets are configured using IPs, so that the target host’s certificate can be verified with the proper SNI.
healthchecks.active.concurrencyoptionalbodyNumber of targets to check concurrently in active health checks. Defaults to 10.
healthchecks.active.typeoptionalbodyWhether to perform active health checks using HTTP or HTTPS, or just attempt a TCP connection. Accepted values are: \"tcp\", \"http\", \"https\", \"grpc\", \"grpcs\". Defaults to \"http\".
healthchecks.passive.unhealthy.http_failuresoptionalbodyNumber of HTTP failures in proxied traffic (as defined by healthchecks.passive.unhealthy.http_statuses) to consider a target unhealthy, as observed by passive health checks. Defaults to 0.
healthchecks.passive.unhealthy.http_statusesoptionalbodyAn array of HTTP statuses which represent unhealthiness when produced by proxied traffic, as observed by passive health checks. Defaults to [429, 500, 503]. With form-encoded, the notation is http_statuses[]=429&http_statuses[]=500. With JSON, use an Array.
healthchecks.passive.unhealthy.tcp_failuresoptionalbodyNumber of TCP failures in proxied traffic to consider a target unhealthy, as observed by passive health checks. Defaults to 0.
healthchecks.passive.unhealthy.timeoutsoptionalbodyNumber of timeouts in proxied traffic to consider a target unhealthy, as observed by passive health checks. Defaults to 0.
healthchecks.passive.typeoptionalbodyWhether to perform passive health checks interpreting HTTP/HTTPS statuses, or just check for TCP connection success. In passive checks, http and https options are equivalent. Accepted values are: \"tcp\", \"http\", \"https\", \"grpc\", \"grpcs\". Defaults to \"http\".
healthchecks.passive.healthy.successesoptionalbodyNumber of successes in proxied traffic (as defined by healthchecks.passive.healthy.http_statuses) to consider a target healthy, as observed by passive health checks. Defaults to 0.
healthchecks.passive.healthy.http_statusesoptionalbodyAn array of HTTP statuses which represent healthiness when produced by proxied traffic, as observed by passive health checks. Defaults to [200, 201, 202, 203, 204, 205, 206, 207, 208, 226, 300, 301, 302, 303, 304, 305, 306, 307, 308]. With form-encoded, the notation is http_statuses[]=200&http_statuses[]=201. With JSON, use an Array.
healthchecks.thresholdoptionalbodyThe minimum percentage of the upstream’s targets’ weight that must be available for the whole upstream to be considered healthy. Defaults to 0.
tagsoptionalbodyAn optional set of strings associated with the Upstream, for grouping and filtering.
host_headeroptionalbodyThe hostname to be used as Host header when proxying requests through Kong.
" + }, + "response": [ + { + "name": "Update Upstream - 200", + "originalRequest": { + "method": "PATCH", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"hash_on\": \"none\",\r\n \"algorithm\": \"round-robin\",\r\n \"name\": \"my-upstream\",\r\n \"tags\": [\r\n \"user-level\",\r\n \"low-priority\"\r\n ],\r\n \"hash_fallback_header\": null,\r\n \"hash_fallback\": \"none\",\r\n \"hash_on_cookie\": null,\r\n \"host_header\": \"example.com\",\r\n \"hash_on_cookie_path\": \"/\",\r\n \"healthchecks\": {\r\n \"threshold\": 0,\r\n \"active\": {\r\n \"unhealthy\": {\r\n \"http_statuses\": [\r\n 429,\r\n 404,\r\n 500,\r\n 501,\r\n 502,\r\n 503,\r\n 504,\r\n 505\r\n ],\r\n \"tcp_failures\": 0,\r\n \"timeouts\": 0,\r\n \"http_failures\": 0,\r\n \"interval\": 0\r\n },\r\n \"type\": \"http\",\r\n \"http_path\": \"/\",\r\n \"timeout\": 1,\r\n \"healthy\": {\r\n \"successes\": 0,\r\n \"interval\": 0,\r\n \"http_statuses\": [\r\n 200,\r\n 302\r\n ]\r\n },\r\n \"https_sni\": \"example.com\",\r\n \"https_verify_certificate\": true,\r\n \"concurrency\": 10\r\n },\r\n \"passive\": {\r\n \"unhealthy\": {\r\n \"http_failures\": 0,\r\n \"http_statuses\": [\r\n 429,\r\n 500,\r\n 503\r\n ],\r\n \"tcp_failures\": 0,\r\n \"timeouts\": 0\r\n },\r\n \"healthy\": {\r\n \"http_statuses\": [\r\n 200,\r\n 201,\r\n 202,\r\n 203,\r\n 204,\r\n 205,\r\n 206,\r\n 207,\r\n 208,\r\n 226,\r\n 300,\r\n 301,\r\n 302,\r\n 303,\r\n 304,\r\n 305,\r\n 306,\r\n 307,\r\n 308\r\n ],\r\n \"successes\": 0\r\n },\r\n \"type\": \"http\"\r\n }\r\n },\r\n \"hash_on_header\": null,\r\n \"slots\": 10000\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{gateway}}/upstreams/:upstreamNameOrId", + "host": [ + "{{gateway}}" + ], + "path": [ + "upstreams", + ":upstreamNameOrId" + ], + "variable": [ + { + "key": "upstreamNameOrId", + "value": "my-upstream" + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "Text", + "header": [ + { + "key": "Date", + "value": "Thu, 12 Mar 2020 20:47:32 GMT" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "Server", + "value": "kong/2.0.1" + }, + { + "key": "Content-Length", + "value": "922" + }, + { + "key": "X-Kong-Admin-Latency", + "value": "21" + } + ], + "cookie": [], + "body": "{\n \"created_at\": 1584044267,\n \"hash_on\": \"none\",\n \"id\": \"f8d38987-1eb6-4cb2-a7c8-6b11a17de911\",\n \"algorithm\": \"round-robin\",\n \"name\": \"my-upstream\",\n \"tags\": [\n \"user-level\",\n \"low-priority\"\n ],\n \"hash_fallback_header\": null,\n \"hash_fallback\": \"none\",\n \"hash_on_cookie\": null,\n \"host_header\": \"example.com\",\n \"hash_on_cookie_path\": \"/\",\n \"healthchecks\": {\n \"threshold\": 0,\n \"active\": {\n \"unhealthy\": {\n \"http_statuses\": [\n 429,\n 404,\n 500,\n 501,\n 502,\n 503,\n 504,\n 505\n ],\n \"tcp_failures\": 0,\n \"timeouts\": 0,\n \"http_failures\": 0,\n \"interval\": 0\n },\n \"type\": \"http\",\n \"http_path\": \"/\",\n \"timeout\": 1,\n \"healthy\": {\n \"successes\": 0,\n \"interval\": 0,\n \"http_statuses\": [\n 200,\n 302\n ]\n },\n \"https_sni\": \"example.com\",\n \"https_verify_certificate\": true,\n \"concurrency\": 10\n },\n \"passive\": {\n \"unhealthy\": {\n \"http_failures\": 0,\n \"http_statuses\": [\n 429,\n 500,\n 503\n ],\n \"tcp_failures\": 0,\n \"timeouts\": 0\n },\n \"healthy\": {\n \"http_statuses\": [\n 200,\n 201,\n 202,\n 203,\n 204,\n 205,\n 206,\n 207,\n 208,\n 226,\n 300,\n 301,\n 302,\n 303,\n 304,\n 305,\n 306,\n 307,\n 308\n ],\n \"successes\": 0\n },\n \"type\": \"http\"\n }\n },\n \"hash_on_header\": null,\n \"slots\": 10000\n}" + } + ] + }, + { + "name": "Update Upstream Associated to a Specific Target", + "request": { + "method": "PATCH", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"hash_on\": \"none\",\r\n \"algorithm\": \"round-robin\",\r\n \"name\": \"my-upstream\",\r\n \"tags\": [\r\n \"user-level\",\r\n \"low-priority\"\r\n ],\r\n \"hash_fallback_header\": null,\r\n \"hash_fallback\": \"none\",\r\n \"hash_on_cookie\": null,\r\n \"host_header\": \"example.com\",\r\n \"hash_on_cookie_path\": \"/\",\r\n \"healthchecks\": {\r\n \"threshold\": 0,\r\n \"active\": {\r\n \"unhealthy\": {\r\n \"http_statuses\": [\r\n 429,\r\n 404,\r\n 500,\r\n 501,\r\n 502,\r\n 503,\r\n 504,\r\n 505\r\n ],\r\n \"tcp_failures\": 0,\r\n \"timeouts\": 0,\r\n \"http_failures\": 0,\r\n \"interval\": 0\r\n },\r\n \"type\": \"http\",\r\n \"http_path\": \"/\",\r\n \"timeout\": 1,\r\n \"healthy\": {\r\n \"successes\": 0,\r\n \"interval\": 0,\r\n \"http_statuses\": [\r\n 200,\r\n 302\r\n ]\r\n },\r\n \"https_sni\": \"example.com\",\r\n \"https_verify_certificate\": true,\r\n \"concurrency\": 10\r\n },\r\n \"passive\": {\r\n \"unhealthy\": {\r\n \"http_failures\": 0,\r\n \"http_statuses\": [\r\n 429,\r\n 500,\r\n 503\r\n ],\r\n \"tcp_failures\": 0,\r\n \"timeouts\": 0\r\n },\r\n \"healthy\": {\r\n \"http_statuses\": [\r\n 200,\r\n 201,\r\n 202,\r\n 203,\r\n 204,\r\n 205,\r\n 206,\r\n 207,\r\n 208,\r\n 226,\r\n 300,\r\n 301,\r\n 302,\r\n 303,\r\n 304,\r\n 305,\r\n 306,\r\n 307,\r\n 308\r\n ],\r\n \"successes\": 0\r\n },\r\n \"type\": \"http\"\r\n }\r\n },\r\n \"hash_on_header\": null,\r\n \"slots\": 10000\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{gateway}}/targets/:targetHost:portOrId/upstream", + "host": [ + "{{gateway}}" + ], + "path": [ + "targets", + ":targetHost:portOrId", + "upstream" + ], + "variable": [ + { + "key": "targetHost:portOrId", + "value": "" + } + ] + }, + "description": "# Update Upstream Associated to a Specific Target [konghq](https://docs.konghq.com/2.0.x/admin-api/#update-upstream-associated-to-a-specific-target)\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n
AttributesMandatoryTypeDescription
target host:port or idrequiredpathThe unique identifier or the host:port of the Target associated to the Upstream to be updated.
\n\n# Request Body\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
AttributesMandatoryTypeDescription
namerequiredbodyThis is a hostname, which must be equal to the host of a Service.
algorithmoptionalbodyWhich load balancing algorithm to use. Accepted values are: \"consistent-hashing\", \"least-connections\", \"round-robin\". Defaults to \"round-robin\".
hash_onoptionalbodyWhat to use as hashing input. Using none results in a weighted-round-robin scheme with no hashing. Accepted values are: \"none\", \"consumer\", \"ip\", \"header\", \"cookie\". Defaults to \"none\".
hash_fallbackoptionalbodyWhat to use as hashing input if the primary hash_on does not return a hash (eg. header is missing, or no consumer identified). Not available if hash_on is set to cookie. Accepted values are: \"none\", \"consumer\", \"ip\", \"header\", \"cookie\". Defaults to \"none\".
hash_on_headersemi-optionalbodyThe header name to take the value from as hash input. Only required when hash_on is set to header.
hash_fallback_headersemi-optionalbodyThe header name to take the value from as hash input. Only required when hash_fallback is set to header.
hash_on_cookiesemi-optionalbodyThe cookie name to take the value from as hash input. Only required when hash_on or hash_fallback is set to cookie. If the specified cookie is not in the request, Kong will generate a value and set the cookie in the response.
hash_on_cookie_pathsemi-optionalbodyThe cookie path to set in the response headers. Only required when hash_on or hash_fallback is set to cookie. Defaults to \"/\".
slotsoptionalbodyThe number of slots in the loadbalancer algorithm (10-65536). Defaults to 10000.
healthchecks.active.https_verify_certificateoptionalbodyWhether to check the validity of the SSL certificate of the remote host when performing active health checks using HTTPS. Defaults to true.
healthchecks.active.unhealthy.http_statusesoptionalbodyAn array of HTTP statuses to consider a failure, indicating unhealthiness, when returned by a probe in active health checks. Defaults to [429, 404, 500, 501, 502, 503, 504, 505]. With form-encoded, the notation is http_statuses[]=429&http_statuses[]=404. With JSON, use an Array.
healthchecks.active.unhealthy.tcp_failuresoptionalbodyNumber of TCP failures in active probes to consider a target unhealthy. Defaults to 0.
healthchecks.active.unhealthy.timeoutsoptionalbodyNumber of timeouts in active probes to consider a target unhealthy. Defaults to 0.
healthchecks.active.unhealthy.http_failuresoptionalbodyNumber of HTTP failures in active probes (as defined by healthchecks.active.unhealthy.http_statuses) to consider a target unhealthy. Defaults to 0.
healthchecks.active.unhealthy.intervaloptionalbodyInterval between active health checks for unhealthy targets (in seconds). A value of zero indicates that active probes for unhealthy targets should not be performed. Defaults to 0.
healthchecks.active.http_pathoptionalbodyPath to use in GET HTTP request to run as a probe on active health checks. Defaults to \"/\".
healthchecks.active.timeoutoptionalbodySocket timeout for active health checks (in seconds). Defaults to 1.
healthchecks.active.healthy.http_statusesoptionalbodyAn array of HTTP statuses to consider a success, indicating healthiness, when returned by a probe in active health checks. Defaults to [200, 302]. With form-encoded, the notation is http_statuses[]=200&http_statuses[]=302. With JSON, use an Array.
healthchecks.active.healthy.intervaloptionalbodyInterval between active health checks for healthy targets (in seconds). A value of zero indicates that active probes for healthy targets should not be performed. Defaults to 0.
healthchecks.active.healthy.successesoptionalbodyNumber of successes in active probes (as defined by healthchecks.active.healthy.http_statuses) to consider a target healthy. Defaults to 0.
healthchecks.active.https_snioptionalbodyThe hostname to use as an SNI (Server Name Identification) when performing active health checks using HTTPS. This is particularly useful when Targets are configured using IPs, so that the target host’s certificate can be verified with the proper SNI.
healthchecks.active.concurrencyoptionalbodyNumber of targets to check concurrently in active health checks. Defaults to 10.
healthchecks.active.typeoptionalbodyWhether to perform active health checks using HTTP or HTTPS, or just attempt a TCP connection. Accepted values are: \"tcp\", \"http\", \"https\", \"grpc\", \"grpcs\". Defaults to \"http\".
healthchecks.passive.unhealthy.http_failuresoptionalbodyNumber of HTTP failures in proxied traffic (as defined by healthchecks.passive.unhealthy.http_statuses) to consider a target unhealthy, as observed by passive health checks. Defaults to 0.
healthchecks.passive.unhealthy.http_statusesoptionalbodyAn array of HTTP statuses which represent unhealthiness when produced by proxied traffic, as observed by passive health checks. Defaults to [429, 500, 503]. With form-encoded, the notation is http_statuses[]=429&http_statuses[]=500. With JSON, use an Array.
healthchecks.passive.unhealthy.tcp_failuresoptionalbodyNumber of TCP failures in proxied traffic to consider a target unhealthy, as observed by passive health checks. Defaults to 0.
healthchecks.passive.unhealthy.timeoutsoptionalbodyNumber of timeouts in proxied traffic to consider a target unhealthy, as observed by passive health checks. Defaults to 0.
healthchecks.passive.typeoptionalbodyWhether to perform passive health checks interpreting HTTP/HTTPS statuses, or just check for TCP connection success. In passive checks, http and https options are equivalent. Accepted values are: \"tcp\", \"http\", \"https\", \"grpc\", \"grpcs\". Defaults to \"http\".
healthchecks.passive.healthy.successesoptionalbodyNumber of successes in proxied traffic (as defined by healthchecks.passive.healthy.http_statuses) to consider a target healthy, as observed by passive health checks. Defaults to 0.
healthchecks.passive.healthy.http_statusesoptionalbodyAn array of HTTP statuses which represent healthiness when produced by proxied traffic, as observed by passive health checks. Defaults to [200, 201, 202, 203, 204, 205, 206, 207, 208, 226, 300, 301, 302, 303, 304, 305, 306, 307, 308]. With form-encoded, the notation is http_statuses[]=200&http_statuses[]=201. With JSON, use an Array.
healthchecks.thresholdoptionalbodyThe minimum percentage of the upstream’s targets’ weight that must be available for the whole upstream to be considered healthy. Defaults to 0.
tagsoptionalbodyAn optional set of strings associated with the Upstream, for grouping and filtering.
host_headeroptionalbodyThe hostname to be used as Host header when proxying requests through Kong.
" + }, + "response": [] + } + ], + "description": "https://docs.konghq.com/2.0.x/admin-api/#update-upstream", + "event": [ + { + "listen": "prerequest", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + }, + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + } + ] + }, + { + "name": "Update Or Create Upstream", + "item": [ + { + "name": "Create Or Update Upstream", + "request": { + "method": "PUT", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"hash_on\": \"none\",\r\n \"algorithm\": \"round-robin\",\r\n \"name\": \"my-upstream\",\r\n \"tags\": [\r\n \"user-level\",\r\n \"low-priority\"\r\n ],\r\n \"hash_fallback_header\": null,\r\n \"hash_fallback\": \"none\",\r\n \"hash_on_cookie\": null,\r\n \"host_header\": \"example.com\",\r\n \"hash_on_cookie_path\": \"/\",\r\n \"healthchecks\": {\r\n \"threshold\": 0,\r\n \"active\": {\r\n \"unhealthy\": {\r\n \"http_statuses\": [\r\n 429,\r\n 404,\r\n 500,\r\n 501,\r\n 502,\r\n 503,\r\n 504,\r\n 505\r\n ],\r\n \"tcp_failures\": 0,\r\n \"timeouts\": 0,\r\n \"http_failures\": 0,\r\n \"interval\": 0\r\n },\r\n \"type\": \"http\",\r\n \"http_path\": \"/\",\r\n \"timeout\": 1,\r\n \"healthy\": {\r\n \"successes\": 0,\r\n \"interval\": 0,\r\n \"http_statuses\": [\r\n 200,\r\n 302\r\n ]\r\n },\r\n \"https_sni\": \"example.com\",\r\n \"https_verify_certificate\": true,\r\n \"concurrency\": 10\r\n },\r\n \"passive\": {\r\n \"unhealthy\": {\r\n \"http_failures\": 0,\r\n \"http_statuses\": [\r\n 429,\r\n 500,\r\n 503\r\n ],\r\n \"tcp_failures\": 0,\r\n \"timeouts\": 0\r\n },\r\n \"healthy\": {\r\n \"http_statuses\": [\r\n 200,\r\n 201,\r\n 202,\r\n 203,\r\n 204,\r\n 205,\r\n 206,\r\n 207,\r\n 208,\r\n 226,\r\n 300,\r\n 301,\r\n 302,\r\n 303,\r\n 304,\r\n 305,\r\n 306,\r\n 307,\r\n 308\r\n ],\r\n \"successes\": 0\r\n },\r\n \"type\": \"http\"\r\n }\r\n },\r\n \"hash_on_header\": null,\r\n \"slots\": 10000\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{gateway}}/upstreams/:upstreamNameOrId", + "host": [ + "{{gateway}}" + ], + "path": [ + "upstreams", + ":upstreamNameOrId" + ], + "variable": [ + { + "key": "upstreamNameOrId", + "value": "my-upstream" + } + ] + }, + "description": "# Create Or Update Upstream [konghq](https://docs.konghq.com/2.0.x/admin-api/#create-or-update-upstream)\n* Inserts (or replaces) the Upstream under the requested resource with the definition specified in the body. The Upstream will be identified via the name or id attribute.\n\n* When the name or id attribute has the structure of a UUID, the Upstream being inserted/replaced will be identified by its id. Otherwise it will be identified by its name.\n\n* When creating a new Upstream without specifying id (neither in the URL nor in the body), then it will be auto-generated.\n\n* Notice that specifying a name in the URL and a different one in the request body is not allowed.\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n
AttributesMandatoryTypeDescription
upstream name or idrequiredpathThe unique identifier or the name of the Upstream to create or update.
\n\n# Request Body\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
AttributesMandatoryTypeDescription
namerequiredbodyThis is a hostname, which must be equal to the host of a Service.
algorithmoptionalbodyWhich load balancing algorithm to use. Accepted values are: \"consistent-hashing\", \"least-connections\", \"round-robin\". Defaults to \"round-robin\".
hash_onoptionalbodyWhat to use as hashing input. Using none results in a weighted-round-robin scheme with no hashing. Accepted values are: \"none\", \"consumer\", \"ip\", \"header\", \"cookie\". Defaults to \"none\".
hash_fallbackoptionalbodyWhat to use as hashing input if the primary hash_on does not return a hash (eg. header is missing, or no consumer identified). Not available if hash_on is set to cookie. Accepted values are: \"none\", \"consumer\", \"ip\", \"header\", \"cookie\". Defaults to \"none\".
hash_on_headersemi-optionalbodyThe header name to take the value from as hash input. Only required when hash_on is set to header.
hash_fallback_headersemi-optionalbodyThe header name to take the value from as hash input. Only required when hash_fallback is set to header.
hash_on_cookiesemi-optionalbodyThe cookie name to take the value from as hash input. Only required when hash_on or hash_fallback is set to cookie. If the specified cookie is not in the request, Kong will generate a value and set the cookie in the response.
hash_on_cookie_pathsemi-optionalbodyThe cookie path to set in the response headers. Only required when hash_on or hash_fallback is set to cookie. Defaults to \"/\".
slotsoptionalbodyThe number of slots in the loadbalancer algorithm (10-65536). Defaults to 10000.
healthchecks.active.https_verify_certificateoptionalbodyWhether to check the validity of the SSL certificate of the remote host when performing active health checks using HTTPS. Defaults to true.
healthchecks.active.unhealthy.http_statusesoptionalbodyAn array of HTTP statuses to consider a failure, indicating unhealthiness, when returned by a probe in active health checks. Defaults to [429, 404, 500, 501, 502, 503, 504, 505]. With form-encoded, the notation is http_statuses[]=429&http_statuses[]=404. With JSON, use an Array.
healthchecks.active.unhealthy.tcp_failuresoptionalbodyNumber of TCP failures in active probes to consider a target unhealthy. Defaults to 0.
healthchecks.active.unhealthy.timeoutsoptionalbodyNumber of timeouts in active probes to consider a target unhealthy. Defaults to 0.
healthchecks.active.unhealthy.http_failuresoptionalbodyNumber of HTTP failures in active probes (as defined by healthchecks.active.unhealthy.http_statuses) to consider a target unhealthy. Defaults to 0.
healthchecks.active.unhealthy.intervaloptionalbodyInterval between active health checks for unhealthy targets (in seconds). A value of zero indicates that active probes for unhealthy targets should not be performed. Defaults to 0.
healthchecks.active.http_pathoptionalbodyPath to use in GET HTTP request to run as a probe on active health checks. Defaults to \"/\".
healthchecks.active.timeoutoptionalbodySocket timeout for active health checks (in seconds). Defaults to 1.
healthchecks.active.healthy.http_statusesoptionalbodyAn array of HTTP statuses to consider a success, indicating healthiness, when returned by a probe in active health checks. Defaults to [200, 302]. With form-encoded, the notation is http_statuses[]=200&http_statuses[]=302. With JSON, use an Array.
healthchecks.active.healthy.intervaloptionalbodyInterval between active health checks for healthy targets (in seconds). A value of zero indicates that active probes for healthy targets should not be performed. Defaults to 0.
healthchecks.active.healthy.successesoptionalbodyNumber of successes in active probes (as defined by healthchecks.active.healthy.http_statuses) to consider a target healthy. Defaults to 0.
healthchecks.active.https_snioptionalbodyThe hostname to use as an SNI (Server Name Identification) when performing active health checks using HTTPS. This is particularly useful when Targets are configured using IPs, so that the target host’s certificate can be verified with the proper SNI.
healthchecks.active.concurrencyoptionalbodyNumber of targets to check concurrently in active health checks. Defaults to 10.
healthchecks.active.typeoptionalbodyWhether to perform active health checks using HTTP or HTTPS, or just attempt a TCP connection. Accepted values are: \"tcp\", \"http\", \"https\", \"grpc\", \"grpcs\". Defaults to \"http\".
healthchecks.passive.unhealthy.http_failuresoptionalbodyNumber of HTTP failures in proxied traffic (as defined by healthchecks.passive.unhealthy.http_statuses) to consider a target unhealthy, as observed by passive health checks. Defaults to 0.
healthchecks.passive.unhealthy.http_statusesoptionalbodyAn array of HTTP statuses which represent unhealthiness when produced by proxied traffic, as observed by passive health checks. Defaults to [429, 500, 503]. With form-encoded, the notation is http_statuses[]=429&http_statuses[]=500. With JSON, use an Array.
healthchecks.passive.unhealthy.tcp_failuresoptionalbodyNumber of TCP failures in proxied traffic to consider a target unhealthy, as observed by passive health checks. Defaults to 0.
healthchecks.passive.unhealthy.timeoutsoptionalbodyNumber of timeouts in proxied traffic to consider a target unhealthy, as observed by passive health checks. Defaults to 0.
healthchecks.passive.typeoptionalbodyWhether to perform passive health checks interpreting HTTP/HTTPS statuses, or just check for TCP connection success. In passive checks, http and https options are equivalent. Accepted values are: \"tcp\", \"http\", \"https\", \"grpc\", \"grpcs\". Defaults to \"http\".
healthchecks.passive.healthy.successesoptionalbodyNumber of successes in proxied traffic (as defined by healthchecks.passive.healthy.http_statuses) to consider a target healthy, as observed by passive health checks. Defaults to 0.
healthchecks.passive.healthy.http_statusesoptionalbodyAn array of HTTP statuses which represent healthiness when produced by proxied traffic, as observed by passive health checks. Defaults to [200, 201, 202, 203, 204, 205, 206, 207, 208, 226, 300, 301, 302, 303, 304, 305, 306, 307, 308]. With form-encoded, the notation is http_statuses[]=200&http_statuses[]=201. With JSON, use an Array.
healthchecks.thresholdoptionalbodyThe minimum percentage of the upstream’s targets’ weight that must be available for the whole upstream to be considered healthy. Defaults to 0.
tagsoptionalbodyAn optional set of strings associated with the Upstream, for grouping and filtering.
host_headeroptionalbodyThe hostname to be used as Host header when proxying requests through Kong.
" + }, + "response": [] + }, + { + "name": "Create Or Update Upstream Associated to a Specific Target", + "request": { + "method": "PUT", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"hash_on\": \"none\",\r\n \"algorithm\": \"round-robin\",\r\n \"name\": \"my-upstream\",\r\n \"tags\": [\r\n \"user-level\",\r\n \"low-priority\"\r\n ],\r\n \"hash_fallback_header\": null,\r\n \"hash_fallback\": \"none\",\r\n \"hash_on_cookie\": null,\r\n \"host_header\": \"example.com\",\r\n \"hash_on_cookie_path\": \"/\",\r\n \"healthchecks\": {\r\n \"threshold\": 0,\r\n \"active\": {\r\n \"unhealthy\": {\r\n \"http_statuses\": [\r\n 429,\r\n 404,\r\n 500,\r\n 501,\r\n 502,\r\n 503,\r\n 504,\r\n 505\r\n ],\r\n \"tcp_failures\": 0,\r\n \"timeouts\": 0,\r\n \"http_failures\": 0,\r\n \"interval\": 0\r\n },\r\n \"type\": \"http\",\r\n \"http_path\": \"/\",\r\n \"timeout\": 1,\r\n \"healthy\": {\r\n \"successes\": 0,\r\n \"interval\": 0,\r\n \"http_statuses\": [\r\n 200,\r\n 302\r\n ]\r\n },\r\n \"https_sni\": \"example.com\",\r\n \"https_verify_certificate\": true,\r\n \"concurrency\": 10\r\n },\r\n \"passive\": {\r\n \"unhealthy\": {\r\n \"http_failures\": 0,\r\n \"http_statuses\": [\r\n 429,\r\n 500,\r\n 503\r\n ],\r\n \"tcp_failures\": 0,\r\n \"timeouts\": 0\r\n },\r\n \"healthy\": {\r\n \"http_statuses\": [\r\n 200,\r\n 201,\r\n 202,\r\n 203,\r\n 204,\r\n 205,\r\n 206,\r\n 207,\r\n 208,\r\n 226,\r\n 300,\r\n 301,\r\n 302,\r\n 303,\r\n 304,\r\n 305,\r\n 306,\r\n 307,\r\n 308\r\n ],\r\n \"successes\": 0\r\n },\r\n \"type\": \"http\"\r\n }\r\n },\r\n \"hash_on_header\": null,\r\n \"slots\": 10000\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{gateway}}/targets/:targetHost:portOrId/upstream", + "host": [ + "{{gateway}}" + ], + "path": [ + "targets", + ":targetHost:portOrId", + "upstream" + ], + "variable": [ + { + "key": "targetHost:portOrId", + "value": "" + } + ] + }, + "description": "# Create Or Update Upstream Associated to a Specific Target [konghq](https://docs.konghq.com/2.0.x/admin-api/#create-or-update-upstream-associated-to-a-specific-target)\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n
AttributesMandatoryTypeDescription
target host:port or idrequiredpathThe unique identifier or the host:port of the Target associated to the Upstream to be created or updated.
\n\n# Request Body\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
AttributesMandatoryTypeDescription
namerequiredbodyThis is a hostname, which must be equal to the host of a Service.
algorithmoptionalbodyWhich load balancing algorithm to use. Accepted values are: \"consistent-hashing\", \"least-connections\", \"round-robin\". Defaults to \"round-robin\".
hash_onoptionalbodyWhat to use as hashing input. Using none results in a weighted-round-robin scheme with no hashing. Accepted values are: \"none\", \"consumer\", \"ip\", \"header\", \"cookie\". Defaults to \"none\".
hash_fallbackoptionalbodyWhat to use as hashing input if the primary hash_on does not return a hash (eg. header is missing, or no consumer identified). Not available if hash_on is set to cookie. Accepted values are: \"none\", \"consumer\", \"ip\", \"header\", \"cookie\". Defaults to \"none\".
hash_on_headersemi-optionalbodyThe header name to take the value from as hash input. Only required when hash_on is set to header.
hash_fallback_headersemi-optionalbodyThe header name to take the value from as hash input. Only required when hash_fallback is set to header.
hash_on_cookiesemi-optionalbodyThe cookie name to take the value from as hash input. Only required when hash_on or hash_fallback is set to cookie. If the specified cookie is not in the request, Kong will generate a value and set the cookie in the response.
hash_on_cookie_pathsemi-optionalbodyThe cookie path to set in the response headers. Only required when hash_on or hash_fallback is set to cookie. Defaults to \"/\".
slotsoptionalbodyThe number of slots in the loadbalancer algorithm (10-65536). Defaults to 10000.
healthchecks.active.https_verify_certificateoptionalbodyWhether to check the validity of the SSL certificate of the remote host when performing active health checks using HTTPS. Defaults to true.
healthchecks.active.unhealthy.http_statusesoptionalbodyAn array of HTTP statuses to consider a failure, indicating unhealthiness, when returned by a probe in active health checks. Defaults to [429, 404, 500, 501, 502, 503, 504, 505]. With form-encoded, the notation is http_statuses[]=429&http_statuses[]=404. With JSON, use an Array.
healthchecks.active.unhealthy.tcp_failuresoptionalbodyNumber of TCP failures in active probes to consider a target unhealthy. Defaults to 0.
healthchecks.active.unhealthy.timeoutsoptionalbodyNumber of timeouts in active probes to consider a target unhealthy. Defaults to 0.
healthchecks.active.unhealthy.http_failuresoptionalbodyNumber of HTTP failures in active probes (as defined by healthchecks.active.unhealthy.http_statuses) to consider a target unhealthy. Defaults to 0.
healthchecks.active.unhealthy.intervaloptionalbodyInterval between active health checks for unhealthy targets (in seconds). A value of zero indicates that active probes for unhealthy targets should not be performed. Defaults to 0.
healthchecks.active.http_pathoptionalbodyPath to use in GET HTTP request to run as a probe on active health checks. Defaults to \"/\".
healthchecks.active.timeoutoptionalbodySocket timeout for active health checks (in seconds). Defaults to 1.
healthchecks.active.healthy.http_statusesoptionalbodyAn array of HTTP statuses to consider a success, indicating healthiness, when returned by a probe in active health checks. Defaults to [200, 302]. With form-encoded, the notation is http_statuses[]=200&http_statuses[]=302. With JSON, use an Array.
healthchecks.active.healthy.intervaloptionalbodyInterval between active health checks for healthy targets (in seconds). A value of zero indicates that active probes for healthy targets should not be performed. Defaults to 0.
healthchecks.active.healthy.successesoptionalbodyNumber of successes in active probes (as defined by healthchecks.active.healthy.http_statuses) to consider a target healthy. Defaults to 0.
healthchecks.active.https_snioptionalbodyThe hostname to use as an SNI (Server Name Identification) when performing active health checks using HTTPS. This is particularly useful when Targets are configured using IPs, so that the target host’s certificate can be verified with the proper SNI.
healthchecks.active.concurrencyoptionalbodyNumber of targets to check concurrently in active health checks. Defaults to 10.
healthchecks.active.typeoptionalbodyWhether to perform active health checks using HTTP or HTTPS, or just attempt a TCP connection. Accepted values are: \"tcp\", \"http\", \"https\", \"grpc\", \"grpcs\". Defaults to \"http\".
healthchecks.passive.unhealthy.http_failuresoptionalbodyNumber of HTTP failures in proxied traffic (as defined by healthchecks.passive.unhealthy.http_statuses) to consider a target unhealthy, as observed by passive health checks. Defaults to 0.
healthchecks.passive.unhealthy.http_statusesoptionalbodyAn array of HTTP statuses which represent unhealthiness when produced by proxied traffic, as observed by passive health checks. Defaults to [429, 500, 503]. With form-encoded, the notation is http_statuses[]=429&http_statuses[]=500. With JSON, use an Array.
healthchecks.passive.unhealthy.tcp_failuresoptionalbodyNumber of TCP failures in proxied traffic to consider a target unhealthy, as observed by passive health checks. Defaults to 0.
healthchecks.passive.unhealthy.timeoutsoptionalbodyNumber of timeouts in proxied traffic to consider a target unhealthy, as observed by passive health checks. Defaults to 0.
healthchecks.passive.typeoptionalbodyWhether to perform passive health checks interpreting HTTP/HTTPS statuses, or just check for TCP connection success. In passive checks, http and https options are equivalent. Accepted values are: \"tcp\", \"http\", \"https\", \"grpc\", \"grpcs\". Defaults to \"http\".
healthchecks.passive.healthy.successesoptionalbodyNumber of successes in proxied traffic (as defined by healthchecks.passive.healthy.http_statuses) to consider a target healthy, as observed by passive health checks. Defaults to 0.
healthchecks.passive.healthy.http_statusesoptionalbodyAn array of HTTP statuses which represent healthiness when produced by proxied traffic, as observed by passive health checks. Defaults to [200, 201, 202, 203, 204, 205, 206, 207, 208, 226, 300, 301, 302, 303, 304, 305, 306, 307, 308]. With form-encoded, the notation is http_statuses[]=200&http_statuses[]=201. With JSON, use an Array.
healthchecks.thresholdoptionalbodyThe minimum percentage of the upstream’s targets’ weight that must be available for the whole upstream to be considered healthy. Defaults to 0.
tagsoptionalbodyAn optional set of strings associated with the Upstream, for grouping and filtering.
host_headeroptionalbodyThe hostname to be used as Host header when proxying requests through Kong.
" + }, + "response": [] + } + ], + "description": "https://docs.konghq.com/2.0.x/admin-api/#update-or-create-upstream", + "event": [ + { + "listen": "prerequest", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + }, + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + } + ] + }, + { + "name": "Delete Upstream", + "item": [ + { + "name": "Delete Upstream", + "request": { + "method": "DELETE", + "header": [], + "url": { + "raw": "{{gateway}}/upstreams/:upstreamNameOrId", + "host": [ + "{{gateway}}" + ], + "path": [ + "upstreams", + ":upstreamNameOrId" + ], + "variable": [ + { + "key": "upstreamNameOrId", + "value": "my-upstream", + "description": "The unique identifier or the name of the Upstream to retrieve." + } + ] + }, + "description": "# Delete Upstream [konghq](https://docs.konghq.com/2.0.x/admin-api/#delete-upstream-1)\n\n \n \n \n \n \n \n \n \n \n \n \n \n
AttributesMandatoryTypeDescription
upstream name or idrequiredpathThe unique identifier or the name of the Upstream to delete.
" + }, + "response": [ + { + "name": "Delete Upstream - 204", + "originalRequest": { + "method": "DELETE", + "header": [], + "url": { + "raw": "{{gateway}}/upstreams/:upstreamNameOrId", + "host": [ + "{{gateway}}" + ], + "path": [ + "upstreams", + ":upstreamNameOrId" + ], + "variable": [ + { + "key": "upstreamNameOrId", + "value": "my-upstream", + "description": "The unique identifier or the name of the Upstream to delete" + } + ] + } + }, + "status": "No Content", + "code": 204, + "_postman_previewlanguage": "Text", + "header": [ + { + "key": "Date", + "value": "Thu, 12 Mar 2020 21:14:03 GMT" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "Server", + "value": "kong/2.0.1" + }, + { + "key": "X-Kong-Admin-Latency", + "value": "27" + } + ], + "cookie": [], + "body": "" + } + ] + }, + { + "name": "Delete Upstream Associated to a Specific Target", + "request": { + "method": "DELETE", + "header": [], + "url": { + "raw": "{{gateway}}/targets/:targetHost:portOrId/upstream", + "host": [ + "{{gateway}}" + ], + "path": [ + "targets", + ":targetHost:portOrId", + "upstream" + ], + "variable": [ + { + "key": "targetHost:portOrId", + "value": "", + "description": "The unique identifier or the host:port of the Target associated to the Upstream to be delete." + } + ] + }, + "description": "# Delete Upstream Associated to a Specific Target [konghq](https://docs.konghq.com/2.0.x/admin-api/#delete-upstream-associated-to-a-specific-target)\n\n \n \n \n \n \n \n \n \n \n \n \n \n
AttributesMandatoryTypeDescription
target host:port or idrequiredpathThe unique identifier or the host:port of the Target associated to the Upstream to be delete.
" + }, + "response": [] + } + ], + "description": "https://docs.konghq.com/2.0.x/admin-api/#delete-upstream", + "event": [ + { + "listen": "prerequest", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + }, + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + } + ] + }, + { + "name": "Show Upstream Health for Node", + "item": [ + { + "name": "List All Upstreams", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{gateway}}/upstreams/:nameOrId/health?balancer_health=1", + "host": [ + "{{gateway}}" + ], + "path": [ + "upstreams", + ":nameOrId", + "health" + ], + "query": [ + { + "key": "balancer_health", + "value": "1", + "description": "If set to 1, Kong will return the health status of the whole Upstream." + } + ], + "variable": [ + { + "key": "nameOrId", + "value": "my-upstream", + "description": "The unique identifier or the name of the Upstream for which to display Target health." + } + ] + }, + "description": "# List All Upstreams [konghq](https://docs.konghq.com/2.0.x/admin-api/#list-all-upstreams)\n* Displays the health status for all Targets of a given Upstream, or for the whole Upstream, according to the perspective of a specific Kong node. Note that, being node-specific information, making this same request to different nodes of the Kong cluster may produce different results. For example, one specific node of the Kong cluster may be experiencing network issues, causing it to fail to connect to some Targets: these Targets will be marked as unhealthy by that node (directing traffic from this node to other Targets that it can successfully reach), but healthy to all others Kong nodes (which have no problems using that Target).\n\n* The data field of the response contains an array of Target objects. The health for each Target is returned in its health field:\n\n\t* If a Target fails to be activated in the balancer due to DNS issues, its status displays as DNS_ERROR.\n\t* When health checks are not enabled in the Upstream configuration, the health status for active Targets is displayed as HEALTHCHECKS_OFF.\n\t* When health checks are enabled and the Target is determined to be healthy, either automatically or manually, its status is displayed as HEALTHY. This means that this Target is currently included in this Upstream’s load balancer execution.\n\n* When a Target has been disabled by either active or passive health checks (circuit breakers) or manually, its status is displayed as UNHEALTHY. The load balancer is not directing any traffic to this Target via this Upstream.\nWhen the request query parameter balancer_health is set to 1, the data field of the response refers to the whole Upstream, and its health attribute is defined by the state of all of Upstream’s Targets, according to the field [health checker’s threshold][healthchecks.threshold].\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
AttributesMandatoryTypeDescription
name or idrequiredpathThe unique identifier or the name of the Upstream for which to display Target health.
balancer_healthoptionalqueryIf set to 1, Kong will return the health status of the whole Upstream.
" + }, + "response": [ + { + "name": "List All Upstreams-200", + "originalRequest": { + "method": "GET", + "header": [], + "url": { + "raw": "{{gateway}}/upstreams", + "host": [ + "{{gateway}}" + ], + "path": [ + "upstreams" + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "Text", + "header": [ + { + "key": "Date", + "value": "Thu, 12 Mar 2020 20:21:55 GMT" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "Server", + "value": "kong/2.0.1" + }, + { + "key": "Content-Length", + "value": "945" + }, + { + "key": "X-Kong-Admin-Latency", + "value": "1" + } + ], + "cookie": [], + "body": "{\n\t\"data\": [\n\t\t{\n\t\t\t\"id\": \"ea29aaa3-3b2d-488c-b90c-56df8e0dd8c6\",\n\t\t\t\"created_at\": 1422386534,\n\t\t\t\"name\": \"my-upstream\",\n\t\t\t\"algorithm\": \"round-robin\",\n\t\t\t\"hash_on\": \"none\",\n\t\t\t\"hash_fallback\": \"none\",\n\t\t\t\"hash_on_cookie_path\": \"/\",\n\t\t\t\"slots\": 10000,\n\t\t\t\"healthchecks\": {\n\t\t\t\t\"active\": {\n\t\t\t\t\t\"https_verify_certificate\": true,\n\t\t\t\t\t\"unhealthy\": {\n\t\t\t\t\t\t\"http_statuses\": [\n\t\t\t\t\t\t\t429,\n\t\t\t\t\t\t\t404,\n\t\t\t\t\t\t\t500,\n\t\t\t\t\t\t\t501,\n\t\t\t\t\t\t\t502,\n\t\t\t\t\t\t\t503,\n\t\t\t\t\t\t\t504,\n\t\t\t\t\t\t\t505\n\t\t\t\t\t\t],\n\t\t\t\t\t\t\"tcp_failures\": 0,\n\t\t\t\t\t\t\"timeouts\": 0,\n\t\t\t\t\t\t\"http_failures\": 0,\n\t\t\t\t\t\t\"interval\": 0\n\t\t\t\t\t},\n\t\t\t\t\t\"http_path\": \"/\",\n\t\t\t\t\t\"timeout\": 1,\n\t\t\t\t\t\"healthy\": {\n\t\t\t\t\t\t\"http_statuses\": [\n\t\t\t\t\t\t\t200,\n\t\t\t\t\t\t\t302\n\t\t\t\t\t\t],\n\t\t\t\t\t\t\"interval\": 0,\n\t\t\t\t\t\t\"successes\": 0\n\t\t\t\t\t},\n\t\t\t\t\t\"https_sni\": \"example.com\",\n\t\t\t\t\t\"concurrency\": 10,\n\t\t\t\t\t\"type\": \"http\"\n\t\t\t\t},\n\t\t\t\t\"passive\": {\n\t\t\t\t\t\"unhealthy\": {\n\t\t\t\t\t\t\"http_failures\": 0,\n\t\t\t\t\t\t\"http_statuses\": [\n\t\t\t\t\t\t\t429,\n\t\t\t\t\t\t\t500,\n\t\t\t\t\t\t\t503\n\t\t\t\t\t\t],\n\t\t\t\t\t\t\"tcp_failures\": 0,\n\t\t\t\t\t\t\"timeouts\": 0\n\t\t\t\t\t},\n\t\t\t\t\t\"type\": \"http\",\n\t\t\t\t\t\"healthy\": {\n\t\t\t\t\t\t\"successes\": 0,\n\t\t\t\t\t\t\"http_statuses\": [\n\t\t\t\t\t\t\t200,\n\t\t\t\t\t\t\t201,\n\t\t\t\t\t\t\t202,\n\t\t\t\t\t\t\t203,\n\t\t\t\t\t\t\t204,\n\t\t\t\t\t\t\t205,\n\t\t\t\t\t\t\t206,\n\t\t\t\t\t\t\t207,\n\t\t\t\t\t\t\t208,\n\t\t\t\t\t\t\t226,\n\t\t\t\t\t\t\t300,\n\t\t\t\t\t\t\t301,\n\t\t\t\t\t\t\t302,\n\t\t\t\t\t\t\t303,\n\t\t\t\t\t\t\t304,\n\t\t\t\t\t\t\t305,\n\t\t\t\t\t\t\t306,\n\t\t\t\t\t\t\t307,\n\t\t\t\t\t\t\t308\n\t\t\t\t\t\t]\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"threshold\": 0\n\t\t\t},\n\t\t\t\"tags\": [\n\t\t\t\t\"user-level\",\n\t\t\t\t\"low-priority\"\n\t\t\t],\n\t\t\t\"host_header\": \"example.com\"\n\t\t},\n\t\t{\n\t\t\t\"id\": \"4fe14415-73d5-4f00-9fbc-c72a0fccfcb2\",\n\t\t\t\"created_at\": 1422386534,\n\t\t\t\"name\": \"my-upstream\",\n\t\t\t\"algorithm\": \"round-robin\",\n\t\t\t\"hash_on\": \"none\",\n\t\t\t\"hash_fallback\": \"none\",\n\t\t\t\"hash_on_cookie_path\": \"/\",\n\t\t\t\"slots\": 10000,\n\t\t\t\"healthchecks\": {\n\t\t\t\t\"active\": {\n\t\t\t\t\t\"https_verify_certificate\": true,\n\t\t\t\t\t\"unhealthy\": {\n\t\t\t\t\t\t\"http_statuses\": [\n\t\t\t\t\t\t\t429,\n\t\t\t\t\t\t\t404,\n\t\t\t\t\t\t\t500,\n\t\t\t\t\t\t\t501,\n\t\t\t\t\t\t\t502,\n\t\t\t\t\t\t\t503,\n\t\t\t\t\t\t\t504,\n\t\t\t\t\t\t\t505\n\t\t\t\t\t\t],\n\t\t\t\t\t\t\"tcp_failures\": 0,\n\t\t\t\t\t\t\"timeouts\": 0,\n\t\t\t\t\t\t\"http_failures\": 0,\n\t\t\t\t\t\t\"interval\": 0\n\t\t\t\t\t},\n\t\t\t\t\t\"http_path\": \"/\",\n\t\t\t\t\t\"timeout\": 1,\n\t\t\t\t\t\"healthy\": {\n\t\t\t\t\t\t\"http_statuses\": [\n\t\t\t\t\t\t\t200,\n\t\t\t\t\t\t\t302\n\t\t\t\t\t\t],\n\t\t\t\t\t\t\"interval\": 0,\n\t\t\t\t\t\t\"successes\": 0\n\t\t\t\t\t},\n\t\t\t\t\t\"https_sni\": \"example.com\",\n\t\t\t\t\t\"concurrency\": 10,\n\t\t\t\t\t\"type\": \"http\"\n\t\t\t\t},\n\t\t\t\t\"passive\": {\n\t\t\t\t\t\"unhealthy\": {\n\t\t\t\t\t\t\"http_failures\": 0,\n\t\t\t\t\t\t\"http_statuses\": [\n\t\t\t\t\t\t\t429,\n\t\t\t\t\t\t\t500,\n\t\t\t\t\t\t\t503\n\t\t\t\t\t\t],\n\t\t\t\t\t\t\"tcp_failures\": 0,\n\t\t\t\t\t\t\"timeouts\": 0\n\t\t\t\t\t},\n\t\t\t\t\t\"type\": \"http\",\n\t\t\t\t\t\"healthy\": {\n\t\t\t\t\t\t\"successes\": 0,\n\t\t\t\t\t\t\"http_statuses\": [\n\t\t\t\t\t\t\t200,\n\t\t\t\t\t\t\t201,\n\t\t\t\t\t\t\t202,\n\t\t\t\t\t\t\t203,\n\t\t\t\t\t\t\t204,\n\t\t\t\t\t\t\t205,\n\t\t\t\t\t\t\t206,\n\t\t\t\t\t\t\t207,\n\t\t\t\t\t\t\t208,\n\t\t\t\t\t\t\t226,\n\t\t\t\t\t\t\t300,\n\t\t\t\t\t\t\t301,\n\t\t\t\t\t\t\t302,\n\t\t\t\t\t\t\t303,\n\t\t\t\t\t\t\t304,\n\t\t\t\t\t\t\t305,\n\t\t\t\t\t\t\t306,\n\t\t\t\t\t\t\t307,\n\t\t\t\t\t\t\t308\n\t\t\t\t\t\t]\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"threshold\": 0\n\t\t\t},\n\t\t\t\"tags\": [\n\t\t\t\t\"admin\",\n\t\t\t\t\"high-priority\",\n\t\t\t\t\"critical\"\n\t\t\t],\n\t\t\t\"host_header\": \"example.com\"\n\t\t}\n\t],\n\t\"next\": \"http://localhost:8001/upstreams?offset=6378122c-a0a1-438d-a5c6-efabae9fb969\"\n}" + }, + { + "name": "List All Upstreams", + "originalRequest": { + "method": "GET", + "header": [], + "url": { + "raw": "{{gateway}}/upstreams/:nameOrId/health?balancer_health=0", + "host": [ + "{{gateway}}" + ], + "path": [ + "upstreams", + ":nameOrId", + "health" + ], + "query": [ + { + "key": "balancer_health", + "value": "0", + "description": "If set to 1, Kong will return the health status of the whole Upstream." + } + ], + "variable": [ + { + "key": "nameOrId", + "value": "my-upstream", + "description": "The unique identifier or the name of the Upstream for which to display Target health." + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "Text", + "header": [ + { + "key": "Date", + "value": "Thu, 12 Mar 2020 21:32:22 GMT" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "Server", + "value": "kong/2.0.1" + }, + { + "key": "Content-Length", + "value": "143" + }, + { + "key": "X-Kong-Admin-Latency", + "value": "2" + } + ], + "cookie": [], + "body": "{\n \"total\": 2,\n \"node_id\": \"cbb297c0-14a9-46bc-ad91-1d0ef9b42df9\",\n \"data\": [\n {\n \"created_at\": 1485524883980,\n \"id\": \"18c0ad90-f942-4098-88db-bbee3e43b27f\",\n \"health\": \"HEALTHY\",\n \"target\": \"127.0.0.1:20000\",\n \"upstream_id\": \"07131005-ba30-4204-a29f-0927d53257b4\",\n \"weight\": 100,\n \"name\": \"aliqua veniam\",\n \"algorithm\": \"non officia aliquip\",\n \"hash_on\": \"laborum dolore ea pariatur\",\n \"hash_fallback\": \"mollit anim sit\",\n \"hash_on_cookie_path\": \"deserunt cillum\",\n \"slots\": -93720927,\n \"healthchecks\": {\n \"threshold\": 0,\n \"active\": {\n \"unhealthy\": {\n \"http_statuses\": [\n 429,\n 404,\n 500,\n 501,\n 502,\n 503,\n 504,\n 505\n ],\n \"tcp_failures\": 0,\n \"timeouts\": 0,\n \"http_failures\": 0,\n \"interval\": 0\n },\n \"type\": \"http\",\n \"http_path\": \"/\",\n \"timeout\": 1,\n \"healthy\": {\n \"successes\": 0,\n \"interval\": 0,\n \"http_statuses\": [\n 200,\n 302\n ]\n },\n \"https_sni\": \"example.com\",\n \"https_verify_certificate\": true,\n \"concurrency\": 10\n },\n \"passive\": {\n \"unhealthy\": {\n \"http_failures\": 0,\n \"http_statuses\": [\n 429,\n 500,\n 503\n ],\n \"tcp_failures\": 0,\n \"timeouts\": 0\n },\n \"healthy\": {\n \"http_statuses\": [\n 200,\n 201,\n 202,\n 203,\n 204,\n 205,\n 206,\n 207,\n 208,\n 226,\n 300,\n 301,\n 302,\n 303,\n 304,\n 305,\n 306,\n 307,\n 308\n ],\n \"successes\": 0\n },\n \"type\": \"http\"\n }\n },\n \"tags\": [\n \"culpa ei\",\n \"enim\"\n ],\n \"host_header\": \"labore proident elit irure incididunt\"\n },\n {\n \"created_at\": 1485524914883,\n \"id\": \"6c6f34eb-e6c3-4c1f-ac58-4060e5bca890\",\n \"health\": \"UNHEALTHY\",\n \"target\": \"127.0.0.1:20002\",\n \"upstream_id\": \"07131005-ba30-4204-a29f-0927d53257b4\",\n \"weight\": 200,\n \"name\": \"\",\n \"algorithm\": \"labore aliqua pariatur\",\n \"hash_on\": \"esse ea in id\",\n \"hash_fallback\": \"aliquip\",\n \"hash_on_cookie_path\": \"incididunt eu eiusmod mollit\",\n \"slots\": -60979601,\n \"healthchecks\": {\n \"threshold\": 0,\n \"active\": {\n \"unhealthy\": {\n \"http_statuses\": [\n 429,\n 404,\n 500,\n 501,\n 502,\n 503,\n 504,\n 505\n ],\n \"tcp_failures\": 0,\n \"timeouts\": 0,\n \"http_failures\": 0,\n \"interval\": 0\n },\n \"type\": \"http\",\n \"http_path\": \"/\",\n \"timeout\": 1,\n \"healthy\": {\n \"successes\": 0,\n \"interval\": 0,\n \"http_statuses\": [\n 200,\n 302\n ]\n },\n \"https_sni\": \"example.com\",\n \"https_verify_certificate\": true,\n \"concurrency\": 10\n },\n \"passive\": {\n \"unhealthy\": {\n \"http_failures\": 0,\n \"http_statuses\": [\n 429,\n 500,\n 503\n ],\n \"tcp_failures\": 0,\n \"timeouts\": 0\n },\n \"healthy\": {\n \"http_statuses\": [\n 200,\n 201,\n 202,\n 203,\n 204,\n 205,\n 206,\n 207,\n 208,\n 226,\n 300,\n 301,\n 302,\n 303,\n 304,\n 305,\n 306,\n 307,\n 308\n ],\n \"successes\": 0\n },\n \"type\": \"http\"\n }\n },\n \"tags\": [\n \"consectetur qui eiusmod\"\n ],\n \"host_header\": \"reprehenderit ad quis\"\n }\n ],\n \"next\": \"aliquip ipsum\"\n}" + }, + { + "name": "List All Upstreams", + "originalRequest": { + "method": "GET", + "header": [], + "url": { + "raw": "{{gateway}}/upstreams/:nameOrId/health?balancer_health=1", + "host": [ + "{{gateway}}" + ], + "path": [ + "upstreams", + ":nameOrId", + "health" + ], + "query": [ + { + "key": "balancer_health", + "value": "1", + "description": "If set to 1, Kong will return the health status of the whole Upstream." + } + ], + "variable": [ + { + "key": "nameOrId", + "value": "my-upstream", + "description": "The unique identifier or the name of the Upstream for which to display Target health." + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "Text", + "header": [ + { + "key": "Date", + "value": "Thu, 12 Mar 2020 21:32:22 GMT" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "Server", + "value": "kong/2.0.1" + }, + { + "key": "Content-Length", + "value": "143" + }, + { + "key": "X-Kong-Admin-Latency", + "value": "2" + } + ], + "cookie": [], + "body": "{\n \"data\": [\n {\n \"id\": \"incididunt\",\n \"created_at\": 3675253,\n \"name\": \"aliqua veniam\",\n \"algorithm\": \"non officia aliquip\",\n \"hash_on\": \"laborum dolore ea pariatur\",\n \"hash_fallback\": \"mollit anim sit\",\n \"hash_on_cookie_path\": \"deserunt cillum\",\n \"slots\": -93720927,\n \"healthchecks\": {\n \"threshold\": 0,\n \"active\": {\n \"unhealthy\": {\n \"http_statuses\": [\n 429,\n 404,\n 500,\n 501,\n 502,\n 503,\n 504,\n 505\n ],\n \"tcp_failures\": 0,\n \"timeouts\": 0,\n \"http_failures\": 0,\n \"interval\": 0\n },\n \"type\": \"http\",\n \"http_path\": \"/\",\n \"timeout\": 1,\n \"healthy\": {\n \"successes\": 0,\n \"interval\": 0,\n \"http_statuses\": [\n 200,\n 302\n ]\n },\n \"https_sni\": \"example.com\",\n \"https_verify_certificate\": true,\n \"concurrency\": 10\n },\n \"passive\": {\n \"unhealthy\": {\n \"http_failures\": 0,\n \"http_statuses\": [\n 429,\n 500,\n 503\n ],\n \"tcp_failures\": 0,\n \"timeouts\": 0\n },\n \"healthy\": {\n \"http_statuses\": [\n 200,\n 201,\n 202,\n 203,\n 204,\n 205,\n 206,\n 207,\n 208,\n 226,\n 300,\n 301,\n 302,\n 303,\n 304,\n 305,\n 306,\n 307,\n 308\n ],\n \"successes\": 0\n },\n \"type\": \"http\"\n }\n },\n \"tags\": [\n \"culpa ei\",\n \"enim\"\n ],\n \"host_header\": \"labore proident elit irure incididunt\"\n },\n {\n \"id\": \"in minim ipsum dolore\",\n \"created_at\": 66976784,\n \"name\": \"\",\n \"algorithm\": \"labore aliqua pariatur\",\n \"hash_on\": \"esse ea in id\",\n \"hash_fallback\": \"aliquip\",\n \"hash_on_cookie_path\": \"incididunt eu eiusmod mollit\",\n \"slots\": -60979601,\n \"healthchecks\": {\n \"threshold\": 0,\n \"active\": {\n \"unhealthy\": {\n \"http_statuses\": [\n 429,\n 404,\n 500,\n 501,\n 502,\n 503,\n 504,\n 505\n ],\n \"tcp_failures\": 0,\n \"timeouts\": 0,\n \"http_failures\": 0,\n \"interval\": 0\n },\n \"type\": \"http\",\n \"http_path\": \"/\",\n \"timeout\": 1,\n \"healthy\": {\n \"successes\": 0,\n \"interval\": 0,\n \"http_statuses\": [\n 200,\n 302\n ]\n },\n \"https_sni\": \"example.com\",\n \"https_verify_certificate\": true,\n \"concurrency\": 10\n },\n \"passive\": {\n \"unhealthy\": {\n \"http_failures\": 0,\n \"http_statuses\": [\n 429,\n 500,\n 503\n ],\n \"tcp_failures\": 0,\n \"timeouts\": 0\n },\n \"healthy\": {\n \"http_statuses\": [\n 200,\n 201,\n 202,\n 203,\n 204,\n 205,\n 206,\n 207,\n 208,\n 226,\n 300,\n 301,\n 302,\n 303,\n 304,\n 305,\n 306,\n 307,\n 308\n ],\n \"successes\": 0\n },\n \"type\": \"http\"\n }\n },\n \"tags\": [\n \"consectetur qui eiusmod\"\n ],\n \"host_header\": \"reprehenderit ad quis\"\n },\n {\n \"id\": \"fugiat elit non ut\",\n \"created_at\": -99389103,\n \"name\": \"Ut adipisicing nisi laborum\",\n \"algorithm\": \"ea\",\n \"hash_on\": \"et sint\",\n \"hash_fallback\": \"commo\",\n \"hash_on_cookie_path\": \"deserunt consectetur c\",\n \"slots\": 71186640,\n \"healthchecks\": {\n \"threshold\": 0,\n \"active\": {\n \"unhealthy\": {\n \"http_statuses\": [\n 429,\n 404,\n 500,\n 501,\n 502,\n 503,\n 504,\n 505\n ],\n \"tcp_failures\": 0,\n \"timeouts\": 0,\n \"http_failures\": 0,\n \"interval\": 0\n },\n \"type\": \"http\",\n \"http_path\": \"/\",\n \"timeout\": 1,\n \"healthy\": {\n \"successes\": 0,\n \"interval\": 0,\n \"http_statuses\": [\n 200,\n 302\n ]\n },\n \"https_sni\": \"example.com\",\n \"https_verify_certificate\": true,\n \"concurrency\": 10\n },\n \"passive\": {\n \"unhealthy\": {\n \"http_failures\": 0,\n \"http_statuses\": [\n 429,\n 500,\n 503\n ],\n \"tcp_failures\": 0,\n \"timeouts\": 0\n },\n \"healthy\": {\n \"http_statuses\": [\n 200,\n 201,\n 202,\n 203,\n 204,\n 205,\n 206,\n 207,\n 208,\n 226,\n 300,\n 301,\n 302,\n 303,\n 304,\n 305,\n 306,\n 307,\n 308\n ],\n \"successes\": 0\n },\n \"type\": \"http\"\n }\n },\n \"tags\": [\n \"ut ex officia consequat\"\n ],\n \"host_header\": \"ex elit dolore enim\"\n },\n {\n \"id\": \"in Excepteur\",\n \"created_at\": -58732565,\n \"name\": \"ipsum\",\n \"algorithm\": \"anim exercitation voluptate\",\n \"hash_on\": \"Lorem velit\",\n \"hash_fallback\": \"pariatur do\",\n \"hash_on_cookie_path\": \"est consequat nisi\",\n \"slots\": 93978358,\n \"healthchecks\": {\n \"threshold\": 0,\n \"active\": {\n \"unhealthy\": {\n \"http_statuses\": [\n 429,\n 404,\n 500,\n 501,\n 502,\n 503,\n 504,\n 505\n ],\n \"tcp_failures\": 0,\n \"timeouts\": 0,\n \"http_failures\": 0,\n \"interval\": 0\n },\n \"type\": \"http\",\n \"http_path\": \"/\",\n \"timeout\": 1,\n \"healthy\": {\n \"successes\": 0,\n \"interval\": 0,\n \"http_statuses\": [\n 200,\n 302\n ]\n },\n \"https_sni\": \"example.com\",\n \"https_verify_certificate\": true,\n \"concurrency\": 10\n },\n \"passive\": {\n \"unhealthy\": {\n \"http_failures\": 0,\n \"http_statuses\": [\n 429,\n 500,\n 503\n ],\n \"tcp_failures\": 0,\n \"timeouts\": 0\n },\n \"healthy\": {\n \"http_statuses\": [\n 200,\n 201,\n 202,\n 203,\n 204,\n 205,\n 206,\n 207,\n 208,\n 226,\n 300,\n 301,\n 302,\n 303,\n 304,\n 305,\n 306,\n 307,\n 308\n ],\n \"successes\": 0\n },\n \"type\": \"http\"\n }\n },\n \"tags\": [\n \"do des\",\n \"labore id ut\",\n \"magna\"\n ],\n \"host_header\": \"ut magna Excepteur\"\n }\n ],\n \"next\": \"aliquip ipsum\",\n \"node_id\": \"cbb297c0-14a9-46bc-ad91-1d0ef9b42df9\"\n}" + } + ] + } + ], + "description": "https://docs.konghq.com/2.0.x/admin-api/#list-upstreams\n\n* Displays the health status for all Targets of a given Upstream, or for the whole Upstream, according to the perspective of a specific Kong node. Note that, being node-specific information, making this same request to different nodes of the Kong cluster may produce different results. For example, one specific node of the Kong cluster may be experiencing network issues, causing it to fail to connect to some Targets: these Targets will be marked as unhealthy by that node (directing traffic from this node to other Targets that it can successfully reach), but healthy to all others Kong nodes (which have no problems using that Target).\n\n* The data field of the response contains an array of Target objects. The health for each Target is returned in its health field:\n\n\t* If a Target fails to be activated in the balancer due to DNS issues, its status displays as DNS_ERROR.\n\t* When health checks are not enabled in the Upstream configuration, the health status for active Targets is displayed as HEALTHCHECKS_OFF.\n\t* When health checks are enabled and the Target is determined to be healthy, either automatically or manually, its status is displayed as HEALTHY. This means that this Target is currently included in this Upstream’s load balancer execution.\n\n* When a Target has been disabled by either active or passive health checks (circuit breakers) or manually, its status is displayed as UNHEALTHY. The load balancer is not directing any traffic to this Target via this Upstream.\nWhen the request query parameter balancer_health is set to 1, the data field of the response refers to the whole Upstream, and its health attribute is defined by the state of all of Upstream’s Targets, according to the field [health checker’s threshold][healthchecks.threshold].", + "event": [ + { + "listen": "prerequest", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + }, + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + } + ] + } + ], + "description": "https://docs.konghq.com/2.0.x/admin-api/#upstream-object\n\n* The upstream object represents a virtual hostname and can be used to loadbalance incoming requests over multiple services (targets). So for example an upstream named service.v1.xyz for a Service object whose host is service.v1.xyz. Requests for this Service would be proxied to the targets defined within the upstream.\n\n* An upstream also includes a health checker, which is able to enable and disable targets based on their ability or inability to serve requests. The configuration for the health checker is stored in the upstream object, and applies to all of its targets.\n\n* Upstreams can be both tagged and filtered by tags.\n\n\n{\n \"id\": \"58c8ccbb-eafb-4566-991f-2ed4f678fa70\",\n \"created_at\": 1422386534,\n \"name\": \"my-upstream\",\n \"algorithm\": \"round-robin\",\n \"hash_on\": \"none\",\n \"hash_fallback\": \"none\",\n \"hash_on_cookie_path\": \"/\",\n \"slots\": 10000,\n \"healthchecks\": {\n \"active\": {\n \"https_verify_certificate\": true,\n \"unhealthy\": {\n \"http_statuses\": [429, 404, 500, 501, 502, 503, 504, 505],\n \"tcp_failures\": 0,\n \"timeouts\": 0,\n \"http_failures\": 0,\n \"interval\": 0\n },\n \"http_path\": \"/\",\n \"timeout\": 1,\n \"healthy\": {\n \"http_statuses\": [200, 302],\n \"interval\": 0,\n \"successes\": 0\n },\n \"https_sni\": \"example.com\",\n \"concurrency\": 10,\n \"type\": \"http\"\n },\n \"passive\": {\n \"unhealthy\": {\n \"http_failures\": 0,\n \"http_statuses\": [429, 500, 503],\n \"tcp_failures\": 0,\n \"timeouts\": 0\n },\n \"type\": \"http\",\n \"healthy\": {\n \"successes\": 0,\n \"http_statuses\": [200, 201, 202, 203, 204, 205, 206, 207, 208, 226, 300, 301, 302, 303, 304, 305, 306, 307, 308]\n }\n },\n \"threshold\": 0\n },\n \"tags\": [\"user-level\", \"low-priority\"],\n \"host_header\": \"example.com\"\n}", + "event": [ + { + "listen": "prerequest", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + }, + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + } + ] + }, + { + "name": "Target Object", + "item": [ + { + "name": "Add Target", + "item": [ + { + "name": "Create Target Associated to a Specific Upstream", + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"upstream\": {\n \"id\": \"885a0392-ef1b-4de3-aacf-af3f1697ce2c\"\n },\n \"target\": \"example.com:8000\",\n \"weight\": 100,\n \"tags\": [\n \"user-level\",\n \"low-priority\"\n ]\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{gateway}}/upstreams/:upstreamHost:portOriI/targets", + "host": [ + "{{gateway}}" + ], + "path": [ + "upstreams", + ":upstreamHost:portOriI", + "targets" + ], + "variable": [ + { + "key": "upstreamHost:portOriI", + "value": "", + "description": "The unique identifier or the host:port attribute of the Upstream that should be associated to the newly-created Target." + } + ] + }, + "description": "# Create Target Associated to a Specific Upstream [konghq](https://docs.konghq.com/2.0.x/admin-api/#create-target-associated-to-a-specific-upstream)\n* A target is an ip address/hostname with a port that identifies an instance of a backend service. Every upstream can have many targets, and the targets can be dynamically added. Changes are effectuated on the fly.\n\n* Because the upstream maintains a history of target changes, the targets cannot be deleted or modified. To disable a target, post a new one with weight=0; alternatively, use the DELETE convenience method to accomplish the same.\n\n* The current target object definition is the one with the latest created_at.\n\n* Targets can be both tagged and filtered by tags.\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n
AttributesMandatoryTypeDescription
upstream host:port or idrequiredpathThe unique identifier or the host:port attribute of the Upstream that should be associated to the newly-created Target.
\n\n# Request Body\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
AttributesMandatoryTypeDescription
targetrequiredbodyThe target address (ip or hostname) and port. If the hostname resolves to an SRV record, the port value will be overridden by the value from the DNS record.
weightoptionalbodyThe weight this target gets within the upstream loadbalancer (0-1000). If the hostname resolves to an SRV record, the weight value will be overridden by the value from the DNS record. Defaults to 100.
tagsoptionalbodyAn optional set of strings associated with the Target, for grouping and filtering.
" + }, + "response": [ + { + "name": "Create Target Associated to a Specific Upstream - 201", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"upstream\": {\n \"id\": \"885a0392-ef1b-4de3-aacf-af3f1697ce2c\"\n },\n \"target\": \"example.com:8000\",\n \"weight\": 100,\n \"tags\": [\n \"user-level\",\n \"low-priority\"\n ]\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{gateway}}/upstreams/:upstreamHost:portOriI/targets", + "host": [ + "{{gateway}}" + ], + "path": [ + "upstreams", + ":upstreamHost:portOriI", + "targets" + ], + "variable": [ + { + "key": "upstreamHost:portOriI", + "value": "example.com:8000", + "description": "The unique identifier or the host:port attribute of the Upstream that should be associated to the newly-created Target." + } + ] + } + }, + "status": "Created", + "code": 201, + "_postman_previewlanguage": "Text", + "header": [ + { + "key": "Date", + "value": "Thu, 12 Mar 2020 21:57:10 GMT" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "Server", + "value": "kong/2.0.1" + }, + { + "key": "Content-Length", + "value": "23" + }, + { + "key": "X-Kong-Admin-Latency", + "value": "0" + } + ], + "cookie": [], + "body": "{\n\t\"id\": \"a3395f66-2af6-4c79-bea2-1b6933764f80\",\n\t\"created_at\": 1422386534,\n\t\"upstream\": {\n\t\t\"id\": \"885a0392-ef1b-4de3-aacf-af3f1697ce2c\"\n\t},\n\t\"target\": \"example.com:8000\",\n\t\"weight\": 100,\n\t\"tags\": [\n\t\t\"user-level\",\n\t\t\"low-priority\"\n\t]\n}" + } + ] + } + ], + "description": "https://docs.konghq.com/2.0.x/admin-api/#add-target" + }, + { + "name": "List Targets", + "item": [ + { + "name": "List Targets Associated to a Specific Upstream", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{gateway}}/upstreams/:upstreamHost:portOrId/targets", + "host": [ + "{{gateway}}" + ], + "path": [ + "upstreams", + ":upstreamHost:portOrId", + "targets" + ], + "variable": [ + { + "key": "upstreamHost:portOrId", + "value": "" + } + ] + }, + "description": "# List Targets Associated to a Specific Upstream [konghq](https://docs.konghq.com/2.0.x/admin-api/#list-targets-associated-to-a-specific-upstream)\n\n \n \n \n \n \n \n \n \n \n \n \n \n
AttributesMandatoryTypeDescription
upstream host:port or idrequiredpathThe unique identifier or the host:port attribute of the Upstream whose Targets are to be retrieved. When using this endpoint, only Targets associated to the specified Upstream will be listed.
" + }, + "response": [ + { + "name": "List Targets Associated to a Specific Upstream-200", + "originalRequest": { + "method": "GET", + "header": [], + "url": { + "raw": "{{gateway}}/upstreams/:upstreamHost:portOrId/targets", + "host": [ + "{{gateway}}" + ], + "path": [ + "upstreams", + ":upstreamHost:portOrId", + "targets" + ], + "variable": [ + { + "key": "upstreamHost:portOrId", + "value": "" + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "Text", + "header": [ + { + "key": "Date", + "value": "Thu, 12 Mar 2020 22:04:50 GMT" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "Server", + "value": "kong/2.0.1" + }, + { + "key": "Content-Length", + "value": "23" + }, + { + "key": "X-Kong-Admin-Latency", + "value": "0" + } + ], + "cookie": [], + "body": "{\n\t\"data\": [\n\t\t{\n\t\t\t\"id\": \"f5a9c0ca-bdbb-490f-8928-2ca95836239a\",\n\t\t\t\"created_at\": 1422386534,\n\t\t\t\"upstream\": {\n\t\t\t\t\"id\": \"173a6cee-90d1-40a7-89cf-0329eca780a6\"\n\t\t\t},\n\t\t\t\"target\": \"example.com:8000\",\n\t\t\t\"weight\": 100,\n\t\t\t\"tags\": [\n\t\t\t\t\"user-level\",\n\t\t\t\t\"low-priority\"\n\t\t\t]\n\t\t},\n\t\t{\n\t\t\t\"id\": \"bdab0e47-4e37-4f0b-8fd0-87d95cc4addc\",\n\t\t\t\"created_at\": 1422386534,\n\t\t\t\"upstream\": {\n\t\t\t\t\"id\": \"f00c6da4-3679-4b44-b9fb-36a19bd3ae83\"\n\t\t\t},\n\t\t\t\"target\": \"example.com:8000\",\n\t\t\t\"weight\": 100,\n\t\t\t\"tags\": [\n\t\t\t\t\"admin\",\n\t\t\t\t\"high-priority\",\n\t\t\t\t\"critical\"\n\t\t\t]\n\t\t}\n\t],\n\t\"next\": \"http://localhost:8001/targets?offset=6378122c-a0a1-438d-a5c6-efabae9fb969\"\n}" + } + ] + } + ], + "description": "https://docs.konghq.com/2.0.x/admin-api/#list-targets" + }, + { + "name": "Delete Target", + "request": { + "method": "DELETE", + "header": [], + "url": { + "raw": "{{gateway}}/upstreams/:upstreamNameOrId/targets/:host:portOrId", + "host": [ + "{{gateway}}" + ], + "path": [ + "upstreams", + ":upstreamNameOrId", + "targets", + ":host:portOrId" + ], + "variable": [ + { + "key": "upstreamNameOrId", + "value": "", + "description": "The unique identifier or the name of the upstream for which to delete the target." + }, + { + "key": "host:portOrId", + "value": "", + "description": "The host:port combination element of the target to remove, or the id of an existing target entry." + } + ] + }, + "description": "# Delete Upstream [konghq](https://docs.konghq.com/2.0.x/admin-api/#delete-upstream-1)\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
AttributesMandatoryTypeDescription
upstream name or idrequiredpathThe unique identifier or the name of the upstream for which to delete the target.
host:port or idrequiredpathThe host:port combination element of the target to remove, or the id of an existing target entry.
" + }, + "response": [] + }, + { + "name": "Set Target Address As Healthy", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{gateway}}/upstreams/:upstreamNameOrId/targets/:targetOrID/:address/healthy", + "host": [ + "{{gateway}}" + ], + "path": [ + "upstreams", + ":upstreamNameOrId", + "targets", + ":targetOrID", + ":address", + "healthy" + ], + "variable": [ + { + "key": "upstreamNameOrId", + "value": "", + "description": "The unique identifier or the name of the upstream." + }, + { + "key": "targetOrID", + "value": "", + "description": "The host/port combination element of the target to set as healthy, or the id of an existing target entry." + }, + { + "key": "address", + "value": "", + "description": "The host/port combination element of the address to set as healthy." + } + ] + }, + "description": "# Set Target Address As Healthy [konghq](https://docs.konghq.com/2.0.x/admin-api/#set-target-address-as-healthy)\n* Set the current health status of an individual address resolved by a target in the load balancer to “healthy” in the entire Kong cluster.\n\n* This endpoint can be used to manually re-enable an address resolved by a target that was previously disabled by the upstream’s health checker. Upstreams only forward requests to healthy nodes, so this call tells Kong to start using this address again.\n\n* This resets the health counters of the health checkers running in all workers of the Kong node, and broadcasts a cluster-wide message so that the “healthy” status is propagated to the whole Kong cluster.\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
AttributesMandatoryTypeDescription
upstream name or idrequiredpathThe unique identifier or the name of the upstream.
target or idrequiredpathThe host/port combination element of the target to set as healthy, or the id of an existing target entry.
addressrequiredpathThe host/port combination element of the address to set as healthy.
" + }, + "response": [] + }, + { + "name": "Set Target Address As Unhealthy", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{gateway}}/upstreams/:upstreamNameOrId/targets/:targetOrID/:address/unhealthy", + "host": [ + "{{gateway}}" + ], + "path": [ + "upstreams", + ":upstreamNameOrId", + "targets", + ":targetOrID", + ":address", + "unhealthy" + ], + "variable": [ + { + "key": "upstreamNameOrId", + "value": "", + "description": "The unique identifier or the name of the upstream." + }, + { + "key": "targetOrID", + "value": "", + "description": "The host/port combination element of the target to set as unhealthy, or the id of an existing target entry." + }, + { + "key": "address", + "value": "", + "description": "The host/port combination element of the address to set as unhealthy." + } + ] + }, + "description": "# Set Target Address As Unhealthy [konghq](https://docs.konghq.com/2.0.x/admin-api/#set-target-address-as-unhealthy)\n* Set the current health status of an individual address resolved by a target in the load balancer to “unhealthy” in the entire Kong cluster.\n\n* This endpoint can be used to manually disable an address and have it stop responding to requests. Upstreams only forward requests to healthy nodes, so this call tells Kong to start skipping this address.\n\n* This call resets the health counters of the health checkers running in all workers of the Kong node, and broadcasts a cluster-wide message so that the “unhealthy” status is propagated to the whole Kong cluster.\n\n* Active health checks continue to execute for unhealthy addresses. Note that if active health checks are enabled and the probe detects that the address is actually healthy, it will automatically re-enable it again. To permanently remove a target from the balancer, you should delete a target instead.\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
AttributesMandatoryTypeDescription
upstream name or idrequiredpathThe unique identifier or the name of the upstream.
target or idrequiredpathThe host/port combination element of the target to set as unhealthy, or the id of an existing target entry.
addressrequiredpathThe host/port combination element of the address to set as unhealthy.
" + }, + "response": [] + }, + { + "name": "Set Target As Healthy", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{gateway}}/upstreams/:upstreamNameOrId/targets/:targetOrID/healthy", + "host": [ + "{{gateway}}" + ], + "path": [ + "upstreams", + ":upstreamNameOrId", + "targets", + ":targetOrID", + "healthy" + ], + "variable": [ + { + "key": "upstreamNameOrId", + "value": "", + "description": "The unique identifier or the name of the upstream." + }, + { + "key": "targetOrID", + "value": "", + "description": "The host/port combination element of the target to set as healthy, or the id of an existing target entry." + } + ] + }, + "description": "# Set Target As Healthy [konghq](https://docs.konghq.com/2.0.x/admin-api/#set-target-as-healthy)\n* Set the current health status of a target in the load balancer to “healthy” in the entire Kong cluster. This sets the “healthy” status to all addresses resolved by this target.\n\n* This endpoint can be used to manually re-enable a target that was previously disabled by the upstream’s health checker. Upstreams only forward requests to healthy nodes, so this call tells Kong to start using this target again.\n\n* This resets the health counters of the health checkers running in all workers of the Kong node, and broadcasts a cluster-wide message so that the “healthy” status is propagated to the whole Kong cluster.\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
AttributesMandatoryTypeDescription
upstream name or idrequiredpathThe unique identifier or the name of the upstream.
target or idrequiredpathThe host/port combination element of the target to set as healthy, or the id of an existing target entry.
" + }, + "response": [] + }, + { + "name": "Set Target As Unhealthy", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{gateway}}/upstreams/:upstreamNameOrId/targets/:targetOrID/unhealthy", + "host": [ + "{{gateway}}" + ], + "path": [ + "upstreams", + ":upstreamNameOrId", + "targets", + ":targetOrID", + "unhealthy" + ], + "variable": [ + { + "key": "upstreamNameOrId", + "value": "", + "description": "The unique identifier or the name of the upstream." + }, + { + "key": "targetOrID", + "value": "", + "description": "The host/port combination element of the target to set as unhealthy, or the id of an existing target entry." + } + ] + }, + "description": "# Set Target As Unhealthy [konghq](https://docs.konghq.com/2.0.x/admin-api/#set-target-as-unhealthy)\n* Set the current health status of a target in the load balancer to “unhealthy” in the entire Kong cluster. This sets the “unhealthy” status to all addresses resolved by this target.\n\n* This endpoint can be used to manually disable a target and have it stop responding to requests. Upstreams only forward requests to healthy nodes, so this call tells Kong to start skipping this target.\n\n* This call resets the health counters of the health checkers running in all workers of the Kong node, and broadcasts a cluster-wide message so that the “unhealthy” status is propagated to the whole Kong cluster.\n\n* Active health checks continue to execute for unhealthy targets. Note that if active health checks are enabled and the probe detects that the target is actually healthy, it will automatically re-enable it again. To permanently remove a target from the balancer, you should delete a target instead.\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
AttributesMandatoryTypeDescription
upstream name or idrequiredpathThe unique identifier or the name of the upstream.
target or idrequiredpathThe host/port combination element of the target to set as unhealthy, or the id of an existing target entry.
" + }, + "response": [] + }, + { + "name": "List All Targets", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{gateway}}/upstreams/:nameOrId/targets/all/", + "host": [ + "{{gateway}}" + ], + "path": [ + "upstreams", + ":nameOrId", + "targets", + "all", + "" + ], + "variable": [ + { + "key": "nameOrId", + "value": "", + "description": "The unique identifier or the name of the upstream for which to list the targets." + } + ] + }, + "description": "# List All Targets [konghq](https://docs.konghq.com/2.0.x/admin-api/#list-all-targets)\n* Lists all targets of the upstream. Multiple target objects for the same target may be returned, showing the history of changes for a specific target. The target object with the latest created_at is the current definition.\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n
AttributesMandatoryTypeDescription
name or idrequiredpathThe unique identifier or the name of the upstream for which to list the targets.
" + }, + "response": [] + } + ], + "description": "https://docs.konghq.com/2.0.x/admin-api/#target-object\n\n* A target is an ip address/hostname with a port that identifies an instance of a backend service. Every upstream can have many targets, and the targets can be dynamically added. Changes are effectuated on the fly.\n\n* Because the upstream maintains a history of target changes, the targets cannot be deleted or modified. To disable a target, post a new one with weight=0; alternatively, use the DELETE convenience method to accomplish the same.\n\n* The current target object definition is the one with the latest created_at.\n\n* Targets can be both tagged and filtered by tags.\n\n{\n \"id\": \"a3395f66-2af6-4c79-bea2-1b6933764f80\",\n \"created_at\": 1422386534,\n \"upstream\": {\"id\":\"885a0392-ef1b-4de3-aacf-af3f1697ce2c\"},\n \"target\": \"example.com:8000\",\n \"weight\": 100,\n \"tags\": [\"user-level\", \"low-priority\"]\n}\n" + }, + { + "name": "Delete CA Certificate", + "request": { + "method": "DELETE", + "header": [], + "url": { + "raw": "http://localhost:8001/ca_/certificates/:ca_certificateId", + "protocol": "http", + "host": [ + "localhost" + ], + "port": "8001", + "path": [ + "ca_", + "certificates", + ":ca_certificateId" + ], + "variable": [ + { + "key": "ca_certificateId", + "value": "aliquip quis et", + "description": "(Required) The unique identifier of the CA Certificate to delete." + } + ] + }, + "description": "# Delete CA Certificate [konghq](https://docs.konghq.com/2.0.x/admin-api/#delete-ca-certificate-1)\n\n# Path parameters\n\n \n \n \n \n \n \n \n \n \n \n \n \n
AttributesMandatoryTypeDescription
certificate idrequiredpathThe unique identifier of the CA Certificate to delete.
" + }, + "response": [ + { + "name": "Untitled Example", + "originalRequest": { + "method": "DELETE", + "header": [], + "url": { + "raw": "" + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "Text", + "header": [ + { + "key": "Content-Type", + "value": "text/plain" + } + ], + "cookie": [], + "body": "" + }, + { + "name": "Not Found", + "originalRequest": { + "method": "DELETE", + "header": [], + "url": { + "raw": "" + } + }, + "status": "Not Found", + "code": 404, + "_postman_previewlanguage": "Text", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"message\": \"SNI not found\"\n}" + } + ] + } + ], + "event": [ + { + "listen": "prerequest", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + }, + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + } + ], + "variable": [ + { + "key": "gateway", + "value": "https://localhost:8444", + "type": "string" + }, + { + "key": "baseUrl", + "value": "http://localhost:8001", + "type": "string" + } + ] +} \ No newline at end of file diff --git a/ph-ee-env-template/PostmanCollections/G2P Sandbox Demo Prep.json b/ph-ee-env-template/PostmanCollections/G2P Sandbox Demo Prep.json new file mode 100644 index 000000000..33e46297e --- /dev/null +++ b/ph-ee-env-template/PostmanCollections/G2P Sandbox Demo Prep.json @@ -0,0 +1,1731 @@ +{ + "info": { + "_postman_id": "2096587a-21c5-4433-82e3-0b7e35045a07", + "name": "G2P Sandbox Demo Prep", + "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json", + "_exporter_id": "4940958" + }, + "item": [ + { + "name": "00-init-setup", + "item": [ + { + "name": "payer-savings-Product", + "event": [ + { + "listen": "prerequest", + "script": { + "exec": [ + "function randomString(minValue, maxValue, dataSet = 'abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ') {", + " if (!minValue) {", + " minValue = 1;", + " maxValue = 4;", + " }", + "", + " if (!maxValue) {", + " maxValue = minValue;", + " }", + "", + " let length = _.random(minValue, maxValue),", + " randomString = \"\";", + "", + " for (let i = 0; i < length; i++)", + " randomString += dataSet.charAt(Math.floor(Math.random() * dataSet.length));", + " return randomString;", + "}", + "", + "pm.variables.replaceIn('{{$randomFirstName}}');", + "pm.environment.set('shortName2', randomString());" + ], + "type": "text/javascript" + } + }, + { + "listen": "test", + "script": { + "exec": [ + "var jsonData = JSON.parse(responseBody);", + "postman.setEnvironmentVariable(\"payerSavingsProductId\", jsonData.resourceId);" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "authority", + "value": "fynams.mifos.g2pconnect.io" + }, + { + "key": "accept", + "value": "application/json, text/plain, */*" + }, + { + "key": "accept-language", + "value": "en-GB,en-US;q=0.9,en;q=0.8" + }, + { + "key": "authorization", + "value": "Basic bWlmb3M6cGFzc3dvcmQ=" + }, + { + "key": "content-type", + "value": "application/json;charset=UTF-8" + }, + { + "key": "fineract-platform-tenantid", + "value": "{{Tenant2}}" + }, + { + "key": "origin", + "value": "https://65.0.42.17:8443", + "disabled": true + }, + { + "key": "referer", + "value": "https://65.0.42.17:8443/", + "disabled": true + }, + { + "key": "sec-ch-ua", + "value": "\"Not?A_Brand\";v=\"8\", \"Chromium\";v=\"108\", \"Google Chrome\";v=\"108\"" + }, + { + "key": "sec-ch-ua-mobile", + "value": "?0" + }, + { + "key": "sec-ch-ua-platform", + "value": "\"macOS\"" + }, + { + "key": "sec-fetch-dest", + "value": "empty" + }, + { + "key": "sec-fetch-mode", + "value": "cors" + }, + { + "key": "sec-fetch-site", + "value": "cross-site" + }, + { + "key": "user-agent", + "value": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"currencyCode\": \"USD\",\n \"digitsAfterDecimal\": 2,\n \"interestCompoundingPeriodType\": 1,\n \"interestPostingPeriodType\": 4,\n \"interestCalculationType\": 1,\n \"interestCalculationDaysInYearType\": 365,\n \"accountingRule\": \"1\",\n \"name\": \"{{name2}}\",\n \"shortName\": \"{{shortName2}}\",\n \"inMultiplesOf\": \"1\",\n \"nominalAnnualInterestRate\": 5,\n \"paymentChannelToFundSourceMappings\": [],\n \"feeToIncomeAccountMappings\": [],\n \"penaltyToIncomeAccountMappings\": [],\n \"charges\": [],\n \"locale\": \"en\"\n}" + }, + "url": { + "raw": "https://{{Host2}}/savingsproducts", + "protocol": "https", + "host": [ + "{{Host2}}" + ], + "path": [ + "savingsproducts" + ] + } + }, + "response": [] + }, + { + "name": "payee-savings Products", + "event": [ + { + "listen": "prerequest", + "script": { + "exec": [ + "function randomString(minValue, maxValue, dataSet = 'abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ') {", + " if (!minValue) {", + " minValue = 1;", + " maxValue = 4;", + " }", + "", + " if (!maxValue) {", + " maxValue = minValue;", + " }", + "", + " let length = _.random(minValue, maxValue),", + " randomString = \"\";", + "", + " for (let i = 0; i < length; i++)", + " randomString += dataSet.charAt(Math.floor(Math.random() * dataSet.length));", + " return randomString;", + "}", + "", + "pm.variables.replaceIn('{{$randomFirstName}}');", + "pm.environment.set('shortName', randomString());" + ], + "type": "text/javascript" + } + }, + { + "listen": "test", + "script": { + "exec": [ + "var jsonData = JSON.parse(responseBody);", + "postman.setEnvironmentVariable(\"payeeSavingsProductId\", jsonData.resourceId);" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "authority", + "value": "fynams.mifos.g2pconnect.io" + }, + { + "key": "accept", + "value": "application/json, text/plain, */*" + }, + { + "key": "accept-language", + "value": "en-GB,en-US;q=0.9,en;q=0.8" + }, + { + "key": "authorization", + "value": "Basic bWlmb3M6cGFzc3dvcmQ=" + }, + { + "key": "content-type", + "value": "application/json;charset=UTF-8" + }, + { + "key": "fineract-platform-tenantid", + "value": "{{Tenant1}}" + }, + { + "key": "origin", + "value": "https://65.0.42.17:8443", + "disabled": true + }, + { + "key": "referer", + "value": "https://65.0.42.17:8443/", + "disabled": true + }, + { + "key": "sec-ch-ua", + "value": "\"Not?A_Brand\";v=\"8\", \"Chromium\";v=\"108\", \"Google Chrome\";v=\"108\"" + }, + { + "key": "sec-ch-ua-mobile", + "value": "?0" + }, + { + "key": "sec-ch-ua-platform", + "value": "\"macOS\"" + }, + { + "key": "sec-fetch-dest", + "value": "empty" + }, + { + "key": "sec-fetch-mode", + "value": "cors" + }, + { + "key": "sec-fetch-site", + "value": "cross-site" + }, + { + "key": "user-agent", + "value": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"currencyCode\": \"USD\",\n \"digitsAfterDecimal\": 2,\n \"interestCompoundingPeriodType\": 1,\n \"interestPostingPeriodType\": 4,\n \"interestCalculationType\": 1,\n \"interestCalculationDaysInYearType\": 365,\n \"accountingRule\": \"1\",\n \"name\": \"{{name}}\",\n \"shortName\": \"{{shortName}}\",\n \"inMultiplesOf\": \"1\",\n \"nominalAnnualInterestRate\": 5,\n \"paymentChannelToFundSourceMappings\": [],\n \"feeToIncomeAccountMappings\": [],\n \"penaltyToIncomeAccountMappings\": [],\n \"charges\": [],\n \"locale\": \"en\"\n}" + }, + "url": { + "raw": "https://{{Host1}}/savingsproducts", + "protocol": "https", + "host": [ + "{{Host1}}" + ], + "path": [ + "savingsproducts" + ] + } + }, + "response": [] + }, + { + "name": "Instruction to run the Runner folder", + "event": [ + { + "listen": "prerequest", + "script": { + "exec": [ + "function randomString(minValue, maxValue, dataSet = 'abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ') {", + " if (!minValue) {", + " minValue = 1;", + " maxValue = 4;", + " }", + "", + " if (!maxValue) {", + " maxValue = minValue;", + " }", + "", + " let length = _.random(minValue, maxValue),", + " randomString = \"\";", + "", + " for (let i = 0; i < length; i++)", + " randomString += dataSet.charAt(Math.floor(Math.random() * dataSet.length));", + " return randomString;", + "}", + "", + "pm.variables.replaceIn('{{$randomFirstName}}');", + "pm.environment.set('shortName2', randomString());" + ], + "type": "text/javascript" + } + }, + { + "listen": "test", + "script": { + "exec": [ + "var jsonData = JSON.parse(responseBody);", + "postman.setEnvironmentVariable(\"savingsProductId2\", jsonData.resourceId);" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "OPTIONS", + "header": [ + { + "key": "sec-ch-ua-platform", + "value": "\"macOS\"" + }, + { + "key": "sec-fetch-dest", + "value": "empty" + }, + { + "key": "sec-fetch-mode", + "value": "cors" + }, + { + "key": "sec-fetch-site", + "value": "cross-site" + }, + { + "key": "user-agent", + "value": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36" + } + ], + "body": { + "mode": "raw", + "raw": "Click on option and select Run Folder option to Use Postman Runner to run the below folder with the CSV provided \nat https://raw.githubusercontent.com/openMF/ph-ee-env-template/master/PostmanCollections/Environment/fineract-transfer-demo-prep.csv" + }, + "url": { + "raw": "Use Postman Runner to run the below folder with the CSV provided as fineract-transfer-demo-prep.csv", + "host": [ + "Use Postman Runner to run the below folder with the CSV provided as fineract-transfer-demo-prep", + "csv" + ] + } + }, + "response": [] + } + ] + }, + { + "name": "01-Runner", + "item": [ + { + "name": "Payer", + "item": [ + { + "name": "Create payer Clients", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "var jsonData = JSON.parse(responseBody);", + "postman.setEnvironmentVariable(\"payerClientId\", jsonData.resourceId);" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "function randomString(minValue, maxValue, dataSet = 'abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ') {", + " if (!minValue) {", + " minValue = 1;", + " maxValue = 4;", + " }", + "", + " if (!maxValue) {", + " maxValue = minValue;", + " }", + "", + " let length = _.random(minValue, maxValue),", + " randomString = \"\";", + "", + " for (let i = 0; i < length; i++)", + " randomString += dataSet.charAt(Math.floor(Math.random() * dataSet.length));", + " return randomString;", + "}", + "", + "pm.variables.replaceIn('{{$randomFirstName}}');", + "pm.environment.set('lastname', randomString());", + "", + "const monthNames = [\"January\",\"February\",\"March\",\"April\",\"May\",\"June\",\"July\",\"August\",\"September\",\"October\",\"November\",\"December\",]", + "today = new Date();", + "day = today.getDate();", + "month = monthNames[new Date().getMonth()];", + "year = today.getFullYear();", + "date = day + ' ' + month + ' ' + year", + "pm.environment.set(\"activationDate\", date);", + "pm.environment.set(\"submissionDate\", date);", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "authority", + "value": "fynams.mifos.g2pconnect.io" + }, + { + "key": "accept", + "value": "application/json, text/plain, */*" + }, + { + "key": "accept-language", + "value": "en-GB,en-US;q=0.9,en;q=0.8" + }, + { + "key": "authorization", + "value": "Basic bWlmb3M6cGFzc3dvcmQ=" + }, + { + "key": "content-type", + "value": "application/json;charset=UTF-8" + }, + { + "key": "fineract-platform-tenantid", + "value": "{{Tenant2}}" + }, + { + "key": "origin", + "value": "https://65.0.42.17:8443" + }, + { + "key": "referer", + "value": "https://65.0.42.17:8443/" + }, + { + "key": "sec-ch-ua", + "value": "\"Not?A_Brand\";v=\"8\", \"Chromium\";v=\"108\", \"Google Chrome\";v=\"108\"" + }, + { + "key": "sec-ch-ua-mobile", + "value": "?0" + }, + { + "key": "sec-ch-ua-platform", + "value": "\"macOS\"" + }, + { + "key": "sec-fetch-dest", + "value": "empty" + }, + { + "key": "sec-fetch-mode", + "value": "cors" + }, + { + "key": "sec-fetch-site", + "value": "cross-site" + }, + { + "key": "user-agent", + "value": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36" + }, + { + "key": "", + "value": "", + "type": "text", + "disabled": true + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"address\": [],\n \"familyMembers\": [],\n \"officeId\": 1,\n \"firstname\": \"{{$randomFirstName}}\",\n \"lastname\": \"{{$randomLastName}}\",\n \"active\": true,\n \"legalFormId\": 1,\n \"locale\": \"en\",\n \"dateFormat\": \"dd MMMM yyyy\",\n \"activationDate\": \"{{payer-activationDate}}\",\n \"submittedOnDate\": \"{{payer-activationDate}}\",\n \"savingsProductId\": null\n}" + }, + "url": { + "raw": "https://{{Host1}}/clients", + "protocol": "https", + "host": [ + "{{Host1}}" + ], + "path": [ + "clients" + ] + } + }, + "response": [] + }, + { + "name": "savingsaccounts", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "var jsonData = JSON.parse(responseBody);", + "postman.setEnvironmentVariable(\"savingsAccId\", jsonData.savingsId);", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "const monthNames = [\"January\",\"February\",\"March\",\"April\",\"May\",\"June\",\"July\",\"August\",\"September\",\"October\",\"November\",\"December\",]", + "today = new Date();", + "day = today.getDate();", + "month = monthNames[new Date().getMonth()];", + "year = today.getFullYear();", + "date = day + ' ' + month + ' ' + year", + "pm.environment.set(\"submissionDate\", date);", + "", + "function randomString(minValue, maxValue, dataSet = 'abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ') {", + " if (!minValue) {", + " minValue = 1;", + " maxValue = 4;", + " }", + "", + " if (!maxValue) {", + " maxValue = minValue;", + " }", + "", + " let length = _.random(minValue, maxValue),", + " randomString = \"\";", + "", + " for (let i = 0; i < length; i++)", + " randomString += dataSet.charAt(Math.floor(Math.random() * dataSet.length));", + " return randomString;", + "}", + "pm.environment.set('externalId1', randomString());" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "authority", + "value": "fynams.mifos.g2pconnect.io" + }, + { + "key": "accept", + "value": "application/json, text/plain, */*" + }, + { + "key": "accept-language", + "value": "en-GB,en-US;q=0.9,en;q=0.8" + }, + { + "key": "authorization", + "value": "Basic bWlmb3M6cGFzc3dvcmQ=" + }, + { + "key": "content-type", + "value": "application/json;charset=UTF-8" + }, + { + "key": "fineract-platform-tenantid", + "value": "{{Tenant2}}" + }, + { + "key": "origin", + "value": "https://65.0.42.17:8443" + }, + { + "key": "referer", + "value": "https://65.0.42.17:8443/" + }, + { + "key": "sec-ch-ua", + "value": "\"Not?A_Brand\";v=\"8\", \"Chromium\";v=\"108\", \"Google Chrome\";v=\"108\"" + }, + { + "key": "sec-ch-ua-mobile", + "value": "?0" + }, + { + "key": "sec-ch-ua-platform", + "value": "\"macOS\"" + }, + { + "key": "sec-fetch-dest", + "value": "empty" + }, + { + "key": "sec-fetch-mode", + "value": "cors" + }, + { + "key": "sec-fetch-site", + "value": "cross-site" + }, + { + "key": "user-agent", + "value": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"productId\": \"{{payerSavingsProductId}}\",\n \"nominalAnnualInterestRate\": 5,\n \"withdrawalFeeForTransfers\": false,\n \"allowOverdraft\": false,\n \"lienAllowed\": false,\n \"enforceMinRequiredBalance\": false,\n \"withHoldTax\": false,\n \"interestCompoundingPeriodType\": 1,\n \"interestPostingPeriodType\": 4,\n \"interestCalculationType\": 1,\n \"interestCalculationDaysInYearType\": 365,\n \"submittedOnDate\": \"{{payee-submissionDate}}\",\n \"locale\": \"en\",\n \"dateFormat\": \"dd MMMM yyyy\",\n \"monthDayFormat\": \"dd MMM\",\n \"charges\": [],\n \"clientId\": \"{{payerClientId}}\",\n \"externalId\": \"{{payer_externalId}}\"\n}" + }, + "url": { + "raw": "https://{{Host1}}/savingsaccounts", + "protocol": "https", + "host": [ + "{{Host1}}" + ], + "path": [ + "savingsaccounts" + ] + } + }, + "response": [] + }, + { + "name": "approve", + "event": [ + { + "listen": "prerequest", + "script": { + "exec": [ + "const monthNames = [\"January\",\"February\",\"March\",\"April\",\"May\",\"June\",\"July\",\"August\",\"September\",\"October\",\"November\",\"December\",]", + "today = new Date();", + "day = today.getDate();", + "month = monthNames[new Date().getMonth()];", + "year = today.getFullYear();", + "date = day + ' ' + month + ' ' + year", + "pm.environment.set(\"approvedDate\", date);" + ], + "type": "text/javascript" + } + }, + { + "listen": "test", + "script": { + "exec": [ + "", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "authority", + "value": "fynams.mifos.g2pconnect.io" + }, + { + "key": "accept", + "value": "application/json, text/plain, */*" + }, + { + "key": "accept-language", + "value": "en-GB,en-US;q=0.9,en;q=0.8" + }, + { + "key": "authorization", + "value": "Basic bWlmb3M6cGFzc3dvcmQ=" + }, + { + "key": "content-type", + "value": "application/json;charset=UTF-8" + }, + { + "key": "fineract-platform-tenantid", + "value": "{{Tenant2}}" + }, + { + "key": "origin", + "value": "https://65.0.42.17:8443" + }, + { + "key": "referer", + "value": "https://65.0.42.17:8443/" + }, + { + "key": "sec-ch-ua", + "value": "\"Not?A_Brand\";v=\"8\", \"Chromium\";v=\"108\", \"Google Chrome\";v=\"108\"" + }, + { + "key": "sec-ch-ua-mobile", + "value": "?0" + }, + { + "key": "sec-ch-ua-platform", + "value": "\"macOS\"" + }, + { + "key": "sec-fetch-dest", + "value": "empty" + }, + { + "key": "sec-fetch-mode", + "value": "cors" + }, + { + "key": "sec-fetch-site", + "value": "cross-site" + }, + { + "key": "user-agent", + "value": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"approvedOnDate\": \"{{payer-approvedDate}}\",\n \"locale\": \"en\",\n \"dateFormat\": \"dd MMMM yyyy\"\n}" + }, + "url": { + "raw": "https://{{Host1}}/savingsaccounts/{{savingsAccId}}?command=approve", + "protocol": "https", + "host": [ + "{{Host1}}" + ], + "path": [ + "savingsaccounts", + "{{savingsAccId}}" + ], + "query": [ + { + "key": "command", + "value": "approve" + } + ] + } + }, + "response": [] + }, + { + "name": "activate", + "event": [ + { + "listen": "prerequest", + "script": { + "exec": [ + "const monthNames = [\"January\",\"February\",\"March\",\"April\",\"May\",\"June\",\"July\",\"August\",\"September\",\"October\",\"November\",\"December\",]", + "today = new Date();", + "day = today.getDate();", + "month = monthNames[new Date().getMonth()];", + "year = today.getFullYear();", + "date = day + ' ' + month + ' ' + year", + "pm.environment.set(\"activationDate\", date);" + ], + "type": "text/javascript" + } + }, + { + "listen": "test", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "authority", + "value": "fynams.mifos.g2pconnect.io" + }, + { + "key": "accept", + "value": "application/json, text/plain, */*" + }, + { + "key": "accept-language", + "value": "en-GB,en-US;q=0.9,en;q=0.8" + }, + { + "key": "authorization", + "value": "Basic bWlmb3M6cGFzc3dvcmQ=" + }, + { + "key": "content-type", + "value": "application/json;charset=UTF-8" + }, + { + "key": "fineract-platform-tenantid", + "value": "{{Tenant2}}" + }, + { + "key": "origin", + "value": "https://65.0.42.17:8443" + }, + { + "key": "referer", + "value": "https://65.0.42.17:8443/" + }, + { + "key": "sec-ch-ua", + "value": "\"Not?A_Brand\";v=\"8\", \"Chromium\";v=\"108\", \"Google Chrome\";v=\"108\"" + }, + { + "key": "sec-ch-ua-mobile", + "value": "?0" + }, + { + "key": "sec-ch-ua-platform", + "value": "\"macOS\"" + }, + { + "key": "sec-fetch-dest", + "value": "empty" + }, + { + "key": "sec-fetch-mode", + "value": "cors" + }, + { + "key": "sec-fetch-site", + "value": "cross-site" + }, + { + "key": "user-agent", + "value": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"activatedOnDate\": \"{{payer-acc-activationDate}}\",\n \"locale\": \"en\",\n \"dateFormat\": \"dd MMMM yyyy\"\n}" + }, + "url": { + "raw": "https://{{Host1}}/savingsaccounts/{{savingsAccId}}?command=activate", + "protocol": "https", + "host": [ + "{{Host1}}" + ], + "path": [ + "savingsaccounts", + "{{savingsAccId}}" + ], + "query": [ + { + "key": "command", + "value": "activate" + } + ] + } + }, + "response": [] + }, + { + "name": "savingsaccounts deposit", + "event": [ + { + "listen": "prerequest", + "script": { + "exec": [ + "const monthNames = [\"January\",\"February\",\"March\",\"April\",\"May\",\"June\",\"July\",\"August\",\"September\",\"October\",\"November\",\"December\",]", + "today = new Date();", + "day = today.getDate();", + "month = monthNames[new Date().getMonth()];", + "year = today.getFullYear();", + "date = day + ' ' + month + ' ' + year", + "pm.environment.set(\"transactionDate\", date);" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "authority", + "value": "fynams.mifos.g2pconnect.io" + }, + { + "key": "accept", + "value": "application/json, text/plain, */*" + }, + { + "key": "accept-language", + "value": "en-GB,en-US;q=0.9,en;q=0.8" + }, + { + "key": "authorization", + "value": "Basic bWlmb3M6cGFzc3dvcmQ=" + }, + { + "key": "content-type", + "value": "application/json;charset=UTF-8" + }, + { + "key": "fineract-platform-tenantid", + "value": "{{Tenant2}}" + }, + { + "key": "origin", + "value": "https://65.0.42.17:8443" + }, + { + "key": "referer", + "value": "https://65.0.42.17:8443/" + }, + { + "key": "sec-ch-ua", + "value": "\"Not?A_Brand\";v=\"8\", \"Chromium\";v=\"108\", \"Google Chrome\";v=\"108\"" + }, + { + "key": "sec-ch-ua-mobile", + "value": "?0" + }, + { + "key": "sec-ch-ua-platform", + "value": "\"macOS\"" + }, + { + "key": "sec-fetch-dest", + "value": "empty" + }, + { + "key": "sec-fetch-mode", + "value": "cors" + }, + { + "key": "sec-fetch-site", + "value": "cross-site" + }, + { + "key": "user-agent", + "value": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"dateFormat\": \"dd MMMM yyyy\",\n \"locale\": \"en\",\n \"paymentTypeId\": 1,\n \"transactionAmount\": 1000,\n \"transactionDate\": \"{{payer-transactionDate}}\"\n}" + }, + "url": { + "raw": "https://{{Host1}}/savingsaccounts/{{savingsAccId}}/transactions?command=deposit", + "protocol": "https", + "host": [ + "{{Host1}}" + ], + "path": [ + "savingsaccounts", + "{{savingsAccId}}", + "transactions" + ], + "query": [ + { + "key": "command", + "value": "deposit" + } + ] + } + }, + "response": [] + }, + { + "name": "Set Payer nterop Identifier", + "event": [ + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "authority", + "value": "fynams.mifos.g2pconnect.io" + }, + { + "key": "accept", + "value": "application/json, text/plain, */*" + }, + { + "key": "accept-language", + "value": "en-GB,en-US;q=0.9,en;q=0.8" + }, + { + "key": "authorization", + "value": "Basic bWlmb3M6cGFzc3dvcmQ=" + }, + { + "key": "content-type", + "value": "application/json;charset=UTF-8" + }, + { + "key": "fineract-platform-tenantid", + "value": "{{Tenant2}}" + }, + { + "key": "origin", + "value": "https://65.0.42.17:8443" + }, + { + "key": "referer", + "value": "https://65.0.42.17:8443/" + }, + { + "key": "sec-ch-ua", + "value": "\"Not?A_Brand\";v=\"8\", \"Chromium\";v=\"108\", \"Google Chrome\";v=\"108\"" + }, + { + "key": "sec-ch-ua-mobile", + "value": "?0" + }, + { + "key": "sec-ch-ua-platform", + "value": "\"macOS\"" + }, + { + "key": "sec-fetch-dest", + "value": "empty" + }, + { + "key": "sec-fetch-mode", + "value": "cors" + }, + { + "key": "sec-fetch-site", + "value": "cross-site" + }, + { + "key": "user-agent", + "value": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"accountId\": \"{{payer_externalId}}\"\n}" + }, + "url": { + "raw": "https://{{Host1}}/interoperation/parties/{{payer_identifierType}}/{{payer_identifier}}", + "protocol": "https", + "host": [ + "{{Host1}}" + ], + "path": [ + "interoperation", + "parties", + "{{payer_identifierType}}", + "{{payer_identifier}}" + ] + } + }, + "response": [] + } + ] + }, + { + "name": "Payee", + "item": [ + { + "name": "Create payee Clients", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "var jsonData = JSON.parse(responseBody);", + "postman.setEnvironmentVariable(\"payeeClientId\", jsonData.resourceId);" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "const monthNames = [\"January\",\"February\",\"March\",\"April\",\"May\",\"June\",\"July\",\"August\",\"September\",\"October\",\"November\",\"December\",]", + "today = new Date();", + "day = today.getDate();", + "month = monthNames[new Date().getMonth()];", + "year = today.getFullYear();", + "date = day + ' ' + month + ' ' + year", + "pm.environment.set(\"activationDate\", date);", + "pm.environment.set(\"submissionDate\", date);", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "authority", + "value": "fynams.mifos.g2pconnect.io" + }, + { + "key": "accept", + "value": "application/json, text/plain, */*" + }, + { + "key": "accept-language", + "value": "en-GB,en-US;q=0.9,en;q=0.8" + }, + { + "key": "authorization", + "value": "Basic bWlmb3M6cGFzc3dvcmQ=" + }, + { + "key": "content-type", + "value": "application/json;charset=UTF-8" + }, + { + "key": "fineract-platform-tenantid", + "value": "{{Tenant1}}" + }, + { + "key": "origin", + "value": "https://65.0.42.17:8443" + }, + { + "key": "referer", + "value": "https://65.0.42.17:8443/" + }, + { + "key": "sec-ch-ua", + "value": "\"Not?A_Brand\";v=\"8\", \"Chromium\";v=\"108\", \"Google Chrome\";v=\"108\"" + }, + { + "key": "sec-ch-ua-mobile", + "value": "?0" + }, + { + "key": "sec-ch-ua-platform", + "value": "\"macOS\"" + }, + { + "key": "sec-fetch-dest", + "value": "empty" + }, + { + "key": "sec-fetch-mode", + "value": "cors" + }, + { + "key": "sec-fetch-site", + "value": "cross-site" + }, + { + "key": "user-agent", + "value": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"address\": [],\n \"familyMembers\": [],\n \"officeId\": 1,\n \"firstname\": \"{{$randomFirstName}}\",\n \"lastname\": \"{{$randomLastName}}\",\n \"active\": true,\n \"legalFormId\": 1,\n \"locale\": \"en\",\n \"dateFormat\": \"dd MMMM yyyy\",\n \"activationDate\": \"{{payee-activationDate}}\",\n \"submittedOnDate\": \"{{payee-activationDate}}\",\n \"savingsProductId\": null\n}" + }, + "url": { + "raw": "https://{{Host2}}/clients", + "protocol": "https", + "host": [ + "{{Host2}}" + ], + "path": [ + "clients" + ] + } + }, + "response": [] + }, + { + "name": "savingsaccounts", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "var jsonData = JSON.parse(responseBody);", + "postman.setEnvironmentVariable(\"savingsAccId2\", jsonData.resourceId);" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "const monthNames = [\"January\",\"February\",\"March\",\"April\",\"May\",\"June\",\"July\",\"August\",\"September\",\"October\",\"November\",\"December\",]", + "today = new Date();", + "day = today.getDate();", + "month = monthNames[new Date().getMonth()];", + "year = today.getFullYear();", + "date = day + ' ' + month + ' ' + year", + "pm.environment.set(\"submissionDate\", date);", + "", + "function randomString(minValue, maxValue, dataSet = 'abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ') {", + " if (!minValue) {", + " minValue = 1;", + " maxValue = 4;", + " }", + "", + " if (!maxValue) {", + " maxValue = minValue;", + " }", + "", + " let length = _.random(minValue, maxValue),", + " randomString = \"\";", + "", + " for (let i = 0; i < length; i++)", + " randomString += dataSet.charAt(Math.floor(Math.random() * dataSet.length));", + " return randomString;", + "}", + "pm.environment.set('externalId2', randomString());" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "authority", + "value": "fynams.mifos.g2pconnect.io" + }, + { + "key": "accept", + "value": "application/json, text/plain, */*" + }, + { + "key": "accept-language", + "value": "en-GB,en-US;q=0.9,en;q=0.8" + }, + { + "key": "authorization", + "value": "Basic bWlmb3M6cGFzc3dvcmQ=" + }, + { + "key": "content-type", + "value": "application/json;charset=UTF-8" + }, + { + "key": "fineract-platform-tenantid", + "value": "{{Tenant1}}" + }, + { + "key": "origin", + "value": "https://65.0.42.17:8443" + }, + { + "key": "referer", + "value": "https://65.0.42.17:8443/" + }, + { + "key": "sec-ch-ua", + "value": "\"Not?A_Brand\";v=\"8\", \"Chromium\";v=\"108\", \"Google Chrome\";v=\"108\"" + }, + { + "key": "sec-ch-ua-mobile", + "value": "?0" + }, + { + "key": "sec-ch-ua-platform", + "value": "\"macOS\"" + }, + { + "key": "sec-fetch-dest", + "value": "empty" + }, + { + "key": "sec-fetch-mode", + "value": "cors" + }, + { + "key": "sec-fetch-site", + "value": "cross-site" + }, + { + "key": "user-agent", + "value": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"productId\": \"{{payeeSavingsProductId}}\",\n \"nominalAnnualInterestRate\": 5,\n \"withdrawalFeeForTransfers\": false,\n \"allowOverdraft\": false,\n \"lienAllowed\": false,\n \"enforceMinRequiredBalance\": false,\n \"withHoldTax\": false,\n \"interestCompoundingPeriodType\": 1,\n \"interestPostingPeriodType\": 4,\n \"interestCalculationType\": 1,\n \"interestCalculationDaysInYearType\": 365,\n \"submittedOnDate\": \"{{payee-submissionDate}}\",\n \"locale\": \"en\",\n \"dateFormat\": \"dd MMMM yyyy\",\n \"monthDayFormat\": \"dd MMM\",\n \"charges\": [],\n \"clientId\": \"{{payeeClientId}}\",\n \"externalId\": \"{{payee_externalId}}\"\n}" + }, + "url": { + "raw": "https://{{Host2}}/savingsaccounts", + "protocol": "https", + "host": [ + "{{Host2}}" + ], + "path": [ + "savingsaccounts" + ] + } + }, + "response": [] + }, + { + "name": "approve payee", + "event": [ + { + "listen": "prerequest", + "script": { + "exec": [ + "const monthNames = [\"January\",\"February\",\"March\",\"April\",\"May\",\"June\",\"July\",\"August\",\"September\",\"October\",\"November\",\"December\",]", + "today = new Date();", + "day = today.getDate();", + "month = monthNames[new Date().getMonth()];", + "year = today.getFullYear();", + "date = day + ' ' + month + ' ' + year", + "pm.environment.set(\"approvedDate\", date);" + ], + "type": "text/javascript" + } + }, + { + "listen": "test", + "script": { + "exec": [ + "const monthNames = [\"January\",\"February\",\"March\",\"April\",\"May\",\"June\",\"July\",\"August\",\"September\",\"October\",\"November\",\"December\",]", + "today = new Date();", + "day = today.getDate();", + "month = monthNames[new Date().getMonth()];", + "year = today.getFullYear();", + "date = day + ' ' + month + ' ' + year", + "pm.environment.set(\"approvedDate\", date);" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "authority", + "value": "fynams.mifos.g2pconnect.io" + }, + { + "key": "accept", + "value": "application/json, text/plain, */*" + }, + { + "key": "accept-language", + "value": "en-GB,en-US;q=0.9,en;q=0.8" + }, + { + "key": "authorization", + "value": "Basic bWlmb3M6cGFzc3dvcmQ=" + }, + { + "key": "content-type", + "value": "application/json;charset=UTF-8" + }, + { + "key": "fineract-platform-tenantid", + "value": "{{Tenant1}}" + }, + { + "key": "origin", + "value": "https://65.0.42.17:8443" + }, + { + "key": "referer", + "value": "https://65.0.42.17:8443/" + }, + { + "key": "sec-ch-ua", + "value": "\"Not?A_Brand\";v=\"8\", \"Chromium\";v=\"108\", \"Google Chrome\";v=\"108\"" + }, + { + "key": "sec-ch-ua-mobile", + "value": "?0" + }, + { + "key": "sec-ch-ua-platform", + "value": "\"macOS\"" + }, + { + "key": "sec-fetch-dest", + "value": "empty" + }, + { + "key": "sec-fetch-mode", + "value": "cors" + }, + { + "key": "sec-fetch-site", + "value": "cross-site" + }, + { + "key": "user-agent", + "value": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"approvedOnDate\": \"{{payee-approvedDate}}\",\n \"locale\": \"en\",\n \"dateFormat\": \"dd MMMM yyyy\"\n}" + }, + "url": { + "raw": "https://{{Host2}}/savingsaccounts/{{savingsAccId2}}?command=approve", + "protocol": "https", + "host": [ + "{{Host2}}" + ], + "path": [ + "savingsaccounts", + "{{savingsAccId2}}" + ], + "query": [ + { + "key": "command", + "value": "approve" + } + ] + } + }, + "response": [] + }, + { + "name": "activate payee", + "event": [ + { + "listen": "prerequest", + "script": { + "exec": [ + "const monthNames = [\"January\",\"February\",\"March\",\"April\",\"May\",\"June\",\"July\",\"August\",\"September\",\"October\",\"November\",\"December\",]", + "today = new Date();", + "day = today.getDate();", + "month = monthNames[new Date().getMonth()];", + "year = today.getFullYear();", + "date = day + ' ' + month + ' ' + year", + "pm.environment.set(\"activationDate\", date);" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "authority", + "value": "fynams.mifos.g2pconnect.io" + }, + { + "key": "accept", + "value": "application/json, text/plain, */*" + }, + { + "key": "accept-language", + "value": "en-GB,en-US;q=0.9,en;q=0.8" + }, + { + "key": "authorization", + "value": "Basic bWlmb3M6cGFzc3dvcmQ=" + }, + { + "key": "content-type", + "value": "application/json;charset=UTF-8" + }, + { + "key": "fineract-platform-tenantid", + "value": "{{Tenant1}}" + }, + { + "key": "origin", + "value": "https://65.0.42.17:8443" + }, + { + "key": "referer", + "value": "https://65.0.42.17:8443/" + }, + { + "key": "sec-ch-ua", + "value": "\"Not?A_Brand\";v=\"8\", \"Chromium\";v=\"108\", \"Google Chrome\";v=\"108\"" + }, + { + "key": "sec-ch-ua-mobile", + "value": "?0" + }, + { + "key": "sec-ch-ua-platform", + "value": "\"macOS\"" + }, + { + "key": "sec-fetch-dest", + "value": "empty" + }, + { + "key": "sec-fetch-mode", + "value": "cors" + }, + { + "key": "sec-fetch-site", + "value": "cross-site" + }, + { + "key": "user-agent", + "value": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"activatedOnDate\": \"{{payee-acc-activationDate}}\",\n \"locale\": \"en\",\n \"dateFormat\": \"dd MMMM yyyy\"\n}" + }, + "url": { + "raw": "https://{{Host2}}/savingsaccounts/{{savingsAccId2}}?command=activate", + "protocol": "https", + "host": [ + "{{Host2}}" + ], + "path": [ + "savingsaccounts", + "{{savingsAccId2}}" + ], + "query": [ + { + "key": "command", + "value": "activate" + } + ] + } + }, + "response": [] + }, + { + "name": "savingsaccounts deposit payee", + "event": [ + { + "listen": "prerequest", + "script": { + "exec": [ + "const monthNames = [\"January\",\"February\",\"March\",\"April\",\"May\",\"June\",\"July\",\"August\",\"September\",\"October\",\"November\",\"December\",]", + "today = new Date();", + "day = today.getDate();", + "month = monthNames[new Date().getMonth()];", + "year = today.getFullYear();", + "date = day + ' ' + month + ' ' + year", + "pm.environment.set(\"transactionDate\", date);" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "authority", + "value": "fynams.mifos.g2pconnect.io" + }, + { + "key": "accept", + "value": "application/json, text/plain, */*" + }, + { + "key": "accept-language", + "value": "en-GB,en-US;q=0.9,en;q=0.8" + }, + { + "key": "authorization", + "value": "Basic bWlmb3M6cGFzc3dvcmQ=" + }, + { + "key": "content-type", + "value": "application/json;charset=UTF-8" + }, + { + "key": "fineract-platform-tenantid", + "value": "{{Tenant1}}" + }, + { + "key": "origin", + "value": "https://65.0.42.17:8443" + }, + { + "key": "referer", + "value": "https://65.0.42.17:8443/" + }, + { + "key": "sec-ch-ua", + "value": "\"Not?A_Brand\";v=\"8\", \"Chromium\";v=\"108\", \"Google Chrome\";v=\"108\"" + }, + { + "key": "sec-ch-ua-mobile", + "value": "?0" + }, + { + "key": "sec-ch-ua-platform", + "value": "\"macOS\"" + }, + { + "key": "sec-fetch-dest", + "value": "empty" + }, + { + "key": "sec-fetch-mode", + "value": "cors" + }, + { + "key": "sec-fetch-site", + "value": "cross-site" + }, + { + "key": "user-agent", + "value": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"dateFormat\": \"dd MMMM yyyy\",\n \"locale\": \"en\",\n \"paymentTypeId\": 1,\n \"transactionAmount\": 1000,\n \"transactionDate\": \"{{payee-transactionDate}}\"\n}" + }, + "url": { + "raw": "https://{{Host2}}/savingsaccounts/{{savingsAccId2}}/transactions?command=deposit", + "protocol": "https", + "host": [ + "{{Host2}}" + ], + "path": [ + "savingsaccounts", + "{{savingsAccId2}}", + "transactions" + ], + "query": [ + { + "key": "command", + "value": "deposit" + } + ] + } + }, + "response": [] + }, + { + "name": "Set Payee nterop Identifier", + "request": { + "method": "POST", + "header": [ + { + "key": "authority", + "value": "fynams.mifos.g2pconnect.io" + }, + { + "key": "accept", + "value": "application/json, text/plain, */*" + }, + { + "key": "accept-language", + "value": "en-GB,en-US;q=0.9,en;q=0.8" + }, + { + "key": "authorization", + "value": "Basic bWlmb3M6cGFzc3dvcmQ=" + }, + { + "key": "content-type", + "value": "application/json;charset=UTF-8" + }, + { + "key": "fineract-platform-tenantid", + "value": "{{Tenant1}}" + }, + { + "key": "origin", + "value": "https://65.0.42.17:8443" + }, + { + "key": "referer", + "value": "https://65.0.42.17:8443/" + }, + { + "key": "sec-ch-ua", + "value": "\"Not?A_Brand\";v=\"8\", \"Chromium\";v=\"108\", \"Google Chrome\";v=\"108\"" + }, + { + "key": "sec-ch-ua-mobile", + "value": "?0" + }, + { + "key": "sec-ch-ua-platform", + "value": "\"macOS\"" + }, + { + "key": "sec-fetch-dest", + "value": "empty" + }, + { + "key": "sec-fetch-mode", + "value": "cors" + }, + { + "key": "sec-fetch-site", + "value": "cross-site" + }, + { + "key": "user-agent", + "value": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"accountId\": \"{{payee_externalId}}\"\n}" + }, + "url": { + "raw": "https://{{Host2}}/interoperation/parties/{{payee_identifierType}}/{{payee_identifier}}", + "protocol": "https", + "host": [ + "{{Host2}}" + ], + "path": [ + "interoperation", + "parties", + "{{payee_identifierType}}", + "{{payee_identifier}}" + ] + } + }, + "response": [] + } + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/ph-ee-env-template/PostmanCollections/Mobile Money Simulator.json b/ph-ee-env-template/PostmanCollections/Mobile Money Simulator.json new file mode 100644 index 000000000..ccb5e0cd0 --- /dev/null +++ b/ph-ee-env-template/PostmanCollections/Mobile Money Simulator.json @@ -0,0 +1,38475 @@ +{ + "info": { + "_postman_id": "45eb93e3-9756-4a42-89d4-5cae0dde3ab7", + "name": "Mobile Money Simulator API", + "description": "This document defines the RESTful endpoints provided by the GSMA Mobile Money API\nYou can find out more about what the API can do for your business at\n[https://developer.mobilemoneyapi.io]\n", + "schema": "https://schema.getpostman.com/json/collection/v2.0.0/collection.json" + }, + "item": [ + { + "name": "transactions", + "item": [ + { + "name": "{transaction Reference}", + "item": [ + { + "name": "View A Transaction", + "id": "2d541615-77b7-45c9-bb09-cd9aa48f1d77", + "request": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/transactions/:transactionReference", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "transactions", + ":transactionReference" + ], + "variable": [ + { + "id": "0cd31ef6-2d96-46f8-99f4-d5c12efe7302", + "key": "transactionReference", + "value": "", + "description": "(Required) Path variable to uniquely identify the transaction." + } + ] + }, + "description": "This endpoint returns the details of a transaction" + }, + "response": [ + { + "id": "6c2f6b69-5330-498f-ac7c-f000b3a7a9db", + "name": "Represents an Error Caused by a Failure to Identify the Target Resource", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/transactions/:transactionReference", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "transactions", + ":transactionReference" + ], + "variable": [ + { + "key": "transactionReference" + } + ] + } + }, + "status": "Not Found", + "code": 404, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "8168ad8d-96ed-407a-8088-f00717930314", + "name": "Represents a Transaction response", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/transactions/:transactionReference", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "transactions", + ":transactionReference" + ], + "variable": [ + { + "key": "transactionReference" + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"amount\": \"15.21\",\n \"currency\": \"\",\n \"type\": \"\",\n \"transactionReference\": \"\",\n \"transactionStatus\": \"\",\n \"debitParty\": [\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n },\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n }\n ],\n \"creditParty\": [\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n },\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n }\n ],\n \"subType\": \"\",\n \"descriptionText\": \"\",\n \"requestDate\": \"\",\n \"requestingOrganisationTransactionReference\": \"\",\n \"oneTimeCode\": \"\",\n \"geoCode\": \"37.423825,-122.082900\",\n \"senderKyc\": {\n \"nationality\": \"\",\n \"dateOfBirth\": \"2000-11-20\",\n \"occupation\": \"\",\n \"employerName\": \"\",\n \"contactPhone\": \"\",\n \"gender\": \"\",\n \"idDocument\": [\n {\n \"idType\": \"\",\n \"idNumber\": \"\",\n \"issueDate\": \"2018-11-20\",\n \"expiryDate\": \"2018-11-20\",\n \"issuer\": \"\",\n \"issuerPlace\": \"\",\n \"issuerCountry\": \"\",\n \"otherIddescription\": \"\"\n },\n {\n \"idType\": \"\",\n \"idNumber\": \"\",\n \"issueDate\": \"2018-11-20\",\n \"expiryDate\": \"2018-11-20\",\n \"issuer\": \"\",\n \"issuerPlace\": \"\",\n \"issuerCountry\": \"\",\n \"otherIddescription\": \"\"\n }\n ],\n \"postalAddress\": {\n \"country\": \"\",\n \"addressLine1\": \"\",\n \"addressLine2\": \"\",\n \"addressLine3\": \"\",\n \"city\": \"\",\n \"stateProvince\": \"\",\n \"postalCode\": \"\"\n },\n \"subjectName\": {\n \"title\": \"\",\n \"firstName\": \"\",\n \"middleName\": \"\",\n \"lastName\": \"\",\n \"fullName\": \"\",\n \"nativeName\": \"\"\n },\n \"emailAddress\": \"\",\n \"birthCountry\": \"\"\n },\n \"recipientKyc\": {\n \"nationality\": \"\",\n \"dateOfBirth\": \"2000-11-20\",\n \"occupation\": \"\",\n \"employerName\": \"\",\n \"contactPhone\": \"\",\n \"gender\": \"\",\n \"idDocument\": [\n {\n \"idType\": \"\",\n \"idNumber\": \"\",\n \"issueDate\": \"2018-11-20\",\n \"expiryDate\": \"2018-11-20\",\n \"issuer\": \"\",\n \"issuerPlace\": \"\",\n \"issuerCountry\": \"\",\n \"otherIddescription\": \"\"\n },\n {\n \"idType\": \"\",\n \"idNumber\": \"\",\n \"issueDate\": \"2018-11-20\",\n \"expiryDate\": \"2018-11-20\",\n \"issuer\": \"\",\n \"issuerPlace\": \"\",\n \"issuerCountry\": \"\",\n \"otherIddescription\": \"\"\n }\n ],\n \"postalAddress\": {\n \"country\": \"\",\n \"addressLine1\": \"\",\n \"addressLine2\": \"\",\n \"addressLine3\": \"\",\n \"city\": \"\",\n \"stateProvince\": \"\",\n \"postalCode\": \"\"\n },\n \"subjectName\": {\n \"title\": \"\",\n \"firstName\": \"\",\n \"middleName\": \"\",\n \"lastName\": \"\",\n \"fullName\": \"\",\n \"nativeName\": \"\"\n },\n \"emailAddress\": \"\",\n \"birthCountry\": \"\"\n },\n \"originalTransactionReference\": \"\",\n \"servicingIdentity\": \"\",\n \"fees\": [\n {\n \"feeType\": \"\",\n \"feeCurrency\": \"\",\n \"feeAmount\": \"15.21\"\n },\n {\n \"feeType\": \"\",\n \"feeCurrency\": \"\",\n \"feeAmount\": \"15.21\"\n }\n ],\n \"requestingLei\": \"54930084UKLVMY22DS16\",\n \"receivingLei\": \"5493000IBP32UQZ0KL24\",\n \"metadata\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ],\n \"creationDate\": \"\",\n \"modificationDate\": \"\",\n \"dateCreated\": \"\",\n \"dateModified\": \"\",\n \"transactionReceipt\": \"\",\n \"internationalTransferInformation\": {\n \"originCountry\": \"\",\n \"quotationReference\": \"\",\n \"quoteId\": \"\",\n \"receivingCountry\": \"\",\n \"remittancePurpose\": \"\",\n \"relationshipSender\": \"\",\n \"deliveryMethod\": \"\",\n \"senderBlockingReason\": \"\",\n \"recipientBlockingReason\": \"\"\n }\n}" + }, + { + "id": "a3c550a0-a4da-41fb-a10e-dbb93d9d23e3", + "name": "Represents an Error Caused by the Violation of a Business Rule", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/transactions/:transactionReference", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "transactions", + ":transactionReference" + ], + "variable": [ + { + "key": "transactionReference" + } + ] + } + }, + "status": "Bad Request", + "code": 400, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "a0cce2df-62f8-4051-84b3-87273444faf7", + "name": "Represents an Error Caused by an Authorisation Failure", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/transactions/:transactionReference", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "transactions", + ":transactionReference" + ], + "variable": [ + { + "key": "transactionReference" + } + ] + } + }, + "status": "Unauthorized", + "code": 401, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "f94af51e-5acd-4ee5-a103-3c3049a2fe09", + "name": "Represents an Error Caused by a General Server-Side Issue", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/transactions/:transactionReference", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "transactions", + ":transactionReference" + ], + "variable": [ + { + "key": "transactionReference" + } + ] + } + }, + "status": "Internal Server Error", + "code": 500, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "5f403d4f-fb62-4ee8-ac00-9ee41ad6c19e", + "name": "Represents an Error Caused by System Unavailability", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/transactions/:transactionReference", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "transactions", + ":transactionReference" + ], + "variable": [ + { + "key": "transactionReference" + } + ] + } + }, + "status": "Service Unavailable", + "code": 503, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + } + ] + }, + { + "name": "Create A Reversal", + "id": "05e67d0c-668d-4cc1-81c1-decdfaecea93", + "request": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"type\": \"\",\n \"amount\": \"\",\n \"currency\": \"\",\n \"subType\": \"\",\n \"descriptionText\": \"\",\n \"requestDate\": \"\",\n \"geoCode\": \"\",\n \"requestingOrganisationTransactionReference\": \"\",\n \"debitParty\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ],\n \"creditParty\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ],\n \"requestingLei\": \"\",\n \"receivingLei\": \"\",\n \"servicingIdentity\": \"\",\n \"fees\": [\n {\n \"feeType\": \"\",\n \"feeCurrency\": \"\",\n \"feeAmount\": \"\"\n },\n {\n \"feeType\": \"\",\n \"feeCurrency\": \"\",\n \"feeAmount\": \"\"\n }\n ],\n \"metadata\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + "url": { + "raw": "{{baseUrl}}/transactions/:transactionReference/reversals", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "transactions", + ":transactionReference", + "reversals" + ], + "variable": [ + { + "id": "87a621e8-28d2-4ef1-ba6a-0692a3285556", + "key": "transactionReference", + "value": "", + "description": "(Required) Path variable to uniquely identify the transaction." + } + ] + }, + "description": "Provided with a valid object representation, this endpoint allows for a new reversal to be created" + }, + "response": [ + { + "id": "9fc6ba5b-3e11-4e1b-b806-3ca902b7b91a", + "name": "Represents an Error Caused by an Authorisation Failure", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/transactions/:transactionReference/reversals", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "transactions", + ":transactionReference", + "reversals" + ], + "variable": [ + { + "key": "transactionReference" + } + ] + } + }, + "status": "Unauthorized", + "code": 401, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "7930c3c6-14f9-449b-a968-9921581d4fef", + "name": "Represents an Error Caused by System Unavailability", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/transactions/:transactionReference/reversals", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "transactions", + ":transactionReference", + "reversals" + ], + "variable": [ + { + "key": "transactionReference" + } + ] + } + }, + "status": "Service Unavailable", + "code": 503, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "96a1ec33-b8e5-417b-9e2d-b0f3cb6cb19b", + "name": "Represents an Error Caused by a Failure to Identify the Target Resource", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/transactions/:transactionReference/reversals", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "transactions", + ":transactionReference", + "reversals" + ], + "variable": [ + { + "key": "transactionReference" + } + ] + } + }, + "status": "Not Found", + "code": 404, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "71364a2a-8908-482c-ad9a-fb3f93e144a0", + "name": "Represents an Asynchronous response", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/transactions/:transactionReference/reversals", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "transactions", + ":transactionReference", + "reversals" + ], + "variable": [ + { + "key": "transactionReference" + } + ] + } + }, + "status": "Accepted", + "code": 202, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"notificationMethod\": \"\",\n \"serverCorrelationId\": \"\",\n \"status\": \"\",\n \"pendingReason\": \"\",\n \"objectReference\": \"\",\n \"expiryTime\": \"\",\n \"pollLimit\": \"\",\n \"error\": {\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n }\n}" + }, + { + "id": "bc0833a7-c9b9-45bd-8858-1b909b681270", + "name": "Represents a Transaction Reversal response", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/transactions/:transactionReference/reversals", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "transactions", + ":transactionReference", + "reversals" + ], + "variable": [ + { + "key": "transactionReference" + } + ] + } + }, + "status": "Created", + "code": 201, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"type\": \"reversal\",\n \"originalTransactionReference\": \"\",\n \"transactionReference\": \"\",\n \"transactionStatus\": \"\",\n \"amount\": \"15.21\",\n \"currency\": \"\",\n \"subType\": \"\",\n \"descriptionText\": \"\",\n \"requestDate\": \"\",\n \"geoCode\": \"37.423825,-122.082900\",\n \"requestingOrganisationTransactionReference\": \"\",\n \"debitParty\": [\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n },\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n }\n ],\n \"creditParty\": [\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n },\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n }\n ],\n \"requestingLei\": \"54930084UKLVMY22DS16\",\n \"receivingLei\": \"5493000IBP32UQZ0KL24\",\n \"servicingIdentity\": \"\",\n \"fees\": [\n {\n \"feeType\": \"\",\n \"feeCurrency\": \"\",\n \"feeAmount\": \"15.21\"\n },\n {\n \"feeType\": \"\",\n \"feeCurrency\": \"\",\n \"feeAmount\": \"15.21\"\n }\n ],\n \"metadata\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ],\n \"creationDate\": \"\",\n \"modificationDate\": \"\",\n \"dateCreated\": \"\",\n \"dateModified\": \"\",\n \"transactionReceipt\": \"\"\n}" + }, + { + "id": "c9862f3e-fac6-4994-80d3-aaef0d47d91c", + "name": "Represents an Error Caused by the Violation of a Business Rule", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/transactions/:transactionReference/reversals", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "transactions", + ":transactionReference", + "reversals" + ], + "variable": [ + { + "key": "transactionReference" + } + ] + } + }, + "status": "Bad Request", + "code": 400, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "354b6cca-1d3d-4b8c-b83b-739c5b2a3378", + "name": "Represents an Error Caused by a General Server-Side Issue", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/transactions/:transactionReference/reversals", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "transactions", + ":transactionReference", + "reversals" + ], + "variable": [ + { + "key": "transactionReference" + } + ] + } + }, + "status": "Internal Server Error", + "code": 500, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + } + ] + } + ], + "id": "25865a43-dfaa-44d5-925d-4658ba205585" + }, + { + "name": "Create a Transaction", + "id": "b4ddde92-33c5-4013-8708-8ab164eaa6a9", + "request": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"amount\": \"\",\n \"currency\": \"\",\n \"type\": \"\",\n \"debitParty\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ],\n \"creditParty\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ],\n \"subType\": \"\",\n \"descriptionText\": \"\",\n \"requestDate\": \"\",\n \"requestingOrganisationTransactionReference\": \"\",\n \"oneTimeCode\": \"\",\n \"geoCode\": \"\",\n \"senderKyc\": {\n \"nationality\": \"\",\n \"dateOfBirth\": \"\",\n \"occupation\": \"\",\n \"employerName\": \"\",\n \"contactPhone\": \"\",\n \"gender\": \"\",\n \"idDocument\": [\n {\n \"idType\": \"\",\n \"idNumber\": \"\",\n \"issueDate\": \"\",\n \"expiryDate\": \"\",\n \"issuer\": \"\",\n \"issuerPlace\": \"\",\n \"issuerCountry\": \"\",\n \"otherIddescription\": \"\"\n },\n {\n \"idType\": \"\",\n \"idNumber\": \"\",\n \"issueDate\": \"\",\n \"expiryDate\": \"\",\n \"issuer\": \"\",\n \"issuerPlace\": \"\",\n \"issuerCountry\": \"\",\n \"otherIddescription\": \"\"\n }\n ],\n \"postalAddress\": {\n \"country\": \"\",\n \"addressLine1\": \"\",\n \"addressLine2\": \"\",\n \"addressLine3\": \"\",\n \"city\": \"\",\n \"stateProvince\": \"\",\n \"postalCode\": \"\"\n },\n \"subjectName\": {\n \"title\": \"\",\n \"firstName\": \"\",\n \"middleName\": \"\",\n \"lastName\": \"\",\n \"fullName\": \"\",\n \"nativeName\": \"\"\n },\n \"emailAddress\": \"\",\n \"birthCountry\": \"\"\n },\n \"recipientKyc\": {\n \"nationality\": \"\",\n \"dateOfBirth\": \"\",\n \"occupation\": \"\",\n \"employerName\": \"\",\n \"contactPhone\": \"\",\n \"gender\": \"\",\n \"idDocument\": [\n {\n \"idType\": \"\",\n \"idNumber\": \"\",\n \"issueDate\": \"\",\n \"expiryDate\": \"\",\n \"issuer\": \"\",\n \"issuerPlace\": \"\",\n \"issuerCountry\": \"\",\n \"otherIddescription\": \"\"\n },\n {\n \"idType\": \"\",\n \"idNumber\": \"\",\n \"issueDate\": \"\",\n \"expiryDate\": \"\",\n \"issuer\": \"\",\n \"issuerPlace\": \"\",\n \"issuerCountry\": \"\",\n \"otherIddescription\": \"\"\n }\n ],\n \"postalAddress\": {\n \"country\": \"\",\n \"addressLine1\": \"\",\n \"addressLine2\": \"\",\n \"addressLine3\": \"\",\n \"city\": \"\",\n \"stateProvince\": \"\",\n \"postalCode\": \"\"\n },\n \"subjectName\": {\n \"title\": \"\",\n \"firstName\": \"\",\n \"middleName\": \"\",\n \"lastName\": \"\",\n \"fullName\": \"\",\n \"nativeName\": \"\"\n },\n \"emailAddress\": \"\",\n \"birthCountry\": \"\"\n },\n \"originalTransactionReference\": \"\",\n \"servicingIdentity\": \"\",\n \"fees\": [\n {\n \"feeType\": \"\",\n \"feeCurrency\": \"\",\n \"feeAmount\": \"\"\n },\n {\n \"feeType\": \"\",\n \"feeCurrency\": \"\",\n \"feeAmount\": \"\"\n }\n ],\n \"requestingLei\": \"\",\n \"receivingLei\": \"\",\n \"metadata\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ],\n \"internationalTransferInformation\": {\n \"originCountry\": \"\",\n \"quotationReference\": \"\",\n \"quoteId\": \"\",\n \"receivingCountry\": \"\",\n \"remittancePurpose\": \"\",\n \"relationshipSender\": \"\",\n \"deliveryMethod\": \"\"\n }\n}" + }, + "url": "{{baseUrl}}/transactions", + "description": "Provided with a valid object representation, this endpoint allows for a new transaction to be created" + }, + "response": [ + { + "id": "64036438-09d1-4ce5-8626-4ff166772202", + "name": "Represents an Asynchronous response", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": "{{baseUrl}}/transactions" + }, + "status": "Accepted", + "code": 202, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"notificationMethod\": \"\",\n \"serverCorrelationId\": \"\",\n \"status\": \"\",\n \"pendingReason\": \"\",\n \"objectReference\": \"\",\n \"expiryTime\": \"\",\n \"pollLimit\": \"\",\n \"error\": {\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n }\n}" + }, + { + "id": "0d354dea-c62e-433a-9d3b-f158ae2187be", + "name": "Represents an Error Caused by the Violation of a Business Rule", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": "{{baseUrl}}/transactions" + }, + "status": "Bad Request", + "code": 400, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "497d1e56-df26-43eb-bbcd-daf0a9b557f2", + "name": "Represents an Error Caused by System Unavailability", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": "{{baseUrl}}/transactions" + }, + "status": "Service Unavailable", + "code": 503, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "b065aceb-0934-4dc6-8c0f-f016ebfab9b9", + "name": "Represents an Error Caused by a General Server-Side Issue", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": "{{baseUrl}}/transactions" + }, + "status": "Internal Server Error", + "code": 500, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "4a92b484-b806-4173-954a-129105568747", + "name": "Represents an Error Caused by an Authorisation Failure", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": "{{baseUrl}}/transactions" + }, + "status": "Unauthorized", + "code": 401, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "c6fe582f-521b-4b34-b325-03e77c27e032", + "name": "Represents a Transaction response", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": "{{baseUrl}}/transactions" + }, + "status": "Created", + "code": 201, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"amount\": \"15.21\",\n \"currency\": \"\",\n \"type\": \"\",\n \"transactionReference\": \"\",\n \"transactionStatus\": \"\",\n \"debitParty\": [\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n },\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n }\n ],\n \"creditParty\": [\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n },\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n }\n ],\n \"subType\": \"\",\n \"descriptionText\": \"\",\n \"requestDate\": \"\",\n \"requestingOrganisationTransactionReference\": \"\",\n \"oneTimeCode\": \"\",\n \"geoCode\": \"37.423825,-122.082900\",\n \"senderKyc\": {\n \"nationality\": \"\",\n \"dateOfBirth\": \"2000-11-20\",\n \"occupation\": \"\",\n \"employerName\": \"\",\n \"contactPhone\": \"\",\n \"gender\": \"\",\n \"idDocument\": [\n {\n \"idType\": \"\",\n \"idNumber\": \"\",\n \"issueDate\": \"2018-11-20\",\n \"expiryDate\": \"2018-11-20\",\n \"issuer\": \"\",\n \"issuerPlace\": \"\",\n \"issuerCountry\": \"\",\n \"otherIddescription\": \"\"\n },\n {\n \"idType\": \"\",\n \"idNumber\": \"\",\n \"issueDate\": \"2018-11-20\",\n \"expiryDate\": \"2018-11-20\",\n \"issuer\": \"\",\n \"issuerPlace\": \"\",\n \"issuerCountry\": \"\",\n \"otherIddescription\": \"\"\n }\n ],\n \"postalAddress\": {\n \"country\": \"\",\n \"addressLine1\": \"\",\n \"addressLine2\": \"\",\n \"addressLine3\": \"\",\n \"city\": \"\",\n \"stateProvince\": \"\",\n \"postalCode\": \"\"\n },\n \"subjectName\": {\n \"title\": \"\",\n \"firstName\": \"\",\n \"middleName\": \"\",\n \"lastName\": \"\",\n \"fullName\": \"\",\n \"nativeName\": \"\"\n },\n \"emailAddress\": \"\",\n \"birthCountry\": \"\"\n },\n \"recipientKyc\": {\n \"nationality\": \"\",\n \"dateOfBirth\": \"2000-11-20\",\n \"occupation\": \"\",\n \"employerName\": \"\",\n \"contactPhone\": \"\",\n \"gender\": \"\",\n \"idDocument\": [\n {\n \"idType\": \"\",\n \"idNumber\": \"\",\n \"issueDate\": \"2018-11-20\",\n \"expiryDate\": \"2018-11-20\",\n \"issuer\": \"\",\n \"issuerPlace\": \"\",\n \"issuerCountry\": \"\",\n \"otherIddescription\": \"\"\n },\n {\n \"idType\": \"\",\n \"idNumber\": \"\",\n \"issueDate\": \"2018-11-20\",\n \"expiryDate\": \"2018-11-20\",\n \"issuer\": \"\",\n \"issuerPlace\": \"\",\n \"issuerCountry\": \"\",\n \"otherIddescription\": \"\"\n }\n ],\n \"postalAddress\": {\n \"country\": \"\",\n \"addressLine1\": \"\",\n \"addressLine2\": \"\",\n \"addressLine3\": \"\",\n \"city\": \"\",\n \"stateProvince\": \"\",\n \"postalCode\": \"\"\n },\n \"subjectName\": {\n \"title\": \"\",\n \"firstName\": \"\",\n \"middleName\": \"\",\n \"lastName\": \"\",\n \"fullName\": \"\",\n \"nativeName\": \"\"\n },\n \"emailAddress\": \"\",\n \"birthCountry\": \"\"\n },\n \"originalTransactionReference\": \"\",\n \"servicingIdentity\": \"\",\n \"fees\": [\n {\n \"feeType\": \"\",\n \"feeCurrency\": \"\",\n \"feeAmount\": \"15.21\"\n },\n {\n \"feeType\": \"\",\n \"feeCurrency\": \"\",\n \"feeAmount\": \"15.21\"\n }\n ],\n \"requestingLei\": \"54930084UKLVMY22DS16\",\n \"receivingLei\": \"5493000IBP32UQZ0KL24\",\n \"metadata\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ],\n \"creationDate\": \"\",\n \"modificationDate\": \"\",\n \"dateCreated\": \"\",\n \"dateModified\": \"\",\n \"transactionReceipt\": \"\",\n \"internationalTransferInformation\": {\n \"originCountry\": \"\",\n \"quotationReference\": \"\",\n \"quoteId\": \"\",\n \"receivingCountry\": \"\",\n \"remittancePurpose\": \"\",\n \"relationshipSender\": \"\",\n \"deliveryMethod\": \"\",\n \"senderBlockingReason\": \"\",\n \"recipientBlockingReason\": \"\"\n }\n}" + }, + { + "id": "e355e5d6-5687-4348-983d-f7bfd78aa234", + "name": "Represents an Error Caused by a Failure to Identify the Target Resource", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": "{{baseUrl}}/transactions" + }, + "status": "Not Found", + "code": 404, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + } + ] + }, + { + "name": "Create a Transaction", + "id": "9369c301-68bd-4c14-a84a-80cc7d072f4b", + "request": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "[\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n]" + }, + "url": { + "raw": "{{baseUrl}}/transactions/type/:transactionType", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "transactions", + "type", + ":transactionType" + ], + "variable": [ + { + "id": "99876d6f-6f02-44d3-b28f-98cade58f478", + "key": "transactionType", + "value": "", + "description": "(Required) Identifies the type of transaction that is to be created." + } + ] + }, + "description": "Provided with a valid object representation, this endpoint allows for a new transaction to be created for a given transaction type passed via the URL." + }, + "response": [ + { + "id": "812b315f-c905-44c7-96b2-6568147b81e7", + "name": "Represents an Error Caused by a Failure to Identify the Target Resource", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/transactions/type/:transactionType", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "transactions", + "type", + ":transactionType" + ], + "variable": [ + { + "key": "transactionType" + } + ] + } + }, + "status": "Not Found", + "code": 404, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "ccf83cbd-49c6-44e8-b658-d3a9ef5be182", + "name": "Represents an Error Caused by the Violation of a Business Rule", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/transactions/type/:transactionType", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "transactions", + "type", + ":transactionType" + ], + "variable": [ + { + "key": "transactionType" + } + ] + } + }, + "status": "Bad Request", + "code": 400, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "02079faa-292c-4752-a052-6d5b2fe7954a", + "name": "Represents an Error Caused by an Authorisation Failure", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/transactions/type/:transactionType", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "transactions", + "type", + ":transactionType" + ], + "variable": [ + { + "key": "transactionType" + } + ] + } + }, + "status": "Unauthorized", + "code": 401, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "d92ae219-56ee-46ac-9075-e5994062019a", + "name": "Represents a Transaction response", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/transactions/type/:transactionType", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "transactions", + "type", + ":transactionType" + ], + "variable": [ + { + "key": "transactionType" + } + ] + } + }, + "status": "Created", + "code": 201, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "[\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n },\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n }\n]" + }, + { + "id": "a08ef545-bd45-4698-bee4-e55934349911", + "name": "Represents an Error Caused by System Unavailability", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/transactions/type/:transactionType", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "transactions", + "type", + ":transactionType" + ], + "variable": [ + { + "key": "transactionType" + } + ] + } + }, + "status": "Service Unavailable", + "code": 503, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "8ad1bb0c-2658-4f0b-bf3b-e3536e65f1bf", + "name": "Represents an Error Caused by a General Server-Side Issue", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/transactions/type/:transactionType", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "transactions", + "type", + ":transactionType" + ], + "variable": [ + { + "key": "transactionType" + } + ] + } + }, + "status": "Internal Server Error", + "code": 500, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "15a87369-b38f-4293-8160-7dcee1be0c09", + "name": "Represents an Asynchronous response", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/transactions/type/:transactionType", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "transactions", + "type", + ":transactionType" + ], + "variable": [ + { + "key": "transactionType" + } + ] + } + }, + "status": "Accepted", + "code": 202, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"notificationMethod\": \"\",\n \"serverCorrelationId\": \"\",\n \"status\": \"\",\n \"pendingReason\": \"\",\n \"objectReference\": \"\",\n \"expiryTime\": \"\",\n \"pollLimit\": \"\",\n \"error\": {\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n }\n}" + } + ] + } + ], + "id": "1c8996e1-71b8-4abf-98ee-59ff40eb9528" + }, + { + "name": "batchtransactions", + "item": [ + { + "name": "{batch Id}", + "item": [ + { + "name": "View A Transaction Batch", + "id": "91ef8f15-d531-4590-a8b4-b3faeec2fe43", + "request": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/batchtransactions/:batchId", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "batchtransactions", + ":batchId" + ], + "variable": [ + { + "id": "1326db07-d76c-4956-8013-cf6bccd81619", + "key": "batchId", + "value": "", + "description": "(Required) Path variable to uniquely identify the transaction batch." + } + ] + }, + "description": "This endpoint returns the current status of a batch transaction" + }, + "response": [ + { + "id": "37f73eb0-c7f5-41f0-94b8-dfa6d95f5129", + "name": "Represents an Error Caused by the Violation of a Business Rule", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/batchtransactions/:batchId", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "batchtransactions", + ":batchId" + ], + "variable": [ + { + "key": "batchId" + } + ] + } + }, + "status": "Bad Request", + "code": 400, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "966aeb5e-e850-4712-a3e9-decbcdb2fb4c", + "name": "Represents a Batch Transaction response", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/batchtransactions/:batchId", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "batchtransactions", + ":batchId" + ], + "variable": [ + { + "key": "batchId" + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"approvalDate\": \"\",\n \"batchId\": \"\",\n \"batchStatus\": \"\",\n \"completionDate\": \"\",\n \"creationDate\": \"\",\n \"batchTitle\": \"\",\n \"batchdescription\": \"\",\n \"processingFlag\": \"\",\n \"scheduledStartDate\": \"\",\n \"completedDate\": \"\",\n \"rejectionCount\": \"\",\n \"parsingSuccessCount\": \"\",\n \"completedCount\": \"\"\n}" + }, + { + "id": "54636077-3b5d-445f-92c6-99181c5eecc7", + "name": "Represents an Error Caused by an Authorisation Failure", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/batchtransactions/:batchId", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "batchtransactions", + ":batchId" + ], + "variable": [ + { + "key": "batchId" + } + ] + } + }, + "status": "Unauthorized", + "code": 401, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "64898acd-f8f4-4771-af3a-bd61541909e1", + "name": "Represents an Error Caused by a Failure to Identify the Target Resource", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/batchtransactions/:batchId", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "batchtransactions", + ":batchId" + ], + "variable": [ + { + "key": "batchId" + } + ] + } + }, + "status": "Not Found", + "code": 404, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "32856cb8-2a4a-407c-87c7-55b3581e1949", + "name": "Represents an Error Caused by a General Server-Side Issue", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/batchtransactions/:batchId", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "batchtransactions", + ":batchId" + ], + "variable": [ + { + "key": "batchId" + } + ] + } + }, + "status": "Internal Server Error", + "code": 500, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "cea66015-b39e-4c80-afd7-2d755eef9599", + "name": "Represents an Error Caused by System Unavailability", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/batchtransactions/:batchId", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "batchtransactions", + ":batchId" + ], + "variable": [ + { + "key": "batchId" + } + ] + } + }, + "status": "Service Unavailable", + "code": 503, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + } + ] + }, + { + "name": "Update A Transaction Batch", + "id": "59cfe090-a677-452b-98a5-9f59552cba24", + "request": { + "method": "PATCH", + "header": [ + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "[\n {\n \"op\": \"\",\n \"path\": \"\",\n \"value\": \"\"\n },\n {\n \"op\": \"\",\n \"path\": \"\",\n \"value\": \"\"\n }\n]" + }, + "url": { + "raw": "{{baseUrl}}/batchtransactions/:batchId", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "batchtransactions", + ":batchId" + ], + "variable": [ + { + "id": "cab10dfd-b99a-4e63-acc2-7f31d22fb14a", + "key": "batchId", + "value": "", + "description": "(Required) Path variable to uniquely identify the transaction batch." + } + ] + }, + "description": "This endpoint updates a specific transaction batch" + }, + "response": [ + { + "id": "c6b55dda-76e6-46ac-90df-48907ab3b7f7", + "name": "Represents an Error Caused by a Failure to Identify the Target Resource", + "originalRequest": { + "method": "PATCH", + "header": [ + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/batchtransactions/:batchId", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "batchtransactions", + ":batchId" + ], + "variable": [ + { + "key": "batchId" + } + ] + } + }, + "status": "Not Found", + "code": 404, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "b300fbac-0f4b-444c-8e94-e99fba9ff83b", + "name": "Represents an Error Caused by System Unavailability", + "originalRequest": { + "method": "PATCH", + "header": [ + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/batchtransactions/:batchId", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "batchtransactions", + ":batchId" + ], + "variable": [ + { + "key": "batchId" + } + ] + } + }, + "status": "Service Unavailable", + "code": 503, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "9b43c14f-7cba-4c24-8bbe-4b77d850722a", + "name": "An empty response is returned for a synchronous successful patch.", + "originalRequest": { + "method": "PATCH", + "header": [ + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/batchtransactions/:batchId", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "batchtransactions", + ":batchId" + ], + "variable": [ + { + "key": "batchId" + } + ] + } + }, + "status": "No Content", + "code": 204, + "_postman_previewlanguage": "text", + "header": [ + { + "key": "Content-Type", + "value": "text/plain" + } + ], + "cookie": [], + "body": "" + }, + { + "id": "1ebe658d-cde8-402f-ad0e-4b00ec51527d", + "name": "Represents an Error Caused by a General Server-Side Issue", + "originalRequest": { + "method": "PATCH", + "header": [ + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/batchtransactions/:batchId", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "batchtransactions", + ":batchId" + ], + "variable": [ + { + "key": "batchId" + } + ] + } + }, + "status": "Internal Server Error", + "code": 500, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "310ee871-b4fe-4110-b1cb-1062e122a0fe", + "name": "Represents an Asynchronous response", + "originalRequest": { + "method": "PATCH", + "header": [ + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/batchtransactions/:batchId", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "batchtransactions", + ":batchId" + ], + "variable": [ + { + "key": "batchId" + } + ] + } + }, + "status": "Accepted", + "code": 202, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"notificationMethod\": \"\",\n \"serverCorrelationId\": \"\",\n \"status\": \"\",\n \"pendingReason\": \"\",\n \"objectReference\": \"\",\n \"expiryTime\": \"\",\n \"pollLimit\": \"\",\n \"error\": {\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n }\n}" + }, + { + "id": "8d0adf2c-2f29-438a-98f8-b59f8b69d35a", + "name": "Represents an Error Caused by the Violation of a Business Rule", + "originalRequest": { + "method": "PATCH", + "header": [ + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/batchtransactions/:batchId", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "batchtransactions", + ":batchId" + ], + "variable": [ + { + "key": "batchId" + } + ] + } + }, + "status": "Bad Request", + "code": 400, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "aefe1231-ac7c-4d52-8209-5cf4e1d4809e", + "name": "Represents an Error Caused by an Authorisation Failure", + "originalRequest": { + "method": "PATCH", + "header": [ + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/batchtransactions/:batchId", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "batchtransactions", + ":batchId" + ], + "variable": [ + { + "key": "batchId" + } + ] + } + }, + "status": "Unauthorized", + "code": 401, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + } + ] + }, + { + "name": "View Batch Rejections", + "id": "f5d52b99-752d-4e11-bbfa-a3e3425fcec3", + "request": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/batchtransactions/:batchId/rejections?limit=&offset=&fromDateTime=&toDateTime=", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "batchtransactions", + ":batchId", + "rejections" + ], + "query": [ + { + "key": "limit", + "value": "", + "description": "Supports pagination. If this is not supplied, then the server will apply a limit of 50 records returned for each request." + }, + { + "key": "offset", + "value": "", + "description": "Supports pagination. This value will indicate the cursor position from where to retrieve the set of records. For example, a limit of 50 and offset of 10 will return records 11 to 60." + }, + { + "key": "fromDateTime", + "value": "", + "description": "Indicates the minimum date for which records should be returned." + }, + { + "key": "toDateTime", + "value": "", + "description": "Indicates the maximum date for which records should be returned." + } + ], + "variable": [ + { + "id": "c8dfd13a-1ce7-4f69-b1cd-507ba335ff61", + "key": "batchId", + "value": "", + "description": "(Required) Path variable to uniquely identify the transaction batch." + } + ] + }, + "description": "This endpoint returns rejected transactions for a specific batch\"" + }, + "response": [ + { + "id": "7b756a08-4f2a-4df5-8976-b6223db0dd84", + "name": "Represents an Error Caused by a General Server-Side Issue", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/batchtransactions/:batchId/rejections?limit=&offset=&fromDateTime=&toDateTime=", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "batchtransactions", + ":batchId", + "rejections" + ], + "query": [ + { + "key": "limit", + "value": "" + }, + { + "key": "offset", + "value": "" + }, + { + "key": "fromDateTime", + "value": "" + }, + { + "key": "toDateTime", + "value": "" + } + ], + "variable": [ + { + "key": "batchId" + } + ] + } + }, + "status": "Internal Server Error", + "code": 500, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "2823e07e-f5fa-437f-b83c-809325a58114", + "name": "Represents an Error Caused by an Authorisation Failure", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/batchtransactions/:batchId/rejections?limit=&offset=&fromDateTime=&toDateTime=", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "batchtransactions", + ":batchId", + "rejections" + ], + "query": [ + { + "key": "limit", + "value": "" + }, + { + "key": "offset", + "value": "" + }, + { + "key": "fromDateTime", + "value": "" + }, + { + "key": "toDateTime", + "value": "" + } + ], + "variable": [ + { + "key": "batchId" + } + ] + } + }, + "status": "Unauthorized", + "code": 401, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "9c836556-27b9-4360-bd30-0b33a56817f5", + "name": "Represents an Error Caused by System Unavailability", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/batchtransactions/:batchId/rejections?limit=&offset=&fromDateTime=&toDateTime=", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "batchtransactions", + ":batchId", + "rejections" + ], + "query": [ + { + "key": "limit", + "value": "" + }, + { + "key": "offset", + "value": "" + }, + { + "key": "fromDateTime", + "value": "" + }, + { + "key": "toDateTime", + "value": "" + } + ], + "variable": [ + { + "key": "batchId" + } + ] + } + }, + "status": "Service Unavailable", + "code": 503, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "b84ecaa8-ca58-4f55-baaf-9e8ded126da9", + "name": "Represents a Batch Transaction Rejection response", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/batchtransactions/:batchId/rejections?limit=&offset=&fromDateTime=&toDateTime=", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "batchtransactions", + ":batchId", + "rejections" + ], + "query": [ + { + "key": "limit", + "value": "" + }, + { + "key": "offset", + "value": "" + }, + { + "key": "fromDateTime", + "value": "" + }, + { + "key": "toDateTime", + "value": "" + } + ], + "variable": [ + { + "key": "batchId" + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "X-Records-Available-Count", + "value": "", + "description": "Integer containing number of records that are available to be returned." + }, + { + "key": "X-Records-Returned-Count", + "value": "", + "description": "Integer containing number of records that are returned." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "[\n {\n \"creditParty\": [\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n },\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n }\n ],\n \"debitParty\": [\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n },\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n }\n ],\n \"rejectionDate\": \"\",\n \"rejectionReason\": \"\",\n \"transactionReference\": \"\",\n \"dateRejected\": \"\",\n \"requestingOrganisationTransactionReference\": \"\"\n },\n {\n \"creditParty\": [\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n },\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n }\n ],\n \"debitParty\": [\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n },\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n }\n ],\n \"rejectionDate\": \"\",\n \"rejectionReason\": \"\",\n \"transactionReference\": \"\",\n \"dateRejected\": \"\",\n \"requestingOrganisationTransactionReference\": \"\"\n }\n]" + }, + { + "id": "f927b0dc-f0b5-42e8-a0bc-0c8069829ad3", + "name": "Represents an Error Caused by a Failure to Identify the Target Resource", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/batchtransactions/:batchId/rejections?limit=&offset=&fromDateTime=&toDateTime=", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "batchtransactions", + ":batchId", + "rejections" + ], + "query": [ + { + "key": "limit", + "value": "" + }, + { + "key": "offset", + "value": "" + }, + { + "key": "fromDateTime", + "value": "" + }, + { + "key": "toDateTime", + "value": "" + } + ], + "variable": [ + { + "key": "batchId" + } + ] + } + }, + "status": "Not Found", + "code": 404, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "a595fd79-f39b-4f72-ace2-0759ee673fc7", + "name": "Represents an Error Caused by the Violation of a Business Rule", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/batchtransactions/:batchId/rejections?limit=&offset=&fromDateTime=&toDateTime=", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "batchtransactions", + ":batchId", + "rejections" + ], + "query": [ + { + "key": "limit", + "value": "" + }, + { + "key": "offset", + "value": "" + }, + { + "key": "fromDateTime", + "value": "" + }, + { + "key": "toDateTime", + "value": "" + } + ], + "variable": [ + { + "key": "batchId" + } + ] + } + }, + "status": "Bad Request", + "code": 400, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + } + ] + }, + { + "name": "View Batch Completions", + "id": "d2589c72-36f1-4696-b38c-e67e7fad2b1f", + "request": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/batchtransactions/:batchId/completions?limit=&offset=&fromDateTime=&toDateTime=", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "batchtransactions", + ":batchId", + "completions" + ], + "query": [ + { + "key": "limit", + "value": "", + "description": "Supports pagination. If this is not supplied, then the server will apply a limit of 50 records returned for each request." + }, + { + "key": "offset", + "value": "", + "description": "Supports pagination. This value will indicate the cursor position from where to retrieve the set of records. For example, a limit of 50 and offset of 10 will return records 11 to 60." + }, + { + "key": "fromDateTime", + "value": "", + "description": "Indicates the minimum date for which records should be returned." + }, + { + "key": "toDateTime", + "value": "", + "description": "Indicates the maximum date for which records should be returned." + } + ], + "variable": [ + { + "id": "ee414283-3d15-43b9-aa81-b568db1f710e", + "key": "batchId", + "value": "", + "description": "(Required) Path variable to uniquely identify the transaction batch." + } + ] + }, + "description": "This endpoint returns completed transactions for a specific batch" + }, + "response": [ + { + "id": "cd56e4ee-158e-4e2d-be44-5eab85b18625", + "name": "Represents an Error Caused by an Authorisation Failure", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/batchtransactions/:batchId/completions?limit=&offset=&fromDateTime=&toDateTime=", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "batchtransactions", + ":batchId", + "completions" + ], + "query": [ + { + "key": "limit", + "value": "" + }, + { + "key": "offset", + "value": "" + }, + { + "key": "fromDateTime", + "value": "" + }, + { + "key": "toDateTime", + "value": "" + } + ], + "variable": [ + { + "key": "batchId" + } + ] + } + }, + "status": "Unauthorized", + "code": 401, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "cd8d8a22-9f2d-4f49-837b-092be38687c1", + "name": "Represents an Error Caused by the Violation of a Business Rule", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/batchtransactions/:batchId/completions?limit=&offset=&fromDateTime=&toDateTime=", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "batchtransactions", + ":batchId", + "completions" + ], + "query": [ + { + "key": "limit", + "value": "" + }, + { + "key": "offset", + "value": "" + }, + { + "key": "fromDateTime", + "value": "" + }, + { + "key": "toDateTime", + "value": "" + } + ], + "variable": [ + { + "key": "batchId" + } + ] + } + }, + "status": "Bad Request", + "code": 400, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "37df0162-b0a4-4159-8dac-2f1630365f22", + "name": "Represents an Error Caused by a Failure to Identify the Target Resource", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/batchtransactions/:batchId/completions?limit=&offset=&fromDateTime=&toDateTime=", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "batchtransactions", + ":batchId", + "completions" + ], + "query": [ + { + "key": "limit", + "value": "" + }, + { + "key": "offset", + "value": "" + }, + { + "key": "fromDateTime", + "value": "" + }, + { + "key": "toDateTime", + "value": "" + } + ], + "variable": [ + { + "key": "batchId" + } + ] + } + }, + "status": "Not Found", + "code": 404, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "a2b13d42-5b95-457f-9e2b-654dd4ca6eac", + "name": "Represent a list of Batch Completions", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/batchtransactions/:batchId/completions?limit=&offset=&fromDateTime=&toDateTime=", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "batchtransactions", + ":batchId", + "completions" + ], + "query": [ + { + "key": "limit", + "value": "" + }, + { + "key": "offset", + "value": "" + }, + { + "key": "fromDateTime", + "value": "" + }, + { + "key": "toDateTime", + "value": "" + } + ], + "variable": [ + { + "key": "batchId" + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "X-Records-Available-Count", + "value": "", + "description": "Integer containing number of records that are available to be returned." + }, + { + "key": "X-Records-Returned-Count", + "value": "", + "description": "Integer containing number of records that are returned." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "[\n {\n \"completionDate\": \"\",\n \"creditParty\": [\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n },\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n }\n ],\n \"debitParty\": [\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n },\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n }\n ],\n \"link\": \"\",\n \"transactionReference\": \"\",\n \"completedDate\": \"\",\n \"requestingOrganisationTransactionReference\": \"\"\n },\n {\n \"completionDate\": \"\",\n \"creditParty\": [\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n },\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n }\n ],\n \"debitParty\": [\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n },\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n }\n ],\n \"link\": \"\",\n \"transactionReference\": \"\",\n \"completedDate\": \"\",\n \"requestingOrganisationTransactionReference\": \"\"\n }\n]" + }, + { + "id": "73445b5f-8a76-403e-a93f-c248f449c938", + "name": "Represents an Error Caused by System Unavailability", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/batchtransactions/:batchId/completions?limit=&offset=&fromDateTime=&toDateTime=", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "batchtransactions", + ":batchId", + "completions" + ], + "query": [ + { + "key": "limit", + "value": "" + }, + { + "key": "offset", + "value": "" + }, + { + "key": "fromDateTime", + "value": "" + }, + { + "key": "toDateTime", + "value": "" + } + ], + "variable": [ + { + "key": "batchId" + } + ] + } + }, + "status": "Service Unavailable", + "code": 503, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "d702b4df-b443-4442-b672-6c368fb1aa3a", + "name": "Represents an Error Caused by a General Server-Side Issue", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/batchtransactions/:batchId/completions?limit=&offset=&fromDateTime=&toDateTime=", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "batchtransactions", + ":batchId", + "completions" + ], + "query": [ + { + "key": "limit", + "value": "" + }, + { + "key": "offset", + "value": "" + }, + { + "key": "fromDateTime", + "value": "" + }, + { + "key": "toDateTime", + "value": "" + } + ], + "variable": [ + { + "key": "batchId" + } + ] + } + }, + "status": "Internal Server Error", + "code": 500, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + } + ] + } + ], + "id": "4ea5291d-b1d5-4516-9b6f-2089b0b97550" + }, + { + "name": "Create A Transaction Batch", + "id": "9be67f4b-ecbe-4609-82e4-e924ad45833e", + "request": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"transactions\": [\n {\n \"amount\": \"\",\n \"currency\": \"\",\n \"type\": \"\",\n \"debitParty\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ],\n \"creditParty\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ],\n \"subType\": \"\",\n \"descriptionText\": \"\",\n \"requestDate\": \"\",\n \"requestingOrganisationTransactionReference\": \"\",\n \"oneTimeCode\": \"\",\n \"geoCode\": \"\",\n \"senderKyc\": {\n \"nationality\": \"\",\n \"dateOfBirth\": \"\",\n \"occupation\": \"\",\n \"employerName\": \"\",\n \"contactPhone\": \"\",\n \"gender\": \"\",\n \"idDocument\": [\n {\n \"idType\": \"\",\n \"idNumber\": \"\",\n \"issueDate\": \"\",\n \"expiryDate\": \"\",\n \"issuer\": \"\",\n \"issuerPlace\": \"\",\n \"issuerCountry\": \"\",\n \"otherIddescription\": \"\"\n },\n {\n \"idType\": \"\",\n \"idNumber\": \"\",\n \"issueDate\": \"\",\n \"expiryDate\": \"\",\n \"issuer\": \"\",\n \"issuerPlace\": \"\",\n \"issuerCountry\": \"\",\n \"otherIddescription\": \"\"\n }\n ],\n \"postalAddress\": {\n \"country\": \"\",\n \"addressLine1\": \"\",\n \"addressLine2\": \"\",\n \"addressLine3\": \"\",\n \"city\": \"\",\n \"stateProvince\": \"\",\n \"postalCode\": \"\"\n },\n \"subjectName\": {\n \"title\": \"\",\n \"firstName\": \"\",\n \"middleName\": \"\",\n \"lastName\": \"\",\n \"fullName\": \"\",\n \"nativeName\": \"\"\n },\n \"emailAddress\": \"\",\n \"birthCountry\": \"\"\n },\n \"recipientKyc\": {\n \"nationality\": \"\",\n \"dateOfBirth\": \"\",\n \"occupation\": \"\",\n \"employerName\": \"\",\n \"contactPhone\": \"\",\n \"gender\": \"\",\n \"idDocument\": [\n {\n \"idType\": \"\",\n \"idNumber\": \"\",\n \"issueDate\": \"\",\n \"expiryDate\": \"\",\n \"issuer\": \"\",\n \"issuerPlace\": \"\",\n \"issuerCountry\": \"\",\n \"otherIddescription\": \"\"\n },\n {\n \"idType\": \"\",\n \"idNumber\": \"\",\n \"issueDate\": \"\",\n \"expiryDate\": \"\",\n \"issuer\": \"\",\n \"issuerPlace\": \"\",\n \"issuerCountry\": \"\",\n \"otherIddescription\": \"\"\n }\n ],\n \"postalAddress\": {\n \"country\": \"\",\n \"addressLine1\": \"\",\n \"addressLine2\": \"\",\n \"addressLine3\": \"\",\n \"city\": \"\",\n \"stateProvince\": \"\",\n \"postalCode\": \"\"\n },\n \"subjectName\": {\n \"title\": \"\",\n \"firstName\": \"\",\n \"middleName\": \"\",\n \"lastName\": \"\",\n \"fullName\": \"\",\n \"nativeName\": \"\"\n },\n \"emailAddress\": \"\",\n \"birthCountry\": \"\"\n },\n \"originalTransactionReference\": \"\",\n \"servicingIdentity\": \"\",\n \"fees\": [\n {\n \"feeType\": \"\",\n \"feeCurrency\": \"\",\n \"feeAmount\": \"\"\n },\n {\n \"feeType\": \"\",\n \"feeCurrency\": \"\",\n \"feeAmount\": \"\"\n }\n ],\n \"requestingLei\": \"\",\n \"receivingLei\": \"\",\n \"metadata\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ],\n \"internationalTransferInformation\": {\n \"originCountry\": \"\",\n \"quotationReference\": \"\",\n \"quoteId\": \"\",\n \"receivingCountry\": \"\",\n \"remittancePurpose\": \"\",\n \"relationshipSender\": \"\",\n \"deliveryMethod\": \"\"\n }\n },\n {\n \"amount\": \"\",\n \"currency\": \"\",\n \"type\": \"\",\n \"debitParty\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ],\n \"creditParty\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ],\n \"subType\": \"\",\n \"descriptionText\": \"\",\n \"requestDate\": \"\",\n \"requestingOrganisationTransactionReference\": \"\",\n \"oneTimeCode\": \"\",\n \"geoCode\": \"\",\n \"senderKyc\": {\n \"nationality\": \"\",\n \"dateOfBirth\": \"\",\n \"occupation\": \"\",\n \"employerName\": \"\",\n \"contactPhone\": \"\",\n \"gender\": \"\",\n \"idDocument\": [\n {\n \"idType\": \"\",\n \"idNumber\": \"\",\n \"issueDate\": \"\",\n \"expiryDate\": \"\",\n \"issuer\": \"\",\n \"issuerPlace\": \"\",\n \"issuerCountry\": \"\",\n \"otherIddescription\": \"\"\n },\n {\n \"idType\": \"\",\n \"idNumber\": \"\",\n \"issueDate\": \"\",\n \"expiryDate\": \"\",\n \"issuer\": \"\",\n \"issuerPlace\": \"\",\n \"issuerCountry\": \"\",\n \"otherIddescription\": \"\"\n }\n ],\n \"postalAddress\": {\n \"country\": \"\",\n \"addressLine1\": \"\",\n \"addressLine2\": \"\",\n \"addressLine3\": \"\",\n \"city\": \"\",\n \"stateProvince\": \"\",\n \"postalCode\": \"\"\n },\n \"subjectName\": {\n \"title\": \"\",\n \"firstName\": \"\",\n \"middleName\": \"\",\n \"lastName\": \"\",\n \"fullName\": \"\",\n \"nativeName\": \"\"\n },\n \"emailAddress\": \"\",\n \"birthCountry\": \"\"\n },\n \"recipientKyc\": {\n \"nationality\": \"\",\n \"dateOfBirth\": \"\",\n \"occupation\": \"\",\n \"employerName\": \"\",\n \"contactPhone\": \"\",\n \"gender\": \"\",\n \"idDocument\": [\n {\n \"idType\": \"\",\n \"idNumber\": \"\",\n \"issueDate\": \"\",\n \"expiryDate\": \"\",\n \"issuer\": \"\",\n \"issuerPlace\": \"\",\n \"issuerCountry\": \"\",\n \"otherIddescription\": \"\"\n },\n {\n \"idType\": \"\",\n \"idNumber\": \"\",\n \"issueDate\": \"\",\n \"expiryDate\": \"\",\n \"issuer\": \"\",\n \"issuerPlace\": \"\",\n \"issuerCountry\": \"\",\n \"otherIddescription\": \"\"\n }\n ],\n \"postalAddress\": {\n \"country\": \"\",\n \"addressLine1\": \"\",\n \"addressLine2\": \"\",\n \"addressLine3\": \"\",\n \"city\": \"\",\n \"stateProvince\": \"\",\n \"postalCode\": \"\"\n },\n \"subjectName\": {\n \"title\": \"\",\n \"firstName\": \"\",\n \"middleName\": \"\",\n \"lastName\": \"\",\n \"fullName\": \"\",\n \"nativeName\": \"\"\n },\n \"emailAddress\": \"\",\n \"birthCountry\": \"\"\n },\n \"originalTransactionReference\": \"\",\n \"servicingIdentity\": \"\",\n \"fees\": [\n {\n \"feeType\": \"\",\n \"feeCurrency\": \"\",\n \"feeAmount\": \"\"\n },\n {\n \"feeType\": \"\",\n \"feeCurrency\": \"\",\n \"feeAmount\": \"\"\n }\n ],\n \"requestingLei\": \"\",\n \"receivingLei\": \"\",\n \"metadata\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ],\n \"internationalTransferInformation\": {\n \"originCountry\": \"\",\n \"quotationReference\": \"\",\n \"quoteId\": \"\",\n \"receivingCountry\": \"\",\n \"remittancePurpose\": \"\",\n \"relationshipSender\": \"\",\n \"deliveryMethod\": \"\"\n }\n }\n ],\n \"batchTitle\": \"\",\n \"batchdescription\": \"\",\n \"scheduledStartDate\": \"\",\n \"batchStatus\": \"\"\n}" + }, + "url": "{{baseUrl}}/batchtransactions", + "description": "Provided with a valid object representation, this endpoint allows for a new transaction batch to be created" + }, + "response": [ + { + "id": "574977f6-e8f9-4a78-abeb-49bb7634936d", + "name": "Represents an Error Caused by a General Server-Side Issue", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": "{{baseUrl}}/batchtransactions" + }, + "status": "Internal Server Error", + "code": 500, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "da5eb1a9-ea19-405b-84ad-3547139a8c7f", + "name": "Represents an Error Caused by the Violation of a Business Rule", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": "{{baseUrl}}/batchtransactions" + }, + "status": "Bad Request", + "code": 400, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "d1fc979b-9c52-4e1f-904e-8914577064e8", + "name": "Represents an Error Caused by a Failure to Identify the Target Resource", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": "{{baseUrl}}/batchtransactions" + }, + "status": "Not Found", + "code": 404, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "cade094e-d403-4127-9471-ccc90c77a1eb", + "name": "Represents an Error Caused by an Authorisation Failure", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": "{{baseUrl}}/batchtransactions" + }, + "status": "Unauthorized", + "code": 401, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "5f85b625-1d0c-4bd2-afaa-7809d11a8536", + "name": "Represents an Error Caused by System Unavailability", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": "{{baseUrl}}/batchtransactions" + }, + "status": "Service Unavailable", + "code": 503, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "b6e5f472-e190-41e9-be1e-0e45134e2cea", + "name": "Represents an Asynchronous response", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": "{{baseUrl}}/batchtransactions" + }, + "status": "Accepted", + "code": 202, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"notificationMethod\": \"\",\n \"serverCorrelationId\": \"\",\n \"status\": \"\",\n \"pendingReason\": \"\",\n \"objectReference\": \"\",\n \"expiryTime\": \"\",\n \"pollLimit\": \"\",\n \"error\": {\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n }\n}" + } + ] + } + ], + "id": "27fbafbf-0d7c-4ffd-afe6-c076c2cdb75c" + }, + { + "name": "accounts", + "item": [ + { + "name": "{account Id}", + "item": [ + { + "name": "bills", + "item": [ + { + "name": "View Account Bills", + "id": "f6ccde57-b640-4d71-8c7e-275d58d4070c", + "request": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/bills", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "bills" + ], + "variable": [ + { + "id": "3c548146-f8ec-40e8-b468-d9caf596177e", + "key": "accountId", + "value": "", + "description": "(Required) Path variable to uniquely identify an account. Up to three account identifiers can be supplied. Identifiers are delimited by $ and values are delimited by @. Example: organisationid@1234$accountid@3333. Valid account identifiers are accountcategory, bankaccountno, accountrank, identityalias, iban, accountid, msisdn, swiftbic, sortcode, organisationid, username, walletid, linkref, consumerno, serviceprovider, storeid, bankname, bankaccounttitle, emailaddress, mandatereference." + } + ] + }, + "description": "This endpoint returns bills linked to an account" + }, + "response": [ + { + "id": "f23b39b1-1653-4155-afe1-8c79a1adf72b", + "name": "Represent a list of Bills", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/bills", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "bills" + ], + "variable": [ + { + "key": "accountId" + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "[\n {\n \"currency\": \"\",\n \"amountDue\": \"15.21\",\n \"dueDate\": \"2018-11-20\",\n \"billReference\": \"\",\n \"minimumAmountDue\": \"15.21\",\n \"billdescription\": \"\",\n \"billStatus\": \"\",\n \"metadata\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n },\n {\n \"currency\": \"\",\n \"amountDue\": \"15.21\",\n \"dueDate\": \"2018-11-20\",\n \"billReference\": \"\",\n \"minimumAmountDue\": \"15.21\",\n \"billdescription\": \"\",\n \"billStatus\": \"\",\n \"metadata\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n }\n]" + }, + { + "id": "faa84c0d-9671-4346-a598-5feed3501007", + "name": "Represents an Error Caused by System Unavailability", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/bills", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "bills" + ], + "variable": [ + { + "key": "accountId" + } + ] + } + }, + "status": "Service Unavailable", + "code": 503, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "278612bb-adc5-4641-83ae-44e262ece9e7", + "name": "Represents an Error Caused by the Violation of a Business Rule", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/bills", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "bills" + ], + "variable": [ + { + "key": "accountId" + } + ] + } + }, + "status": "Bad Request", + "code": 400, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "a00bb8c0-16e5-4535-8079-325499d6cb48", + "name": "Represents an Error Caused by a General Server-Side Issue", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/bills", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "bills" + ], + "variable": [ + { + "key": "accountId" + } + ] + } + }, + "status": "Internal Server Error", + "code": 500, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "d0f547e9-77db-410d-85d8-8a44be4bb652", + "name": "Represents an Error Caused by an Authorisation Failure", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/bills", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "bills" + ], + "variable": [ + { + "key": "accountId" + } + ] + } + }, + "status": "Unauthorized", + "code": 401, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "84b166ed-b9e3-4d76-8e3a-ea3e0175af11", + "name": "Represents an Error Caused by a Failure to Identify the Target Resource", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/bills", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "bills" + ], + "variable": [ + { + "key": "accountId" + } + ] + } + }, + "status": "Not Found", + "code": 404, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + } + ] + }, + { + "name": "Create A Bill Payment", + "id": "c9ac4ba8-dbbb-4200-b47f-fd590ee2d6b9", + "request": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"currency\": \"\",\n \"amountPaid\": \"\",\n \"paidAmount\": \"\",\n \"serviceProviderPaymentReference\": \"\",\n \"requestingOrganisation\": \"\",\n \"requestingOrganisationTransactionReference\": \"\",\n \"customerReference\": \"\",\n \"paymentType\": \"\",\n \"supplementaryBillReferenceDetails\": [\n {\n \"paymentReferenceType\": \"\",\n \"paymentReferenceValue\": \"\"\n },\n {\n \"paymentReferenceType\": \"\",\n \"paymentReferenceValue\": \"\"\n }\n ],\n \"metadata\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/bills/:billReference/payments", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "bills", + ":billReference", + "payments" + ], + "variable": [ + { + "id": "dc0da533-dd28-4135-ac12-691f6bd91a74", + "key": "accountId", + "value": "", + "description": "(Required) Path variable to uniquely identify an account. Up to three account identifiers can be supplied. Identifiers are delimited by $ and values are delimited by @. Example: organisationid@1234$accountid@3333. Valid account identifiers are accountcategory, bankaccountno, accountrank, identityalias, iban, accountid, msisdn, swiftbic, sortcode, organisationid, username, walletid, linkref, consumerno, serviceprovider, storeid, bankname, bankaccounttitle, emailaddress, mandatereference." + }, + { + "id": "0c7cef25-797a-4f01-9913-cb5b48682595", + "key": "billReference", + "value": "", + "description": "(Required) Path variable to uniquely identify a bill." + } + ] + }, + "description": "Provided with a valid object representation, this endpoint allows for a new bill payment to be created for a specific account\"" + }, + "response": [ + { + "id": "2eff9efa-ac41-420b-b553-cc6946c69a49", + "name": "Represents an Error Caused by System Unavailability", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/bills/:billReference/payments", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "bills", + ":billReference", + "payments" + ], + "variable": [ + { + "key": "accountId" + }, + { + "key": "billReference" + } + ] + } + }, + "status": "Service Unavailable", + "code": 503, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "aaaa61ad-8fd5-43ae-a5e2-0b46296bea77", + "name": "Represents an Error Caused by a Failure to Identify the Target Resource", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/bills/:billReference/payments", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "bills", + ":billReference", + "payments" + ], + "variable": [ + { + "key": "accountId" + }, + { + "key": "billReference" + } + ] + } + }, + "status": "Not Found", + "code": 404, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "36b434f4-9762-4faf-abf6-6c10115d468d", + "name": "Represents an Error Caused by a General Server-Side Issue", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/bills/:billReference/payments", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "bills", + ":billReference", + "payments" + ], + "variable": [ + { + "key": "accountId" + }, + { + "key": "billReference" + } + ] + } + }, + "status": "Internal Server Error", + "code": 500, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "11e85295-0ca5-46a6-98c4-9c8232c6501f", + "name": "Represents an Error Caused by an Authorisation Failure", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/bills/:billReference/payments", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "bills", + ":billReference", + "payments" + ], + "variable": [ + { + "key": "accountId" + }, + { + "key": "billReference" + } + ] + } + }, + "status": "Unauthorized", + "code": 401, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "dff55ea1-084a-4347-84de-2ba330268986", + "name": "Represents an Error Caused by the Violation of a Business Rule", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/bills/:billReference/payments", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "bills", + ":billReference", + "payments" + ], + "variable": [ + { + "key": "accountId" + }, + { + "key": "billReference" + } + ] + } + }, + "status": "Bad Request", + "code": 400, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "517b2dc9-d549-4bea-b53e-56df9528e19a", + "name": "Represents a Bill Payment response", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/bills/:billReference/payments", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "bills", + ":billReference", + "payments" + ], + "variable": [ + { + "key": "accountId" + }, + { + "key": "billReference" + } + ] + } + }, + "status": "Created", + "code": 201, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"currency\": \"\",\n \"amountPaid\": \"15.21\",\n \"billPaymentStatus\": \"\",\n \"paidAmount\": \"15.21\",\n \"serviceProviderPaymentReference\": \"\",\n \"requestingOrganisation\": \"\",\n \"requestingOrganisationTransactionReference\": \"\",\n \"customerReference\": \"\",\n \"paymentType\": \"\",\n \"serviceProviderComment\": \"\",\n \"serviceProviderNotification\": \"\",\n \"supplementaryBillReferenceDetails\": [\n {\n \"paymentReferenceType\": \"\",\n \"paymentReferenceValue\": \"\"\n },\n {\n \"paymentReferenceType\": \"\",\n \"paymentReferenceValue\": \"\"\n }\n ],\n \"metadata\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "70a62da6-889e-4fac-9929-ac641b2c318d", + "name": "Represents an Asynchronous response", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/bills/:billReference/payments", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "bills", + ":billReference", + "payments" + ], + "variable": [ + { + "key": "accountId" + }, + { + "key": "billReference" + } + ] + } + }, + "status": "Accepted", + "code": 202, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"notificationMethod\": \"\",\n \"serverCorrelationId\": \"\",\n \"status\": \"\",\n \"pendingReason\": \"\",\n \"objectReference\": \"\",\n \"expiryTime\": \"\",\n \"pollLimit\": \"\",\n \"error\": {\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n }\n}" + } + ] + } + ], + "id": "45cba0ef-cceb-494c-ac98-bce45f03a4b7" + }, + { + "name": "debitmandates", + "item": [ + { + "name": "{debit Mandate Reference}", + "item": [ + { + "name": "View A Debit Mandate", + "id": "fa0b9dbe-27ba-484b-92ca-8600eff411ac", + "request": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/debitmandates/:debitMandateReference", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "debitmandates", + ":debitMandateReference" + ], + "variable": [ + { + "id": "5eb38aa1-5c4c-4d17-a0fd-501c56d267e2", + "key": "accountId", + "value": "", + "description": "(Required) Path variable to uniquely identify an account. Up to three account identifiers can be supplied. Identifiers are delimited by $ and values are delimited by @. Example: organisationid@1234$accountid@3333. Valid account identifiers are accountcategory, bankaccountno, accountrank, identityalias, iban, accountid, msisdn, swiftbic, sortcode, organisationid, username, walletid, linkref, consumerno, serviceprovider, storeid, bankname, bankaccounttitle, emailaddress, mandatereference." + }, + { + "id": "491ac50f-c31b-4c16-b7ba-16ccaa622adb", + "key": "debitMandateReference", + "value": "", + "description": "(Required) Path variable to uniquely identify a Debit Mandate Reference." + } + ] + }, + "description": "This endpoint returns a specific debit mandate linked to an account" + }, + "response": [ + { + "id": "9b2dee4d-5344-4245-8cf6-e72667e073b9", + "name": "Represents an Error Caused by System Unavailability", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/debitmandates/:debitMandateReference", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "debitmandates", + ":debitMandateReference" + ], + "variable": [ + { + "key": "accountId" + }, + { + "key": "debitMandateReference" + } + ] + } + }, + "status": "Service Unavailable", + "code": 503, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "5369649d-861c-4c11-ba38-eb6ae3607232", + "name": "Represents a Debit Mandate response", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/debitmandates/:debitMandateReference", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "debitmandates", + ":debitMandateReference" + ], + "variable": [ + { + "key": "accountId" + }, + { + "key": "debitMandateReference" + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"mandateReference\": \"\",\n \"currency\": \"\",\n \"amountLimit\": \"15.21\",\n \"startDate\": \"2018-11-20\",\n \"endDate\": \"2018-11-20\",\n \"numberOfPayments\": \"\",\n \"frequencyType\": \"\",\n \"mandateStatus\": \"\",\n \"requestDate\": \"\",\n \"creationDate\": \"\",\n \"modificationDate\": \"\",\n \"dateCreated\": \"\",\n \"dateModified\": \"\"\n}" + }, + { + "id": "f26eb10e-b9a3-47bf-ba9c-99d526d6693a", + "name": "Represents an Error Caused by the Violation of a Business Rule", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/debitmandates/:debitMandateReference", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "debitmandates", + ":debitMandateReference" + ], + "variable": [ + { + "key": "accountId" + }, + { + "key": "debitMandateReference" + } + ] + } + }, + "status": "Bad Request", + "code": 400, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "d79d3ec0-1582-4223-968f-308a5b0c9510", + "name": "Represents an Error Caused by an Authorisation Failure", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/debitmandates/:debitMandateReference", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "debitmandates", + ":debitMandateReference" + ], + "variable": [ + { + "key": "accountId" + }, + { + "key": "debitMandateReference" + } + ] + } + }, + "status": "Unauthorized", + "code": 401, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "136d32e9-c16c-4a6d-9325-30ea08876eee", + "name": "Represents an Error Caused by a General Server-Side Issue", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/debitmandates/:debitMandateReference", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "debitmandates", + ":debitMandateReference" + ], + "variable": [ + { + "key": "accountId" + }, + { + "key": "debitMandateReference" + } + ] + } + }, + "status": "Internal Server Error", + "code": 500, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "53221b54-6cea-4df7-8dd2-03304b64dee9", + "name": "Represents an Error Caused by a Failure to Identify the Target Resource", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/debitmandates/:debitMandateReference", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "debitmandates", + ":debitMandateReference" + ], + "variable": [ + { + "key": "accountId" + }, + { + "key": "debitMandateReference" + } + ] + } + }, + "status": "Not Found", + "code": 404, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + } + ] + }, + { + "name": "Update A Debit Mandate", + "id": "fddff5c0-8fcf-4781-9328-bd159f2b5896", + "request": { + "method": "PATCH", + "header": [ + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "[\n {\n \"op\": \"\",\n \"path\": \"\",\n \"value\": \"\"\n },\n {\n \"op\": \"\",\n \"path\": \"\",\n \"value\": \"\"\n }\n]" + }, + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/debitmandates/:debitMandateReference", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "debitmandates", + ":debitMandateReference" + ], + "variable": [ + { + "id": "e51959b6-2298-47ec-a965-5462d32ea61c", + "key": "accountId", + "value": "", + "description": "(Required) Path variable to uniquely identify an account. Up to three account identifiers can be supplied. Identifiers are delimited by $ and values are delimited by @. Example: organisationid@1234$accountid@3333. Valid account identifiers are accountcategory, bankaccountno, accountrank, identityalias, iban, accountid, msisdn, swiftbic, sortcode, organisationid, username, walletid, linkref, consumerno, serviceprovider, storeid, bankname, bankaccounttitle, emailaddress, mandatereference." + }, + { + "id": "689ab42a-4fba-440f-be57-d9d3089e6e69", + "key": "debitMandateReference", + "value": "", + "description": "(Required) Path variable to uniquely identify a Debit Mandate Reference." + } + ] + }, + "description": "This endpoint updates a specific debit mandate linked to an account" + }, + "response": [ + { + "id": "3309f7be-1236-4270-93df-6c77a908b1d2", + "name": "Represents an Error Caused by a General Server-Side Issue", + "originalRequest": { + "method": "PATCH", + "header": [ + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/debitmandates/:debitMandateReference", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "debitmandates", + ":debitMandateReference" + ], + "variable": [ + { + "key": "accountId" + }, + { + "key": "debitMandateReference" + } + ] + } + }, + "status": "Internal Server Error", + "code": 500, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "50442813-1f5d-4cde-8c53-4214309836f5", + "name": "An empty response is returned for a synchronous successful patch.", + "originalRequest": { + "method": "PATCH", + "header": [ + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/debitmandates/:debitMandateReference", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "debitmandates", + ":debitMandateReference" + ], + "variable": [ + { + "key": "accountId" + }, + { + "key": "debitMandateReference" + } + ] + } + }, + "status": "No Content", + "code": 204, + "_postman_previewlanguage": "text", + "header": [ + { + "key": "Content-Type", + "value": "text/plain" + } + ], + "cookie": [], + "body": "" + }, + { + "id": "6694a78e-126a-4078-808c-d7259c2986d5", + "name": "Represents an Error Caused by System Unavailability", + "originalRequest": { + "method": "PATCH", + "header": [ + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/debitmandates/:debitMandateReference", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "debitmandates", + ":debitMandateReference" + ], + "variable": [ + { + "key": "accountId" + }, + { + "key": "debitMandateReference" + } + ] + } + }, + "status": "Service Unavailable", + "code": 503, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "a51b134a-1172-41cc-9277-eef9d8700ece", + "name": "Represents an Error Caused by the Violation of a Business Rule", + "originalRequest": { + "method": "PATCH", + "header": [ + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/debitmandates/:debitMandateReference", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "debitmandates", + ":debitMandateReference" + ], + "variable": [ + { + "key": "accountId" + }, + { + "key": "debitMandateReference" + } + ] + } + }, + "status": "Bad Request", + "code": 400, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "29fd40b2-4bc5-49cf-98e2-eb788ab65ffb", + "name": "Represents an Error Caused by a Failure to Identify the Target Resource", + "originalRequest": { + "method": "PATCH", + "header": [ + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/debitmandates/:debitMandateReference", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "debitmandates", + ":debitMandateReference" + ], + "variable": [ + { + "key": "accountId" + }, + { + "key": "debitMandateReference" + } + ] + } + }, + "status": "Not Found", + "code": 404, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "04c321b1-34b7-4e0f-a8ff-aa3e5fe892fa", + "name": "Represents an Error Caused by an Authorisation Failure", + "originalRequest": { + "method": "PATCH", + "header": [ + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/debitmandates/:debitMandateReference", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "debitmandates", + ":debitMandateReference" + ], + "variable": [ + { + "key": "accountId" + }, + { + "key": "debitMandateReference" + } + ] + } + }, + "status": "Unauthorized", + "code": 401, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "716c7268-669e-46d2-a051-2d675fa03453", + "name": "Represents an Asynchronous response", + "originalRequest": { + "method": "PATCH", + "header": [ + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/debitmandates/:debitMandateReference", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "debitmandates", + ":debitMandateReference" + ], + "variable": [ + { + "key": "accountId" + }, + { + "key": "debitMandateReference" + } + ] + } + }, + "status": "Accepted", + "code": 202, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"notificationMethod\": \"\",\n \"serverCorrelationId\": \"\",\n \"status\": \"\",\n \"pendingReason\": \"\",\n \"objectReference\": \"\",\n \"expiryTime\": \"\",\n \"pollLimit\": \"\",\n \"error\": {\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n }\n}" + } + ] + } + ], + "id": "262db991-dede-4005-9aae-73aa841622f5" + }, + { + "name": "Create A Debit Mandate", + "id": "f8e3f30f-ddf7-414c-9359-40228654586f", + "request": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"requestDate\": \"\",\n \"startDate\": \"\",\n \"currency\": \"\",\n \"amountLimit\": \"schema type not provided\",\n \"endDate\": \"\",\n \"numberOfPayments\": \"\",\n \"frequencyType\": \"\",\n \"mandateStatus\": \"\"\n}" + }, + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/debitmandates", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "debitmandates" + ], + "variable": [ + { + "id": "7784a70b-bee2-491d-929c-14761d315e63", + "key": "accountId", + "value": "", + "description": "(Required) Path variable to uniquely identify an account. Up to three account identifiers can be supplied. Identifiers are delimited by $ and values are delimited by @. Example: organisationid@1234$accountid@3333. Valid account identifiers are accountcategory, bankaccountno, accountrank, identityalias, iban, accountid, msisdn, swiftbic, sortcode, organisationid, username, walletid, linkref, consumerno, serviceprovider, storeid, bankname, bankaccounttitle, emailaddress, mandatereference." + } + ] + }, + "description": "Provided with a valid object representation, this endpoint allows for a new debit mandate to be created for a specific account." + }, + "response": [ + { + "id": "2b923842-2e89-408d-89b4-2afafcd9e0be", + "name": "Represents an Error Caused by a General Server-Side Issue", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/debitmandates", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "debitmandates" + ], + "variable": [ + { + "key": "accountId" + } + ] + } + }, + "status": "Internal Server Error", + "code": 500, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "850db059-c60c-4ca1-adc9-7bf8e015d4c2", + "name": "Represents an Error Caused by System Unavailability", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/debitmandates", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "debitmandates" + ], + "variable": [ + { + "key": "accountId" + } + ] + } + }, + "status": "Service Unavailable", + "code": 503, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "d9b4407b-413a-4f66-849e-80dae6f7cdc5", + "name": "Represents an Asynchronous response", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/debitmandates", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "debitmandates" + ], + "variable": [ + { + "key": "accountId" + } + ] + } + }, + "status": "Accepted", + "code": 202, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"notificationMethod\": \"\",\n \"serverCorrelationId\": \"\",\n \"status\": \"\",\n \"pendingReason\": \"\",\n \"objectReference\": \"\",\n \"expiryTime\": \"\",\n \"pollLimit\": \"\",\n \"error\": {\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n }\n}" + }, + { + "id": "7b0995fb-5d68-4f18-986e-2081b13e3da0", + "name": "Represents an Error Caused by a Failure to Identify the Target Resource", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/debitmandates", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "debitmandates" + ], + "variable": [ + { + "key": "accountId" + } + ] + } + }, + "status": "Not Found", + "code": 404, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "a11b629c-9ca7-4c96-ba48-1a312842d627", + "name": "Represents an Error Caused by an Authorisation Failure", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/debitmandates", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "debitmandates" + ], + "variable": [ + { + "key": "accountId" + } + ] + } + }, + "status": "Unauthorized", + "code": 401, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "76eac912-b6a8-4a73-81f6-b4ade0ad168b", + "name": "Represents a Debit Mandate response", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/debitmandates", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "debitmandates" + ], + "variable": [ + { + "key": "accountId" + } + ] + } + }, + "status": "Created", + "code": 201, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"mandateReference\": \"\",\n \"currency\": \"\",\n \"amountLimit\": \"15.21\",\n \"startDate\": \"2018-11-20\",\n \"endDate\": \"2018-11-20\",\n \"numberOfPayments\": \"\",\n \"frequencyType\": \"\",\n \"mandateStatus\": \"\",\n \"requestDate\": \"\",\n \"creationDate\": \"\",\n \"modificationDate\": \"\",\n \"dateCreated\": \"\",\n \"dateModified\": \"\"\n}" + }, + { + "id": "5abc561a-5fc2-49ec-9fb4-294c8cbfbc19", + "name": "Represents an Error Caused by the Violation of a Business Rule", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/debitmandates", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "debitmandates" + ], + "variable": [ + { + "key": "accountId" + } + ] + } + }, + "status": "Bad Request", + "code": 400, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + } + ] + } + ], + "id": "4bec1f1d-c802-4d37-81e8-325957bcc441" + }, + { + "name": "links", + "item": [ + { + "name": "{link Reference}", + "item": [ + { + "name": "View A Link", + "id": "107d7db3-204a-4cc5-87d0-2ae6edff2114", + "request": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/links/:linkReference", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "links", + ":linkReference" + ], + "variable": [ + { + "id": "e193b586-e508-4ee0-9965-cfd07aabe744", + "key": "accountId", + "value": "", + "description": "(Required) Path variable to uniquely identify an account. Up to three account identifiers can be supplied. Identifiers are delimited by $ and values are delimited by @. Example: organisationid@1234$accountid@3333. Valid account identifiers are accountcategory, bankaccountno, accountrank, identityalias, iban, accountid, msisdn, swiftbic, sortcode, organisationid, username, walletid, linkref, consumerno, serviceprovider, storeid, bankname, bankaccounttitle, emailaddress, mandatereference." + }, + { + "id": "839cc31b-4836-4f3c-9645-65e90203be80", + "key": "linkReference", + "value": "", + "description": "(Required) Path variable to uniquely identify a link." + } + ] + }, + "description": "This endpoint returns a specific link" + }, + "response": [ + { + "id": "02a7f7b0-2a74-4017-bd01-22816cc99a9d", + "name": "Represents an Error Caused by a Failure to Identify the Target Resource", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/links/:linkReference", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "links", + ":linkReference" + ], + "variable": [ + { + "key": "accountId" + }, + { + "key": "linkReference" + } + ] + } + }, + "status": "Not Found", + "code": 404, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "d01ac6a6-b0e5-4228-b352-e31feda5f7b0", + "name": "Represents an Error Caused by the Violation of a Business Rule", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/links/:linkReference", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "links", + ":linkReference" + ], + "variable": [ + { + "key": "accountId" + }, + { + "key": "linkReference" + } + ] + } + }, + "status": "Bad Request", + "code": 400, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "39fa6924-b781-4fa5-b110-f14d8a661354", + "name": "Represents a Link response\"", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/links/:linkReference", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "links", + ":linkReference" + ], + "variable": [ + { + "key": "accountId" + }, + { + "key": "linkReference" + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"linkReference\": \"\",\n \"sourceAccountIdentifiers\": [\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n },\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n }\n ],\n \"status\": \"\",\n \"mode\": \"\"\n}" + }, + { + "id": "f4d6ef66-2258-4551-9f88-31cb740e1cfd", + "name": "Represents an Error Caused by a General Server-Side Issue", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/links/:linkReference", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "links", + ":linkReference" + ], + "variable": [ + { + "key": "accountId" + }, + { + "key": "linkReference" + } + ] + } + }, + "status": "Internal Server Error", + "code": 500, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "3ce79cd8-e2a7-42e7-a050-537f9dc23c3d", + "name": "Represents an Error Caused by an Authorisation Failure", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/links/:linkReference", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "links", + ":linkReference" + ], + "variable": [ + { + "key": "accountId" + }, + { + "key": "linkReference" + } + ] + } + }, + "status": "Unauthorized", + "code": 401, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "a917514a-667c-40a9-b929-6c14a3a20d23", + "name": "Represents an Error Caused by System Unavailability", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/links/:linkReference", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "links", + ":linkReference" + ], + "variable": [ + { + "key": "accountId" + }, + { + "key": "linkReference" + } + ] + } + }, + "status": "Service Unavailable", + "code": 503, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + } + ] + }, + { + "name": "Update A Link", + "id": "c59a2599-b2c2-45df-938f-ed9d80ba8233", + "request": { + "method": "PATCH", + "header": [ + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "[\n {\n \"op\": \"\",\n \"path\": \"\",\n \"value\": \"\"\n },\n {\n \"op\": \"\",\n \"path\": \"\",\n \"value\": \"\"\n }\n]" + }, + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/links/:linkReference", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "links", + ":linkReference" + ], + "variable": [ + { + "id": "4244ab01-f5b2-4e30-ae2d-529384d5fb0e", + "key": "accountId", + "value": "", + "description": "(Required) Path variable to uniquely identify an account. Up to three account identifiers can be supplied. Identifiers are delimited by $ and values are delimited by @. Example: organisationid@1234$accountid@3333. Valid account identifiers are accountcategory, bankaccountno, accountrank, identityalias, iban, accountid, msisdn, swiftbic, sortcode, organisationid, username, walletid, linkref, consumerno, serviceprovider, storeid, bankname, bankaccounttitle, emailaddress, mandatereference." + }, + { + "id": "fdd2e746-df72-40c9-8ade-2967ce01318c", + "key": "linkReference", + "value": "", + "description": "(Required) Path variable to uniquely identify a link." + } + ] + }, + "description": "This endpoint updates a specific link" + }, + "response": [ + { + "id": "a9f160c9-ec5d-4c6b-9feb-9ec1ef860a12", + "name": "An empty response is returned for a synchronous successful patch.", + "originalRequest": { + "method": "PATCH", + "header": [ + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/links/:linkReference", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "links", + ":linkReference" + ], + "variable": [ + { + "key": "accountId" + }, + { + "key": "linkReference" + } + ] + } + }, + "status": "No Content", + "code": 204, + "_postman_previewlanguage": "text", + "header": [ + { + "key": "Content-Type", + "value": "text/plain" + } + ], + "cookie": [], + "body": "" + }, + { + "id": "2b5feea2-3215-4fc8-9039-d705ea8f29cc", + "name": "Represents an Error Caused by an Authorisation Failure", + "originalRequest": { + "method": "PATCH", + "header": [ + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/links/:linkReference", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "links", + ":linkReference" + ], + "variable": [ + { + "key": "accountId" + }, + { + "key": "linkReference" + } + ] + } + }, + "status": "Unauthorized", + "code": 401, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "c0aa6317-61c2-4d77-aa5c-a070c9091aed", + "name": "Represents an Error Caused by a Failure to Identify the Target Resource", + "originalRequest": { + "method": "PATCH", + "header": [ + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/links/:linkReference", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "links", + ":linkReference" + ], + "variable": [ + { + "key": "accountId" + }, + { + "key": "linkReference" + } + ] + } + }, + "status": "Not Found", + "code": 404, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "c0afe394-e0a4-4303-91cc-4b190769ae86", + "name": "Represents an Error Caused by System Unavailability", + "originalRequest": { + "method": "PATCH", + "header": [ + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/links/:linkReference", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "links", + ":linkReference" + ], + "variable": [ + { + "key": "accountId" + }, + { + "key": "linkReference" + } + ] + } + }, + "status": "Service Unavailable", + "code": 503, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "b5ab700c-40ee-445e-8772-5a701ddfec72", + "name": "Represents an Asynchronous response", + "originalRequest": { + "method": "PATCH", + "header": [ + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/links/:linkReference", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "links", + ":linkReference" + ], + "variable": [ + { + "key": "accountId" + }, + { + "key": "linkReference" + } + ] + } + }, + "status": "Accepted", + "code": 202, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"notificationMethod\": \"\",\n \"serverCorrelationId\": \"\",\n \"status\": \"\",\n \"pendingReason\": \"\",\n \"objectReference\": \"\",\n \"expiryTime\": \"\",\n \"pollLimit\": \"\",\n \"error\": {\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n }\n}" + }, + { + "id": "30b58009-2a3a-4a73-9f84-dd316e5f0b57", + "name": "Represents an Error Caused by a General Server-Side Issue", + "originalRequest": { + "method": "PATCH", + "header": [ + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/links/:linkReference", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "links", + ":linkReference" + ], + "variable": [ + { + "key": "accountId" + }, + { + "key": "linkReference" + } + ] + } + }, + "status": "Internal Server Error", + "code": 500, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "cc52a2b7-3e9f-4083-ac85-36940fc3ebd6", + "name": "Represents an Error Caused by the Violation of a Business Rule", + "originalRequest": { + "method": "PATCH", + "header": [ + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/links/:linkReference", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "links", + ":linkReference" + ], + "variable": [ + { + "key": "accountId" + }, + { + "key": "linkReference" + } + ] + } + }, + "status": "Bad Request", + "code": 400, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + } + ] + } + ], + "id": "828ce975-3166-44d5-8076-73ff389918d7" + }, + { + "name": "Create A Link", + "id": "87fdf522-e032-461f-b69e-174501c0ec42", + "request": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"sourceAccountIdentifiers\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ],\n \"status\": \"\",\n \"mode\": \"\"\n}" + }, + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/links", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "links" + ], + "variable": [ + { + "id": "64c5cea2-2ab9-4939-9542-6e09a074d39c", + "key": "accountId", + "value": "", + "description": "(Required) Path variable to uniquely identify an account. Up to three account identifiers can be supplied. Identifiers are delimited by $ and values are delimited by @. Example: organisationid@1234$accountid@3333. Valid account identifiers are accountcategory, bankaccountno, accountrank, identityalias, iban, accountid, msisdn, swiftbic, sortcode, organisationid, username, walletid, linkref, consumerno, serviceprovider, storeid, bankname, bankaccounttitle, emailaddress, mandatereference." + } + ] + }, + "description": "Provided with a valid object representation, this endpoint allows a new link to be created for a specific account" + }, + "response": [ + { + "id": "41204326-6f23-4980-ac8e-a2dca96ab45a", + "name": "Represents an Error Caused by an Authorisation Failure", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/links", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "links" + ], + "variable": [ + { + "key": "accountId" + } + ] + } + }, + "status": "Unauthorized", + "code": 401, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "3e4727a5-d6c3-4078-942b-51512067b1ef", + "name": "Represents an Error Caused by a Failure to Identify the Target Resource", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/links", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "links" + ], + "variable": [ + { + "key": "accountId" + } + ] + } + }, + "status": "Not Found", + "code": 404, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "ee1d7a80-ab9a-4c37-af39-0bb184e7b064", + "name": "Represents an Error Caused by System Unavailability", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/links", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "links" + ], + "variable": [ + { + "key": "accountId" + } + ] + } + }, + "status": "Service Unavailable", + "code": 503, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "99119381-1f78-4915-9c0a-262a3afd9a7e", + "name": "Represents an Error Caused by the Violation of a Business Rule", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/links", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "links" + ], + "variable": [ + { + "key": "accountId" + } + ] + } + }, + "status": "Bad Request", + "code": 400, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "dfd00523-17eb-4912-b57b-773e1b52deef", + "name": "Represents an Asynchronous response", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/links", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "links" + ], + "variable": [ + { + "key": "accountId" + } + ] + } + }, + "status": "Accepted", + "code": 202, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"notificationMethod\": \"\",\n \"serverCorrelationId\": \"\",\n \"status\": \"\",\n \"pendingReason\": \"\",\n \"objectReference\": \"\",\n \"expiryTime\": \"\",\n \"pollLimit\": \"\",\n \"error\": {\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n }\n}" + }, + { + "id": "d789c207-1438-4414-946f-ed719e260bda", + "name": "Represents an Error Caused by a General Server-Side Issue", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/links", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "links" + ], + "variable": [ + { + "key": "accountId" + } + ] + } + }, + "status": "Internal Server Error", + "code": 500, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "d417aa97-2d1b-4326-8019-53b43ce23795", + "name": "Represents a Link response", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/links", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "links" + ], + "variable": [ + { + "key": "accountId" + } + ] + } + }, + "status": "Created", + "code": 201, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"linkReference\": \"\",\n \"sourceAccountIdentifiers\": [\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n },\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n }\n ],\n \"status\": \"\",\n \"mode\": \"\"\n}" + } + ] + } + ], + "id": "ce799aec-69c6-4567-9d92-17e327fd499f" + }, + { + "name": "authorisationcodes", + "item": [ + { + "name": "{authorisation Code}", + "item": [ + { + "name": "View an Authorisation Code", + "id": "4a543d25-ba0c-49b8-b33f-18f4532f0fd2", + "request": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/authorisationcodes/:authorisationCode", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "authorisationcodes", + ":authorisationCode" + ], + "variable": [ + { + "id": "7f001950-b629-4f4d-a098-3d1061bd7690", + "key": "accountId", + "value": "", + "description": "(Required) Path variable to uniquely identify an account. Up to three account identifiers can be supplied. Identifiers are delimited by $ and values are delimited by @. Example: organisationid@1234$accountid@3333. Valid account identifiers are accountcategory, bankaccountno, accountrank, identityalias, iban, accountid, msisdn, swiftbic, sortcode, organisationid, username, walletid, linkref, consumerno, serviceprovider, storeid, bankname, bankaccounttitle, emailaddress, mandatereference." + }, + { + "id": "be60a4bb-ab06-469c-9d8e-50880604ff56", + "key": "authorisationCode", + "value": "", + "description": "(Required) Path variable to uniquely identify an authorisation code." + } + ] + }, + "description": "This endpoint returns a specific Authorisation Code linked to an account" + }, + "response": [ + { + "id": "d3762a22-bff5-4c36-89bb-8a8ae0cde948", + "name": "Represents an Error Caused by System Unavailability", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/authorisationcodes/:authorisationCode", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "authorisationcodes", + ":authorisationCode" + ], + "variable": [ + { + "key": "accountId" + }, + { + "key": "authorisationCode" + } + ] + } + }, + "status": "Service Unavailable", + "code": 503, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "aa6e35c3-debd-46fb-adfb-ec6a89387c26", + "name": "Represents an Error Caused by the Violation of a Business Rule", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/authorisationcodes/:authorisationCode", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "authorisationcodes", + ":authorisationCode" + ], + "variable": [ + { + "key": "accountId" + }, + { + "key": "authorisationCode" + } + ] + } + }, + "status": "Bad Request", + "code": 400, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "725bbfc5-7b56-480a-a838-10d6f8dc1aaa", + "name": "Represents an Error Caused by an Authorisation Failure", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/authorisationcodes/:authorisationCode", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "authorisationcodes", + ":authorisationCode" + ], + "variable": [ + { + "key": "accountId" + }, + { + "key": "authorisationCode" + } + ] + } + }, + "status": "Unauthorized", + "code": 401, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "4a66160d-aa44-42eb-b55c-ba8ca48c1525", + "name": "Represents an Error Caused by a Failure to Identify the Target Resource", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/authorisationcodes/:authorisationCode", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "authorisationcodes", + ":authorisationCode" + ], + "variable": [ + { + "key": "accountId" + }, + { + "key": "authorisationCode" + } + ] + } + }, + "status": "Not Found", + "code": 404, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "5e4a9630-83a7-422e-9f41-3e86d890f102", + "name": "Represents an Authorisation Code response", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/authorisationcodes/:authorisationCode", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "authorisationcodes", + ":authorisationCode" + ], + "variable": [ + { + "key": "accountId" + }, + { + "key": "authorisationCode" + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"authorisationCode\": \"\",\n \"codeState\": \"\",\n \"codeLifetime\": \"\",\n \"requestDate\": \"\",\n \"amount\": \"15.21\",\n \"currency\": \"\",\n \"amountType\": \"\",\n \"holdFundsIndicator\": \"\",\n \"redemptionChannels\": [\n {\n \"channelType\": \"\"\n },\n {\n \"channelType\": \"\"\n }\n ],\n \"redemptionTransactionTypes\": [\n {\n \"transactionType\": \"\",\n \"transactionSubtype\": \"\"\n },\n {\n \"transactionType\": \"\",\n \"transactionSubtype\": \"\"\n }\n ],\n \"redemptionAccountIdentifiers\": [\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n },\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n }\n ],\n \"metadata\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "00df84c1-baa2-432e-a18b-a605a3c032eb", + "name": "Represents an Error Caused by a General Server-Side Issue", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/authorisationcodes/:authorisationCode", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "authorisationcodes", + ":authorisationCode" + ], + "variable": [ + { + "key": "accountId" + }, + { + "key": "authorisationCode" + } + ] + } + }, + "status": "Internal Server Error", + "code": 500, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + } + ] + }, + { + "name": "Update an Authorisation Code", + "id": "f6dee45d-a6bf-4c86-84f3-15cb71bf2a15", + "request": { + "method": "PATCH", + "header": [ + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "[\n {\n \"op\": \"\",\n \"path\": \"\",\n \"value\": \"\"\n },\n {\n \"op\": \"\",\n \"path\": \"\",\n \"value\": \"\"\n }\n]" + }, + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/authorisationcodes/:authorisationCode", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "authorisationcodes", + ":authorisationCode" + ], + "variable": [ + { + "id": "6f17d4b0-2247-4318-b84b-a54d9f92a6b8", + "key": "accountId", + "value": "", + "description": "(Required) Path variable to uniquely identify an account. Up to three account identifiers can be supplied. Identifiers are delimited by $ and values are delimited by @. Example: organisationid@1234$accountid@3333. Valid account identifiers are accountcategory, bankaccountno, accountrank, identityalias, iban, accountid, msisdn, swiftbic, sortcode, organisationid, username, walletid, linkref, consumerno, serviceprovider, storeid, bankname, bankaccounttitle, emailaddress, mandatereference." + }, + { + "id": "04e279e2-98fa-4a16-831b-6fad85ef0944", + "key": "authorisationCode", + "value": "", + "description": "(Required) Path variable to uniquely identify an authorisation code." + } + ] + }, + "description": "This endpoint updates a specific Authorisation Code linked to an account" + }, + "response": [ + { + "id": "78cf6060-93f9-4a76-9a62-85e4ac03bae6", + "name": "Represents an Error Caused by System Unavailability", + "originalRequest": { + "method": "PATCH", + "header": [ + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/authorisationcodes/:authorisationCode", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "authorisationcodes", + ":authorisationCode" + ], + "variable": [ + { + "key": "accountId" + }, + { + "key": "authorisationCode" + } + ] + } + }, + "status": "Service Unavailable", + "code": 503, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "14d539ed-2d37-4f1a-92c8-b7e4094aa1bd", + "name": "Represents an Asynchronous response", + "originalRequest": { + "method": "PATCH", + "header": [ + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/authorisationcodes/:authorisationCode", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "authorisationcodes", + ":authorisationCode" + ], + "variable": [ + { + "key": "accountId" + }, + { + "key": "authorisationCode" + } + ] + } + }, + "status": "Accepted", + "code": 202, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"notificationMethod\": \"\",\n \"serverCorrelationId\": \"\",\n \"status\": \"\",\n \"pendingReason\": \"\",\n \"objectReference\": \"\",\n \"expiryTime\": \"\",\n \"pollLimit\": \"\",\n \"error\": {\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n }\n}" + }, + { + "id": "2b8a5ddb-f923-4534-a523-d75079e3af36", + "name": "Represents an Error Caused by a Failure to Identify the Target Resource", + "originalRequest": { + "method": "PATCH", + "header": [ + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/authorisationcodes/:authorisationCode", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "authorisationcodes", + ":authorisationCode" + ], + "variable": [ + { + "key": "accountId" + }, + { + "key": "authorisationCode" + } + ] + } + }, + "status": "Not Found", + "code": 404, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "f1bc39d1-6bc6-4c76-854a-71ec3732a881", + "name": "An empty response is returned for a synchronous successful patch.", + "originalRequest": { + "method": "PATCH", + "header": [ + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/authorisationcodes/:authorisationCode", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "authorisationcodes", + ":authorisationCode" + ], + "variable": [ + { + "key": "accountId" + }, + { + "key": "authorisationCode" + } + ] + } + }, + "status": "No Content", + "code": 204, + "_postman_previewlanguage": "text", + "header": [ + { + "key": "Content-Type", + "value": "text/plain" + } + ], + "cookie": [], + "body": "" + }, + { + "id": "c4dae55f-c579-4fa6-ad87-835ee81e3f1e", + "name": "Represents an Error Caused by the Violation of a Business Rule", + "originalRequest": { + "method": "PATCH", + "header": [ + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/authorisationcodes/:authorisationCode", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "authorisationcodes", + ":authorisationCode" + ], + "variable": [ + { + "key": "accountId" + }, + { + "key": "authorisationCode" + } + ] + } + }, + "status": "Bad Request", + "code": 400, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "95961c02-80ea-48e9-a5da-bc5cf8b42bae", + "name": "Represents an Error Caused by a General Server-Side Issue", + "originalRequest": { + "method": "PATCH", + "header": [ + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/authorisationcodes/:authorisationCode", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "authorisationcodes", + ":authorisationCode" + ], + "variable": [ + { + "key": "accountId" + }, + { + "key": "authorisationCode" + } + ] + } + }, + "status": "Internal Server Error", + "code": 500, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "501e922a-6b71-4151-8541-2c646df38642", + "name": "Represents an Error Caused by an Authorisation Failure", + "originalRequest": { + "method": "PATCH", + "header": [ + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/authorisationcodes/:authorisationCode", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "authorisationcodes", + ":authorisationCode" + ], + "variable": [ + { + "key": "accountId" + }, + { + "key": "authorisationCode" + } + ] + } + }, + "status": "Unauthorized", + "code": 401, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + } + ] + } + ], + "id": "a1d15f45-6a45-4cd0-8865-bfc05a3fe9db" + }, + { + "name": "Create an Authorisation Code", + "id": "c7d41b9d-50ec-41c6-b208-3ef80ac5e948", + "request": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"requestDate\": \"\",\n \"codeLifetime\": \"\",\n \"amount\": \"\",\n \"currency\": \"\",\n \"amountType\": \"\",\n \"holdFundsIndicator\": \"\",\n \"redemptionChannels\": [\n {\n \"channelType\": \"\"\n },\n {\n \"channelType\": \"\"\n }\n ],\n \"redemptionTransactionTypes\": [\n {\n \"transactionType\": \"\",\n \"transactionSubtype\": \"\"\n },\n {\n \"transactionType\": \"\",\n \"transactionSubtype\": \"\"\n }\n ],\n \"redemptionAccountIdentifiers\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ],\n \"metadata\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/authorisationcodes", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "authorisationcodes" + ], + "variable": [ + { + "id": "52ec263b-5897-4657-a9d5-b441d7d18b03", + "key": "accountId", + "value": "", + "description": "(Required) Path variable to uniquely identify an account. Up to three account identifiers can be supplied. Identifiers are delimited by $ and values are delimited by @. Example: organisationid@1234$accountid@3333. Valid account identifiers are accountcategory, bankaccountno, accountrank, identityalias, iban, accountid, msisdn, swiftbic, sortcode, organisationid, username, walletid, linkref, consumerno, serviceprovider, storeid, bankname, bankaccounttitle, emailaddress, mandatereference." + } + ] + }, + "description": "this endpoint allows allows a mobile money payer or payee to generate a code which when presented to the other party, can be redeemed for an amount set by the payer or payee, depending upon the use case" + }, + "response": [ + { + "id": "786237bd-5fb5-42cb-a9d6-7ae22ee832e0", + "name": "Represents an Asynchronous response", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/authorisationcodes", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "authorisationcodes" + ], + "variable": [ + { + "key": "accountId" + } + ] + } + }, + "status": "Accepted", + "code": 202, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"notificationMethod\": \"\",\n \"serverCorrelationId\": \"\",\n \"status\": \"\",\n \"pendingReason\": \"\",\n \"objectReference\": \"\",\n \"expiryTime\": \"\",\n \"pollLimit\": \"\",\n \"error\": {\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n }\n}" + }, + { + "id": "87e8a512-9cbb-48f9-8bbb-67792567565b", + "name": "Represents an Error Caused by the Violation of a Business Rule", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/authorisationcodes", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "authorisationcodes" + ], + "variable": [ + { + "key": "accountId" + } + ] + } + }, + "status": "Bad Request", + "code": 400, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "a297b008-ffb8-4b98-b9eb-0579297879e8", + "name": "Represents an Error Caused by a General Server-Side Issue", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/authorisationcodes", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "authorisationcodes" + ], + "variable": [ + { + "key": "accountId" + } + ] + } + }, + "status": "Internal Server Error", + "code": 500, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "4891c910-3ac5-45a5-9fd4-5c1e24b09d17", + "name": "Represents an Error Caused by an Authorisation Failure", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/authorisationcodes", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "authorisationcodes" + ], + "variable": [ + { + "key": "accountId" + } + ] + } + }, + "status": "Unauthorized", + "code": 401, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "6a84b8db-8ddc-436f-98c6-cd944bec272e", + "name": "Represents an Error Caused by System Unavailability", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/authorisationcodes", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "authorisationcodes" + ], + "variable": [ + { + "key": "accountId" + } + ] + } + }, + "status": "Service Unavailable", + "code": 503, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "2d08e0c5-5bc8-4116-9614-3b57910095d5", + "name": "Represents an Authorisation Code response", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/authorisationcodes", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "authorisationcodes" + ], + "variable": [ + { + "key": "accountId" + } + ] + } + }, + "status": "Created", + "code": 201, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"authorisationCode\": \"\",\n \"codeState\": \"\",\n \"codeLifetime\": \"\",\n \"requestDate\": \"\",\n \"amount\": \"15.21\",\n \"currency\": \"\",\n \"amountType\": \"\",\n \"holdFundsIndicator\": \"\",\n \"redemptionChannels\": [\n {\n \"channelType\": \"\"\n },\n {\n \"channelType\": \"\"\n }\n ],\n \"redemptionTransactionTypes\": [\n {\n \"transactionType\": \"\",\n \"transactionSubtype\": \"\"\n },\n {\n \"transactionType\": \"\",\n \"transactionSubtype\": \"\"\n }\n ],\n \"redemptionAccountIdentifiers\": [\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n },\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n }\n ],\n \"metadata\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "828a32d4-b7d2-404a-92de-caee42d3505c", + "name": "Represents an Error Caused by a Failure to Identify the Target Resource", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/authorisationcodes", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "authorisationcodes" + ], + "variable": [ + { + "key": "accountId" + } + ] + } + }, + "status": "Not Found", + "code": 404, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + } + ] + } + ], + "id": "914b13c9-3fa8-40ae-8603-3376ffd57161" + }, + { + "name": "View Account Status", + "id": "f059be2c-cda8-4b9a-a8d6-1521f2e0eff9", + "request": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/status", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "status" + ], + "variable": [ + { + "id": "b0f3bc1c-6697-4d9c-91f6-74881cfc906f", + "key": "accountId", + "value": "", + "description": "(Required) Path variable to uniquely identify an account. Up to three account identifiers can be supplied. Identifiers are delimited by $ and values are delimited by @. Example: organisationid@1234$accountid@3333. Valid account identifiers are accountcategory, bankaccountno, accountrank, identityalias, iban, accountid, msisdn, swiftbic, sortcode, organisationid, username, walletid, linkref, consumerno, serviceprovider, storeid, bankname, bankaccounttitle, emailaddress, mandatereference." + } + ] + }, + "description": "This endpoint returns the current status of an account. This API accepts multiple identifiers" + }, + "response": [ + { + "id": "99bbd0f3-bdd9-42ce-b7a7-c4707fa04391", + "name": "Represents an Error Caused by System Unavailability", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/status", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "status" + ], + "variable": [ + { + "key": "accountId" + } + ] + } + }, + "status": "Service Unavailable", + "code": 503, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "ead43c14-9ccf-4063-b20a-9637e60150a0", + "name": "Represents an Error Caused by an Authorisation Failure", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/status", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "status" + ], + "variable": [ + { + "key": "accountId" + } + ] + } + }, + "status": "Unauthorized", + "code": 401, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "5a0302dc-0cbc-4447-a691-92e01cb49336", + "name": "Represents an Error Caused by a General Server-Side Issue", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/status", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "status" + ], + "variable": [ + { + "key": "accountId" + } + ] + } + }, + "status": "Internal Server Error", + "code": 500, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "1cefe49d-29d5-4bc4-b95b-5a4503eed828", + "name": "Represents an Account Status response", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/status", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "status" + ], + "variable": [ + { + "key": "accountId" + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"accountStatus\": \"\",\n \"subStatus\": \"\",\n \"lei\": \"5493000IBP32UQZ0KL24\"\n}" + }, + { + "id": "b3ce6177-5793-49a2-a451-e2b44eec7611", + "name": "Represents an Error Caused by a Failure to Identify the Target Resource", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/status", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "status" + ], + "variable": [ + { + "key": "accountId" + } + ] + } + }, + "status": "Not Found", + "code": 404, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "8a4ddd2f-f2d2-475e-b355-687e0368c6e2", + "name": "Represents an Error Caused by the Violation of a Business Rule", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/status", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "status" + ], + "variable": [ + { + "key": "accountId" + } + ] + } + }, + "status": "Bad Request", + "code": 400, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + } + ] + }, + { + "name": "View Account Name", + "id": "cb09658d-bb77-48a2-8fcc-40cfcde42851", + "request": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/accountname", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "accountname" + ], + "variable": [ + { + "id": "4dad5214-3d8c-40d9-a415-cd7bcb59ed56", + "key": "accountId", + "value": "", + "description": "(Required) Path variable to uniquely identify an account. Up to three account identifiers can be supplied. Identifiers are delimited by $ and values are delimited by @. Example: organisationid@1234$accountid@3333. Valid account identifiers are accountcategory, bankaccountno, accountrank, identityalias, iban, accountid, msisdn, swiftbic, sortcode, organisationid, username, walletid, linkref, consumerno, serviceprovider, storeid, bankname, bankaccounttitle, emailaddress, mandatereference." + } + ] + }, + "description": "This endpoint returns the status of a given account." + }, + "response": [ + { + "id": "1ab8b83b-589b-441a-b37d-00e1fc3c60c4", + "name": "Represents an Error Caused by a General Server-Side Issue", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/accountname", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "accountname" + ], + "variable": [ + { + "key": "accountId" + } + ] + } + }, + "status": "Internal Server Error", + "code": 500, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "097e89f7-30d2-4739-94b2-d04d837062a7", + "name": "Represents an Error Caused by the Violation of a Business Rule", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/accountname", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "accountname" + ], + "variable": [ + { + "key": "accountId" + } + ] + } + }, + "status": "Bad Request", + "code": 400, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "abba06c4-2735-4db7-83cc-d28f312729e5", + "name": "Represents an Error Caused by System Unavailability", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/accountname", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "accountname" + ], + "variable": [ + { + "key": "accountId" + } + ] + } + }, + "status": "Service Unavailable", + "code": 503, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "b8702e64-77df-4ef5-bd75-f8ffd3a79c07", + "name": "Represents an Error Caused by an Authorisation Failure", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/accountname", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "accountname" + ], + "variable": [ + { + "key": "accountId" + } + ] + } + }, + "status": "Unauthorized", + "code": 401, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "ac1ceb56-6507-4dc4-894e-2295d8ad3d9d", + "name": "Represents an Account Name response", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/accountname", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "accountname" + ], + "variable": [ + { + "key": "accountId" + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"name\": {\n \"title\": \"\",\n \"firstName\": \"\",\n \"middleName\": \"\",\n \"lastName\": \"\",\n \"fullName\": \"\",\n \"nativeName\": \"\"\n },\n \"lei\": \"5493000IBP32UQZ0KL24\"\n}" + }, + { + "id": "4a95a665-5828-4342-b4f3-52809b16d0bc", + "name": "Represents an Error Caused by a Failure to Identify the Target Resource", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/accountname", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "accountname" + ], + "variable": [ + { + "key": "accountId" + } + ] + } + }, + "status": "Not Found", + "code": 404, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + } + ] + }, + { + "name": "View Account Balance", + "id": "d90367fb-56f6-429b-98fc-1c1e05ad0570", + "request": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/balance", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "balance" + ], + "variable": [ + { + "id": "4189f538-2b18-433f-bdda-b9ee56eb47dc", + "key": "accountId", + "value": "", + "description": "(Required) Path variable to uniquely identify an account. Up to three account identifiers can be supplied. Identifiers are delimited by $ and values are delimited by @. Example: organisationid@1234$accountid@3333. Valid account identifiers are accountcategory, bankaccountno, accountrank, identityalias, iban, accountid, msisdn, swiftbic, sortcode, organisationid, username, walletid, linkref, consumerno, serviceprovider, storeid, bankname, bankaccounttitle, emailaddress, mandatereference." + } + ] + }, + "description": "This endpoint returns the balance of an account" + }, + "response": [ + { + "id": "892a8338-0f2e-49d9-a291-3e35c7c1e6de", + "name": "Represents an Error Caused by an Authorisation Failure", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/balance", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "balance" + ], + "variable": [ + { + "key": "accountId" + } + ] + } + }, + "status": "Unauthorized", + "code": 401, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "46dbd459-ce55-4b6f-a264-4155039b2c67", + "name": "Represents an Error Caused by System Unavailability", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/balance", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "balance" + ], + "variable": [ + { + "key": "accountId" + } + ] + } + }, + "status": "Service Unavailable", + "code": 503, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "53c34828-66e1-4fec-8859-5eeea0509cd8", + "name": "Represents an Account Balance response", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/balance", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "balance" + ], + "variable": [ + { + "key": "accountId" + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"currentBalance\": \"15.21\",\n \"availableBalance\": \"15.21\",\n \"reservedBalance\": \"15.21\",\n \"unclearedBalance\": \"15.21\",\n \"currency\": \"\",\n \"accountStatus\": \"\"\n}" + }, + { + "id": "f190d813-f465-4b51-bd49-22d35f975b7c", + "name": "Represents an Error Caused by a General Server-Side Issue", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/balance", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "balance" + ], + "variable": [ + { + "key": "accountId" + } + ] + } + }, + "status": "Internal Server Error", + "code": 500, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "e70728e3-2a60-47a5-b7a2-409a59e219ad", + "name": "Represents an Error Caused by a Failure to Identify the Target Resource", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/balance", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "balance" + ], + "variable": [ + { + "key": "accountId" + } + ] + } + }, + "status": "Not Found", + "code": 404, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "e4d5738f-f744-4a3a-a8e0-6a9c457d96d0", + "name": "Represents an Error Caused by the Violation of a Business Rule", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/balance", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "balance" + ], + "variable": [ + { + "key": "accountId" + } + ] + } + }, + "status": "Bad Request", + "code": 400, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + } + ] + }, + { + "name": "View Account Specific Transaction", + "id": "0f806e0e-0d5a-4e7d-902b-9d0b6beb0a6b", + "request": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/transactions?limit=&offset=&fromDateTime=&toDateTime=&transactionStatus=&transactionType=", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "transactions" + ], + "query": [ + { + "key": "limit", + "value": "", + "description": "Supports pagination. If this is not supplied, then the server will apply a limit of 50 records returned for each request." + }, + { + "key": "offset", + "value": "", + "description": "Supports pagination. This value will indicate the cursor position from where to retrieve the set of records. For example, a limit of 50 and offset of 10 will return records 11 to 60." + }, + { + "key": "fromDateTime", + "value": "", + "description": "Indicates the minimum date for which records should be returned." + }, + { + "key": "toDateTime", + "value": "", + "description": "Indicates the maximum date for which records should be returned." + }, + { + "key": "transactionStatus", + "value": "", + "description": "Query variable to uniquely identify the transaction status." + }, + { + "key": "transactionType", + "value": "", + "description": "Identifies the type of transaction." + } + ], + "variable": [ + { + "id": "38f836df-b009-4dba-ab25-244eda23ebc3", + "key": "accountId", + "value": "", + "description": "(Required) Path variable to uniquely identify an account. Up to three account identifiers can be supplied. Identifiers are delimited by $ and values are delimited by @. Example: organisationid@1234$accountid@3333. Valid account identifiers are accountcategory, bankaccountno, accountrank, identityalias, iban, accountid, msisdn, swiftbic, sortcode, organisationid, username, walletid, linkref, consumerno, serviceprovider, storeid, bankname, bankaccounttitle, emailaddress, mandatereference." + } + ] + }, + "description": "This endpoint returns transactions linked to a specific account" + }, + "response": [ + { + "id": "ca8affad-32a7-4bd1-8729-ec46053203f0", + "name": "Represents an Error Caused by the Violation of a Business Rule", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/transactions?limit=&offset=&fromDateTime=&toDateTime=&transactionStatus=&transactionType=", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "transactions" + ], + "query": [ + { + "key": "limit", + "value": "" + }, + { + "key": "offset", + "value": "" + }, + { + "key": "fromDateTime", + "value": "" + }, + { + "key": "toDateTime", + "value": "" + }, + { + "key": "transactionStatus", + "value": "" + }, + { + "key": "transactionType", + "value": "" + } + ], + "variable": [ + { + "key": "accountId" + } + ] + } + }, + "status": "Bad Request", + "code": 400, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "5e4da8af-9f3f-4ff4-a6c8-c1cfb8da34e4", + "name": "Represents an Error Caused by System Unavailability", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/transactions?limit=&offset=&fromDateTime=&toDateTime=&transactionStatus=&transactionType=", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "transactions" + ], + "query": [ + { + "key": "limit", + "value": "" + }, + { + "key": "offset", + "value": "" + }, + { + "key": "fromDateTime", + "value": "" + }, + { + "key": "toDateTime", + "value": "" + }, + { + "key": "transactionStatus", + "value": "" + }, + { + "key": "transactionType", + "value": "" + } + ], + "variable": [ + { + "key": "accountId" + } + ] + } + }, + "status": "Service Unavailable", + "code": 503, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "3cce3ff8-65f9-4461-bc61-1fd7a8c3a68d", + "name": "Represent a list of Transactions", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/transactions?limit=&offset=&fromDateTime=&toDateTime=&transactionStatus=&transactionType=", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "transactions" + ], + "query": [ + { + "key": "limit", + "value": "" + }, + { + "key": "offset", + "value": "" + }, + { + "key": "fromDateTime", + "value": "" + }, + { + "key": "toDateTime", + "value": "" + }, + { + "key": "transactionStatus", + "value": "" + }, + { + "key": "transactionType", + "value": "" + } + ], + "variable": [ + { + "key": "accountId" + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "X-Records-Available-Count", + "value": "", + "description": "Integer containing number of records that are available to be returned." + }, + { + "key": "X-Records-Returned-Count", + "value": "", + "description": "Integer containing number of records that are returned." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "[\n {\n \"amount\": \"15.21\",\n \"currency\": \"\",\n \"type\": \"\",\n \"transactionReference\": \"\",\n \"transactionStatus\": \"\",\n \"debitParty\": [\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n },\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n }\n ],\n \"creditParty\": [\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n },\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n }\n ],\n \"subType\": \"\",\n \"descriptionText\": \"\",\n \"requestDate\": \"\",\n \"requestingOrganisationTransactionReference\": \"\",\n \"oneTimeCode\": \"\",\n \"geoCode\": \"37.423825,-122.082900\",\n \"senderKyc\": {\n \"nationality\": \"\",\n \"dateOfBirth\": \"2000-11-20\",\n \"occupation\": \"\",\n \"employerName\": \"\",\n \"contactPhone\": \"\",\n \"gender\": \"\",\n \"idDocument\": [\n {\n \"idType\": \"\",\n \"idNumber\": \"\",\n \"issueDate\": \"2018-11-20\",\n \"expiryDate\": \"2018-11-20\",\n \"issuer\": \"\",\n \"issuerPlace\": \"\",\n \"issuerCountry\": \"\",\n \"otherIddescription\": \"\"\n },\n {\n \"idType\": \"\",\n \"idNumber\": \"\",\n \"issueDate\": \"2018-11-20\",\n \"expiryDate\": \"2018-11-20\",\n \"issuer\": \"\",\n \"issuerPlace\": \"\",\n \"issuerCountry\": \"\",\n \"otherIddescription\": \"\"\n }\n ],\n \"postalAddress\": {\n \"country\": \"\",\n \"addressLine1\": \"\",\n \"addressLine2\": \"\",\n \"addressLine3\": \"\",\n \"city\": \"\",\n \"stateProvince\": \"\",\n \"postalCode\": \"\"\n },\n \"subjectName\": {\n \"title\": \"\",\n \"firstName\": \"\",\n \"middleName\": \"\",\n \"lastName\": \"\",\n \"fullName\": \"\",\n \"nativeName\": \"\"\n },\n \"emailAddress\": \"\",\n \"birthCountry\": \"\"\n },\n \"recipientKyc\": {\n \"nationality\": \"\",\n \"dateOfBirth\": \"2000-11-20\",\n \"occupation\": \"\",\n \"employerName\": \"\",\n \"contactPhone\": \"\",\n \"gender\": \"\",\n \"idDocument\": [\n {\n \"idType\": \"\",\n \"idNumber\": \"\",\n \"issueDate\": \"2018-11-20\",\n \"expiryDate\": \"2018-11-20\",\n \"issuer\": \"\",\n \"issuerPlace\": \"\",\n \"issuerCountry\": \"\",\n \"otherIddescription\": \"\"\n },\n {\n \"idType\": \"\",\n \"idNumber\": \"\",\n \"issueDate\": \"2018-11-20\",\n \"expiryDate\": \"2018-11-20\",\n \"issuer\": \"\",\n \"issuerPlace\": \"\",\n \"issuerCountry\": \"\",\n \"otherIddescription\": \"\"\n }\n ],\n \"postalAddress\": {\n \"country\": \"\",\n \"addressLine1\": \"\",\n \"addressLine2\": \"\",\n \"addressLine3\": \"\",\n \"city\": \"\",\n \"stateProvince\": \"\",\n \"postalCode\": \"\"\n },\n \"subjectName\": {\n \"title\": \"\",\n \"firstName\": \"\",\n \"middleName\": \"\",\n \"lastName\": \"\",\n \"fullName\": \"\",\n \"nativeName\": \"\"\n },\n \"emailAddress\": \"\",\n \"birthCountry\": \"\"\n },\n \"originalTransactionReference\": \"\",\n \"servicingIdentity\": \"\",\n \"fees\": [\n {\n \"feeType\": \"\",\n \"feeCurrency\": \"\",\n \"feeAmount\": \"15.21\"\n },\n {\n \"feeType\": \"\",\n \"feeCurrency\": \"\",\n \"feeAmount\": \"15.21\"\n }\n ],\n \"requestingLei\": \"54930084UKLVMY22DS16\",\n \"receivingLei\": \"5493000IBP32UQZ0KL24\",\n \"metadata\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ],\n \"creationDate\": \"\",\n \"modificationDate\": \"\",\n \"dateCreated\": \"\",\n \"dateModified\": \"\",\n \"transactionReceipt\": \"\",\n \"internationalTransferInformation\": {\n \"originCountry\": \"\",\n \"quotationReference\": \"\",\n \"quoteId\": \"\",\n \"receivingCountry\": \"\",\n \"remittancePurpose\": \"\",\n \"relationshipSender\": \"\",\n \"deliveryMethod\": \"\",\n \"senderBlockingReason\": \"\",\n \"recipientBlockingReason\": \"\"\n }\n },\n {\n \"amount\": \"15.21\",\n \"currency\": \"\",\n \"type\": \"\",\n \"transactionReference\": \"\",\n \"transactionStatus\": \"\",\n \"debitParty\": [\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n },\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n }\n ],\n \"creditParty\": [\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n },\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n }\n ],\n \"subType\": \"\",\n \"descriptionText\": \"\",\n \"requestDate\": \"\",\n \"requestingOrganisationTransactionReference\": \"\",\n \"oneTimeCode\": \"\",\n \"geoCode\": \"37.423825,-122.082900\",\n \"senderKyc\": {\n \"nationality\": \"\",\n \"dateOfBirth\": \"2000-11-20\",\n \"occupation\": \"\",\n \"employerName\": \"\",\n \"contactPhone\": \"\",\n \"gender\": \"\",\n \"idDocument\": [\n {\n \"idType\": \"\",\n \"idNumber\": \"\",\n \"issueDate\": \"2018-11-20\",\n \"expiryDate\": \"2018-11-20\",\n \"issuer\": \"\",\n \"issuerPlace\": \"\",\n \"issuerCountry\": \"\",\n \"otherIddescription\": \"\"\n },\n {\n \"idType\": \"\",\n \"idNumber\": \"\",\n \"issueDate\": \"2018-11-20\",\n \"expiryDate\": \"2018-11-20\",\n \"issuer\": \"\",\n \"issuerPlace\": \"\",\n \"issuerCountry\": \"\",\n \"otherIddescription\": \"\"\n }\n ],\n \"postalAddress\": {\n \"country\": \"\",\n \"addressLine1\": \"\",\n \"addressLine2\": \"\",\n \"addressLine3\": \"\",\n \"city\": \"\",\n \"stateProvince\": \"\",\n \"postalCode\": \"\"\n },\n \"subjectName\": {\n \"title\": \"\",\n \"firstName\": \"\",\n \"middleName\": \"\",\n \"lastName\": \"\",\n \"fullName\": \"\",\n \"nativeName\": \"\"\n },\n \"emailAddress\": \"\",\n \"birthCountry\": \"\"\n },\n \"recipientKyc\": {\n \"nationality\": \"\",\n \"dateOfBirth\": \"2000-11-20\",\n \"occupation\": \"\",\n \"employerName\": \"\",\n \"contactPhone\": \"\",\n \"gender\": \"\",\n \"idDocument\": [\n {\n \"idType\": \"\",\n \"idNumber\": \"\",\n \"issueDate\": \"2018-11-20\",\n \"expiryDate\": \"2018-11-20\",\n \"issuer\": \"\",\n \"issuerPlace\": \"\",\n \"issuerCountry\": \"\",\n \"otherIddescription\": \"\"\n },\n {\n \"idType\": \"\",\n \"idNumber\": \"\",\n \"issueDate\": \"2018-11-20\",\n \"expiryDate\": \"2018-11-20\",\n \"issuer\": \"\",\n \"issuerPlace\": \"\",\n \"issuerCountry\": \"\",\n \"otherIddescription\": \"\"\n }\n ],\n \"postalAddress\": {\n \"country\": \"\",\n \"addressLine1\": \"\",\n \"addressLine2\": \"\",\n \"addressLine3\": \"\",\n \"city\": \"\",\n \"stateProvince\": \"\",\n \"postalCode\": \"\"\n },\n \"subjectName\": {\n \"title\": \"\",\n \"firstName\": \"\",\n \"middleName\": \"\",\n \"lastName\": \"\",\n \"fullName\": \"\",\n \"nativeName\": \"\"\n },\n \"emailAddress\": \"\",\n \"birthCountry\": \"\"\n },\n \"originalTransactionReference\": \"\",\n \"servicingIdentity\": \"\",\n \"fees\": [\n {\n \"feeType\": \"\",\n \"feeCurrency\": \"\",\n \"feeAmount\": \"15.21\"\n },\n {\n \"feeType\": \"\",\n \"feeCurrency\": \"\",\n \"feeAmount\": \"15.21\"\n }\n ],\n \"requestingLei\": \"54930084UKLVMY22DS16\",\n \"receivingLei\": \"5493000IBP32UQZ0KL24\",\n \"metadata\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ],\n \"creationDate\": \"\",\n \"modificationDate\": \"\",\n \"dateCreated\": \"\",\n \"dateModified\": \"\",\n \"transactionReceipt\": \"\",\n \"internationalTransferInformation\": {\n \"originCountry\": \"\",\n \"quotationReference\": \"\",\n \"quoteId\": \"\",\n \"receivingCountry\": \"\",\n \"remittancePurpose\": \"\",\n \"relationshipSender\": \"\",\n \"deliveryMethod\": \"\",\n \"senderBlockingReason\": \"\",\n \"recipientBlockingReason\": \"\"\n }\n }\n]" + }, + { + "id": "93328e3c-01c9-4af2-b1a9-e4f2701872a2", + "name": "Represents an Error Caused by an Authorisation Failure", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/transactions?limit=&offset=&fromDateTime=&toDateTime=&transactionStatus=&transactionType=", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "transactions" + ], + "query": [ + { + "key": "limit", + "value": "" + }, + { + "key": "offset", + "value": "" + }, + { + "key": "fromDateTime", + "value": "" + }, + { + "key": "toDateTime", + "value": "" + }, + { + "key": "transactionStatus", + "value": "" + }, + { + "key": "transactionType", + "value": "" + } + ], + "variable": [ + { + "key": "accountId" + } + ] + } + }, + "status": "Unauthorized", + "code": 401, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "24f32653-1710-4ced-a3b9-2f3fbef09346", + "name": "Represents an Error Caused by a Failure to Identify the Target Resource", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/transactions?limit=&offset=&fromDateTime=&toDateTime=&transactionStatus=&transactionType=", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "transactions" + ], + "query": [ + { + "key": "limit", + "value": "" + }, + { + "key": "offset", + "value": "" + }, + { + "key": "fromDateTime", + "value": "" + }, + { + "key": "toDateTime", + "value": "" + }, + { + "key": "transactionStatus", + "value": "" + }, + { + "key": "transactionType", + "value": "" + } + ], + "variable": [ + { + "key": "accountId" + } + ] + } + }, + "status": "Not Found", + "code": 404, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "7e2e5cdd-11c8-41d2-a910-6cccfe484040", + "name": "Represents an Error Caused by a General Server-Side Issue", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/transactions?limit=&offset=&fromDateTime=&toDateTime=&transactionStatus=&transactionType=", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "transactions" + ], + "query": [ + { + "key": "limit", + "value": "" + }, + { + "key": "offset", + "value": "" + }, + { + "key": "fromDateTime", + "value": "" + }, + { + "key": "toDateTime", + "value": "" + }, + { + "key": "transactionStatus", + "value": "" + }, + { + "key": "transactionType", + "value": "" + } + ], + "variable": [ + { + "key": "accountId" + } + ] + } + }, + "status": "Internal Server Error", + "code": 500, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + } + ] + }, + { + "name": "View Account Statements", + "id": "a6ad0e2e-0dc0-490f-83aa-abb33d6a078d", + "request": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/statemententries?limit=&offset=&fromDateTime=&toDateTime=&transactionStatus=&displayType=", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "statemententries" + ], + "query": [ + { + "key": "limit", + "value": "", + "description": "Supports pagination. If this is not supplied, then the server will apply a limit of 50 records returned for each request." + }, + { + "key": "offset", + "value": "", + "description": "Supports pagination. This value will indicate the cursor position from where to retrieve the set of records. For example, a limit of 50 and offset of 10 will return records 11 to 60." + }, + { + "key": "fromDateTime", + "value": "", + "description": "Indicates the minimum date for which records should be returned." + }, + { + "key": "toDateTime", + "value": "", + "description": "Indicates the maximum date for which records should be returned." + }, + { + "key": "transactionStatus", + "value": "", + "description": "Query variable to uniquely identify the transaction status." + }, + { + "key": "displayType", + "value": "", + "description": "Query parameter to to identify the display type of the statement entries to be returned." + } + ], + "variable": [ + { + "id": "0b68370c-f4a5-4500-bf73-79a82d463be6", + "key": "accountId", + "value": "", + "description": "(Required) Path variable to uniquely identify an account. Up to three account identifiers can be supplied. Identifiers are delimited by $ and values are delimited by @. Example: organisationid@1234$accountid@3333. Valid account identifiers are accountcategory, bankaccountno, accountrank, identityalias, iban, accountid, msisdn, swiftbic, sortcode, organisationid, username, walletid, linkref, consumerno, serviceprovider, storeid, bankname, bankaccounttitle, emailaddress, mandatereference." + } + ] + }, + "description": "The Statement Entries API enables generic representations of transactions to be returned. Typically, the returned representations are used for the purposes of presenting a statement to the account holder. In order to return a statement, an account must be specified." + }, + "response": [ + { + "id": "c95aef59-d4be-46d5-9c71-571e12e296cc", + "name": "Represents an Error Caused by System Unavailability", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/statemententries?limit=&offset=&fromDateTime=&toDateTime=&transactionStatus=&displayType=", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "statemententries" + ], + "query": [ + { + "key": "limit", + "value": "" + }, + { + "key": "offset", + "value": "" + }, + { + "key": "fromDateTime", + "value": "" + }, + { + "key": "toDateTime", + "value": "" + }, + { + "key": "transactionStatus", + "value": "" + }, + { + "key": "displayType", + "value": "" + } + ], + "variable": [ + { + "key": "accountId" + } + ] + } + }, + "status": "Service Unavailable", + "code": 503, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "4dff6303-48ec-458b-bd5d-5ef03bf5da60", + "name": "Represents an Error Caused by a Failure to Identify the Target Resource", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/statemententries?limit=&offset=&fromDateTime=&toDateTime=&transactionStatus=&displayType=", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "statemententries" + ], + "query": [ + { + "key": "limit", + "value": "" + }, + { + "key": "offset", + "value": "" + }, + { + "key": "fromDateTime", + "value": "" + }, + { + "key": "toDateTime", + "value": "" + }, + { + "key": "transactionStatus", + "value": "" + }, + { + "key": "displayType", + "value": "" + } + ], + "variable": [ + { + "key": "accountId" + } + ] + } + }, + "status": "Not Found", + "code": 404, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "61aa3748-bb58-434c-8ace-29776f44d0ff", + "name": "Represents an Error Caused by the Violation of a Business Rule", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/statemententries?limit=&offset=&fromDateTime=&toDateTime=&transactionStatus=&displayType=", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "statemententries" + ], + "query": [ + { + "key": "limit", + "value": "" + }, + { + "key": "offset", + "value": "" + }, + { + "key": "fromDateTime", + "value": "" + }, + { + "key": "toDateTime", + "value": "" + }, + { + "key": "transactionStatus", + "value": "" + }, + { + "key": "displayType", + "value": "" + } + ], + "variable": [ + { + "key": "accountId" + } + ] + } + }, + "status": "Bad Request", + "code": 400, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "6130ad46-afed-429d-9687-dc4f3cf90e05", + "name": "Represents an Error Caused by an Authorisation Failure", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/statemententries?limit=&offset=&fromDateTime=&toDateTime=&transactionStatus=&displayType=", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "statemententries" + ], + "query": [ + { + "key": "limit", + "value": "" + }, + { + "key": "offset", + "value": "" + }, + { + "key": "fromDateTime", + "value": "" + }, + { + "key": "toDateTime", + "value": "" + }, + { + "key": "transactionStatus", + "value": "" + }, + { + "key": "displayType", + "value": "" + } + ], + "variable": [ + { + "key": "accountId" + } + ] + } + }, + "status": "Unauthorized", + "code": 401, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "21492fad-1e0c-4d53-bffa-4c5d6c36c0b9", + "name": "Represent a list of Statement Entries", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/statemententries?limit=&offset=&fromDateTime=&toDateTime=&transactionStatus=&displayType=", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "statemententries" + ], + "query": [ + { + "key": "limit", + "value": "" + }, + { + "key": "offset", + "value": "" + }, + { + "key": "fromDateTime", + "value": "" + }, + { + "key": "toDateTime", + "value": "" + }, + { + "key": "transactionStatus", + "value": "" + }, + { + "key": "displayType", + "value": "" + } + ], + "variable": [ + { + "key": "accountId" + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "X-Records-Available-Count", + "value": "", + "description": "Integer containing number of records that are available to be returned." + }, + { + "key": "X-Records-Returned-Count", + "value": "", + "description": "Integer containing number of records that are returned." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "[\n {\n \"amount\": \"15.21\",\n \"creditParty\": [\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n },\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n }\n ],\n \"currency\": \"\",\n \"debitParty\": [\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n },\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n }\n ],\n \"transactionReference\": \"\",\n \"transactionStatus\": \"\",\n \"displayType\": \"\",\n \"descriptionText\": \"\",\n \"requestDate\": \"\",\n \"creationDate\": \"\",\n \"modificationDate\": \"\",\n \"dateCreated\": \"\",\n \"dateModified\": \"\",\n \"transactionReceipt\": \"\"\n },\n {\n \"amount\": \"15.21\",\n \"creditParty\": [\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n },\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n }\n ],\n \"currency\": \"\",\n \"debitParty\": [\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n },\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n }\n ],\n \"transactionReference\": \"\",\n \"transactionStatus\": \"\",\n \"displayType\": \"\",\n \"descriptionText\": \"\",\n \"requestDate\": \"\",\n \"creationDate\": \"\",\n \"modificationDate\": \"\",\n \"dateCreated\": \"\",\n \"dateModified\": \"\",\n \"transactionReceipt\": \"\"\n }\n]" + }, + { + "id": "54e98986-2280-45b7-9042-17c4af85bafb", + "name": "Represents an Error Caused by a General Server-Side Issue", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/statemententries?limit=&offset=&fromDateTime=&toDateTime=&transactionStatus=&displayType=", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "statemententries" + ], + "query": [ + { + "key": "limit", + "value": "" + }, + { + "key": "offset", + "value": "" + }, + { + "key": "fromDateTime", + "value": "" + }, + { + "key": "toDateTime", + "value": "" + }, + { + "key": "transactionStatus", + "value": "" + }, + { + "key": "displayType", + "value": "" + } + ], + "variable": [ + { + "key": "accountId" + } + ] + } + }, + "status": "Internal Server Error", + "code": 500, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + } + ] + }, + { + "name": "View Bill Companies", + "id": "b3373767-ad56-4166-8d45-65d816e06f73", + "request": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/billcompanies?limit=&offset=", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "billcompanies" + ], + "query": [ + { + "key": "limit", + "value": "", + "description": "Supports pagination. If this is not supplied, then the server will apply a limit of 50 records returned for each request." + }, + { + "key": "offset", + "value": "", + "description": "Supports pagination. This value will indicate the cursor position from where to retrieve the set of records. For example, a limit of 50 and offset of 10 will return records 11 to 60." + } + ], + "variable": [ + { + "id": "78288cff-109f-4e57-af88-e4700ad5cede", + "key": "accountId", + "value": "", + "description": "(Required) Path variable to uniquely identify an account. Up to three account identifiers can be supplied. Identifiers are delimited by $ and values are delimited by @. Example: organisationid@1234$accountid@3333. Valid account identifiers are accountcategory, bankaccountno, accountrank, identityalias, iban, accountid, msisdn, swiftbic, sortcode, organisationid, username, walletid, linkref, consumerno, serviceprovider, storeid, bankname, bankaccounttitle, emailaddress, mandatereference." + } + ] + }, + "description": "This Bill Companies API is used to return a list of Service Providers that accept Bill Payments for a given account." + }, + "response": [ + { + "id": "f65dd196-64a6-468c-b629-b1b141eab584", + "name": "Represents an Error Caused by an Authorisation Failure", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/billcompanies?limit=&offset=", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "billcompanies" + ], + "query": [ + { + "key": "limit", + "value": "" + }, + { + "key": "offset", + "value": "" + } + ], + "variable": [ + { + "key": "accountId" + } + ] + } + }, + "status": "Unauthorized", + "code": 401, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "060ec2d8-1b6b-45a4-a954-8c9c52ce2e44", + "name": "Represent a list of Bill Companies", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/billcompanies?limit=&offset=", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "billcompanies" + ], + "query": [ + { + "key": "limit", + "value": "" + }, + { + "key": "offset", + "value": "" + } + ], + "variable": [ + { + "key": "accountId" + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "[\n {\n \"companyName\": \"\",\n \"serviceProvider\": \"\",\n \"serviceProviderType\": \"\",\n \"serviceProviderSubType\": \"\",\n \"supplementaryServiceProviderDetails\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n },\n {\n \"companyName\": \"\",\n \"serviceProvider\": \"\",\n \"serviceProviderType\": \"\",\n \"serviceProviderSubType\": \"\",\n \"supplementaryServiceProviderDetails\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n }\n]" + }, + { + "id": "c38623ac-9de3-48ca-9595-6068adc49bcb", + "name": "Represents an Error Caused by System Unavailability", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/billcompanies?limit=&offset=", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "billcompanies" + ], + "query": [ + { + "key": "limit", + "value": "" + }, + { + "key": "offset", + "value": "" + } + ], + "variable": [ + { + "key": "accountId" + } + ] + } + }, + "status": "Service Unavailable", + "code": 503, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "09f9e1b5-1ba5-4d10-8ed5-2ce647abdb27", + "name": "Represents an Error Caused by a General Server-Side Issue", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/billcompanies?limit=&offset=", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "billcompanies" + ], + "query": [ + { + "key": "limit", + "value": "" + }, + { + "key": "offset", + "value": "" + } + ], + "variable": [ + { + "key": "accountId" + } + ] + } + }, + "status": "Internal Server Error", + "code": 500, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "b21b6619-14e1-4653-bb5e-be66953fcdae", + "name": "Represents an Error Caused by the Violation of a Business Rule", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/billcompanies?limit=&offset=", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "billcompanies" + ], + "query": [ + { + "key": "limit", + "value": "" + }, + { + "key": "offset", + "value": "" + } + ], + "variable": [ + { + "key": "accountId" + } + ] + } + }, + "status": "Bad Request", + "code": 400, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "6d4ed3e1-6166-4b97-ac04-e066f6420478", + "name": "Represents an Error Caused by a Failure to Identify the Target Resource", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/billcompanies?limit=&offset=", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "billcompanies" + ], + "query": [ + { + "key": "limit", + "value": "" + }, + { + "key": "offset", + "value": "" + } + ], + "variable": [ + { + "key": "accountId" + } + ] + } + }, + "status": "Not Found", + "code": 404, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + } + ] + } + ], + "id": "cbb15822-e342-49cd-9e98-7fbbd22f0808" + }, + { + "name": "{identifier Type}/{identifier}", + "item": [ + { + "name": "bills", + "item": [ + { + "name": "View Account Bills", + "id": "f1c20f12-51ae-429d-98d7-88e15071bd6f", + "request": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/bills", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "bills" + ], + "variable": [ + { + "id": "db1fcb65-f86c-4a1f-a784-3b33a63d8b2e", + "key": "identifierType", + "value": "", + "description": "(Required) Path variable to specify the type of the identifier that is used to identify the account." + }, + { + "id": "686d313d-6892-45d8-99c1-80e652bc3ecd", + "key": "identifier", + "value": "", + "description": "(Required) Path variable that contains the account identifier." + } + ] + }, + "description": "This endpoint returns bills linked to an account." + }, + "response": [ + { + "id": "34901fc5-b006-4fa2-838c-f27bda404ce9", + "name": "Represent a list of Bills", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/bills", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "bills" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "[\n {\n \"currency\": \"\",\n \"amountDue\": \"15.21\",\n \"dueDate\": \"2018-11-20\",\n \"billReference\": \"\",\n \"minimumAmountDue\": \"15.21\",\n \"billdescription\": \"\",\n \"billStatus\": \"\",\n \"metadata\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n },\n {\n \"currency\": \"\",\n \"amountDue\": \"15.21\",\n \"dueDate\": \"2018-11-20\",\n \"billReference\": \"\",\n \"minimumAmountDue\": \"15.21\",\n \"billdescription\": \"\",\n \"billStatus\": \"\",\n \"metadata\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n }\n]" + }, + { + "id": "e452c4fb-d77d-4d8b-b328-cc5af6e14479", + "name": "Represents an Error Caused by the Violation of a Business Rule", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/bills", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "bills" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + } + ] + } + }, + "status": "Bad Request", + "code": 400, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "000b649e-7db1-4edc-a393-bbf0b39d334e", + "name": "Represents an Error Caused by an Authorisation Failure", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/bills", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "bills" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + } + ] + } + }, + "status": "Unauthorized", + "code": 401, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "368dc00f-0c79-48c2-b0c8-87e92948ebd0", + "name": "Represents an Error Caused by a Failure to Identify the Target Resource", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/bills", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "bills" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + } + ] + } + }, + "status": "Not Found", + "code": 404, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "939f3b29-000a-474f-9dd2-34f61136104f", + "name": "Represents an Error Caused by a General Server-Side Issue", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/bills", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "bills" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + } + ] + } + }, + "status": "Internal Server Error", + "code": 500, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "220bede6-9d28-4942-a9d7-b4967f16aeec", + "name": "Represents an Error Caused by System Unavailability", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/bills", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "bills" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + } + ] + } + }, + "status": "Service Unavailable", + "code": 503, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + } + ] + }, + { + "name": "Create A Bill Payment", + "id": "e847d6f4-81eb-40ad-8793-cddf26b28d49", + "request": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"currency\": \"\",\n \"amountPaid\": \"\",\n \"paidAmount\": \"\",\n \"serviceProviderPaymentReference\": \"\",\n \"requestingOrganisation\": \"\",\n \"requestingOrganisationTransactionReference\": \"\",\n \"customerReference\": \"\",\n \"paymentType\": \"\",\n \"supplementaryBillReferenceDetails\": [\n {\n \"paymentReferenceType\": \"\",\n \"paymentReferenceValue\": \"\"\n },\n {\n \"paymentReferenceType\": \"\",\n \"paymentReferenceValue\": \"\"\n }\n ],\n \"metadata\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/bills/:billReference/payments", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "bills", + ":billReference", + "payments" + ], + "variable": [ + { + "id": "e8554b34-729d-496c-8cbb-903f341f245b", + "key": "identifierType", + "value": "", + "description": "(Required) Path variable to specify the type of the identifier that is used to identify the account." + }, + { + "id": "00113f3f-4409-4d23-b1c8-b6429cc9b265", + "key": "identifier", + "value": "", + "description": "(Required) Path variable that contains the account identifier." + }, + { + "id": "414173be-8d61-4263-b3b2-39ddacb3dfaf", + "key": "billReference", + "value": "", + "description": "(Required) Path variable to uniquely identify a bill." + } + ] + }, + "description": "Provided with a valid object representation, this endpoint allows for a new bill payment to be created for a specific account." + }, + "response": [ + { + "id": "58cd56a5-afad-468a-9186-186319aa2010", + "name": "Represents an Error Caused by a Failure to Identify the Target Resource", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/bills/:billReference/payments", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "bills", + ":billReference", + "payments" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + }, + { + "key": "billReference" + } + ] + } + }, + "status": "Not Found", + "code": 404, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "42fd0998-4936-4953-89be-e76aca1caa11", + "name": "Represents a Bill Payment response", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/bills/:billReference/payments", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "bills", + ":billReference", + "payments" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + }, + { + "key": "billReference" + } + ] + } + }, + "status": "Created", + "code": 201, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"currency\": \"\",\n \"amountPaid\": \"15.21\",\n \"billPaymentStatus\": \"\",\n \"paidAmount\": \"15.21\",\n \"serviceProviderPaymentReference\": \"\",\n \"requestingOrganisation\": \"\",\n \"requestingOrganisationTransactionReference\": \"\",\n \"customerReference\": \"\",\n \"paymentType\": \"\",\n \"serviceProviderComment\": \"\",\n \"serviceProviderNotification\": \"\",\n \"supplementaryBillReferenceDetails\": [\n {\n \"paymentReferenceType\": \"\",\n \"paymentReferenceValue\": \"\"\n },\n {\n \"paymentReferenceType\": \"\",\n \"paymentReferenceValue\": \"\"\n }\n ],\n \"metadata\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "f956f6f6-f3a3-4fae-b9a6-b7f4b793bc93", + "name": "Represents an Error Caused by System Unavailability", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/bills/:billReference/payments", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "bills", + ":billReference", + "payments" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + }, + { + "key": "billReference" + } + ] + } + }, + "status": "Service Unavailable", + "code": 503, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "b941002a-9004-4608-843e-04cc013bc477", + "name": "Represents an Asynchronous response", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/bills/:billReference/payments", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "bills", + ":billReference", + "payments" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + }, + { + "key": "billReference" + } + ] + } + }, + "status": "Accepted", + "code": 202, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"notificationMethod\": \"\",\n \"serverCorrelationId\": \"\",\n \"status\": \"\",\n \"pendingReason\": \"\",\n \"objectReference\": \"\",\n \"expiryTime\": \"\",\n \"pollLimit\": \"\",\n \"error\": {\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n }\n}" + }, + { + "id": "52bf9018-50fa-471d-b9ac-91c0ac42c196", + "name": "Represents an Error Caused by an Authorisation Failure", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/bills/:billReference/payments", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "bills", + ":billReference", + "payments" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + }, + { + "key": "billReference" + } + ] + } + }, + "status": "Unauthorized", + "code": 401, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "52bbd69f-92a7-47b0-8bc9-7b07960996d9", + "name": "Represents an Error Caused by the Violation of a Business Rule", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/bills/:billReference/payments", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "bills", + ":billReference", + "payments" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + }, + { + "key": "billReference" + } + ] + } + }, + "status": "Bad Request", + "code": 400, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "65c91324-a1a9-4028-8da4-4a2c1e263b72", + "name": "Represents an Error Caused by a General Server-Side Issue", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/bills/:billReference/payments", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "bills", + ":billReference", + "payments" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + }, + { + "key": "billReference" + } + ] + } + }, + "status": "Internal Server Error", + "code": 500, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + } + ] + } + ], + "id": "5f63b953-019d-473e-afc6-4ae98717da9b" + }, + { + "name": "debitmandates", + "item": [ + { + "name": "{debit Mandate Reference}", + "item": [ + { + "name": "View A Debit Mandate", + "id": "8e7e30cc-2e2d-46dd-8589-7329ea5557fe", + "request": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/debitmandates/:debitMandateReference", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "debitmandates", + ":debitMandateReference" + ], + "variable": [ + { + "id": "3a99e09b-5822-4dc2-9fdb-e87fc2f5a83e", + "key": "identifierType", + "value": "", + "description": "(Required) Path variable to specify the type of the identifier that is used to identify the account." + }, + { + "id": "20ae3cc7-cae1-429f-9dab-173591349004", + "key": "identifier", + "value": "", + "description": "(Required) Path variable that contains the account identifier." + }, + { + "id": "0ed6e69c-7bf6-4519-9480-4dfd1b9de459", + "key": "debitMandateReference", + "value": "", + "description": "(Required) Path variable to uniquely identify a Debit Mandate Reference." + } + ] + }, + "description": "This endpoint returns a specific debit mandate linked to an account." + }, + "response": [ + { + "id": "aad4ee06-2794-4df6-a83e-72c63918565c", + "name": "Represents a Debit Mandate response", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/debitmandates/:debitMandateReference", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "debitmandates", + ":debitMandateReference" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + }, + { + "key": "debitMandateReference" + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"mandateReference\": \"\",\n \"currency\": \"\",\n \"amountLimit\": \"15.21\",\n \"startDate\": \"2018-11-20\",\n \"endDate\": \"2018-11-20\",\n \"numberOfPayments\": \"\",\n \"frequencyType\": \"\",\n \"mandateStatus\": \"\",\n \"requestDate\": \"\",\n \"creationDate\": \"\",\n \"modificationDate\": \"\",\n \"dateCreated\": \"\",\n \"dateModified\": \"\"\n}" + }, + { + "id": "7867a833-703c-4fc5-9a6c-a9c29013e391", + "name": "Represents an Error Caused by System Unavailability", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/debitmandates/:debitMandateReference", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "debitmandates", + ":debitMandateReference" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + }, + { + "key": "debitMandateReference" + } + ] + } + }, + "status": "Service Unavailable", + "code": 503, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "67f47962-d5f4-424d-b35e-38a3ccdcf882", + "name": "Represents an Error Caused by an Authorisation Failure", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/debitmandates/:debitMandateReference", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "debitmandates", + ":debitMandateReference" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + }, + { + "key": "debitMandateReference" + } + ] + } + }, + "status": "Unauthorized", + "code": 401, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "64924af9-7088-4bb6-85e1-10ea8b197e2b", + "name": "Represents an Error Caused by a Failure to Identify the Target Resource", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/debitmandates/:debitMandateReference", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "debitmandates", + ":debitMandateReference" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + }, + { + "key": "debitMandateReference" + } + ] + } + }, + "status": "Not Found", + "code": 404, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "5e5b5f44-5706-4fc5-8cca-c0ff3363f357", + "name": "Represents an Error Caused by the Violation of a Business Rule", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/debitmandates/:debitMandateReference", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "debitmandates", + ":debitMandateReference" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + }, + { + "key": "debitMandateReference" + } + ] + } + }, + "status": "Bad Request", + "code": 400, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "f4a3fe04-616b-4ead-b18d-1d931fb9fbdd", + "name": "Represents an Error Caused by a General Server-Side Issue", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/debitmandates/:debitMandateReference", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "debitmandates", + ":debitMandateReference" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + }, + { + "key": "debitMandateReference" + } + ] + } + }, + "status": "Internal Server Error", + "code": 500, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + } + ] + }, + { + "name": "Update A Debit Mandate", + "id": "2560dfab-d18d-4d7b-a403-56e3cb9d89c0", + "request": { + "method": "PATCH", + "header": [ + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "[\n {\n \"op\": \"\",\n \"path\": \"\",\n \"value\": \"\"\n },\n {\n \"op\": \"\",\n \"path\": \"\",\n \"value\": \"\"\n }\n]" + }, + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/debitmandates/:debitMandateReference", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "debitmandates", + ":debitMandateReference" + ], + "variable": [ + { + "id": "6c6d3001-9cd1-4ba3-9a2f-92aa3ffefe1d", + "key": "identifierType", + "value": "", + "description": "(Required) Path variable to specify the type of the identifier that is used to identify the account." + }, + { + "id": "ac2b3c8b-666f-4f93-807b-78ef7ce22c27", + "key": "identifier", + "value": "", + "description": "(Required) Path variable that contains the account identifier." + }, + { + "id": "7280cf1a-97e3-447d-9cc6-6c32c7020568", + "key": "debitMandateReference", + "value": "", + "description": "(Required) Path variable to uniquely identify a Debit Mandate Reference." + } + ] + }, + "description": "This endpoint updates a specific debit mandate linked to an account." + }, + "response": [ + { + "id": "241bb811-44c6-4fe2-936f-a1c4d225a1d7", + "name": "Represents an Error Caused by an Authorisation Failure", + "originalRequest": { + "method": "PATCH", + "header": [ + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/debitmandates/:debitMandateReference", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "debitmandates", + ":debitMandateReference" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + }, + { + "key": "debitMandateReference" + } + ] + } + }, + "status": "Unauthorized", + "code": 401, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "4c919d3e-9e4a-447d-99c2-a3a829c5befb", + "name": "Represents an Error Caused by a General Server-Side Issue", + "originalRequest": { + "method": "PATCH", + "header": [ + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/debitmandates/:debitMandateReference", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "debitmandates", + ":debitMandateReference" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + }, + { + "key": "debitMandateReference" + } + ] + } + }, + "status": "Internal Server Error", + "code": 500, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "cac92990-2d06-415f-88ae-cd3930b6616a", + "name": "Represents an Error Caused by the Violation of a Business Rule", + "originalRequest": { + "method": "PATCH", + "header": [ + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/debitmandates/:debitMandateReference", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "debitmandates", + ":debitMandateReference" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + }, + { + "key": "debitMandateReference" + } + ] + } + }, + "status": "Bad Request", + "code": 400, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "20c956de-2d06-43f2-b70b-a5a686442ddc", + "name": "Represents an Error Caused by System Unavailability", + "originalRequest": { + "method": "PATCH", + "header": [ + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/debitmandates/:debitMandateReference", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "debitmandates", + ":debitMandateReference" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + }, + { + "key": "debitMandateReference" + } + ] + } + }, + "status": "Service Unavailable", + "code": 503, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "b3e63e41-d848-4cd9-a356-491b301bc59c", + "name": "Represents an Asynchronous response", + "originalRequest": { + "method": "PATCH", + "header": [ + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/debitmandates/:debitMandateReference", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "debitmandates", + ":debitMandateReference" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + }, + { + "key": "debitMandateReference" + } + ] + } + }, + "status": "Accepted", + "code": 202, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"notificationMethod\": \"\",\n \"serverCorrelationId\": \"\",\n \"status\": \"\",\n \"pendingReason\": \"\",\n \"objectReference\": \"\",\n \"expiryTime\": \"\",\n \"pollLimit\": \"\",\n \"error\": {\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n }\n}" + }, + { + "id": "9d8d8693-6ee0-4d3f-86b0-ee30a56db130", + "name": "Represents an Error Caused by a Failure to Identify the Target Resource", + "originalRequest": { + "method": "PATCH", + "header": [ + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/debitmandates/:debitMandateReference", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "debitmandates", + ":debitMandateReference" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + }, + { + "key": "debitMandateReference" + } + ] + } + }, + "status": "Not Found", + "code": 404, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "77aa2aa1-909d-4613-b64d-587a3783b7d4", + "name": "An empty response is returned for a synchronous successful patch.", + "originalRequest": { + "method": "PATCH", + "header": [ + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/debitmandates/:debitMandateReference", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "debitmandates", + ":debitMandateReference" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + }, + { + "key": "debitMandateReference" + } + ] + } + }, + "status": "No Content", + "code": 204, + "_postman_previewlanguage": "text", + "header": [ + { + "key": "Content-Type", + "value": "text/plain" + } + ], + "cookie": [], + "body": "" + } + ] + } + ], + "id": "e2b73ad7-2fc8-4bc2-8af1-099d8a6ece1e" + }, + { + "name": "Create A Debit Mandate", + "id": "af52eb98-fe16-4bde-aa9b-65efb7b92c29", + "request": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"requestDate\": \"\",\n \"startDate\": \"\",\n \"currency\": \"\",\n \"amountLimit\": \"schema type not provided\",\n \"endDate\": \"\",\n \"numberOfPayments\": \"\",\n \"frequencyType\": \"\",\n \"mandateStatus\": \"\"\n}" + }, + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/debitmandates", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "debitmandates" + ], + "variable": [ + { + "id": "59d60305-7c6b-4b0b-b8d2-4b082b825272", + "key": "identifierType", + "value": "", + "description": "(Required) Path variable to specify the type of the identifier that is used to identify the account." + }, + { + "id": "dec24a30-c4d6-4978-b5b1-78c5cac79e6a", + "key": "identifier", + "value": "", + "description": "(Required) Path variable that contains the account identifier." + } + ] + }, + "description": "Provided with a valid object representation, this endpoint allows for a new debit mandate to be created for a specific account." + }, + "response": [ + { + "id": "9a1feca5-5f47-4894-8ebb-62d6e46d9320", + "name": "Represents an Error Caused by System Unavailability", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/debitmandates", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "debitmandates" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + } + ] + } + }, + "status": "Service Unavailable", + "code": 503, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "0d79f558-b96f-4a88-af00-c2ec6cd4d322", + "name": "Represents a Debit Mandate response", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/debitmandates", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "debitmandates" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + } + ] + } + }, + "status": "Created", + "code": 201, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"mandateReference\": \"\",\n \"currency\": \"\",\n \"amountLimit\": \"15.21\",\n \"startDate\": \"2018-11-20\",\n \"endDate\": \"2018-11-20\",\n \"numberOfPayments\": \"\",\n \"frequencyType\": \"\",\n \"mandateStatus\": \"\",\n \"requestDate\": \"\",\n \"creationDate\": \"\",\n \"modificationDate\": \"\",\n \"dateCreated\": \"\",\n \"dateModified\": \"\"\n}" + }, + { + "id": "9ae653cc-57f2-4fea-b43a-db77e55647a3", + "name": "Represents an Error Caused by an Authorisation Failure", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/debitmandates", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "debitmandates" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + } + ] + } + }, + "status": "Unauthorized", + "code": 401, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "5d5bf587-5696-4666-af0d-c0a13894c841", + "name": "Represents an Error Caused by a Failure to Identify the Target Resource", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/debitmandates", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "debitmandates" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + } + ] + } + }, + "status": "Not Found", + "code": 404, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "051870a0-f87a-4fad-b304-ce867169e7af", + "name": "Represents an Error Caused by a General Server-Side Issue", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/debitmandates", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "debitmandates" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + } + ] + } + }, + "status": "Internal Server Error", + "code": 500, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "292efab8-c86c-4edc-8874-e343ed94657f", + "name": "Represents an Error Caused by the Violation of a Business Rule", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/debitmandates", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "debitmandates" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + } + ] + } + }, + "status": "Bad Request", + "code": 400, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "11629946-cdef-48b7-9b79-8db0c6977156", + "name": "Represents an Asynchronous response", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/debitmandates", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "debitmandates" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + } + ] + } + }, + "status": "Accepted", + "code": 202, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"notificationMethod\": \"\",\n \"serverCorrelationId\": \"\",\n \"status\": \"\",\n \"pendingReason\": \"\",\n \"objectReference\": \"\",\n \"expiryTime\": \"\",\n \"pollLimit\": \"\",\n \"error\": {\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n }\n}" + } + ] + } + ], + "id": "e9f5feef-3ff0-4569-9a47-aa856c213d18" + }, + { + "name": "links", + "item": [ + { + "name": "{link Reference}", + "item": [ + { + "name": "View A Link", + "id": "904df70b-83d9-4fbf-9264-6a1cc0437770", + "request": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/links/:linkReference", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "links", + ":linkReference" + ], + "variable": [ + { + "id": "741cddef-e08e-4565-824c-967ba5b51394", + "key": "identifierType", + "value": "", + "description": "(Required) Path variable to specify the type of the identifier that is used to identify the account." + }, + { + "id": "ff89548e-4568-40ce-9787-48302cf49533", + "key": "identifier", + "value": "", + "description": "(Required) Path variable that contains the account identifier." + }, + { + "id": "a6e33280-f231-4a74-b0eb-9415334948e8", + "key": "linkReference", + "value": "", + "description": "(Required) Path variable to uniquely identify a link." + } + ] + }, + "description": "This endpoint returns a specific link for a given account." + }, + "response": [ + { + "id": "3b9d69e3-2e20-41c3-8ad1-f4075a088ca2", + "name": "Represents an Error Caused by System Unavailability", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/links/:linkReference", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "links", + ":linkReference" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + }, + { + "key": "linkReference" + } + ] + } + }, + "status": "Service Unavailable", + "code": 503, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "de9bae5d-223c-4a9f-ac8c-df8262524045", + "name": "Represents an Error Caused by the Violation of a Business Rule", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/links/:linkReference", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "links", + ":linkReference" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + }, + { + "key": "linkReference" + } + ] + } + }, + "status": "Bad Request", + "code": 400, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "2f0b2fea-6b7d-40a4-9f58-fd6d31c94b62", + "name": "Represents a Link response", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/links/:linkReference", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "links", + ":linkReference" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + }, + { + "key": "linkReference" + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"linkReference\": \"\",\n \"sourceAccountIdentifiers\": [\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n },\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n }\n ],\n \"status\": \"\",\n \"mode\": \"\"\n}" + }, + { + "id": "bb4fd5a0-1ccd-4197-9a76-e492ee5362bc", + "name": "Represents an Error Caused by a General Server-Side Issue", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/links/:linkReference", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "links", + ":linkReference" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + }, + { + "key": "linkReference" + } + ] + } + }, + "status": "Internal Server Error", + "code": 500, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "9c310eb4-9480-49ed-8dd5-03661d98f9d4", + "name": "Represents an Error Caused by a Failure to Identify the Target Resource", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/links/:linkReference", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "links", + ":linkReference" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + }, + { + "key": "linkReference" + } + ] + } + }, + "status": "Not Found", + "code": 404, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "b3bed71f-0ff0-446a-97de-9915cde0ee73", + "name": "Represents an Error Caused by an Authorisation Failure", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/links/:linkReference", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "links", + ":linkReference" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + }, + { + "key": "linkReference" + } + ] + } + }, + "status": "Unauthorized", + "code": 401, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + } + ] + }, + { + "name": "Update A Link", + "id": "00dae5ca-2ae5-4b1e-9861-92992407b039", + "request": { + "method": "PATCH", + "header": [ + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "[\n {\n \"op\": \"\",\n \"path\": \"\",\n \"value\": \"\"\n },\n {\n \"op\": \"\",\n \"path\": \"\",\n \"value\": \"\"\n }\n]" + }, + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/links/:linkReference", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "links", + ":linkReference" + ], + "variable": [ + { + "id": "9d4c64b8-28fd-4c63-a26a-655499eddfff", + "key": "identifierType", + "value": "", + "description": "(Required) Path variable to specify the type of the identifier that is used to identify the account." + }, + { + "id": "dcacc3f6-1da5-49b0-a634-c2543d108cb8", + "key": "identifier", + "value": "", + "description": "(Required) Path variable that contains the account identifier." + }, + { + "id": "e1bde203-ad90-40a6-b779-54c4baf70eaf", + "key": "linkReference", + "value": "", + "description": "(Required) Path variable to uniquely identify a link." + } + ] + }, + "description": "This endpoint updates a specific link.\"" + }, + "response": [ + { + "id": "ddce7238-b093-4d78-b208-12c8add0e7da", + "name": "Represents an Error Caused by the Violation of a Business Rule", + "originalRequest": { + "method": "PATCH", + "header": [ + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/links/:linkReference", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "links", + ":linkReference" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + }, + { + "key": "linkReference" + } + ] + } + }, + "status": "Bad Request", + "code": 400, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "d1d2c44d-e195-403b-a57a-ac2ded588c47", + "name": "Represents an Error Caused by System Unavailability", + "originalRequest": { + "method": "PATCH", + "header": [ + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/links/:linkReference", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "links", + ":linkReference" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + }, + { + "key": "linkReference" + } + ] + } + }, + "status": "Service Unavailable", + "code": 503, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "0450f5f6-5e61-4dd3-95d3-a7c65beb6857", + "name": "Represents an Error Caused by a General Server-Side Issue", + "originalRequest": { + "method": "PATCH", + "header": [ + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/links/:linkReference", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "links", + ":linkReference" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + }, + { + "key": "linkReference" + } + ] + } + }, + "status": "Internal Server Error", + "code": 500, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "b69ca60b-3660-4fd4-9dcc-a72c42057f6d", + "name": "An empty response is returned for a synchronous successful patch.", + "originalRequest": { + "method": "PATCH", + "header": [ + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/links/:linkReference", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "links", + ":linkReference" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + }, + { + "key": "linkReference" + } + ] + } + }, + "status": "No Content", + "code": 204, + "_postman_previewlanguage": "text", + "header": [ + { + "key": "Content-Type", + "value": "text/plain" + } + ], + "cookie": [], + "body": "" + }, + { + "id": "40814420-1191-455e-91c5-6bbb70f5f18a", + "name": "Represents an Error Caused by a Failure to Identify the Target Resource", + "originalRequest": { + "method": "PATCH", + "header": [ + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/links/:linkReference", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "links", + ":linkReference" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + }, + { + "key": "linkReference" + } + ] + } + }, + "status": "Not Found", + "code": 404, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "71f6e7e5-d1ef-498d-ac6b-485c11f6441e", + "name": "Represents an Asynchronous response", + "originalRequest": { + "method": "PATCH", + "header": [ + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/links/:linkReference", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "links", + ":linkReference" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + }, + { + "key": "linkReference" + } + ] + } + }, + "status": "Accepted", + "code": 202, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"notificationMethod\": \"\",\n \"serverCorrelationId\": \"\",\n \"status\": \"\",\n \"pendingReason\": \"\",\n \"objectReference\": \"\",\n \"expiryTime\": \"\",\n \"pollLimit\": \"\",\n \"error\": {\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n }\n}" + }, + { + "id": "4e351e53-876a-4d06-89a1-e9a49ad351be", + "name": "Represents an Error Caused by an Authorisation Failure", + "originalRequest": { + "method": "PATCH", + "header": [ + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/links/:linkReference", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "links", + ":linkReference" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + }, + { + "key": "linkReference" + } + ] + } + }, + "status": "Unauthorized", + "code": 401, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + } + ] + } + ], + "id": "a7c50288-086c-45f0-abbf-390de0a397a1" + }, + { + "name": "Create A Link", + "id": "ad5bbcc9-ed4e-47f9-901d-01285251559a", + "request": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"sourceAccountIdentifiers\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ],\n \"status\": \"\",\n \"mode\": \"\"\n}" + }, + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/links", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "links" + ], + "variable": [ + { + "id": "27cbd6ec-ec23-43c5-b2bf-790d74e46fa7", + "key": "identifierType", + "value": "", + "description": "(Required) Path variable to specify the type of the identifier that is used to identify the account." + }, + { + "id": "c146dcc3-d35a-4ca7-973b-fa19ecda1362", + "key": "identifier", + "value": "", + "description": "(Required) Path variable that contains the account identifier." + } + ] + }, + "description": "Provided with a valid object representation, this endpoint allows a new link to be created for a specific account." + }, + "response": [ + { + "id": "f2ffad90-675c-41e4-ac72-7ceda8446ea4", + "name": "Represents an Asynchronous response", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/links", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "links" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + } + ] + } + }, + "status": "Accepted", + "code": 202, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"notificationMethod\": \"\",\n \"serverCorrelationId\": \"\",\n \"status\": \"\",\n \"pendingReason\": \"\",\n \"objectReference\": \"\",\n \"expiryTime\": \"\",\n \"pollLimit\": \"\",\n \"error\": {\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n }\n}" + }, + { + "id": "8f2574da-6e19-4b10-a5b0-73e83fde4f81", + "name": "Represents an Error Caused by the Violation of a Business Rule", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/links", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "links" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + } + ] + } + }, + "status": "Bad Request", + "code": 400, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "b12c279b-8623-4b83-a624-44cee8fe4ae4", + "name": "Represents an Error Caused by System Unavailability", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/links", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "links" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + } + ] + } + }, + "status": "Service Unavailable", + "code": 503, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "db72990f-ddd5-4456-b1bb-c17b4f6e49ac", + "name": "Represents a Link response", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/links", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "links" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + } + ] + } + }, + "status": "Created", + "code": 201, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"linkReference\": \"\",\n \"sourceAccountIdentifiers\": [\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n },\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n }\n ],\n \"status\": \"\",\n \"mode\": \"\"\n}" + }, + { + "id": "6a8c960d-bd58-438f-88cb-06dbd8bdd7da", + "name": "Represents an Error Caused by a Failure to Identify the Target Resource", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/links", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "links" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + } + ] + } + }, + "status": "Not Found", + "code": 404, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "0e75be00-6e26-4772-b05d-9ae53f389043", + "name": "Represents an Error Caused by a General Server-Side Issue", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/links", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "links" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + } + ] + } + }, + "status": "Internal Server Error", + "code": 500, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "5ce2b0f5-2e83-4557-af29-6a30d3393dfc", + "name": "Represents an Error Caused by an Authorisation Failure", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/links", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "links" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + } + ] + } + }, + "status": "Unauthorized", + "code": 401, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + } + ] + } + ], + "id": "2caa7c18-3e48-44bd-b683-4284c668459b" + }, + { + "name": "authorisationcodes", + "item": [ + { + "name": "{authorisation Code}", + "item": [ + { + "name": "View an Authorisation Code", + "id": "2da8dac1-1058-4536-b308-16a5ae65c2b4", + "request": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/authorisationcodes/:authorisationCode", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "authorisationcodes", + ":authorisationCode" + ], + "variable": [ + { + "id": "2f15134a-cbe7-481d-8aeb-738e570b95b0", + "key": "identifierType", + "value": "", + "description": "(Required) Path variable to specify the type of the identifier that is used to identify the account." + }, + { + "id": "661d7443-475f-4f04-b6fa-ea655dd0b040", + "key": "identifier", + "value": "", + "description": "(Required) Path variable that contains the account identifier." + }, + { + "id": "96e72ac5-db9b-4db7-a374-f6b3402eb880", + "key": "authorisationCode", + "value": "", + "description": "(Required) Path variable to uniquely identify an authorisation code." + } + ] + }, + "description": "This endpoint returns a specific Authorisation Code linked to an account." + }, + "response": [ + { + "id": "95df9fde-64e6-4f4d-a204-0ccd080eed86", + "name": "Represents an Error Caused by a General Server-Side Issue", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/authorisationcodes/:authorisationCode", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "authorisationcodes", + ":authorisationCode" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + }, + { + "key": "authorisationCode" + } + ] + } + }, + "status": "Internal Server Error", + "code": 500, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "57b43620-a272-48b4-b021-c337b6905bb8", + "name": "Represents an Error Caused by the Violation of a Business Rule", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/authorisationcodes/:authorisationCode", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "authorisationcodes", + ":authorisationCode" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + }, + { + "key": "authorisationCode" + } + ] + } + }, + "status": "Bad Request", + "code": 400, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "8d393068-7878-4ab9-9829-df5e5ac7a396", + "name": "Represents an Error Caused by a Failure to Identify the Target Resource", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/authorisationcodes/:authorisationCode", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "authorisationcodes", + ":authorisationCode" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + }, + { + "key": "authorisationCode" + } + ] + } + }, + "status": "Not Found", + "code": 404, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "f448c2ea-687c-4833-b6d2-32bf9a78879f", + "name": "Represents an Error Caused by System Unavailability", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/authorisationcodes/:authorisationCode", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "authorisationcodes", + ":authorisationCode" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + }, + { + "key": "authorisationCode" + } + ] + } + }, + "status": "Service Unavailable", + "code": 503, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "feeccc55-ca96-44aa-b1ef-dc061125d93f", + "name": "Represents an Authorisation Code response", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/authorisationcodes/:authorisationCode", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "authorisationcodes", + ":authorisationCode" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + }, + { + "key": "authorisationCode" + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"authorisationCode\": \"\",\n \"codeState\": \"\",\n \"codeLifetime\": \"\",\n \"requestDate\": \"\",\n \"amount\": \"15.21\",\n \"currency\": \"\",\n \"amountType\": \"\",\n \"holdFundsIndicator\": \"\",\n \"redemptionChannels\": [\n {\n \"channelType\": \"\"\n },\n {\n \"channelType\": \"\"\n }\n ],\n \"redemptionTransactionTypes\": [\n {\n \"transactionType\": \"\",\n \"transactionSubtype\": \"\"\n },\n {\n \"transactionType\": \"\",\n \"transactionSubtype\": \"\"\n }\n ],\n \"redemptionAccountIdentifiers\": [\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n },\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n }\n ],\n \"metadata\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "1231b06f-69ab-4fcd-9843-92611bb82c6b", + "name": "Represents an Error Caused by an Authorisation Failure", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/authorisationcodes/:authorisationCode", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "authorisationcodes", + ":authorisationCode" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + }, + { + "key": "authorisationCode" + } + ] + } + }, + "status": "Unauthorized", + "code": 401, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + } + ] + }, + { + "name": "Cancel an Authorisation Code", + "id": "3db938a1-56ff-4af6-9a7a-865c2521f038", + "request": { + "method": "PATCH", + "header": [ + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "[\n {\n \"op\": \"\",\n \"path\": \"\",\n \"value\": \"\"\n },\n {\n \"op\": \"\",\n \"path\": \"\",\n \"value\": \"\"\n }\n]" + }, + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/authorisationcodes/:authorisationCode", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "authorisationcodes", + ":authorisationCode" + ], + "variable": [ + { + "id": "3d418994-c4fe-4d62-b9e4-817aadccdfa7", + "key": "identifierType", + "value": "", + "description": "(Required) Path variable to specify the type of the identifier that is used to identify the account." + }, + { + "id": "f489c775-d951-43de-b69a-5c2e328a21ea", + "key": "identifier", + "value": "", + "description": "(Required) Path variable that contains the account identifier." + }, + { + "id": "d71116b9-dfb4-4300-a805-58764ec586b9", + "key": "authorisationCode", + "value": "", + "description": "(Required) Path variable to uniquely identify an authorisation code." + } + ] + }, + "description": "This endpoint cancels a specific authorisation code linked to an account." + }, + "response": [ + { + "id": "274ee9d8-f2bd-4fe9-9a58-d16091ea9521", + "name": "Represents an Error Caused by a Failure to Identify the Target Resource", + "originalRequest": { + "method": "PATCH", + "header": [ + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/authorisationcodes/:authorisationCode", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "authorisationcodes", + ":authorisationCode" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + }, + { + "key": "authorisationCode" + } + ] + } + }, + "status": "Not Found", + "code": 404, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "986377fb-b83c-4901-9fcd-bc145b42ee28", + "name": "Represents an Error Caused by a General Server-Side Issue", + "originalRequest": { + "method": "PATCH", + "header": [ + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/authorisationcodes/:authorisationCode", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "authorisationcodes", + ":authorisationCode" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + }, + { + "key": "authorisationCode" + } + ] + } + }, + "status": "Internal Server Error", + "code": 500, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "dbeac018-49dd-4ffb-9be0-37866334d5db", + "name": "Represents an Error Caused by the Violation of a Business Rule", + "originalRequest": { + "method": "PATCH", + "header": [ + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/authorisationcodes/:authorisationCode", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "authorisationcodes", + ":authorisationCode" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + }, + { + "key": "authorisationCode" + } + ] + } + }, + "status": "Bad Request", + "code": 400, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "6321f485-4c24-498f-95cf-0aebbf10d557", + "name": "Represents an Error Caused by an Authorisation Failure", + "originalRequest": { + "method": "PATCH", + "header": [ + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/authorisationcodes/:authorisationCode", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "authorisationcodes", + ":authorisationCode" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + }, + { + "key": "authorisationCode" + } + ] + } + }, + "status": "Unauthorized", + "code": 401, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "34df3ddb-7e54-4b9d-a000-2134d81723a9", + "name": "Represents an Error Caused by System Unavailability", + "originalRequest": { + "method": "PATCH", + "header": [ + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/authorisationcodes/:authorisationCode", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "authorisationcodes", + ":authorisationCode" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + }, + { + "key": "authorisationCode" + } + ] + } + }, + "status": "Service Unavailable", + "code": 503, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "5fb99699-2ba2-4710-a8f8-be4e19868056", + "name": "Represents an Asynchronous response", + "originalRequest": { + "method": "PATCH", + "header": [ + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/authorisationcodes/:authorisationCode", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "authorisationcodes", + ":authorisationCode" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + }, + { + "key": "authorisationCode" + } + ] + } + }, + "status": "Accepted", + "code": 202, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"notificationMethod\": \"\",\n \"serverCorrelationId\": \"\",\n \"status\": \"\",\n \"pendingReason\": \"\",\n \"objectReference\": \"\",\n \"expiryTime\": \"\",\n \"pollLimit\": \"\",\n \"error\": {\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n }\n}" + }, + { + "id": "97d6a5cb-bb14-4308-98dc-ac9cac9140f4", + "name": "An empty response is returned for a synchronous successful patch.", + "originalRequest": { + "method": "PATCH", + "header": [ + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/authorisationcodes/:authorisationCode", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "authorisationcodes", + ":authorisationCode" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + }, + { + "key": "authorisationCode" + } + ] + } + }, + "status": "No Content", + "code": 204, + "_postman_previewlanguage": "text", + "header": [ + { + "key": "Content-Type", + "value": "text/plain" + } + ], + "cookie": [], + "body": "" + } + ] + } + ], + "id": "bdf6190b-06a4-481f-85f4-97fc14ec0baf" + }, + { + "name": "Create an Authorisation Code via an account identifier.", + "id": "e01a6293-d408-49e8-b337-f69cec77c7a4", + "request": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"requestDate\": \"\",\n \"codeLifetime\": \"\",\n \"amount\": \"\",\n \"currency\": \"\",\n \"amountType\": \"\",\n \"holdFundsIndicator\": \"\",\n \"redemptionChannels\": [\n {\n \"channelType\": \"\"\n },\n {\n \"channelType\": \"\"\n }\n ],\n \"redemptionTransactionTypes\": [\n {\n \"transactionType\": \"\",\n \"transactionSubtype\": \"\"\n },\n {\n \"transactionType\": \"\",\n \"transactionSubtype\": \"\"\n }\n ],\n \"redemptionAccountIdentifiers\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ],\n \"metadata\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/authorisationcodes", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "authorisationcodes" + ], + "variable": [ + { + "id": "9eb62b66-cde6-4c29-92b6-939da5e74fe5", + "key": "identifierType", + "value": "", + "description": "(Required) Path variable to specify the type of the identifier that is used to identify the account." + }, + { + "id": "0ec6b913-f9c6-42a1-9667-f597577883fb", + "key": "identifier", + "value": "", + "description": "(Required) Path variable that contains the account identifier." + } + ] + }, + "description": "This endpoint allows allows a mobile money payer or payee to generate a code which when presented to the other party, can be redeemed for an amount set by the payer or payee, depending upon the use case." + }, + "response": [ + { + "id": "e9a25466-3398-4260-92fc-2241511b0c1b", + "name": "Represents an Error Caused by System Unavailability", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/authorisationcodes", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "authorisationcodes" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + } + ] + } + }, + "status": "Service Unavailable", + "code": 503, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "b4b90690-8f03-4955-b44d-58e98b9ff339", + "name": "Represents an Error Caused by the Violation of a Business Rule", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/authorisationcodes", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "authorisationcodes" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + } + ] + } + }, + "status": "Bad Request", + "code": 400, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "8bc1a679-fe01-4cf9-90e4-db7c2242ff7a", + "name": "Represents an Authorisation Code response", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/authorisationcodes", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "authorisationcodes" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + } + ] + } + }, + "status": "Created", + "code": 201, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"authorisationCode\": \"\",\n \"codeState\": \"\",\n \"codeLifetime\": \"\",\n \"requestDate\": \"\",\n \"amount\": \"15.21\",\n \"currency\": \"\",\n \"amountType\": \"\",\n \"holdFundsIndicator\": \"\",\n \"redemptionChannels\": [\n {\n \"channelType\": \"\"\n },\n {\n \"channelType\": \"\"\n }\n ],\n \"redemptionTransactionTypes\": [\n {\n \"transactionType\": \"\",\n \"transactionSubtype\": \"\"\n },\n {\n \"transactionType\": \"\",\n \"transactionSubtype\": \"\"\n }\n ],\n \"redemptionAccountIdentifiers\": [\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n },\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n }\n ],\n \"metadata\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "0816fa54-996d-450a-be4d-19c72837ef87", + "name": "Represents an Error Caused by a General Server-Side Issue", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/authorisationcodes", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "authorisationcodes" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + } + ] + } + }, + "status": "Internal Server Error", + "code": 500, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "fe53a289-2f22-48b3-a3aa-5a1f034a0194", + "name": "Represents an Asynchronous response", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/authorisationcodes", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "authorisationcodes" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + } + ] + } + }, + "status": "Accepted", + "code": 202, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"notificationMethod\": \"\",\n \"serverCorrelationId\": \"\",\n \"status\": \"\",\n \"pendingReason\": \"\",\n \"objectReference\": \"\",\n \"expiryTime\": \"\",\n \"pollLimit\": \"\",\n \"error\": {\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n }\n}" + }, + { + "id": "9c7df6e0-3c73-480a-9ce0-232cb4b54e8d", + "name": "Represents an Error Caused by an Authorisation Failure", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/authorisationcodes", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "authorisationcodes" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + } + ] + } + }, + "status": "Unauthorized", + "code": 401, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "b9890782-6898-4d40-a0f2-8edf770ae4c2", + "name": "Represents an Error Caused by a Failure to Identify the Target Resource", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/authorisationcodes", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "authorisationcodes" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + } + ] + } + }, + "status": "Not Found", + "code": 404, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + } + ] + } + ], + "id": "d05ce068-4e8d-4119-9a04-f89e15e812ef" + }, + { + "name": "View Account Status", + "id": "4db3b1e6-f050-4d33-aa6f-d5b91d15b543", + "request": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/status", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "status" + ], + "variable": [ + { + "id": "4cc2b7a8-1ce2-43de-b7d8-d309c935365e", + "key": "identifierType", + "value": "", + "description": "(Required) Path variable to specify the type of the identifier that is used to identify the account." + }, + { + "id": "754282c0-63c0-4c17-972e-d2ab35cf2446", + "key": "identifier", + "value": "", + "description": "(Required) Path variable that contains the account identifier." + } + ] + }, + "description": "This endpoint returns the current status of an account." + }, + "response": [ + { + "id": "3b8fb1d3-f2d0-4df9-b567-34fb2372188f", + "name": "Represents an Error Caused by an Authorisation Failure", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/status", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "status" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + } + ] + } + }, + "status": "Unauthorized", + "code": 401, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "5a05269e-df79-4b76-8e3c-5f2438fd6484", + "name": "Represents an Error Caused by a Failure to Identify the Target Resource", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/status", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "status" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + } + ] + } + }, + "status": "Not Found", + "code": 404, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "e6758400-a37c-4bb2-8899-6f20f29db6b0", + "name": "Represents an Account Status response", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/status", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "status" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"accountStatus\": \"\",\n \"subStatus\": \"\",\n \"lei\": \"5493000IBP32UQZ0KL24\"\n}" + }, + { + "id": "6e45c4a2-4944-4d76-81b9-81275ca257b0", + "name": "Represents an Error Caused by a General Server-Side Issue", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/status", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "status" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + } + ] + } + }, + "status": "Internal Server Error", + "code": 500, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "1561ecd4-19ac-448e-b6e6-d15e92a40041", + "name": "Represents an Error Caused by the Violation of a Business Rule", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/status", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "status" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + } + ] + } + }, + "status": "Bad Request", + "code": 400, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "0c559a96-12c9-4973-8809-2218f40cca1b", + "name": "Represents an Error Caused by System Unavailability", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/status", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "status" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + } + ] + } + }, + "status": "Service Unavailable", + "code": 503, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + } + ] + }, + { + "name": "View Account Name", + "id": "381c3d51-ca85-4db3-b653-3ed74e4d9307", + "request": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/accountname", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "accountname" + ], + "variable": [ + { + "id": "3933e0cc-ed58-4daa-a0a3-316698e1a51c", + "key": "identifierType", + "value": "", + "description": "(Required) Path variable to specify the type of the identifier that is used to identify the account." + }, + { + "id": "0cf5c0d8-d70c-4151-9d39-ada766ffbce9", + "key": "identifier", + "value": "", + "description": "(Required) Path variable that contains the account identifier." + } + ] + }, + "description": "This endpoint returns the name of an account holder." + }, + "response": [ + { + "id": "9c605e56-0b21-4159-b8e2-1bf39a8d7984", + "name": "Represents an Error Caused by an Authorisation Failure", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/accountname", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "accountname" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + } + ] + } + }, + "status": "Unauthorized", + "code": 401, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "b1d630f1-05b8-4d56-b3fc-d8513559f24b", + "name": "Represents an Error Caused by the Violation of a Business Rule", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/accountname", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "accountname" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + } + ] + } + }, + "status": "Bad Request", + "code": 400, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "3031d8e8-63d0-4e7f-93a6-1e288cd9dbff", + "name": "Represents an Error Caused by a General Server-Side Issue", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/accountname", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "accountname" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + } + ] + } + }, + "status": "Internal Server Error", + "code": 500, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "d139a102-cf23-4d53-9006-0371fff824c2", + "name": "Represents an Error Caused by System Unavailability", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/accountname", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "accountname" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + } + ] + } + }, + "status": "Service Unavailable", + "code": 503, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "fc0ec62b-fabc-4b7d-aca4-176709d896ba", + "name": "Represents an Error Caused by a Failure to Identify the Target Resource", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/accountname", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "accountname" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + } + ] + } + }, + "status": "Not Found", + "code": 404, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "45ead0bc-77be-489e-94f7-d224179d9b6e", + "name": "Represents an Account Name response", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/accountname", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "accountname" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"name\": {\n \"title\": \"\",\n \"firstName\": \"\",\n \"middleName\": \"\",\n \"lastName\": \"\",\n \"fullName\": \"\",\n \"nativeName\": \"\"\n },\n \"lei\": \"5493000IBP32UQZ0KL24\"\n}" + } + ] + }, + { + "name": "View Account Balance", + "id": "fe21d2b6-00a4-479f-9423-67cea51f641c", + "request": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/balance", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "balance" + ], + "variable": [ + { + "id": "cef52622-eeb9-4082-801f-36f9105fb15e", + "key": "identifierType", + "value": "", + "description": "(Required) Path variable to specify the type of the identifier that is used to identify the account." + }, + { + "id": "0526615c-7843-48a1-88fc-b4db339e4e4b", + "key": "identifier", + "value": "", + "description": "(Required) Path variable that contains the account identifier." + } + ] + }, + "description": "This endpoint returns the balance of an account." + }, + "response": [ + { + "id": "5fc52be9-8ab9-4b12-a90a-1959a4868bcf", + "name": "Represents an Error Caused by System Unavailability", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/balance", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "balance" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + } + ] + } + }, + "status": "Service Unavailable", + "code": 503, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "f82ec491-b95f-490e-95e3-7783518e7dfe", + "name": "Represents an Error Caused by a General Server-Side Issue", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/balance", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "balance" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + } + ] + } + }, + "status": "Internal Server Error", + "code": 500, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "deaeb00f-69da-4dd3-a5bd-4ed57dafa5b0", + "name": "Represents an Account Balance response", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/balance", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "balance" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"currentBalance\": \"15.21\",\n \"availableBalance\": \"15.21\",\n \"reservedBalance\": \"15.21\",\n \"unclearedBalance\": \"15.21\",\n \"currency\": \"\",\n \"accountStatus\": \"\"\n}" + }, + { + "id": "0c0a9c3b-b2db-4565-96be-440ae2a714cd", + "name": "Represents an Error Caused by an Authorisation Failure", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/balance", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "balance" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + } + ] + } + }, + "status": "Unauthorized", + "code": 401, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "f72e1e49-5eb2-4ee5-bb3a-73843eee985f", + "name": "Represents an Error Caused by the Violation of a Business Rule", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/balance", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "balance" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + } + ] + } + }, + "status": "Bad Request", + "code": 400, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "4b04f8b4-ceed-4917-a8de-0738a5a7bab6", + "name": "Represents an Error Caused by a Failure to Identify the Target Resource", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/balance", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "balance" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + } + ] + } + }, + "status": "Not Found", + "code": 404, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + } + ] + }, + { + "name": "View Account Specific Transaction", + "id": "0bd8ad40-55ce-4635-8901-4c8a9b1937c9", + "request": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/transactions?limit=&offset=&fromDateTime=&toDateTime=&transactionStatus=&transactionType=", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "transactions" + ], + "query": [ + { + "key": "limit", + "value": "", + "description": "Supports pagination. If this is not supplied, then the server will apply a limit of 50 records returned for each request." + }, + { + "key": "offset", + "value": "", + "description": "Supports pagination. This value will indicate the cursor position from where to retrieve the set of records. For example, a limit of 50 and offset of 10 will return records 11 to 60." + }, + { + "key": "fromDateTime", + "value": "", + "description": "Indicates the minimum date for which records should be returned." + }, + { + "key": "toDateTime", + "value": "", + "description": "Indicates the maximum date for which records should be returned." + }, + { + "key": "transactionStatus", + "value": "", + "description": "Query variable to uniquely identify the transaction status." + }, + { + "key": "transactionType", + "value": "", + "description": "Identifies the type of transaction." + } + ], + "variable": [ + { + "id": "0c509b81-544b-4b1c-8b38-375f9a5e650c", + "key": "identifierType", + "value": "", + "description": "(Required) Path variable to specify the type of the identifier that is used to identify the account." + }, + { + "id": "7404e5c1-00ee-42f1-b8dd-51aeba7a3282", + "key": "identifier", + "value": "", + "description": "(Required) Path variable that contains the account identifier." + } + ] + }, + "description": "This endpoint returns transactions linked to a specific account." + }, + "response": [ + { + "id": "525f895c-e04c-4176-a8a1-c51d37da443b", + "name": "Represents an Error Caused by the Violation of a Business Rule", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/transactions?limit=&offset=&fromDateTime=&toDateTime=&transactionStatus=&transactionType=", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "transactions" + ], + "query": [ + { + "key": "limit", + "value": "" + }, + { + "key": "offset", + "value": "" + }, + { + "key": "fromDateTime", + "value": "" + }, + { + "key": "toDateTime", + "value": "" + }, + { + "key": "transactionStatus", + "value": "" + }, + { + "key": "transactionType", + "value": "" + } + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + } + ] + } + }, + "status": "Bad Request", + "code": 400, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "a74f660d-b6f6-49f5-a389-162d6a82c0a8", + "name": "Represent a list of Transactions", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/transactions?limit=&offset=&fromDateTime=&toDateTime=&transactionStatus=&transactionType=", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "transactions" + ], + "query": [ + { + "key": "limit", + "value": "" + }, + { + "key": "offset", + "value": "" + }, + { + "key": "fromDateTime", + "value": "" + }, + { + "key": "toDateTime", + "value": "" + }, + { + "key": "transactionStatus", + "value": "" + }, + { + "key": "transactionType", + "value": "" + } + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "X-Records-Available-Count", + "value": "", + "description": "Integer containing number of records that are available to be returned." + }, + { + "key": "X-Records-Returned-Count", + "value": "", + "description": "Integer containing number of records that are returned." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "[\n {\n \"amount\": \"15.21\",\n \"currency\": \"\",\n \"type\": \"\",\n \"transactionReference\": \"\",\n \"transactionStatus\": \"\",\n \"debitParty\": [\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n },\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n }\n ],\n \"creditParty\": [\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n },\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n }\n ],\n \"subType\": \"\",\n \"descriptionText\": \"\",\n \"requestDate\": \"\",\n \"requestingOrganisationTransactionReference\": \"\",\n \"oneTimeCode\": \"\",\n \"geoCode\": \"37.423825,-122.082900\",\n \"senderKyc\": {\n \"nationality\": \"\",\n \"dateOfBirth\": \"2000-11-20\",\n \"occupation\": \"\",\n \"employerName\": \"\",\n \"contactPhone\": \"\",\n \"gender\": \"\",\n \"idDocument\": [\n {\n \"idType\": \"\",\n \"idNumber\": \"\",\n \"issueDate\": \"2018-11-20\",\n \"expiryDate\": \"2018-11-20\",\n \"issuer\": \"\",\n \"issuerPlace\": \"\",\n \"issuerCountry\": \"\",\n \"otherIddescription\": \"\"\n },\n {\n \"idType\": \"\",\n \"idNumber\": \"\",\n \"issueDate\": \"2018-11-20\",\n \"expiryDate\": \"2018-11-20\",\n \"issuer\": \"\",\n \"issuerPlace\": \"\",\n \"issuerCountry\": \"\",\n \"otherIddescription\": \"\"\n }\n ],\n \"postalAddress\": {\n \"country\": \"\",\n \"addressLine1\": \"\",\n \"addressLine2\": \"\",\n \"addressLine3\": \"\",\n \"city\": \"\",\n \"stateProvince\": \"\",\n \"postalCode\": \"\"\n },\n \"subjectName\": {\n \"title\": \"\",\n \"firstName\": \"\",\n \"middleName\": \"\",\n \"lastName\": \"\",\n \"fullName\": \"\",\n \"nativeName\": \"\"\n },\n \"emailAddress\": \"\",\n \"birthCountry\": \"\"\n },\n \"recipientKyc\": {\n \"nationality\": \"\",\n \"dateOfBirth\": \"2000-11-20\",\n \"occupation\": \"\",\n \"employerName\": \"\",\n \"contactPhone\": \"\",\n \"gender\": \"\",\n \"idDocument\": [\n {\n \"idType\": \"\",\n \"idNumber\": \"\",\n \"issueDate\": \"2018-11-20\",\n \"expiryDate\": \"2018-11-20\",\n \"issuer\": \"\",\n \"issuerPlace\": \"\",\n \"issuerCountry\": \"\",\n \"otherIddescription\": \"\"\n },\n {\n \"idType\": \"\",\n \"idNumber\": \"\",\n \"issueDate\": \"2018-11-20\",\n \"expiryDate\": \"2018-11-20\",\n \"issuer\": \"\",\n \"issuerPlace\": \"\",\n \"issuerCountry\": \"\",\n \"otherIddescription\": \"\"\n }\n ],\n \"postalAddress\": {\n \"country\": \"\",\n \"addressLine1\": \"\",\n \"addressLine2\": \"\",\n \"addressLine3\": \"\",\n \"city\": \"\",\n \"stateProvince\": \"\",\n \"postalCode\": \"\"\n },\n \"subjectName\": {\n \"title\": \"\",\n \"firstName\": \"\",\n \"middleName\": \"\",\n \"lastName\": \"\",\n \"fullName\": \"\",\n \"nativeName\": \"\"\n },\n \"emailAddress\": \"\",\n \"birthCountry\": \"\"\n },\n \"originalTransactionReference\": \"\",\n \"servicingIdentity\": \"\",\n \"fees\": [\n {\n \"feeType\": \"\",\n \"feeCurrency\": \"\",\n \"feeAmount\": \"15.21\"\n },\n {\n \"feeType\": \"\",\n \"feeCurrency\": \"\",\n \"feeAmount\": \"15.21\"\n }\n ],\n \"requestingLei\": \"54930084UKLVMY22DS16\",\n \"receivingLei\": \"5493000IBP32UQZ0KL24\",\n \"metadata\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ],\n \"creationDate\": \"\",\n \"modificationDate\": \"\",\n \"dateCreated\": \"\",\n \"dateModified\": \"\",\n \"transactionReceipt\": \"\",\n \"internationalTransferInformation\": {\n \"originCountry\": \"\",\n \"quotationReference\": \"\",\n \"quoteId\": \"\",\n \"receivingCountry\": \"\",\n \"remittancePurpose\": \"\",\n \"relationshipSender\": \"\",\n \"deliveryMethod\": \"\",\n \"senderBlockingReason\": \"\",\n \"recipientBlockingReason\": \"\"\n }\n },\n {\n \"amount\": \"15.21\",\n \"currency\": \"\",\n \"type\": \"\",\n \"transactionReference\": \"\",\n \"transactionStatus\": \"\",\n \"debitParty\": [\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n },\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n }\n ],\n \"creditParty\": [\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n },\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n }\n ],\n \"subType\": \"\",\n \"descriptionText\": \"\",\n \"requestDate\": \"\",\n \"requestingOrganisationTransactionReference\": \"\",\n \"oneTimeCode\": \"\",\n \"geoCode\": \"37.423825,-122.082900\",\n \"senderKyc\": {\n \"nationality\": \"\",\n \"dateOfBirth\": \"2000-11-20\",\n \"occupation\": \"\",\n \"employerName\": \"\",\n \"contactPhone\": \"\",\n \"gender\": \"\",\n \"idDocument\": [\n {\n \"idType\": \"\",\n \"idNumber\": \"\",\n \"issueDate\": \"2018-11-20\",\n \"expiryDate\": \"2018-11-20\",\n \"issuer\": \"\",\n \"issuerPlace\": \"\",\n \"issuerCountry\": \"\",\n \"otherIddescription\": \"\"\n },\n {\n \"idType\": \"\",\n \"idNumber\": \"\",\n \"issueDate\": \"2018-11-20\",\n \"expiryDate\": \"2018-11-20\",\n \"issuer\": \"\",\n \"issuerPlace\": \"\",\n \"issuerCountry\": \"\",\n \"otherIddescription\": \"\"\n }\n ],\n \"postalAddress\": {\n \"country\": \"\",\n \"addressLine1\": \"\",\n \"addressLine2\": \"\",\n \"addressLine3\": \"\",\n \"city\": \"\",\n \"stateProvince\": \"\",\n \"postalCode\": \"\"\n },\n \"subjectName\": {\n \"title\": \"\",\n \"firstName\": \"\",\n \"middleName\": \"\",\n \"lastName\": \"\",\n \"fullName\": \"\",\n \"nativeName\": \"\"\n },\n \"emailAddress\": \"\",\n \"birthCountry\": \"\"\n },\n \"recipientKyc\": {\n \"nationality\": \"\",\n \"dateOfBirth\": \"2000-11-20\",\n \"occupation\": \"\",\n \"employerName\": \"\",\n \"contactPhone\": \"\",\n \"gender\": \"\",\n \"idDocument\": [\n {\n \"idType\": \"\",\n \"idNumber\": \"\",\n \"issueDate\": \"2018-11-20\",\n \"expiryDate\": \"2018-11-20\",\n \"issuer\": \"\",\n \"issuerPlace\": \"\",\n \"issuerCountry\": \"\",\n \"otherIddescription\": \"\"\n },\n {\n \"idType\": \"\",\n \"idNumber\": \"\",\n \"issueDate\": \"2018-11-20\",\n \"expiryDate\": \"2018-11-20\",\n \"issuer\": \"\",\n \"issuerPlace\": \"\",\n \"issuerCountry\": \"\",\n \"otherIddescription\": \"\"\n }\n ],\n \"postalAddress\": {\n \"country\": \"\",\n \"addressLine1\": \"\",\n \"addressLine2\": \"\",\n \"addressLine3\": \"\",\n \"city\": \"\",\n \"stateProvince\": \"\",\n \"postalCode\": \"\"\n },\n \"subjectName\": {\n \"title\": \"\",\n \"firstName\": \"\",\n \"middleName\": \"\",\n \"lastName\": \"\",\n \"fullName\": \"\",\n \"nativeName\": \"\"\n },\n \"emailAddress\": \"\",\n \"birthCountry\": \"\"\n },\n \"originalTransactionReference\": \"\",\n \"servicingIdentity\": \"\",\n \"fees\": [\n {\n \"feeType\": \"\",\n \"feeCurrency\": \"\",\n \"feeAmount\": \"15.21\"\n },\n {\n \"feeType\": \"\",\n \"feeCurrency\": \"\",\n \"feeAmount\": \"15.21\"\n }\n ],\n \"requestingLei\": \"54930084UKLVMY22DS16\",\n \"receivingLei\": \"5493000IBP32UQZ0KL24\",\n \"metadata\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ],\n \"creationDate\": \"\",\n \"modificationDate\": \"\",\n \"dateCreated\": \"\",\n \"dateModified\": \"\",\n \"transactionReceipt\": \"\",\n \"internationalTransferInformation\": {\n \"originCountry\": \"\",\n \"quotationReference\": \"\",\n \"quoteId\": \"\",\n \"receivingCountry\": \"\",\n \"remittancePurpose\": \"\",\n \"relationshipSender\": \"\",\n \"deliveryMethod\": \"\",\n \"senderBlockingReason\": \"\",\n \"recipientBlockingReason\": \"\"\n }\n }\n]" + }, + { + "id": "ce0b09b5-9aa2-49b7-821c-15b37c50539f", + "name": "Represents an Error Caused by System Unavailability", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/transactions?limit=&offset=&fromDateTime=&toDateTime=&transactionStatus=&transactionType=", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "transactions" + ], + "query": [ + { + "key": "limit", + "value": "" + }, + { + "key": "offset", + "value": "" + }, + { + "key": "fromDateTime", + "value": "" + }, + { + "key": "toDateTime", + "value": "" + }, + { + "key": "transactionStatus", + "value": "" + }, + { + "key": "transactionType", + "value": "" + } + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + } + ] + } + }, + "status": "Service Unavailable", + "code": 503, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "3ce86cba-fcbb-418f-888c-b3398636e8b4", + "name": "Represents an Error Caused by an Authorisation Failure", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/transactions?limit=&offset=&fromDateTime=&toDateTime=&transactionStatus=&transactionType=", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "transactions" + ], + "query": [ + { + "key": "limit", + "value": "" + }, + { + "key": "offset", + "value": "" + }, + { + "key": "fromDateTime", + "value": "" + }, + { + "key": "toDateTime", + "value": "" + }, + { + "key": "transactionStatus", + "value": "" + }, + { + "key": "transactionType", + "value": "" + } + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + } + ] + } + }, + "status": "Unauthorized", + "code": 401, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "9a29bcca-d143-424c-acb9-640bf4078c7a", + "name": "Represents an Error Caused by a General Server-Side Issue", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/transactions?limit=&offset=&fromDateTime=&toDateTime=&transactionStatus=&transactionType=", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "transactions" + ], + "query": [ + { + "key": "limit", + "value": "" + }, + { + "key": "offset", + "value": "" + }, + { + "key": "fromDateTime", + "value": "" + }, + { + "key": "toDateTime", + "value": "" + }, + { + "key": "transactionStatus", + "value": "" + }, + { + "key": "transactionType", + "value": "" + } + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + } + ] + } + }, + "status": "Internal Server Error", + "code": 500, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "bc83f67f-fea2-4859-b2bb-b1251c16e97b", + "name": "Represents an Error Caused by a Failure to Identify the Target Resource", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/transactions?limit=&offset=&fromDateTime=&toDateTime=&transactionStatus=&transactionType=", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "transactions" + ], + "query": [ + { + "key": "limit", + "value": "" + }, + { + "key": "offset", + "value": "" + }, + { + "key": "fromDateTime", + "value": "" + }, + { + "key": "toDateTime", + "value": "" + }, + { + "key": "transactionStatus", + "value": "" + }, + { + "key": "transactionType", + "value": "" + } + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + } + ] + } + }, + "status": "Not Found", + "code": 404, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + } + ] + }, + { + "name": "View Account Statements", + "id": "ff25c724-9b0e-47b1-ac4c-d63ee4134c46", + "request": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/statemententries?limit=&offset=&fromDateTime=&toDateTime=&transactionStatus=&displayType=", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "statemententries" + ], + "query": [ + { + "key": "limit", + "value": "", + "description": "Supports pagination. If this is not supplied, then the server will apply a limit of 50 records returned for each request." + }, + { + "key": "offset", + "value": "", + "description": "Supports pagination. This value will indicate the cursor position from where to retrieve the set of records. For example, a limit of 50 and offset of 10 will return records 11 to 60." + }, + { + "key": "fromDateTime", + "value": "", + "description": "Indicates the minimum date for which records should be returned." + }, + { + "key": "toDateTime", + "value": "", + "description": "Indicates the maximum date for which records should be returned." + }, + { + "key": "transactionStatus", + "value": "", + "description": "Query variable to uniquely identify the transaction status." + }, + { + "key": "displayType", + "value": "", + "description": "Query parameter to to identify the display type of the statement entries to be returned." + } + ], + "variable": [ + { + "id": "b5164301-b5bd-4aba-9d18-03c9a92f84dc", + "key": "identifierType", + "value": "", + "description": "(Required) Path variable to specify the type of the identifier that is used to identify the account." + }, + { + "id": "e0a55f43-82e2-4495-89e0-ab6858e55927", + "key": "identifier", + "value": "", + "description": "(Required) Path variable that contains the account identifier." + } + ] + }, + "description": "The Statement Entries API enables generic representations of transactions to be returned. Typically, the returned representations are used for the purposes of presenting a statement to the account holder. In order to return a statement, an account must be specified." + }, + "response": [ + { + "id": "3e8dfbc6-d997-4e54-b7d1-f27e88f6863e", + "name": "Represent a list of Statement Entries", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/statemententries?limit=&offset=&fromDateTime=&toDateTime=&transactionStatus=&displayType=", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "statemententries" + ], + "query": [ + { + "key": "limit", + "value": "" + }, + { + "key": "offset", + "value": "" + }, + { + "key": "fromDateTime", + "value": "" + }, + { + "key": "toDateTime", + "value": "" + }, + { + "key": "transactionStatus", + "value": "" + }, + { + "key": "displayType", + "value": "" + } + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "X-Records-Available-Count", + "value": "", + "description": "Integer containing number of records that are available to be returned." + }, + { + "key": "X-Records-Returned-Count", + "value": "", + "description": "Integer containing number of records that are returned." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "[\n {\n \"amount\": \"15.21\",\n \"creditParty\": [\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n },\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n }\n ],\n \"currency\": \"\",\n \"debitParty\": [\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n },\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n }\n ],\n \"transactionReference\": \"\",\n \"transactionStatus\": \"\",\n \"displayType\": \"\",\n \"descriptionText\": \"\",\n \"requestDate\": \"\",\n \"creationDate\": \"\",\n \"modificationDate\": \"\",\n \"dateCreated\": \"\",\n \"dateModified\": \"\",\n \"transactionReceipt\": \"\"\n },\n {\n \"amount\": \"15.21\",\n \"creditParty\": [\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n },\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n }\n ],\n \"currency\": \"\",\n \"debitParty\": [\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n },\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n }\n ],\n \"transactionReference\": \"\",\n \"transactionStatus\": \"\",\n \"displayType\": \"\",\n \"descriptionText\": \"\",\n \"requestDate\": \"\",\n \"creationDate\": \"\",\n \"modificationDate\": \"\",\n \"dateCreated\": \"\",\n \"dateModified\": \"\",\n \"transactionReceipt\": \"\"\n }\n]" + }, + { + "id": "d58f178b-cad1-414a-b61f-059b1ac2c590", + "name": "Represents an Error Caused by a Failure to Identify the Target Resource", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/statemententries?limit=&offset=&fromDateTime=&toDateTime=&transactionStatus=&displayType=", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "statemententries" + ], + "query": [ + { + "key": "limit", + "value": "" + }, + { + "key": "offset", + "value": "" + }, + { + "key": "fromDateTime", + "value": "" + }, + { + "key": "toDateTime", + "value": "" + }, + { + "key": "transactionStatus", + "value": "" + }, + { + "key": "displayType", + "value": "" + } + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + } + ] + } + }, + "status": "Not Found", + "code": 404, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "a7655300-b641-4baa-b853-aad29f03685a", + "name": "Represents an Error Caused by the Violation of a Business Rule", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/statemententries?limit=&offset=&fromDateTime=&toDateTime=&transactionStatus=&displayType=", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "statemententries" + ], + "query": [ + { + "key": "limit", + "value": "" + }, + { + "key": "offset", + "value": "" + }, + { + "key": "fromDateTime", + "value": "" + }, + { + "key": "toDateTime", + "value": "" + }, + { + "key": "transactionStatus", + "value": "" + }, + { + "key": "displayType", + "value": "" + } + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + } + ] + } + }, + "status": "Bad Request", + "code": 400, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "86885775-706e-4d9f-8fd9-8724b1c599ba", + "name": "Represents an Error Caused by an Authorisation Failure", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/statemententries?limit=&offset=&fromDateTime=&toDateTime=&transactionStatus=&displayType=", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "statemententries" + ], + "query": [ + { + "key": "limit", + "value": "" + }, + { + "key": "offset", + "value": "" + }, + { + "key": "fromDateTime", + "value": "" + }, + { + "key": "toDateTime", + "value": "" + }, + { + "key": "transactionStatus", + "value": "" + }, + { + "key": "displayType", + "value": "" + } + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + } + ] + } + }, + "status": "Unauthorized", + "code": 401, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "535c81eb-9b14-45ed-beb8-4ae2a31e23a1", + "name": "Represents an Error Caused by System Unavailability", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/statemententries?limit=&offset=&fromDateTime=&toDateTime=&transactionStatus=&displayType=", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "statemententries" + ], + "query": [ + { + "key": "limit", + "value": "" + }, + { + "key": "offset", + "value": "" + }, + { + "key": "fromDateTime", + "value": "" + }, + { + "key": "toDateTime", + "value": "" + }, + { + "key": "transactionStatus", + "value": "" + }, + { + "key": "displayType", + "value": "" + } + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + } + ] + } + }, + "status": "Service Unavailable", + "code": 503, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "bc096527-aced-484a-96a4-055192feadeb", + "name": "Represents an Error Caused by a General Server-Side Issue", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/statemententries?limit=&offset=&fromDateTime=&toDateTime=&transactionStatus=&displayType=", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "statemententries" + ], + "query": [ + { + "key": "limit", + "value": "" + }, + { + "key": "offset", + "value": "" + }, + { + "key": "fromDateTime", + "value": "" + }, + { + "key": "toDateTime", + "value": "" + }, + { + "key": "transactionStatus", + "value": "" + }, + { + "key": "displayType", + "value": "" + } + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + } + ] + } + }, + "status": "Internal Server Error", + "code": 500, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + } + ] + }, + { + "name": "View Bill Companies", + "id": "466b5f03-968b-40aa-87ab-f05c58f36ada", + "request": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/billcompanies?limit=&offset=", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "billcompanies" + ], + "query": [ + { + "key": "limit", + "value": "", + "description": "Supports pagination. If this is not supplied, then the server will apply a limit of 50 records returned for each request." + }, + { + "key": "offset", + "value": "", + "description": "Supports pagination. This value will indicate the cursor position from where to retrieve the set of records. For example, a limit of 50 and offset of 10 will return records 11 to 60." + } + ], + "variable": [ + { + "id": "8d45e794-b361-4e92-9496-7fbdb8c6393c", + "key": "identifierType", + "value": "", + "description": "(Required) Path variable to specify the type of the identifier that is used to identify the account." + }, + { + "id": "4c831a89-5622-4434-8a8d-62453c8f0665", + "key": "identifier", + "value": "", + "description": "(Required) Path variable that contains the account identifier." + } + ] + }, + "description": "This Bill Companies API is used to return a list of Service Providers that accept Bill Payments for a given account." + }, + "response": [ + { + "id": "e14dfa1f-4c4e-4efc-9cf3-9bc9ba7f634c", + "name": "Represents an Error Caused by a Failure to Identify the Target Resource", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/billcompanies?limit=&offset=", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "billcompanies" + ], + "query": [ + { + "key": "limit", + "value": "" + }, + { + "key": "offset", + "value": "" + } + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + } + ] + } + }, + "status": "Not Found", + "code": 404, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "6ec287f9-888e-4e39-bc16-aae1334a9f57", + "name": "Represents an Error Caused by an Authorisation Failure", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/billcompanies?limit=&offset=", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "billcompanies" + ], + "query": [ + { + "key": "limit", + "value": "" + }, + { + "key": "offset", + "value": "" + } + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + } + ] + } + }, + "status": "Unauthorized", + "code": 401, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "e0e61848-b74f-458d-b988-7ecfe1bc2417", + "name": "Represents an Error Caused by a General Server-Side Issue", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/billcompanies?limit=&offset=", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "billcompanies" + ], + "query": [ + { + "key": "limit", + "value": "" + }, + { + "key": "offset", + "value": "" + } + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + } + ] + } + }, + "status": "Internal Server Error", + "code": 500, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "b68ee484-7802-4662-8399-7bf34533f23c", + "name": "Represents an Error Caused by System Unavailability", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/billcompanies?limit=&offset=", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "billcompanies" + ], + "query": [ + { + "key": "limit", + "value": "" + }, + { + "key": "offset", + "value": "" + } + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + } + ] + } + }, + "status": "Service Unavailable", + "code": 503, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "c1c5a091-211e-4124-be8d-fd67d81798b8", + "name": "Represents an Error Caused by the Violation of a Business Rule", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/billcompanies?limit=&offset=", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "billcompanies" + ], + "query": [ + { + "key": "limit", + "value": "" + }, + { + "key": "offset", + "value": "" + } + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + } + ] + } + }, + "status": "Bad Request", + "code": 400, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "426a2a0a-5ac1-4fad-9507-2b3198d0fbfd", + "name": "Represent a list of Bill Companies", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/billcompanies?limit=&offset=", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "billcompanies" + ], + "query": [ + { + "key": "limit", + "value": "" + }, + { + "key": "offset", + "value": "" + } + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "[\n {\n \"companyName\": \"\",\n \"serviceProvider\": \"\",\n \"serviceProviderType\": \"\",\n \"serviceProviderSubType\": \"\",\n \"supplementaryServiceProviderDetails\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n },\n {\n \"companyName\": \"\",\n \"serviceProvider\": \"\",\n \"serviceProviderType\": \"\",\n \"serviceProviderSubType\": \"\",\n \"supplementaryServiceProviderDetails\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n }\n]" + } + ] + } + ], + "id": "c0bd96a9-a118-4f9a-879a-350404aae4b0" + }, + { + "name": "View Account Balance", + "id": "838313ad-e919-4872-9a41-9ca752c41d8e", + "request": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": "{{baseUrl}}/accounts/balance", + "description": "This endpoint returns the balance of an account. As the account is not passed as a parameter, the account is assumed to be that of the calling client.\"" + }, + "response": [ + { + "id": "4c8c360e-1517-4777-a665-032036669bc0", + "name": "Represents an Error Caused by a Failure to Identify the Target Resource", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": "{{baseUrl}}/accounts/balance" + }, + "status": "Not Found", + "code": 404, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "d58f2ca0-9695-4227-b25a-8476f8c7f976", + "name": "Represents an Account Balance response", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": "{{baseUrl}}/accounts/balance" + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"currentBalance\": \"15.21\",\n \"availableBalance\": \"15.21\",\n \"reservedBalance\": \"15.21\",\n \"unclearedBalance\": \"15.21\",\n \"currency\": \"\",\n \"accountStatus\": \"\"\n}" + }, + { + "id": "59978f81-2ba7-4a14-8d5c-029ea28b2c4d", + "name": "Represents an Error Caused by a General Server-Side Issue", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": "{{baseUrl}}/accounts/balance" + }, + "status": "Internal Server Error", + "code": 500, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "4b9b532a-801a-44b3-865e-37aab7b5d8d1", + "name": "Represents an Error Caused by System Unavailability", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": "{{baseUrl}}/accounts/balance" + }, + "status": "Service Unavailable", + "code": 503, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "ab51666f-a161-44fe-b766-a5bea2c97143", + "name": "Represents an Error Caused by the Violation of a Business Rule", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": "{{baseUrl}}/accounts/balance" + }, + "status": "Bad Request", + "code": 400, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "ff2d060c-1854-4b41-915b-dd9770394d4d", + "name": "Represents an Error Caused by an Authorisation Failure", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": "{{baseUrl}}/accounts/balance" + }, + "status": "Unauthorized", + "code": 401, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + } + ] + } + ], + "id": "9f588794-09d1-461a-a5c9-dcdf12a8f600" + }, + { + "name": "billcompanies", + "item": [ + { + "name": "View Bill Companies", + "id": "b64b1d77-25ff-47c5-8652-279a337fa416", + "request": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/billcompanies?limit=&offset=", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "billcompanies" + ], + "query": [ + { + "key": "limit", + "value": "", + "description": "Supports pagination. If this is not supplied, then the server will apply a limit of 50 records returned for each request." + }, + { + "key": "offset", + "value": "", + "description": "Supports pagination. This value will indicate the cursor position from where to retrieve the set of records. For example, a limit of 50 and offset of 10 will return records 11 to 60." + } + ] + }, + "description": "The Bill Companies API is used to return a list of Service Providers that accept Bill Payments." + }, + "response": [ + { + "id": "1b69adec-05cc-47cc-aa5b-c28f9219ac66", + "name": "Represent a list of Bill Companies", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/billcompanies?limit=&offset=", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "billcompanies" + ], + "query": [ + { + "key": "limit", + "value": "" + }, + { + "key": "offset", + "value": "" + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "[\n {\n \"companyName\": \"\",\n \"serviceProvider\": \"\",\n \"serviceProviderType\": \"\",\n \"serviceProviderSubType\": \"\",\n \"supplementaryServiceProviderDetails\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n },\n {\n \"companyName\": \"\",\n \"serviceProvider\": \"\",\n \"serviceProviderType\": \"\",\n \"serviceProviderSubType\": \"\",\n \"supplementaryServiceProviderDetails\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n }\n]" + }, + { + "id": "54f38b95-3b82-421d-9e3c-695266b9d844", + "name": "Represents an Error Caused by System Unavailability", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/billcompanies?limit=&offset=", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "billcompanies" + ], + "query": [ + { + "key": "limit", + "value": "" + }, + { + "key": "offset", + "value": "" + } + ] + } + }, + "status": "Service Unavailable", + "code": 503, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "b551f74c-eda3-4f0d-bae1-88af66dc8393", + "name": "Represents an Error Caused by a General Server-Side Issue", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/billcompanies?limit=&offset=", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "billcompanies" + ], + "query": [ + { + "key": "limit", + "value": "" + }, + { + "key": "offset", + "value": "" + } + ] + } + }, + "status": "Internal Server Error", + "code": 500, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "a963adf9-f117-4ca9-a191-d545f7e670b4", + "name": "Represents an Error Caused by an Authorisation Failure", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/billcompanies?limit=&offset=", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "billcompanies" + ], + "query": [ + { + "key": "limit", + "value": "" + }, + { + "key": "offset", + "value": "" + } + ] + } + }, + "status": "Unauthorized", + "code": 401, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "305ff661-a091-429e-a397-9759864eeb47", + "name": "Represents an Error Caused by the Violation of a Business Rule", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/billcompanies?limit=&offset=", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "billcompanies" + ], + "query": [ + { + "key": "limit", + "value": "" + }, + { + "key": "offset", + "value": "" + } + ] + } + }, + "status": "Bad Request", + "code": 400, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "6d62d737-f5e2-480e-9bd6-29c1a0d7cce0", + "name": "Represents an Error Caused by a Failure to Identify the Target Resource", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/billcompanies?limit=&offset=", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "billcompanies" + ], + "query": [ + { + "key": "limit", + "value": "" + }, + { + "key": "offset", + "value": "" + } + ] + } + }, + "status": "Not Found", + "code": 404, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + } + ] + }, + { + "name": "View a Specific Bill Company", + "id": "90851b98-449e-410d-917f-942d544cb094", + "request": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/billcompanies/:serviceProvider", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "billcompanies", + ":serviceProvider" + ], + "variable": [ + { + "id": "9367c398-0b02-44c3-8584-6910158a7eb9", + "key": "serviceProvider", + "value": "", + "description": "(Required) The identifier for the Bill Payment Service Provider." + } + ] + }, + "description": "This Bill Companies API is used to return a information for a specific Service Providers that accepts Bill Payments." + }, + "response": [ + { + "id": "bf8fb499-f2bc-45d3-bd59-0c9810fe99fa", + "name": "Represents an Error Caused by System Unavailability", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/billcompanies/:serviceProvider", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "billcompanies", + ":serviceProvider" + ], + "variable": [ + { + "key": "serviceProvider" + } + ] + } + }, + "status": "Service Unavailable", + "code": 503, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "14bc4994-ffab-4d86-9150-0ffb73415865", + "name": "Represents an Error Caused by an Authorisation Failure", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/billcompanies/:serviceProvider", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "billcompanies", + ":serviceProvider" + ], + "variable": [ + { + "key": "serviceProvider" + } + ] + } + }, + "status": "Unauthorized", + "code": 401, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "c239c75d-20dc-40b2-8735-4c6faa2d8cb5", + "name": "Represents an Error Caused by a General Server-Side Issue", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/billcompanies/:serviceProvider", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "billcompanies", + ":serviceProvider" + ], + "variable": [ + { + "key": "serviceProvider" + } + ] + } + }, + "status": "Internal Server Error", + "code": 500, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "062ca350-6d00-491b-95c0-46dac100b6a2", + "name": "Returns a specific Bill Payment Service Provider", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/billcompanies/:serviceProvider", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "billcompanies", + ":serviceProvider" + ], + "variable": [ + { + "key": "serviceProvider" + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"companyName\": \"\",\n \"serviceProvider\": \"\",\n \"serviceProviderType\": \"\",\n \"serviceProviderSubType\": \"\",\n \"supplementaryServiceProviderDetails\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "11d63496-de48-4d74-8b9a-1364a656a56d", + "name": "Represents an Error Caused by a Failure to Identify the Target Resource", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/billcompanies/:serviceProvider", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "billcompanies", + ":serviceProvider" + ], + "variable": [ + { + "key": "serviceProvider" + } + ] + } + }, + "status": "Not Found", + "code": 404, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "ab667cda-e56a-4357-a864-ad074d6babbb", + "name": "Represents an Error Caused by the Violation of a Business Rule", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/billcompanies/:serviceProvider", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "billcompanies", + ":serviceProvider" + ], + "variable": [ + { + "key": "serviceProvider" + } + ] + } + }, + "status": "Bad Request", + "code": 400, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + } + ] + } + ], + "id": "3c5d340a-2a2d-4dc8-99d1-5ff0fdc19d9a" + }, + { + "name": "quotations", + "item": [ + { + "name": "Create A New Quotation", + "id": "e7d896a6-fadf-43ce-a5b4-bd6eec3213ca", + "request": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"creditParty\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ],\n \"debitParty\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ],\n \"requestAmount\": \"\",\n \"requestCurrency\": \"\",\n \"requestDate\": \"\",\n \"senderKyc\": {\n \"nationality\": \"\",\n \"dateOfBirth\": \"\",\n \"occupation\": \"\",\n \"employerName\": \"\",\n \"contactPhone\": \"\",\n \"gender\": \"\",\n \"idDocument\": [\n {\n \"idType\": \"\",\n \"idNumber\": \"\",\n \"issueDate\": \"\",\n \"expiryDate\": \"\",\n \"issuer\": \"\",\n \"issuerPlace\": \"\",\n \"issuerCountry\": \"\",\n \"otherIddescription\": \"\"\n },\n {\n \"idType\": \"\",\n \"idNumber\": \"\",\n \"issueDate\": \"\",\n \"expiryDate\": \"\",\n \"issuer\": \"\",\n \"issuerPlace\": \"\",\n \"issuerCountry\": \"\",\n \"otherIddescription\": \"\"\n }\n ],\n \"postalAddress\": {\n \"country\": \"\",\n \"addressLine1\": \"\",\n \"addressLine2\": \"\",\n \"addressLine3\": \"\",\n \"city\": \"\",\n \"stateProvince\": \"\",\n \"postalCode\": \"\"\n },\n \"subjectName\": {\n \"title\": \"\",\n \"firstName\": \"\",\n \"middleName\": \"\",\n \"lastName\": \"\",\n \"fullName\": \"\",\n \"nativeName\": \"\"\n },\n \"emailAddress\": \"\",\n \"birthCountry\": \"\"\n },\n \"recipientKyc\": {\n \"nationality\": \"\",\n \"dateOfBirth\": \"\",\n \"occupation\": \"\",\n \"employerName\": \"\",\n \"contactPhone\": \"\",\n \"gender\": \"\",\n \"idDocument\": [\n {\n \"idType\": \"\",\n \"idNumber\": \"\",\n \"issueDate\": \"\",\n \"expiryDate\": \"\",\n \"issuer\": \"\",\n \"issuerPlace\": \"\",\n \"issuerCountry\": \"\",\n \"otherIddescription\": \"\"\n },\n {\n \"idType\": \"\",\n \"idNumber\": \"\",\n \"issueDate\": \"\",\n \"expiryDate\": \"\",\n \"issuer\": \"\",\n \"issuerPlace\": \"\",\n \"issuerCountry\": \"\",\n \"otherIddescription\": \"\"\n }\n ],\n \"postalAddress\": {\n \"country\": \"\",\n \"addressLine1\": \"\",\n \"addressLine2\": \"\",\n \"addressLine3\": \"\",\n \"city\": \"\",\n \"stateProvince\": \"\",\n \"postalCode\": \"\"\n },\n \"subjectName\": {\n \"title\": \"\",\n \"firstName\": \"\",\n \"middleName\": \"\",\n \"lastName\": \"\",\n \"fullName\": \"\",\n \"nativeName\": \"\"\n },\n \"emailAddress\": \"\",\n \"birthCountry\": \"\"\n },\n \"type\": \"\",\n \"subType\": \"\",\n \"chosenDeliveryMethod\": \"\",\n \"metadata\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + "url": "{{baseUrl}}/quotations", + "description": "Provided with a valid object representation, this endpoint allows for a new quotation to be created." + }, + "response": [ + { + "id": "643c8008-38ac-460c-8ff3-4cc301c65745", + "name": "Represents an Error Caused by the Violation of a Business Rule", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": "{{baseUrl}}/quotations" + }, + "status": "Bad Request", + "code": 400, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "49bae996-d40c-4e5f-937a-bc19f62891d6", + "name": "Represents an Error Caused by a General Server-Side Issue", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": "{{baseUrl}}/quotations" + }, + "status": "Internal Server Error", + "code": 500, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "00269bc9-1d35-4791-ab3f-2539dd35c166", + "name": "Represents an Error Caused by a Failure to Identify the Target Resource", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": "{{baseUrl}}/quotations" + }, + "status": "Not Found", + "code": 404, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "32ebb4b9-519c-4f5b-8aec-eb118ac881b1", + "name": "Represents an Error Caused by System Unavailability", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": "{{baseUrl}}/quotations" + }, + "status": "Service Unavailable", + "code": 503, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "3eee04ee-0046-4938-a887-15cf52385aa5", + "name": "Represents a Quotation response", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": "{{baseUrl}}/quotations" + }, + "status": "Created", + "code": 201, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"quotationReference\": \"\",\n \"requestDate\": \"\",\n \"debitParty\": [\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n },\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n }\n ],\n \"creditParty\": [\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n },\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n }\n ],\n \"requestAmount\": \"15.21\",\n \"requestCurrency\": \"\",\n \"senderKyc\": {\n \"nationality\": \"\",\n \"dateOfBirth\": \"2000-11-20\",\n \"occupation\": \"\",\n \"employerName\": \"\",\n \"contactPhone\": \"\",\n \"gender\": \"\",\n \"idDocument\": [\n {\n \"idType\": \"\",\n \"idNumber\": \"\",\n \"issueDate\": \"2018-11-20\",\n \"expiryDate\": \"2018-11-20\",\n \"issuer\": \"\",\n \"issuerPlace\": \"\",\n \"issuerCountry\": \"\",\n \"otherIddescription\": \"\"\n },\n {\n \"idType\": \"\",\n \"idNumber\": \"\",\n \"issueDate\": \"2018-11-20\",\n \"expiryDate\": \"2018-11-20\",\n \"issuer\": \"\",\n \"issuerPlace\": \"\",\n \"issuerCountry\": \"\",\n \"otherIddescription\": \"\"\n }\n ],\n \"postalAddress\": {\n \"country\": \"\",\n \"addressLine1\": \"\",\n \"addressLine2\": \"\",\n \"addressLine3\": \"\",\n \"city\": \"\",\n \"stateProvince\": \"\",\n \"postalCode\": \"\"\n },\n \"subjectName\": {\n \"title\": \"\",\n \"firstName\": \"\",\n \"middleName\": \"\",\n \"lastName\": \"\",\n \"fullName\": \"\",\n \"nativeName\": \"\"\n },\n \"emailAddress\": \"\",\n \"birthCountry\": \"\"\n },\n \"recipientKyc\": {\n \"nationality\": \"\",\n \"dateOfBirth\": \"2000-11-20\",\n \"occupation\": \"\",\n \"employerName\": \"\",\n \"contactPhone\": \"\",\n \"gender\": \"\",\n \"idDocument\": [\n {\n \"idType\": \"\",\n \"idNumber\": \"\",\n \"issueDate\": \"2018-11-20\",\n \"expiryDate\": \"2018-11-20\",\n \"issuer\": \"\",\n \"issuerPlace\": \"\",\n \"issuerCountry\": \"\",\n \"otherIddescription\": \"\"\n },\n {\n \"idType\": \"\",\n \"idNumber\": \"\",\n \"issueDate\": \"2018-11-20\",\n \"expiryDate\": \"2018-11-20\",\n \"issuer\": \"\",\n \"issuerPlace\": \"\",\n \"issuerCountry\": \"\",\n \"otherIddescription\": \"\"\n }\n ],\n \"postalAddress\": {\n \"country\": \"\",\n \"addressLine1\": \"\",\n \"addressLine2\": \"\",\n \"addressLine3\": \"\",\n \"city\": \"\",\n \"stateProvince\": \"\",\n \"postalCode\": \"\"\n },\n \"subjectName\": {\n \"title\": \"\",\n \"firstName\": \"\",\n \"middleName\": \"\",\n \"lastName\": \"\",\n \"fullName\": \"\",\n \"nativeName\": \"\"\n },\n \"emailAddress\": \"\",\n \"birthCountry\": \"\"\n },\n \"type\": \"\",\n \"subType\": \"\",\n \"chosenDeliveryMethod\": \"\",\n \"quotes\": [\n {\n \"quoteId\": \"\",\n \"receivingAmount\": \"15.21\",\n \"receivingCurrency\": \"\",\n \"sendingAmount\": \"15.21\",\n \"sendingCurrency\": \"\",\n \"quoteExpiryTime\": \"\",\n \"receivingServiceProvider\": \"\",\n \"fxRate\": \"1.3436\",\n \"deliveryMethod\": \"\",\n \"fees\": [\n {\n \"feeType\": \"\",\n \"feeCurrency\": \"\",\n \"feeAmount\": \"15.21\"\n },\n {\n \"feeType\": \"\",\n \"feeCurrency\": \"\",\n \"feeAmount\": \"15.21\"\n }\n ]\n },\n {\n \"quoteId\": \"\",\n \"receivingAmount\": \"15.21\",\n \"receivingCurrency\": \"\",\n \"sendingAmount\": \"15.21\",\n \"sendingCurrency\": \"\",\n \"quoteExpiryTime\": \"\",\n \"receivingServiceProvider\": \"\",\n \"fxRate\": \"1.3436\",\n \"deliveryMethod\": \"\",\n \"fees\": [\n {\n \"feeType\": \"\",\n \"feeCurrency\": \"\",\n \"feeAmount\": \"15.21\"\n },\n {\n \"feeType\": \"\",\n \"feeCurrency\": \"\",\n \"feeAmount\": \"15.21\"\n }\n ]\n }\n ],\n \"senderBlockingReason\": \"\",\n \"recipientBlockingReason\": \"\",\n \"metadata\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ],\n \"quotationStatus\": \"\",\n \"creationDate\": \"\",\n \"modificationDate\": \"\",\n \"dateCreated\": \"\",\n \"dateModified\": \"\",\n \"availableDeliveryMethod\": \"\"\n}" + }, + { + "id": "6a96ef49-50ef-46cf-978b-576b149fab4c", + "name": "Represents an Asynchronous response", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": "{{baseUrl}}/quotations" + }, + "status": "Accepted", + "code": 202, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"notificationMethod\": \"\",\n \"serverCorrelationId\": \"\",\n \"status\": \"\",\n \"pendingReason\": \"\",\n \"objectReference\": \"\",\n \"expiryTime\": \"\",\n \"pollLimit\": \"\",\n \"error\": {\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n }\n}" + }, + { + "id": "f237dd1c-f43b-4127-ae1d-3f66376d427c", + "name": "Represents an Error Caused by an Authorisation Failure", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": "{{baseUrl}}/quotations" + }, + "status": "Unauthorized", + "code": 401, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + } + ] + }, + { + "name": "View A Quotation", + "id": "10c99022-f396-4c6f-b895-2d78ae1c10af", + "request": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/quotations/:quotationReference", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "quotations", + ":quotationReference" + ], + "variable": [ + { + "id": "63e08dca-7ee5-4bf8-b4d8-9bc442376619", + "key": "quotationReference", + "value": "", + "description": "(Required) Path variable to uniquely identify the quotation." + } + ] + }, + "description": "This endpoint returns a specific quotation" + }, + "response": [ + { + "id": "0a87983c-d4cc-47a1-be97-de05c175b544", + "name": "Represents an Error Caused by a General Server-Side Issue", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/quotations/:quotationReference", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "quotations", + ":quotationReference" + ], + "variable": [ + { + "key": "quotationReference" + } + ] + } + }, + "status": "Internal Server Error", + "code": 500, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "9940781a-031d-4785-8bc0-45984cac5e0f", + "name": "Represents an Error Caused by a Failure to Identify the Target Resource", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/quotations/:quotationReference", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "quotations", + ":quotationReference" + ], + "variable": [ + { + "key": "quotationReference" + } + ] + } + }, + "status": "Not Found", + "code": 404, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "38335c02-5cfb-4786-be0e-c26fe2a40b2a", + "name": "Represents an Error Caused by an Authorisation Failure", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/quotations/:quotationReference", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "quotations", + ":quotationReference" + ], + "variable": [ + { + "key": "quotationReference" + } + ] + } + }, + "status": "Unauthorized", + "code": 401, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "6826f7db-f5de-49f3-ac46-dfa889b45798", + "name": "Represents an Error Caused by System Unavailability", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/quotations/:quotationReference", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "quotations", + ":quotationReference" + ], + "variable": [ + { + "key": "quotationReference" + } + ] + } + }, + "status": "Service Unavailable", + "code": 503, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "38324d5b-ea39-4f9a-ac6c-ab767fbd9689", + "name": "Represents an Error Caused by the Violation of a Business Rule", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/quotations/:quotationReference", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "quotations", + ":quotationReference" + ], + "variable": [ + { + "key": "quotationReference" + } + ] + } + }, + "status": "Bad Request", + "code": 400, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "307de53f-d0a4-4b7b-bacf-6e380063e142", + "name": "Represents a Quotation response", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/quotations/:quotationReference", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "quotations", + ":quotationReference" + ], + "variable": [ + { + "key": "quotationReference" + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"quotationReference\": \"\",\n \"requestDate\": \"\",\n \"debitParty\": [\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n },\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n }\n ],\n \"creditParty\": [\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n },\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n }\n ],\n \"requestAmount\": \"15.21\",\n \"requestCurrency\": \"\",\n \"senderKyc\": {\n \"nationality\": \"\",\n \"dateOfBirth\": \"2000-11-20\",\n \"occupation\": \"\",\n \"employerName\": \"\",\n \"contactPhone\": \"\",\n \"gender\": \"\",\n \"idDocument\": [\n {\n \"idType\": \"\",\n \"idNumber\": \"\",\n \"issueDate\": \"2018-11-20\",\n \"expiryDate\": \"2018-11-20\",\n \"issuer\": \"\",\n \"issuerPlace\": \"\",\n \"issuerCountry\": \"\",\n \"otherIddescription\": \"\"\n },\n {\n \"idType\": \"\",\n \"idNumber\": \"\",\n \"issueDate\": \"2018-11-20\",\n \"expiryDate\": \"2018-11-20\",\n \"issuer\": \"\",\n \"issuerPlace\": \"\",\n \"issuerCountry\": \"\",\n \"otherIddescription\": \"\"\n }\n ],\n \"postalAddress\": {\n \"country\": \"\",\n \"addressLine1\": \"\",\n \"addressLine2\": \"\",\n \"addressLine3\": \"\",\n \"city\": \"\",\n \"stateProvince\": \"\",\n \"postalCode\": \"\"\n },\n \"subjectName\": {\n \"title\": \"\",\n \"firstName\": \"\",\n \"middleName\": \"\",\n \"lastName\": \"\",\n \"fullName\": \"\",\n \"nativeName\": \"\"\n },\n \"emailAddress\": \"\",\n \"birthCountry\": \"\"\n },\n \"recipientKyc\": {\n \"nationality\": \"\",\n \"dateOfBirth\": \"2000-11-20\",\n \"occupation\": \"\",\n \"employerName\": \"\",\n \"contactPhone\": \"\",\n \"gender\": \"\",\n \"idDocument\": [\n {\n \"idType\": \"\",\n \"idNumber\": \"\",\n \"issueDate\": \"2018-11-20\",\n \"expiryDate\": \"2018-11-20\",\n \"issuer\": \"\",\n \"issuerPlace\": \"\",\n \"issuerCountry\": \"\",\n \"otherIddescription\": \"\"\n },\n {\n \"idType\": \"\",\n \"idNumber\": \"\",\n \"issueDate\": \"2018-11-20\",\n \"expiryDate\": \"2018-11-20\",\n \"issuer\": \"\",\n \"issuerPlace\": \"\",\n \"issuerCountry\": \"\",\n \"otherIddescription\": \"\"\n }\n ],\n \"postalAddress\": {\n \"country\": \"\",\n \"addressLine1\": \"\",\n \"addressLine2\": \"\",\n \"addressLine3\": \"\",\n \"city\": \"\",\n \"stateProvince\": \"\",\n \"postalCode\": \"\"\n },\n \"subjectName\": {\n \"title\": \"\",\n \"firstName\": \"\",\n \"middleName\": \"\",\n \"lastName\": \"\",\n \"fullName\": \"\",\n \"nativeName\": \"\"\n },\n \"emailAddress\": \"\",\n \"birthCountry\": \"\"\n },\n \"type\": \"\",\n \"subType\": \"\",\n \"chosenDeliveryMethod\": \"\",\n \"quotes\": [\n {\n \"quoteId\": \"\",\n \"receivingAmount\": \"15.21\",\n \"receivingCurrency\": \"\",\n \"sendingAmount\": \"15.21\",\n \"sendingCurrency\": \"\",\n \"quoteExpiryTime\": \"\",\n \"receivingServiceProvider\": \"\",\n \"fxRate\": \"1.3436\",\n \"deliveryMethod\": \"\",\n \"fees\": [\n {\n \"feeType\": \"\",\n \"feeCurrency\": \"\",\n \"feeAmount\": \"15.21\"\n },\n {\n \"feeType\": \"\",\n \"feeCurrency\": \"\",\n \"feeAmount\": \"15.21\"\n }\n ]\n },\n {\n \"quoteId\": \"\",\n \"receivingAmount\": \"15.21\",\n \"receivingCurrency\": \"\",\n \"sendingAmount\": \"15.21\",\n \"sendingCurrency\": \"\",\n \"quoteExpiryTime\": \"\",\n \"receivingServiceProvider\": \"\",\n \"fxRate\": \"1.3436\",\n \"deliveryMethod\": \"\",\n \"fees\": [\n {\n \"feeType\": \"\",\n \"feeCurrency\": \"\",\n \"feeAmount\": \"15.21\"\n },\n {\n \"feeType\": \"\",\n \"feeCurrency\": \"\",\n \"feeAmount\": \"15.21\"\n }\n ]\n }\n ],\n \"senderBlockingReason\": \"\",\n \"recipientBlockingReason\": \"\",\n \"metadata\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ],\n \"quotationStatus\": \"\",\n \"creationDate\": \"\",\n \"modificationDate\": \"\",\n \"dateCreated\": \"\",\n \"dateModified\": \"\",\n \"availableDeliveryMethod\": \"\"\n}" + } + ] + } + ], + "id": "2d83261d-d2b5-4032-997f-4cf0bd20bc80" + }, + { + "name": "requeststates/{server Correlation Id}", + "item": [ + { + "name": "View A Request State", + "id": "5ee95b5d-8818-49aa-93a0-da60e5ddeb08", + "request": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + } + ], + "url": { + "raw": "{{baseUrl}}/requeststates/:serverCorrelationId", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "requeststates", + ":serverCorrelationId" + ], + "variable": [ + { + "id": "a7645c31-d137-471c-a8ff-c85194d01ff8", + "key": "serverCorrelationId", + "value": "", + "description": "(Required) Path variable to uniquely identify a request state. Must be supplied as a UUID." + } + ] + }, + "description": "This endpoint returns a specific request state" + }, + "response": [ + { + "id": "2e68f156-50b9-4927-989c-1e6f10b046b8", + "name": "Represents an Error Caused by a Failure to Identify the Target Resource", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + } + ], + "url": { + "raw": "{{baseUrl}}/requeststates/:serverCorrelationId", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "requeststates", + ":serverCorrelationId" + ], + "variable": [ + { + "key": "serverCorrelationId" + } + ] + } + }, + "status": "Not Found", + "code": 404, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "22f849b6-afe2-4ef2-95be-ebc26667e94f", + "name": "Represents an Error Caused by an Authorisation Failure", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + } + ], + "url": { + "raw": "{{baseUrl}}/requeststates/:serverCorrelationId", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "requeststates", + ":serverCorrelationId" + ], + "variable": [ + { + "key": "serverCorrelationId" + } + ] + } + }, + "status": "Unauthorized", + "code": 401, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "10871140-c997-4628-8cff-2e16dd2c6bbe", + "name": "Represents an Asynchronous response", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + } + ], + "url": { + "raw": "{{baseUrl}}/requeststates/:serverCorrelationId", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "requeststates", + ":serverCorrelationId" + ], + "variable": [ + { + "key": "serverCorrelationId" + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"notificationMethod\": \"\",\n \"serverCorrelationId\": \"\",\n \"status\": \"\",\n \"pendingReason\": \"\",\n \"objectReference\": \"\",\n \"expiryTime\": \"\",\n \"pollLimit\": \"\",\n \"error\": {\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n }\n}" + }, + { + "id": "3155f9cc-39ec-49f9-883a-79fa6741b71f", + "name": "Represents an Error Caused by a General Server-Side Issue", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + } + ], + "url": { + "raw": "{{baseUrl}}/requeststates/:serverCorrelationId", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "requeststates", + ":serverCorrelationId" + ], + "variable": [ + { + "key": "serverCorrelationId" + } + ] + } + }, + "status": "Internal Server Error", + "code": 500, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "03f8e6c3-3d6d-4f2f-afab-e3e25f584a70", + "name": "Represents an Error Caused by the Violation of a Business Rule", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + } + ], + "url": { + "raw": "{{baseUrl}}/requeststates/:serverCorrelationId", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "requeststates", + ":serverCorrelationId" + ], + "variable": [ + { + "key": "serverCorrelationId" + } + ] + } + }, + "status": "Bad Request", + "code": 400, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "c4b284c7-962b-4e35-b4e1-d82607b3e1cf", + "name": "Represents an Error Caused by System Unavailability", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + } + ], + "url": { + "raw": "{{baseUrl}}/requeststates/:serverCorrelationId", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "requeststates", + ":serverCorrelationId" + ], + "variable": [ + { + "key": "serverCorrelationId" + } + ] + } + }, + "status": "Service Unavailable", + "code": 503, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + } + ] + }, + { + "name": "Update A Request State", + "id": "ea5ced60-35ca-4623-ae08-42f92d2efd4f", + "request": { + "method": "PATCH", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "[\n {\n \"op\": \"\",\n \"path\": \"\",\n \"value\": \"\"\n },\n {\n \"op\": \"\",\n \"path\": \"\",\n \"value\": \"\"\n }\n]" + }, + "url": { + "raw": "{{baseUrl}}/requeststates/:serverCorrelationId", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "requeststates", + ":serverCorrelationId" + ], + "variable": [ + { + "id": "8ed7fe4c-1471-4d9f-bbfd-5b2dd8bf13f0", + "key": "serverCorrelationId", + "value": "", + "description": "(Required) Path variable to uniquely identify a request state. Must be supplied as a UUID." + } + ] + }, + "description": "This endpoint updates a specific request state. This operation is to be deprecated. Please refer to Callback definitions for the revised approach to implementing asynchronous callbacks." + }, + "response": [ + { + "id": "9779875f-cc6e-448c-a67e-97a97361b557", + "name": "Represents an Error Caused by System Unavailability", + "originalRequest": { + "method": "PATCH", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + } + ], + "url": { + "raw": "{{baseUrl}}/requeststates/:serverCorrelationId", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "requeststates", + ":serverCorrelationId" + ], + "variable": [ + { + "key": "serverCorrelationId" + } + ] + } + }, + "status": "Service Unavailable", + "code": 503, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "fc5067ab-6a78-4c05-a04d-d8b727e9468b", + "name": "Represents an Error Caused by an Authorisation Failure", + "originalRequest": { + "method": "PATCH", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + } + ], + "url": { + "raw": "{{baseUrl}}/requeststates/:serverCorrelationId", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "requeststates", + ":serverCorrelationId" + ], + "variable": [ + { + "key": "serverCorrelationId" + } + ] + } + }, + "status": "Unauthorized", + "code": 401, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "2997c436-3dbb-42a4-9a17-b5d5b9a01a34", + "name": "Represents an Error Caused by a Failure to Identify the Target Resource", + "originalRequest": { + "method": "PATCH", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + } + ], + "url": { + "raw": "{{baseUrl}}/requeststates/:serverCorrelationId", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "requeststates", + ":serverCorrelationId" + ], + "variable": [ + { + "key": "serverCorrelationId" + } + ] + } + }, + "status": "Not Found", + "code": 404, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "aa0aa7c5-4c2c-4a7f-843f-1146fa7e95da", + "name": "An empty response is returned for a synchronous successful patch.", + "originalRequest": { + "method": "PATCH", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + } + ], + "url": { + "raw": "{{baseUrl}}/requeststates/:serverCorrelationId", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "requeststates", + ":serverCorrelationId" + ], + "variable": [ + { + "key": "serverCorrelationId" + } + ] + } + }, + "status": "No Content", + "code": 204, + "_postman_previewlanguage": "text", + "header": [ + { + "key": "Content-Type", + "value": "text/plain" + } + ], + "cookie": [], + "body": "" + }, + { + "id": "87c607be-8a73-4b3b-a3ec-28e5fd613310", + "name": "Represents an Error Caused by the Violation of a Business Rule", + "originalRequest": { + "method": "PATCH", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + } + ], + "url": { + "raw": "{{baseUrl}}/requeststates/:serverCorrelationId", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "requeststates", + ":serverCorrelationId" + ], + "variable": [ + { + "key": "serverCorrelationId" + } + ] + } + }, + "status": "Bad Request", + "code": 400, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "3b50f059-8f59-4ca8-8747-314dba04d406", + "name": "Represents an Error Caused by a General Server-Side Issue", + "originalRequest": { + "method": "PATCH", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + } + ], + "url": { + "raw": "{{baseUrl}}/requeststates/:serverCorrelationId", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "requeststates", + ":serverCorrelationId" + ], + "variable": [ + { + "key": "serverCorrelationId" + } + ] + } + }, + "status": "Internal Server Error", + "code": 500, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + } + ] + } + ], + "id": "c4d19532-5f8b-4cc1-a687-e35e57c02541" + }, + { + "name": "View Specific Statement", + "id": "e4f7be34-6bcf-46a6-9013-0d04a367f588", + "request": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/statemententries/:transactionReference", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "statemententries", + ":transactionReference" + ], + "variable": [ + { + "id": "238f652d-6f3f-4bf9-8433-b83845e3750a", + "key": "transactionReference", + "value": "", + "description": "(Required) Path variable to uniquely identify the transaction." + } + ] + }, + "description": "The Statement Entries API enables generic representations of transactions to be returned. Typically, the returned representations are used for the purposes of presenting a statement to the account holder. In order to return a statement, a transaction reference must be specified." + }, + "response": [ + { + "id": "d55f457b-cb75-4f69-9cf1-ad567e658b1b", + "name": "Represents an Error Caused by an Authorisation Failure", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/statemententries/:transactionReference", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "statemententries", + ":transactionReference" + ], + "variable": [ + { + "key": "transactionReference" + } + ] + } + }, + "status": "Unauthorized", + "code": 401, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "6ea3168b-2f05-4246-adb3-b599981a9fcc", + "name": "Represents an Error Caused by System Unavailability", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/statemententries/:transactionReference", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "statemententries", + ":transactionReference" + ], + "variable": [ + { + "key": "transactionReference" + } + ] + } + }, + "status": "Service Unavailable", + "code": 503, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "0a1f3724-07f9-45fc-84fe-f2db40ef9621", + "name": "Represents an Error Caused by the Violation of a Business Rule", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/statemententries/:transactionReference", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "statemententries", + ":transactionReference" + ], + "variable": [ + { + "key": "transactionReference" + } + ] + } + }, + "status": "Bad Request", + "code": 400, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "a8b20204-e816-4040-be17-2585f3c4cee1", + "name": "Represents an Error Caused by a Failure to Identify the Target Resource", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/statemententries/:transactionReference", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "statemententries", + ":transactionReference" + ], + "variable": [ + { + "key": "transactionReference" + } + ] + } + }, + "status": "Not Found", + "code": 404, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "8af6a05e-64f4-4175-8e69-538b4ff98ef9", + "name": "Represents an Error Caused by a General Server-Side Issue", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/statemententries/:transactionReference", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "statemententries", + ":transactionReference" + ], + "variable": [ + { + "key": "transactionReference" + } + ] + } + }, + "status": "Internal Server Error", + "code": 500, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "49440a58-4e80-431a-8bd1-27c1ed1b493b", + "name": "Represent a list of Statement Entries", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/statemententries/:transactionReference", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "statemententries", + ":transactionReference" + ], + "variable": [ + { + "key": "transactionReference" + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"amount\": \"15.21\",\n \"creditParty\": [\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n },\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n }\n ],\n \"currency\": \"\",\n \"debitParty\": [\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n },\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n }\n ],\n \"transactionReference\": \"\",\n \"transactionStatus\": \"\",\n \"displayType\": \"\",\n \"descriptionText\": \"\",\n \"requestDate\": \"\",\n \"creationDate\": \"\",\n \"modificationDate\": \"\",\n \"dateCreated\": \"\",\n \"dateModified\": \"\",\n \"transactionReceipt\": \"\"\n}" + } + ] + }, + { + "name": "Create A Bill Payment", + "id": "6927f254-80a5-4a21-a5ec-5675c6c43d89", + "request": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"currency\": \"\",\n \"amountPaid\": \"\",\n \"paidAmount\": \"\",\n \"serviceProviderPaymentReference\": \"\",\n \"requestingOrganisation\": \"\",\n \"requestingOrganisationTransactionReference\": \"\",\n \"customerReference\": \"\",\n \"paymentType\": \"\",\n \"supplementaryBillReferenceDetails\": [\n {\n \"paymentReferenceType\": \"\",\n \"paymentReferenceValue\": \"\"\n },\n {\n \"paymentReferenceType\": \"\",\n \"paymentReferenceValue\": \"\"\n }\n ],\n \"metadata\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + "url": { + "raw": "{{baseUrl}}/bills/:billReference/payments", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "bills", + ":billReference", + "payments" + ], + "variable": [ + { + "id": "9e76b898-9611-4b7a-889f-007de76a571f", + "key": "billReference", + "value": "", + "description": "(Required) Path variable to uniquely identify a bill." + } + ] + }, + "description": "Provided with a valid object representation, this endpoint allows for a new bill payment to be created." + }, + "response": [ + { + "id": "644b1b48-1a7b-416f-bc37-108b2cb3d67c", + "name": "Represents an Error Caused by System Unavailability", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/bills/:billReference/payments", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "bills", + ":billReference", + "payments" + ], + "variable": [ + { + "key": "billReference" + } + ] + } + }, + "status": "Service Unavailable", + "code": 503, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "0f9cf546-6e47-4e82-9735-fb91a376db5a", + "name": "Represents a Bill Payment response", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/bills/:billReference/payments", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "bills", + ":billReference", + "payments" + ], + "variable": [ + { + "key": "billReference" + } + ] + } + }, + "status": "Created", + "code": 201, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"currency\": \"\",\n \"amountPaid\": \"15.21\",\n \"billPaymentStatus\": \"\",\n \"paidAmount\": \"15.21\",\n \"serviceProviderPaymentReference\": \"\",\n \"requestingOrganisation\": \"\",\n \"requestingOrganisationTransactionReference\": \"\",\n \"customerReference\": \"\",\n \"paymentType\": \"\",\n \"serviceProviderComment\": \"\",\n \"serviceProviderNotification\": \"\",\n \"supplementaryBillReferenceDetails\": [\n {\n \"paymentReferenceType\": \"\",\n \"paymentReferenceValue\": \"\"\n },\n {\n \"paymentReferenceType\": \"\",\n \"paymentReferenceValue\": \"\"\n }\n ],\n \"metadata\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "204391ea-7764-44ac-ab05-f748c4cbdbc0", + "name": "Represents an Error Caused by a General Server-Side Issue", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/bills/:billReference/payments", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "bills", + ":billReference", + "payments" + ], + "variable": [ + { + "key": "billReference" + } + ] + } + }, + "status": "Internal Server Error", + "code": 500, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "e063ffdf-c515-4c4b-b610-341eaf03c9df", + "name": "Represents an Error Caused by the Violation of a Business Rule", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/bills/:billReference/payments", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "bills", + ":billReference", + "payments" + ], + "variable": [ + { + "key": "billReference" + } + ] + } + }, + "status": "Bad Request", + "code": 400, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "064a1cfa-2b5a-4f42-93e9-81d6e62d0467", + "name": "Represents an Asynchronous response", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/bills/:billReference/payments", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "bills", + ":billReference", + "payments" + ], + "variable": [ + { + "key": "billReference" + } + ] + } + }, + "status": "Accepted", + "code": 202, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"notificationMethod\": \"\",\n \"serverCorrelationId\": \"\",\n \"status\": \"\",\n \"pendingReason\": \"\",\n \"objectReference\": \"\",\n \"expiryTime\": \"\",\n \"pollLimit\": \"\",\n \"error\": {\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n }\n}" + }, + { + "id": "a3e8903d-7d80-4b18-a20c-ce6d00a0189f", + "name": "Represents an Error Caused by an Authorisation Failure", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/bills/:billReference/payments", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "bills", + ":billReference", + "payments" + ], + "variable": [ + { + "key": "billReference" + } + ] + } + }, + "status": "Unauthorized", + "code": 401, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "907bf521-1a37-45ab-99df-ed024c149e0b", + "name": "Represents an Error Caused by a Failure to Identify the Target Resource", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/bills/:billReference/payments", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "bills", + ":billReference", + "payments" + ], + "variable": [ + { + "key": "billReference" + } + ] + } + }, + "status": "Not Found", + "code": 404, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + } + ] + }, + { + "name": "Check API availability", + "id": "b4acff96-9414-41d2-b659-6db912c311a9", + "request": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + } + ], + "url": "{{baseUrl}}/heartbeat", + "description": "This endpoint returns the current status of the API" + }, + "response": [ + { + "id": "42e2844d-0d81-4c8f-a92d-88b3ba5050c7", + "name": "Represents an Error Caused by System Unavailability", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + } + ], + "url": "{{baseUrl}}/heartbeat" + }, + "status": "Service Unavailable", + "code": 503, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "79ba8697-5d39-494a-bbe3-151f38f3c3fe", + "name": "Represents an Error Caused by a Failure to Identify the Target Resource", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + } + ], + "url": "{{baseUrl}}/heartbeat" + }, + "status": "Not Found", + "code": 404, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "b0df66dc-a8f3-4d7a-97d3-4b7bed2b7bb7", + "name": "Represents an Error Caused by a General Server-Side Issue", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + } + ], + "url": "{{baseUrl}}/heartbeat" + }, + "status": "Internal Server Error", + "code": 500, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "c46f81c9-c81b-4555-befe-7dab29b1cea8", + "name": "Represents an Error Caused by the Violation of a Business Rule", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + } + ], + "url": "{{baseUrl}}/heartbeat" + }, + "status": "Bad Request", + "code": 400, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "76bdb336-9e77-4ad3-86ad-23e1ed1059f8", + "name": "Represents a Heartbeat response", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + } + ], + "url": "{{baseUrl}}/heartbeat" + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"serviceStatus\": \"\",\n \"delay\": \"\",\n \"plannedRestorationTime\": \"\"\n}" + }, + { + "id": "07c34754-50a4-4b29-93aa-d18442c805b8", + "name": "Represents an Error Caused by an Authorisation Failure", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + } + ], + "url": "{{baseUrl}}/heartbeat" + }, + "status": "Unauthorized", + "code": 401, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + } + ] + }, + { + "name": "View A Response", + "id": "be2b3f66-6031-4863-a1fc-62f099331e82", + "request": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + } + ], + "url": { + "raw": "{{baseUrl}}/responses/:clientCorrelationId", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "responses", + ":clientCorrelationId" + ], + "variable": [ + { + "id": "80b9c846-8240-4143-8400-62126b8cfc14", + "key": "clientCorrelationId", + "value": "", + "description": "(Required) Path variable to uniquely identify a response object. Must be supplied as a UUID." + } + ] + }, + "description": "This endpoint returns a specific response." + }, + "response": [ + { + "id": "9eab04a6-bb23-4962-b255-94452758858f", + "name": "Represents an Error Caused by a General Server-Side Issue", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + } + ], + "url": { + "raw": "{{baseUrl}}/responses/:clientCorrelationId", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "responses", + ":clientCorrelationId" + ], + "variable": [ + { + "key": "clientCorrelationId" + } + ] + } + }, + "status": "Internal Server Error", + "code": 500, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "8d565028-136c-4a4b-82b4-380ee143be31", + "name": "Represents an Error Caused by an Authorisation Failure", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + } + ], + "url": { + "raw": "{{baseUrl}}/responses/:clientCorrelationId", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "responses", + ":clientCorrelationId" + ], + "variable": [ + { + "key": "clientCorrelationId" + } + ] + } + }, + "status": "Unauthorized", + "code": 401, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "da23db15-d90c-4287-979f-6dcbe4441dc4", + "name": "Represents an Response object response", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + } + ], + "url": { + "raw": "{{baseUrl}}/responses/:clientCorrelationId", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "responses", + ":clientCorrelationId" + ], + "variable": [ + { + "key": "clientCorrelationId" + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"link\": \"\"\n}" + }, + { + "id": "d4a647a5-6471-4e21-85ee-ebd8952dd8ed", + "name": "Represents an Error Caused by the Violation of a Business Rule", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + } + ], + "url": { + "raw": "{{baseUrl}}/responses/:clientCorrelationId", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "responses", + ":clientCorrelationId" + ], + "variable": [ + { + "key": "clientCorrelationId" + } + ] + } + }, + "status": "Bad Request", + "code": 400, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "54045f37-22d6-4a16-9323-f967b6e75116", + "name": "Represents an Error Caused by System Unavailability", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + } + ], + "url": { + "raw": "{{baseUrl}}/responses/:clientCorrelationId", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "responses", + ":clientCorrelationId" + ], + "variable": [ + { + "key": "clientCorrelationId" + } + ] + } + }, + "status": "Service Unavailable", + "code": 503, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "id": "d2587bea-6250-4b13-913f-331a305c1340", + "name": "Represents an Error Caused by a Failure to Identify the Target Resource", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + } + ], + "url": { + "raw": "{{baseUrl}}/responses/:clientCorrelationId", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "responses", + ":clientCorrelationId" + ], + "variable": [ + { + "key": "clientCorrelationId" + } + ] + } + }, + "status": "Not Found", + "code": 404, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + } + ] + } + ], + "variable": [ + { + "id": "a278f053-e39c-4c0f-906a-7e2ab5538467", + "key": "baseUrl", + "value": "https://sandbox.mobilemoneyapi.io/simulator/v1.1/passthrough/mm", + "type": "string" + } + ] +} \ No newline at end of file diff --git a/ph-ee-env-template/PostmanCollections/Mojaloop Setup.postman_collection.json b/ph-ee-env-template/PostmanCollections/Mojaloop Setup.postman_collection.json new file mode 100644 index 000000000..546a99639 --- /dev/null +++ b/ph-ee-env-template/PostmanCollections/Mojaloop Setup.postman_collection.json @@ -0,0 +1,3661 @@ +{ + "info": { + "_postman_id": "0f06e33a-12a2-49ed-8b9c-6ba059f6a42e", + "name": "Mojaloop Setup", + "description": "Setup the mojaloop environment in any cluster with mojaloop chart already deployed. Use Mojaloop-Local environment along with this collection.", + "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json", + "_exporter_id": "17902615" + }, + "item": [ + { + "name": "Hub Account", + "item": [ + { + "name": "Add Hub Account-HUB_MULTILATERAL_SETTLEMENT", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 201\", function () {", + " pm.response.to.have.status(201);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "{{BEARER_TOKEN}}", + "type": "string" + } + ] + }, + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "FSPIOP-Source", + "type": "text", + "value": "{{payerfsp}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"type\": \"HUB_MULTILATERAL_SETTLEMENT\",\n \"currency\": \"{{currency}}\"\n}" + }, + "url": { + "raw": "{{HOST_CENTRAL_LEDGER}}/participants/Hub/accounts", + "host": [ + "{{HOST_CENTRAL_LEDGER}}" + ], + "path": [ + "participants", + "Hub", + "accounts" + ] + } + }, + "response": [] + }, + { + "name": "Add Hub Account-HUB_RECONCILIATION", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 201\", function () {", + " pm.response.to.have.status(201);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "{{BEARER_TOKEN}}", + "type": "string" + } + ] + }, + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "FSPIOP-Source", + "value": "{{payerfsp}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"type\": \"HUB_RECONCILIATION\",\n \"currency\": \"{{currency}}\"\n}" + }, + "url": { + "raw": "{{HOST_CENTRAL_LEDGER}}/participants/Hub/accounts", + "host": [ + "{{HOST_CENTRAL_LEDGER}}" + ], + "path": [ + "participants", + "Hub", + "accounts" + ] + } + }, + "response": [] + }, + { + "name": "Hub Set Endpoint-SETTLEMENT_TRANSFER_POSITION_CHANGE_EMAIL Copy", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 201\", function () {", + " pm.response.to.have.status(201);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "{{BEARER_TOKEN}}", + "type": "string" + } + ] + }, + "method": "POST", + "header": [ + { + "key": "Cache-Control", + "value": "no-cache" + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"type\": \"SETTLEMENT_TRANSFER_POSITION_CHANGE_EMAIL\",\n \"value\": \"sridevi.miriyala@modusbox.com\"\n}" + }, + "url": { + "raw": "{{HOST_CENTRAL_LEDGER}}/participants/Hub/endpoints", + "host": [ + "{{HOST_CENTRAL_LEDGER}}" + ], + "path": [ + "participants", + "Hub", + "endpoints" + ] + }, + "description": "Generated from a curl request: \ncurl -i -X POST {{HOST_CENTRAL_LEDGER}}/participants/testfsp2/initialPositionAndLimits -H 'Cache-Control: no-cache' -H 'Content-Type: application/json' -d '{\n \\\"currency\\\": \\\"USD\\\",\n \\\"limit\\\": {\n \\\"type\\\": \\\"NET_DEBIT_CAP\\\",\n \\\"value\\\": 1000\n },\n \\\"initialPosition\\\": 0\n }'" + }, + "response": [ + { + "name": "2. Create Initial Position and Limits", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "Cache-Control", + "value": "no-cache" + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"currency\": \"USD\",\n \"limit\": {\n \"type\": \"NET_DEBIT_CAP\",\n \"value\": 1000\n },\n \"initialPosition\": 0\n }" + }, + "url": { + "raw": "http://http:/central-ledger.sandbox.fynarfin.io/admin/participants/testfsp/initialPositionAndLimits", + "protocol": "http", + "host": [ + "http" + ], + "port": "", + "path": [ + "central-ledger.sandbox.fynarfin.io", + "admin", + "participants", + "testfsp", + "initialPositionAndLimits" + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "Text", + "header": [], + "cookie": [], + "body": "" + } + ] + }, + { + "name": "Hub Set Endpoint-NET_DEBIT_CAP_ADJUSTMENT_EMAIL Copy", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 201\", function () {", + " pm.response.to.have.status(201);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "{{BEARER_TOKEN}}", + "type": "string" + } + ] + }, + "method": "POST", + "header": [ + { + "key": "Cache-Control", + "value": "no-cache" + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"type\": \"NET_DEBIT_CAP_ADJUSTMENT_EMAIL\",\n \"value\": \"sridevi.miriyala@modusbox.com\"\n}" + }, + "url": { + "raw": "{{HOST_CENTRAL_LEDGER}}/participants/Hub/endpoints", + "host": [ + "{{HOST_CENTRAL_LEDGER}}" + ], + "path": [ + "participants", + "Hub", + "endpoints" + ] + }, + "description": "Generated from a curl request: \ncurl -i -X POST {{HOST_CENTRAL_LEDGER}}/participants/testfsp2/initialPositionAndLimits -H 'Cache-Control: no-cache' -H 'Content-Type: application/json' -d '{\n \\\"currency\\\": \\\"USD\\\",\n \\\"limit\\\": {\n \\\"type\\\": \\\"NET_DEBIT_CAP\\\",\n \\\"value\\\": 1000\n },\n \\\"initialPosition\\\": 0\n }'" + }, + "response": [ + { + "name": "2. Create Initial Position and Limits", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "Cache-Control", + "value": "no-cache" + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"currency\": \"USD\",\n \"limit\": {\n \"type\": \"NET_DEBIT_CAP\",\n \"value\": 1000\n },\n \"initialPosition\": 0\n }" + }, + "url": { + "raw": "http://http:/central-ledger.sandbox.fynarfin.io/admin/participants/testfsp/initialPositionAndLimits", + "protocol": "http", + "host": [ + "http" + ], + "port": "", + "path": [ + "central-ledger.sandbox.fynarfin.io", + "admin", + "participants", + "testfsp", + "initialPositionAndLimits" + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "Text", + "header": [], + "cookie": [], + "body": "" + } + ] + }, + { + "name": "Hub Endpoint-NET_DEBIT_CAP_THRESHOLD_BREACH_EMAIL Copy", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 201\", function () {", + " pm.response.to.have.status(201);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "{{BEARER_TOKEN}}", + "type": "string" + } + ] + }, + "method": "POST", + "header": [ + { + "key": "Cache-Control", + "value": "no-cache" + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"type\": \"NET_DEBIT_CAP_THRESHOLD_BREACH_EMAIL\",\n \"value\": \"sridevi.miriyala@modusbox.com\"\n}" + }, + "url": { + "raw": "{{HOST_CENTRAL_LEDGER}}/participants/Hub/endpoints", + "host": [ + "{{HOST_CENTRAL_LEDGER}}" + ], + "path": [ + "participants", + "Hub", + "endpoints" + ] + }, + "description": "Generated from a curl request: \ncurl -i -X POST {{HOST_CENTRAL_LEDGER}}/participants/testfsp2/initialPositionAndLimits -H 'Cache-Control: no-cache' -H 'Content-Type: application/json' -d '{\n \\\"currency\\\": \\\"USD\\\",\n \\\"limit\\\": {\n \\\"type\\\": \\\"NET_DEBIT_CAP\\\",\n \\\"value\\\": 1000\n },\n \\\"initialPosition\\\": 0\n }'" + }, + "response": [ + { + "name": "2. Create Initial Position and Limits", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "Cache-Control", + "value": "no-cache" + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"currency\": \"USD\",\n \"limit\": {\n \"type\": \"NET_DEBIT_CAP\",\n \"value\": 1000\n },\n \"initialPosition\": 0\n }" + }, + "url": { + "raw": "http://http:/central-ledger.sandbox.fynarfin.io/participants/testfsp/initialPositionAndLimits", + "protocol": "http", + "host": [ + "http" + ], + "port": "", + "path": [ + "central-ledger.sandbox.fynarfin.io", + "participants", + "testfsp", + "initialPositionAndLimits" + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "Text", + "header": [], + "cookie": [], + "body": "" + } + ] + } + ] + }, + { + "name": "Settlement Models", + "item": [ + { + "name": "Create settlement model DEFERREDNET", + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"name\": \"DEFERREDNET\",\n \"settlementGranularity\": \"NET\",\n \"settlementInterchange\": \"MULTILATERAL\",\n \"settlementDelay\": \"DEFERRED\",\n \"requireLiquidityCheck\": true,\n \"ledgerAccountType\": \"POSITION\",\n \"autoPositionReset\": true,\n \"settlementAccountType\" : \"SETTLEMENT\"\n}" + }, + "url": { + "raw": "{{HOST_CENTRAL_LEDGER}}/settlementModels", + "host": [ + "{{HOST_CENTRAL_LEDGER}}" + ], + "path": [ + "settlementModels" + ] + } + }, + "response": [] + }, + { + "name": "Create settlement model DEFERRED NET USD", + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"name\": \"DEFERREDNETUSD\",\n \"settlementGranularity\": \"NET\",\n \"settlementInterchange\": \"MULTILATERAL\",\n \"settlementDelay\": \"DEFERRED\",\n \"currency\": \"USD\",\n \"requireLiquidityCheck\": true,\n \"ledgerAccountType\": \"POSITION\",\n \"autoPositionReset\": true,\n \"settlementAccountType\" : \"SETTLEMENT\"\n}" + }, + "url": { + "raw": "{{HOST_CENTRAL_LEDGER}}/settlementModels", + "host": [ + "{{HOST_CENTRAL_LEDGER}}" + ], + "path": [ + "settlementModels" + ] + } + }, + "response": [] + } + ] + }, + { + "name": "FSP Onboarding", + "item": [ + { + "name": "payerfsp (p2p transfers)", + "item": [ + { + "name": "Add payerfsp - TRANSFERS", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 201\", function () {", + " pm.response.to.have.status(201);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "name": "Content-Type", + "value": "application/json", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\"name\": \"{{payerfsp}}\",\"currency\": \"{{currency}}\"}" + }, + "url": { + "raw": "{{HOST_CENTRAL_LEDGER}}/participants", + "host": [ + "{{HOST_CENTRAL_LEDGER}}" + ], + "path": [ + "participants" + ] + } + }, + "response": [] + }, + { + "name": "Add initial position and limits - payerfsp", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 201\", function () {", + " pm.response.to.have.status(201);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "name": "Content-Type", + "value": "application/json", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"currency\": \"{{currency}}\",\n\t\"limit\": {\n\t \"type\": \"NET_DEBIT_CAP\",\n\t \"value\": 1000000\n\t},\n\t\"initialPosition\": 0\n}" + }, + "url": { + "raw": "{{HOST_CENTRAL_LEDGER}}/participants/{{payerfsp}}/initialPositionAndLimits", + "host": [ + "{{HOST_CENTRAL_LEDGER}}" + ], + "path": [ + "participants", + "{{payerfsp}}", + "initialPositionAndLimits" + ] + } + }, + "response": [] + }, + { + "name": "Add payerfsp callback - PARTICIPANT PUT", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 201\", function () {", + " pm.response.to.have.status(201);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "name": "Content-Type", + "type": "text", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"type\": \"FSPIOP_CALLBACK_URL_PARTICIPANT_PUT\",\n \"value\": \"{{PAYER_CALLBACK_HOST}}/{{payerfsp}}/participants/{{partyIdType}}/{{partyIdentifier}}\"\n}" + }, + "url": { + "raw": "{{HOST_CENTRAL_LEDGER}}/participants/{{payerfsp}}/endpoints", + "host": [ + "{{HOST_CENTRAL_LEDGER}}" + ], + "path": [ + "participants", + "{{payerfsp}}", + "endpoints" + ] + } + }, + "response": [] + }, + { + "name": "Add payerfsp callback - PARTICIPANT PUT Error", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 201\", function () {", + " pm.response.to.have.status(201);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "name": "Content-Type", + "type": "text", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"type\": \"FSPIOP_CALLBACK_URL_PARTICIPANT_PUT_ERROR\",\n \"value\": \"{{PAYER_CALLBACK_HOST}}/{{payerfsp}}/participants/{{partyIdType}}/{{partyIdentifier}}/error\"\n}" + }, + "url": { + "raw": "{{HOST_CENTRAL_LEDGER}}/participants/{{payerfsp}}/endpoints", + "host": [ + "{{HOST_CENTRAL_LEDGER}}" + ], + "path": [ + "participants", + "{{payerfsp}}", + "endpoints" + ] + } + }, + "response": [] + }, + { + "name": "Add payerfsp callback - PARTICIPANT PUT Batch", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 201\", function () {", + " pm.response.to.have.status(201);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "name": "Content-Type", + "type": "text", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"type\": \"FSPIOP_CALLBACK_URL_PARTICIPANT_BATCH_PUT\",\n \"value\": \"{{PAYER_CALLBACK_HOST}}/{{payerfsp}}/participants/{{requestId}}\"\n}" + }, + "url": { + "raw": "{{HOST_CENTRAL_LEDGER}}/participants/{{payerfsp}}/endpoints", + "host": [ + "{{HOST_CENTRAL_LEDGER}}" + ], + "path": [ + "participants", + "{{payerfsp}}", + "endpoints" + ] + } + }, + "response": [] + }, + { + "name": "Add payerfsp callback - PARTICIPANT PUT Batch Error", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 201\", function () {", + " pm.response.to.have.status(201);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "name": "Content-Type", + "type": "text", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"type\": \"FSPIOP_CALLBACK_URL_PARTICIPANT_BATCH_PUT_ERROR\",\n \"value\": \"{{PAYER_CALLBACK_HOST}}/{{payerfsp}}/participants/{{requestId}}/error\"\n}" + }, + "url": { + "raw": "{{HOST_CENTRAL_LEDGER}}/participants/{{payerfsp}}/endpoints", + "host": [ + "{{HOST_CENTRAL_LEDGER}}" + ], + "path": [ + "participants", + "{{payerfsp}}", + "endpoints" + ] + } + }, + "response": [] + }, + { + "name": "Add payerfsp callback - PARTIES GET", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 201\", function () {", + " pm.response.to.have.status(201);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "name": "Content-Type", + "type": "text", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"type\": \"FSPIOP_CALLBACK_URL_PARTIES_GET\",\n \"value\": \"{{PAYER_CALLBACK_HOST}}/switch/parties/{{partyIdType}}/{{partyIdentifier}}\"\n}" + }, + "url": { + "raw": "{{HOST_CENTRAL_LEDGER}}/participants/{{payerfsp}}/endpoints", + "host": [ + "{{HOST_CENTRAL_LEDGER}}" + ], + "path": [ + "participants", + "{{payerfsp}}", + "endpoints" + ] + } + }, + "response": [] + }, + { + "name": "Add payerfsp callback - PARTIES PUT", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 201\", function () {", + " pm.response.to.have.status(201);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "name": "Content-Type", + "type": "text", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"type\": \"FSPIOP_CALLBACK_URL_PARTIES_PUT\",\n \"value\": \"{{PAYER_CALLBACK_HOST}}/switch/parties/{{partyIdType}}/{{partyIdentifier}}\"\n}" + }, + "url": { + "raw": "{{HOST_CENTRAL_LEDGER}}/participants/{{payerfsp}}/endpoints", + "host": [ + "{{HOST_CENTRAL_LEDGER}}" + ], + "path": [ + "participants", + "{{payerfsp}}", + "endpoints" + ] + } + }, + "response": [] + }, + { + "name": "Add payerfsp callback - PARTIES PUT Error", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 201\", function () {", + " pm.response.to.have.status(201);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "name": "Content-Type", + "type": "text", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"type\": \"FSPIOP_CALLBACK_URL_PARTIES_PUT_ERROR\",\n \"value\": \"{{PAYER_CALLBACK_HOST}}/switch/parties/{{partyIdType}}/{{partyIdentifier}}/error\"\n}" + }, + "url": { + "raw": "{{HOST_CENTRAL_LEDGER}}/participants/{{payerfsp}}/endpoints", + "host": [ + "{{HOST_CENTRAL_LEDGER}}" + ], + "path": [ + "participants", + "{{payerfsp}}", + "endpoints" + ] + } + }, + "response": [] + }, + { + "name": "Add payerfsp callback - QUOTES PUT", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 201\", function () {", + " pm.response.to.have.status(201);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "name": "Content-Type", + "type": "text", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"type\": \"FSPIOP_CALLBACK_URL_QUOTES\",\n \"value\": \"{{PAYER_CALLBACK_HOST}}/switch\"\n}" + }, + "url": { + "raw": "{{HOST_CENTRAL_LEDGER}}/participants/{{payerfsp}}/endpoints", + "host": [ + "{{HOST_CENTRAL_LEDGER}}" + ], + "path": [ + "participants", + "{{payerfsp}}", + "endpoints" + ] + } + }, + "response": [] + }, + { + "name": "Add payerfsp callback - TRANSFER POST", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 201\", function () {", + " pm.response.to.have.status(201);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "name": "Content-Type", + "type": "text", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"type\": \"FSPIOP_CALLBACK_URL_TRANSFER_POST\",\n \"value\": \"{{PAYER_CALLBACK_HOST}}/switch/transfers\"\n}" + }, + "url": { + "raw": "{{HOST_CENTRAL_LEDGER}}/participants/{{payerfsp}}/endpoints", + "host": [ + "{{HOST_CENTRAL_LEDGER}}" + ], + "path": [ + "participants", + "{{payerfsp}}", + "endpoints" + ] + } + }, + "response": [] + }, + { + "name": "Add payerfsp callback - TRANSFER PUT", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 201\", function () {", + " pm.response.to.have.status(201);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "name": "Content-Type", + "type": "text", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"type\": \"FSPIOP_CALLBACK_URL_TRANSFER_PUT\",\n \"value\": \"{{PAYER_CALLBACK_HOST}}/switch/transfers/{{transferId}}\"\n}" + }, + "url": { + "raw": "{{HOST_CENTRAL_LEDGER}}/participants/{{payerfsp}}/endpoints", + "host": [ + "{{HOST_CENTRAL_LEDGER}}" + ], + "path": [ + "participants", + "{{payerfsp}}", + "endpoints" + ] + } + }, + "response": [] + }, + { + "name": "Add payerfsp callback - TRANSFER ERROR", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 201\", function () {", + " pm.response.to.have.status(201);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "name": "Content-Type", + "type": "text", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"type\": \"FSPIOP_CALLBACK_URL_TRANSFER_ERROR\",\n \"value\": \"{{PAYER_CALLBACK_HOST}}/switch/transfers/{{transferId}}/error\"\n}" + }, + "url": { + "raw": "{{HOST_CENTRAL_LEDGER}}/participants/{{payerfsp}}/endpoints", + "host": [ + "{{HOST_CENTRAL_LEDGER}}" + ], + "path": [ + "participants", + "{{payerfsp}}", + "endpoints" + ] + } + }, + "response": [] + }, + { + "name": "Add payerfsp callback - PARTICIPANT SUB-ID PUT", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 201\", function () {", + " pm.response.to.have.status(201);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "name": "Content-Type", + "type": "text", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"type\": \"FSPIOP_CALLBACK_URL_PARTICIPANT_SUB_ID_PUT\",\n \"value\": \"{{PAYER_CALLBACK_HOST}}/{{payerfsp}}/participants/{{partyIdType}}/{{partyIdentifier}}/{{partySubIdOrType}}\"\n}" + }, + "url": { + "raw": "{{HOST_CENTRAL_LEDGER}}/participants/{{payerfsp}}/endpoints", + "host": [ + "{{HOST_CENTRAL_LEDGER}}" + ], + "path": [ + "participants", + "{{payerfsp}}", + "endpoints" + ] + } + }, + "response": [] + }, + { + "name": "Add payerfsp callback - PARTICIPANT SUB-ID PUT Error", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 201\", function () {", + " pm.response.to.have.status(201);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "name": "Content-Type", + "type": "text", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"type\": \"FSPIOP_CALLBACK_URL_PARTICIPANT_SUB_ID_PUT_ERROR\",\n \"value\": \"{{PAYER_CALLBACK_HOST}}/{{payerfsp}}/participants/{{partyIdType}}/{{partyIdentifier}}/{{partySubIdOrType}}/error\"\n}" + }, + "url": { + "raw": "{{HOST_CENTRAL_LEDGER}}/participants/{{payerfsp}}/endpoints", + "host": [ + "{{HOST_CENTRAL_LEDGER}}" + ], + "path": [ + "participants", + "{{payerfsp}}", + "endpoints" + ] + } + }, + "response": [] + }, + { + "name": "Add payerfsp callback - PARTICIPANT SUB-ID DELETE", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 201\", function () {", + " pm.response.to.have.status(201);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "name": "Content-Type", + "type": "text", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"type\": \"FSPIOP_CALLBACK_URL_PARTICIPANT_SUB_ID_DELETE\",\n \"value\": \"{{PAYER_CALLBACK_HOST}}/{{payerfsp}}/participants/{{partyIdType}}/{{partyIdentifier}}/{{partySubIdOrType}}\"\n}" + }, + "url": { + "raw": "{{HOST_CENTRAL_LEDGER}}/participants/{{payerfsp}}/endpoints", + "host": [ + "{{HOST_CENTRAL_LEDGER}}" + ], + "path": [ + "participants", + "{{payerfsp}}", + "endpoints" + ] + } + }, + "response": [] + }, + { + "name": "Add payerfsp callback - PARTIES SUB-ID GET", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 201\", function () {", + " pm.response.to.have.status(201);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "name": "Content-Type", + "type": "text", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"type\": \"FSPIOP_CALLBACK_URL_PARTIES_SUB_ID_GET\",\n \"value\": \"{{PAYER_CALLBACK_HOST}}/{{payerfsp}}/parties/{{partyIdType}}/{{partyIdentifier}}/{{partySubIdOrType}}\"\n}" + }, + "url": { + "raw": "{{HOST_CENTRAL_LEDGER}}/participants/{{payerfsp}}/endpoints", + "host": [ + "{{HOST_CENTRAL_LEDGER}}" + ], + "path": [ + "participants", + "{{payerfsp}}", + "endpoints" + ] + } + }, + "response": [] + }, + { + "name": "Add payerfsp callback - PARTIES SUB-ID PUT", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 201\", function () {", + " pm.response.to.have.status(201);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "name": "Content-Type", + "type": "text", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"type\": \"FSPIOP_CALLBACK_URL_PARTIES_SUB_ID_PUT\",\n \"value\": \"{{PAYER_CALLBACK_HOST}}/{{payerfsp}}/parties/{{partyIdType}}/{{partyIdentifier}}/{{partySubIdOrType}}\"\n}" + }, + "url": { + "raw": "{{HOST_CENTRAL_LEDGER}}/participants/{{payerfsp}}/endpoints", + "host": [ + "{{HOST_CENTRAL_LEDGER}}" + ], + "path": [ + "participants", + "{{payerfsp}}", + "endpoints" + ] + } + }, + "response": [] + }, + { + "name": "Add payerfsp callback - PARTIES SUB-ID PUT Error", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 201\", function () {", + " pm.response.to.have.status(201);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "name": "Content-Type", + "type": "text", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"type\": \"FSPIOP_CALLBACK_URL_PARTIES_SUB_ID_PUT_ERROR\",\n \"value\": \"{{PAYER_CALLBACK_HOST}}/{{payerfsp}}/parties/{{partyIdType}}/{{partyIdentifier}}/{{partySubIdOrType}}/error\"\n}" + }, + "url": { + "raw": "{{HOST_CENTRAL_LEDGER}}/participants/{{payerfsp}}/endpoints", + "host": [ + "{{HOST_CENTRAL_LEDGER}}" + ], + "path": [ + "participants", + "{{payerfsp}}", + "endpoints" + ] + } + }, + "response": [] + }, + { + "name": "Add payerfsp callback - FSPIOP_CALLBACK_URL_TRX_REQ_SERVICE", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 201\", function () {", + " pm.response.to.have.status(201);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "name": "Content-Type", + "type": "text", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"type\": \"FSPIOP_CALLBACK_URL_TRX_REQ_SERVICE\",\n \"value\": \"{{PAYER_CALLBACK_HOST}}\"\n}" + }, + "url": { + "raw": "{{HOST_CENTRAL_LEDGER}}/participants/{{payerfsp}}/endpoints", + "host": [ + "{{HOST_CENTRAL_LEDGER}}" + ], + "path": [ + "participants", + "{{payerfsp}}", + "endpoints" + ] + } + }, + "response": [] + }, + { + "name": "Add payerfsp callback - FSPIOP_CALLBACK_URL_AUTHORIZATIONS", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 201\", function () {", + " pm.response.to.have.status(201);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "name": "Content-Type", + "type": "text", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"type\": \"FSPIOP_CALLBACK_URL_AUTHORIZATIONS\",\n \"value\": \"{{PAYER_CALLBACK_HOST}}\"\n}" + }, + "url": { + "raw": "{{HOST_CENTRAL_LEDGER}}/participants/{{payerfsp}}/endpoints", + "host": [ + "{{HOST_CENTRAL_LEDGER}}" + ], + "path": [ + "participants", + "{{payerfsp}}", + "endpoints" + ] + } + }, + "response": [] + }, + { + "name": "Record Funds In - payerfsp ", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 202\", function () {", + " pm.response.to.have.status(202);", + "});" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "var uuid = require('uuid');", + "var generatedUUID = uuid.v4();", + "pm.environment.set('fundsInPrepareTransferId', generatedUUID);", + "pm.environment.set('fundsInPrepareAmount', 5000);", + "", + "", + "const payerfspGetStatusRequest = {", + " url: pm.environment.get(\"HOST_CENTRAL_LEDGER\")+pm.environment.get(\"BASE_CENTRAL_LEDGER_ADMIN\")+'/participants/'+pm.environment.get(\"payerfsp\")+'/accounts',", + " method: 'GET',", + " header: {", + " \"Authorization\":\"Bearer \"+pm.environment.get(\"HUB_OPERATOR_BEARER_TOKEN\"),", + " \"FSPIOP-Source\": pm.environment.get(\"hub_operator\"),", + " \"Content-Type\": \"application/json\"", + " }", + "};", + "pm.sendRequest(payerfspGetStatusRequest, function (err, response) {", + " console.log(response.json())", + " var jsonData = response.json()", + " for(var i in jsonData) {", + " if((jsonData[i].ledgerAccountType === 'SETTLEMENT') && (jsonData[i].currency === pm.environment.get(\"currency\"))) {", + " pm.environment.set(\"payerfspSettlementAccountId\",jsonData[i].id)", + " pm.environment.set(\"payerfspSettlementAccountBalanceBeforeFundsIn\",jsonData[i].value)", + " }", + " }", + "});", + "", + "const hubGetStatusRequest = {", + " url: pm.environment.get(\"HOST_CENTRAL_LEDGER\")+pm.environment.get(\"BASE_CENTRAL_LEDGER_ADMIN\")+'/participants/Hub/accounts',", + " method: 'GET',", + " header: {", + " \"Authorization\":\"Bearer \"+pm.environment.get(\"BEARER_TOKEN\"),", + " \"FSPIOP-Source\": pm.environment.get(\"payerfsp\"),", + " \"Content-Type\": \"application/json\"", + " }", + "};", + "pm.sendRequest(hubGetStatusRequest, function (err, response) {", + " console.log(response.json())", + " var jsonData = response.json()", + " for(var i in jsonData) {", + " if((jsonData[i].ledgerAccountType === 'HUB_RECONCILIATION') && (jsonData[i].currency === pm.environment.get(\"currency\"))) {", + " pm.environment.set(\"hubReconAccountBalanceBeforeFundsIn\",jsonData[i].value)", + " }", + " }", + "});", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "{{BEARER_TOKEN}}", + "type": "string" + } + ] + }, + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "FSPIOP-Source", + "value": "{{payerfsp}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"transferId\": \"{{fundsInPrepareTransferId}}\",\n \"externalReference\": \"string\",\n \"action\": \"recordFundsIn\",\n \"reason\": \"string\",\n \"amount\": {\n \"amount\":\"{{fundsInPrepareAmount}}\" ,\n \"currency\": \"{{currency}}\"\n },\n \"extensionList\": {\n \"extension\": [\n {\n \"key\": \"string\",\n \"value\": \"string\"\n }\n ]\n }\n}" + }, + "url": { + "raw": "{{HOST_CENTRAL_LEDGER}}/participants/{{payerfsp}}/accounts/{{payerfspSettlementAccountId}}", + "host": [ + "{{HOST_CENTRAL_LEDGER}}" + ], + "path": [ + "participants", + "{{payerfsp}}", + "accounts", + "{{payerfspSettlementAccountId}}" + ] + } + }, + "response": [] + } + ] + }, + { + "name": "payeefsp (p2p transfers)", + "item": [ + { + "name": "Add payeefsp - TRANSFERS", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 201\", function () {", + " pm.response.to.have.status(201);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "name": "Content-Type", + "type": "text", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\"name\": \"{{payeefsp}}\",\"currency\": \"{{currency}}\"}" + }, + "url": { + "raw": "{{HOST_CENTRAL_LEDGER}}/participants", + "host": [ + "{{HOST_CENTRAL_LEDGER}}" + ], + "path": [ + "participants" + ] + } + }, + "response": [] + }, + { + "name": "Add initial position and limits - payeefsp", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 201\", function () {", + " pm.response.to.have.status(201);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "name": "Content-Type", + "type": "text", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"currency\": \"{{currency}}\",\n\t\"limit\": {\n\t \"type\": \"NET_DEBIT_CAP\",\n\t \"value\": 1000000\n\t},\n\t\"initialPosition\": 0\n}" + }, + "url": { + "raw": "{{HOST_CENTRAL_LEDGER}}/participants/{{payeefsp}}/initialPositionAndLimits", + "host": [ + "{{HOST_CENTRAL_LEDGER}}" + ], + "path": [ + "participants", + "{{payeefsp}}", + "initialPositionAndLimits" + ] + } + }, + "response": [] + }, + { + "name": "Add payerfsp callback - PARTICIPANT PUT", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 201\", function () {", + " pm.response.to.have.status(201);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "name": "Content-Type", + "type": "text", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"type\": \"FSPIOP_CALLBACK_URL_PARTICIPANT_PUT\",\n \"value\": \"{{PAYEE_CALLBACK_HOST}}/{{payeefsp}}/participants/{{partyIdType}}/{{partyIdentifier}}\"\n}" + }, + "url": { + "raw": "{{HOST_CENTRAL_LEDGER}}/participants/{{payeefsp}}/endpoints", + "host": [ + "{{HOST_CENTRAL_LEDGER}}" + ], + "path": [ + "participants", + "{{payeefsp}}", + "endpoints" + ] + } + }, + "response": [] + }, + { + "name": "Add payerfsp callback - PARTICIPANT PUT Error", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 201\", function () {", + " pm.response.to.have.status(201);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "name": "Content-Type", + "type": "text", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"type\": \"FSPIOP_CALLBACK_URL_PARTICIPANT_PUT_ERROR\",\n \"value\": \"{{PAYEE_CALLBACK_HOST}}/{{payeefsp}}/participants/{{partyIdType}}/{{partyIdentifier}}/error\"\n}" + }, + "url": { + "raw": "{{HOST_CENTRAL_LEDGER}}/participants/{{payeefsp}}/endpoints", + "host": [ + "{{HOST_CENTRAL_LEDGER}}" + ], + "path": [ + "participants", + "{{payeefsp}}", + "endpoints" + ] + } + }, + "response": [] + }, + { + "name": "Add payerfsp callback - PARTICIPANT PUT Batch", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 201\", function () {", + " pm.response.to.have.status(201);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "name": "Content-Type", + "type": "text", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"type\": \"FSPIOP_CALLBACK_URL_PARTICIPANT_BATCH_PUT\",\n \"value\": \"{{PAYEE_CALLBACK_HOST}}/{{payeefsp}}/participants/{{requestId}}\"\n}" + }, + "url": { + "raw": "{{HOST_CENTRAL_LEDGER}}/participants/{{payeefsp}}/endpoints", + "host": [ + "{{HOST_CENTRAL_LEDGER}}" + ], + "path": [ + "participants", + "{{payeefsp}}", + "endpoints" + ] + } + }, + "response": [] + }, + { + "name": "Add payerfsp callback - PARTICIPANT PUT Batch Error", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 201\", function () {", + " pm.response.to.have.status(201);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "name": "Content-Type", + "type": "text", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"type\": \"FSPIOP_CALLBACK_URL_PARTICIPANT_BATCH_PUT_ERROR\",\n \"value\": \"{{PAYEE_CALLBACK_HOST}}/{{payeefsp}}/participants/{{requestId}}/error\"\n}" + }, + "url": { + "raw": "{{HOST_CENTRAL_LEDGER}}/participants/{{payeefsp}}/endpoints", + "host": [ + "{{HOST_CENTRAL_LEDGER}}" + ], + "path": [ + "participants", + "{{payeefsp}}", + "endpoints" + ] + } + }, + "response": [] + }, + { + "name": "Add payerfsp callback - PARTIES GET", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 201\", function () {", + " pm.response.to.have.status(201);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "name": "Content-Type", + "type": "text", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"type\": \"FSPIOP_CALLBACK_URL_PARTIES_GET\",\n \"value\": \"{{PAYEE_CALLBACK_HOST}}/switch/parties/{{partyIdType}}/{{partyIdentifier}}\"\n}" + }, + "url": { + "raw": "{{HOST_CENTRAL_LEDGER}}/participants/{{payeefsp}}/endpoints", + "host": [ + "{{HOST_CENTRAL_LEDGER}}" + ], + "path": [ + "participants", + "{{payeefsp}}", + "endpoints" + ] + } + }, + "response": [] + }, + { + "name": "Add payerfsp callback - PARTIES PUT", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 201\", function () {", + " pm.response.to.have.status(201);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "name": "Content-Type", + "type": "text", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"type\": \"FSPIOP_CALLBACK_URL_PARTIES_PUT\",\n \"value\": \"{{PAYEE_CALLBACK_HOST}}/switch/parties/{{partyIdType}}/{{partyIdentifier}}\"\n}" + }, + "url": { + "raw": "{{HOST_CENTRAL_LEDGER}}/participants/{{payeefsp}}/endpoints", + "host": [ + "{{HOST_CENTRAL_LEDGER}}" + ], + "path": [ + "participants", + "{{payeefsp}}", + "endpoints" + ] + } + }, + "response": [] + }, + { + "name": "Add payerfsp callback - PARTIES PUT Error", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 201\", function () {", + " pm.response.to.have.status(201);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "name": "Content-Type", + "type": "text", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"type\": \"FSPIOP_CALLBACK_URL_PARTIES_PUT_ERROR\",\n \"value\": \"{{PAYEE_CALLBACK_HOST}}/switch/parties/{{partyIdType}}/{{partyIdentifier}}/error\"\n}" + }, + "url": { + "raw": "{{HOST_CENTRAL_LEDGER}}/participants/{{payeefsp}}/endpoints", + "host": [ + "{{HOST_CENTRAL_LEDGER}}" + ], + "path": [ + "participants", + "{{payeefsp}}", + "endpoints" + ] + } + }, + "response": [] + }, + { + "name": "Add payerfsp callback - QUOTES PUT", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 201\", function () {", + " pm.response.to.have.status(201);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "name": "Content-Type", + "type": "text", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"type\": \"FSPIOP_CALLBACK_URL_QUOTES\",\n \"value\": \"{{PAYEE_CALLBACK_HOST}}/switch\"\n}" + }, + "url": { + "raw": "{{HOST_CENTRAL_LEDGER}}/participants/{{payeefsp}}/endpoints", + "host": [ + "{{HOST_CENTRAL_LEDGER}}" + ], + "path": [ + "participants", + "{{payeefsp}}", + "endpoints" + ] + } + }, + "response": [] + }, + { + "name": "Add payeefsp callback - TRANSFER POST", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 201\", function () {", + " pm.response.to.have.status(201);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "name": "Content-Type", + "type": "text", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"type\": \"FSPIOP_CALLBACK_URL_TRANSFER_POST\",\n \"value\": \"{{PAYEE_CALLBACK_HOST}}/switch/transfers\"\n}" + }, + "url": { + "raw": "{{HOST_CENTRAL_LEDGER}}/participants/{{payeefsp}}/endpoints", + "host": [ + "{{HOST_CENTRAL_LEDGER}}" + ], + "path": [ + "participants", + "{{payeefsp}}", + "endpoints" + ] + } + }, + "response": [] + }, + { + "name": "Add payeefsp callback - TRANSFER PUT", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 201\", function () {", + " pm.response.to.have.status(201);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "name": "Content-Type", + "type": "text", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"type\": \"FSPIOP_CALLBACK_URL_TRANSFER_PUT\",\n \"value\": \"{{PAYEE_CALLBACK_HOST}}/switch/transfers/{{transferId}}\"\n}" + }, + "url": { + "raw": "{{HOST_CENTRAL_LEDGER}}/participants/{{payeefsp}}/endpoints", + "host": [ + "{{HOST_CENTRAL_LEDGER}}" + ], + "path": [ + "participants", + "{{payeefsp}}", + "endpoints" + ] + } + }, + "response": [] + }, + { + "name": "Add payeefsp callback - TRANSFER ERROR", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 201\", function () {", + " pm.response.to.have.status(201);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "name": "Content-Type", + "type": "text", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"type\": \"FSPIOP_CALLBACK_URL_TRANSFER_ERROR\",\n \"value\": \"{{PAYEE_CALLBACK_HOST}}/switch/transfers/{{transferId}}/error\"\n}" + }, + "url": { + "raw": "{{HOST_CENTRAL_LEDGER}}/participants/{{payeefsp}}/endpoints", + "host": [ + "{{HOST_CENTRAL_LEDGER}}" + ], + "path": [ + "participants", + "{{payeefsp}}", + "endpoints" + ] + } + }, + "response": [] + }, + { + "name": "Add payeefsp callback - PARTICIPANT SUB-ID PUT", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 201\", function () {", + " pm.response.to.have.status(201);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "name": "Content-Type", + "type": "text", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"type\": \"FSPIOP_CALLBACK_URL_PARTICIPANT_SUB_ID_PUT\",\n \"value\": \"{{PAYEE_CALLBACK_HOST}}/{{payeefsp}}/participants/{{partyIdType}}/{{partyIdentifier}}/{{partySubIdOrType}}\"\n}" + }, + "url": { + "raw": "{{HOST_CENTRAL_LEDGER}}/participants/{{payeefsp}}/endpoints", + "host": [ + "{{HOST_CENTRAL_LEDGER}}" + ], + "path": [ + "participants", + "{{payeefsp}}", + "endpoints" + ] + } + }, + "response": [] + }, + { + "name": "Add payeefsp callback - PARTICIPANT SUB-ID PUT Error", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 201\", function () {", + " pm.response.to.have.status(201);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "name": "Content-Type", + "type": "text", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"type\": \"FSPIOP_CALLBACK_URL_PARTICIPANT_SUB_ID_PUT_ERROR\",\n \"value\": \"{{PAYEE_CALLBACK_HOST}}/{{payeefsp}}/participants/{{partyIdType}}/{{partyIdentifier}}/{{partySubIdOrType}}/error\"\n}" + }, + "url": { + "raw": "{{HOST_CENTRAL_LEDGER}}/participants/{{payeefsp}}/endpoints", + "host": [ + "{{HOST_CENTRAL_LEDGER}}" + ], + "path": [ + "participants", + "{{payeefsp}}", + "endpoints" + ] + } + }, + "response": [] + }, + { + "name": "Add payeefsp callback - PARTIES SUB-ID GET", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 201\", function () {", + " pm.response.to.have.status(201);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "name": "Content-Type", + "type": "text", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"type\": \"FSPIOP_CALLBACK_URL_PARTIES_SUB_ID_GET\",\n \"value\": \"{{PAYEE_CALLBACK_HOST}}/{{payeefsp}}/parties/{{partyIdType}}/{{partyIdentifier}}/{{partySubIdOrType}}\"\n}" + }, + "url": { + "raw": "{{HOST_CENTRAL_LEDGER}}/participants/{{payeefsp}}/endpoints", + "host": [ + "{{HOST_CENTRAL_LEDGER}}" + ], + "path": [ + "participants", + "{{payeefsp}}", + "endpoints" + ] + } + }, + "response": [] + }, + { + "name": "Add payeefsp callback - PARTIES SUB-ID PUT", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 201\", function () {", + " pm.response.to.have.status(201);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "name": "Content-Type", + "type": "text", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"type\": \"FSPIOP_CALLBACK_URL_PARTIES_SUB_ID_PUT\",\n \"value\": \"{{PAYEE_CALLBACK_HOST}}/{{payeefsp}}/parties/{{partyIdType}}/{{partyIdentifier}}/{{partySubIdOrType}}\"\n}" + }, + "url": { + "raw": "{{HOST_CENTRAL_LEDGER}}/participants/{{payeefsp}}/endpoints", + "host": [ + "{{HOST_CENTRAL_LEDGER}}" + ], + "path": [ + "participants", + "{{payeefsp}}", + "endpoints" + ] + } + }, + "response": [] + }, + { + "name": "Add payeefsp callback - PARTIES SUB-ID PUT Error", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 201\", function () {", + " pm.response.to.have.status(201);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "name": "Content-Type", + "type": "text", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"type\": \"FSPIOP_CALLBACK_URL_PARTIES_SUB_ID_PUT_ERROR\",\n \"value\": \"{{PAYEE_CALLBACK_HOST}}/{{payeefsp}}/parties/{{partyIdType}}/{{partyIdentifier}}/{{partySubIdOrType}}/error\"\n}" + }, + "url": { + "raw": "{{HOST_CENTRAL_LEDGER}}/participants/{{payeefsp}}/endpoints", + "host": [ + "{{HOST_CENTRAL_LEDGER}}" + ], + "path": [ + "participants", + "{{payeefsp}}", + "endpoints" + ] + } + }, + "response": [] + }, + { + "name": "Record Funds In - payeefsp ", + "event": [ + { + "listen": "prerequest", + "script": { + "exec": [ + "var uuid = require('uuid');", + "var generatedUUID = uuid.v4();", + "pm.environment.set('fundsInPrepareTransferId', generatedUUID);", + "pm.environment.set('fundsInPrepareAmount', 5000);", + "", + "", + "const payerfspGetStatusRequest = {", + " url: pm.environment.get(\"HOST_CENTRAL_LEDGER\")+pm.environment.get(\"BASE_CENTRAL_LEDGER_ADMIN\")+'/participants/'+pm.environment.get(\"payeefsp\")+'/accounts',", + " method: 'GET',", + " header: {", + " \"Authorization\":\"Bearer \"+pm.environment.get(\"HUB_OPERATOR_BEARER_TOKEN\"),", + " \"FSPIOP-Source\": pm.environment.get(\"hub_operator\"),", + " \"Content-Type\": \"application/json\"", + " }", + "};", + "pm.sendRequest(payerfspGetStatusRequest, function (err, response) {", + " console.log(response.json())", + " var jsonData = response.json()", + " for(var i in jsonData) {", + " if((jsonData[i].ledgerAccountType === 'SETTLEMENT') && (jsonData[i].currency === pm.environment.get(\"currency\"))) {", + " pm.environment.set(\"payeefspSettlementAccountId\",jsonData[i].id)", + " pm.environment.set(\"payeefspSettlementAccountBalanceBeforeFundsIn\",jsonData[i].value)", + " }", + " }", + "});", + "", + "const hubGetStatusRequest = {", + " url: pm.environment.get(\"HOST_CENTRAL_LEDGER\")+pm.environment.get(\"BASE_CENTRAL_LEDGER_ADMIN\")+'/participants/Hub/accounts',", + " method: 'GET',", + " header: {", + " \"Authorization\":\"Bearer \"+pm.environment.get(\"BEARER_TOKEN\"),", + " \"FSPIOP-Source\": pm.environment.get(\"payerfsp\"),", + " \"Content-Type\": \"application/json\"", + " }", + "};", + "pm.sendRequest(hubGetStatusRequest, function (err, response) {", + " console.log(response.json())", + " var jsonData = response.json()", + " for(var i in jsonData) {", + " if((jsonData[i].ledgerAccountType === 'HUB_RECONCILIATION') && (jsonData[i].currency === pm.environment.get(\"currency\"))) {", + " pm.environment.set(\"hubReconAccountBalanceBeforeFundsIn\",jsonData[i].value)", + " }", + " }", + "});", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 202\", function () {", + " pm.response.to.have.status(202);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "{{HUBOPERATOR_BEARER_TOKEN}}", + "type": "string" + } + ] + }, + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "FSPIOP-Source", + "type": "text", + "value": "{{hub_operator}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"transferId\": \"{{fundsInPrepareTransferId}}\",\n \"externalReference\": \"string\",\n \"action\": \"recordFundsIn\",\n \"reason\": \"string\",\n \"amount\": {\n \"amount\":\"{{fundsInPrepareAmount}}\" ,\n \"currency\": \"{{currency}}\"\n },\n \"extensionList\": {\n \"extension\": [\n {\n \"key\": \"string\",\n \"value\": \"string\"\n }\n ]\n }\n}" + }, + "url": { + "raw": "{{HOST_CENTRAL_LEDGER}}/participants/{{payeefsp}}/accounts/{{payeefspSettlementAccountId}}", + "host": [ + "{{HOST_CENTRAL_LEDGER}}" + ], + "path": [ + "participants", + "{{payeefsp}}", + "accounts", + "{{payeefspSettlementAccountId}}" + ] + } + }, + "response": [] + } + ] + } + ], + "event": [ + { + "listen": "prerequest", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + }, + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + } + ] + }, + { + "name": "Add Users to Simulators", + "item": [ + { + "name": "payeefsp", + "item": [ + { + "name": "Add User - 27713803912", + "event": [ + { + "listen": "prerequest", + "script": { + "exec": [ + "pm.environment.set('fullName', 'Siabelo Maroka');", + "pm.environment.set('firstName', 'Siabelo');", + "pm.environment.set('lastName', 'Maroka');", + "pm.environment.set('dob', '3/3/1973');", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 202\", function () {", + " pm.response.to.have.status(202);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"party\": {\n \"partyIdInfo\": {\n \"partyIdType\": \"MSISDN\",\n \"partyIdentifier\": \"27713803912\",\n \"fspId\": \"{{payeefsp}}\"\n },\n \"name\": \"{{fullName}}\",\n \"personalInfo\": {\n \"complexName\": {\n \"firstName\": \"{{firstName}}\",\n \"lastName\": \"{{lastName}}\"\n },\n \"dateOfBirth\": \"{{dob}}\"\n }\n }\n}" + }, + "url": { + "raw": "{{HOST_SIMULATOR}}/{{payeefsp}}/parties/MSISDN/27713803912", + "host": [ + "{{HOST_SIMULATOR}}" + ], + "path": [ + "{{payeefsp}}", + "parties", + "MSISDN", + "27713803912" + ] + } + }, + "response": [] + }, + { + "name": "Add User - 27713803913", + "event": [ + { + "listen": "prerequest", + "script": { + "exec": [ + "pm.environment.set('fullName', 'Nanga Makwetla');", + "pm.environment.set('firstName', 'Nanga');", + "pm.environment.set('lastName', 'Makwetla');", + "pm.environment.set('dob', '4/4/1974');", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 202\", function () {", + " pm.response.to.have.status(202);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"party\": {\n \"partyIdInfo\": {\n \"partyIdType\": \"MSISDN\",\n \"partyIdentifier\": \"27713803932\",\n \"fspId\": \"{{payeefsp}}\"\n },\n \"name\": \"{{fullName}}\",\n \"personalInfo\": {\n \"complexName\": {\n \"firstName\": \"{{firstName}}\",\n \"lastName\": \"{{lastName}}\"\n },\n \"dateOfBirth\": \"{{dob}}\"\n }\n }\n}" + }, + "url": { + "raw": "{{HOST_SIMULATOR}}/{{payeefsp}}/parties/MSISDN/27713803913", + "host": [ + "{{HOST_SIMULATOR}}" + ], + "path": [ + "{{payeefsp}}", + "parties", + "MSISDN", + "27713803913" + ] + } + }, + "response": [] + }, + { + "name": "Add User - 27713803914", + "event": [ + { + "listen": "prerequest", + "script": { + "exec": [ + "pm.environment.set('fullName', 'Abimbola Alao');", + "pm.environment.set('firstName', 'Abimbola');", + "pm.environment.set('lastName', 'Alao');", + "pm.environment.set('dob', '5/5/1975');", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 202\", function () {", + " pm.response.to.have.status(202);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"party\": {\n \"partyIdInfo\": {\n \"partyIdType\": \"MSISDN\",\n \"partyIdentifier\": \"27713803914\",\n \"fspId\": \"{{payeefsp}}\"\n },\n \"name\": \"{{fullName}}\",\n \"personalInfo\": {\n \"complexName\": {\n \"firstName\": \"{{firstName}}\",\n \"lastName\": \"{{lastName}}\"\n },\n \"dateOfBirth\": \"{{dob}}\"\n }\n }\n}" + }, + "url": { + "raw": "{{HOST_SIMULATOR}}/{{payeefsp}}/parties/MSISDN/27713803914", + "host": [ + "{{HOST_SIMULATOR}}" + ], + "path": [ + "{{payeefsp}}", + "parties", + "MSISDN", + "27713803914" + ] + } + }, + "response": [] + }, + { + "name": "Add User - 27713803915", + "event": [ + { + "listen": "prerequest", + "script": { + "exec": [ + "pm.environment.set('fullName', 'Adeola Baba');", + "pm.environment.set('firstName', 'Adeola');", + "pm.environment.set('lastName', 'Baba');", + "pm.environment.set('dob', '6/6/1976');", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 202\", function () {", + " pm.response.to.have.status(202);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"party\": {\n \"partyIdInfo\": {\n \"partyIdType\": \"MSISDN\",\n \"partyIdentifier\": \"27713803915\",\n \"fspId\": \"{{payeefsp}}\"\n },\n \"name\": \"{{fullName}}\",\n \"personalInfo\": {\n \"complexName\": {\n \"firstName\": \"{{firstName}}\",\n \"lastName\": \"{{lastName}}\"\n },\n \"dateOfBirth\": \"{{dob}}\"\n }\n }\n}" + }, + "url": { + "raw": "{{HOST_SIMULATOR}}/{{payeefsp}}/parties/MSISDN/27713803915", + "host": [ + "{{HOST_SIMULATOR}}" + ], + "path": [ + "{{payeefsp}}", + "parties", + "MSISDN", + "27713803915" + ] + } + }, + "response": [] + }, + { + "name": "Add User - {{pathfinderMSISDN}}", + "event": [ + { + "listen": "prerequest", + "script": { + "exec": [ + "pm.variables.set('fullName', 'SimFirst SimLast');", + "pm.variables.set('firstName', 'SimFirst');", + "pm.variables.set('lastName', 'SimLast');", + "pm.variables.set('dob', '2010-10-10');", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 202\", function () {", + " pm.response.to.have.status(202);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"party\": {\n \"partyIdInfo\": {\n \"partyIdType\": \"MSISDN\",\n \"partyIdentifier\": \"{{pathfinderMSISDN}}\",\n \"fspId\": \"{{payeefsp}}\"\n },\n \"name\": \"{{fullName}}\",\n \"personalInfo\": {\n \"complexName\": {\n \"firstName\": \"{{firstName}}\",\n \"lastName\": \"{{lastName}}\"\n },\n \"dateOfBirth\": \"{{dob}}\"\n }\n }\n}" + }, + "url": { + "raw": "{{HOST_SIMULATOR}}/{{payeefsp}}/parties/MSISDN/{{pathfinderMSISDN}}", + "host": [ + "{{HOST_SIMULATOR}}" + ], + "path": [ + "{{payeefsp}}", + "parties", + "MSISDN", + "{{pathfinderMSISDN}}" + ] + } + }, + "response": [] + } + ] + } + ] + }, + { + "name": "Oracle Onboarding", + "item": [ + { + "name": "Register Simulator Oracle for MSISDN", + "request": { + "method": "POST", + "header": [ + { + "key": "Accept", + "value": "application/vnd.interoperability.participants+json;version=1" + }, + { + "key": "Cache-Control", + "value": "no-cache" + }, + { + "key": "Content-Type", + "value": "application/vnd.interoperability.participants+json;version=1.0" + }, + { + "key": "Date", + "value": "" + }, + { + "key": "Postman-Token", + "value": "003d55c1-2ebc-4e25-b9da-26bf053a8a5c" + }, + { + "key": "cache-control", + "value": "no-cache" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"oracleIdType\": \"MSISDN\",\n \"endpoint\": {\n \"value\": \"{{HOST_SIMULATOR_K8S_CLUSTER}}/oracle\",\n \"endpointType\": \"URL\"\n },\n \"currency\": \"USD\",\n \"isDefault\": true\n}" + }, + "url": { + "raw": "{{HOST_ACCOUNT_LOOKUP_ADMIN}}/oracles", + "host": [ + "{{HOST_ACCOUNT_LOOKUP_ADMIN}}" + ], + "path": [ + "oracles" + ] + } + }, + "response": [] + }, + { + "name": "Register Participant 27720201001 against MSISDN Simulator for PayerFSP", + "request": { + "method": "POST", + "header": [ + { + "key": "Accept", + "value": "application/vnd.interoperability.participants+json;version=1" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Content-Type", + "value": "application/vnd.interoperability.participants+json;version=1.0" + }, + { + "key": "Date", + "value": "{{transferDate}}" + }, + { + "key": "FSPIOP-Source", + "value": "{{payerfsp}}" + }, + { + "key": "Postman-Token", + "value": "7aa4c9f3-1738-49f0-8904-7821e2336692,4127ff87-7d17-483c-8e3e-f0b562a16d84" + }, + { + "key": "User-Agent", + "value": "PostmanRuntime/7.11.0" + }, + { + "key": "accept-encoding", + "value": "gzip, deflate" + }, + { + "key": "cache-control", + "value": "no-cache" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"fspId\": \"payerfsp\",\n \"currency\": \"USD\"\n}" + }, + "url": { + "raw": "{{HOST_ACCOUNT_LOOKUP_SERVICE}}/participants/MSISDN/27720201001", + "host": [ + "{{HOST_ACCOUNT_LOOKUP_SERVICE}}" + ], + "path": [ + "participants", + "MSISDN", + "27720201001" + ] + } + }, + "response": [] + }, + { + "name": "Register Participant 27720201002 against MSISDN Simulator for PayeeFSP", + "request": { + "method": "POST", + "header": [ + { + "key": "Accept", + "value": "application/vnd.interoperability.participants+json;version=1" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Content-Type", + "value": "application/vnd.interoperability.participants+json;version=1.0" + }, + { + "key": "Date", + "value": "{{transferDate}}" + }, + { + "key": "FSPIOP-Source", + "value": "{{payeefsp}}" + }, + { + "key": "Postman-Token", + "value": "7aa4c9f3-1738-49f0-8904-7821e2336692,4127ff87-7d17-483c-8e3e-f0b562a16d84" + }, + { + "key": "User-Agent", + "value": "PostmanRuntime/7.11.0" + }, + { + "key": "accept-encoding", + "value": "gzip, deflate" + }, + { + "key": "cache-control", + "value": "no-cache" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"fspId\": \"payeefsp\",\n \"currency\": \"USD\"\n}" + }, + "url": { + "raw": "{{HOST_ACCOUNT_LOOKUP_SERVICE}}/participants/MSISDN/27720201002", + "host": [ + "{{HOST_ACCOUNT_LOOKUP_SERVICE}}" + ], + "path": [ + "participants", + "MSISDN", + "27720201002" + ] + } + }, + "response": [] + }, + { + "name": "Register Participant {{pathfinderMSISDN}} against MSISDN Simulator for PayeeFSP", + "request": { + "method": "POST", + "header": [ + { + "key": "Accept", + "value": "application/vnd.interoperability.participants+json;version=1" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Content-Type", + "value": "application/vnd.interoperability.participants+json;version=1.0" + }, + { + "key": "Date", + "value": "{{transferDate}}" + }, + { + "key": "FSPIOP-Source", + "value": "{{payeefsp}}" + }, + { + "key": "Postman-Token", + "value": "7aa4c9f3-1738-49f0-8904-7821e2336692,4127ff87-7d17-483c-8e3e-f0b562a16d84" + }, + { + "key": "User-Agent", + "value": "PostmanRuntime/7.11.0" + }, + { + "key": "accept-encoding", + "value": "gzip, deflate" + }, + { + "key": "cache-control", + "value": "no-cache" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"fspId\": \"payeefsp\",\n \"currency\": \"USD\"\n}" + }, + "url": { + "raw": "{{HOST_ACCOUNT_LOOKUP_SERVICE}}/participants/MSISDN/{{pathfinderMSISDN}}", + "host": [ + "{{HOST_ACCOUNT_LOOKUP_SERVICE}}" + ], + "path": [ + "participants", + "MSISDN", + "{{pathfinderMSISDN}}" + ] + } + }, + "response": [] + }, + { + "name": "Create Party record for MSISDN 27720201002 on simulator for PayeeFSP", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"party\": {\n \"partyIdInfo\": {\n \"partyIdType\": \"MSISDN\",\n \"partyIdentifier\": \"27720201002\",\n \"fspId\": \"payeefsp\"\n },\n \"name\": \"SiabeloMaroka\",\n \"personalInfo\": {\n \"complexName\": {\n \"firstName\": \"Aruna\",\n \"lastName\": \"Switch\"\n },\n \"dateOfBirth\": \"1/7/1980\"\n }\n }\n}" + }, + "url": { + "raw": "{{HOST_SIMULATOR}}/{{payeefsp}}/parties/MSISDN/27720201002", + "host": [ + "{{HOST_SIMULATOR}}" + ], + "path": [ + "{{payeefsp}}", + "parties", + "MSISDN", + "27720201002" + ] + } + }, + "response": [] + } + ] + }, + { + "name": "Add Users to ALS / mock-pathfinder", + "item": [ + { + "name": "Add 27713803910 to payerfsp", + "event": [ + { + "listen": "prerequest", + "script": { + "exec": [ + "if (!pm.environment.get('participant')) {", + " pm.environment.set('participant', 'testfsp'); ", + "}", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 202\", function () {", + " pm.response.to.be.success;", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Accept", + "value": "application/vnd.interoperability.participants+json;version=1", + "type": "text" + }, + { + "key": "Content-Type", + "value": "application/vnd.interoperability.participants+json;version=1.0" + }, + { + "key": "Date", + "value": "{{transferDate}}" + }, + { + "key": "FSPIOP-Source", + "value": "{{payerfsp}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"fspId\": \"{{payerfsp}}\",\n \"currency\": \"USD\"\n}\n" + }, + "url": { + "raw": "{{HOST_ACCOUNT_LOOKUP_SERVICE}}/participants/MSISDN/27713803910", + "host": [ + "{{HOST_ACCOUNT_LOOKUP_SERVICE}}" + ], + "path": [ + "participants", + "MSISDN", + "27713803910" + ] + }, + "description": "Set the Proxy URIs for a specific FSP. This will allow the switch to re-direct the incoming Quote requests to the respective FSP.\n\n*Note: connectorPort has been deprecated and is no longer used, but still required in the request." + }, + "response": [] + }, + { + "name": "Add 27713803911 to payerfsp", + "event": [ + { + "listen": "prerequest", + "script": { + "exec": [ + "if (!pm.environment.get('participant')) {", + " pm.environment.set('participant', 'testfsp'); ", + "}", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 202 or 200\", function () {", + " pm.response.to.be.success;", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Accept", + "value": "application/vnd.interoperability.participants+json;version=1", + "type": "text" + }, + { + "key": "Content-Type", + "value": "application/vnd.interoperability.participants+json;version=1.0" + }, + { + "key": "Date", + "value": "{{transferDate}}" + }, + { + "key": "FSPIOP-Source", + "value": "{{payerfsp}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"fspId\": \"{{payerfsp}}\",\n \"currency\": \"USD\"\n}\n" + }, + "url": { + "raw": "{{HOST_ACCOUNT_LOOKUP_SERVICE}}/participants/MSISDN/27713803911", + "host": [ + "{{HOST_ACCOUNT_LOOKUP_SERVICE}}" + ], + "path": [ + "participants", + "MSISDN", + "27713803911" + ] + }, + "description": "Set the Proxy URIs for a specific FSP. This will allow the switch to re-direct the incoming Quote requests to the respective FSP.\n\n*Note: connectorPort has been deprecated and is no longer used, but still required in the request." + }, + "response": [] + }, + { + "name": "Add 27713803912 to payeefsp", + "event": [ + { + "listen": "prerequest", + "script": { + "exec": [ + "if (!pm.environment.get('participant')) {", + " pm.environment.set('participant', 'testfsp'); ", + "}", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 202\", function () {", + " pm.response.to.be.success;", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Accept", + "value": "application/vnd.interoperability.participants+json;version=1", + "type": "text" + }, + { + "key": "Content-Type", + "value": "application/vnd.interoperability.participants+json;version=1.0" + }, + { + "key": "Date", + "value": "{{transferDate}}" + }, + { + "key": "FSPIOP-Source", + "value": "{{payeefsp}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"fspId\": \"{{payeefsp}}\",\n \"currency\": \"USD\"\n}\n" + }, + "url": { + "raw": "{{HOST_ACCOUNT_LOOKUP_SERVICE}}/participants/MSISDN/27713803912", + "host": [ + "{{HOST_ACCOUNT_LOOKUP_SERVICE}}" + ], + "path": [ + "participants", + "MSISDN", + "27713803912" + ] + }, + "description": "Set the Proxy URIs for a specific FSP. This will allow the switch to re-direct the incoming Quote requests to the respective FSP.\n\n*Note: connectorPort has been deprecated and is no longer used, but still required in the request." + }, + "response": [] + }, + { + "name": "Add {{pathfinderMSISDN}} to payeefsp", + "event": [ + { + "listen": "prerequest", + "script": { + "exec": [ + "if (!pm.environment.get('participant')) {", + " pm.environment.set('participant', 'testfsp'); ", + "}", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 202\", function () {", + " pm.response.to.be.success;", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Accept", + "value": "application/vnd.interoperability.participants+json;version=1", + "type": "text" + }, + { + "key": "Content-Type", + "value": "application/vnd.interoperability.participants+json;version=1.0" + }, + { + "key": "Date", + "value": "{{transferDate}}" + }, + { + "key": "FSPIOP-Source", + "value": "{{payeefsp}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"fspId\": \"{{payeefsp}}\",\n \"currency\": \"USD\"\n}\n" + }, + "url": { + "raw": "{{HOST_ACCOUNT_LOOKUP_SERVICE}}/participants/MSISDN/{{pathfinderMSISDN}}", + "host": [ + "{{HOST_ACCOUNT_LOOKUP_SERVICE}}" + ], + "path": [ + "participants", + "MSISDN", + "{{pathfinderMSISDN}}" + ] + }, + "description": "Set the Proxy URIs for a specific FSP. This will allow the switch to re-direct the incoming Quote requests to the respective FSP.\n\n*Note: connectorPort has been deprecated and is no longer used, but still required in the request." + }, + "response": [] + }, + { + "name": "Add 27713803913 to payeefsp", + "event": [ + { + "listen": "prerequest", + "script": { + "exec": [ + "if (!pm.environment.get('participant')) {", + " pm.environment.set('participant', 'testfsp'); ", + "}", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 202\", function () {", + " pm.response.to.be.success;", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Accept", + "value": "application/vnd.interoperability.participants+json;version=1", + "type": "text" + }, + { + "key": "Content-Type", + "value": "application/vnd.interoperability.participants+json;version=1.0" + }, + { + "key": "Date", + "value": "{{transferDate}}" + }, + { + "key": "FSPIOP-Source", + "value": "{{payeefsp}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"fspId\": \"{{payeefsp}}\",\n \"currency\": \"USD\"\n}\n" + }, + "url": { + "raw": "{{HOST_ACCOUNT_LOOKUP_SERVICE}}/participants/MSISDN/27713803913", + "host": [ + "{{HOST_ACCOUNT_LOOKUP_SERVICE}}" + ], + "path": [ + "participants", + "MSISDN", + "27713803913" + ] + }, + "description": "Set the Proxy URIs for a specific FSP. This will allow the switch to re-direct the incoming Quote requests to the respective FSP.\n\n*Note: connectorPort has been deprecated and is no longer used, but still required in the request." + }, + "response": [] + }, + { + "name": "Add 27713803914 to payeefsp", + "event": [ + { + "listen": "prerequest", + "script": { + "exec": [ + "if (!pm.environment.get('participant')) {", + " pm.environment.set('participant', 'testfsp'); ", + "}", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 202\", function () {", + " pm.response.to.be.success;", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Accept", + "value": "application/vnd.interoperability.participants+json;version=1", + "type": "text" + }, + { + "key": "Content-Type", + "value": "application/vnd.interoperability.participants+json;version=1.0" + }, + { + "key": "Date", + "value": "{{transferDate}}" + }, + { + "key": "FSPIOP-Source", + "value": "{{payeefsp}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"fspId\": \"{{payeefsp}}\",\n \"currency\": \"USD\"\n}\n" + }, + "url": { + "raw": "{{HOST_ACCOUNT_LOOKUP_SERVICE}}/participants/MSISDN/27713803914", + "host": [ + "{{HOST_ACCOUNT_LOOKUP_SERVICE}}" + ], + "path": [ + "participants", + "MSISDN", + "27713803914" + ] + }, + "description": "Set the Proxy URIs for a specific FSP. This will allow the switch to re-direct the incoming Quote requests to the respective FSP.\n\n*Note: connectorPort has been deprecated and is no longer used, but still required in the request." + }, + "response": [] + }, + { + "name": "Add 27713803915 to payeefsp", + "event": [ + { + "listen": "prerequest", + "script": { + "exec": [ + "if (!pm.environment.get('participant')) {", + " pm.environment.set('participant', 'testfsp'); ", + "}", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 202\", function () {", + " pm.response.to.be.success;", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Accept", + "value": "application/vnd.interoperability.participants+json;version=1", + "type": "text" + }, + { + "key": "Content-Type", + "value": "application/vnd.interoperability.participants+json;version=1.0" + }, + { + "key": "Date", + "value": "{{transferDate}}" + }, + { + "key": "FSPIOP-Source", + "value": "{{payeefsp}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"fspId\": \"{{payeefsp}}\",\n \"currency\": \"USD\"\n}\n" + }, + "url": { + "raw": "{{HOST_ACCOUNT_LOOKUP_SERVICE}}/participants/MSISDN/27713803915", + "host": [ + "{{HOST_ACCOUNT_LOOKUP_SERVICE}}" + ], + "path": [ + "participants", + "MSISDN", + "27713803915" + ] + }, + "description": "Set the Proxy URIs for a specific FSP. This will allow the switch to re-direct the incoming Quote requests to the respective FSP.\n\n*Note: connectorPort has been deprecated and is no longer used, but still required in the request." + }, + "response": [] + } + ] + }, + { + "name": "Scenarios", + "item": [ + { + "name": "Party Lookup", + "item": [ + { + "name": "Get Parties", + "protocolProfileBehavior": { + "disabledSystemHeaders": { + "accept": true + } + }, + "request": { + "method": "GET", + "header": [ + { + "key": "Accept", + "value": "application/vnd.interoperability.parties+json;version=1.0", + "type": "text" + }, + { + "key": "Content-Type", + "value": "application/vnd.interoperability.parties+json;version=1.0", + "type": "text" + }, + { + "key": "date", + "value": "Wed, 15 Feb 2023 09:31:08 GMT", + "type": "text" + }, + { + "key": "fspiop-source", + "value": "{{payerfsp}}", + "type": "text" + }, + { + "key": "traceparent", + "value": "00-aabbe7816aae8b6b3fd6dd3374a124bd-0123456789abcdef0-00", + "type": "text", + "disabled": true + }, + { + "key": "Authorization", + "value": "", + "type": "text", + "disabled": true + } + ], + "url": { + "raw": "{{HOST_ACCOUNT_LOOKUP_SERVICE}}/parties/MSISDN/27713803912", + "host": [ + "{{HOST_ACCOUNT_LOOKUP_SERVICE}}" + ], + "path": [ + "parties", + "MSISDN", + "27713803912" + ] + } + }, + "response": [] + } + ], + "description": "Source callback url must be setup preperly for party lookup to work. \nRefer to [this](https://docs.mojaloop.io/technical/account-lookup-service/als-get-parties.html)/below UML diagram for better understanding.\n\n" + }, + { + "name": "Quoting Request", + "item": [ + { + "name": "Send quote", + "protocolProfileBehavior": { + "disabledSystemHeaders": { + "accept": true + } + }, + "request": { + "method": "POST", + "header": [ + { + "key": "Accept", + "value": "application/vnd.interoperability.quotes+json;version=1.1", + "type": "text" + }, + { + "key": "Content-Type", + "value": "application/vnd.interoperability.quotes+json;version=1.1", + "type": "text" + }, + { + "key": "date", + "value": "Mon, 13 Feb 2023 13:23:00 GMT", + "type": "text" + }, + { + "key": "fspiop-source", + "value": "{{payerfsp}}", + "type": "text" + }, + { + "key": "traceparent", + "value": "00-aabbe7816aae8b6b3fd6dd3374a124bd-0123456789abcdef0-00", + "type": "text", + "disabled": true + }, + { + "key": "Authorization", + "value": "", + "type": "text", + "disabled": true + }, + { + "key": "fspiop-destination", + "value": "{{payeefsp}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"quoteId\": \"92060082-dc72-4877-bd90-6606c85ef156\",\n \"transactionId\": \"{{txnId}}\",\n \"transactionRequestId\": \"288dc44c-662f-4f78-80d4-557a26effdf5\",\n \"payer\": {\n \"partyIdInfo\": {\n \"partyIdType\": \"MSISDN\",\n \"partyIdentifier\": \"{{payerMSISDN}}\",\n \"fspId\": \"{{payerfsp}}\"\n },\n \"personalInfo\": {\n \"complexName\": {\n \"firstName\": \"Firstname-Test\",\n \"lastName\": \"Lastname-Test\"\n },\n \"dateOfBirth\": \"1984-01-01\"\n }\n },\n \"payee\": {\n \"partyIdInfo\": {\n \"partyIdType\": \"MSISDN\",\n \"partyIdentifier\": \"{{payeeMSISDN}}\",\n \"fspId\": \"{{payeefsp}}\"\n }\n },\n \"amountType\": \"RECEIVE\",\n \"amount\": {\n \"amount\": \"100\",\n \"currency\": \"USD\"\n },\n \"transactionType\": {\n \"scenario\": \"TRANSFER\",\n \"initiator\": \"PAYER\",\n \"initiatorType\": \"CONSUMER\"\n },\n \"note\": \"test\"\n}" + }, + "url": { + "raw": "{{HOST_QUOTING_SERVICE}}/quotes", + "host": [ + "{{HOST_QUOTING_SERVICE}}" + ], + "path": [ + "quotes" + ] + } + }, + "response": [] + } + ], + "description": "For quotation to work with custom cluster make sure to register the source(ex. payer) callback properly. \nRefer [this](https://docs.mojaloop.io/technical/quoting-service/qs-post-quotes.html)/below UML for better understanding of the flow.\n\n\"\"" + }, + { + "name": "Transfer request", + "item": [ + { + "name": "Send transfer", + "protocolProfileBehavior": { + "disabledSystemHeaders": { + "accept": true + } + }, + "request": { + "method": "POST", + "header": [ + { + "key": "Accept", + "value": "application/vnd.interoperability.transfers+json;version=1.1", + "type": "text" + }, + { + "key": "Content-Type", + "value": "application/vnd.interoperability.transfers+json;version=1.1", + "type": "text" + }, + { + "key": "date", + "value": "Mon, 13 Feb 2023 13:23:40 GMT", + "type": "text" + }, + { + "key": "fspiop-source", + "value": "{{payerfsp}}", + "type": "text" + }, + { + "key": "traceparent", + "value": "00-aabbf3b0dac6e7242f66db3d6ae44ad1-0123456789abcdef0-00", + "type": "text", + "disabled": true + }, + { + "key": "Authorization", + "value": "", + "type": "text", + "disabled": true + }, + { + "key": "fspiop-destination", + "value": "{{payeefsp}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"transferId\": \"{{txnId}}\",\n \"payerFsp\": \"{{payerfsp}}\",\n \"payeeFsp\": \"{{payeefsp}}\",\n \"amount\": {\n \"amount\": \"100\",\n \"currency\": \"USD\"\n },\n \"expiration\": \"2023-02-13T13:23:49.791Z\",\n \"ilpPacket\": \"AYIDBAAAAAAAACcQG2cucGF5ZWVmc3AubXNpc2RuLjQ0OTk5OTExMoIC3GV5SjBjbUZ1YzJGamRHbHZia2xrSWpvaVkyWXhaamszTXpFdFpESTBPQzAwWTJNNUxXSmxOR010Tnprek4yWXlaV1EyWXpFNElpd2ljWFZ2ZEdWSlpDSTZJamt5TURZd01EZ3lMV1JqTnpJdE5EZzNOeTFpWkRrd0xUWTJNRFpqT0RWbFpqRTFOaUlzSW5CaGVXVmxJanA3SW5CaGNuUjVTV1JKYm1adklqcDdJbkJoY25SNVNXUlVlWEJsSWpvaVRWTkpVMFJPSWl3aWNHRnlkSGxKWkdWdWRHbG1hV1Z5SWpvaU5EUTVPVGs1TVRFeUlpd2labk53U1dRaU9pSndZWGxsWldaemNDSjlmU3dpY0dGNVpYSWlPbnNpY0dGeWRIbEpaRWx1Wm04aU9uc2ljR0Z5ZEhsSlpGUjVjR1VpT2lKTlUwbFRSRTRpTENKd1lYSjBlVWxrWlc1MGFXWnBaWElpT2lJME5EazVPVGs1T1RraUxDSm1jM0JKWkNJNkluQmhlV1Z5Wm5Od0luMHNJbkJsY25OdmJtRnNTVzVtYnlJNmV5SmpiMjF3YkdWNFRtRnRaU0k2ZXlKbWFYSnpkRTVoYldVaU9pSkdhWEp6ZEc1aGJXVXRWR1Z6ZENJc0lteGhjM1JPWVcxbElqb2lUR0Z6ZEc1aGJXVXRWR1Z6ZENKOUxDSmtZWFJsVDJaQ2FYSjBhQ0k2SWpFNU9EUXRNREV0TURFaWZYMHNJbUZ0YjNWdWRDSTZleUpoYlc5MWJuUWlPaUl4TURBaUxDSmpkWEp5Wlc1amVTSTZJbFZUUkNKOUxDSjBjbUZ1YzJGamRHbHZibFI1Y0dVaU9uc2ljMk5sYm1GeWFXOGlPaUpVVWtGT1UwWkZVaUlzSW1sdWFYUnBZWFJ2Y2lJNklsQkJXVVZTSWl3aWFXNXBkR2xoZEc5eVZIbHdaU0k2SWtOUFRsTlZUVVZTSW4xOQA\",\n \"condition\": \"8hjc1-YZ8YOyWFvQ9XZ_RO1PMUI1wJDbgeRqxWqOcRs\"\n}" + }, + "url": { + "raw": "{{HOST_ML_API_ADAPTER}}/transfers", + "host": [ + "{{HOST_ML_API_ADAPTER}}" + ], + "path": [ + "transfers" + ] + } + }, + "response": [] + } + ] + } + ] + } + ], + "event": [ + { + "listen": "prerequest", + "script": { + "type": "text/javascript", + "exec": [ + "", + "// Ensure that the following variables are not set in the environment", + "// This is a fix for the following issue: https://github.com/mojaloop/project/issues/903", + "// This will ensure that templates are not replaced in the endpoint configs:", + "pm.environment.unset('partyIdType')", + "pm.environment.unset('partyIdentifier')", + "pm.environment.unset('requestId')", + "pm.environment.unset('transferId')", + "", + "pm.globals.unset('partyIdType')", + "pm.globals.unset('partyIdentifier')", + "pm.globals.unset('requestId')", + "pm.globals.unset('transferId')" + ] + } + }, + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + } + ] +} \ No newline at end of file diff --git a/ph-ee-env-template/PostmanCollections/Payment Hub.json b/ph-ee-env-template/PostmanCollections/Payment Hub.json new file mode 100644 index 000000000..ec57220b5 --- /dev/null +++ b/ph-ee-env-template/PostmanCollections/Payment Hub.json @@ -0,0 +1,49840 @@ +{ + "info": { + "_postman_id": "3f9bad4a-e0b2-4c48-ab5d-ac2ebd44b822", + "name": "Payment Hub APIs", + "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json", + "_exporter_id": "30685438" + }, + "item": [ + { + "name": "Operations App APIs", + "item": [ + { + "name": "Authorization", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 200\", function () {", + " pm.response.to.have.status(200);", + " pm.expect(pm.response.text).not.equal(null)", + "});", + "var jsonData = JSON.parse(responseBody);", + "postman.setEnvironmentVariable(\"access_token\", jsonData.access_token);", + "", + "if(postman.getEnvironmentVariable(\"AutoTest\") == \"true\"){", + " var nextTextIndex = Number(postman.getEnvironmentVariable(\"NextTestIndex\"));", + " var apis = pm.environment.get('TestApiList');", + " var testList = JSON.parse(apis);", + " if(testList.length>nextTextIndex){", + " postman.setEnvironmentVariable(\"NextTestIndex\", 1+ nextTextIndex);", + " postman.setNextRequest(testList[nextTextIndex]); ", + " }else{", + " postman.setNextRequest(null); ", + " }", + "}" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "postman.setEnvironmentVariable(\"NextTestIndex\", 1);" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "User-Agent", + "value": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:96.0) Gecko/20100101 Firefox/96.0", + "disabled": true + }, + { + "key": "Accept", + "value": "application/json, text/plain, */*", + "disabled": true + }, + { + "key": "Accept-Language", + "value": "en-US,en;q=0.5", + "disabled": true + }, + { + "key": "Accept-Encoding", + "value": "gzip, deflate", + "disabled": true + }, + { + "key": "Platform-TenantId", + "value": "{{TenantName}}" + }, + { + "key": "Authorization", + "value": "Basic Y2xpZW50Og==" + }, + { + "key": "Content-Type", + "value": "application/json", + "disabled": true + }, + { + "key": "Origin", + "value": "http://localhost:4200", + "disabled": true + }, + { + "key": "Connection", + "value": "keep-alive", + "disabled": true + }, + { + "key": "Referer", + "value": "http://localhost:4200/", + "disabled": true + } + ], + "body": { + "mode": "raw", + "raw": "{}" + }, + "url": { + "raw": "{{OperationsHostName}}/oauth/token?username=mifos&password=password&grant_type=password", + "host": [ + "{{OperationsHostName}}" + ], + "path": [ + "oauth", + "token" + ], + "query": [ + { + "key": "username", + "value": "mifos" + }, + { + "key": "password", + "value": "password" + }, + { + "key": "grant_type", + "value": "password" + } + ] + } + }, + "response": [] + }, + { + "name": "Filter Transaction Request", + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "{{access_token}}", + "type": "string" + } + ] + }, + "method": "POST", + "header": [ + { + "key": "Platform-TenantId", + "value": "{{TenantName}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"errorDescription\": [\"Ams local is disabled\"],\n \"transactionId\": [],\n \"payerId\": [],\n \"payeeId\": [],\n \"externalId\": [],\n \"workflowInstanceKey\": [],\n \"state\": []\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{OperationsHostName}}/api/v1/transactionRequests?startTo=2022-08-19 16:16:33&command=export", + "host": [ + "{{OperationsHostName}}" + ], + "path": [ + "api", + "v1", + "transactionRequests" + ], + "query": [ + { + "key": "startTo", + "value": "2022-08-19 16:16:33", + "description": "YYYY:MM:DD HH:mm:ss" + }, + { + "key": "state", + "value": "FAILED", + "disabled": true + }, + { + "key": "startFrom", + "value": "2022-09-14 10:29:33", + "description": "YYYY:MM:DD HH:mm:ss", + "disabled": true + }, + { + "key": "command", + "value": "export" + } + ] + } + }, + "response": [ + { + "name": "Filter Transaction Request by transactionId and startTo", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "Platform-TenantId", + "value": "{{TenantName}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"transactionId\": [\"8c2358be640c4BtABNeY\", \"dd2183f3ac5d5leU5nz3\"]\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{OperationsHostName}}/api/v1/transactionRequests/export?startTo=2022-06-10 10:17:18", + "host": [ + "{{OperationsHostName}}" + ], + "path": [ + "api", + "v1", + "transactionRequests", + "export" + ], + "query": [ + { + "key": "startTo", + "value": "2022-06-10 10:17:18", + "description": "Supported filter\nTRANSACTIONID\nPAYERID \nPAYEEID\nEXTERNALID\nWORKFLOWINSTANCEKEY" + }, + { + "key": "state", + "value": "ACCEPTED", + "disabled": true + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "plain", + "header": [ + { + "key": "Content-Disposition", + "value": "attachment; filename=transactionRequest_2022-07-08_10-09-02.csv" + }, + { + "key": "X-Content-Type-Options", + "value": "nosniff" + }, + { + "key": "X-XSS-Protection", + "value": "1; mode=block" + }, + { + "key": "Cache-Control", + "value": "no-cache, no-store, max-age=0, must-revalidate" + }, + { + "key": "Pragma", + "value": "no-cache" + }, + { + "key": "Expires", + "value": "0" + }, + { + "key": "X-Frame-Options", + "value": "DENY" + }, + { + "key": "Content-Type", + "value": "text/csv;charset=ISO-8859-1" + }, + { + "key": "Content-Length", + "value": "450" + }, + { + "key": "Date", + "value": "Fri, 08 Jul 2022 10:09:02 GMT" + } + ], + "cookie": [], + "body": "WORKFLOWINSTANCEKEY,TRANSACTIONID,STARTEDAT,COMPLETEDAT,STATE,PAYEEDFSPID,PAYEEPARTYID,PAYEEPARTYIDTYPE,PAYEEFEE,PAYEEQUOTECODE,PAYERDFSPID,PAYERPARTYID,PAYERPARTYIDTYPE,PAYERFEE,PAYERQUOTECODE,AMOUNT,CURRENCY,DIRECTION,AUTHTYPE,INITIATORTYPE,SCENARIO,VARIABLES\r\n2251799816099637,8c2358be640c4BtABNeY,Thu Jun 09 10:17:18 UTC 2022,,ACCEPTED,,24450523,ACCOUNTID,,,,254708374149,MSISDN,,,1,USD,INCOMING,,BUSINESS,MPESA,{IndirectList: not instantiated}\r\n" + }, + { + "name": "Filter Transaction Request by transactionId", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "Platform-TenantId", + "value": "{{TenantName}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"transactionId\": [\"8c2358be640c4BtABNeY\", \"dd2183f3ac5d5leU5nz3\"]\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{OperationsHostName}}/api/v1/transactionRequests/export", + "host": [ + "{{OperationsHostName}}" + ], + "path": [ + "api", + "v1", + "transactionRequests", + "export" + ], + "query": [ + { + "key": "startTo", + "value": "2022-06-10 10:17:18", + "description": "Supported filter\nTRANSACTIONID\nPAYERID \nPAYEEID\nEXTERNALID\nWORKFLOWINSTANCEKEY", + "disabled": true + }, + { + "key": "state", + "value": "ACCEPTED", + "disabled": true + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "plain", + "header": [ + { + "key": "Content-Disposition", + "value": "attachment; filename=transactionRequest_2022-07-08_10-10-36.csv" + }, + { + "key": "X-Content-Type-Options", + "value": "nosniff" + }, + { + "key": "X-XSS-Protection", + "value": "1; mode=block" + }, + { + "key": "Cache-Control", + "value": "no-cache, no-store, max-age=0, must-revalidate" + }, + { + "key": "Pragma", + "value": "no-cache" + }, + { + "key": "Expires", + "value": "0" + }, + { + "key": "X-Frame-Options", + "value": "DENY" + }, + { + "key": "Content-Type", + "value": "text/csv;charset=ISO-8859-1" + }, + { + "key": "Content-Length", + "value": "637" + }, + { + "key": "Date", + "value": "Fri, 08 Jul 2022 10:10:36 GMT" + } + ], + "cookie": [], + "body": "WORKFLOWINSTANCEKEY,TRANSACTIONID,STARTEDAT,COMPLETEDAT,STATE,PAYEEDFSPID,PAYEEPARTYID,PAYEEPARTYIDTYPE,PAYEEFEE,PAYEEQUOTECODE,PAYERDFSPID,PAYERPARTYID,PAYERPARTYIDTYPE,PAYERFEE,PAYERQUOTECODE,AMOUNT,CURRENCY,DIRECTION,AUTHTYPE,INITIATORTYPE,SCENARIO,VARIABLES\r\n2251799816729405,dd2183f3ac5d5leU5nz3,Sun Jun 12 00:22:28 UTC 2022,,ACCEPTED,,24450523,ACCOUNTID,,,,254708374149,MSISDN,,,1,ASD,INCOMING,,BUSINESS,MPESA,{IndirectList: not instantiated}\r\n2251799816099637,8c2358be640c4BtABNeY,Thu Jun 09 10:17:18 UTC 2022,,ACCEPTED,,24450523,ACCOUNTID,,,,254708374149,MSISDN,,,1,USD,INCOMING,,BUSINESS,MPESA,{IndirectList: not instantiated}\r\n" + }, + { + "name": "Filter Transaction Request by transactionId and errorDescription", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "Platform-TenantId", + "value": "{{TenantName}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"transactionId\": [\"8c2358be640c4BtABNeY\"],\n \"errorDescription\": [\"Ams local is disabled\"]\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{OperationsHostName}}/api/v1/transactionRequests/export", + "host": [ + "{{OperationsHostName}}" + ], + "path": [ + "api", + "v1", + "transactionRequests", + "export" + ], + "query": [ + { + "key": "startTo", + "value": "2022-06-10 10:17:18", + "description": "Supported filter\nTRANSACTIONID\nPAYERID \nPAYEEID\nEXTERNALID\nWORKFLOWINSTANCEKEY", + "disabled": true + }, + { + "key": "state", + "value": "ACCEPTED", + "disabled": true + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "plain", + "header": [ + { + "key": "Content-Disposition", + "value": "attachment; filename=transactionRequest_2022-07-08_10-11-51.csv" + }, + { + "key": "X-Content-Type-Options", + "value": "nosniff" + }, + { + "key": "X-XSS-Protection", + "value": "1; mode=block" + }, + { + "key": "Cache-Control", + "value": "no-cache, no-store, max-age=0, must-revalidate" + }, + { + "key": "Pragma", + "value": "no-cache" + }, + { + "key": "Expires", + "value": "0" + }, + { + "key": "X-Frame-Options", + "value": "DENY" + }, + { + "key": "Content-Type", + "value": "text/csv;charset=ISO-8859-1" + }, + { + "key": "Content-Length", + "value": "824" + }, + { + "key": "Date", + "value": "Fri, 08 Jul 2022 10:11:51 GMT" + } + ], + "cookie": [], + "body": "WORKFLOWINSTANCEKEY,TRANSACTIONID,STARTEDAT,COMPLETEDAT,STATE,PAYEEDFSPID,PAYEEPARTYID,PAYEEPARTYIDTYPE,PAYEEFEE,PAYEEQUOTECODE,PAYERDFSPID,PAYERPARTYID,PAYERPARTYIDTYPE,PAYERFEE,PAYERQUOTECODE,AMOUNT,CURRENCY,DIRECTION,AUTHTYPE,INITIATORTYPE,SCENARIO,VARIABLES\r\n2251799816099637,8c2358be640c4BtABNeY,Thu Jun 09 10:17:18 UTC 2022,,ACCEPTED,,24450523,ACCOUNTID,,,,254708374149,MSISDN,,,1,USD,INCOMING,,BUSINESS,MPESA,{IndirectList: not instantiated}\r\n2251799816729405,dd2183f3ac5d5leU5nz3,Sun Jun 12 00:22:28 UTC 2022,,ACCEPTED,,24450523,ACCOUNTID,,,,254708374149,MSISDN,,,1,ASD,INCOMING,,BUSINESS,MPESA,{IndirectList: not instantiated}\r\n2251799816099637,8c2358be640c4BtABNeY,Thu Jun 09 10:17:18 UTC 2022,,ACCEPTED,,24450523,ACCOUNTID,,,,254708374149,MSISDN,,,1,USD,INCOMING,,BUSINESS,MPESA,{IndirectList: not instantiated}\r\n" + }, + { + "name": "Filter Transaction Request by state", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "Platform-TenantId", + "value": "{{TenantName}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"state\": [\"ACCEPTED\"]\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{OperationsHostName}}/api/v1/transactionRequests/export", + "host": [ + "{{OperationsHostName}}" + ], + "path": [ + "api", + "v1", + "transactionRequests", + "export" + ], + "query": [ + { + "key": "startTo", + "value": "2022-06-10 10:17:18", + "description": "Supported filter\nTRANSACTIONID\nPAYERID \nPAYEEID\nEXTERNALID\nWORKFLOWINSTANCEKEY", + "disabled": true + }, + { + "key": "state", + "value": "ACCEPTED", + "disabled": true + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "plain", + "header": [ + { + "key": "Content-Disposition", + "value": "attachment; filename=transactionRequest_2022-07-08_10-12-40.csv" + }, + { + "key": "X-Content-Type-Options", + "value": "nosniff" + }, + { + "key": "X-XSS-Protection", + "value": "1; mode=block" + }, + { + "key": "Cache-Control", + "value": "no-cache, no-store, max-age=0, must-revalidate" + }, + { + "key": "Pragma", + "value": "no-cache" + }, + { + "key": "Expires", + "value": "0" + }, + { + "key": "X-Frame-Options", + "value": "DENY" + }, + { + "key": "Content-Type", + "value": "text/csv;charset=ISO-8859-1" + }, + { + "key": "Content-Length", + "value": "637" + }, + { + "key": "Date", + "value": "Fri, 08 Jul 2022 10:12:40 GMT" + } + ], + "cookie": [], + "body": "WORKFLOWINSTANCEKEY,TRANSACTIONID,STARTEDAT,COMPLETEDAT,STATE,PAYEEDFSPID,PAYEEPARTYID,PAYEEPARTYIDTYPE,PAYEEFEE,PAYEEQUOTECODE,PAYERDFSPID,PAYERPARTYID,PAYERPARTYIDTYPE,PAYERFEE,PAYERQUOTECODE,AMOUNT,CURRENCY,DIRECTION,AUTHTYPE,INITIATORTYPE,SCENARIO,VARIABLES\r\n2251799816729405,dd2183f3ac5d5leU5nz3,Sun Jun 12 00:22:28 UTC 2022,,ACCEPTED,,24450523,ACCOUNTID,,,,254708374149,MSISDN,,,1,ASD,INCOMING,,BUSINESS,MPESA,{IndirectList: not instantiated}\r\n2251799816099637,8c2358be640c4BtABNeY,Thu Jun 09 10:17:18 UTC 2022,,ACCEPTED,,24450523,ACCOUNTID,,,,254708374149,MSISDN,,,1,USD,INCOMING,,BUSINESS,MPESA,{IndirectList: not instantiated}\r\n" + }, + { + "name": "Filter Transaction Request by workflowInstanceKey", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "Platform-TenantId", + "value": "{{TenantName}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"workflowInstanceKey\": [\"2251799816099637\"]\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{OperationsHostName}}/api/v1/transactionRequests/export", + "host": [ + "{{OperationsHostName}}" + ], + "path": [ + "api", + "v1", + "transactionRequests", + "export" + ], + "query": [ + { + "key": "startTo", + "value": "2022-06-10 10:17:18", + "description": "Supported filter\nTRANSACTIONID\nPAYERID \nPAYEEID\nEXTERNALID\nWORKFLOWINSTANCEKEY", + "disabled": true + }, + { + "key": "state", + "value": "ACCEPTED", + "disabled": true + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "plain", + "header": [ + { + "key": "Content-Disposition", + "value": "attachment; filename=transactionRequest_2022-07-08_10-14-21.csv" + }, + { + "key": "X-Content-Type-Options", + "value": "nosniff" + }, + { + "key": "X-XSS-Protection", + "value": "1; mode=block" + }, + { + "key": "Cache-Control", + "value": "no-cache, no-store, max-age=0, must-revalidate" + }, + { + "key": "Pragma", + "value": "no-cache" + }, + { + "key": "Expires", + "value": "0" + }, + { + "key": "X-Frame-Options", + "value": "DENY" + }, + { + "key": "Content-Type", + "value": "text/csv;charset=ISO-8859-1" + }, + { + "key": "Content-Length", + "value": "450" + }, + { + "key": "Date", + "value": "Fri, 08 Jul 2022 10:14:21 GMT" + } + ], + "cookie": [], + "body": "WORKFLOWINSTANCEKEY,TRANSACTIONID,STARTEDAT,COMPLETEDAT,STATE,PAYEEDFSPID,PAYEEPARTYID,PAYEEPARTYIDTYPE,PAYEEFEE,PAYEEQUOTECODE,PAYERDFSPID,PAYERPARTYID,PAYERPARTYIDTYPE,PAYERFEE,PAYERQUOTECODE,AMOUNT,CURRENCY,DIRECTION,AUTHTYPE,INITIATORTYPE,SCENARIO,VARIABLES\r\n2251799816099637,8c2358be640c4BtABNeY,Thu Jun 09 10:17:18 UTC 2022,,ACCEPTED,,24450523,ACCOUNTID,,,,254708374149,MSISDN,,,1,USD,INCOMING,,BUSINESS,MPESA,{IndirectList: not instantiated}\r\n" + }, + { + "name": "Filter Transaction Request bu errorDescription", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "Platform-TenantId", + "value": "{{TenantName}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"errorDescription\": [\"Ams local is disabled\"]\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{OperationsHostName}}/api/v1/transactionRequests/export", + "host": [ + "{{OperationsHostName}}" + ], + "path": [ + "api", + "v1", + "transactionRequests", + "export" + ], + "query": [ + { + "key": "startTo", + "value": "2022-06-10 10:17:18", + "description": "Supported filter\nTRANSACTIONID\nPAYERID \nPAYEEID\nEXTERNALID\nWORKFLOWINSTANCEKEY", + "disabled": true + }, + { + "key": "state", + "value": "FAILED", + "disabled": true + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "plain", + "header": [ + { + "key": "Content-Disposition", + "value": "attachment; filename=transactionRequest_2022-07-08_10-18-27.csv" + }, + { + "key": "X-Content-Type-Options", + "value": "nosniff" + }, + { + "key": "X-XSS-Protection", + "value": "1; mode=block" + }, + { + "key": "Cache-Control", + "value": "no-cache, no-store, max-age=0, must-revalidate" + }, + { + "key": "Pragma", + "value": "no-cache" + }, + { + "key": "Expires", + "value": "0" + }, + { + "key": "X-Frame-Options", + "value": "DENY" + }, + { + "key": "Content-Type", + "value": "text/csv;charset=ISO-8859-1" + }, + { + "key": "Content-Length", + "value": "637" + }, + { + "key": "Date", + "value": "Fri, 08 Jul 2022 10:18:27 GMT" + } + ], + "cookie": [], + "body": "WORKFLOWINSTANCEKEY,TRANSACTIONID,STARTEDAT,COMPLETEDAT,STATE,PAYEEDFSPID,PAYEEPARTYID,PAYEEPARTYIDTYPE,PAYEEFEE,PAYEEQUOTECODE,PAYERDFSPID,PAYERPARTYID,PAYERPARTYIDTYPE,PAYERFEE,PAYERQUOTECODE,AMOUNT,CURRENCY,DIRECTION,AUTHTYPE,INITIATORTYPE,SCENARIO,VARIABLES\r\n2251799816729405,dd2183f3ac5d5leU5nz3,Sun Jun 12 00:22:28 UTC 2022,,ACCEPTED,,24450523,ACCOUNTID,,,,254708374149,MSISDN,,,1,ASD,INCOMING,,BUSINESS,MPESA,{IndirectList: not instantiated}\r\n2251799816099637,8c2358be640c4BtABNeY,Thu Jun 09 10:17:18 UTC 2022,,ACCEPTED,,24450523,ACCOUNTID,,,,254708374149,MSISDN,,,1,USD,INCOMING,,BUSINESS,MPESA,{IndirectList: not instantiated}\r\n" + }, + { + "name": "Filter Transaction Request by errorDescription and startFrom", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "Platform-TenantId", + "value": "{{TenantName}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"errorDescription\": [\"Ams local is disabled\"]\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{OperationsHostName}}/api/v1/transactionRequests/export?startFrom=2022-06-10 10:17:18", + "host": [ + "{{OperationsHostName}}" + ], + "path": [ + "api", + "v1", + "transactionRequests", + "export" + ], + "query": [ + { + "key": "startTo", + "value": "2022-06-10 10:17:18", + "description": "Supported filter\nTRANSACTIONID\nPAYERID \nPAYEEID\nEXTERNALID\nWORKFLOWINSTANCEKEY", + "disabled": true + }, + { + "key": "state", + "value": "FAILED", + "disabled": true + }, + { + "key": "startFrom", + "value": "2022-06-10 10:17:18" + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "plain", + "header": [ + { + "key": "Content-Disposition", + "value": "attachment; filename=transactionRequest_2022-07-08_10-19-18.csv" + }, + { + "key": "X-Content-Type-Options", + "value": "nosniff" + }, + { + "key": "X-XSS-Protection", + "value": "1; mode=block" + }, + { + "key": "Cache-Control", + "value": "no-cache, no-store, max-age=0, must-revalidate" + }, + { + "key": "Pragma", + "value": "no-cache" + }, + { + "key": "Expires", + "value": "0" + }, + { + "key": "X-Frame-Options", + "value": "DENY" + }, + { + "key": "Content-Type", + "value": "text/csv;charset=ISO-8859-1" + }, + { + "key": "Content-Length", + "value": "450" + }, + { + "key": "Date", + "value": "Fri, 08 Jul 2022 10:19:18 GMT" + } + ], + "cookie": [], + "body": "WORKFLOWINSTANCEKEY,TRANSACTIONID,STARTEDAT,COMPLETEDAT,STATE,PAYEEDFSPID,PAYEEPARTYID,PAYEEPARTYIDTYPE,PAYEEFEE,PAYEEQUOTECODE,PAYERDFSPID,PAYERPARTYID,PAYERPARTYIDTYPE,PAYERFEE,PAYERQUOTECODE,AMOUNT,CURRENCY,DIRECTION,AUTHTYPE,INITIATORTYPE,SCENARIO,VARIABLES\r\n2251799816729405,dd2183f3ac5d5leU5nz3,Sun Jun 12 00:22:28 UTC 2022,,ACCEPTED,,24450523,ACCOUNTID,,,,254708374149,MSISDN,,,1,ASD,INCOMING,,BUSINESS,MPESA,{IndirectList: not instantiated}\r\n" + }, + { + "name": "Filter Transaction Request empty response", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "Platform-TenantId", + "value": "{{TenantName}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"errorDescription\": [\"Ams local is disabled\"]\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{OperationsHostName}}/api/v1/transactionRequests/export?startTo=2022-06-10 10:17:18&startFrom=2022-06-10 10:17:18", + "host": [ + "{{OperationsHostName}}" + ], + "path": [ + "api", + "v1", + "transactionRequests", + "export" + ], + "query": [ + { + "key": "startTo", + "value": "2022-06-10 10:17:18", + "description": "YYYY:MM:DD HH:mm:ss" + }, + { + "key": "state", + "value": "FAILED", + "disabled": true + }, + { + "key": "startFrom", + "value": "2022-06-10 10:17:18", + "description": "YYYY:MM:DD HH:mm:ss" + } + ] + } + }, + "status": "Not Found", + "code": 404, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Content-Type-Options", + "value": "nosniff" + }, + { + "key": "X-XSS-Protection", + "value": "1; mode=block" + }, + { + "key": "Cache-Control", + "value": "no-cache, no-store, max-age=0, must-revalidate" + }, + { + "key": "Pragma", + "value": "no-cache" + }, + { + "key": "Expires", + "value": "0" + }, + { + "key": "X-Frame-Options", + "value": "DENY" + }, + { + "key": "Content-Type", + "value": "application/json;charset=UTF-8" + }, + { + "key": "Transfer-Encoding", + "value": "chunked" + }, + { + "key": "Date", + "value": "Fri, 08 Jul 2022 10:20:01 GMT" + } + ], + "cookie": [], + "body": "{\n \"developerMessage\": \"Empty response\",\n \"errorDescription\": \"Empty response\",\n \"errorCode\": \"404\"\n}" + } + ] + }, + { + "name": "Get all error codes", + "request": { + "method": "GET", + "header": [ + { + "key": "Platform-TenantId", + "value": "{{TenantName}}", + "type": "text" + } + ], + "url": { + "raw": "{{OperationsHostName}}/api/v1/errorcode/", + "host": [ + "{{OperationsHostName}}" + ], + "path": [ + "api", + "v1", + "errorcode", + "" + ] + } + }, + "response": [ + { + "name": "Get all error codes 200", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "Platform-TenantId", + "value": "{{TenantName}}", + "type": "text" + } + ], + "url": { + "raw": "{{operationsAppIngress}}/api/v1/errorcode/", + "host": [ + "{{operationsAppIngress}}" + ], + "path": [ + "api", + "v1", + "errorcode", + "" + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json;charset=UTF-8" + }, + { + "key": "Transfer-Encoding", + "value": "chunked" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "X-Content-Type-Options", + "value": "nosniff" + }, + { + "key": "X-XSS-Protection", + "value": "1; mode=block" + }, + { + "key": "Cache-Control", + "value": "no-cache, no-store, max-age=0, must-revalidate" + }, + { + "key": "Pragma", + "value": "no-cache" + }, + { + "key": "Expires", + "value": "0" + }, + { + "key": "X-Frame-Options", + "value": "DENY" + }, + { + "key": "Date", + "value": "Mon, 07 Feb 2022 16:39:05 GMT" + }, + { + "key": "vary", + "value": "Origin" + }, + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "X-Kong-Upstream-Latency", + "value": "15" + }, + { + "key": "X-Kong-Proxy-Latency", + "value": "4" + }, + { + "key": "Via", + "value": "kong/2.2.1" + } + ], + "cookie": [], + "body": "[\n {\n \"id\": 1,\n \"transactionType\": \"COLLECTION-MPESA\",\n \"errorMessage\": \"DS timeout.\",\n \"errorCode\": \"1037\",\n \"recoverable\": true\n }\n]" + } + ] + }, + { + "name": "Get error code by id", + "request": { + "method": "GET", + "header": [ + { + "key": "Platform-TenantId", + "value": "{{TenantName}}", + "type": "text" + } + ], + "url": { + "raw": "{{OperationsHostName}}/api/v1/errorcode/1", + "host": [ + "{{OperationsHostName}}" + ], + "path": [ + "api", + "v1", + "errorcode", + "1" + ] + } + }, + "response": [ + { + "name": "Get error code by id 200", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "Platform-TenantId", + "value": "{{TenantName}}", + "type": "text" + } + ], + "url": { + "raw": "{{operationsAppIngress}}/api/v1/errorcode/1", + "host": [ + "{{operationsAppIngress}}" + ], + "path": [ + "api", + "v1", + "errorcode", + "1" + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json;charset=UTF-8" + }, + { + "key": "Transfer-Encoding", + "value": "chunked" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "X-Content-Type-Options", + "value": "nosniff" + }, + { + "key": "X-XSS-Protection", + "value": "1; mode=block" + }, + { + "key": "Cache-Control", + "value": "no-cache, no-store, max-age=0, must-revalidate" + }, + { + "key": "Pragma", + "value": "no-cache" + }, + { + "key": "Expires", + "value": "0" + }, + { + "key": "X-Frame-Options", + "value": "DENY" + }, + { + "key": "Date", + "value": "Mon, 07 Feb 2022 16:40:29 GMT" + }, + { + "key": "vary", + "value": "Origin" + }, + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "X-Kong-Upstream-Latency", + "value": "24" + }, + { + "key": "X-Kong-Proxy-Latency", + "value": "5" + }, + { + "key": "Via", + "value": "kong/2.2.1" + } + ], + "cookie": [], + "body": "{\n \"id\": 1,\n \"transactionType\": \"COLLECTION-MPESA\",\n \"errorMessage\": \"DS timeout.\",\n \"errorCode\": \"1037\",\n \"recoverable\": true\n}" + } + ] + }, + { + "name": "Filter error codes", + "request": { + "method": "GET", + "header": [ + { + "key": "Platform-TenantId", + "value": "{{TenantName}}", + "type": "text" + } + ], + "url": { + "raw": "{{OperationsHostName}}/api/v1/errorcode/filter?value=1037&by=errorCode", + "host": [ + "{{OperationsHostName}}" + ], + "path": [ + "api", + "v1", + "errorcode", + "filter" + ], + "query": [ + { + "key": "value", + "value": "1037" + }, + { + "key": "by", + "value": "errorCode" + } + ] + } + }, + "response": [ + { + "name": "Filter error code by transactionType", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "Platform-TenantId", + "value": "{{TenantName}}", + "type": "text" + } + ], + "url": { + "raw": "{{operationsAppIngress}}/api/v1/errorcode/filter?by=transactionType&value=COLLECTION-MPESA", + "host": [ + "{{operationsAppIngress}}" + ], + "path": [ + "api", + "v1", + "errorcode", + "filter" + ], + "query": [ + { + "key": "by", + "value": "transactionType" + }, + { + "key": "value", + "value": "COLLECTION-MPESA" + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json;charset=UTF-8" + }, + { + "key": "Transfer-Encoding", + "value": "chunked" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "X-Content-Type-Options", + "value": "nosniff" + }, + { + "key": "X-XSS-Protection", + "value": "1; mode=block" + }, + { + "key": "Cache-Control", + "value": "no-cache, no-store, max-age=0, must-revalidate" + }, + { + "key": "Pragma", + "value": "no-cache" + }, + { + "key": "Expires", + "value": "0" + }, + { + "key": "X-Frame-Options", + "value": "DENY" + }, + { + "key": "Date", + "value": "Mon, 07 Feb 2022 16:43:34 GMT" + }, + { + "key": "vary", + "value": "Origin" + }, + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "X-Kong-Upstream-Latency", + "value": "10" + }, + { + "key": "X-Kong-Proxy-Latency", + "value": "3" + }, + { + "key": "Via", + "value": "kong/2.2.1" + } + ], + "cookie": [], + "body": "[\n {\n \"id\": 1,\n \"transactionType\": \"COLLECTION-MPESA\",\n \"errorMessage\": \"DS timeout.\",\n \"errorCode\": \"1037\",\n \"recoverable\": true\n }\n]" + }, + { + "name": "Filter error code by is recoverable or not", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "Platform-TenantId", + "value": "{{TenantName}}", + "type": "text" + } + ], + "url": { + "raw": "{{operationsAppIngress}}/api/v1/errorcode/filter?by=recoverable&value=true", + "host": [ + "{{operationsAppIngress}}" + ], + "path": [ + "api", + "v1", + "errorcode", + "filter" + ], + "query": [ + { + "key": "by", + "value": "recoverable" + }, + { + "key": "value", + "value": "true" + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json;charset=UTF-8" + }, + { + "key": "Transfer-Encoding", + "value": "chunked" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "X-Content-Type-Options", + "value": "nosniff" + }, + { + "key": "X-XSS-Protection", + "value": "1; mode=block" + }, + { + "key": "Cache-Control", + "value": "no-cache, no-store, max-age=0, must-revalidate" + }, + { + "key": "Pragma", + "value": "no-cache" + }, + { + "key": "Expires", + "value": "0" + }, + { + "key": "X-Frame-Options", + "value": "DENY" + }, + { + "key": "Date", + "value": "Mon, 07 Feb 2022 16:42:57 GMT" + }, + { + "key": "vary", + "value": "Origin" + }, + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "X-Kong-Upstream-Latency", + "value": "8" + }, + { + "key": "X-Kong-Proxy-Latency", + "value": "3" + }, + { + "key": "Via", + "value": "kong/2.2.1" + } + ], + "cookie": [], + "body": "[\n {\n \"id\": 1,\n \"transactionType\": \"COLLECTION-MPESA\",\n \"errorMessage\": \"DS timeout.\",\n \"errorCode\": \"1037\",\n \"recoverable\": true\n }\n]" + }, + { + "name": "Filter error code by errorCode", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "Platform-TenantId", + "value": "{{TenantName}}", + "type": "text" + } + ], + "url": { + "raw": "{{operationsAppIngress}}/api/v1/errorcode/filter?by=errorCode&value=1037", + "host": [ + "{{operationsAppIngress}}" + ], + "path": [ + "api", + "v1", + "errorcode", + "filter" + ], + "query": [ + { + "key": "by", + "value": "errorCode" + }, + { + "key": "value", + "value": "1037" + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json;charset=UTF-8" + }, + { + "key": "Transfer-Encoding", + "value": "chunked" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "X-Content-Type-Options", + "value": "nosniff" + }, + { + "key": "X-XSS-Protection", + "value": "1; mode=block" + }, + { + "key": "Cache-Control", + "value": "no-cache, no-store, max-age=0, must-revalidate" + }, + { + "key": "Pragma", + "value": "no-cache" + }, + { + "key": "Expires", + "value": "0" + }, + { + "key": "X-Frame-Options", + "value": "DENY" + }, + { + "key": "Date", + "value": "Mon, 07 Feb 2022 16:42:13 GMT" + }, + { + "key": "vary", + "value": "Origin" + }, + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "X-Kong-Upstream-Latency", + "value": "17" + }, + { + "key": "X-Kong-Proxy-Latency", + "value": "4" + }, + { + "key": "Via", + "value": "kong/2.2.1" + } + ], + "cookie": [], + "body": "[\n {\n \"id\": 1,\n \"transactionType\": \"COLLECTION-MPESA\",\n \"errorMessage\": \"DS timeout.\",\n \"errorCode\": \"1037\",\n \"recoverable\": true\n }\n]" + } + ] + }, + { + "name": "Add error code", + "request": { + "method": "POST", + "header": [ + { + "key": "Platform-TenantId", + "value": "{{TenantName}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"transactionType\": \"COLLECTION-MPESA\",\n \"errorMessage\": \"Request cancelled by user\",\n \"errorCode\": \"1031\",\n \"recoverable\": false\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{OperationsHostName}}/api/v1/errorcode/", + "host": [ + "{{OperationsHostName}}" + ], + "path": [ + "api", + "v1", + "errorcode", + "" + ] + } + }, + "response": [ + { + "name": "Add error code 200", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "Platform-TenantId", + "value": "{{TenantName}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"transactionType\": \"COLLECTION-MPESA\",\n \"errorMessage\": \"DS timeout.\",\n \"errorCode\": 1037,\n \"recoverable\": true\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{operationsAppIngress}}/api/v1/errorcode/", + "host": [ + "{{operationsAppIngress}}" + ], + "path": [ + "api", + "v1", + "errorcode", + "" + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json;charset=UTF-8" + }, + { + "key": "Transfer-Encoding", + "value": "chunked" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "X-Content-Type-Options", + "value": "nosniff" + }, + { + "key": "X-XSS-Protection", + "value": "1; mode=block" + }, + { + "key": "Cache-Control", + "value": "no-cache, no-store, max-age=0, must-revalidate" + }, + { + "key": "Pragma", + "value": "no-cache" + }, + { + "key": "Expires", + "value": "0" + }, + { + "key": "X-Frame-Options", + "value": "DENY" + }, + { + "key": "Date", + "value": "Mon, 07 Feb 2022 16:38:38 GMT" + }, + { + "key": "vary", + "value": "Origin" + }, + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "X-Kong-Upstream-Latency", + "value": "136" + }, + { + "key": "X-Kong-Proxy-Latency", + "value": "23" + }, + { + "key": "Via", + "value": "kong/2.2.1" + } + ], + "cookie": [], + "body": "{\n \"id\": 1,\n \"transactionType\": \"COLLECTION-MPESA\",\n \"errorMessage\": \"DS timeout.\",\n \"errorCode\": \"1037\",\n \"recoverable\": true\n}" + } + ] + }, + { + "name": "Transfers", + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "{{access_token}}", + "type": "string" + } + ] + }, + "method": "GET", + "header": [ + { + "key": "User-Agent", + "value": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:90.0) Gecko/20100101 Firefox/90.0", + "disabled": true + }, + { + "key": "Accept", + "value": "application/json, text/plain, */*", + "disabled": true + }, + { + "key": "Accept-Language", + "value": "en-US,en;q=0.5", + "disabled": true + }, + { + "key": "Platform-TenantId", + "value": "{{TenantName}}" + }, + { + "key": "Authorization", + "value": "Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsiaWRlbnRpdHktcHJvdmlkZXIiLCJvYWYiXSwidXNlcl9uYW1lIjoibWlmb3MiLCJzY29wZSI6WyJpZGVudGl0eSJdLCJleHAiOjE2NDI2NzA0MTcsImF1dGhvcml0aWVzIjpbIlJFRlVORCIsIkFMTF9GVU5DVElPTlMiXSwianRpIjoiQStsajFsRVNsWW9YMU9uNjdyTlNRbFhHY05VPSIsImNsaWVudF9pZCI6ImNsaWVudCJ9.flZD_GlQJ2w8P_cU0DC2hojJLUA9WS_Bc3yy9X-1v8hR1xhJZjdHUKfBl-TqNdwPnWHEvuKNdsGSEzNCP8CYR71n3J33gzEpcKVZ0P7d2bOOLX6EgtSjDdjSLU_IGRxmOZEGES9p-UPAARbj24vIM3kugG6jBbVTJ08DksnLRXP0MdWjAmW6JNq0Y2VAJq_0LSCdab5XZT-vQsRL5PdrKvPT1w28jDFklWCrft6G-6SQbqkJPGR_oQPwYBmaZOx5ateE6JDMZN5CVmejExRVPYgE-tMxXRh7GZFTDaSW1DiMzNriBeDSu3NUkuwOCC4B4Z-XmzQJw36uE6pvqGT-Pg" + }, + { + "key": "Origin", + "value": "http://localhost:4200", + "disabled": true + }, + { + "key": "Connection", + "value": "keep-alive", + "disabled": true + }, + { + "key": "Referer", + "value": "http://localhost:4200/", + "disabled": true + } + ], + "url": { + "raw": "{{OperationsHostName}}/api/v1/transfers?size=1&page=0&clientCorrelationId=123456789", + "host": [ + "{{OperationsHostName}}" + ], + "path": [ + "api", + "v1", + "transfers" + ], + "query": [ + { + "key": "direction", + "value": "OUTGOING", + "description": "INCOMING or OUTGOING direction", + "disabled": true + }, + { + "key": "status", + "value": "{{status}}", + "description": "Transaction Status. Values can be COMPLETED, FAILED, IN_PROGRESS and ALL. By default set to ALL.", + "disabled": true + }, + { + "key": "size", + "value": "1" + }, + { + "key": "page", + "value": "0" + }, + { + "key": "clientCorrelationId", + "value": "123456789" + } + ] + } + }, + "response": [] + }, + { + "name": "Variables", + "request": { + "auth": { + "type": "noauth" + }, + "method": "GET", + "header": [ + { + "key": "User-Agent", + "value": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:90.0) Gecko/20100101 Firefox/90.0", + "disabled": true + }, + { + "key": "Accept", + "value": "application/json, text/plain, */*", + "disabled": true + }, + { + "key": "Accept-Language", + "value": "en-US,en;q=0.5", + "disabled": true + }, + { + "key": "Platform-TenantId", + "value": "{{TenantName}}" + }, + { + "key": "Authorization", + "value": "Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsiaWRlbnRpdHktcHJvdmlkZXIiLCJvYWYiXSwidXNlcl9uYW1lIjoibWlmb3MiLCJzY29wZSI6WyJpZGVudGl0eSJdLCJleHAiOjE2NDI2NzA0MTcsImF1dGhvcml0aWVzIjpbIlJFRlVORCIsIkFMTF9GVU5DVElPTlMiXSwianRpIjoiQStsajFsRVNsWW9YMU9uNjdyTlNRbFhHY05VPSIsImNsaWVudF9pZCI6ImNsaWVudCJ9.flZD_GlQJ2w8P_cU0DC2hojJLUA9WS_Bc3yy9X-1v8hR1xhJZjdHUKfBl-TqNdwPnWHEvuKNdsGSEzNCP8CYR71n3J33gzEpcKVZ0P7d2bOOLX6EgtSjDdjSLU_IGRxmOZEGES9p-UPAARbj24vIM3kugG6jBbVTJ08DksnLRXP0MdWjAmW6JNq0Y2VAJq_0LSCdab5XZT-vQsRL5PdrKvPT1w28jDFklWCrft6G-6SQbqkJPGR_oQPwYBmaZOx5ateE6JDMZN5CVmejExRVPYgE-tMxXRh7GZFTDaSW1DiMzNriBeDSu3NUkuwOCC4B4Z-XmzQJw36uE6pvqGT-Pg", + "disabled": true + }, + { + "key": "Origin", + "value": "http://localhost:4200", + "disabled": true + }, + { + "key": "Connection", + "value": "keep-alive", + "disabled": true + }, + { + "key": "Referer", + "value": "http://localhost:4200/", + "disabled": true + } + ], + "url": { + "raw": "{{OperationsHostName}}/api/v1/variables/21037e77-7227-4757-8e45-5c356f369b11", + "host": [ + "{{OperationsHostName}}" + ], + "path": [ + "api", + "v1", + "variables", + "21037e77-7227-4757-8e45-5c356f369b11" + ], + "query": [ + { + "key": "direction", + "value": "OUTGOING", + "description": "INCOMING or OUTGOING direction", + "disabled": true + }, + { + "key": "status", + "value": "{{status}}", + "description": "Transaction Status. Values can be COMPLETED, FAILED, IN_PROGRESS and ALL. By default set to ALL.", + "disabled": true + }, + { + "key": "size", + "value": "1", + "disabled": true + }, + { + "key": "page", + "value": "0", + "disabled": true + }, + { + "key": "clientCorrelationId", + "value": "123456789", + "disabled": true + } + ] + } + }, + "response": [] + }, + { + "name": "Get Transaction Request", + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "{{access_token}}", + "type": "string" + } + ] + }, + "method": "GET", + "header": [ + { + "key": "Platform-TenantId", + "value": "{{TenantName}}", + "type": "text" + } + ], + "url": { + "raw": "{{OperationsHostName}}/api/v1/transactionRequests/?clientCorrelationId=123", + "host": [ + "{{OperationsHostName}}" + ], + "path": [ + "api", + "v1", + "transactionRequests", + "" + ], + "query": [ + { + "key": "transactionId", + "value": "8c2358be640c4BtABNeY", + "disabled": true + }, + { + "key": "page", + "value": "0", + "disabled": true + }, + { + "key": "size", + "value": "1", + "disabled": true + }, + { + "key": "state", + "value": "ACCEPTED", + "description": "IN_PROGRESS, RECEIVED, ACCEPTED, REJECTED, FAILED", + "disabled": true + }, + { + "key": "amount", + "value": "1", + "disabled": true + }, + { + "key": "currency", + "value": "USD", + "disabled": true + }, + { + "key": "direction", + "value": "INCOMING", + "disabled": true + }, + { + "key": "payerPartyId", + "value": "254708374149", + "disabled": true + }, + { + "key": "payeePartyId", + "value": "24450523", + "disabled": true + }, + { + "key": "payeeDfspId", + "value": "null", + "disabled": true + }, + { + "key": "payerDfspId", + "value": "null", + "disabled": true + }, + { + "key": "startFrom", + "value": "2022-06-09 10:00:00", + "description": "yyyy-MM-dd HH:mm:ss", + "disabled": true + }, + { + "key": "startTo", + "value": "2022-06-09 11:00:00", + "description": "yyyy-MM-dd HH:mm:ss", + "disabled": true + }, + { + "key": "sortedBy", + "value": "currency", + "disabled": true + }, + { + "key": "sortedOrder", + "value": "ASC", + "description": "DESC, ASC", + "disabled": true + }, + { + "key": "clientCorrelationId", + "value": "123" + } + ] + } + }, + "response": [ + { + "name": "Get Transaction Request by transactionId", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "Platform-TenantId", + "value": "{{TenantName}}", + "type": "text" + } + ], + "url": { + "raw": "{{OperationsHostName}}/api/v1/transactionRequests/?transactionId=8c2358be640c4BtABNeY", + "host": [ + "{{OperationsHostName}}" + ], + "path": [ + "api", + "v1", + "transactionRequests", + "" + ], + "query": [ + { + "key": "transactionId", + "value": "8c2358be640c4BtABNeY" + }, + { + "key": "page", + "value": "0", + "disabled": true + }, + { + "key": "size", + "value": "1", + "disabled": true + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Content-Type-Options", + "value": "nosniff" + }, + { + "key": "X-XSS-Protection", + "value": "1; mode=block" + }, + { + "key": "Cache-Control", + "value": "no-cache, no-store, max-age=0, must-revalidate" + }, + { + "key": "Pragma", + "value": "no-cache" + }, + { + "key": "Expires", + "value": "0" + }, + { + "key": "X-Frame-Options", + "value": "DENY" + }, + { + "key": "Content-Type", + "value": "application/json;charset=UTF-8" + }, + { + "key": "Transfer-Encoding", + "value": "chunked" + }, + { + "key": "Date", + "value": "Tue, 05 Jul 2022 16:00:23 GMT" + } + ], + "cookie": [], + "body": "{\n \"content\": [\n {\n \"id\": 1,\n \"workflowInstanceKey\": \"2251799816099637\",\n \"transactionId\": \"8c2358be640c4BtABNeY\",\n \"startedAt\": 1654769838000,\n \"completedAt\": null,\n \"state\": \"ACCEPTED\",\n \"payeeDfspId\": null,\n \"payeePartyId\": \"24450523\",\n \"payeePartyIdType\": \"ACCOUNTID\",\n \"payeeFee\": null,\n \"payeeQuoteCode\": null,\n \"payerDfspId\": null,\n \"payerPartyId\": \"254708374149\",\n \"payerPartyIdType\": \"MSISDN\",\n \"payerFee\": null,\n \"payerQuoteCode\": null,\n \"amount\": 1,\n \"currency\": \"USD\",\n \"direction\": \"INCOMING\",\n \"authType\": null,\n \"initiatorType\": \"BUSINESS\",\n \"scenario\": \"MPESA\"\n }\n ],\n \"totalPages\": 1,\n \"totalElements\": 1,\n \"last\": true,\n \"numberOfElements\": 1,\n \"sort\": [\n {\n \"direction\": \"DESC\",\n \"property\": \"startedAt\",\n \"ignoreCase\": false,\n \"nullHandling\": \"NATIVE\",\n \"descending\": true,\n \"ascending\": false\n }\n ],\n \"first\": true,\n \"size\": 20,\n \"number\": 0\n}" + }, + { + "name": "Get Transaction Request by state", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "Platform-TenantId", + "value": "{{TenantName}}", + "type": "text" + } + ], + "url": { + "raw": "{{OperationsHostName}}/api/v1/transactionRequests/?state=ACCEPTED", + "host": [ + "{{OperationsHostName}}" + ], + "path": [ + "api", + "v1", + "transactionRequests", + "" + ], + "query": [ + { + "key": "transactionId", + "value": "8c2358be640c4BtABNeY", + "disabled": true + }, + { + "key": "page", + "value": "0", + "disabled": true + }, + { + "key": "size", + "value": "1", + "disabled": true + }, + { + "key": "state", + "value": "ACCEPTED" + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Content-Type-Options", + "value": "nosniff" + }, + { + "key": "X-XSS-Protection", + "value": "1; mode=block" + }, + { + "key": "Cache-Control", + "value": "no-cache, no-store, max-age=0, must-revalidate" + }, + { + "key": "Pragma", + "value": "no-cache" + }, + { + "key": "Expires", + "value": "0" + }, + { + "key": "X-Frame-Options", + "value": "DENY" + }, + { + "key": "Content-Type", + "value": "application/json;charset=UTF-8" + }, + { + "key": "Transfer-Encoding", + "value": "chunked" + }, + { + "key": "Date", + "value": "Tue, 05 Jul 2022 16:02:51 GMT" + } + ], + "cookie": [], + "body": "{\n \"content\": [\n {\n \"id\": 2,\n \"workflowInstanceKey\": \"2251799816729405\",\n \"transactionId\": \"dd2183f3ac5d5leU5nz3\",\n \"startedAt\": 1654993348000,\n \"completedAt\": null,\n \"state\": \"ACCEPTED\",\n \"payeeDfspId\": null,\n \"payeePartyId\": \"24450523\",\n \"payeePartyIdType\": \"ACCOUNTID\",\n \"payeeFee\": null,\n \"payeeQuoteCode\": null,\n \"payerDfspId\": null,\n \"payerPartyId\": \"254708374149\",\n \"payerPartyIdType\": \"MSISDN\",\n \"payerFee\": null,\n \"payerQuoteCode\": null,\n \"amount\": 1,\n \"currency\": \"USD\",\n \"direction\": \"INCOMING\",\n \"authType\": null,\n \"initiatorType\": \"BUSINESS\",\n \"scenario\": \"MPESA\"\n },\n {\n \"id\": 1,\n \"workflowInstanceKey\": \"2251799816099637\",\n \"transactionId\": \"8c2358be640c4BtABNeY\",\n \"startedAt\": 1654769838000,\n \"completedAt\": null,\n \"state\": \"ACCEPTED\",\n \"payeeDfspId\": null,\n \"payeePartyId\": \"24450523\",\n \"payeePartyIdType\": \"ACCOUNTID\",\n \"payeeFee\": null,\n \"payeeQuoteCode\": null,\n \"payerDfspId\": null,\n \"payerPartyId\": \"254708374149\",\n \"payerPartyIdType\": \"MSISDN\",\n \"payerFee\": null,\n \"payerQuoteCode\": null,\n \"amount\": 1,\n \"currency\": \"USD\",\n \"direction\": \"INCOMING\",\n \"authType\": null,\n \"initiatorType\": \"BUSINESS\",\n \"scenario\": \"MPESA\"\n }\n ],\n \"totalPages\": 1,\n \"totalElements\": 2,\n \"last\": true,\n \"numberOfElements\": 2,\n \"sort\": [\n {\n \"direction\": \"DESC\",\n \"property\": \"startedAt\",\n \"ignoreCase\": false,\n \"nullHandling\": \"NATIVE\",\n \"descending\": true,\n \"ascending\": false\n }\n ],\n \"first\": true,\n \"size\": 20,\n \"number\": 0\n}" + }, + { + "name": "Get Transaction Request by amount", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "Platform-TenantId", + "value": "{{TenantName}}", + "type": "text" + } + ], + "url": { + "raw": "{{OperationsHostName}}/api/v1/transactionRequests/?amount=1", + "host": [ + "{{OperationsHostName}}" + ], + "path": [ + "api", + "v1", + "transactionRequests", + "" + ], + "query": [ + { + "key": "transactionId", + "value": "8c2358be640c4BtABNeY", + "disabled": true + }, + { + "key": "page", + "value": "0", + "disabled": true + }, + { + "key": "size", + "value": "1", + "disabled": true + }, + { + "key": "state", + "value": "ACCEPTED", + "disabled": true + }, + { + "key": "amount", + "value": "1" + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Content-Type-Options", + "value": "nosniff" + }, + { + "key": "X-XSS-Protection", + "value": "1; mode=block" + }, + { + "key": "Cache-Control", + "value": "no-cache, no-store, max-age=0, must-revalidate" + }, + { + "key": "Pragma", + "value": "no-cache" + }, + { + "key": "Expires", + "value": "0" + }, + { + "key": "X-Frame-Options", + "value": "DENY" + }, + { + "key": "Content-Type", + "value": "application/json;charset=UTF-8" + }, + { + "key": "Transfer-Encoding", + "value": "chunked" + }, + { + "key": "Date", + "value": "Tue, 05 Jul 2022 16:05:13 GMT" + } + ], + "cookie": [], + "body": "{\n \"content\": [\n {\n \"id\": 2,\n \"workflowInstanceKey\": \"2251799816729405\",\n \"transactionId\": \"dd2183f3ac5d5leU5nz3\",\n \"startedAt\": 1654993348000,\n \"completedAt\": null,\n \"state\": \"ACCEPTED\",\n \"payeeDfspId\": null,\n \"payeePartyId\": \"24450523\",\n \"payeePartyIdType\": \"ACCOUNTID\",\n \"payeeFee\": null,\n \"payeeQuoteCode\": null,\n \"payerDfspId\": null,\n \"payerPartyId\": \"254708374149\",\n \"payerPartyIdType\": \"MSISDN\",\n \"payerFee\": null,\n \"payerQuoteCode\": null,\n \"amount\": 1,\n \"currency\": \"USD\",\n \"direction\": \"INCOMING\",\n \"authType\": null,\n \"initiatorType\": \"BUSINESS\",\n \"scenario\": \"MPESA\"\n },\n {\n \"id\": 1,\n \"workflowInstanceKey\": \"2251799816099637\",\n \"transactionId\": \"8c2358be640c4BtABNeY\",\n \"startedAt\": 1654769838000,\n \"completedAt\": null,\n \"state\": \"ACCEPTED\",\n \"payeeDfspId\": null,\n \"payeePartyId\": \"24450523\",\n \"payeePartyIdType\": \"ACCOUNTID\",\n \"payeeFee\": null,\n \"payeeQuoteCode\": null,\n \"payerDfspId\": null,\n \"payerPartyId\": \"254708374149\",\n \"payerPartyIdType\": \"MSISDN\",\n \"payerFee\": null,\n \"payerQuoteCode\": null,\n \"amount\": 1,\n \"currency\": \"USD\",\n \"direction\": \"INCOMING\",\n \"authType\": null,\n \"initiatorType\": \"BUSINESS\",\n \"scenario\": \"MPESA\"\n }\n ],\n \"totalPages\": 1,\n \"totalElements\": 2,\n \"last\": true,\n \"numberOfElements\": 2,\n \"sort\": [\n {\n \"direction\": \"DESC\",\n \"property\": \"startedAt\",\n \"ignoreCase\": false,\n \"nullHandling\": \"NATIVE\",\n \"descending\": true,\n \"ascending\": false\n }\n ],\n \"first\": true,\n \"size\": 20,\n \"number\": 0\n}" + }, + { + "name": "Get Transaction Request by currency", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "Platform-TenantId", + "value": "{{TenantName}}", + "type": "text" + } + ], + "url": { + "raw": "{{OperationsHostName}}/api/v1/transactionRequests/?currency=USD", + "host": [ + "{{OperationsHostName}}" + ], + "path": [ + "api", + "v1", + "transactionRequests", + "" + ], + "query": [ + { + "key": "transactionId", + "value": "8c2358be640c4BtABNeY", + "disabled": true + }, + { + "key": "page", + "value": "0", + "disabled": true + }, + { + "key": "size", + "value": "1", + "disabled": true + }, + { + "key": "state", + "value": "ACCEPTED", + "disabled": true + }, + { + "key": "amount", + "value": "1", + "disabled": true + }, + { + "key": "currency", + "value": "USD" + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Content-Type-Options", + "value": "nosniff" + }, + { + "key": "X-XSS-Protection", + "value": "1; mode=block" + }, + { + "key": "Cache-Control", + "value": "no-cache, no-store, max-age=0, must-revalidate" + }, + { + "key": "Pragma", + "value": "no-cache" + }, + { + "key": "Expires", + "value": "0" + }, + { + "key": "X-Frame-Options", + "value": "DENY" + }, + { + "key": "Content-Type", + "value": "application/json;charset=UTF-8" + }, + { + "key": "Transfer-Encoding", + "value": "chunked" + }, + { + "key": "Date", + "value": "Tue, 05 Jul 2022 16:06:00 GMT" + } + ], + "cookie": [], + "body": "{\n \"content\": [\n {\n \"id\": 2,\n \"workflowInstanceKey\": \"2251799816729405\",\n \"transactionId\": \"dd2183f3ac5d5leU5nz3\",\n \"startedAt\": 1654993348000,\n \"completedAt\": null,\n \"state\": \"ACCEPTED\",\n \"payeeDfspId\": null,\n \"payeePartyId\": \"24450523\",\n \"payeePartyIdType\": \"ACCOUNTID\",\n \"payeeFee\": null,\n \"payeeQuoteCode\": null,\n \"payerDfspId\": null,\n \"payerPartyId\": \"254708374149\",\n \"payerPartyIdType\": \"MSISDN\",\n \"payerFee\": null,\n \"payerQuoteCode\": null,\n \"amount\": 1,\n \"currency\": \"USD\",\n \"direction\": \"INCOMING\",\n \"authType\": null,\n \"initiatorType\": \"BUSINESS\",\n \"scenario\": \"MPESA\"\n },\n {\n \"id\": 1,\n \"workflowInstanceKey\": \"2251799816099637\",\n \"transactionId\": \"8c2358be640c4BtABNeY\",\n \"startedAt\": 1654769838000,\n \"completedAt\": null,\n \"state\": \"ACCEPTED\",\n \"payeeDfspId\": null,\n \"payeePartyId\": \"24450523\",\n \"payeePartyIdType\": \"ACCOUNTID\",\n \"payeeFee\": null,\n \"payeeQuoteCode\": null,\n \"payerDfspId\": null,\n \"payerPartyId\": \"254708374149\",\n \"payerPartyIdType\": \"MSISDN\",\n \"payerFee\": null,\n \"payerQuoteCode\": null,\n \"amount\": 1,\n \"currency\": \"USD\",\n \"direction\": \"INCOMING\",\n \"authType\": null,\n \"initiatorType\": \"BUSINESS\",\n \"scenario\": \"MPESA\"\n }\n ],\n \"totalPages\": 1,\n \"totalElements\": 2,\n \"last\": true,\n \"numberOfElements\": 2,\n \"sort\": [\n {\n \"direction\": \"DESC\",\n \"property\": \"startedAt\",\n \"ignoreCase\": false,\n \"nullHandling\": \"NATIVE\",\n \"descending\": true,\n \"ascending\": false\n }\n ],\n \"first\": true,\n \"size\": 20,\n \"number\": 0\n}" + }, + { + "name": "Get Transaction Request by direction", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "Platform-TenantId", + "value": "{{TenantName}}", + "type": "text" + } + ], + "url": { + "raw": "{{OperationsHostName}}/api/v1/transactionRequests/?direction=INCOMING", + "host": [ + "{{OperationsHostName}}" + ], + "path": [ + "api", + "v1", + "transactionRequests", + "" + ], + "query": [ + { + "key": "transactionId", + "value": "8c2358be640c4BtABNeY", + "disabled": true + }, + { + "key": "page", + "value": "0", + "disabled": true + }, + { + "key": "size", + "value": "1", + "disabled": true + }, + { + "key": "state", + "value": "ACCEPTED", + "disabled": true + }, + { + "key": "amount", + "value": "1", + "disabled": true + }, + { + "key": "currency", + "value": "USD", + "disabled": true + }, + { + "key": "direction", + "value": "INCOMING" + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Content-Type-Options", + "value": "nosniff" + }, + { + "key": "X-XSS-Protection", + "value": "1; mode=block" + }, + { + "key": "Cache-Control", + "value": "no-cache, no-store, max-age=0, must-revalidate" + }, + { + "key": "Pragma", + "value": "no-cache" + }, + { + "key": "Expires", + "value": "0" + }, + { + "key": "X-Frame-Options", + "value": "DENY" + }, + { + "key": "Content-Type", + "value": "application/json;charset=UTF-8" + }, + { + "key": "Transfer-Encoding", + "value": "chunked" + }, + { + "key": "Date", + "value": "Tue, 05 Jul 2022 16:07:07 GMT" + } + ], + "cookie": [], + "body": "{\n \"content\": [\n {\n \"id\": 2,\n \"workflowInstanceKey\": \"2251799816729405\",\n \"transactionId\": \"dd2183f3ac5d5leU5nz3\",\n \"startedAt\": 1654993348000,\n \"completedAt\": null,\n \"state\": \"ACCEPTED\",\n \"payeeDfspId\": null,\n \"payeePartyId\": \"24450523\",\n \"payeePartyIdType\": \"ACCOUNTID\",\n \"payeeFee\": null,\n \"payeeQuoteCode\": null,\n \"payerDfspId\": null,\n \"payerPartyId\": \"254708374149\",\n \"payerPartyIdType\": \"MSISDN\",\n \"payerFee\": null,\n \"payerQuoteCode\": null,\n \"amount\": 1,\n \"currency\": \"USD\",\n \"direction\": \"INCOMING\",\n \"authType\": null,\n \"initiatorType\": \"BUSINESS\",\n \"scenario\": \"MPESA\"\n },\n {\n \"id\": 1,\n \"workflowInstanceKey\": \"2251799816099637\",\n \"transactionId\": \"8c2358be640c4BtABNeY\",\n \"startedAt\": 1654769838000,\n \"completedAt\": null,\n \"state\": \"ACCEPTED\",\n \"payeeDfspId\": null,\n \"payeePartyId\": \"24450523\",\n \"payeePartyIdType\": \"ACCOUNTID\",\n \"payeeFee\": null,\n \"payeeQuoteCode\": null,\n \"payerDfspId\": null,\n \"payerPartyId\": \"254708374149\",\n \"payerPartyIdType\": \"MSISDN\",\n \"payerFee\": null,\n \"payerQuoteCode\": null,\n \"amount\": 1,\n \"currency\": \"USD\",\n \"direction\": \"INCOMING\",\n \"authType\": null,\n \"initiatorType\": \"BUSINESS\",\n \"scenario\": \"MPESA\"\n }\n ],\n \"totalPages\": 1,\n \"totalElements\": 2,\n \"last\": true,\n \"numberOfElements\": 2,\n \"sort\": [\n {\n \"direction\": \"DESC\",\n \"property\": \"startedAt\",\n \"ignoreCase\": false,\n \"nullHandling\": \"NATIVE\",\n \"descending\": true,\n \"ascending\": false\n }\n ],\n \"first\": true,\n \"size\": 20,\n \"number\": 0\n}" + }, + { + "name": "Get Transaction Request by payerPartyId", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "Platform-TenantId", + "value": "{{TenantName}}", + "type": "text" + } + ], + "url": { + "raw": "{{OperationsHostName}}/api/v1/transactionRequests/?payerPartyId=254708374149", + "host": [ + "{{OperationsHostName}}" + ], + "path": [ + "api", + "v1", + "transactionRequests", + "" + ], + "query": [ + { + "key": "transactionId", + "value": "8c2358be640c4BtABNeY", + "disabled": true + }, + { + "key": "page", + "value": "0", + "disabled": true + }, + { + "key": "size", + "value": "1", + "disabled": true + }, + { + "key": "state", + "value": "ACCEPTED", + "disabled": true + }, + { + "key": "amount", + "value": "1", + "disabled": true + }, + { + "key": "currency", + "value": "USD", + "disabled": true + }, + { + "key": "direction", + "value": "INCOMING", + "disabled": true + }, + { + "key": "payerPartyId", + "value": "254708374149" + }, + { + "key": "payeePartyId", + "value": "0", + "disabled": true + }, + { + "key": "payeeDfspId", + "value": "0", + "disabled": true + }, + { + "key": "payerDfspId", + "value": "0", + "disabled": true + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Content-Type-Options", + "value": "nosniff" + }, + { + "key": "X-XSS-Protection", + "value": "1; mode=block" + }, + { + "key": "Cache-Control", + "value": "no-cache, no-store, max-age=0, must-revalidate" + }, + { + "key": "Pragma", + "value": "no-cache" + }, + { + "key": "Expires", + "value": "0" + }, + { + "key": "X-Frame-Options", + "value": "DENY" + }, + { + "key": "Content-Type", + "value": "application/json;charset=UTF-8" + }, + { + "key": "Transfer-Encoding", + "value": "chunked" + }, + { + "key": "Date", + "value": "Tue, 05 Jul 2022 16:08:39 GMT" + } + ], + "cookie": [], + "body": "{\n \"content\": [\n {\n \"id\": 2,\n \"workflowInstanceKey\": \"2251799816729405\",\n \"transactionId\": \"dd2183f3ac5d5leU5nz3\",\n \"startedAt\": 1654993348000,\n \"completedAt\": null,\n \"state\": \"ACCEPTED\",\n \"payeeDfspId\": null,\n \"payeePartyId\": \"24450523\",\n \"payeePartyIdType\": \"ACCOUNTID\",\n \"payeeFee\": null,\n \"payeeQuoteCode\": null,\n \"payerDfspId\": null,\n \"payerPartyId\": \"254708374149\",\n \"payerPartyIdType\": \"MSISDN\",\n \"payerFee\": null,\n \"payerQuoteCode\": null,\n \"amount\": 1,\n \"currency\": \"USD\",\n \"direction\": \"INCOMING\",\n \"authType\": null,\n \"initiatorType\": \"BUSINESS\",\n \"scenario\": \"MPESA\"\n },\n {\n \"id\": 1,\n \"workflowInstanceKey\": \"2251799816099637\",\n \"transactionId\": \"8c2358be640c4BtABNeY\",\n \"startedAt\": 1654769838000,\n \"completedAt\": null,\n \"state\": \"ACCEPTED\",\n \"payeeDfspId\": null,\n \"payeePartyId\": \"24450523\",\n \"payeePartyIdType\": \"ACCOUNTID\",\n \"payeeFee\": null,\n \"payeeQuoteCode\": null,\n \"payerDfspId\": null,\n \"payerPartyId\": \"254708374149\",\n \"payerPartyIdType\": \"MSISDN\",\n \"payerFee\": null,\n \"payerQuoteCode\": null,\n \"amount\": 1,\n \"currency\": \"USD\",\n \"direction\": \"INCOMING\",\n \"authType\": null,\n \"initiatorType\": \"BUSINESS\",\n \"scenario\": \"MPESA\"\n }\n ],\n \"totalPages\": 1,\n \"totalElements\": 2,\n \"last\": true,\n \"numberOfElements\": 2,\n \"sort\": [\n {\n \"direction\": \"DESC\",\n \"property\": \"startedAt\",\n \"ignoreCase\": false,\n \"nullHandling\": \"NATIVE\",\n \"descending\": true,\n \"ascending\": false\n }\n ],\n \"first\": true,\n \"size\": 20,\n \"number\": 0\n}" + }, + { + "name": "Get Transaction Request by payeePartyId", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "Platform-TenantId", + "value": "{{TenantName}}", + "type": "text" + } + ], + "url": { + "raw": "{{OperationsHostName}}/api/v1/transactionRequests/?payeePartyId=24450523", + "host": [ + "{{OperationsHostName}}" + ], + "path": [ + "api", + "v1", + "transactionRequests", + "" + ], + "query": [ + { + "key": "transactionId", + "value": "8c2358be640c4BtABNeY", + "disabled": true + }, + { + "key": "page", + "value": "0", + "disabled": true + }, + { + "key": "size", + "value": "1", + "disabled": true + }, + { + "key": "state", + "value": "ACCEPTED", + "disabled": true + }, + { + "key": "amount", + "value": "1", + "disabled": true + }, + { + "key": "currency", + "value": "USD", + "disabled": true + }, + { + "key": "direction", + "value": "INCOMING", + "disabled": true + }, + { + "key": "payerPartyId", + "value": "254708374149", + "disabled": true + }, + { + "key": "payeePartyId", + "value": "24450523" + }, + { + "key": "payeeDfspId", + "value": "0", + "disabled": true + }, + { + "key": "payerDfspId", + "value": "0", + "disabled": true + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Content-Type-Options", + "value": "nosniff" + }, + { + "key": "X-XSS-Protection", + "value": "1; mode=block" + }, + { + "key": "Cache-Control", + "value": "no-cache, no-store, max-age=0, must-revalidate" + }, + { + "key": "Pragma", + "value": "no-cache" + }, + { + "key": "Expires", + "value": "0" + }, + { + "key": "X-Frame-Options", + "value": "DENY" + }, + { + "key": "Content-Type", + "value": "application/json;charset=UTF-8" + }, + { + "key": "Transfer-Encoding", + "value": "chunked" + }, + { + "key": "Date", + "value": "Tue, 05 Jul 2022 16:09:53 GMT" + } + ], + "cookie": [], + "body": "{\n \"content\": [\n {\n \"id\": 2,\n \"workflowInstanceKey\": \"2251799816729405\",\n \"transactionId\": \"dd2183f3ac5d5leU5nz3\",\n \"startedAt\": 1654993348000,\n \"completedAt\": null,\n \"state\": \"ACCEPTED\",\n \"payeeDfspId\": null,\n \"payeePartyId\": \"24450523\",\n \"payeePartyIdType\": \"ACCOUNTID\",\n \"payeeFee\": null,\n \"payeeQuoteCode\": null,\n \"payerDfspId\": null,\n \"payerPartyId\": \"254708374149\",\n \"payerPartyIdType\": \"MSISDN\",\n \"payerFee\": null,\n \"payerQuoteCode\": null,\n \"amount\": 1,\n \"currency\": \"USD\",\n \"direction\": \"INCOMING\",\n \"authType\": null,\n \"initiatorType\": \"BUSINESS\",\n \"scenario\": \"MPESA\"\n },\n {\n \"id\": 1,\n \"workflowInstanceKey\": \"2251799816099637\",\n \"transactionId\": \"8c2358be640c4BtABNeY\",\n \"startedAt\": 1654769838000,\n \"completedAt\": null,\n \"state\": \"ACCEPTED\",\n \"payeeDfspId\": null,\n \"payeePartyId\": \"24450523\",\n \"payeePartyIdType\": \"ACCOUNTID\",\n \"payeeFee\": null,\n \"payeeQuoteCode\": null,\n \"payerDfspId\": null,\n \"payerPartyId\": \"254708374149\",\n \"payerPartyIdType\": \"MSISDN\",\n \"payerFee\": null,\n \"payerQuoteCode\": null,\n \"amount\": 1,\n \"currency\": \"USD\",\n \"direction\": \"INCOMING\",\n \"authType\": null,\n \"initiatorType\": \"BUSINESS\",\n \"scenario\": \"MPESA\"\n }\n ],\n \"totalPages\": 1,\n \"totalElements\": 2,\n \"last\": true,\n \"numberOfElements\": 2,\n \"sort\": [\n {\n \"direction\": \"DESC\",\n \"property\": \"startedAt\",\n \"ignoreCase\": false,\n \"nullHandling\": \"NATIVE\",\n \"descending\": true,\n \"ascending\": false\n }\n ],\n \"first\": true,\n \"size\": 20,\n \"number\": 0\n}" + }, + { + "name": "Get Transaction Request by payeeDfspId", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "Platform-TenantId", + "value": "{{TenantName}}", + "type": "text" + } + ], + "url": { + "raw": "{{OperationsHostName}}/api/v1/transactionRequests/?payeeDfspId=null", + "host": [ + "{{OperationsHostName}}" + ], + "path": [ + "api", + "v1", + "transactionRequests", + "" + ], + "query": [ + { + "key": "transactionId", + "value": "8c2358be640c4BtABNeY", + "disabled": true + }, + { + "key": "page", + "value": "0", + "disabled": true + }, + { + "key": "size", + "value": "1", + "disabled": true + }, + { + "key": "state", + "value": "ACCEPTED", + "disabled": true + }, + { + "key": "amount", + "value": "1", + "disabled": true + }, + { + "key": "currency", + "value": "USD", + "disabled": true + }, + { + "key": "direction", + "value": "INCOMING", + "disabled": true + }, + { + "key": "payerPartyId", + "value": "254708374149", + "disabled": true + }, + { + "key": "payeePartyId", + "value": "24450523", + "disabled": true + }, + { + "key": "payeeDfspId", + "value": "null" + }, + { + "key": "payerDfspId", + "value": "0", + "disabled": true + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Content-Type-Options", + "value": "nosniff" + }, + { + "key": "X-XSS-Protection", + "value": "1; mode=block" + }, + { + "key": "Cache-Control", + "value": "no-cache, no-store, max-age=0, must-revalidate" + }, + { + "key": "Pragma", + "value": "no-cache" + }, + { + "key": "Expires", + "value": "0" + }, + { + "key": "X-Frame-Options", + "value": "DENY" + }, + { + "key": "Content-Type", + "value": "application/json;charset=UTF-8" + }, + { + "key": "Transfer-Encoding", + "value": "chunked" + }, + { + "key": "Date", + "value": "Tue, 05 Jul 2022 16:11:26 GMT" + } + ], + "cookie": [], + "body": "{\n \"content\": [],\n \"totalPages\": 0,\n \"totalElements\": 0,\n \"last\": true,\n \"numberOfElements\": 0,\n \"sort\": [\n {\n \"direction\": \"DESC\",\n \"property\": \"startedAt\",\n \"ignoreCase\": false,\n \"nullHandling\": \"NATIVE\",\n \"descending\": true,\n \"ascending\": false\n }\n ],\n \"first\": true,\n \"size\": 20,\n \"number\": 0\n}" + }, + { + "name": "Get Transaction Request by payerDfspId", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "Platform-TenantId", + "value": "{{TenantName}}", + "type": "text" + } + ], + "url": { + "raw": "{{OperationsHostName}}/api/v1/transactionRequests/?payerDfspId=null", + "host": [ + "{{OperationsHostName}}" + ], + "path": [ + "api", + "v1", + "transactionRequests", + "" + ], + "query": [ + { + "key": "transactionId", + "value": "8c2358be640c4BtABNeY", + "disabled": true + }, + { + "key": "page", + "value": "0", + "disabled": true + }, + { + "key": "size", + "value": "1", + "disabled": true + }, + { + "key": "state", + "value": "ACCEPTED", + "disabled": true + }, + { + "key": "amount", + "value": "1", + "disabled": true + }, + { + "key": "currency", + "value": "USD", + "disabled": true + }, + { + "key": "direction", + "value": "INCOMING", + "disabled": true + }, + { + "key": "payerPartyId", + "value": "254708374149", + "disabled": true + }, + { + "key": "payeePartyId", + "value": "24450523", + "disabled": true + }, + { + "key": "payeeDfspId", + "value": "null", + "disabled": true + }, + { + "key": "payerDfspId", + "value": "null" + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Content-Type-Options", + "value": "nosniff" + }, + { + "key": "X-XSS-Protection", + "value": "1; mode=block" + }, + { + "key": "Cache-Control", + "value": "no-cache, no-store, max-age=0, must-revalidate" + }, + { + "key": "Pragma", + "value": "no-cache" + }, + { + "key": "Expires", + "value": "0" + }, + { + "key": "X-Frame-Options", + "value": "DENY" + }, + { + "key": "Content-Type", + "value": "application/json;charset=UTF-8" + }, + { + "key": "Transfer-Encoding", + "value": "chunked" + }, + { + "key": "Date", + "value": "Tue, 05 Jul 2022 16:12:21 GMT" + } + ], + "cookie": [], + "body": "{\n \"content\": [],\n \"totalPages\": 0,\n \"totalElements\": 0,\n \"last\": true,\n \"numberOfElements\": 0,\n \"sort\": [\n {\n \"direction\": \"DESC\",\n \"property\": \"startedAt\",\n \"ignoreCase\": false,\n \"nullHandling\": \"NATIVE\",\n \"descending\": true,\n \"ascending\": false\n }\n ],\n \"first\": true,\n \"size\": 20,\n \"number\": 0\n}" + }, + { + "name": "Get Transaction Request before a date", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "Platform-TenantId", + "value": "{{TenantName}}", + "type": "text" + } + ], + "url": { + "raw": "{{OperationsHostName}}/api/v1/transactionRequests/?startTo=2022-06-10 10:17:18", + "host": [ + "{{OperationsHostName}}" + ], + "path": [ + "api", + "v1", + "transactionRequests", + "" + ], + "query": [ + { + "key": "transactionId", + "value": "8c2358be640c4BtABNeY", + "disabled": true + }, + { + "key": "page", + "value": "0", + "disabled": true + }, + { + "key": "size", + "value": "1", + "disabled": true + }, + { + "key": "state", + "value": "ACCEPTED", + "description": "IN_PROGRESS, RECEIVED, ACCEPTED, REJECTED, FAILED", + "disabled": true + }, + { + "key": "amount", + "value": "1", + "disabled": true + }, + { + "key": "currency", + "value": "USD", + "disabled": true + }, + { + "key": "direction", + "value": "INCOMING", + "disabled": true + }, + { + "key": "payerPartyId", + "value": "254708374149", + "disabled": true + }, + { + "key": "payeePartyId", + "value": "24450523", + "disabled": true + }, + { + "key": "payeeDfspId", + "value": "null", + "disabled": true + }, + { + "key": "payerDfspId", + "value": "null", + "disabled": true + }, + { + "key": "startFrom", + "value": "2022-06-10 10:17:18", + "description": "yyyy-MM-dd HH:mm:ss", + "disabled": true + }, + { + "key": "startTo", + "value": "2022-06-10 10:17:18", + "description": "yyyy-MM-dd HH:mm:ss" + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Content-Type-Options", + "value": "nosniff" + }, + { + "key": "X-XSS-Protection", + "value": "1; mode=block" + }, + { + "key": "Cache-Control", + "value": "no-cache, no-store, max-age=0, must-revalidate" + }, + { + "key": "Pragma", + "value": "no-cache" + }, + { + "key": "Expires", + "value": "0" + }, + { + "key": "X-Frame-Options", + "value": "DENY" + }, + { + "key": "Content-Type", + "value": "application/json;charset=UTF-8" + }, + { + "key": "Transfer-Encoding", + "value": "chunked" + }, + { + "key": "Date", + "value": "Wed, 06 Jul 2022 10:14:37 GMT" + } + ], + "cookie": [], + "body": "{\n \"content\": [\n {\n \"id\": 1,\n \"workflowInstanceKey\": \"2251799816099637\",\n \"transactionId\": \"8c2358be640c4BtABNeY\",\n \"startedAt\": 1654769838000,\n \"completedAt\": null,\n \"state\": \"ACCEPTED\",\n \"payeeDfspId\": null,\n \"payeePartyId\": \"24450523\",\n \"payeePartyIdType\": \"ACCOUNTID\",\n \"payeeFee\": null,\n \"payeeQuoteCode\": null,\n \"payerDfspId\": null,\n \"payerPartyId\": \"254708374149\",\n \"payerPartyIdType\": \"MSISDN\",\n \"payerFee\": null,\n \"payerQuoteCode\": null,\n \"amount\": 1,\n \"currency\": \"USD\",\n \"direction\": \"INCOMING\",\n \"authType\": null,\n \"initiatorType\": \"BUSINESS\",\n \"scenario\": \"MPESA\"\n }\n ],\n \"totalPages\": 1,\n \"totalElements\": 1,\n \"last\": true,\n \"numberOfElements\": 1,\n \"sort\": [\n {\n \"direction\": \"DESC\",\n \"property\": \"startedAt\",\n \"ignoreCase\": false,\n \"nullHandling\": \"NATIVE\",\n \"descending\": true,\n \"ascending\": false\n }\n ],\n \"first\": true,\n \"size\": 20,\n \"number\": 0\n}" + }, + { + "name": "Get Transaction Request after a date", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "Platform-TenantId", + "value": "{{TenantName}}", + "type": "text" + } + ], + "url": { + "raw": "{{OperationsHostName}}/api/v1/transactionRequests/?startFrom=2022-06-10 10:17:18", + "host": [ + "{{OperationsHostName}}" + ], + "path": [ + "api", + "v1", + "transactionRequests", + "" + ], + "query": [ + { + "key": "transactionId", + "value": "8c2358be640c4BtABNeY", + "disabled": true + }, + { + "key": "page", + "value": "0", + "disabled": true + }, + { + "key": "size", + "value": "1", + "disabled": true + }, + { + "key": "state", + "value": "ACCEPTED", + "description": "IN_PROGRESS, RECEIVED, ACCEPTED, REJECTED, FAILED", + "disabled": true + }, + { + "key": "amount", + "value": "1", + "disabled": true + }, + { + "key": "currency", + "value": "USD", + "disabled": true + }, + { + "key": "direction", + "value": "INCOMING", + "disabled": true + }, + { + "key": "payerPartyId", + "value": "254708374149", + "disabled": true + }, + { + "key": "payeePartyId", + "value": "24450523", + "disabled": true + }, + { + "key": "payeeDfspId", + "value": "null", + "disabled": true + }, + { + "key": "payerDfspId", + "value": "null", + "disabled": true + }, + { + "key": "startFrom", + "value": "2022-06-10 10:17:18", + "description": "yyyy-MM-dd HH:mm:ss" + }, + { + "key": "startTo", + "value": "2022-06-10 10:17:18", + "description": "yyyy-MM-dd HH:mm:ss", + "disabled": true + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Content-Type-Options", + "value": "nosniff" + }, + { + "key": "X-XSS-Protection", + "value": "1; mode=block" + }, + { + "key": "Cache-Control", + "value": "no-cache, no-store, max-age=0, must-revalidate" + }, + { + "key": "Pragma", + "value": "no-cache" + }, + { + "key": "Expires", + "value": "0" + }, + { + "key": "X-Frame-Options", + "value": "DENY" + }, + { + "key": "Content-Type", + "value": "application/json;charset=UTF-8" + }, + { + "key": "Transfer-Encoding", + "value": "chunked" + }, + { + "key": "Date", + "value": "Wed, 06 Jul 2022 10:15:01 GMT" + } + ], + "cookie": [], + "body": "{\n \"content\": [\n {\n \"id\": 2,\n \"workflowInstanceKey\": \"2251799816729405\",\n \"transactionId\": \"dd2183f3ac5d5leU5nz3\",\n \"startedAt\": 1654993348000,\n \"completedAt\": null,\n \"state\": \"ACCEPTED\",\n \"payeeDfspId\": null,\n \"payeePartyId\": \"24450523\",\n \"payeePartyIdType\": \"ACCOUNTID\",\n \"payeeFee\": null,\n \"payeeQuoteCode\": null,\n \"payerDfspId\": null,\n \"payerPartyId\": \"254708374149\",\n \"payerPartyIdType\": \"MSISDN\",\n \"payerFee\": null,\n \"payerQuoteCode\": null,\n \"amount\": 1,\n \"currency\": \"USD\",\n \"direction\": \"INCOMING\",\n \"authType\": null,\n \"initiatorType\": \"BUSINESS\",\n \"scenario\": \"MPESA\"\n }\n ],\n \"totalPages\": 1,\n \"totalElements\": 1,\n \"last\": true,\n \"numberOfElements\": 1,\n \"sort\": [\n {\n \"direction\": \"DESC\",\n \"property\": \"startedAt\",\n \"ignoreCase\": false,\n \"nullHandling\": \"NATIVE\",\n \"descending\": true,\n \"ascending\": false\n }\n ],\n \"first\": true,\n \"size\": 20,\n \"number\": 0\n}" + }, + { + "name": "Get Transaction Request between a date", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "Platform-TenantId", + "value": "{{TenantName}}", + "type": "text" + } + ], + "url": { + "raw": "{{OperationsHostName}}/api/v1/transactionRequests/?startFrom=2022-06-09 10:00:00&startTo=2022-06-09 11:00:00", + "host": [ + "{{OperationsHostName}}" + ], + "path": [ + "api", + "v1", + "transactionRequests", + "" + ], + "query": [ + { + "key": "transactionId", + "value": "8c2358be640c4BtABNeY", + "disabled": true + }, + { + "key": "page", + "value": "0", + "disabled": true + }, + { + "key": "size", + "value": "1", + "disabled": true + }, + { + "key": "state", + "value": "ACCEPTED", + "description": "IN_PROGRESS, RECEIVED, ACCEPTED, REJECTED, FAILED", + "disabled": true + }, + { + "key": "amount", + "value": "1", + "disabled": true + }, + { + "key": "currency", + "value": "USD", + "disabled": true + }, + { + "key": "direction", + "value": "INCOMING", + "disabled": true + }, + { + "key": "payerPartyId", + "value": "254708374149", + "disabled": true + }, + { + "key": "payeePartyId", + "value": "24450523", + "disabled": true + }, + { + "key": "payeeDfspId", + "value": "null", + "disabled": true + }, + { + "key": "payerDfspId", + "value": "null", + "disabled": true + }, + { + "key": "startFrom", + "value": "2022-06-09 10:00:00", + "description": "yyyy-MM-dd HH:mm:ss" + }, + { + "key": "startTo", + "value": "2022-06-09 11:00:00", + "description": "yyyy-MM-dd HH:mm:ss" + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Content-Type-Options", + "value": "nosniff" + }, + { + "key": "X-XSS-Protection", + "value": "1; mode=block" + }, + { + "key": "Cache-Control", + "value": "no-cache, no-store, max-age=0, must-revalidate" + }, + { + "key": "Pragma", + "value": "no-cache" + }, + { + "key": "Expires", + "value": "0" + }, + { + "key": "X-Frame-Options", + "value": "DENY" + }, + { + "key": "Content-Type", + "value": "application/json;charset=UTF-8" + }, + { + "key": "Transfer-Encoding", + "value": "chunked" + }, + { + "key": "Date", + "value": "Wed, 06 Jul 2022 10:16:06 GMT" + } + ], + "cookie": [], + "body": "{\n \"content\": [\n {\n \"id\": 1,\n \"workflowInstanceKey\": \"2251799816099637\",\n \"transactionId\": \"8c2358be640c4BtABNeY\",\n \"startedAt\": 1654769838000,\n \"completedAt\": null,\n \"state\": \"ACCEPTED\",\n \"payeeDfspId\": null,\n \"payeePartyId\": \"24450523\",\n \"payeePartyIdType\": \"ACCOUNTID\",\n \"payeeFee\": null,\n \"payeeQuoteCode\": null,\n \"payerDfspId\": null,\n \"payerPartyId\": \"254708374149\",\n \"payerPartyIdType\": \"MSISDN\",\n \"payerFee\": null,\n \"payerQuoteCode\": null,\n \"amount\": 1,\n \"currency\": \"USD\",\n \"direction\": \"INCOMING\",\n \"authType\": null,\n \"initiatorType\": \"BUSINESS\",\n \"scenario\": \"MPESA\"\n }\n ],\n \"totalPages\": 1,\n \"totalElements\": 1,\n \"last\": true,\n \"numberOfElements\": 1,\n \"sort\": [\n {\n \"direction\": \"DESC\",\n \"property\": \"startedAt\",\n \"ignoreCase\": false,\n \"nullHandling\": \"NATIVE\",\n \"descending\": true,\n \"ascending\": false\n }\n ],\n \"first\": true,\n \"size\": 20,\n \"number\": 0\n}" + }, + { + "name": "Get Transaction Request by sortedBy", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "Platform-TenantId", + "value": "{{TenantName}}", + "type": "text" + } + ], + "url": { + "raw": "{{OperationsHostName}}/api/v1/transactionRequests/?sortedBy=currency", + "host": [ + "{{OperationsHostName}}" + ], + "path": [ + "api", + "v1", + "transactionRequests", + "" + ], + "query": [ + { + "key": "transactionId", + "value": "8c2358be640c4BtABNeY", + "disabled": true + }, + { + "key": "page", + "value": "0", + "disabled": true + }, + { + "key": "size", + "value": "1", + "disabled": true + }, + { + "key": "state", + "value": "ACCEPTED", + "description": "IN_PROGRESS, RECEIVED, ACCEPTED, REJECTED, FAILED", + "disabled": true + }, + { + "key": "amount", + "value": "1", + "disabled": true + }, + { + "key": "currency", + "value": "USD", + "disabled": true + }, + { + "key": "direction", + "value": "INCOMING", + "disabled": true + }, + { + "key": "payerPartyId", + "value": "254708374149", + "disabled": true + }, + { + "key": "payeePartyId", + "value": "24450523", + "disabled": true + }, + { + "key": "payeeDfspId", + "value": "null", + "disabled": true + }, + { + "key": "payerDfspId", + "value": "null", + "disabled": true + }, + { + "key": "startFrom", + "value": "2022-06-09 10:00:00", + "description": "yyyy-MM-dd HH:mm:ss", + "disabled": true + }, + { + "key": "startTo", + "value": "2022-06-09 11:00:00", + "description": "yyyy-MM-dd HH:mm:ss", + "disabled": true + }, + { + "key": "sortedBy", + "value": "currency" + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Content-Type-Options", + "value": "nosniff" + }, + { + "key": "X-XSS-Protection", + "value": "1; mode=block" + }, + { + "key": "Cache-Control", + "value": "no-cache, no-store, max-age=0, must-revalidate" + }, + { + "key": "Pragma", + "value": "no-cache" + }, + { + "key": "Expires", + "value": "0" + }, + { + "key": "X-Frame-Options", + "value": "DENY" + }, + { + "key": "Content-Type", + "value": "application/json;charset=UTF-8" + }, + { + "key": "Transfer-Encoding", + "value": "chunked" + }, + { + "key": "Date", + "value": "Wed, 06 Jul 2022 10:20:16 GMT" + } + ], + "cookie": [], + "body": "{\n \"content\": [\n {\n \"id\": 1,\n \"workflowInstanceKey\": \"2251799816099637\",\n \"transactionId\": \"8c2358be640c4BtABNeY\",\n \"startedAt\": 1654769838000,\n \"completedAt\": null,\n \"state\": \"ACCEPTED\",\n \"payeeDfspId\": null,\n \"payeePartyId\": \"24450523\",\n \"payeePartyIdType\": \"ACCOUNTID\",\n \"payeeFee\": null,\n \"payeeQuoteCode\": null,\n \"payerDfspId\": null,\n \"payerPartyId\": \"254708374149\",\n \"payerPartyIdType\": \"MSISDN\",\n \"payerFee\": null,\n \"payerQuoteCode\": null,\n \"amount\": 1,\n \"currency\": \"USD\",\n \"direction\": \"INCOMING\",\n \"authType\": null,\n \"initiatorType\": \"BUSINESS\",\n \"scenario\": \"MPESA\"\n },\n {\n \"id\": 2,\n \"workflowInstanceKey\": \"2251799816729405\",\n \"transactionId\": \"dd2183f3ac5d5leU5nz3\",\n \"startedAt\": 1654993348000,\n \"completedAt\": null,\n \"state\": \"ACCEPTED\",\n \"payeeDfspId\": null,\n \"payeePartyId\": \"24450523\",\n \"payeePartyIdType\": \"ACCOUNTID\",\n \"payeeFee\": null,\n \"payeeQuoteCode\": null,\n \"payerDfspId\": null,\n \"payerPartyId\": \"254708374149\",\n \"payerPartyIdType\": \"MSISDN\",\n \"payerFee\": null,\n \"payerQuoteCode\": null,\n \"amount\": 1,\n \"currency\": \"USD\",\n \"direction\": \"INCOMING\",\n \"authType\": null,\n \"initiatorType\": \"BUSINESS\",\n \"scenario\": \"MPESA\"\n }\n ],\n \"totalPages\": 1,\n \"totalElements\": 2,\n \"last\": true,\n \"numberOfElements\": 2,\n \"sort\": [\n {\n \"direction\": \"DESC\",\n \"property\": \"currency\",\n \"ignoreCase\": false,\n \"nullHandling\": \"NATIVE\",\n \"descending\": true,\n \"ascending\": false\n }\n ],\n \"first\": true,\n \"size\": 20,\n \"number\": 0\n}" + }, + { + "name": "Get Transaction Request in ascending order", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "Platform-TenantId", + "value": "{{TenantName}}", + "type": "text" + } + ], + "url": { + "raw": "{{OperationsHostName}}/api/v1/transactionRequests/?sortedOrder=ASC", + "host": [ + "{{OperationsHostName}}" + ], + "path": [ + "api", + "v1", + "transactionRequests", + "" + ], + "query": [ + { + "key": "transactionId", + "value": "8c2358be640c4BtABNeY", + "disabled": true + }, + { + "key": "page", + "value": "0", + "disabled": true + }, + { + "key": "size", + "value": "1", + "disabled": true + }, + { + "key": "state", + "value": "ACCEPTED", + "description": "IN_PROGRESS, RECEIVED, ACCEPTED, REJECTED, FAILED", + "disabled": true + }, + { + "key": "amount", + "value": "1", + "disabled": true + }, + { + "key": "currency", + "value": "USD", + "disabled": true + }, + { + "key": "direction", + "value": "INCOMING", + "disabled": true + }, + { + "key": "payerPartyId", + "value": "254708374149", + "disabled": true + }, + { + "key": "payeePartyId", + "value": "24450523", + "disabled": true + }, + { + "key": "payeeDfspId", + "value": "null", + "disabled": true + }, + { + "key": "payerDfspId", + "value": "null", + "disabled": true + }, + { + "key": "startFrom", + "value": "2022-06-09 10:00:00", + "description": "yyyy-MM-dd HH:mm:ss", + "disabled": true + }, + { + "key": "startTo", + "value": "2022-06-09 11:00:00", + "description": "yyyy-MM-dd HH:mm:ss", + "disabled": true + }, + { + "key": "sortedBy", + "value": "currency", + "disabled": true + }, + { + "key": "sortedOrder", + "value": "ASC", + "description": "DESC, ASC" + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Content-Type-Options", + "value": "nosniff" + }, + { + "key": "X-XSS-Protection", + "value": "1; mode=block" + }, + { + "key": "Cache-Control", + "value": "no-cache, no-store, max-age=0, must-revalidate" + }, + { + "key": "Pragma", + "value": "no-cache" + }, + { + "key": "Expires", + "value": "0" + }, + { + "key": "X-Frame-Options", + "value": "DENY" + }, + { + "key": "Content-Type", + "value": "application/json;charset=UTF-8" + }, + { + "key": "Transfer-Encoding", + "value": "chunked" + }, + { + "key": "Date", + "value": "Wed, 06 Jul 2022 10:23:03 GMT" + } + ], + "cookie": [], + "body": "{\n \"content\": [\n {\n \"id\": 1,\n \"workflowInstanceKey\": \"2251799816099637\",\n \"transactionId\": \"8c2358be640c4BtABNeY\",\n \"startedAt\": 1654769838000,\n \"completedAt\": null,\n \"state\": \"ACCEPTED\",\n \"payeeDfspId\": null,\n \"payeePartyId\": \"24450523\",\n \"payeePartyIdType\": \"ACCOUNTID\",\n \"payeeFee\": null,\n \"payeeQuoteCode\": null,\n \"payerDfspId\": null,\n \"payerPartyId\": \"254708374149\",\n \"payerPartyIdType\": \"MSISDN\",\n \"payerFee\": null,\n \"payerQuoteCode\": null,\n \"amount\": 1,\n \"currency\": \"USD\",\n \"direction\": \"INCOMING\",\n \"authType\": null,\n \"initiatorType\": \"BUSINESS\",\n \"scenario\": \"MPESA\"\n },\n {\n \"id\": 2,\n \"workflowInstanceKey\": \"2251799816729405\",\n \"transactionId\": \"dd2183f3ac5d5leU5nz3\",\n \"startedAt\": 1654993348000,\n \"completedAt\": null,\n \"state\": \"ACCEPTED\",\n \"payeeDfspId\": null,\n \"payeePartyId\": \"24450523\",\n \"payeePartyIdType\": \"ACCOUNTID\",\n \"payeeFee\": null,\n \"payeeQuoteCode\": null,\n \"payerDfspId\": null,\n \"payerPartyId\": \"254708374149\",\n \"payerPartyIdType\": \"MSISDN\",\n \"payerFee\": null,\n \"payerQuoteCode\": null,\n \"amount\": 1,\n \"currency\": \"ASD\",\n \"direction\": \"INCOMING\",\n \"authType\": null,\n \"initiatorType\": \"BUSINESS\",\n \"scenario\": \"MPESA\"\n }\n ],\n \"totalPages\": 1,\n \"totalElements\": 2,\n \"last\": true,\n \"numberOfElements\": 2,\n \"sort\": [\n {\n \"direction\": \"ASC\",\n \"property\": \"startedAt\",\n \"ignoreCase\": false,\n \"nullHandling\": \"NATIVE\",\n \"descending\": false,\n \"ascending\": true\n }\n ],\n \"first\": true,\n \"size\": 20,\n \"number\": 0\n}" + } + ] + }, + { + "name": "Generate x-signature (dev utility)", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "postman.setEnvironmentVariable(\"x-signature\", responseBody);", + "postman.setEnvironmentVariable(\"X-CorrelationId\", pm.request.headers.get(\"X-CorrelationID\"));" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "auth": { + "type": "noauth" + }, + "method": "POST", + "header": [ + { + "key": "X-CorrelationID", + "value": "{{$guid}}", + "type": "text" + }, + { + "key": "Platform-TenantId", + "value": "{{TenantName}}", + "type": "text" + }, + { + "key": "privateKey", + "value": "{{privateKey}}", + "type": "text" + } + ], + "body": { + "mode": "formdata", + "formdata": [ + { + "key": "data", + "type": "file", + "src": "/Users/ankitagarwal/fynarfin/ph-ee-bulk-demo-7.csv" + } + ] + }, + "url": { + "raw": "{{OperationsHostName}}/api/v1/util/x-signature", + "host": [ + "{{OperationsHostName}}" + ], + "path": [ + "api", + "v1", + "util", + "x-signature" + ] + } + }, + "response": [] + } + ] + }, + { + "name": "Account Management", + "item": [ + { + "name": "Account Statement by Identifier", + "request": { + "method": "GET", + "header": [ + { + "key": "Platform-TenantId", + "value": "ibank-usa", + "type": "text" + } + ], + "url": { + "raw": "{{ChannelHostName}}/channel/accounts/{{IdentifierType}}/{{IdentifierId}}/statemententries", + "host": [ + "{{ChannelHostName}}" + ], + "path": [ + "channel", + "accounts", + "{{IdentifierType}}", + "{{IdentifierId}}", + "statemententries" + ] + } + }, + "response": [] + }, + { + "name": "Account Balance", + "protocolProfileBehavior": { + "disableBodyPruning": true + }, + "request": { + "method": "GET", + "header": [ + { + "key": "Platform-TenantId", + "type": "text", + "value": "ibank-usa" + }, + { + "key": "Content-Type", + "type": "text", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "" + }, + "url": { + "raw": "{{ChannelHostName}}/channel/accounts/{{IdentifierType}}/{{IdentifierId}}/balance", + "host": [ + "{{ChannelHostName}}" + ], + "path": [ + "channel", + "accounts", + "{{IdentifierType}}", + "{{IdentifierId}}", + "balance" + ] + } + }, + "response": [] + }, + { + "name": "Account Status", + "request": { + "method": "GET", + "header": [ + { + "key": "Platform-TenantId", + "value": "ibank-usa", + "type": "text" + } + ], + "url": { + "raw": "{{ChannelHostName}}/channel/accounts/{{IdentifierType}}/{{IdentifierId}}/status", + "host": [ + "{{ChannelHostName}}" + ], + "path": [ + "channel", + "accounts", + "{{IdentifierType}}", + "{{IdentifierId}}", + "status" + ] + } + }, + "response": [] + }, + { + "name": "Account Name", + "protocolProfileBehavior": { + "disableBodyPruning": true + }, + "request": { + "method": "GET", + "header": [ + { + "key": "Platform-TenantId", + "type": "text", + "value": "ibank-usa" + }, + { + "key": "Content-Type", + "type": "text", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "" + }, + "url": { + "raw": "{{ChannelHostName}}/channel/accounts/{{IdentifierType}}/{{IdentifierId}}/accountname", + "host": [ + "{{ChannelHostName}}" + ], + "path": [ + "channel", + "accounts", + "{{IdentifierType}}", + "{{IdentifierId}}", + "accountname" + ] + } + }, + "response": [] + }, + { + "name": "Account Transactions", + "protocolProfileBehavior": { + "disableBodyPruning": true + }, + "request": { + "method": "GET", + "header": [ + { + "key": "Platform-TenantId", + "type": "text", + "value": "ibank-usa" + }, + { + "key": "Content-Type", + "type": "text", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "" + }, + "url": { + "raw": "{{ChannelHostName}}/channel/accounts/{{IdentifierType}}/{{IdentifierId}}/transactions", + "host": [ + "{{ChannelHostName}}" + ], + "path": [ + "channel", + "accounts", + "{{IdentifierType}}", + "{{IdentifierId}}", + "transactions" + ] + } + }, + "response": [] + }, + { + "name": "Deposit Money Copy", + "request": { + "method": "POST", + "header": [ + { + "key": "Platform-TenantId", + "value": "ibank-usa", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"amount\": \"304\",\n \"type\": \"transfer\",\n \"creditParty\": [\n {\n \"key\": \"msisdn\",\n \"value\": \"+919900878571\"\n }\n ],\n \"currency\": \"USD\"\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{ChannelHostName}}/channel/deposit", + "host": [ + "{{ChannelHostName}}" + ], + "path": [ + "channel", + "deposit" + ] + } + }, + "response": [] + } + ] + }, + { + "name": "Customer Management", + "item": [ + { + "name": "Customer Set PIN", + "request": { + "method": "POST", + "header": [ + { + "key": "Platform-TenantId", + "type": "text", + "value": "ibank-usa" + }, + { + "key": "Content-Type", + "type": "text", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"existingPin\": \"String\",\n \"pin\": \"String\"\n}" + }, + "url": { + "raw": "{{ChannelHostName}}/channel/customers/{{IdentifierType}}/{{IdentifierId}}/cpin", + "host": [ + "{{ChannelHostName}}" + ], + "path": [ + "channel", + "customers", + "{{IdentifierType}}", + "{{IdentifierId}}", + "cpin" + ] + } + }, + "response": [] + }, + { + "name": "Customer Creation", + "request": { + "method": "POST", + "header": [ + { + "key": "Platform-TenantId", + "type": "text", + "value": "ibank-usa" + }, + { + "key": "Content-Type", + "type": "text", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"identifierType\": \"String\",\n \"IdentifierId\": \"String\"\n}" + }, + "url": { + "raw": "{{ChannelHostName}}/channel/customers", + "host": [ + "{{ChannelHostName}}" + ], + "path": [ + "channel", + "customers" + ] + } + }, + "response": [] + } + ] + }, + { + "name": "Miscellaneous", + "item": [ + { + "name": "Heartbeat", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{ChannelHostName}}/channel/heartbeat", + "host": [ + "{{ChannelHostName}}" + ], + "path": [ + "channel", + "heartbeat" + ] + } + }, + "response": [] + } + ] + }, + { + "name": "Mojaloop APIs", + "item": [ + { + "name": "Transfer Details", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{ChannelHostName}}/channel/transfer/{{transactionId}}", + "host": [ + "{{ChannelHostName}}" + ], + "path": [ + "channel", + "transfer", + "{{transactionId}}" + ] + } + }, + "response": [] + }, + { + "name": "Transfer", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"payer\": {\n \"partyIdInfo\": {\n \"partyIdType\": \"MSISDN\",\n \"partyIdentifier\": \"27710101999\"\n }\n },\n \"payee\": {\n \"partyIdInfo\": {\n \"partyIdType\": \"MSISDN\",\n \"partyIdentifier\": \"27710102999\"\n }\n },\n \"amount\": {\n \"amount\": 230,\n \"currency\": \"TZS\"\n }\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{ChannelHostName}}/channel/transfer", + "host": [ + "{{ChannelHostName}}" + ], + "path": [ + "channel", + "transfer" + ] + } + }, + "response": [] + }, + { + "name": "Transfer Request", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"payer\": {\n \"partyIdInfo\": {\n \"partyIdType\": \"MSISDN\",\n \"partyIdentifier\": \"27710203999\"\n }\n },\n \"payee\": {\n \"partyIdInfo\": {\n \"partyIdType\": \"MSISDN\",\n \"partyIdentifier\": \"27710305999\"\n }\n },\n \"amount\": {\n \"amount\": 77,\n \"currency\": \"TZS\"\n }\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{ChannelHostName}}/channel/transactionRequest", + "host": [ + "{{ChannelHostName}}" + ], + "path": [ + "channel", + "transactionRequest" + ] + } + }, + "response": [] + }, + { + "name": "Party Registration", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"accountId\":\"9062b90de19b43989005\",\n \"idType\": \"EMAIL\",\n \"idValue\": \"test@test.hu\"\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{ChannelHostName}}/channel/partyRegistration", + "host": [ + "{{ChannelHostName}}" + ], + "path": [ + "channel", + "partyRegistration" + ] + } + }, + "response": [] + } + ] + }, + { + "name": "Channel APIs", + "item": [ + { + "name": "GSMA Stub", + "item": [ + { + "name": "transactions", + "item": [ + { + "name": "{transaction Reference}", + "item": [ + { + "name": "View A Transaction", + "protocolProfileBehavior": { + "disabledSystemHeaders": { + "accept": true + } + }, + "request": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API.", + "disabled": true + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + }, + { + "key": "Accept", + "value": "application/json", + "type": "text" + } + ], + "url": { + "raw": "{{ChannelGSMAHostName}}/transactions/{{transactionReference}}", + "host": [ + "{{ChannelGSMAHostName}}" + ], + "path": [ + "transactions", + "{{transactionReference}}" + ] + }, + "description": "This endpoint returns the details of a transaction" + }, + "response": [ + { + "name": "Represents an Error Caused by a Failure to Identify the Target Resource", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/transactions/:transactionReference", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "transactions", + ":transactionReference" + ], + "variable": [ + { + "key": "transactionReference" + } + ] + } + }, + "status": "Not Found", + "code": 404, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents a Transaction response", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/transactions/:transactionReference", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "transactions", + ":transactionReference" + ], + "variable": [ + { + "key": "transactionReference" + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"amount\": \"15.21\",\n \"currency\": \"\",\n \"type\": \"\",\n \"transactionReference\": \"\",\n \"transactionStatus\": \"\",\n \"debitParty\": [\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n },\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n }\n ],\n \"creditParty\": [\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n },\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n }\n ],\n \"subType\": \"\",\n \"descriptionText\": \"\",\n \"requestDate\": \"\",\n \"requestingOrganisationTransactionReference\": \"\",\n \"oneTimeCode\": \"\",\n \"geoCode\": \"37.423825,-122.082900\",\n \"senderKyc\": {\n \"nationality\": \"\",\n \"dateOfBirth\": \"2000-11-20\",\n \"occupation\": \"\",\n \"employerName\": \"\",\n \"contactPhone\": \"\",\n \"gender\": \"\",\n \"idDocument\": [\n {\n \"idType\": \"\",\n \"idNumber\": \"\",\n \"issueDate\": \"2018-11-20\",\n \"expiryDate\": \"2018-11-20\",\n \"issuer\": \"\",\n \"issuerPlace\": \"\",\n \"issuerCountry\": \"\",\n \"otherIddescription\": \"\"\n },\n {\n \"idType\": \"\",\n \"idNumber\": \"\",\n \"issueDate\": \"2018-11-20\",\n \"expiryDate\": \"2018-11-20\",\n \"issuer\": \"\",\n \"issuerPlace\": \"\",\n \"issuerCountry\": \"\",\n \"otherIddescription\": \"\"\n }\n ],\n \"postalAddress\": {\n \"country\": \"\",\n \"addressLine1\": \"\",\n \"addressLine2\": \"\",\n \"addressLine3\": \"\",\n \"city\": \"\",\n \"stateProvince\": \"\",\n \"postalCode\": \"\"\n },\n \"subjectName\": {\n \"title\": \"\",\n \"firstName\": \"\",\n \"middleName\": \"\",\n \"lastName\": \"\",\n \"fullName\": \"\",\n \"nativeName\": \"\"\n },\n \"emailAddress\": \"\",\n \"birthCountry\": \"\"\n },\n \"recipientKyc\": {\n \"nationality\": \"\",\n \"dateOfBirth\": \"2000-11-20\",\n \"occupation\": \"\",\n \"employerName\": \"\",\n \"contactPhone\": \"\",\n \"gender\": \"\",\n \"idDocument\": [\n {\n \"idType\": \"\",\n \"idNumber\": \"\",\n \"issueDate\": \"2018-11-20\",\n \"expiryDate\": \"2018-11-20\",\n \"issuer\": \"\",\n \"issuerPlace\": \"\",\n \"issuerCountry\": \"\",\n \"otherIddescription\": \"\"\n },\n {\n \"idType\": \"\",\n \"idNumber\": \"\",\n \"issueDate\": \"2018-11-20\",\n \"expiryDate\": \"2018-11-20\",\n \"issuer\": \"\",\n \"issuerPlace\": \"\",\n \"issuerCountry\": \"\",\n \"otherIddescription\": \"\"\n }\n ],\n \"postalAddress\": {\n \"country\": \"\",\n \"addressLine1\": \"\",\n \"addressLine2\": \"\",\n \"addressLine3\": \"\",\n \"city\": \"\",\n \"stateProvince\": \"\",\n \"postalCode\": \"\"\n },\n \"subjectName\": {\n \"title\": \"\",\n \"firstName\": \"\",\n \"middleName\": \"\",\n \"lastName\": \"\",\n \"fullName\": \"\",\n \"nativeName\": \"\"\n },\n \"emailAddress\": \"\",\n \"birthCountry\": \"\"\n },\n \"originalTransactionReference\": \"\",\n \"servicingIdentity\": \"\",\n \"fees\": [\n {\n \"feeType\": \"\",\n \"feeCurrency\": \"\",\n \"feeAmount\": \"15.21\"\n },\n {\n \"feeType\": \"\",\n \"feeCurrency\": \"\",\n \"feeAmount\": \"15.21\"\n }\n ],\n \"requestingLei\": \"54930084UKLVMY22DS16\",\n \"receivingLei\": \"5493000IBP32UQZ0KL24\",\n \"metadata\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ],\n \"creationDate\": \"\",\n \"modificationDate\": \"\",\n \"dateCreated\": \"\",\n \"dateModified\": \"\",\n \"transactionReceipt\": \"\",\n \"internationalTransferInformation\": {\n \"originCountry\": \"\",\n \"quotationReference\": \"\",\n \"quoteId\": \"\",\n \"receivingCountry\": \"\",\n \"remittancePurpose\": \"\",\n \"relationshipSender\": \"\",\n \"deliveryMethod\": \"\",\n \"senderBlockingReason\": \"\",\n \"recipientBlockingReason\": \"\"\n }\n}" + }, + { + "name": "Represents an Error Caused by the Violation of a Business Rule", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/transactions/:transactionReference", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "transactions", + ":transactionReference" + ], + "variable": [ + { + "key": "transactionReference" + } + ] + } + }, + "status": "Bad Request", + "code": 400, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by an Authorisation Failure", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/transactions/:transactionReference", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "transactions", + ":transactionReference" + ], + "variable": [ + { + "key": "transactionReference" + } + ] + } + }, + "status": "Unauthorized", + "code": 401, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by a General Server-Side Issue", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/transactions/:transactionReference", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "transactions", + ":transactionReference" + ], + "variable": [ + { + "key": "transactionReference" + } + ] + } + }, + "status": "Internal Server Error", + "code": 500, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by System Unavailability", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/transactions/:transactionReference", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "transactions", + ":transactionReference" + ], + "variable": [ + { + "key": "transactionReference" + } + ] + } + }, + "status": "Service Unavailable", + "code": 503, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + } + ] + }, + { + "name": "Create A Reversal", + "request": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API.", + "disabled": true + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID.", + "disabled": true + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server.", + "disabled": true + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication", + "disabled": true + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server.", + "disabled": true + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed.", + "disabled": true + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", + "disabled": true + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", + "disabled": true + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App.", + "disabled": true + }, + { + "key": "X-Callback-URL", + "value": "", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT.", + "disabled": true + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header.", + "disabled": true + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header.", + "disabled": true + }, + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Accept", + "value": "application/json", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"requestingOrganisationTransactionReference\": \"string\",\n \"creditParty\": [\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n }\n ],\n \"debitParty\": [\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n }\n ],\n \"type\": \"reversal\",\n \"subType\": \"string\",\n \"amount\": \"15.21\",\n \"currency\": \"AED\",\n \"descriptionText\": \"string\",\n \"fees\": [\n {\n \"feeType\": \"string\",\n \"feeAmount\": \"15.21\",\n \"feeCurrency\": \"AED\"\n }\n ],\n \"geoCode\": \"37.423825,-122.082900\",\n \"requestingOrganisation\": {\n \"requestingOrganisationIdentifierType\": \"lei\",\n \"requestingOrganisationIdentifier\": \"string\"\n },\n \"servicingIdentity\": \"string\",\n \"requestDate\": \"2022-09-29T00:38:52.909Z\",\n \"customData\": [\n {\n \"key\": \"string\",\n \"value\": \"string\"\n }\n ],\n \"metadata\": [\n {\n \"key\": \"string\",\n \"value\": \"string\"\n }\n ]\n}" + }, + "url": { + "raw": "{{ChannelGSMAHostName}}/transactions/{{transactionReference}}/reversals", + "host": [ + "{{ChannelGSMAHostName}}" + ], + "path": [ + "transactions", + "{{transactionReference}}", + "reversals" + ] + }, + "description": "Provided with a valid object representation, this endpoint allows for a new reversal to be created" + }, + "response": [ + { + "name": "Represents an Error Caused by an Authorisation Failure", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/transactions/:transactionReference/reversals", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "transactions", + ":transactionReference", + "reversals" + ], + "variable": [ + { + "key": "transactionReference" + } + ] + } + }, + "status": "Unauthorized", + "code": 401, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by System Unavailability", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/transactions/:transactionReference/reversals", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "transactions", + ":transactionReference", + "reversals" + ], + "variable": [ + { + "key": "transactionReference" + } + ] + } + }, + "status": "Service Unavailable", + "code": 503, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by a Failure to Identify the Target Resource", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/transactions/:transactionReference/reversals", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "transactions", + ":transactionReference", + "reversals" + ], + "variable": [ + { + "key": "transactionReference" + } + ] + } + }, + "status": "Not Found", + "code": 404, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Asynchronous response", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/transactions/:transactionReference/reversals", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "transactions", + ":transactionReference", + "reversals" + ], + "variable": [ + { + "key": "transactionReference" + } + ] + } + }, + "status": "Accepted", + "code": 202, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"notificationMethod\": \"\",\n \"serverCorrelationId\": \"\",\n \"status\": \"\",\n \"pendingReason\": \"\",\n \"objectReference\": \"\",\n \"expiryTime\": \"\",\n \"pollLimit\": \"\",\n \"error\": {\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n }\n}" + }, + { + "name": "Represents a Transaction Reversal response", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/transactions/:transactionReference/reversals", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "transactions", + ":transactionReference", + "reversals" + ], + "variable": [ + { + "key": "transactionReference" + } + ] + } + }, + "status": "Created", + "code": 201, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"type\": \"reversal\",\n \"originalTransactionReference\": \"\",\n \"transactionReference\": \"\",\n \"transactionStatus\": \"\",\n \"amount\": \"15.21\",\n \"currency\": \"\",\n \"subType\": \"\",\n \"descriptionText\": \"\",\n \"requestDate\": \"\",\n \"geoCode\": \"37.423825,-122.082900\",\n \"requestingOrganisationTransactionReference\": \"\",\n \"debitParty\": [\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n },\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n }\n ],\n \"creditParty\": [\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n },\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n }\n ],\n \"requestingLei\": \"54930084UKLVMY22DS16\",\n \"receivingLei\": \"5493000IBP32UQZ0KL24\",\n \"servicingIdentity\": \"\",\n \"fees\": [\n {\n \"feeType\": \"\",\n \"feeCurrency\": \"\",\n \"feeAmount\": \"15.21\"\n },\n {\n \"feeType\": \"\",\n \"feeCurrency\": \"\",\n \"feeAmount\": \"15.21\"\n }\n ],\n \"metadata\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ],\n \"creationDate\": \"\",\n \"modificationDate\": \"\",\n \"dateCreated\": \"\",\n \"dateModified\": \"\",\n \"transactionReceipt\": \"\"\n}" + }, + { + "name": "Represents an Error Caused by the Violation of a Business Rule", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/transactions/:transactionReference/reversals", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "transactions", + ":transactionReference", + "reversals" + ], + "variable": [ + { + "key": "transactionReference" + } + ] + } + }, + "status": "Bad Request", + "code": 400, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by a General Server-Side Issue", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/transactions/:transactionReference/reversals", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "transactions", + ":transactionReference", + "reversals" + ], + "variable": [ + { + "key": "transactionReference" + } + ] + } + }, + "status": "Internal Server Error", + "code": 500, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + } + ] + } + ] + }, + { + "name": "Create a Transaction", + "request": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API.", + "disabled": true + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID.", + "disabled": true + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server.", + "disabled": true + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication", + "disabled": true + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server.", + "disabled": true + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed.", + "disabled": true + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", + "disabled": true + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", + "disabled": true + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App.", + "disabled": true + }, + { + "key": "X-Callback-URL", + "value": "", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT.", + "disabled": true + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header.", + "disabled": true + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header.", + "disabled": true + }, + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Accept", + "value": "application/json", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"requestingOrganisationTransactionReference\": \"string\",\n \"originalTransactionReference\": \"string\",\n \"subType\": \"string\",\n \"type\": \"transfer\",\n \"amount\": \"15.21\",\n \"currency\": \"AED\",\n \"descriptionText\": \"string\",\n \"fees\": [\n {\n \"feeType\": \"string\",\n \"feeAmount\": \"15.21\",\n \"feeCurrency\": \"AED\"\n }\n ],\n \"geoCode\": \"37.423825,-122.082900\",\n \"internationalTransferInformation\": {\n \"quotationReference\": \"string\",\n \"quoteId\": \"string\",\n \"originCountry\": \"AD\",\n \"deliveryMethod\": \"directtoaccount\",\n \"receivingCountry\": \"AD\",\n \"relationshipSender\": \"string\",\n \"remittancePurpose\": \"string\",\n \"sendingServiceProviderCountry\": \"AD\"\n },\n \"oneTimeCode\": \"string\",\n \"recipientKyc\": {\n \"birthCountry\": \"AD\",\n \"contactPhone\": \"string\",\n \"dateOfBirth\": \"2000-11-20\",\n \"emailAddress\": \"string\",\n \"employerName\": \"string\",\n \"gender\": \"m\",\n \"idDocument\": [\n {\n \"idType\": \"passport\",\n \"idNumber\": \"string\",\n \"issueDate\": \"2022-09-28T12:51:19.260+00:00\",\n \"expiryDate\": \"2022-09-28T12:51:19.260+00:00\",\n \"issuer\": \"string\",\n \"issuerPlace\": \"string\",\n \"issuerCountry\": \"AD\",\n \"otherIddescription\": \"string\"\n }\n ],\n \"nationality\": \"AD\",\n \"occupation\": \"string\",\n \"postalAddress\": {\n \"addressLine1\": \"string\",\n \"addressLine2\": \"string\",\n \"addressLine3\": \"string\",\n \"city\": \"string\",\n \"stateProvince\": \"string\",\n \"postalCode\": \"string\",\n \"country\": \"AD\"\n },\n \"subjectName\": {\n \"title\": \"string\",\n \"firstName\": \"string\",\n \"middleName\": \"string\",\n \"lastName\": \"string\",\n \"fullName\": \"string\",\n \"nativeName\": \"string\"\n }\n },\n \"senderKyc\": {\n \"birthCountry\": \"AD\",\n \"contactPhone\": \"string\",\n \"dateOfBirth\": \"2022-09-28T12:51:19.260+00:00\",\n \"emailAddress\": \"string\",\n \"employerName\": \"string\",\n \"gender\": \"m\",\n \"idDocument\": [\n {\n \"idType\": \"passport\",\n \"idNumber\": \"string\",\n \"issueDate\": \"2022-09-28T12:51:19.260+00:00\",\n \"expiryDate\": \"2022-09-28T12:51:19.260+00:00\",\n \"issuer\": \"string\",\n \"issuerPlace\": \"string\",\n \"issuerCountry\": \"AD\",\n \"otherIddescription\": \"string\"\n }\n ],\n \"nationality\": \"AD\",\n \"occupation\": \"string\",\n \"postalAddress\": {\n \"addressLine1\": \"string\",\n \"addressLine2\": \"string\",\n \"addressLine3\": \"string\",\n \"city\": \"string\",\n \"stateProvince\": \"string\",\n \"postalCode\": \"string\",\n \"country\": \"AD\"\n },\n \"subjectName\": {\n \"title\": \"string\",\n \"firstName\": \"string\",\n \"middleName\": \"string\",\n \"lastName\": \"string\",\n \"fullName\": \"string\",\n \"nativeName\": \"string\"\n }\n },\n \"requestingOrganisation\": {\n \"requestingOrganisationIdentifierType\": \"lei\",\n \"requestingOrganisationIdentifier\": \"string\"\n },\n \"servicingIdentity\": \"string\",\n \"requestDate\": \"2022-09-28T12:51:19.260+00:00\",\n \"customData\": [\n {\n \"key\": \"string\",\n \"value\": \"string\"\n }\n ],\n \"metadata\": [\n {\n \"key\": \"string\",\n \"value\": \"string\"\n }\n ],\n \"creditParty\": [\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n }\n ],\n \"debitParty\": [\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555987456\"\n }\n ]\n}" + }, + "url": { + "raw": "{{ChannelGSMAHostName}}/transactions", + "host": [ + "{{ChannelGSMAHostName}}" + ], + "path": [ + "transactions" + ] + }, + "description": "Provided with a valid object representation, this endpoint allows for a new transaction to be created" + }, + "response": [ + { + "name": "Represents an Asynchronous response", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/transactions", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "transactions" + ] + } + }, + "status": "Accepted", + "code": 202, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"notificationMethod\": \"\",\n \"serverCorrelationId\": \"\",\n \"status\": \"\",\n \"pendingReason\": \"\",\n \"objectReference\": \"\",\n \"expiryTime\": \"\",\n \"pollLimit\": \"\",\n \"error\": {\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n }\n}" + }, + { + "name": "Represents an Error Caused by the Violation of a Business Rule", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/transactions", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "transactions" + ] + } + }, + "status": "Bad Request", + "code": 400, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by System Unavailability", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/transactions", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "transactions" + ] + } + }, + "status": "Service Unavailable", + "code": 503, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by a General Server-Side Issue", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/transactions", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "transactions" + ] + } + }, + "status": "Internal Server Error", + "code": 500, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by an Authorisation Failure", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/transactions", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "transactions" + ] + } + }, + "status": "Unauthorized", + "code": 401, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents a Transaction response", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/transactions", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "transactions" + ] + } + }, + "status": "Created", + "code": 201, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"amount\": \"15.21\",\n \"currency\": \"\",\n \"type\": \"\",\n \"transactionReference\": \"\",\n \"transactionStatus\": \"\",\n \"debitParty\": [\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n },\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n }\n ],\n \"creditParty\": [\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n },\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n }\n ],\n \"subType\": \"\",\n \"descriptionText\": \"\",\n \"requestDate\": \"\",\n \"requestingOrganisationTransactionReference\": \"\",\n \"oneTimeCode\": \"\",\n \"geoCode\": \"37.423825,-122.082900\",\n \"senderKyc\": {\n \"nationality\": \"\",\n \"dateOfBirth\": \"2000-11-20\",\n \"occupation\": \"\",\n \"employerName\": \"\",\n \"contactPhone\": \"\",\n \"gender\": \"\",\n \"idDocument\": [\n {\n \"idType\": \"\",\n \"idNumber\": \"\",\n \"issueDate\": \"2018-11-20\",\n \"expiryDate\": \"2018-11-20\",\n \"issuer\": \"\",\n \"issuerPlace\": \"\",\n \"issuerCountry\": \"\",\n \"otherIddescription\": \"\"\n },\n {\n \"idType\": \"\",\n \"idNumber\": \"\",\n \"issueDate\": \"2018-11-20\",\n \"expiryDate\": \"2018-11-20\",\n \"issuer\": \"\",\n \"issuerPlace\": \"\",\n \"issuerCountry\": \"\",\n \"otherIddescription\": \"\"\n }\n ],\n \"postalAddress\": {\n \"country\": \"\",\n \"addressLine1\": \"\",\n \"addressLine2\": \"\",\n \"addressLine3\": \"\",\n \"city\": \"\",\n \"stateProvince\": \"\",\n \"postalCode\": \"\"\n },\n \"subjectName\": {\n \"title\": \"\",\n \"firstName\": \"\",\n \"middleName\": \"\",\n \"lastName\": \"\",\n \"fullName\": \"\",\n \"nativeName\": \"\"\n },\n \"emailAddress\": \"\",\n \"birthCountry\": \"\"\n },\n \"recipientKyc\": {\n \"nationality\": \"\",\n \"dateOfBirth\": \"2000-11-20\",\n \"occupation\": \"\",\n \"employerName\": \"\",\n \"contactPhone\": \"\",\n \"gender\": \"\",\n \"idDocument\": [\n {\n \"idType\": \"\",\n \"idNumber\": \"\",\n \"issueDate\": \"2018-11-20\",\n \"expiryDate\": \"2018-11-20\",\n \"issuer\": \"\",\n \"issuerPlace\": \"\",\n \"issuerCountry\": \"\",\n \"otherIddescription\": \"\"\n },\n {\n \"idType\": \"\",\n \"idNumber\": \"\",\n \"issueDate\": \"2018-11-20\",\n \"expiryDate\": \"2018-11-20\",\n \"issuer\": \"\",\n \"issuerPlace\": \"\",\n \"issuerCountry\": \"\",\n \"otherIddescription\": \"\"\n }\n ],\n \"postalAddress\": {\n \"country\": \"\",\n \"addressLine1\": \"\",\n \"addressLine2\": \"\",\n \"addressLine3\": \"\",\n \"city\": \"\",\n \"stateProvince\": \"\",\n \"postalCode\": \"\"\n },\n \"subjectName\": {\n \"title\": \"\",\n \"firstName\": \"\",\n \"middleName\": \"\",\n \"lastName\": \"\",\n \"fullName\": \"\",\n \"nativeName\": \"\"\n },\n \"emailAddress\": \"\",\n \"birthCountry\": \"\"\n },\n \"originalTransactionReference\": \"\",\n \"servicingIdentity\": \"\",\n \"fees\": [\n {\n \"feeType\": \"\",\n \"feeCurrency\": \"\",\n \"feeAmount\": \"15.21\"\n },\n {\n \"feeType\": \"\",\n \"feeCurrency\": \"\",\n \"feeAmount\": \"15.21\"\n }\n ],\n \"requestingLei\": \"54930084UKLVMY22DS16\",\n \"receivingLei\": \"5493000IBP32UQZ0KL24\",\n \"metadata\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ],\n \"creationDate\": \"\",\n \"modificationDate\": \"\",\n \"dateCreated\": \"\",\n \"dateModified\": \"\",\n \"transactionReceipt\": \"\",\n \"internationalTransferInformation\": {\n \"originCountry\": \"\",\n \"quotationReference\": \"\",\n \"quoteId\": \"\",\n \"receivingCountry\": \"\",\n \"remittancePurpose\": \"\",\n \"relationshipSender\": \"\",\n \"deliveryMethod\": \"\",\n \"senderBlockingReason\": \"\",\n \"recipientBlockingReason\": \"\"\n }\n}" + }, + { + "name": "Represents an Error Caused by a Failure to Identify the Target Resource", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/transactions", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "transactions" + ] + } + }, + "status": "Not Found", + "code": 404, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + } + ] + }, + { + "name": "Create a Transaction", + "protocolProfileBehavior": { + "disabledSystemHeaders": { + "accept": true + } + }, + "request": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API.", + "disabled": true + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + }, + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Accept", + "value": "application/json", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{}" + }, + "url": { + "raw": "{{ChannelGSMAHostName}}/transactions/type/transfer", + "host": [ + "{{ChannelGSMAHostName}}" + ], + "path": [ + "transactions", + "type", + "transfer" + ] + }, + "description": "Provided with a valid object representation, this endpoint allows for a new transaction to be created for a given transaction type passed via the URL." + }, + "response": [ + { + "name": "Represents an Error Caused by a Failure to Identify the Target Resource", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/transactions/type/:transactionType", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "transactions", + "type", + ":transactionType" + ], + "variable": [ + { + "key": "transactionType" + } + ] + } + }, + "status": "Not Found", + "code": 404, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by the Violation of a Business Rule", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/transactions/type/:transactionType", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "transactions", + "type", + ":transactionType" + ], + "variable": [ + { + "key": "transactionType" + } + ] + } + }, + "status": "Bad Request", + "code": 400, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by an Authorisation Failure", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/transactions/type/:transactionType", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "transactions", + "type", + ":transactionType" + ], + "variable": [ + { + "key": "transactionType" + } + ] + } + }, + "status": "Unauthorized", + "code": 401, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents a Transaction response", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/transactions/type/:transactionType", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "transactions", + "type", + ":transactionType" + ], + "variable": [ + { + "key": "transactionType" + } + ] + } + }, + "status": "Created", + "code": 201, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "[\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n },\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n }\n]" + }, + { + "name": "Represents an Error Caused by System Unavailability", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/transactions/type/:transactionType", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "transactions", + "type", + ":transactionType" + ], + "variable": [ + { + "key": "transactionType" + } + ] + } + }, + "status": "Service Unavailable", + "code": 503, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by a General Server-Side Issue", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/transactions/type/:transactionType", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "transactions", + "type", + ":transactionType" + ], + "variable": [ + { + "key": "transactionType" + } + ] + } + }, + "status": "Internal Server Error", + "code": 500, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Asynchronous response", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/transactions/type/:transactionType", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "transactions", + "type", + ":transactionType" + ], + "variable": [ + { + "key": "transactionType" + } + ] + } + }, + "status": "Accepted", + "code": 202, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"notificationMethod\": \"\",\n \"serverCorrelationId\": \"\",\n \"status\": \"\",\n \"pendingReason\": \"\",\n \"objectReference\": \"\",\n \"expiryTime\": \"\",\n \"pollLimit\": \"\",\n \"error\": {\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n }\n}" + } + ] + } + ] + }, + { + "name": "batchtransactions", + "item": [ + { + "name": "{batch Id}", + "item": [ + { + "name": "View A Transaction Batch", + "request": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API.", + "disabled": true + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server.", + "disabled": true + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication", + "disabled": true + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server.", + "disabled": true + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed.", + "disabled": true + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", + "disabled": true + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", + "disabled": true + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App.", + "disabled": true + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header.", + "disabled": true + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header.", + "disabled": true + }, + { + "key": "Accept", + "value": "application/json", + "type": "text" + } + ], + "url": { + "raw": "{{ChannelGSMAHostName}}/batchtransactions/{{batchId}}", + "host": [ + "{{ChannelGSMAHostName}}" + ], + "path": [ + "batchtransactions", + "{{batchId}}" + ] + }, + "description": "This endpoint returns the current status of a batch transaction" + }, + "response": [ + { + "name": "Represents an Error Caused by the Violation of a Business Rule", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/batchtransactions/:batchId", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "batchtransactions", + ":batchId" + ], + "variable": [ + { + "key": "batchId" + } + ] + } + }, + "status": "Bad Request", + "code": 400, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents a Batch Transaction response", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/batchtransactions/:batchId", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "batchtransactions", + ":batchId" + ], + "variable": [ + { + "key": "batchId" + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"approvalDate\": \"\",\n \"batchId\": \"\",\n \"batchStatus\": \"\",\n \"completionDate\": \"\",\n \"creationDate\": \"\",\n \"batchTitle\": \"\",\n \"batchdescription\": \"\",\n \"processingFlag\": \"\",\n \"scheduledStartDate\": \"\",\n \"completedDate\": \"\",\n \"rejectionCount\": \"\",\n \"parsingSuccessCount\": \"\",\n \"completedCount\": \"\"\n}" + }, + { + "name": "Represents an Error Caused by an Authorisation Failure", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/batchtransactions/:batchId", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "batchtransactions", + ":batchId" + ], + "variable": [ + { + "key": "batchId" + } + ] + } + }, + "status": "Unauthorized", + "code": 401, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by a Failure to Identify the Target Resource", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/batchtransactions/:batchId", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "batchtransactions", + ":batchId" + ], + "variable": [ + { + "key": "batchId" + } + ] + } + }, + "status": "Not Found", + "code": 404, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by a General Server-Side Issue", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/batchtransactions/:batchId", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "batchtransactions", + ":batchId" + ], + "variable": [ + { + "key": "batchId" + } + ] + } + }, + "status": "Internal Server Error", + "code": 500, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by System Unavailability", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/batchtransactions/:batchId", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "batchtransactions", + ":batchId" + ], + "variable": [ + { + "key": "batchId" + } + ] + } + }, + "status": "Service Unavailable", + "code": 503, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + } + ] + }, + { + "name": "Update A Transaction Batch", + "request": { + "method": "PATCH", + "header": [ + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID.", + "disabled": true + }, + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API.", + "disabled": true + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server.", + "disabled": true + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication", + "disabled": true + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server.", + "disabled": true + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed.", + "disabled": true + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", + "disabled": true + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", + "disabled": true + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App.", + "disabled": true + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header.", + "disabled": true + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header.", + "disabled": true + }, + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Accept", + "value": "application/json", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "[\n {\n \"op\": \"replace\",\n \"path\": \"string\",\n \"value\": \"string\"\n }\n]" + }, + "url": { + "raw": "{{ChannelGSMAHostName}}/batchtransactions/{{batchId}}", + "host": [ + "{{ChannelGSMAHostName}}" + ], + "path": [ + "batchtransactions", + "{{batchId}}" + ] + }, + "description": "This endpoint updates a specific transaction batch" + }, + "response": [ + { + "name": "Represents an Error Caused by a Failure to Identify the Target Resource", + "originalRequest": { + "method": "PATCH", + "header": [ + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/batchtransactions/:batchId", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "batchtransactions", + ":batchId" + ], + "variable": [ + { + "key": "batchId" + } + ] + } + }, + "status": "Not Found", + "code": 404, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by System Unavailability", + "originalRequest": { + "method": "PATCH", + "header": [ + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/batchtransactions/:batchId", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "batchtransactions", + ":batchId" + ], + "variable": [ + { + "key": "batchId" + } + ] + } + }, + "status": "Service Unavailable", + "code": 503, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "An empty response is returned for a synchronous successful patch.", + "originalRequest": { + "method": "PATCH", + "header": [ + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/batchtransactions/:batchId", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "batchtransactions", + ":batchId" + ], + "variable": [ + { + "key": "batchId" + } + ] + } + }, + "status": "No Content", + "code": 204, + "_postman_previewlanguage": "text", + "header": [ + { + "key": "Content-Type", + "value": "text/plain" + } + ], + "cookie": [], + "body": "" + }, + { + "name": "Represents an Error Caused by a General Server-Side Issue", + "originalRequest": { + "method": "PATCH", + "header": [ + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/batchtransactions/:batchId", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "batchtransactions", + ":batchId" + ], + "variable": [ + { + "key": "batchId" + } + ] + } + }, + "status": "Internal Server Error", + "code": 500, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Asynchronous response", + "originalRequest": { + "method": "PATCH", + "header": [ + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/batchtransactions/:batchId", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "batchtransactions", + ":batchId" + ], + "variable": [ + { + "key": "batchId" + } + ] + } + }, + "status": "Accepted", + "code": 202, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"notificationMethod\": \"\",\n \"serverCorrelationId\": \"\",\n \"status\": \"\",\n \"pendingReason\": \"\",\n \"objectReference\": \"\",\n \"expiryTime\": \"\",\n \"pollLimit\": \"\",\n \"error\": {\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n }\n}" + }, + { + "name": "Represents an Error Caused by the Violation of a Business Rule", + "originalRequest": { + "method": "PATCH", + "header": [ + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/batchtransactions/:batchId", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "batchtransactions", + ":batchId" + ], + "variable": [ + { + "key": "batchId" + } + ] + } + }, + "status": "Bad Request", + "code": 400, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by an Authorisation Failure", + "originalRequest": { + "method": "PATCH", + "header": [ + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/batchtransactions/:batchId", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "batchtransactions", + ":batchId" + ], + "variable": [ + { + "key": "batchId" + } + ] + } + }, + "status": "Unauthorized", + "code": 401, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + } + ] + }, + { + "name": "View Batch Rejections", + "request": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API.", + "disabled": true + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server.", + "disabled": true + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication", + "disabled": true + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server.", + "disabled": true + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed.", + "disabled": true + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", + "disabled": true + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", + "disabled": true + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App.", + "disabled": true + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header.", + "disabled": true + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header.", + "disabled": true + }, + { + "key": "Accept", + "value": "application/json", + "type": "text" + } + ], + "url": { + "raw": "{{ChannelGSMAHostName}}/batchtransactions/{{batchId}}/rejections", + "host": [ + "{{ChannelGSMAHostName}}" + ], + "path": [ + "batchtransactions", + "{{batchId}}", + "rejections" + ], + "query": [ + { + "key": "limit", + "value": "", + "description": "Supports pagination. If this is not supplied, then the server will apply a limit of 50 records returned for each request.", + "disabled": true + }, + { + "key": "offset", + "value": "", + "description": "Supports pagination. This value will indicate the cursor position from where to retrieve the set of records. For example, a limit of 50 and offset of 10 will return records 11 to 60.", + "disabled": true + }, + { + "key": "fromDateTime", + "value": "", + "description": "Indicates the minimum date for which records should be returned.", + "disabled": true + }, + { + "key": "toDateTime", + "value": "", + "description": "Indicates the maximum date for which records should be returned.", + "disabled": true + } + ] + }, + "description": "This endpoint returns rejected transactions for a specific batch\"" + }, + "response": [ + { + "name": "Represents an Error Caused by a General Server-Side Issue", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/batchtransactions/:batchId/rejections?limit=&offset=&fromDateTime=&toDateTime=", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "batchtransactions", + ":batchId", + "rejections" + ], + "query": [ + { + "key": "limit", + "value": "" + }, + { + "key": "offset", + "value": "" + }, + { + "key": "fromDateTime", + "value": "" + }, + { + "key": "toDateTime", + "value": "" + } + ], + "variable": [ + { + "key": "batchId" + } + ] + } + }, + "status": "Internal Server Error", + "code": 500, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by an Authorisation Failure", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/batchtransactions/:batchId/rejections?limit=&offset=&fromDateTime=&toDateTime=", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "batchtransactions", + ":batchId", + "rejections" + ], + "query": [ + { + "key": "limit", + "value": "" + }, + { + "key": "offset", + "value": "" + }, + { + "key": "fromDateTime", + "value": "" + }, + { + "key": "toDateTime", + "value": "" + } + ], + "variable": [ + { + "key": "batchId" + } + ] + } + }, + "status": "Unauthorized", + "code": 401, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by System Unavailability", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/batchtransactions/:batchId/rejections?limit=&offset=&fromDateTime=&toDateTime=", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "batchtransactions", + ":batchId", + "rejections" + ], + "query": [ + { + "key": "limit", + "value": "" + }, + { + "key": "offset", + "value": "" + }, + { + "key": "fromDateTime", + "value": "" + }, + { + "key": "toDateTime", + "value": "" + } + ], + "variable": [ + { + "key": "batchId" + } + ] + } + }, + "status": "Service Unavailable", + "code": 503, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents a Batch Transaction Rejection response", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/batchtransactions/:batchId/rejections?limit=&offset=&fromDateTime=&toDateTime=", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "batchtransactions", + ":batchId", + "rejections" + ], + "query": [ + { + "key": "limit", + "value": "" + }, + { + "key": "offset", + "value": "" + }, + { + "key": "fromDateTime", + "value": "" + }, + { + "key": "toDateTime", + "value": "" + } + ], + "variable": [ + { + "key": "batchId" + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "X-Records-Available-Count", + "value": "", + "description": "Integer containing number of records that are available to be returned." + }, + { + "key": "X-Records-Returned-Count", + "value": "", + "description": "Integer containing number of records that are returned." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "[\n {\n \"creditParty\": [\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n },\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n }\n ],\n \"debitParty\": [\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n },\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n }\n ],\n \"rejectionDate\": \"\",\n \"rejectionReason\": \"\",\n \"transactionReference\": \"\",\n \"dateRejected\": \"\",\n \"requestingOrganisationTransactionReference\": \"\"\n },\n {\n \"creditParty\": [\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n },\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n }\n ],\n \"debitParty\": [\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n },\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n }\n ],\n \"rejectionDate\": \"\",\n \"rejectionReason\": \"\",\n \"transactionReference\": \"\",\n \"dateRejected\": \"\",\n \"requestingOrganisationTransactionReference\": \"\"\n }\n]" + }, + { + "name": "Represents an Error Caused by a Failure to Identify the Target Resource", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/batchtransactions/:batchId/rejections?limit=&offset=&fromDateTime=&toDateTime=", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "batchtransactions", + ":batchId", + "rejections" + ], + "query": [ + { + "key": "limit", + "value": "" + }, + { + "key": "offset", + "value": "" + }, + { + "key": "fromDateTime", + "value": "" + }, + { + "key": "toDateTime", + "value": "" + } + ], + "variable": [ + { + "key": "batchId" + } + ] + } + }, + "status": "Not Found", + "code": 404, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by the Violation of a Business Rule", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/batchtransactions/:batchId/rejections?limit=&offset=&fromDateTime=&toDateTime=", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "batchtransactions", + ":batchId", + "rejections" + ], + "query": [ + { + "key": "limit", + "value": "" + }, + { + "key": "offset", + "value": "" + }, + { + "key": "fromDateTime", + "value": "" + }, + { + "key": "toDateTime", + "value": "" + } + ], + "variable": [ + { + "key": "batchId" + } + ] + } + }, + "status": "Bad Request", + "code": 400, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + } + ] + }, + { + "name": "View Batch Completions", + "request": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API.", + "disabled": true + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server.", + "disabled": true + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication", + "disabled": true + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server.", + "disabled": true + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed.", + "disabled": true + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", + "disabled": true + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", + "disabled": true + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App.", + "disabled": true + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header.", + "disabled": true + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header.", + "disabled": true + }, + { + "key": "Accept", + "value": "application/json", + "type": "text" + } + ], + "url": { + "raw": "{{ChannelGSMAHostName}}/batchtransactions/{{batchId}}/completions", + "host": [ + "{{ChannelGSMAHostName}}" + ], + "path": [ + "batchtransactions", + "{{batchId}}", + "completions" + ], + "query": [ + { + "key": "limit", + "value": "", + "description": "Supports pagination. If this is not supplied, then the server will apply a limit of 50 records returned for each request.", + "disabled": true + }, + { + "key": "offset", + "value": "", + "description": "Supports pagination. This value will indicate the cursor position from where to retrieve the set of records. For example, a limit of 50 and offset of 10 will return records 11 to 60.", + "disabled": true + }, + { + "key": "fromDateTime", + "value": "", + "description": "Indicates the minimum date for which records should be returned.", + "disabled": true + }, + { + "key": "toDateTime", + "value": "", + "description": "Indicates the maximum date for which records should be returned.", + "disabled": true + } + ] + }, + "description": "This endpoint returns completed transactions for a specific batch" + }, + "response": [ + { + "name": "Represents an Error Caused by an Authorisation Failure", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/batchtransactions/:batchId/completions?limit=&offset=&fromDateTime=&toDateTime=", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "batchtransactions", + ":batchId", + "completions" + ], + "query": [ + { + "key": "limit", + "value": "" + }, + { + "key": "offset", + "value": "" + }, + { + "key": "fromDateTime", + "value": "" + }, + { + "key": "toDateTime", + "value": "" + } + ], + "variable": [ + { + "key": "batchId" + } + ] + } + }, + "status": "Unauthorized", + "code": 401, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by the Violation of a Business Rule", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/batchtransactions/:batchId/completions?limit=&offset=&fromDateTime=&toDateTime=", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "batchtransactions", + ":batchId", + "completions" + ], + "query": [ + { + "key": "limit", + "value": "" + }, + { + "key": "offset", + "value": "" + }, + { + "key": "fromDateTime", + "value": "" + }, + { + "key": "toDateTime", + "value": "" + } + ], + "variable": [ + { + "key": "batchId" + } + ] + } + }, + "status": "Bad Request", + "code": 400, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by a Failure to Identify the Target Resource", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/batchtransactions/:batchId/completions?limit=&offset=&fromDateTime=&toDateTime=", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "batchtransactions", + ":batchId", + "completions" + ], + "query": [ + { + "key": "limit", + "value": "" + }, + { + "key": "offset", + "value": "" + }, + { + "key": "fromDateTime", + "value": "" + }, + { + "key": "toDateTime", + "value": "" + } + ], + "variable": [ + { + "key": "batchId" + } + ] + } + }, + "status": "Not Found", + "code": 404, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represent a list of Batch Completions", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/batchtransactions/:batchId/completions?limit=&offset=&fromDateTime=&toDateTime=", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "batchtransactions", + ":batchId", + "completions" + ], + "query": [ + { + "key": "limit", + "value": "" + }, + { + "key": "offset", + "value": "" + }, + { + "key": "fromDateTime", + "value": "" + }, + { + "key": "toDateTime", + "value": "" + } + ], + "variable": [ + { + "key": "batchId" + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "X-Records-Available-Count", + "value": "", + "description": "Integer containing number of records that are available to be returned." + }, + { + "key": "X-Records-Returned-Count", + "value": "", + "description": "Integer containing number of records that are returned." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "[\n {\n \"completionDate\": \"\",\n \"creditParty\": [\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n },\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n }\n ],\n \"debitParty\": [\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n },\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n }\n ],\n \"link\": \"\",\n \"transactionReference\": \"\",\n \"completedDate\": \"\",\n \"requestingOrganisationTransactionReference\": \"\"\n },\n {\n \"completionDate\": \"\",\n \"creditParty\": [\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n },\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n }\n ],\n \"debitParty\": [\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n },\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n }\n ],\n \"link\": \"\",\n \"transactionReference\": \"\",\n \"completedDate\": \"\",\n \"requestingOrganisationTransactionReference\": \"\"\n }\n]" + }, + { + "name": "Represents an Error Caused by System Unavailability", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/batchtransactions/:batchId/completions?limit=&offset=&fromDateTime=&toDateTime=", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "batchtransactions", + ":batchId", + "completions" + ], + "query": [ + { + "key": "limit", + "value": "" + }, + { + "key": "offset", + "value": "" + }, + { + "key": "fromDateTime", + "value": "" + }, + { + "key": "toDateTime", + "value": "" + } + ], + "variable": [ + { + "key": "batchId" + } + ] + } + }, + "status": "Service Unavailable", + "code": 503, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by a General Server-Side Issue", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/batchtransactions/:batchId/completions?limit=&offset=&fromDateTime=&toDateTime=", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "batchtransactions", + ":batchId", + "completions" + ], + "query": [ + { + "key": "limit", + "value": "" + }, + { + "key": "offset", + "value": "" + }, + { + "key": "fromDateTime", + "value": "" + }, + { + "key": "toDateTime", + "value": "" + } + ], + "variable": [ + { + "key": "batchId" + } + ] + } + }, + "status": "Internal Server Error", + "code": 500, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + } + ] + } + ] + }, + { + "name": "Create A Transaction Batch", + "request": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API.", + "disabled": true + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID.", + "disabled": true + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server.", + "disabled": true + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication", + "disabled": true + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server.", + "disabled": true + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed.", + "disabled": true + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", + "disabled": true + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", + "disabled": true + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App.", + "disabled": true + }, + { + "key": "X-Callback-URL", + "value": "", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT.", + "disabled": true + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header.", + "disabled": true + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header.", + "disabled": true + }, + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Accept", + "value": "application/json", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"batchStatus\": \"created\",\n \"transactions\": [\n {\n \"requestingOrganisationTransactionReference\": \"string\",\n \"originalTransactionReference\": \"string\",\n \"creditParty\": [\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n }\n ],\n \"debitParty\": [\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n }\n ],\n \"type\": \"billpay\",\n \"subType\": \"string\",\n \"amount\": \"15.21\",\n \"currency\": \"AED\",\n \"descriptionText\": \"string\",\n \"fees\": [\n {\n \"feeType\": \"string\",\n \"feeAmount\": \"15.21\",\n \"feeCurrency\": \"AED\"\n }\n ],\n \"geoCode\": \"37.423825,-122.082900\",\n \"internationalTransferInformation\": {\n \"quotationReference\": \"string\",\n \"quoteId\": \"string\",\n \"originCountry\": \"AD\",\n \"deliveryMethod\": \"directtoaccount\",\n \"receivingCountry\": \"AD\",\n \"relationshipSender\": \"string\",\n \"remittancePurpose\": \"string\",\n \"sendingServiceProviderCountry\": \"AD\"\n },\n \"oneTimeCode\": \"string\",\n \"recipientKyc\": {\n \"birthCountry\": \"AD\",\n \"contactPhone\": \"string\",\n \"dateOfBirth\": \"2000-11-20\",\n \"emailAddress\": \"string\",\n \"employerName\": \"string\",\n \"gender\": \"m\",\n \"idDocument\": [\n {\n \"idType\": \"passport\",\n \"idNumber\": \"string\",\n \"issueDate\": \"2018-11-20\",\n \"expiryDate\": \"2018-11-20\",\n \"issuer\": \"string\",\n \"issuerPlace\": \"string\",\n \"issuerCountry\": \"AD\",\n \"otherIddescription\": \"string\"\n }\n ],\n \"nationality\": \"AD\",\n \"occupation\": \"string\",\n \"postalAddress\": {\n \"addressLine1\": \"string\",\n \"addressLine2\": \"string\",\n \"addressLine3\": \"string\",\n \"city\": \"string\",\n \"stateProvince\": \"string\",\n \"postalCode\": \"string\",\n \"country\": \"AD\"\n },\n \"subjectName\": {\n \"title\": \"string\",\n \"firstName\": \"string\",\n \"middleName\": \"string\",\n \"lastName\": \"string\",\n \"fullName\": \"string\",\n \"nativeName\": \"string\"\n }\n },\n \"senderKyc\": {\n \"birthCountry\": \"AD\",\n \"contactPhone\": \"string\",\n \"dateOfBirth\": \"2000-11-20\",\n \"emailAddress\": \"string\",\n \"employerName\": \"string\",\n \"gender\": \"m\",\n \"idDocument\": [\n {\n \"idType\": \"passport\",\n \"idNumber\": \"string\",\n \"issueDate\": \"2018-11-20\",\n \"expiryDate\": \"2018-11-20\",\n \"issuer\": \"string\",\n \"issuerPlace\": \"string\",\n \"issuerCountry\": \"AD\",\n \"otherIddescription\": \"string\"\n }\n ],\n \"nationality\": \"AD\",\n \"occupation\": \"string\",\n \"postalAddress\": {\n \"addressLine1\": \"string\",\n \"addressLine2\": \"string\",\n \"addressLine3\": \"string\",\n \"city\": \"string\",\n \"stateProvince\": \"string\",\n \"postalCode\": \"string\",\n \"country\": \"AD\"\n },\n \"subjectName\": {\n \"title\": \"string\",\n \"firstName\": \"string\",\n \"middleName\": \"string\",\n \"lastName\": \"string\",\n \"fullName\": \"string\",\n \"nativeName\": \"string\"\n }\n },\n \"requestingOrganisation\": {\n \"requestingOrganisationIdentifierType\": \"lei\",\n \"requestingOrganisationIdentifier\": \"string\"\n },\n \"servicingIdentity\": \"string\",\n \"requestDate\": \"2022-09-29T00:32:25.599Z\",\n \"customData\": [\n {\n \"key\": \"string\",\n \"value\": \"string\"\n }\n ],\n \"metadata\": [\n {\n \"key\": \"string\",\n \"value\": \"string\"\n }\n ]\n }\n ],\n \"batchTitle\": \"string\",\n \"batchdescription\": \"string\",\n \"requestingOrganisation\": {\n \"requestingOrganisationIdentifierType\": \"lei\",\n \"requestingOrganisationIdentifier\": \"string\"\n },\n \"scheduledStartDate\": \"2022-09-29T00:32:25.599Z\",\n \"modificationDate\": \"2022-09-29T00:32:25.599Z\",\n \"requestDate\": \"2022-09-29T00:32:25.599Z\",\n \"customData\": [\n {\n \"key\": \"string\",\n \"value\": \"string\"\n }\n ]\n}" + }, + "url": { + "raw": "{{ChannelGSMAHostName}}/batchtransactions", + "host": [ + "{{ChannelGSMAHostName}}" + ], + "path": [ + "batchtransactions" + ] + }, + "description": "Provided with a valid object representation, this endpoint allows for a new transaction batch to be created" + }, + "response": [ + { + "name": "Represents an Error Caused by a General Server-Side Issue", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/batchtransactions", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "batchtransactions" + ] + } + }, + "status": "Internal Server Error", + "code": 500, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by the Violation of a Business Rule", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/batchtransactions", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "batchtransactions" + ] + } + }, + "status": "Bad Request", + "code": 400, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by a Failure to Identify the Target Resource", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/batchtransactions", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "batchtransactions" + ] + } + }, + "status": "Not Found", + "code": 404, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by an Authorisation Failure", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/batchtransactions", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "batchtransactions" + ] + } + }, + "status": "Unauthorized", + "code": 401, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by System Unavailability", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/batchtransactions", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "batchtransactions" + ] + } + }, + "status": "Service Unavailable", + "code": 503, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Asynchronous response", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/batchtransactions", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "batchtransactions" + ] + } + }, + "status": "Accepted", + "code": 202, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"notificationMethod\": \"\",\n \"serverCorrelationId\": \"\",\n \"status\": \"\",\n \"pendingReason\": \"\",\n \"objectReference\": \"\",\n \"expiryTime\": \"\",\n \"pollLimit\": \"\",\n \"error\": {\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n }\n}" + } + ] + } + ] + }, + { + "name": "accounts", + "item": [ + { + "name": "{account Id}", + "item": [ + { + "name": "bills", + "item": [ + { + "name": "View Account Bills", + "request": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API.", + "disabled": true + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server.", + "disabled": true + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication", + "disabled": true + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server.", + "disabled": true + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed.", + "disabled": true + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", + "disabled": true + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", + "disabled": true + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App.", + "disabled": true + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header.", + "disabled": true + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header.", + "disabled": true + }, + { + "key": "Accept", + "value": "application/json", + "type": "text" + } + ], + "url": { + "raw": "{{ChannelGSMAHostName}}/accounts/{{accountId}}/bills", + "host": [ + "{{ChannelGSMAHostName}}" + ], + "path": [ + "accounts", + "{{accountId}}", + "bills" + ] + }, + "description": "This endpoint returns bills linked to an account" + }, + "response": [ + { + "name": "Represent a list of Bills", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/bills", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "bills" + ], + "variable": [ + { + "key": "accountId" + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "[\n {\n \"currency\": \"\",\n \"amountDue\": \"15.21\",\n \"dueDate\": \"2018-11-20\",\n \"billReference\": \"\",\n \"minimumAmountDue\": \"15.21\",\n \"billdescription\": \"\",\n \"billStatus\": \"\",\n \"metadata\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n },\n {\n \"currency\": \"\",\n \"amountDue\": \"15.21\",\n \"dueDate\": \"2018-11-20\",\n \"billReference\": \"\",\n \"minimumAmountDue\": \"15.21\",\n \"billdescription\": \"\",\n \"billStatus\": \"\",\n \"metadata\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n }\n]" + }, + { + "name": "Represents an Error Caused by System Unavailability", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/bills", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "bills" + ], + "variable": [ + { + "key": "accountId" + } + ] + } + }, + "status": "Service Unavailable", + "code": 503, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by the Violation of a Business Rule", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/bills", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "bills" + ], + "variable": [ + { + "key": "accountId" + } + ] + } + }, + "status": "Bad Request", + "code": 400, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by a General Server-Side Issue", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/bills", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "bills" + ], + "variable": [ + { + "key": "accountId" + } + ] + } + }, + "status": "Internal Server Error", + "code": 500, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by an Authorisation Failure", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/bills", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "bills" + ], + "variable": [ + { + "key": "accountId" + } + ] + } + }, + "status": "Unauthorized", + "code": 401, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by a Failure to Identify the Target Resource", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/bills", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "bills" + ], + "variable": [ + { + "key": "accountId" + } + ] + } + }, + "status": "Not Found", + "code": 404, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + } + ] + }, + { + "name": "Create A Bill Payment", + "request": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API.", + "disabled": true + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID.", + "disabled": true + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server.", + "disabled": true + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication", + "disabled": true + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server.", + "disabled": true + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed.", + "disabled": true + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", + "disabled": true + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", + "disabled": true + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App.", + "disabled": true + }, + { + "key": "X-Callback-URL", + "value": "", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT.", + "disabled": true + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header.", + "disabled": true + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header.", + "disabled": true + }, + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Accept", + "value": "application/json", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"serviceProviderPaymentReference\": \"string\",\n \"requestingOrganisationTransactionReference\": \"string\",\n \"paymentType\": \"partialpayment\",\n \"amountPaid\": \"15.21\",\n \"currency\": \"AED\",\n \"customerReference\": \"string\",\n \"requestingOrganisation\": \"string\",\n \"supplementaryBillReferenceDetails\": [\n {\n \"paymentReferenceType\": \"string\",\n \"paymentReferenceValue\": \"string\"\n }\n ],\n \"requestDate\": \"2022-09-28T17:58:01.111Z\",\n \"customData\": [\n {\n \"key\": \"string\",\n \"value\": \"string\"\n }\n ],\n \"metadata\": [\n {\n \"key\": \"string\",\n \"value\": \"string\"\n }\n ],\n \"paidAmount\": \"15.21\"\n}" + }, + "url": { + "raw": "{{ChannelGSMAHostName}}/accounts/{{accountId}}/bills/{{billReference}}/payments", + "host": [ + "{{ChannelGSMAHostName}}" + ], + "path": [ + "accounts", + "{{accountId}}", + "bills", + "{{billReference}}", + "payments" + ] + }, + "description": "Provided with a valid object representation, this endpoint allows for a new bill payment to be created for a specific account\"" + }, + "response": [ + { + "name": "Represents an Error Caused by System Unavailability", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/bills/:billReference/payments", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "bills", + ":billReference", + "payments" + ], + "variable": [ + { + "key": "accountId" + }, + { + "key": "billReference" + } + ] + } + }, + "status": "Service Unavailable", + "code": 503, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by a Failure to Identify the Target Resource", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/bills/:billReference/payments", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "bills", + ":billReference", + "payments" + ], + "variable": [ + { + "key": "accountId" + }, + { + "key": "billReference" + } + ] + } + }, + "status": "Not Found", + "code": 404, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by a General Server-Side Issue", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/bills/:billReference/payments", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "bills", + ":billReference", + "payments" + ], + "variable": [ + { + "key": "accountId" + }, + { + "key": "billReference" + } + ] + } + }, + "status": "Internal Server Error", + "code": 500, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by an Authorisation Failure", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/bills/:billReference/payments", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "bills", + ":billReference", + "payments" + ], + "variable": [ + { + "key": "accountId" + }, + { + "key": "billReference" + } + ] + } + }, + "status": "Unauthorized", + "code": 401, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by the Violation of a Business Rule", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/bills/:billReference/payments", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "bills", + ":billReference", + "payments" + ], + "variable": [ + { + "key": "accountId" + }, + { + "key": "billReference" + } + ] + } + }, + "status": "Bad Request", + "code": 400, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents a Bill Payment response", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/bills/:billReference/payments", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "bills", + ":billReference", + "payments" + ], + "variable": [ + { + "key": "accountId" + }, + { + "key": "billReference" + } + ] + } + }, + "status": "Created", + "code": 201, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"currency\": \"\",\n \"amountPaid\": \"15.21\",\n \"billPaymentStatus\": \"\",\n \"paidAmount\": \"15.21\",\n \"serviceProviderPaymentReference\": \"\",\n \"requestingOrganisation\": \"\",\n \"requestingOrganisationTransactionReference\": \"\",\n \"customerReference\": \"\",\n \"paymentType\": \"\",\n \"serviceProviderComment\": \"\",\n \"serviceProviderNotification\": \"\",\n \"supplementaryBillReferenceDetails\": [\n {\n \"paymentReferenceType\": \"\",\n \"paymentReferenceValue\": \"\"\n },\n {\n \"paymentReferenceType\": \"\",\n \"paymentReferenceValue\": \"\"\n }\n ],\n \"metadata\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Asynchronous response", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/bills/:billReference/payments", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "bills", + ":billReference", + "payments" + ], + "variable": [ + { + "key": "accountId" + }, + { + "key": "billReference" + } + ] + } + }, + "status": "Accepted", + "code": 202, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"notificationMethod\": \"\",\n \"serverCorrelationId\": \"\",\n \"status\": \"\",\n \"pendingReason\": \"\",\n \"objectReference\": \"\",\n \"expiryTime\": \"\",\n \"pollLimit\": \"\",\n \"error\": {\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n }\n}" + } + ] + } + ] + }, + { + "name": "debitmandates", + "item": [ + { + "name": "{debit Mandate Reference}", + "item": [ + { + "name": "View A Debit Mandate", + "request": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API.", + "disabled": true + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + }, + { + "key": "Accept", + "value": "application/json", + "type": "text" + } + ], + "url": { + "raw": "{{ChannelGSMAHostName}}/accounts/{{accountId}}/debitmandates/{{debitMandateReference}}", + "host": [ + "{{ChannelGSMAHostName}}" + ], + "path": [ + "accounts", + "{{accountId}}", + "debitmandates", + "{{debitMandateReference}}" + ] + }, + "description": "This endpoint returns a specific debit mandate linked to an account" + }, + "response": [ + { + "name": "Represents an Error Caused by System Unavailability", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/debitmandates/:debitMandateReference", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "debitmandates", + ":debitMandateReference" + ], + "variable": [ + { + "key": "accountId" + }, + { + "key": "debitMandateReference" + } + ] + } + }, + "status": "Service Unavailable", + "code": 503, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents a Debit Mandate response", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/debitmandates/:debitMandateReference", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "debitmandates", + ":debitMandateReference" + ], + "variable": [ + { + "key": "accountId" + }, + { + "key": "debitMandateReference" + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"mandateReference\": \"\",\n \"currency\": \"\",\n \"amountLimit\": \"15.21\",\n \"startDate\": \"2018-11-20\",\n \"endDate\": \"2018-11-20\",\n \"numberOfPayments\": \"\",\n \"frequencyType\": \"\",\n \"mandateStatus\": \"\",\n \"requestDate\": \"\",\n \"creationDate\": \"\",\n \"modificationDate\": \"\",\n \"dateCreated\": \"\",\n \"dateModified\": \"\"\n}" + }, + { + "name": "Represents an Error Caused by the Violation of a Business Rule", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/debitmandates/:debitMandateReference", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "debitmandates", + ":debitMandateReference" + ], + "variable": [ + { + "key": "accountId" + }, + { + "key": "debitMandateReference" + } + ] + } + }, + "status": "Bad Request", + "code": 400, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by an Authorisation Failure", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/debitmandates/:debitMandateReference", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "debitmandates", + ":debitMandateReference" + ], + "variable": [ + { + "key": "accountId" + }, + { + "key": "debitMandateReference" + } + ] + } + }, + "status": "Unauthorized", + "code": 401, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by a General Server-Side Issue", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/debitmandates/:debitMandateReference", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "debitmandates", + ":debitMandateReference" + ], + "variable": [ + { + "key": "accountId" + }, + { + "key": "debitMandateReference" + } + ] + } + }, + "status": "Internal Server Error", + "code": 500, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by a Failure to Identify the Target Resource", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/debitmandates/:debitMandateReference", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "debitmandates", + ":debitMandateReference" + ], + "variable": [ + { + "key": "accountId" + }, + { + "key": "debitMandateReference" + } + ] + } + }, + "status": "Not Found", + "code": 404, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + } + ] + }, + { + "name": "Update A Debit Mandate", + "request": { + "method": "PATCH", + "header": [ + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API.", + "disabled": true + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + }, + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Accept", + "value": "application/json", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "[\n {\n \"op\": \"replace\",\n \"path\": \"string\",\n \"value\": \"string\"\n }\n]" + }, + "url": { + "raw": "{{ChannelGSMAHostName}}/accounts/{{accountId}}/debitmandates/{{debitMandateReference}}", + "host": [ + "{{ChannelGSMAHostName}}" + ], + "path": [ + "accounts", + "{{accountId}}", + "debitmandates", + "{{debitMandateReference}}" + ] + }, + "description": "This endpoint updates a specific debit mandate linked to an account" + }, + "response": [ + { + "name": "Represents an Error Caused by a General Server-Side Issue", + "originalRequest": { + "method": "PATCH", + "header": [ + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/debitmandates/:debitMandateReference", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "debitmandates", + ":debitMandateReference" + ], + "variable": [ + { + "key": "accountId" + }, + { + "key": "debitMandateReference" + } + ] + } + }, + "status": "Internal Server Error", + "code": 500, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "An empty response is returned for a synchronous successful patch.", + "originalRequest": { + "method": "PATCH", + "header": [ + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/debitmandates/:debitMandateReference", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "debitmandates", + ":debitMandateReference" + ], + "variable": [ + { + "key": "accountId" + }, + { + "key": "debitMandateReference" + } + ] + } + }, + "status": "No Content", + "code": 204, + "_postman_previewlanguage": "text", + "header": [ + { + "key": "Content-Type", + "value": "text/plain" + } + ], + "cookie": [], + "body": "" + }, + { + "name": "Represents an Error Caused by System Unavailability", + "originalRequest": { + "method": "PATCH", + "header": [ + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/debitmandates/:debitMandateReference", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "debitmandates", + ":debitMandateReference" + ], + "variable": [ + { + "key": "accountId" + }, + { + "key": "debitMandateReference" + } + ] + } + }, + "status": "Service Unavailable", + "code": 503, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by the Violation of a Business Rule", + "originalRequest": { + "method": "PATCH", + "header": [ + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/debitmandates/:debitMandateReference", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "debitmandates", + ":debitMandateReference" + ], + "variable": [ + { + "key": "accountId" + }, + { + "key": "debitMandateReference" + } + ] + } + }, + "status": "Bad Request", + "code": 400, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by a Failure to Identify the Target Resource", + "originalRequest": { + "method": "PATCH", + "header": [ + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/debitmandates/:debitMandateReference", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "debitmandates", + ":debitMandateReference" + ], + "variable": [ + { + "key": "accountId" + }, + { + "key": "debitMandateReference" + } + ] + } + }, + "status": "Not Found", + "code": 404, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by an Authorisation Failure", + "originalRequest": { + "method": "PATCH", + "header": [ + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/debitmandates/:debitMandateReference", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "debitmandates", + ":debitMandateReference" + ], + "variable": [ + { + "key": "accountId" + }, + { + "key": "debitMandateReference" + } + ] + } + }, + "status": "Unauthorized", + "code": 401, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Asynchronous response", + "originalRequest": { + "method": "PATCH", + "header": [ + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/debitmandates/:debitMandateReference", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "debitmandates", + ":debitMandateReference" + ], + "variable": [ + { + "key": "accountId" + }, + { + "key": "debitMandateReference" + } + ] + } + }, + "status": "Accepted", + "code": 202, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"notificationMethod\": \"\",\n \"serverCorrelationId\": \"\",\n \"status\": \"\",\n \"pendingReason\": \"\",\n \"objectReference\": \"\",\n \"expiryTime\": \"\",\n \"pollLimit\": \"\",\n \"error\": {\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n }\n}" + } + ] + } + ] + }, + { + "name": "Create A Debit Mandate", + "request": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API.", + "disabled": true + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + }, + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Accept", + "value": "application/json", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"payee\": [\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n }\n ],\n \"mandateStatus\": \"active\",\n \"amountLimit\": \"string\",\n \"currency\": \"AED\",\n \"startDate\": \"2018-11-20\",\n \"endDate\": \"2018-11-20\",\n \"frequencyType\": \"weekly\",\n \"numberOfPayments\": 0,\n \"requestingOrganisation\": {\n \"requestingOrganisationIdentifierType\": \"lei\",\n \"requestingOrganisationIdentifier\": \"string\"\n },\n \"requestDate\": \"2022-09-29T07:29:08.821Z\",\n \"customData\": [\n {\n \"key\": \"string\",\n \"value\": \"string\"\n }\n ]\n}" + }, + "url": { + "raw": "{{ChannelGSMAHostName}}/accounts/{{accountId}}/debitmandates", + "host": [ + "{{ChannelGSMAHostName}}" + ], + "path": [ + "accounts", + "{{accountId}}", + "debitmandates" + ] + }, + "description": "Provided with a valid object representation, this endpoint allows for a new debit mandate to be created for a specific account." + }, + "response": [ + { + "name": "Represents an Error Caused by a General Server-Side Issue", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/debitmandates", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "debitmandates" + ], + "variable": [ + { + "key": "accountId" + } + ] + } + }, + "status": "Internal Server Error", + "code": 500, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by System Unavailability", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/debitmandates", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "debitmandates" + ], + "variable": [ + { + "key": "accountId" + } + ] + } + }, + "status": "Service Unavailable", + "code": 503, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Asynchronous response", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/debitmandates", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "debitmandates" + ], + "variable": [ + { + "key": "accountId" + } + ] + } + }, + "status": "Accepted", + "code": 202, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"notificationMethod\": \"\",\n \"serverCorrelationId\": \"\",\n \"status\": \"\",\n \"pendingReason\": \"\",\n \"objectReference\": \"\",\n \"expiryTime\": \"\",\n \"pollLimit\": \"\",\n \"error\": {\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n }\n}" + }, + { + "name": "Represents an Error Caused by a Failure to Identify the Target Resource", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/debitmandates", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "debitmandates" + ], + "variable": [ + { + "key": "accountId" + } + ] + } + }, + "status": "Not Found", + "code": 404, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by an Authorisation Failure", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/debitmandates", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "debitmandates" + ], + "variable": [ + { + "key": "accountId" + } + ] + } + }, + "status": "Unauthorized", + "code": 401, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents a Debit Mandate response", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/debitmandates", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "debitmandates" + ], + "variable": [ + { + "key": "accountId" + } + ] + } + }, + "status": "Created", + "code": 201, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"mandateReference\": \"\",\n \"currency\": \"\",\n \"amountLimit\": \"15.21\",\n \"startDate\": \"2018-11-20\",\n \"endDate\": \"2018-11-20\",\n \"numberOfPayments\": \"\",\n \"frequencyType\": \"\",\n \"mandateStatus\": \"\",\n \"requestDate\": \"\",\n \"creationDate\": \"\",\n \"modificationDate\": \"\",\n \"dateCreated\": \"\",\n \"dateModified\": \"\"\n}" + }, + { + "name": "Represents an Error Caused by the Violation of a Business Rule", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/debitmandates", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "debitmandates" + ], + "variable": [ + { + "key": "accountId" + } + ] + } + }, + "status": "Bad Request", + "code": 400, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + } + ] + } + ] + }, + { + "name": "links", + "item": [ + { + "name": "{link Reference}", + "item": [ + { + "name": "View A Link", + "request": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API.", + "disabled": true + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + }, + { + "key": "Accept", + "value": "application/json", + "type": "text" + } + ], + "url": { + "raw": "{{ChannelGSMAHostName}}/accounts/{{accountId}}/links/{{linkReference}}", + "host": [ + "{{ChannelGSMAHostName}}" + ], + "path": [ + "accounts", + "{{accountId}}", + "links", + "{{linkReference}}" + ] + }, + "description": "This endpoint returns a specific link" + }, + "response": [ + { + "name": "Represents an Error Caused by a Failure to Identify the Target Resource", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/links/:linkReference", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "links", + ":linkReference" + ], + "variable": [ + { + "key": "accountId" + }, + { + "key": "linkReference" + } + ] + } + }, + "status": "Not Found", + "code": 404, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by the Violation of a Business Rule", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/links/:linkReference", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "links", + ":linkReference" + ], + "variable": [ + { + "key": "accountId" + }, + { + "key": "linkReference" + } + ] + } + }, + "status": "Bad Request", + "code": 400, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents a Link response\"", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/links/:linkReference", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "links", + ":linkReference" + ], + "variable": [ + { + "key": "accountId" + }, + { + "key": "linkReference" + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"linkReference\": \"\",\n \"sourceAccountIdentifiers\": [\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n },\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n }\n ],\n \"status\": \"\",\n \"mode\": \"\"\n}" + }, + { + "name": "Represents an Error Caused by a General Server-Side Issue", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/links/:linkReference", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "links", + ":linkReference" + ], + "variable": [ + { + "key": "accountId" + }, + { + "key": "linkReference" + } + ] + } + }, + "status": "Internal Server Error", + "code": 500, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by an Authorisation Failure", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/links/:linkReference", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "links", + ":linkReference" + ], + "variable": [ + { + "key": "accountId" + }, + { + "key": "linkReference" + } + ] + } + }, + "status": "Unauthorized", + "code": 401, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by System Unavailability", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/links/:linkReference", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "links", + ":linkReference" + ], + "variable": [ + { + "key": "accountId" + }, + { + "key": "linkReference" + } + ] + } + }, + "status": "Service Unavailable", + "code": 503, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + } + ] + }, + { + "name": "Update A Link", + "request": { + "method": "PATCH", + "header": [ + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API.", + "disabled": true + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + }, + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Accept", + "value": "application/json", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "[\n {\n \"op\": \"replace\",\n \"path\": \"string\",\n \"value\": \"string\"\n }\n]" + }, + "url": { + "raw": "{{ChannelGSMAHostName}}/accounts/{{accountId}}/links/{{linkReference}}", + "host": [ + "{{ChannelGSMAHostName}}" + ], + "path": [ + "accounts", + "{{accountId}}", + "links", + "{{linkReference}}" + ] + }, + "description": "This endpoint updates a specific link" + }, + "response": [ + { + "name": "An empty response is returned for a synchronous successful patch.", + "originalRequest": { + "method": "PATCH", + "header": [ + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/links/:linkReference", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "links", + ":linkReference" + ], + "variable": [ + { + "key": "accountId" + }, + { + "key": "linkReference" + } + ] + } + }, + "status": "No Content", + "code": 204, + "_postman_previewlanguage": "text", + "header": [ + { + "key": "Content-Type", + "value": "text/plain" + } + ], + "cookie": [], + "body": "" + }, + { + "name": "Represents an Error Caused by an Authorisation Failure", + "originalRequest": { + "method": "PATCH", + "header": [ + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/links/:linkReference", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "links", + ":linkReference" + ], + "variable": [ + { + "key": "accountId" + }, + { + "key": "linkReference" + } + ] + } + }, + "status": "Unauthorized", + "code": 401, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by a Failure to Identify the Target Resource", + "originalRequest": { + "method": "PATCH", + "header": [ + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/links/:linkReference", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "links", + ":linkReference" + ], + "variable": [ + { + "key": "accountId" + }, + { + "key": "linkReference" + } + ] + } + }, + "status": "Not Found", + "code": 404, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by System Unavailability", + "originalRequest": { + "method": "PATCH", + "header": [ + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/links/:linkReference", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "links", + ":linkReference" + ], + "variable": [ + { + "key": "accountId" + }, + { + "key": "linkReference" + } + ] + } + }, + "status": "Service Unavailable", + "code": 503, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Asynchronous response", + "originalRequest": { + "method": "PATCH", + "header": [ + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/links/:linkReference", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "links", + ":linkReference" + ], + "variable": [ + { + "key": "accountId" + }, + { + "key": "linkReference" + } + ] + } + }, + "status": "Accepted", + "code": 202, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"notificationMethod\": \"\",\n \"serverCorrelationId\": \"\",\n \"status\": \"\",\n \"pendingReason\": \"\",\n \"objectReference\": \"\",\n \"expiryTime\": \"\",\n \"pollLimit\": \"\",\n \"error\": {\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n }\n}" + }, + { + "name": "Represents an Error Caused by a General Server-Side Issue", + "originalRequest": { + "method": "PATCH", + "header": [ + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/links/:linkReference", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "links", + ":linkReference" + ], + "variable": [ + { + "key": "accountId" + }, + { + "key": "linkReference" + } + ] + } + }, + "status": "Internal Server Error", + "code": 500, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by the Violation of a Business Rule", + "originalRequest": { + "method": "PATCH", + "header": [ + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/links/:linkReference", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "links", + ":linkReference" + ], + "variable": [ + { + "key": "accountId" + }, + { + "key": "linkReference" + } + ] + } + }, + "status": "Bad Request", + "code": 400, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + } + ] + } + ] + }, + { + "name": "Create A Link", + "request": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API.", + "disabled": true + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + }, + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Accept", + "value": "application/json", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"sourceAccountIdentifiers\": [\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n }\n ],\n \"mode\": \"push\",\n \"status\": \"active\",\n \"requestingOrganisation\": {\n \"requestingOrganisationIdentifierType\": \"lei\",\n \"requestingOrganisationIdentifier\": \"string\"\n },\n \"requestDate\": \"2022-09-29T07:26:54.647Z\",\n \"customData\": [\n {\n \"key\": \"string\",\n \"value\": \"string\"\n }\n ]\n}" + }, + "url": { + "raw": "{{ChannelGSMAHostName}}/accounts/{{accountId}}/links", + "host": [ + "{{ChannelGSMAHostName}}" + ], + "path": [ + "accounts", + "{{accountId}}", + "links" + ] + }, + "description": "Provided with a valid object representation, this endpoint allows a new link to be created for a specific account" + }, + "response": [ + { + "name": "Represents an Error Caused by an Authorisation Failure", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/links", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "links" + ], + "variable": [ + { + "key": "accountId" + } + ] + } + }, + "status": "Unauthorized", + "code": 401, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by a Failure to Identify the Target Resource", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/links", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "links" + ], + "variable": [ + { + "key": "accountId" + } + ] + } + }, + "status": "Not Found", + "code": 404, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by System Unavailability", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/links", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "links" + ], + "variable": [ + { + "key": "accountId" + } + ] + } + }, + "status": "Service Unavailable", + "code": 503, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by the Violation of a Business Rule", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/links", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "links" + ], + "variable": [ + { + "key": "accountId" + } + ] + } + }, + "status": "Bad Request", + "code": 400, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Asynchronous response", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/links", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "links" + ], + "variable": [ + { + "key": "accountId" + } + ] + } + }, + "status": "Accepted", + "code": 202, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"notificationMethod\": \"\",\n \"serverCorrelationId\": \"\",\n \"status\": \"\",\n \"pendingReason\": \"\",\n \"objectReference\": \"\",\n \"expiryTime\": \"\",\n \"pollLimit\": \"\",\n \"error\": {\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n }\n}" + }, + { + "name": "Represents an Error Caused by a General Server-Side Issue", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/links", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "links" + ], + "variable": [ + { + "key": "accountId" + } + ] + } + }, + "status": "Internal Server Error", + "code": 500, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents a Link response", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/links", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "links" + ], + "variable": [ + { + "key": "accountId" + } + ] + } + }, + "status": "Created", + "code": 201, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"linkReference\": \"\",\n \"sourceAccountIdentifiers\": [\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n },\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n }\n ],\n \"status\": \"\",\n \"mode\": \"\"\n}" + } + ] + } + ] + }, + { + "name": "authorisationcodes", + "item": [ + { + "name": "{authorisation Code}", + "item": [ + { + "name": "View an Authorisation Code", + "request": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API.", + "disabled": true + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + }, + { + "key": "Accept", + "value": "application/json", + "type": "text" + } + ], + "url": { + "raw": "{{ChannelGSMAHostName}}/accounts/{{accountId}}/authorisationcodes/{{authorisationCode}}", + "host": [ + "{{ChannelGSMAHostName}}" + ], + "path": [ + "accounts", + "{{accountId}}", + "authorisationcodes", + "{{authorisationCode}}" + ] + }, + "description": "This endpoint returns a specific Authorisation Code linked to an account" + }, + "response": [ + { + "name": "Represents an Error Caused by System Unavailability", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/authorisationcodes/:authorisationCode", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "authorisationcodes", + ":authorisationCode" + ], + "variable": [ + { + "key": "accountId" + }, + { + "key": "authorisationCode" + } + ] + } + }, + "status": "Service Unavailable", + "code": 503, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by the Violation of a Business Rule", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/authorisationcodes/:authorisationCode", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "authorisationcodes", + ":authorisationCode" + ], + "variable": [ + { + "key": "accountId" + }, + { + "key": "authorisationCode" + } + ] + } + }, + "status": "Bad Request", + "code": 400, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by an Authorisation Failure", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/authorisationcodes/:authorisationCode", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "authorisationcodes", + ":authorisationCode" + ], + "variable": [ + { + "key": "accountId" + }, + { + "key": "authorisationCode" + } + ] + } + }, + "status": "Unauthorized", + "code": 401, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by a Failure to Identify the Target Resource", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/authorisationcodes/:authorisationCode", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "authorisationcodes", + ":authorisationCode" + ], + "variable": [ + { + "key": "accountId" + }, + { + "key": "authorisationCode" + } + ] + } + }, + "status": "Not Found", + "code": 404, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Authorisation Code response", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/authorisationcodes/:authorisationCode", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "authorisationcodes", + ":authorisationCode" + ], + "variable": [ + { + "key": "accountId" + }, + { + "key": "authorisationCode" + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"authorisationCode\": \"\",\n \"codeState\": \"\",\n \"codeLifetime\": \"\",\n \"requestDate\": \"\",\n \"amount\": \"15.21\",\n \"currency\": \"\",\n \"amountType\": \"\",\n \"holdFundsIndicator\": \"\",\n \"redemptionChannels\": [\n {\n \"channelType\": \"\"\n },\n {\n \"channelType\": \"\"\n }\n ],\n \"redemptionTransactionTypes\": [\n {\n \"transactionType\": \"\",\n \"transactionSubtype\": \"\"\n },\n {\n \"transactionType\": \"\",\n \"transactionSubtype\": \"\"\n }\n ],\n \"redemptionAccountIdentifiers\": [\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n },\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n }\n ],\n \"metadata\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by a General Server-Side Issue", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/authorisationcodes/:authorisationCode", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "authorisationcodes", + ":authorisationCode" + ], + "variable": [ + { + "key": "accountId" + }, + { + "key": "authorisationCode" + } + ] + } + }, + "status": "Internal Server Error", + "code": 500, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + } + ] + }, + { + "name": "Update an Authorisation Code", + "request": { + "method": "PATCH", + "header": [ + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API.", + "disabled": true + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + }, + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Accept", + "value": "application/json", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "[\n {\n \"op\": \"replace\",\n \"path\": \"string\",\n \"value\": \"string\"\n }\n]" + }, + "url": { + "raw": "{{ChannelGSMAHostName}}/accounts/{{accountId}}/authorisationcodes/{{authorisationCode}}", + "host": [ + "{{ChannelGSMAHostName}}" + ], + "path": [ + "accounts", + "{{accountId}}", + "authorisationcodes", + "{{authorisationCode}}" + ] + }, + "description": "This endpoint updates a specific Authorisation Code linked to an account" + }, + "response": [ + { + "name": "Represents an Error Caused by System Unavailability", + "originalRequest": { + "method": "PATCH", + "header": [ + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/authorisationcodes/:authorisationCode", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "authorisationcodes", + ":authorisationCode" + ], + "variable": [ + { + "key": "accountId" + }, + { + "key": "authorisationCode" + } + ] + } + }, + "status": "Service Unavailable", + "code": 503, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Asynchronous response", + "originalRequest": { + "method": "PATCH", + "header": [ + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/authorisationcodes/:authorisationCode", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "authorisationcodes", + ":authorisationCode" + ], + "variable": [ + { + "key": "accountId" + }, + { + "key": "authorisationCode" + } + ] + } + }, + "status": "Accepted", + "code": 202, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"notificationMethod\": \"\",\n \"serverCorrelationId\": \"\",\n \"status\": \"\",\n \"pendingReason\": \"\",\n \"objectReference\": \"\",\n \"expiryTime\": \"\",\n \"pollLimit\": \"\",\n \"error\": {\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n }\n}" + }, + { + "name": "Represents an Error Caused by a Failure to Identify the Target Resource", + "originalRequest": { + "method": "PATCH", + "header": [ + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/authorisationcodes/:authorisationCode", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "authorisationcodes", + ":authorisationCode" + ], + "variable": [ + { + "key": "accountId" + }, + { + "key": "authorisationCode" + } + ] + } + }, + "status": "Not Found", + "code": 404, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "An empty response is returned for a synchronous successful patch.", + "originalRequest": { + "method": "PATCH", + "header": [ + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/authorisationcodes/:authorisationCode", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "authorisationcodes", + ":authorisationCode" + ], + "variable": [ + { + "key": "accountId" + }, + { + "key": "authorisationCode" + } + ] + } + }, + "status": "No Content", + "code": 204, + "_postman_previewlanguage": "text", + "header": [ + { + "key": "Content-Type", + "value": "text/plain" + } + ], + "cookie": [], + "body": "" + }, + { + "name": "Represents an Error Caused by the Violation of a Business Rule", + "originalRequest": { + "method": "PATCH", + "header": [ + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/authorisationcodes/:authorisationCode", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "authorisationcodes", + ":authorisationCode" + ], + "variable": [ + { + "key": "accountId" + }, + { + "key": "authorisationCode" + } + ] + } + }, + "status": "Bad Request", + "code": 400, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by a General Server-Side Issue", + "originalRequest": { + "method": "PATCH", + "header": [ + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/authorisationcodes/:authorisationCode", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "authorisationcodes", + ":authorisationCode" + ], + "variable": [ + { + "key": "accountId" + }, + { + "key": "authorisationCode" + } + ] + } + }, + "status": "Internal Server Error", + "code": 500, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by an Authorisation Failure", + "originalRequest": { + "method": "PATCH", + "header": [ + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/authorisationcodes/:authorisationCode", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "authorisationcodes", + ":authorisationCode" + ], + "variable": [ + { + "key": "accountId" + }, + { + "key": "authorisationCode" + } + ] + } + }, + "status": "Unauthorized", + "code": 401, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + } + ] + } + ] + }, + { + "name": "Create an Authorisation Code", + "request": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API.", + "disabled": true + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + }, + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Accept", + "value": "application/json", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"amount\": \"15.21\",\n \"currency\": \"AED\",\n \"amountType\": \"exact\",\n \"codeLifetime\": 600,\n \"holdFundsIndicator\": true,\n \"redemptionAccountIdentifiers\": [\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n }\n ],\n \"redemptionChannels\": [\n {\n \"channelType\": \"string\"\n }\n ],\n \"redemptionTransactionTypes\": [\n {\n \"transactionType\": \"billpay\",\n \"transactionSubtype\": \"string\"\n }\n ],\n \"requestingOrganisation\": {\n \"requestingOrganisationIdentifierType\": \"lei\",\n \"requestingOrganisationIdentifier\": \"string\"\n },\n \"requestDate\": \"2022-09-29T07:23:27.990Z\",\n \"customData\": [\n {\n \"key\": \"string\",\n \"value\": \"string\"\n }\n ],\n \"metadata\": [\n {\n \"key\": \"string\",\n \"value\": \"string\"\n }\n ]\n}" + }, + "url": { + "raw": "{{ChannelGSMAHostName}}/accounts/{{accountId}}/authorisationcodes", + "host": [ + "{{ChannelGSMAHostName}}" + ], + "path": [ + "accounts", + "{{accountId}}", + "authorisationcodes" + ] + }, + "description": "this endpoint allows allows a mobile money payer or payee to generate a code which when presented to the other party, can be redeemed for an amount set by the payer or payee, depending upon the use case" + }, + "response": [ + { + "name": "Represents an Asynchronous response", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/authorisationcodes", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "authorisationcodes" + ], + "variable": [ + { + "key": "accountId" + } + ] + } + }, + "status": "Accepted", + "code": 202, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"notificationMethod\": \"\",\n \"serverCorrelationId\": \"\",\n \"status\": \"\",\n \"pendingReason\": \"\",\n \"objectReference\": \"\",\n \"expiryTime\": \"\",\n \"pollLimit\": \"\",\n \"error\": {\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n }\n}" + }, + { + "name": "Represents an Error Caused by the Violation of a Business Rule", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/authorisationcodes", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "authorisationcodes" + ], + "variable": [ + { + "key": "accountId" + } + ] + } + }, + "status": "Bad Request", + "code": 400, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by a General Server-Side Issue", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/authorisationcodes", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "authorisationcodes" + ], + "variable": [ + { + "key": "accountId" + } + ] + } + }, + "status": "Internal Server Error", + "code": 500, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by an Authorisation Failure", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/authorisationcodes", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "authorisationcodes" + ], + "variable": [ + { + "key": "accountId" + } + ] + } + }, + "status": "Unauthorized", + "code": 401, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by System Unavailability", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/authorisationcodes", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "authorisationcodes" + ], + "variable": [ + { + "key": "accountId" + } + ] + } + }, + "status": "Service Unavailable", + "code": 503, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Authorisation Code response", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/authorisationcodes", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "authorisationcodes" + ], + "variable": [ + { + "key": "accountId" + } + ] + } + }, + "status": "Created", + "code": 201, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"authorisationCode\": \"\",\n \"codeState\": \"\",\n \"codeLifetime\": \"\",\n \"requestDate\": \"\",\n \"amount\": \"15.21\",\n \"currency\": \"\",\n \"amountType\": \"\",\n \"holdFundsIndicator\": \"\",\n \"redemptionChannels\": [\n {\n \"channelType\": \"\"\n },\n {\n \"channelType\": \"\"\n }\n ],\n \"redemptionTransactionTypes\": [\n {\n \"transactionType\": \"\",\n \"transactionSubtype\": \"\"\n },\n {\n \"transactionType\": \"\",\n \"transactionSubtype\": \"\"\n }\n ],\n \"redemptionAccountIdentifiers\": [\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n },\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n }\n ],\n \"metadata\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by a Failure to Identify the Target Resource", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/authorisationcodes", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "authorisationcodes" + ], + "variable": [ + { + "key": "accountId" + } + ] + } + }, + "status": "Not Found", + "code": 404, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + } + ] + } + ] + }, + { + "name": "View Account Status", + "request": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API.", + "disabled": true + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server.", + "disabled": true + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication", + "disabled": true + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server.", + "disabled": true + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed.", + "disabled": true + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", + "disabled": true + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", + "disabled": true + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App.", + "disabled": true + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header.", + "disabled": true + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header.", + "disabled": true + }, + { + "key": "Accept", + "value": "application/json", + "type": "text" + } + ], + "url": { + "raw": "{{ChannelGSMAHostName}}/accounts/{{accountId}}/status", + "host": [ + "{{ChannelGSMAHostName}}" + ], + "path": [ + "accounts", + "{{accountId}}", + "status" + ] + }, + "description": "This endpoint returns the current status of an account. This API accepts multiple identifiers" + }, + "response": [ + { + "name": "Represents an Error Caused by System Unavailability", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/status", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "status" + ], + "variable": [ + { + "key": "accountId" + } + ] + } + }, + "status": "Service Unavailable", + "code": 503, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by an Authorisation Failure", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/status", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "status" + ], + "variable": [ + { + "key": "accountId" + } + ] + } + }, + "status": "Unauthorized", + "code": 401, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by a General Server-Side Issue", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/status", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "status" + ], + "variable": [ + { + "key": "accountId" + } + ] + } + }, + "status": "Internal Server Error", + "code": 500, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Account Status response", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/status", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "status" + ], + "variable": [ + { + "key": "accountId" + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"accountStatus\": \"\",\n \"subStatus\": \"\",\n \"lei\": \"5493000IBP32UQZ0KL24\"\n}" + }, + { + "name": "Represents an Error Caused by a Failure to Identify the Target Resource", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/status", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "status" + ], + "variable": [ + { + "key": "accountId" + } + ] + } + }, + "status": "Not Found", + "code": 404, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by the Violation of a Business Rule", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/status", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "status" + ], + "variable": [ + { + "key": "accountId" + } + ] + } + }, + "status": "Bad Request", + "code": 400, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + } + ] + }, + { + "name": "View Account Name", + "protocolProfileBehavior": { + "disabledSystemHeaders": { + "accept": true + } + }, + "request": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API.", + "disabled": true + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server.", + "disabled": true + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication", + "disabled": true + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server.", + "disabled": true + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed.", + "disabled": true + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", + "disabled": true + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", + "disabled": true + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App.", + "disabled": true + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header.", + "disabled": true + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header.", + "disabled": true + }, + { + "key": "Accept", + "value": "application/json", + "type": "text" + } + ], + "url": { + "raw": "{{ChannelGSMAHostName}}/accounts/{{accountId}}/accountname", + "host": [ + "{{ChannelGSMAHostName}}" + ], + "path": [ + "accounts", + "{{accountId}}", + "accountname" + ] + }, + "description": "This endpoint returns the status of a given account." + }, + "response": [ + { + "name": "Represents an Error Caused by a General Server-Side Issue", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/accountname", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "accountname" + ], + "variable": [ + { + "key": "accountId" + } + ] + } + }, + "status": "Internal Server Error", + "code": 500, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by the Violation of a Business Rule", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/accountname", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "accountname" + ], + "variable": [ + { + "key": "accountId" + } + ] + } + }, + "status": "Bad Request", + "code": 400, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by System Unavailability", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/accountname", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "accountname" + ], + "variable": [ + { + "key": "accountId" + } + ] + } + }, + "status": "Service Unavailable", + "code": 503, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by an Authorisation Failure", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/accountname", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "accountname" + ], + "variable": [ + { + "key": "accountId" + } + ] + } + }, + "status": "Unauthorized", + "code": 401, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Account Name response", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/accountname", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "accountname" + ], + "variable": [ + { + "key": "accountId" + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"name\": {\n \"title\": \"\",\n \"firstName\": \"\",\n \"middleName\": \"\",\n \"lastName\": \"\",\n \"fullName\": \"\",\n \"nativeName\": \"\"\n },\n \"lei\": \"5493000IBP32UQZ0KL24\"\n}" + }, + { + "name": "Represents an Error Caused by a Failure to Identify the Target Resource", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/accountname", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "accountname" + ], + "variable": [ + { + "key": "accountId" + } + ] + } + }, + "status": "Not Found", + "code": 404, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + } + ] + }, + { + "name": "View Account Balance", + "request": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API.", + "disabled": true + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server.", + "disabled": true + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication", + "disabled": true + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server.", + "disabled": true + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed.", + "disabled": true + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", + "disabled": true + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", + "disabled": true + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App.", + "disabled": true + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header.", + "disabled": true + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header.", + "disabled": true + }, + { + "key": "Accept", + "value": "application/json", + "type": "text" + } + ], + "url": { + "raw": "{{ChannelGSMAHostName}}/accounts/{{accountId}}/balance", + "host": [ + "{{ChannelGSMAHostName}}" + ], + "path": [ + "accounts", + "{{accountId}}", + "balance" + ] + }, + "description": "This endpoint returns the balance of an account" + }, + "response": [ + { + "name": "Represents an Error Caused by an Authorisation Failure", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/balance", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "balance" + ], + "variable": [ + { + "key": "accountId" + } + ] + } + }, + "status": "Unauthorized", + "code": 401, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by System Unavailability", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/balance", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "balance" + ], + "variable": [ + { + "key": "accountId" + } + ] + } + }, + "status": "Service Unavailable", + "code": 503, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Account Balance response", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/balance", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "balance" + ], + "variable": [ + { + "key": "accountId" + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"currentBalance\": \"15.21\",\n \"availableBalance\": \"15.21\",\n \"reservedBalance\": \"15.21\",\n \"unclearedBalance\": \"15.21\",\n \"currency\": \"\",\n \"accountStatus\": \"\"\n}" + }, + { + "name": "Represents an Error Caused by a General Server-Side Issue", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/balance", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "balance" + ], + "variable": [ + { + "key": "accountId" + } + ] + } + }, + "status": "Internal Server Error", + "code": 500, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by a Failure to Identify the Target Resource", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/balance", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "balance" + ], + "variable": [ + { + "key": "accountId" + } + ] + } + }, + "status": "Not Found", + "code": 404, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by the Violation of a Business Rule", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/balance", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "balance" + ], + "variable": [ + { + "key": "accountId" + } + ] + } + }, + "status": "Bad Request", + "code": 400, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + } + ] + }, + { + "name": "View Account Specific Transaction", + "request": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API.", + "disabled": true + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server.", + "disabled": true + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication", + "disabled": true + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server.", + "disabled": true + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed.", + "disabled": true + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", + "disabled": true + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", + "disabled": true + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App.", + "disabled": true + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header.", + "disabled": true + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header.", + "disabled": true + }, + { + "key": "Accept", + "value": "application/json", + "type": "text" + } + ], + "url": { + "raw": "{{ChannelGSMAHostName}}/accounts/{{accountId}}/transactions", + "host": [ + "{{ChannelGSMAHostName}}" + ], + "path": [ + "accounts", + "{{accountId}}", + "transactions" + ], + "query": [ + { + "key": "limit", + "value": "", + "description": "Supports pagination. If this is not supplied, then the server will apply a limit of 50 records returned for each request.", + "disabled": true + }, + { + "key": "offset", + "value": "", + "description": "Supports pagination. This value will indicate the cursor position from where to retrieve the set of records. For example, a limit of 50 and offset of 10 will return records 11 to 60.", + "disabled": true + }, + { + "key": "fromDateTime", + "value": "", + "description": "Indicates the minimum date for which records should be returned.", + "disabled": true + }, + { + "key": "toDateTime", + "value": "", + "description": "Indicates the maximum date for which records should be returned.", + "disabled": true + }, + { + "key": "transactionStatus", + "value": "", + "description": "Query variable to uniquely identify the transaction status.", + "disabled": true + }, + { + "key": "transactionType", + "value": "", + "description": "Identifies the type of transaction.", + "disabled": true + } + ] + }, + "description": "This endpoint returns transactions linked to a specific account" + }, + "response": [ + { + "name": "Represents an Error Caused by the Violation of a Business Rule", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/transactions?limit=&offset=&fromDateTime=&toDateTime=&transactionStatus=&transactionType=", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "transactions" + ], + "query": [ + { + "key": "limit", + "value": "" + }, + { + "key": "offset", + "value": "" + }, + { + "key": "fromDateTime", + "value": "" + }, + { + "key": "toDateTime", + "value": "" + }, + { + "key": "transactionStatus", + "value": "" + }, + { + "key": "transactionType", + "value": "" + } + ], + "variable": [ + { + "key": "accountId" + } + ] + } + }, + "status": "Bad Request", + "code": 400, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by System Unavailability", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/transactions?limit=&offset=&fromDateTime=&toDateTime=&transactionStatus=&transactionType=", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "transactions" + ], + "query": [ + { + "key": "limit", + "value": "" + }, + { + "key": "offset", + "value": "" + }, + { + "key": "fromDateTime", + "value": "" + }, + { + "key": "toDateTime", + "value": "" + }, + { + "key": "transactionStatus", + "value": "" + }, + { + "key": "transactionType", + "value": "" + } + ], + "variable": [ + { + "key": "accountId" + } + ] + } + }, + "status": "Service Unavailable", + "code": 503, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represent a list of Transactions", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/transactions?limit=&offset=&fromDateTime=&toDateTime=&transactionStatus=&transactionType=", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "transactions" + ], + "query": [ + { + "key": "limit", + "value": "" + }, + { + "key": "offset", + "value": "" + }, + { + "key": "fromDateTime", + "value": "" + }, + { + "key": "toDateTime", + "value": "" + }, + { + "key": "transactionStatus", + "value": "" + }, + { + "key": "transactionType", + "value": "" + } + ], + "variable": [ + { + "key": "accountId" + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "X-Records-Available-Count", + "value": "", + "description": "Integer containing number of records that are available to be returned." + }, + { + "key": "X-Records-Returned-Count", + "value": "", + "description": "Integer containing number of records that are returned." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "[\n {\n \"amount\": \"15.21\",\n \"currency\": \"\",\n \"type\": \"\",\n \"transactionReference\": \"\",\n \"transactionStatus\": \"\",\n \"debitParty\": [\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n },\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n }\n ],\n \"creditParty\": [\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n },\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n }\n ],\n \"subType\": \"\",\n \"descriptionText\": \"\",\n \"requestDate\": \"\",\n \"requestingOrganisationTransactionReference\": \"\",\n \"oneTimeCode\": \"\",\n \"geoCode\": \"37.423825,-122.082900\",\n \"senderKyc\": {\n \"nationality\": \"\",\n \"dateOfBirth\": \"2000-11-20\",\n \"occupation\": \"\",\n \"employerName\": \"\",\n \"contactPhone\": \"\",\n \"gender\": \"\",\n \"idDocument\": [\n {\n \"idType\": \"\",\n \"idNumber\": \"\",\n \"issueDate\": \"2018-11-20\",\n \"expiryDate\": \"2018-11-20\",\n \"issuer\": \"\",\n \"issuerPlace\": \"\",\n \"issuerCountry\": \"\",\n \"otherIddescription\": \"\"\n },\n {\n \"idType\": \"\",\n \"idNumber\": \"\",\n \"issueDate\": \"2018-11-20\",\n \"expiryDate\": \"2018-11-20\",\n \"issuer\": \"\",\n \"issuerPlace\": \"\",\n \"issuerCountry\": \"\",\n \"otherIddescription\": \"\"\n }\n ],\n \"postalAddress\": {\n \"country\": \"\",\n \"addressLine1\": \"\",\n \"addressLine2\": \"\",\n \"addressLine3\": \"\",\n \"city\": \"\",\n \"stateProvince\": \"\",\n \"postalCode\": \"\"\n },\n \"subjectName\": {\n \"title\": \"\",\n \"firstName\": \"\",\n \"middleName\": \"\",\n \"lastName\": \"\",\n \"fullName\": \"\",\n \"nativeName\": \"\"\n },\n \"emailAddress\": \"\",\n \"birthCountry\": \"\"\n },\n \"recipientKyc\": {\n \"nationality\": \"\",\n \"dateOfBirth\": \"2000-11-20\",\n \"occupation\": \"\",\n \"employerName\": \"\",\n \"contactPhone\": \"\",\n \"gender\": \"\",\n \"idDocument\": [\n {\n \"idType\": \"\",\n \"idNumber\": \"\",\n \"issueDate\": \"2018-11-20\",\n \"expiryDate\": \"2018-11-20\",\n \"issuer\": \"\",\n \"issuerPlace\": \"\",\n \"issuerCountry\": \"\",\n \"otherIddescription\": \"\"\n },\n {\n \"idType\": \"\",\n \"idNumber\": \"\",\n \"issueDate\": \"2018-11-20\",\n \"expiryDate\": \"2018-11-20\",\n \"issuer\": \"\",\n \"issuerPlace\": \"\",\n \"issuerCountry\": \"\",\n \"otherIddescription\": \"\"\n }\n ],\n \"postalAddress\": {\n \"country\": \"\",\n \"addressLine1\": \"\",\n \"addressLine2\": \"\",\n \"addressLine3\": \"\",\n \"city\": \"\",\n \"stateProvince\": \"\",\n \"postalCode\": \"\"\n },\n \"subjectName\": {\n \"title\": \"\",\n \"firstName\": \"\",\n \"middleName\": \"\",\n \"lastName\": \"\",\n \"fullName\": \"\",\n \"nativeName\": \"\"\n },\n \"emailAddress\": \"\",\n \"birthCountry\": \"\"\n },\n \"originalTransactionReference\": \"\",\n \"servicingIdentity\": \"\",\n \"fees\": [\n {\n \"feeType\": \"\",\n \"feeCurrency\": \"\",\n \"feeAmount\": \"15.21\"\n },\n {\n \"feeType\": \"\",\n \"feeCurrency\": \"\",\n \"feeAmount\": \"15.21\"\n }\n ],\n \"requestingLei\": \"54930084UKLVMY22DS16\",\n \"receivingLei\": \"5493000IBP32UQZ0KL24\",\n \"metadata\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ],\n \"creationDate\": \"\",\n \"modificationDate\": \"\",\n \"dateCreated\": \"\",\n \"dateModified\": \"\",\n \"transactionReceipt\": \"\",\n \"internationalTransferInformation\": {\n \"originCountry\": \"\",\n \"quotationReference\": \"\",\n \"quoteId\": \"\",\n \"receivingCountry\": \"\",\n \"remittancePurpose\": \"\",\n \"relationshipSender\": \"\",\n \"deliveryMethod\": \"\",\n \"senderBlockingReason\": \"\",\n \"recipientBlockingReason\": \"\"\n }\n },\n {\n \"amount\": \"15.21\",\n \"currency\": \"\",\n \"type\": \"\",\n \"transactionReference\": \"\",\n \"transactionStatus\": \"\",\n \"debitParty\": [\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n },\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n }\n ],\n \"creditParty\": [\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n },\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n }\n ],\n \"subType\": \"\",\n \"descriptionText\": \"\",\n \"requestDate\": \"\",\n \"requestingOrganisationTransactionReference\": \"\",\n \"oneTimeCode\": \"\",\n \"geoCode\": \"37.423825,-122.082900\",\n \"senderKyc\": {\n \"nationality\": \"\",\n \"dateOfBirth\": \"2000-11-20\",\n \"occupation\": \"\",\n \"employerName\": \"\",\n \"contactPhone\": \"\",\n \"gender\": \"\",\n \"idDocument\": [\n {\n \"idType\": \"\",\n \"idNumber\": \"\",\n \"issueDate\": \"2018-11-20\",\n \"expiryDate\": \"2018-11-20\",\n \"issuer\": \"\",\n \"issuerPlace\": \"\",\n \"issuerCountry\": \"\",\n \"otherIddescription\": \"\"\n },\n {\n \"idType\": \"\",\n \"idNumber\": \"\",\n \"issueDate\": \"2018-11-20\",\n \"expiryDate\": \"2018-11-20\",\n \"issuer\": \"\",\n \"issuerPlace\": \"\",\n \"issuerCountry\": \"\",\n \"otherIddescription\": \"\"\n }\n ],\n \"postalAddress\": {\n \"country\": \"\",\n \"addressLine1\": \"\",\n \"addressLine2\": \"\",\n \"addressLine3\": \"\",\n \"city\": \"\",\n \"stateProvince\": \"\",\n \"postalCode\": \"\"\n },\n \"subjectName\": {\n \"title\": \"\",\n \"firstName\": \"\",\n \"middleName\": \"\",\n \"lastName\": \"\",\n \"fullName\": \"\",\n \"nativeName\": \"\"\n },\n \"emailAddress\": \"\",\n \"birthCountry\": \"\"\n },\n \"recipientKyc\": {\n \"nationality\": \"\",\n \"dateOfBirth\": \"2000-11-20\",\n \"occupation\": \"\",\n \"employerName\": \"\",\n \"contactPhone\": \"\",\n \"gender\": \"\",\n \"idDocument\": [\n {\n \"idType\": \"\",\n \"idNumber\": \"\",\n \"issueDate\": \"2018-11-20\",\n \"expiryDate\": \"2018-11-20\",\n \"issuer\": \"\",\n \"issuerPlace\": \"\",\n \"issuerCountry\": \"\",\n \"otherIddescription\": \"\"\n },\n {\n \"idType\": \"\",\n \"idNumber\": \"\",\n \"issueDate\": \"2018-11-20\",\n \"expiryDate\": \"2018-11-20\",\n \"issuer\": \"\",\n \"issuerPlace\": \"\",\n \"issuerCountry\": \"\",\n \"otherIddescription\": \"\"\n }\n ],\n \"postalAddress\": {\n \"country\": \"\",\n \"addressLine1\": \"\",\n \"addressLine2\": \"\",\n \"addressLine3\": \"\",\n \"city\": \"\",\n \"stateProvince\": \"\",\n \"postalCode\": \"\"\n },\n \"subjectName\": {\n \"title\": \"\",\n \"firstName\": \"\",\n \"middleName\": \"\",\n \"lastName\": \"\",\n \"fullName\": \"\",\n \"nativeName\": \"\"\n },\n \"emailAddress\": \"\",\n \"birthCountry\": \"\"\n },\n \"originalTransactionReference\": \"\",\n \"servicingIdentity\": \"\",\n \"fees\": [\n {\n \"feeType\": \"\",\n \"feeCurrency\": \"\",\n \"feeAmount\": \"15.21\"\n },\n {\n \"feeType\": \"\",\n \"feeCurrency\": \"\",\n \"feeAmount\": \"15.21\"\n }\n ],\n \"requestingLei\": \"54930084UKLVMY22DS16\",\n \"receivingLei\": \"5493000IBP32UQZ0KL24\",\n \"metadata\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ],\n \"creationDate\": \"\",\n \"modificationDate\": \"\",\n \"dateCreated\": \"\",\n \"dateModified\": \"\",\n \"transactionReceipt\": \"\",\n \"internationalTransferInformation\": {\n \"originCountry\": \"\",\n \"quotationReference\": \"\",\n \"quoteId\": \"\",\n \"receivingCountry\": \"\",\n \"remittancePurpose\": \"\",\n \"relationshipSender\": \"\",\n \"deliveryMethod\": \"\",\n \"senderBlockingReason\": \"\",\n \"recipientBlockingReason\": \"\"\n }\n }\n]" + }, + { + "name": "Represents an Error Caused by an Authorisation Failure", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/transactions?limit=&offset=&fromDateTime=&toDateTime=&transactionStatus=&transactionType=", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "transactions" + ], + "query": [ + { + "key": "limit", + "value": "" + }, + { + "key": "offset", + "value": "" + }, + { + "key": "fromDateTime", + "value": "" + }, + { + "key": "toDateTime", + "value": "" + }, + { + "key": "transactionStatus", + "value": "" + }, + { + "key": "transactionType", + "value": "" + } + ], + "variable": [ + { + "key": "accountId" + } + ] + } + }, + "status": "Unauthorized", + "code": 401, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by a Failure to Identify the Target Resource", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/transactions?limit=&offset=&fromDateTime=&toDateTime=&transactionStatus=&transactionType=", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "transactions" + ], + "query": [ + { + "key": "limit", + "value": "" + }, + { + "key": "offset", + "value": "" + }, + { + "key": "fromDateTime", + "value": "" + }, + { + "key": "toDateTime", + "value": "" + }, + { + "key": "transactionStatus", + "value": "" + }, + { + "key": "transactionType", + "value": "" + } + ], + "variable": [ + { + "key": "accountId" + } + ] + } + }, + "status": "Not Found", + "code": 404, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by a General Server-Side Issue", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/transactions?limit=&offset=&fromDateTime=&toDateTime=&transactionStatus=&transactionType=", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "transactions" + ], + "query": [ + { + "key": "limit", + "value": "" + }, + { + "key": "offset", + "value": "" + }, + { + "key": "fromDateTime", + "value": "" + }, + { + "key": "toDateTime", + "value": "" + }, + { + "key": "transactionStatus", + "value": "" + }, + { + "key": "transactionType", + "value": "" + } + ], + "variable": [ + { + "key": "accountId" + } + ] + } + }, + "status": "Internal Server Error", + "code": 500, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + } + ] + }, + { + "name": "View Account Statements", + "request": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API.", + "disabled": true + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server.", + "disabled": true + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication", + "disabled": true + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server.", + "disabled": true + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed.", + "disabled": true + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", + "disabled": true + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", + "disabled": true + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App.", + "disabled": true + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header.", + "disabled": true + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header.", + "disabled": true + }, + { + "key": "Accept", + "value": "application/json", + "type": "text" + } + ], + "url": { + "raw": "{{ChannelGSMAHostName}}/accounts/{{accountId}}/statemententries", + "host": [ + "{{ChannelGSMAHostName}}" + ], + "path": [ + "accounts", + "{{accountId}}", + "statemententries" + ], + "query": [ + { + "key": "limit", + "value": "", + "description": "Supports pagination. If this is not supplied, then the server will apply a limit of 50 records returned for each request.", + "disabled": true + }, + { + "key": "offset", + "value": "", + "description": "Supports pagination. This value will indicate the cursor position from where to retrieve the set of records. For example, a limit of 50 and offset of 10 will return records 11 to 60.", + "disabled": true + }, + { + "key": "fromDateTime", + "value": "", + "description": "Indicates the minimum date for which records should be returned.", + "disabled": true + }, + { + "key": "toDateTime", + "value": "", + "description": "Indicates the maximum date for which records should be returned.", + "disabled": true + }, + { + "key": "transactionStatus", + "value": "", + "description": "Query variable to uniquely identify the transaction status.", + "disabled": true + }, + { + "key": "displayType", + "value": "", + "description": "Query parameter to to identify the display type of the statement entries to be returned.", + "disabled": true + } + ] + }, + "description": "The Statement Entries API enables generic representations of transactions to be returned. Typically, the returned representations are used for the purposes of presenting a statement to the account holder. In order to return a statement, an account must be specified." + }, + "response": [ + { + "name": "Represents an Error Caused by System Unavailability", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/statemententries?limit=&offset=&fromDateTime=&toDateTime=&transactionStatus=&displayType=", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "statemententries" + ], + "query": [ + { + "key": "limit", + "value": "" + }, + { + "key": "offset", + "value": "" + }, + { + "key": "fromDateTime", + "value": "" + }, + { + "key": "toDateTime", + "value": "" + }, + { + "key": "transactionStatus", + "value": "" + }, + { + "key": "displayType", + "value": "" + } + ], + "variable": [ + { + "key": "accountId" + } + ] + } + }, + "status": "Service Unavailable", + "code": 503, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by a Failure to Identify the Target Resource", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/statemententries?limit=&offset=&fromDateTime=&toDateTime=&transactionStatus=&displayType=", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "statemententries" + ], + "query": [ + { + "key": "limit", + "value": "" + }, + { + "key": "offset", + "value": "" + }, + { + "key": "fromDateTime", + "value": "" + }, + { + "key": "toDateTime", + "value": "" + }, + { + "key": "transactionStatus", + "value": "" + }, + { + "key": "displayType", + "value": "" + } + ], + "variable": [ + { + "key": "accountId" + } + ] + } + }, + "status": "Not Found", + "code": 404, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by the Violation of a Business Rule", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/statemententries?limit=&offset=&fromDateTime=&toDateTime=&transactionStatus=&displayType=", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "statemententries" + ], + "query": [ + { + "key": "limit", + "value": "" + }, + { + "key": "offset", + "value": "" + }, + { + "key": "fromDateTime", + "value": "" + }, + { + "key": "toDateTime", + "value": "" + }, + { + "key": "transactionStatus", + "value": "" + }, + { + "key": "displayType", + "value": "" + } + ], + "variable": [ + { + "key": "accountId" + } + ] + } + }, + "status": "Bad Request", + "code": 400, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by an Authorisation Failure", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/statemententries?limit=&offset=&fromDateTime=&toDateTime=&transactionStatus=&displayType=", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "statemententries" + ], + "query": [ + { + "key": "limit", + "value": "" + }, + { + "key": "offset", + "value": "" + }, + { + "key": "fromDateTime", + "value": "" + }, + { + "key": "toDateTime", + "value": "" + }, + { + "key": "transactionStatus", + "value": "" + }, + { + "key": "displayType", + "value": "" + } + ], + "variable": [ + { + "key": "accountId" + } + ] + } + }, + "status": "Unauthorized", + "code": 401, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represent a list of Statement Entries", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/statemententries?limit=&offset=&fromDateTime=&toDateTime=&transactionStatus=&displayType=", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "statemententries" + ], + "query": [ + { + "key": "limit", + "value": "" + }, + { + "key": "offset", + "value": "" + }, + { + "key": "fromDateTime", + "value": "" + }, + { + "key": "toDateTime", + "value": "" + }, + { + "key": "transactionStatus", + "value": "" + }, + { + "key": "displayType", + "value": "" + } + ], + "variable": [ + { + "key": "accountId" + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "X-Records-Available-Count", + "value": "", + "description": "Integer containing number of records that are available to be returned." + }, + { + "key": "X-Records-Returned-Count", + "value": "", + "description": "Integer containing number of records that are returned." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "[\n {\n \"amount\": \"15.21\",\n \"creditParty\": [\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n },\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n }\n ],\n \"currency\": \"\",\n \"debitParty\": [\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n },\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n }\n ],\n \"transactionReference\": \"\",\n \"transactionStatus\": \"\",\n \"displayType\": \"\",\n \"descriptionText\": \"\",\n \"requestDate\": \"\",\n \"creationDate\": \"\",\n \"modificationDate\": \"\",\n \"dateCreated\": \"\",\n \"dateModified\": \"\",\n \"transactionReceipt\": \"\"\n },\n {\n \"amount\": \"15.21\",\n \"creditParty\": [\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n },\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n }\n ],\n \"currency\": \"\",\n \"debitParty\": [\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n },\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n }\n ],\n \"transactionReference\": \"\",\n \"transactionStatus\": \"\",\n \"displayType\": \"\",\n \"descriptionText\": \"\",\n \"requestDate\": \"\",\n \"creationDate\": \"\",\n \"modificationDate\": \"\",\n \"dateCreated\": \"\",\n \"dateModified\": \"\",\n \"transactionReceipt\": \"\"\n }\n]" + }, + { + "name": "Represents an Error Caused by a General Server-Side Issue", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/statemententries?limit=&offset=&fromDateTime=&toDateTime=&transactionStatus=&displayType=", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "statemententries" + ], + "query": [ + { + "key": "limit", + "value": "" + }, + { + "key": "offset", + "value": "" + }, + { + "key": "fromDateTime", + "value": "" + }, + { + "key": "toDateTime", + "value": "" + }, + { + "key": "transactionStatus", + "value": "" + }, + { + "key": "displayType", + "value": "" + } + ], + "variable": [ + { + "key": "accountId" + } + ] + } + }, + "status": "Internal Server Error", + "code": 500, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + } + ] + }, + { + "name": "View Bill Companies", + "request": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API.", + "disabled": true + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server.", + "disabled": true + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication", + "disabled": true + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server.", + "disabled": true + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed.", + "disabled": true + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header.", + "disabled": true + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header.", + "disabled": true + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", + "disabled": true + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", + "disabled": true + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App.", + "disabled": true + }, + { + "key": "Accept", + "value": "application/json", + "type": "text" + } + ], + "url": { + "raw": "{{ChannelGSMAHostName}}/accounts/{{accountId}}/billcompanies", + "host": [ + "{{ChannelGSMAHostName}}" + ], + "path": [ + "accounts", + "{{accountId}}", + "billcompanies" + ], + "query": [ + { + "key": "limit", + "value": "", + "description": "Supports pagination. If this is not supplied, then the server will apply a limit of 50 records returned for each request.", + "disabled": true + }, + { + "key": "offset", + "value": "", + "description": "Supports pagination. This value will indicate the cursor position from where to retrieve the set of records. For example, a limit of 50 and offset of 10 will return records 11 to 60.", + "disabled": true + } + ] + }, + "description": "This Bill Companies API is used to return a list of Service Providers that accept Bill Payments for a given account." + }, + "response": [ + { + "name": "Represents an Error Caused by an Authorisation Failure", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/billcompanies?limit=&offset=", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "billcompanies" + ], + "query": [ + { + "key": "limit", + "value": "" + }, + { + "key": "offset", + "value": "" + } + ], + "variable": [ + { + "key": "accountId" + } + ] + } + }, + "status": "Unauthorized", + "code": 401, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represent a list of Bill Companies", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/billcompanies?limit=&offset=", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "billcompanies" + ], + "query": [ + { + "key": "limit", + "value": "" + }, + { + "key": "offset", + "value": "" + } + ], + "variable": [ + { + "key": "accountId" + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "[\n {\n \"companyName\": \"\",\n \"serviceProvider\": \"\",\n \"serviceProviderType\": \"\",\n \"serviceProviderSubType\": \"\",\n \"supplementaryServiceProviderDetails\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n },\n {\n \"companyName\": \"\",\n \"serviceProvider\": \"\",\n \"serviceProviderType\": \"\",\n \"serviceProviderSubType\": \"\",\n \"supplementaryServiceProviderDetails\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n }\n]" + }, + { + "name": "Represents an Error Caused by System Unavailability", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/billcompanies?limit=&offset=", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "billcompanies" + ], + "query": [ + { + "key": "limit", + "value": "" + }, + { + "key": "offset", + "value": "" + } + ], + "variable": [ + { + "key": "accountId" + } + ] + } + }, + "status": "Service Unavailable", + "code": 503, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by a General Server-Side Issue", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/billcompanies?limit=&offset=", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "billcompanies" + ], + "query": [ + { + "key": "limit", + "value": "" + }, + { + "key": "offset", + "value": "" + } + ], + "variable": [ + { + "key": "accountId" + } + ] + } + }, + "status": "Internal Server Error", + "code": 500, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by the Violation of a Business Rule", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/billcompanies?limit=&offset=", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "billcompanies" + ], + "query": [ + { + "key": "limit", + "value": "" + }, + { + "key": "offset", + "value": "" + } + ], + "variable": [ + { + "key": "accountId" + } + ] + } + }, + "status": "Bad Request", + "code": 400, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by a Failure to Identify the Target Resource", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:accountId/billcompanies?limit=&offset=", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":accountId", + "billcompanies" + ], + "query": [ + { + "key": "limit", + "value": "" + }, + { + "key": "offset", + "value": "" + } + ], + "variable": [ + { + "key": "accountId" + } + ] + } + }, + "status": "Not Found", + "code": 404, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + } + ] + } + ] + }, + { + "name": "{identifier Type}/{identifier}", + "item": [ + { + "name": "bills", + "item": [ + { + "name": "View Account Bills", + "request": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API.", + "disabled": true + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server.", + "disabled": true + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication", + "disabled": true + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server.", + "disabled": true + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed.", + "disabled": true + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", + "disabled": true + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", + "disabled": true + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App.", + "disabled": true + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header.", + "disabled": true + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header.", + "disabled": true + }, + { + "key": "Accept", + "value": "application/json", + "type": "text" + } + ], + "url": { + "raw": "{{ChannelGSMAHostName}}/accounts/{{identifierType}}/{{identifier}}/bills", + "host": [ + "{{ChannelGSMAHostName}}" + ], + "path": [ + "accounts", + "{{identifierType}}", + "{{identifier}}", + "bills" + ] + }, + "description": "This endpoint returns bills linked to an account." + }, + "response": [ + { + "name": "Represent a list of Bills", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/bills", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "bills" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "[\n {\n \"currency\": \"\",\n \"amountDue\": \"15.21\",\n \"dueDate\": \"2018-11-20\",\n \"billReference\": \"\",\n \"minimumAmountDue\": \"15.21\",\n \"billdescription\": \"\",\n \"billStatus\": \"\",\n \"metadata\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n },\n {\n \"currency\": \"\",\n \"amountDue\": \"15.21\",\n \"dueDate\": \"2018-11-20\",\n \"billReference\": \"\",\n \"minimumAmountDue\": \"15.21\",\n \"billdescription\": \"\",\n \"billStatus\": \"\",\n \"metadata\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n }\n]" + }, + { + "name": "Represents an Error Caused by the Violation of a Business Rule", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/bills", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "bills" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + } + ] + } + }, + "status": "Bad Request", + "code": 400, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by an Authorisation Failure", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/bills", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "bills" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + } + ] + } + }, + "status": "Unauthorized", + "code": 401, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by a Failure to Identify the Target Resource", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/bills", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "bills" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + } + ] + } + }, + "status": "Not Found", + "code": 404, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by a General Server-Side Issue", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/bills", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "bills" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + } + ] + } + }, + "status": "Internal Server Error", + "code": 500, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by System Unavailability", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/bills", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "bills" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + } + ] + } + }, + "status": "Service Unavailable", + "code": 503, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + } + ] + }, + { + "name": "Create A Bill Payment", + "request": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API.", + "disabled": true + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID.", + "disabled": true + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server.", + "disabled": true + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication", + "disabled": true + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server.", + "disabled": true + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed.", + "disabled": true + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", + "disabled": true + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", + "disabled": true + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App.", + "disabled": true + }, + { + "key": "X-Callback-URL", + "value": "", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT.", + "disabled": true + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header.", + "disabled": true + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header.", + "disabled": true + }, + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Accept", + "value": "application/json", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"serviceProviderPaymentReference\": \"string\",\n \"requestingOrganisationTransactionReference\": \"string\",\n \"paymentType\": \"partialpayment\",\n \"amountPaid\": \"15.21\",\n \"currency\": \"AED\",\n \"customerReference\": \"string\",\n \"requestingOrganisation\": \"string\",\n \"supplementaryBillReferenceDetails\": [\n {\n \"paymentReferenceType\": \"string\",\n \"paymentReferenceValue\": \"string\"\n }\n ],\n \"requestDate\": \"2022-09-29T00:07:24.740Z\",\n \"customData\": [\n {\n \"key\": \"string\",\n \"value\": \"string\"\n }\n ],\n \"metadata\": [\n {\n \"key\": \"string\",\n \"value\": \"string\"\n }\n ],\n \"paidAmount\": \"15.21\"\n}" + }, + "url": { + "raw": "{{ChannelGSMAHostName}}/accounts/{{identifierType}}/{{identifier}}/bills/{{billReference}}/payments", + "host": [ + "{{ChannelGSMAHostName}}" + ], + "path": [ + "accounts", + "{{identifierType}}", + "{{identifier}}", + "bills", + "{{billReference}}", + "payments" + ] + }, + "description": "Provided with a valid object representation, this endpoint allows for a new bill payment to be created for a specific account." + }, + "response": [ + { + "name": "Represents an Error Caused by a Failure to Identify the Target Resource", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/bills/:billReference/payments", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "bills", + ":billReference", + "payments" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + }, + { + "key": "billReference" + } + ] + } + }, + "status": "Not Found", + "code": 404, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents a Bill Payment response", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/bills/:billReference/payments", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "bills", + ":billReference", + "payments" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + }, + { + "key": "billReference" + } + ] + } + }, + "status": "Created", + "code": 201, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"currency\": \"\",\n \"amountPaid\": \"15.21\",\n \"billPaymentStatus\": \"\",\n \"paidAmount\": \"15.21\",\n \"serviceProviderPaymentReference\": \"\",\n \"requestingOrganisation\": \"\",\n \"requestingOrganisationTransactionReference\": \"\",\n \"customerReference\": \"\",\n \"paymentType\": \"\",\n \"serviceProviderComment\": \"\",\n \"serviceProviderNotification\": \"\",\n \"supplementaryBillReferenceDetails\": [\n {\n \"paymentReferenceType\": \"\",\n \"paymentReferenceValue\": \"\"\n },\n {\n \"paymentReferenceType\": \"\",\n \"paymentReferenceValue\": \"\"\n }\n ],\n \"metadata\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by System Unavailability", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/bills/:billReference/payments", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "bills", + ":billReference", + "payments" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + }, + { + "key": "billReference" + } + ] + } + }, + "status": "Service Unavailable", + "code": 503, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Asynchronous response", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/bills/:billReference/payments", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "bills", + ":billReference", + "payments" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + }, + { + "key": "billReference" + } + ] + } + }, + "status": "Accepted", + "code": 202, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"notificationMethod\": \"\",\n \"serverCorrelationId\": \"\",\n \"status\": \"\",\n \"pendingReason\": \"\",\n \"objectReference\": \"\",\n \"expiryTime\": \"\",\n \"pollLimit\": \"\",\n \"error\": {\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n }\n}" + }, + { + "name": "Represents an Error Caused by an Authorisation Failure", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/bills/:billReference/payments", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "bills", + ":billReference", + "payments" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + }, + { + "key": "billReference" + } + ] + } + }, + "status": "Unauthorized", + "code": 401, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by the Violation of a Business Rule", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/bills/:billReference/payments", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "bills", + ":billReference", + "payments" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + }, + { + "key": "billReference" + } + ] + } + }, + "status": "Bad Request", + "code": 400, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by a General Server-Side Issue", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/bills/:billReference/payments", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "bills", + ":billReference", + "payments" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + }, + { + "key": "billReference" + } + ] + } + }, + "status": "Internal Server Error", + "code": 500, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + } + ] + } + ] + }, + { + "name": "debitmandates", + "item": [ + { + "name": "{debit Mandate Reference}", + "item": [ + { + "name": "View A Debit Mandate", + "request": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API.", + "disabled": true + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server.", + "disabled": true + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication", + "disabled": true + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server.", + "disabled": true + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed.", + "disabled": true + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", + "disabled": true + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", + "disabled": true + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App.", + "disabled": true + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header.", + "disabled": true + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header.", + "disabled": true + }, + { + "key": "Accept", + "value": "application/json", + "type": "text" + } + ], + "url": { + "raw": "{{ChannelGSMAHostName}}/accounts/{{identifierType}}/{{identifier}}/debitmandates/{{debitMandateReference}}", + "host": [ + "{{ChannelGSMAHostName}}" + ], + "path": [ + "accounts", + "{{identifierType}}", + "{{identifier}}", + "debitmandates", + "{{debitMandateReference}}" + ] + }, + "description": "This endpoint returns a specific debit mandate linked to an account." + }, + "response": [ + { + "name": "Represents a Debit Mandate response", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/debitmandates/:debitMandateReference", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "debitmandates", + ":debitMandateReference" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + }, + { + "key": "debitMandateReference" + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"mandateReference\": \"\",\n \"currency\": \"\",\n \"amountLimit\": \"15.21\",\n \"startDate\": \"2018-11-20\",\n \"endDate\": \"2018-11-20\",\n \"numberOfPayments\": \"\",\n \"frequencyType\": \"\",\n \"mandateStatus\": \"\",\n \"requestDate\": \"\",\n \"creationDate\": \"\",\n \"modificationDate\": \"\",\n \"dateCreated\": \"\",\n \"dateModified\": \"\"\n}" + }, + { + "name": "Represents an Error Caused by System Unavailability", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/debitmandates/:debitMandateReference", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "debitmandates", + ":debitMandateReference" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + }, + { + "key": "debitMandateReference" + } + ] + } + }, + "status": "Service Unavailable", + "code": 503, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by an Authorisation Failure", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/debitmandates/:debitMandateReference", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "debitmandates", + ":debitMandateReference" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + }, + { + "key": "debitMandateReference" + } + ] + } + }, + "status": "Unauthorized", + "code": 401, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by a Failure to Identify the Target Resource", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/debitmandates/:debitMandateReference", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "debitmandates", + ":debitMandateReference" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + }, + { + "key": "debitMandateReference" + } + ] + } + }, + "status": "Not Found", + "code": 404, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by the Violation of a Business Rule", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/debitmandates/:debitMandateReference", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "debitmandates", + ":debitMandateReference" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + }, + { + "key": "debitMandateReference" + } + ] + } + }, + "status": "Bad Request", + "code": 400, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by a General Server-Side Issue", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/debitmandates/:debitMandateReference", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "debitmandates", + ":debitMandateReference" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + }, + { + "key": "debitMandateReference" + } + ] + } + }, + "status": "Internal Server Error", + "code": 500, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + } + ] + }, + { + "name": "Update A Debit Mandate", + "request": { + "method": "PATCH", + "header": [ + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API.", + "disabled": true + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server.", + "disabled": true + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication", + "disabled": true + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server.", + "disabled": true + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed.", + "disabled": true + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", + "disabled": true + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", + "disabled": true + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App.", + "disabled": true + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header.", + "disabled": true + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header.", + "disabled": true + }, + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Accept", + "value": "application/json", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "[\n {\n \"op\": \"replace\",\n \"path\": \"string\",\n \"value\": \"string\"\n }\n]" + }, + "url": { + "raw": "{{ChannelGSMAHostName}}/accounts/{{identifierType}}/{{identifier}}/debitmandates/{{debitMandateReference}}", + "host": [ + "{{ChannelGSMAHostName}}" + ], + "path": [ + "accounts", + "{{identifierType}}", + "{{identifier}}", + "debitmandates", + "{{debitMandateReference}}" + ] + }, + "description": "This endpoint updates a specific debit mandate linked to an account." + }, + "response": [ + { + "name": "Represents an Error Caused by an Authorisation Failure", + "originalRequest": { + "method": "PATCH", + "header": [ + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/debitmandates/:debitMandateReference", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "debitmandates", + ":debitMandateReference" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + }, + { + "key": "debitMandateReference" + } + ] + } + }, + "status": "Unauthorized", + "code": 401, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by a General Server-Side Issue", + "originalRequest": { + "method": "PATCH", + "header": [ + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/debitmandates/:debitMandateReference", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "debitmandates", + ":debitMandateReference" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + }, + { + "key": "debitMandateReference" + } + ] + } + }, + "status": "Internal Server Error", + "code": 500, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by the Violation of a Business Rule", + "originalRequest": { + "method": "PATCH", + "header": [ + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/debitmandates/:debitMandateReference", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "debitmandates", + ":debitMandateReference" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + }, + { + "key": "debitMandateReference" + } + ] + } + }, + "status": "Bad Request", + "code": 400, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by System Unavailability", + "originalRequest": { + "method": "PATCH", + "header": [ + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/debitmandates/:debitMandateReference", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "debitmandates", + ":debitMandateReference" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + }, + { + "key": "debitMandateReference" + } + ] + } + }, + "status": "Service Unavailable", + "code": 503, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Asynchronous response", + "originalRequest": { + "method": "PATCH", + "header": [ + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/debitmandates/:debitMandateReference", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "debitmandates", + ":debitMandateReference" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + }, + { + "key": "debitMandateReference" + } + ] + } + }, + "status": "Accepted", + "code": 202, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"notificationMethod\": \"\",\n \"serverCorrelationId\": \"\",\n \"status\": \"\",\n \"pendingReason\": \"\",\n \"objectReference\": \"\",\n \"expiryTime\": \"\",\n \"pollLimit\": \"\",\n \"error\": {\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n }\n}" + }, + { + "name": "Represents an Error Caused by a Failure to Identify the Target Resource", + "originalRequest": { + "method": "PATCH", + "header": [ + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/debitmandates/:debitMandateReference", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "debitmandates", + ":debitMandateReference" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + }, + { + "key": "debitMandateReference" + } + ] + } + }, + "status": "Not Found", + "code": 404, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "An empty response is returned for a synchronous successful patch.", + "originalRequest": { + "method": "PATCH", + "header": [ + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/debitmandates/:debitMandateReference", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "debitmandates", + ":debitMandateReference" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + }, + { + "key": "debitMandateReference" + } + ] + } + }, + "status": "No Content", + "code": 204, + "_postman_previewlanguage": "text", + "header": [ + { + "key": "Content-Type", + "value": "text/plain" + } + ], + "cookie": [], + "body": "" + } + ] + } + ] + }, + { + "name": "Create A Debit Mandate", + "request": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API.", + "disabled": true + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID.", + "disabled": true + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server.", + "disabled": true + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication", + "disabled": true + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server.", + "disabled": true + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed.", + "disabled": true + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", + "disabled": true + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", + "disabled": true + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App.", + "disabled": true + }, + { + "key": "X-Callback-URL", + "value": "", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT.", + "disabled": true + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header.", + "disabled": true + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header.", + "disabled": true + }, + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Accept", + "value": "application/json", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"payee\": [\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n }\n ],\n \"mandateStatus\": \"active\",\n \"amountLimit\": \"string\",\n \"currency\": \"AED\",\n \"startDate\": \"2018-11-20\",\n \"endDate\": \"2018-11-20\",\n \"frequencyType\": \"weekly\",\n \"numberOfPayments\": 0,\n \"requestingOrganisation\": {\n \"requestingOrganisationIdentifierType\": \"lei\",\n \"requestingOrganisationIdentifier\": \"string\"\n },\n \"requestDate\": \"2022-09-29T00:09:32.272Z\",\n \"customData\": [\n {\n \"key\": \"string\",\n \"value\": \"string\"\n }\n ]\n}" + }, + "url": { + "raw": "{{ChannelGSMAHostName}}/accounts/{{identifierType}}/{{identifier}}/debitmandates", + "host": [ + "{{ChannelGSMAHostName}}" + ], + "path": [ + "accounts", + "{{identifierType}}", + "{{identifier}}", + "debitmandates" + ] + }, + "description": "Provided with a valid object representation, this endpoint allows for a new debit mandate to be created for a specific account." + }, + "response": [ + { + "name": "Represents an Error Caused by System Unavailability", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/debitmandates", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "debitmandates" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + } + ] + } + }, + "status": "Service Unavailable", + "code": 503, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents a Debit Mandate response", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/debitmandates", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "debitmandates" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + } + ] + } + }, + "status": "Created", + "code": 201, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"mandateReference\": \"\",\n \"currency\": \"\",\n \"amountLimit\": \"15.21\",\n \"startDate\": \"2018-11-20\",\n \"endDate\": \"2018-11-20\",\n \"numberOfPayments\": \"\",\n \"frequencyType\": \"\",\n \"mandateStatus\": \"\",\n \"requestDate\": \"\",\n \"creationDate\": \"\",\n \"modificationDate\": \"\",\n \"dateCreated\": \"\",\n \"dateModified\": \"\"\n}" + }, + { + "name": "Represents an Error Caused by an Authorisation Failure", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/debitmandates", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "debitmandates" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + } + ] + } + }, + "status": "Unauthorized", + "code": 401, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by a Failure to Identify the Target Resource", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/debitmandates", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "debitmandates" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + } + ] + } + }, + "status": "Not Found", + "code": 404, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by a General Server-Side Issue", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/debitmandates", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "debitmandates" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + } + ] + } + }, + "status": "Internal Server Error", + "code": 500, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by the Violation of a Business Rule", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/debitmandates", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "debitmandates" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + } + ] + } + }, + "status": "Bad Request", + "code": 400, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Asynchronous response", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/debitmandates", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "debitmandates" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + } + ] + } + }, + "status": "Accepted", + "code": 202, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"notificationMethod\": \"\",\n \"serverCorrelationId\": \"\",\n \"status\": \"\",\n \"pendingReason\": \"\",\n \"objectReference\": \"\",\n \"expiryTime\": \"\",\n \"pollLimit\": \"\",\n \"error\": {\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n }\n}" + } + ] + } + ] + }, + { + "name": "links", + "item": [ + { + "name": "{link Reference}", + "item": [ + { + "name": "View A Link", + "request": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API.", + "disabled": true + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server.", + "disabled": true + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication", + "disabled": true + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server.", + "disabled": true + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed.", + "disabled": true + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", + "disabled": true + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", + "disabled": true + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App.", + "disabled": true + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header.", + "disabled": true + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header.", + "disabled": true + }, + { + "key": "Accept", + "value": "application/json", + "type": "text" + } + ], + "url": { + "raw": "{{ChannelGSMAHostName}}/accounts/{{identifierType}}/{{identifier}}/links/{{linkReference}}", + "host": [ + "{{ChannelGSMAHostName}}" + ], + "path": [ + "accounts", + "{{identifierType}}", + "{{identifier}}", + "links", + "{{linkReference}}" + ] + }, + "description": "This endpoint returns a specific link for a given account." + }, + "response": [ + { + "name": "Represents an Error Caused by System Unavailability", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/links/:linkReference", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "links", + ":linkReference" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + }, + { + "key": "linkReference" + } + ] + } + }, + "status": "Service Unavailable", + "code": 503, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by the Violation of a Business Rule", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/links/:linkReference", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "links", + ":linkReference" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + }, + { + "key": "linkReference" + } + ] + } + }, + "status": "Bad Request", + "code": 400, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents a Link response", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/links/:linkReference", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "links", + ":linkReference" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + }, + { + "key": "linkReference" + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"linkReference\": \"\",\n \"sourceAccountIdentifiers\": [\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n },\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n }\n ],\n \"status\": \"\",\n \"mode\": \"\"\n}" + }, + { + "name": "Represents an Error Caused by a General Server-Side Issue", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/links/:linkReference", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "links", + ":linkReference" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + }, + { + "key": "linkReference" + } + ] + } + }, + "status": "Internal Server Error", + "code": 500, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by a Failure to Identify the Target Resource", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/links/:linkReference", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "links", + ":linkReference" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + }, + { + "key": "linkReference" + } + ] + } + }, + "status": "Not Found", + "code": 404, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by an Authorisation Failure", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/links/:linkReference", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "links", + ":linkReference" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + }, + { + "key": "linkReference" + } + ] + } + }, + "status": "Unauthorized", + "code": 401, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + } + ] + }, + { + "name": "Update A Link", + "request": { + "method": "PATCH", + "header": [ + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID.", + "disabled": true + }, + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API.", + "disabled": true + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server.", + "disabled": true + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication", + "disabled": true + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server.", + "disabled": true + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed.", + "disabled": true + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", + "disabled": true + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", + "disabled": true + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App.", + "disabled": true + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header.", + "disabled": true + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header.", + "disabled": true + }, + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Accept", + "value": "application/json", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "[\n {\n \"op\": \"replace\",\n \"path\": \"string\",\n \"value\": \"string\"\n }\n]" + }, + "url": { + "raw": "{{ChannelGSMAHostName}}/accounts/{{identifierType}}/{{identifier}}/links/{{linkReference}}", + "host": [ + "{{ChannelGSMAHostName}}" + ], + "path": [ + "accounts", + "{{identifierType}}", + "{{identifier}}", + "links", + "{{linkReference}}" + ] + }, + "description": "This endpoint updates a specific link.\"" + }, + "response": [ + { + "name": "Represents an Error Caused by the Violation of a Business Rule", + "originalRequest": { + "method": "PATCH", + "header": [ + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/links/:linkReference", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "links", + ":linkReference" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + }, + { + "key": "linkReference" + } + ] + } + }, + "status": "Bad Request", + "code": 400, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by System Unavailability", + "originalRequest": { + "method": "PATCH", + "header": [ + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/links/:linkReference", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "links", + ":linkReference" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + }, + { + "key": "linkReference" + } + ] + } + }, + "status": "Service Unavailable", + "code": 503, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by a General Server-Side Issue", + "originalRequest": { + "method": "PATCH", + "header": [ + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/links/:linkReference", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "links", + ":linkReference" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + }, + { + "key": "linkReference" + } + ] + } + }, + "status": "Internal Server Error", + "code": 500, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "An empty response is returned for a synchronous successful patch.", + "originalRequest": { + "method": "PATCH", + "header": [ + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/links/:linkReference", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "links", + ":linkReference" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + }, + { + "key": "linkReference" + } + ] + } + }, + "status": "No Content", + "code": 204, + "_postman_previewlanguage": "text", + "header": [ + { + "key": "Content-Type", + "value": "text/plain" + } + ], + "cookie": [], + "body": "" + }, + { + "name": "Represents an Error Caused by a Failure to Identify the Target Resource", + "originalRequest": { + "method": "PATCH", + "header": [ + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/links/:linkReference", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "links", + ":linkReference" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + }, + { + "key": "linkReference" + } + ] + } + }, + "status": "Not Found", + "code": 404, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Asynchronous response", + "originalRequest": { + "method": "PATCH", + "header": [ + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/links/:linkReference", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "links", + ":linkReference" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + }, + { + "key": "linkReference" + } + ] + } + }, + "status": "Accepted", + "code": 202, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"notificationMethod\": \"\",\n \"serverCorrelationId\": \"\",\n \"status\": \"\",\n \"pendingReason\": \"\",\n \"objectReference\": \"\",\n \"expiryTime\": \"\",\n \"pollLimit\": \"\",\n \"error\": {\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n }\n}" + }, + { + "name": "Represents an Error Caused by an Authorisation Failure", + "originalRequest": { + "method": "PATCH", + "header": [ + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/links/:linkReference", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "links", + ":linkReference" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + }, + { + "key": "linkReference" + } + ] + } + }, + "status": "Unauthorized", + "code": 401, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + } + ] + } + ] + }, + { + "name": "Create A Link", + "request": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API.", + "disabled": true + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID.", + "disabled": true + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server.", + "disabled": true + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication", + "disabled": true + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server.", + "disabled": true + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed.", + "disabled": true + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", + "disabled": true + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", + "disabled": true + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App.", + "disabled": true + }, + { + "key": "X-Callback-URL", + "value": "", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT.", + "disabled": true + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header.", + "disabled": true + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header.", + "disabled": true + }, + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Accept", + "value": "application/json", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"sourceAccountIdentifiers\": [\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n }\n ],\n \"mode\": \"push\",\n \"status\": \"active\",\n \"requestingOrganisation\": {\n \"requestingOrganisationIdentifierType\": \"lei\",\n \"requestingOrganisationIdentifier\": \"string\"\n },\n \"requestDate\": \"2022-09-29T00:15:03.101Z\",\n \"customData\": [\n {\n \"key\": \"string\",\n \"value\": \"string\"\n }\n ]\n}" + }, + "url": { + "raw": "{{ChannelGSMAHostName}}/accounts/{{identifierType}}/{{identifier}}/links", + "host": [ + "{{ChannelGSMAHostName}}" + ], + "path": [ + "accounts", + "{{identifierType}}", + "{{identifier}}", + "links" + ] + }, + "description": "Provided with a valid object representation, this endpoint allows a new link to be created for a specific account." + }, + "response": [ + { + "name": "Represents an Asynchronous response", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/links", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "links" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + } + ] + } + }, + "status": "Accepted", + "code": 202, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"notificationMethod\": \"\",\n \"serverCorrelationId\": \"\",\n \"status\": \"\",\n \"pendingReason\": \"\",\n \"objectReference\": \"\",\n \"expiryTime\": \"\",\n \"pollLimit\": \"\",\n \"error\": {\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n }\n}" + }, + { + "name": "Represents an Error Caused by the Violation of a Business Rule", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/links", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "links" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + } + ] + } + }, + "status": "Bad Request", + "code": 400, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by System Unavailability", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/links", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "links" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + } + ] + } + }, + "status": "Service Unavailable", + "code": 503, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents a Link response", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/links", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "links" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + } + ] + } + }, + "status": "Created", + "code": 201, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"linkReference\": \"\",\n \"sourceAccountIdentifiers\": [\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n },\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n }\n ],\n \"status\": \"\",\n \"mode\": \"\"\n}" + }, + { + "name": "Represents an Error Caused by a Failure to Identify the Target Resource", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/links", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "links" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + } + ] + } + }, + "status": "Not Found", + "code": 404, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by a General Server-Side Issue", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/links", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "links" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + } + ] + } + }, + "status": "Internal Server Error", + "code": 500, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by an Authorisation Failure", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/links", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "links" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + } + ] + } + }, + "status": "Unauthorized", + "code": 401, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + } + ] + } + ] + }, + { + "name": "authorisationcodes", + "item": [ + { + "name": "{authorisation Code}", + "item": [ + { + "name": "View an Authorisation Code", + "request": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API.", + "disabled": true + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server.", + "disabled": true + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication", + "disabled": true + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server.", + "disabled": true + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed.", + "disabled": true + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", + "disabled": true + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", + "disabled": true + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App.", + "disabled": true + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header.", + "disabled": true + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header.", + "disabled": true + }, + { + "key": "Accept", + "value": "application/json", + "type": "text" + } + ], + "url": { + "raw": "{{ChannelGSMAHostName}}/accounts/{{identifierType}}/{{identifier}}/authorisationcodes/{{authorisationCode}}", + "host": [ + "{{ChannelGSMAHostName}}" + ], + "path": [ + "accounts", + "{{identifierType}}", + "{{identifier}}", + "authorisationcodes", + "{{authorisationCode}}" + ] + }, + "description": "This endpoint returns a specific Authorisation Code linked to an account." + }, + "response": [ + { + "name": "Represents an Error Caused by a General Server-Side Issue", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/authorisationcodes/:authorisationCode", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "authorisationcodes", + ":authorisationCode" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + }, + { + "key": "authorisationCode" + } + ] + } + }, + "status": "Internal Server Error", + "code": 500, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by the Violation of a Business Rule", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/authorisationcodes/:authorisationCode", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "authorisationcodes", + ":authorisationCode" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + }, + { + "key": "authorisationCode" + } + ] + } + }, + "status": "Bad Request", + "code": 400, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by a Failure to Identify the Target Resource", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/authorisationcodes/:authorisationCode", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "authorisationcodes", + ":authorisationCode" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + }, + { + "key": "authorisationCode" + } + ] + } + }, + "status": "Not Found", + "code": 404, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by System Unavailability", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/authorisationcodes/:authorisationCode", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "authorisationcodes", + ":authorisationCode" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + }, + { + "key": "authorisationCode" + } + ] + } + }, + "status": "Service Unavailable", + "code": 503, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Authorisation Code response", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/authorisationcodes/:authorisationCode", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "authorisationcodes", + ":authorisationCode" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + }, + { + "key": "authorisationCode" + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"authorisationCode\": \"\",\n \"codeState\": \"\",\n \"codeLifetime\": \"\",\n \"requestDate\": \"\",\n \"amount\": \"15.21\",\n \"currency\": \"\",\n \"amountType\": \"\",\n \"holdFundsIndicator\": \"\",\n \"redemptionChannels\": [\n {\n \"channelType\": \"\"\n },\n {\n \"channelType\": \"\"\n }\n ],\n \"redemptionTransactionTypes\": [\n {\n \"transactionType\": \"\",\n \"transactionSubtype\": \"\"\n },\n {\n \"transactionType\": \"\",\n \"transactionSubtype\": \"\"\n }\n ],\n \"redemptionAccountIdentifiers\": [\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n },\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n }\n ],\n \"metadata\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by an Authorisation Failure", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/authorisationcodes/:authorisationCode", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "authorisationcodes", + ":authorisationCode" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + }, + { + "key": "authorisationCode" + } + ] + } + }, + "status": "Unauthorized", + "code": 401, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + } + ] + }, + { + "name": "Cancel an Authorisation Code", + "request": { + "method": "PATCH", + "header": [ + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID.", + "disabled": true + }, + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API.", + "disabled": true + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server.", + "disabled": true + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication", + "disabled": true + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server.", + "disabled": true + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed.", + "disabled": true + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", + "disabled": true + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", + "disabled": true + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App.", + "disabled": true + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header.", + "disabled": true + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header.", + "disabled": true + }, + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Accept", + "value": "application/json", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "[\n {\n \"op\": \"replace\",\n \"path\": \"string\",\n \"value\": \"string\"\n }\n]" + }, + "url": { + "raw": "{{ChannelGSMAHostName}}/accounts/{{identifierType}}/{{identifier}}/authorisationcodes/{{authorisationCode}}", + "host": [ + "{{ChannelGSMAHostName}}" + ], + "path": [ + "accounts", + "{{identifierType}}", + "{{identifier}}", + "authorisationcodes", + "{{authorisationCode}}" + ] + }, + "description": "This endpoint cancels a specific authorisation code linked to an account." + }, + "response": [ + { + "name": "Represents an Error Caused by a Failure to Identify the Target Resource", + "originalRequest": { + "method": "PATCH", + "header": [ + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/authorisationcodes/:authorisationCode", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "authorisationcodes", + ":authorisationCode" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + }, + { + "key": "authorisationCode" + } + ] + } + }, + "status": "Not Found", + "code": 404, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by a General Server-Side Issue", + "originalRequest": { + "method": "PATCH", + "header": [ + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/authorisationcodes/:authorisationCode", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "authorisationcodes", + ":authorisationCode" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + }, + { + "key": "authorisationCode" + } + ] + } + }, + "status": "Internal Server Error", + "code": 500, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by the Violation of a Business Rule", + "originalRequest": { + "method": "PATCH", + "header": [ + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/authorisationcodes/:authorisationCode", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "authorisationcodes", + ":authorisationCode" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + }, + { + "key": "authorisationCode" + } + ] + } + }, + "status": "Bad Request", + "code": 400, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by an Authorisation Failure", + "originalRequest": { + "method": "PATCH", + "header": [ + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/authorisationcodes/:authorisationCode", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "authorisationcodes", + ":authorisationCode" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + }, + { + "key": "authorisationCode" + } + ] + } + }, + "status": "Unauthorized", + "code": 401, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by System Unavailability", + "originalRequest": { + "method": "PATCH", + "header": [ + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/authorisationcodes/:authorisationCode", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "authorisationcodes", + ":authorisationCode" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + }, + { + "key": "authorisationCode" + } + ] + } + }, + "status": "Service Unavailable", + "code": 503, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Asynchronous response", + "originalRequest": { + "method": "PATCH", + "header": [ + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/authorisationcodes/:authorisationCode", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "authorisationcodes", + ":authorisationCode" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + }, + { + "key": "authorisationCode" + } + ] + } + }, + "status": "Accepted", + "code": 202, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"notificationMethod\": \"\",\n \"serverCorrelationId\": \"\",\n \"status\": \"\",\n \"pendingReason\": \"\",\n \"objectReference\": \"\",\n \"expiryTime\": \"\",\n \"pollLimit\": \"\",\n \"error\": {\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n }\n}" + }, + { + "name": "An empty response is returned for a synchronous successful patch.", + "originalRequest": { + "method": "PATCH", + "header": [ + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/authorisationcodes/:authorisationCode", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "authorisationcodes", + ":authorisationCode" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + }, + { + "key": "authorisationCode" + } + ] + } + }, + "status": "No Content", + "code": 204, + "_postman_previewlanguage": "text", + "header": [ + { + "key": "Content-Type", + "value": "text/plain" + } + ], + "cookie": [], + "body": "" + } + ] + } + ] + }, + { + "name": "Create an Authorisation Code via an account identifier.", + "request": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API.", + "disabled": true + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID.", + "disabled": true + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server.", + "disabled": true + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication", + "disabled": true + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server.", + "disabled": true + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed.", + "disabled": true + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", + "disabled": true + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", + "disabled": true + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App.", + "disabled": true + }, + { + "key": "X-Callback-URL", + "value": "", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT.", + "disabled": true + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header.", + "disabled": true + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header.", + "disabled": true + }, + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Accept", + "value": "application/json", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"authorisationCode\": \"string\",\n \"codeState\": \"active\",\n \"amount\": \"15.21\",\n \"currency\": \"AED\",\n \"amountType\": \"exact\",\n \"codeLifetime\": 600,\n \"holdFundsIndicator\": true,\n \"redemptionAccountIdentifiers\": [\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n }\n ],\n \"redemptionChannels\": [\n {\n \"channelType\": \"string\"\n }\n ],\n \"redemptionTransactionTypes\": [\n {\n \"transactionType\": \"billpay\",\n \"transactionSubtype\": \"string\"\n }\n ],\n \"requestingOrganisation\": {\n \"requestingOrganisationIdentifierType\": \"lei\",\n \"requestingOrganisationIdentifier\": \"string\"\n },\n \"creationDate\": \"2022-09-29T00:20:36.540Z\",\n \"modificationDate\": \"2022-09-29T00:20:36.540Z\",\n \"requestDate\": \"2022-09-29T00:20:36.540Z\",\n \"customData\": [\n {\n \"key\": \"string\",\n \"value\": \"string\"\n }\n ],\n \"metadata\": [\n {\n \"key\": \"string\",\n \"value\": \"string\"\n }\n ]\n}" + }, + "url": { + "raw": "{{ChannelGSMAHostName}}/accounts/{{identifierType}}/{{identifier}}/authorisationcodes", + "host": [ + "{{ChannelGSMAHostName}}" + ], + "path": [ + "accounts", + "{{identifierType}}", + "{{identifier}}", + "authorisationcodes" + ] + }, + "description": "This endpoint allows allows a mobile money payer or payee to generate a code which when presented to the other party, can be redeemed for an amount set by the payer or payee, depending upon the use case." + }, + "response": [ + { + "name": "Represents an Error Caused by System Unavailability", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/authorisationcodes", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "authorisationcodes" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + } + ] + } + }, + "status": "Service Unavailable", + "code": 503, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by the Violation of a Business Rule", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/authorisationcodes", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "authorisationcodes" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + } + ] + } + }, + "status": "Bad Request", + "code": 400, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Authorisation Code response", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/authorisationcodes", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "authorisationcodes" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + } + ] + } + }, + "status": "Created", + "code": 201, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"authorisationCode\": \"\",\n \"codeState\": \"\",\n \"codeLifetime\": \"\",\n \"requestDate\": \"\",\n \"amount\": \"15.21\",\n \"currency\": \"\",\n \"amountType\": \"\",\n \"holdFundsIndicator\": \"\",\n \"redemptionChannels\": [\n {\n \"channelType\": \"\"\n },\n {\n \"channelType\": \"\"\n }\n ],\n \"redemptionTransactionTypes\": [\n {\n \"transactionType\": \"\",\n \"transactionSubtype\": \"\"\n },\n {\n \"transactionType\": \"\",\n \"transactionSubtype\": \"\"\n }\n ],\n \"redemptionAccountIdentifiers\": [\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n },\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n }\n ],\n \"metadata\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by a General Server-Side Issue", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/authorisationcodes", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "authorisationcodes" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + } + ] + } + }, + "status": "Internal Server Error", + "code": 500, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Asynchronous response", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/authorisationcodes", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "authorisationcodes" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + } + ] + } + }, + "status": "Accepted", + "code": 202, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"notificationMethod\": \"\",\n \"serverCorrelationId\": \"\",\n \"status\": \"\",\n \"pendingReason\": \"\",\n \"objectReference\": \"\",\n \"expiryTime\": \"\",\n \"pollLimit\": \"\",\n \"error\": {\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n }\n}" + }, + { + "name": "Represents an Error Caused by an Authorisation Failure", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/authorisationcodes", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "authorisationcodes" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + } + ] + } + }, + "status": "Unauthorized", + "code": 401, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by a Failure to Identify the Target Resource", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/authorisationcodes", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "authorisationcodes" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + } + ] + } + }, + "status": "Not Found", + "code": 404, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + } + ] + } + ] + }, + { + "name": "View Account Status", + "request": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API.", + "disabled": true + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server.", + "disabled": true + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication", + "disabled": true + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server.", + "disabled": true + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed.", + "disabled": true + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", + "disabled": true + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", + "disabled": true + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App.", + "disabled": true + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header.", + "disabled": true + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header.", + "disabled": true + }, + { + "key": "Accept", + "value": "application/json", + "type": "text" + } + ], + "url": { + "raw": "{{ChannelGSMAHostName}}/accounts/{{identifierType}}/{{identifier}}/status", + "host": [ + "{{ChannelGSMAHostName}}" + ], + "path": [ + "accounts", + "{{identifierType}}", + "{{identifier}}", + "status" + ] + }, + "description": "This endpoint returns the current status of an account." + }, + "response": [ + { + "name": "Represents an Error Caused by an Authorisation Failure", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/status", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "status" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + } + ] + } + }, + "status": "Unauthorized", + "code": 401, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by a Failure to Identify the Target Resource", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/status", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "status" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + } + ] + } + }, + "status": "Not Found", + "code": 404, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Account Status response", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/status", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "status" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"accountStatus\": \"\",\n \"subStatus\": \"\",\n \"lei\": \"5493000IBP32UQZ0KL24\"\n}" + }, + { + "name": "Represents an Error Caused by a General Server-Side Issue", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/status", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "status" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + } + ] + } + }, + "status": "Internal Server Error", + "code": 500, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by the Violation of a Business Rule", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/status", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "status" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + } + ] + } + }, + "status": "Bad Request", + "code": 400, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by System Unavailability", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/status", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "status" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + } + ] + } + }, + "status": "Service Unavailable", + "code": 503, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + } + ] + }, + { + "name": "View Account Name", + "request": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API.", + "disabled": true + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server.", + "disabled": true + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication", + "disabled": true + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server.", + "disabled": true + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed.", + "disabled": true + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", + "disabled": true + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", + "disabled": true + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App.", + "disabled": true + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header.", + "disabled": true + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header.", + "disabled": true + }, + { + "key": "Accept", + "value": "application/json", + "type": "text" + } + ], + "url": { + "raw": "{{ChannelGSMAHostName}}/accounts/{{identifierType}}/{{identifier}}/accountname", + "host": [ + "{{ChannelGSMAHostName}}" + ], + "path": [ + "accounts", + "{{identifierType}}", + "{{identifier}}", + "accountname" + ] + }, + "description": "This endpoint returns the name of an account holder." + }, + "response": [ + { + "name": "Represents an Error Caused by an Authorisation Failure", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/accountname", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "accountname" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + } + ] + } + }, + "status": "Unauthorized", + "code": 401, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by the Violation of a Business Rule", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/accountname", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "accountname" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + } + ] + } + }, + "status": "Bad Request", + "code": 400, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by a General Server-Side Issue", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/accountname", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "accountname" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + } + ] + } + }, + "status": "Internal Server Error", + "code": 500, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by System Unavailability", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/accountname", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "accountname" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + } + ] + } + }, + "status": "Service Unavailable", + "code": 503, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by a Failure to Identify the Target Resource", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/accountname", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "accountname" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + } + ] + } + }, + "status": "Not Found", + "code": 404, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Account Name response", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/accountname", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "accountname" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"name\": {\n \"title\": \"\",\n \"firstName\": \"\",\n \"middleName\": \"\",\n \"lastName\": \"\",\n \"fullName\": \"\",\n \"nativeName\": \"\"\n },\n \"lei\": \"5493000IBP32UQZ0KL24\"\n}" + } + ] + }, + { + "name": "View Account Balance", + "request": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API.", + "disabled": true + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server.", + "disabled": true + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication", + "disabled": true + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server.", + "disabled": true + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed.", + "disabled": true + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", + "disabled": true + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", + "disabled": true + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App.", + "disabled": true + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header.", + "disabled": true + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header.", + "disabled": true + }, + { + "key": "Accept", + "value": "application/json", + "type": "text" + } + ], + "url": { + "raw": "{{ChannelGSMAHostName}}/accounts/{{identifierType}}/{{identifier}}/balance", + "host": [ + "{{ChannelGSMAHostName}}" + ], + "path": [ + "accounts", + "{{identifierType}}", + "{{identifier}}", + "balance" + ] + }, + "description": "This endpoint returns the balance of an account." + }, + "response": [ + { + "name": "Represents an Error Caused by System Unavailability", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/balance", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "balance" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + } + ] + } + }, + "status": "Service Unavailable", + "code": 503, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by a General Server-Side Issue", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/balance", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "balance" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + } + ] + } + }, + "status": "Internal Server Error", + "code": 500, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Account Balance response", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/balance", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "balance" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"currentBalance\": \"15.21\",\n \"availableBalance\": \"15.21\",\n \"reservedBalance\": \"15.21\",\n \"unclearedBalance\": \"15.21\",\n \"currency\": \"\",\n \"accountStatus\": \"\"\n}" + }, + { + "name": "Represents an Error Caused by an Authorisation Failure", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/balance", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "balance" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + } + ] + } + }, + "status": "Unauthorized", + "code": 401, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by the Violation of a Business Rule", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/balance", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "balance" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + } + ] + } + }, + "status": "Bad Request", + "code": 400, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by a Failure to Identify the Target Resource", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/balance", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "balance" + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + } + ] + } + }, + "status": "Not Found", + "code": 404, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + } + ] + }, + { + "name": "View Account Specific Transaction", + "request": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API.", + "disabled": true + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server.", + "disabled": true + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication", + "disabled": true + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server.", + "disabled": true + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed.", + "disabled": true + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", + "disabled": true + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", + "disabled": true + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App.", + "disabled": true + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header.", + "disabled": true + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header.", + "disabled": true + }, + { + "key": "Accept", + "value": "application/json", + "type": "text" + } + ], + "url": { + "raw": "{{ChannelGSMAHostName}}/accounts/{{identifierType}}/{{identifier}}/transactions", + "host": [ + "{{ChannelGSMAHostName}}" + ], + "path": [ + "accounts", + "{{identifierType}}", + "{{identifier}}", + "transactions" + ], + "query": [ + { + "key": "limit", + "value": "", + "description": "Supports pagination. If this is not supplied, then the server will apply a limit of 50 records returned for each request.", + "disabled": true + }, + { + "key": "offset", + "value": "", + "description": "Supports pagination. This value will indicate the cursor position from where to retrieve the set of records. For example, a limit of 50 and offset of 10 will return records 11 to 60.", + "disabled": true + }, + { + "key": "fromDateTime", + "value": "", + "description": "Indicates the minimum date for which records should be returned.", + "disabled": true + }, + { + "key": "toDateTime", + "value": "", + "description": "Indicates the maximum date for which records should be returned.", + "disabled": true + }, + { + "key": "transactionStatus", + "value": "", + "description": "Query variable to uniquely identify the transaction status.", + "disabled": true + }, + { + "key": "transactionType", + "value": "", + "description": "Identifies the type of transaction.", + "disabled": true + } + ] + }, + "description": "This endpoint returns transactions linked to a specific account." + }, + "response": [ + { + "name": "Represents an Error Caused by the Violation of a Business Rule", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/transactions?limit=&offset=&fromDateTime=&toDateTime=&transactionStatus=&transactionType=", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "transactions" + ], + "query": [ + { + "key": "limit", + "value": "" + }, + { + "key": "offset", + "value": "" + }, + { + "key": "fromDateTime", + "value": "" + }, + { + "key": "toDateTime", + "value": "" + }, + { + "key": "transactionStatus", + "value": "" + }, + { + "key": "transactionType", + "value": "" + } + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + } + ] + } + }, + "status": "Bad Request", + "code": 400, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represent a list of Transactions", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/transactions?limit=&offset=&fromDateTime=&toDateTime=&transactionStatus=&transactionType=", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "transactions" + ], + "query": [ + { + "key": "limit", + "value": "" + }, + { + "key": "offset", + "value": "" + }, + { + "key": "fromDateTime", + "value": "" + }, + { + "key": "toDateTime", + "value": "" + }, + { + "key": "transactionStatus", + "value": "" + }, + { + "key": "transactionType", + "value": "" + } + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "X-Records-Available-Count", + "value": "", + "description": "Integer containing number of records that are available to be returned." + }, + { + "key": "X-Records-Returned-Count", + "value": "", + "description": "Integer containing number of records that are returned." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "[\n {\n \"amount\": \"15.21\",\n \"currency\": \"\",\n \"type\": \"\",\n \"transactionReference\": \"\",\n \"transactionStatus\": \"\",\n \"debitParty\": [\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n },\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n }\n ],\n \"creditParty\": [\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n },\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n }\n ],\n \"subType\": \"\",\n \"descriptionText\": \"\",\n \"requestDate\": \"\",\n \"requestingOrganisationTransactionReference\": \"\",\n \"oneTimeCode\": \"\",\n \"geoCode\": \"37.423825,-122.082900\",\n \"senderKyc\": {\n \"nationality\": \"\",\n \"dateOfBirth\": \"2000-11-20\",\n \"occupation\": \"\",\n \"employerName\": \"\",\n \"contactPhone\": \"\",\n \"gender\": \"\",\n \"idDocument\": [\n {\n \"idType\": \"\",\n \"idNumber\": \"\",\n \"issueDate\": \"2018-11-20\",\n \"expiryDate\": \"2018-11-20\",\n \"issuer\": \"\",\n \"issuerPlace\": \"\",\n \"issuerCountry\": \"\",\n \"otherIddescription\": \"\"\n },\n {\n \"idType\": \"\",\n \"idNumber\": \"\",\n \"issueDate\": \"2018-11-20\",\n \"expiryDate\": \"2018-11-20\",\n \"issuer\": \"\",\n \"issuerPlace\": \"\",\n \"issuerCountry\": \"\",\n \"otherIddescription\": \"\"\n }\n ],\n \"postalAddress\": {\n \"country\": \"\",\n \"addressLine1\": \"\",\n \"addressLine2\": \"\",\n \"addressLine3\": \"\",\n \"city\": \"\",\n \"stateProvince\": \"\",\n \"postalCode\": \"\"\n },\n \"subjectName\": {\n \"title\": \"\",\n \"firstName\": \"\",\n \"middleName\": \"\",\n \"lastName\": \"\",\n \"fullName\": \"\",\n \"nativeName\": \"\"\n },\n \"emailAddress\": \"\",\n \"birthCountry\": \"\"\n },\n \"recipientKyc\": {\n \"nationality\": \"\",\n \"dateOfBirth\": \"2000-11-20\",\n \"occupation\": \"\",\n \"employerName\": \"\",\n \"contactPhone\": \"\",\n \"gender\": \"\",\n \"idDocument\": [\n {\n \"idType\": \"\",\n \"idNumber\": \"\",\n \"issueDate\": \"2018-11-20\",\n \"expiryDate\": \"2018-11-20\",\n \"issuer\": \"\",\n \"issuerPlace\": \"\",\n \"issuerCountry\": \"\",\n \"otherIddescription\": \"\"\n },\n {\n \"idType\": \"\",\n \"idNumber\": \"\",\n \"issueDate\": \"2018-11-20\",\n \"expiryDate\": \"2018-11-20\",\n \"issuer\": \"\",\n \"issuerPlace\": \"\",\n \"issuerCountry\": \"\",\n \"otherIddescription\": \"\"\n }\n ],\n \"postalAddress\": {\n \"country\": \"\",\n \"addressLine1\": \"\",\n \"addressLine2\": \"\",\n \"addressLine3\": \"\",\n \"city\": \"\",\n \"stateProvince\": \"\",\n \"postalCode\": \"\"\n },\n \"subjectName\": {\n \"title\": \"\",\n \"firstName\": \"\",\n \"middleName\": \"\",\n \"lastName\": \"\",\n \"fullName\": \"\",\n \"nativeName\": \"\"\n },\n \"emailAddress\": \"\",\n \"birthCountry\": \"\"\n },\n \"originalTransactionReference\": \"\",\n \"servicingIdentity\": \"\",\n \"fees\": [\n {\n \"feeType\": \"\",\n \"feeCurrency\": \"\",\n \"feeAmount\": \"15.21\"\n },\n {\n \"feeType\": \"\",\n \"feeCurrency\": \"\",\n \"feeAmount\": \"15.21\"\n }\n ],\n \"requestingLei\": \"54930084UKLVMY22DS16\",\n \"receivingLei\": \"5493000IBP32UQZ0KL24\",\n \"metadata\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ],\n \"creationDate\": \"\",\n \"modificationDate\": \"\",\n \"dateCreated\": \"\",\n \"dateModified\": \"\",\n \"transactionReceipt\": \"\",\n \"internationalTransferInformation\": {\n \"originCountry\": \"\",\n \"quotationReference\": \"\",\n \"quoteId\": \"\",\n \"receivingCountry\": \"\",\n \"remittancePurpose\": \"\",\n \"relationshipSender\": \"\",\n \"deliveryMethod\": \"\",\n \"senderBlockingReason\": \"\",\n \"recipientBlockingReason\": \"\"\n }\n },\n {\n \"amount\": \"15.21\",\n \"currency\": \"\",\n \"type\": \"\",\n \"transactionReference\": \"\",\n \"transactionStatus\": \"\",\n \"debitParty\": [\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n },\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n }\n ],\n \"creditParty\": [\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n },\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n }\n ],\n \"subType\": \"\",\n \"descriptionText\": \"\",\n \"requestDate\": \"\",\n \"requestingOrganisationTransactionReference\": \"\",\n \"oneTimeCode\": \"\",\n \"geoCode\": \"37.423825,-122.082900\",\n \"senderKyc\": {\n \"nationality\": \"\",\n \"dateOfBirth\": \"2000-11-20\",\n \"occupation\": \"\",\n \"employerName\": \"\",\n \"contactPhone\": \"\",\n \"gender\": \"\",\n \"idDocument\": [\n {\n \"idType\": \"\",\n \"idNumber\": \"\",\n \"issueDate\": \"2018-11-20\",\n \"expiryDate\": \"2018-11-20\",\n \"issuer\": \"\",\n \"issuerPlace\": \"\",\n \"issuerCountry\": \"\",\n \"otherIddescription\": \"\"\n },\n {\n \"idType\": \"\",\n \"idNumber\": \"\",\n \"issueDate\": \"2018-11-20\",\n \"expiryDate\": \"2018-11-20\",\n \"issuer\": \"\",\n \"issuerPlace\": \"\",\n \"issuerCountry\": \"\",\n \"otherIddescription\": \"\"\n }\n ],\n \"postalAddress\": {\n \"country\": \"\",\n \"addressLine1\": \"\",\n \"addressLine2\": \"\",\n \"addressLine3\": \"\",\n \"city\": \"\",\n \"stateProvince\": \"\",\n \"postalCode\": \"\"\n },\n \"subjectName\": {\n \"title\": \"\",\n \"firstName\": \"\",\n \"middleName\": \"\",\n \"lastName\": \"\",\n \"fullName\": \"\",\n \"nativeName\": \"\"\n },\n \"emailAddress\": \"\",\n \"birthCountry\": \"\"\n },\n \"recipientKyc\": {\n \"nationality\": \"\",\n \"dateOfBirth\": \"2000-11-20\",\n \"occupation\": \"\",\n \"employerName\": \"\",\n \"contactPhone\": \"\",\n \"gender\": \"\",\n \"idDocument\": [\n {\n \"idType\": \"\",\n \"idNumber\": \"\",\n \"issueDate\": \"2018-11-20\",\n \"expiryDate\": \"2018-11-20\",\n \"issuer\": \"\",\n \"issuerPlace\": \"\",\n \"issuerCountry\": \"\",\n \"otherIddescription\": \"\"\n },\n {\n \"idType\": \"\",\n \"idNumber\": \"\",\n \"issueDate\": \"2018-11-20\",\n \"expiryDate\": \"2018-11-20\",\n \"issuer\": \"\",\n \"issuerPlace\": \"\",\n \"issuerCountry\": \"\",\n \"otherIddescription\": \"\"\n }\n ],\n \"postalAddress\": {\n \"country\": \"\",\n \"addressLine1\": \"\",\n \"addressLine2\": \"\",\n \"addressLine3\": \"\",\n \"city\": \"\",\n \"stateProvince\": \"\",\n \"postalCode\": \"\"\n },\n \"subjectName\": {\n \"title\": \"\",\n \"firstName\": \"\",\n \"middleName\": \"\",\n \"lastName\": \"\",\n \"fullName\": \"\",\n \"nativeName\": \"\"\n },\n \"emailAddress\": \"\",\n \"birthCountry\": \"\"\n },\n \"originalTransactionReference\": \"\",\n \"servicingIdentity\": \"\",\n \"fees\": [\n {\n \"feeType\": \"\",\n \"feeCurrency\": \"\",\n \"feeAmount\": \"15.21\"\n },\n {\n \"feeType\": \"\",\n \"feeCurrency\": \"\",\n \"feeAmount\": \"15.21\"\n }\n ],\n \"requestingLei\": \"54930084UKLVMY22DS16\",\n \"receivingLei\": \"5493000IBP32UQZ0KL24\",\n \"metadata\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ],\n \"creationDate\": \"\",\n \"modificationDate\": \"\",\n \"dateCreated\": \"\",\n \"dateModified\": \"\",\n \"transactionReceipt\": \"\",\n \"internationalTransferInformation\": {\n \"originCountry\": \"\",\n \"quotationReference\": \"\",\n \"quoteId\": \"\",\n \"receivingCountry\": \"\",\n \"remittancePurpose\": \"\",\n \"relationshipSender\": \"\",\n \"deliveryMethod\": \"\",\n \"senderBlockingReason\": \"\",\n \"recipientBlockingReason\": \"\"\n }\n }\n]" + }, + { + "name": "Represents an Error Caused by System Unavailability", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/transactions?limit=&offset=&fromDateTime=&toDateTime=&transactionStatus=&transactionType=", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "transactions" + ], + "query": [ + { + "key": "limit", + "value": "" + }, + { + "key": "offset", + "value": "" + }, + { + "key": "fromDateTime", + "value": "" + }, + { + "key": "toDateTime", + "value": "" + }, + { + "key": "transactionStatus", + "value": "" + }, + { + "key": "transactionType", + "value": "" + } + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + } + ] + } + }, + "status": "Service Unavailable", + "code": 503, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by an Authorisation Failure", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/transactions?limit=&offset=&fromDateTime=&toDateTime=&transactionStatus=&transactionType=", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "transactions" + ], + "query": [ + { + "key": "limit", + "value": "" + }, + { + "key": "offset", + "value": "" + }, + { + "key": "fromDateTime", + "value": "" + }, + { + "key": "toDateTime", + "value": "" + }, + { + "key": "transactionStatus", + "value": "" + }, + { + "key": "transactionType", + "value": "" + } + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + } + ] + } + }, + "status": "Unauthorized", + "code": 401, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by a General Server-Side Issue", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/transactions?limit=&offset=&fromDateTime=&toDateTime=&transactionStatus=&transactionType=", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "transactions" + ], + "query": [ + { + "key": "limit", + "value": "" + }, + { + "key": "offset", + "value": "" + }, + { + "key": "fromDateTime", + "value": "" + }, + { + "key": "toDateTime", + "value": "" + }, + { + "key": "transactionStatus", + "value": "" + }, + { + "key": "transactionType", + "value": "" + } + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + } + ] + } + }, + "status": "Internal Server Error", + "code": 500, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by a Failure to Identify the Target Resource", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/transactions?limit=&offset=&fromDateTime=&toDateTime=&transactionStatus=&transactionType=", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "transactions" + ], + "query": [ + { + "key": "limit", + "value": "" + }, + { + "key": "offset", + "value": "" + }, + { + "key": "fromDateTime", + "value": "" + }, + { + "key": "toDateTime", + "value": "" + }, + { + "key": "transactionStatus", + "value": "" + }, + { + "key": "transactionType", + "value": "" + } + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + } + ] + } + }, + "status": "Not Found", + "code": 404, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + } + ] + }, + { + "name": "View Account Statements", + "request": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API.", + "disabled": true + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server.", + "disabled": true + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication", + "disabled": true + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server.", + "disabled": true + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed.", + "disabled": true + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", + "disabled": true + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", + "disabled": true + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App.", + "disabled": true + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header.", + "disabled": true + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header.", + "disabled": true + }, + { + "key": "Accept", + "value": "application/json", + "type": "text" + } + ], + "url": { + "raw": "{{ChannelGSMAHostName}}/accounts/{{identifierType}}/{{identifier}}/statemententries", + "host": [ + "{{ChannelGSMAHostName}}" + ], + "path": [ + "accounts", + "{{identifierType}}", + "{{identifier}}", + "statemententries" + ], + "query": [ + { + "key": "limit", + "value": "", + "description": "Supports pagination. If this is not supplied, then the server will apply a limit of 50 records returned for each request.", + "disabled": true + }, + { + "key": "offset", + "value": "", + "description": "Supports pagination. This value will indicate the cursor position from where to retrieve the set of records. For example, a limit of 50 and offset of 10 will return records 11 to 60.", + "disabled": true + }, + { + "key": "fromDateTime", + "value": "", + "description": "Indicates the minimum date for which records should be returned.", + "disabled": true + }, + { + "key": "toDateTime", + "value": "", + "description": "Indicates the maximum date for which records should be returned.", + "disabled": true + }, + { + "key": "transactionStatus", + "value": "", + "description": "Query variable to uniquely identify the transaction status.", + "disabled": true + }, + { + "key": "displayType", + "value": "", + "description": "Query parameter to to identify the display type of the statement entries to be returned.", + "disabled": true + } + ] + }, + "description": "The Statement Entries API enables generic representations of transactions to be returned. Typically, the returned representations are used for the purposes of presenting a statement to the account holder. In order to return a statement, an account must be specified." + }, + "response": [ + { + "name": "Represent a list of Statement Entries", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/statemententries?limit=&offset=&fromDateTime=&toDateTime=&transactionStatus=&displayType=", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "statemententries" + ], + "query": [ + { + "key": "limit", + "value": "" + }, + { + "key": "offset", + "value": "" + }, + { + "key": "fromDateTime", + "value": "" + }, + { + "key": "toDateTime", + "value": "" + }, + { + "key": "transactionStatus", + "value": "" + }, + { + "key": "displayType", + "value": "" + } + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "X-Records-Available-Count", + "value": "", + "description": "Integer containing number of records that are available to be returned." + }, + { + "key": "X-Records-Returned-Count", + "value": "", + "description": "Integer containing number of records that are returned." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "[\n {\n \"amount\": \"15.21\",\n \"creditParty\": [\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n },\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n }\n ],\n \"currency\": \"\",\n \"debitParty\": [\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n },\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n }\n ],\n \"transactionReference\": \"\",\n \"transactionStatus\": \"\",\n \"displayType\": \"\",\n \"descriptionText\": \"\",\n \"requestDate\": \"\",\n \"creationDate\": \"\",\n \"modificationDate\": \"\",\n \"dateCreated\": \"\",\n \"dateModified\": \"\",\n \"transactionReceipt\": \"\"\n },\n {\n \"amount\": \"15.21\",\n \"creditParty\": [\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n },\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n }\n ],\n \"currency\": \"\",\n \"debitParty\": [\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n },\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n }\n ],\n \"transactionReference\": \"\",\n \"transactionStatus\": \"\",\n \"displayType\": \"\",\n \"descriptionText\": \"\",\n \"requestDate\": \"\",\n \"creationDate\": \"\",\n \"modificationDate\": \"\",\n \"dateCreated\": \"\",\n \"dateModified\": \"\",\n \"transactionReceipt\": \"\"\n }\n]" + }, + { + "name": "Represents an Error Caused by a Failure to Identify the Target Resource", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/statemententries?limit=&offset=&fromDateTime=&toDateTime=&transactionStatus=&displayType=", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "statemententries" + ], + "query": [ + { + "key": "limit", + "value": "" + }, + { + "key": "offset", + "value": "" + }, + { + "key": "fromDateTime", + "value": "" + }, + { + "key": "toDateTime", + "value": "" + }, + { + "key": "transactionStatus", + "value": "" + }, + { + "key": "displayType", + "value": "" + } + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + } + ] + } + }, + "status": "Not Found", + "code": 404, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by the Violation of a Business Rule", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/statemententries?limit=&offset=&fromDateTime=&toDateTime=&transactionStatus=&displayType=", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "statemententries" + ], + "query": [ + { + "key": "limit", + "value": "" + }, + { + "key": "offset", + "value": "" + }, + { + "key": "fromDateTime", + "value": "" + }, + { + "key": "toDateTime", + "value": "" + }, + { + "key": "transactionStatus", + "value": "" + }, + { + "key": "displayType", + "value": "" + } + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + } + ] + } + }, + "status": "Bad Request", + "code": 400, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by an Authorisation Failure", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/statemententries?limit=&offset=&fromDateTime=&toDateTime=&transactionStatus=&displayType=", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "statemententries" + ], + "query": [ + { + "key": "limit", + "value": "" + }, + { + "key": "offset", + "value": "" + }, + { + "key": "fromDateTime", + "value": "" + }, + { + "key": "toDateTime", + "value": "" + }, + { + "key": "transactionStatus", + "value": "" + }, + { + "key": "displayType", + "value": "" + } + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + } + ] + } + }, + "status": "Unauthorized", + "code": 401, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by System Unavailability", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/statemententries?limit=&offset=&fromDateTime=&toDateTime=&transactionStatus=&displayType=", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "statemententries" + ], + "query": [ + { + "key": "limit", + "value": "" + }, + { + "key": "offset", + "value": "" + }, + { + "key": "fromDateTime", + "value": "" + }, + { + "key": "toDateTime", + "value": "" + }, + { + "key": "transactionStatus", + "value": "" + }, + { + "key": "displayType", + "value": "" + } + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + } + ] + } + }, + "status": "Service Unavailable", + "code": 503, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by a General Server-Side Issue", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/statemententries?limit=&offset=&fromDateTime=&toDateTime=&transactionStatus=&displayType=", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "statemententries" + ], + "query": [ + { + "key": "limit", + "value": "" + }, + { + "key": "offset", + "value": "" + }, + { + "key": "fromDateTime", + "value": "" + }, + { + "key": "toDateTime", + "value": "" + }, + { + "key": "transactionStatus", + "value": "" + }, + { + "key": "displayType", + "value": "" + } + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + } + ] + } + }, + "status": "Internal Server Error", + "code": 500, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + } + ] + }, + { + "name": "View Bill Companies", + "request": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API.", + "disabled": true + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server.", + "disabled": true + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication", + "disabled": true + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server.", + "disabled": true + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed.", + "disabled": true + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", + "disabled": true + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", + "disabled": true + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App.", + "disabled": true + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header.", + "disabled": true + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header.", + "disabled": true + }, + { + "key": "Accept", + "value": "application/json", + "type": "text" + } + ], + "url": { + "raw": "{{ChannelGSMAHostName}}/accounts/{{identifierType}}/{{identifier}}/billcompanies", + "host": [ + "{{ChannelGSMAHostName}}" + ], + "path": [ + "accounts", + "{{identifierType}}", + "{{identifier}}", + "billcompanies" + ], + "query": [ + { + "key": "limit", + "value": "", + "description": "Supports pagination. If this is not supplied, then the server will apply a limit of 50 records returned for each request.", + "disabled": true + }, + { + "key": "offset", + "value": "", + "description": "Supports pagination. This value will indicate the cursor position from where to retrieve the set of records. For example, a limit of 50 and offset of 10 will return records 11 to 60.", + "disabled": true + } + ] + }, + "description": "This Bill Companies API is used to return a list of Service Providers that accept Bill Payments for a given account." + }, + "response": [ + { + "name": "Represents an Error Caused by a Failure to Identify the Target Resource", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/billcompanies?limit=&offset=", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "billcompanies" + ], + "query": [ + { + "key": "limit", + "value": "" + }, + { + "key": "offset", + "value": "" + } + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + } + ] + } + }, + "status": "Not Found", + "code": 404, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by an Authorisation Failure", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/billcompanies?limit=&offset=", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "billcompanies" + ], + "query": [ + { + "key": "limit", + "value": "" + }, + { + "key": "offset", + "value": "" + } + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + } + ] + } + }, + "status": "Unauthorized", + "code": 401, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by a General Server-Side Issue", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/billcompanies?limit=&offset=", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "billcompanies" + ], + "query": [ + { + "key": "limit", + "value": "" + }, + { + "key": "offset", + "value": "" + } + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + } + ] + } + }, + "status": "Internal Server Error", + "code": 500, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by System Unavailability", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/billcompanies?limit=&offset=", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "billcompanies" + ], + "query": [ + { + "key": "limit", + "value": "" + }, + { + "key": "offset", + "value": "" + } + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + } + ] + } + }, + "status": "Service Unavailable", + "code": 503, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by the Violation of a Business Rule", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/billcompanies?limit=&offset=", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "billcompanies" + ], + "query": [ + { + "key": "limit", + "value": "" + }, + { + "key": "offset", + "value": "" + } + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + } + ] + } + }, + "status": "Bad Request", + "code": 400, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represent a list of Bill Companies", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/:identifierType/:identifier/billcompanies?limit=&offset=", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + ":identifierType", + ":identifier", + "billcompanies" + ], + "query": [ + { + "key": "limit", + "value": "" + }, + { + "key": "offset", + "value": "" + } + ], + "variable": [ + { + "key": "identifierType" + }, + { + "key": "identifier" + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "[\n {\n \"companyName\": \"\",\n \"serviceProvider\": \"\",\n \"serviceProviderType\": \"\",\n \"serviceProviderSubType\": \"\",\n \"supplementaryServiceProviderDetails\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n },\n {\n \"companyName\": \"\",\n \"serviceProvider\": \"\",\n \"serviceProviderType\": \"\",\n \"serviceProviderSubType\": \"\",\n \"supplementaryServiceProviderDetails\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n }\n]" + } + ] + } + ] + }, + { + "name": "View Account Balance", + "protocolProfileBehavior": { + "disabledSystemHeaders": { + "accept": true + } + }, + "request": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API.", + "disabled": true + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + }, + { + "key": "Accept", + "value": "application/json", + "type": "text" + } + ], + "url": { + "raw": "{{ChannelGSMAHostName}}/accounts/balance", + "host": [ + "{{ChannelGSMAHostName}}" + ], + "path": [ + "accounts", + "balance" + ] + }, + "description": "This endpoint returns the balance of an account. As the account is not passed as a parameter, the account is assumed to be that of the calling client.\"" + }, + "response": [ + { + "name": "Represents an Error Caused by a Failure to Identify the Target Resource", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/balance", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + "balance" + ] + } + }, + "status": "Not Found", + "code": 404, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Account Balance response", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/balance", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + "balance" + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"currentBalance\": \"15.21\",\n \"availableBalance\": \"15.21\",\n \"reservedBalance\": \"15.21\",\n \"unclearedBalance\": \"15.21\",\n \"currency\": \"\",\n \"accountStatus\": \"\"\n}" + }, + { + "name": "Represents an Error Caused by a General Server-Side Issue", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/balance", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + "balance" + ] + } + }, + "status": "Internal Server Error", + "code": 500, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by System Unavailability", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/balance", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + "balance" + ] + } + }, + "status": "Service Unavailable", + "code": 503, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by the Violation of a Business Rule", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/balance", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + "balance" + ] + } + }, + "status": "Bad Request", + "code": 400, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by an Authorisation Failure", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/accounts/balance", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "accounts", + "balance" + ] + } + }, + "status": "Unauthorized", + "code": 401, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + } + ] + } + ] + }, + { + "name": "billcompanies", + "item": [ + { + "name": "View Bill Companies", + "request": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API.", + "disabled": true + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + }, + { + "key": "Accept", + "value": "application/json", + "type": "text" + } + ], + "url": { + "raw": "{{ChannelGSMAHostName}}/billcompanies", + "host": [ + "{{ChannelGSMAHostName}}" + ], + "path": [ + "billcompanies" + ], + "query": [ + { + "key": "limit", + "value": "", + "description": "Supports pagination. If this is not supplied, then the server will apply a limit of 50 records returned for each request.", + "disabled": true + }, + { + "key": "offset", + "value": "", + "description": "Supports pagination. This value will indicate the cursor position from where to retrieve the set of records. For example, a limit of 50 and offset of 10 will return records 11 to 60.", + "disabled": true + } + ] + }, + "description": "The Bill Companies API is used to return a list of Service Providers that accept Bill Payments." + }, + "response": [ + { + "name": "Represent a list of Bill Companies", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/billcompanies?limit=&offset=", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "billcompanies" + ], + "query": [ + { + "key": "limit", + "value": "" + }, + { + "key": "offset", + "value": "" + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "[\n {\n \"companyName\": \"\",\n \"serviceProvider\": \"\",\n \"serviceProviderType\": \"\",\n \"serviceProviderSubType\": \"\",\n \"supplementaryServiceProviderDetails\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n },\n {\n \"companyName\": \"\",\n \"serviceProvider\": \"\",\n \"serviceProviderType\": \"\",\n \"serviceProviderSubType\": \"\",\n \"supplementaryServiceProviderDetails\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n }\n]" + }, + { + "name": "Represents an Error Caused by System Unavailability", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/billcompanies?limit=&offset=", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "billcompanies" + ], + "query": [ + { + "key": "limit", + "value": "" + }, + { + "key": "offset", + "value": "" + } + ] + } + }, + "status": "Service Unavailable", + "code": 503, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by a General Server-Side Issue", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/billcompanies?limit=&offset=", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "billcompanies" + ], + "query": [ + { + "key": "limit", + "value": "" + }, + { + "key": "offset", + "value": "" + } + ] + } + }, + "status": "Internal Server Error", + "code": 500, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by an Authorisation Failure", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/billcompanies?limit=&offset=", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "billcompanies" + ], + "query": [ + { + "key": "limit", + "value": "" + }, + { + "key": "offset", + "value": "" + } + ] + } + }, + "status": "Unauthorized", + "code": 401, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by the Violation of a Business Rule", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/billcompanies?limit=&offset=", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "billcompanies" + ], + "query": [ + { + "key": "limit", + "value": "" + }, + { + "key": "offset", + "value": "" + } + ] + } + }, + "status": "Bad Request", + "code": 400, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by a Failure to Identify the Target Resource", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/billcompanies?limit=&offset=", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "billcompanies" + ], + "query": [ + { + "key": "limit", + "value": "" + }, + { + "key": "offset", + "value": "" + } + ] + } + }, + "status": "Not Found", + "code": 404, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + } + ] + }, + { + "name": "View a Specific Bill Company", + "request": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API.", + "disabled": true + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + }, + { + "key": "Accept", + "value": "application/json", + "type": "text" + } + ], + "url": { + "raw": "{{ChannelGSMAHostName}}/billcompanies/{{serviceProvider}}", + "host": [ + "{{ChannelGSMAHostName}}" + ], + "path": [ + "billcompanies", + "{{serviceProvider}}" + ] + }, + "description": "This Bill Companies API is used to return a information for a specific Service Providers that accepts Bill Payments." + }, + "response": [ + { + "name": "Represents an Error Caused by System Unavailability", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/billcompanies/:serviceProvider", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "billcompanies", + ":serviceProvider" + ], + "variable": [ + { + "key": "serviceProvider" + } + ] + } + }, + "status": "Service Unavailable", + "code": 503, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by an Authorisation Failure", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/billcompanies/:serviceProvider", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "billcompanies", + ":serviceProvider" + ], + "variable": [ + { + "key": "serviceProvider" + } + ] + } + }, + "status": "Unauthorized", + "code": 401, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by a General Server-Side Issue", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/billcompanies/:serviceProvider", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "billcompanies", + ":serviceProvider" + ], + "variable": [ + { + "key": "serviceProvider" + } + ] + } + }, + "status": "Internal Server Error", + "code": 500, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Returns a specific Bill Payment Service Provider", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/billcompanies/:serviceProvider", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "billcompanies", + ":serviceProvider" + ], + "variable": [ + { + "key": "serviceProvider" + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"companyName\": \"\",\n \"serviceProvider\": \"\",\n \"serviceProviderType\": \"\",\n \"serviceProviderSubType\": \"\",\n \"supplementaryServiceProviderDetails\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by a Failure to Identify the Target Resource", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/billcompanies/:serviceProvider", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "billcompanies", + ":serviceProvider" + ], + "variable": [ + { + "key": "serviceProvider" + } + ] + } + }, + "status": "Not Found", + "code": 404, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by the Violation of a Business Rule", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/billcompanies/:serviceProvider", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "billcompanies", + ":serviceProvider" + ], + "variable": [ + { + "key": "serviceProvider" + } + ] + } + }, + "status": "Bad Request", + "code": 400, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + } + ] + } + ] + }, + { + "name": "quotations", + "item": [ + { + "name": "Create A New Quotation", + "request": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API.", + "disabled": true + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID.", + "disabled": true + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server.", + "disabled": true + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication", + "disabled": true + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server.", + "disabled": true + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed.", + "disabled": true + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", + "disabled": true + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", + "disabled": true + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App.", + "disabled": true + }, + { + "key": "X-Callback-URL", + "value": "", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT.", + "disabled": true + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header.", + "disabled": true + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header.", + "disabled": true + }, + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Accept", + "value": "application/json", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"creditParty\": [\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n }\n ],\n \"debitParty\": [\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n }\n ],\n \"type\": \"billpay\",\n \"subType\": \"string\",\n \"requestAmount\": \"15.21\",\n \"requestCurrency\": \"AED\",\n \"chosenDeliveryMethod\": \"directtoaccount\",\n \"originCountry\": \"AD\",\n \"receivingCountry\": \"AD\",\n \"recipientKyc\": {\n \"birthCountry\": \"AD\",\n \"contactPhone\": \"string\",\n \"dateOfBirth\": \"2000-11-20\",\n \"emailAddress\": \"string\",\n \"employerName\": \"string\",\n \"gender\": \"m\",\n \"idDocument\": [\n {\n \"idType\": \"passport\",\n \"idNumber\": \"string\",\n \"issueDate\": \"2018-11-20\",\n \"expiryDate\": \"2018-11-20\",\n \"issuer\": \"string\",\n \"issuerPlace\": \"string\",\n \"issuerCountry\": \"AD\",\n \"otherIddescription\": \"string\"\n }\n ],\n \"nationality\": \"AD\",\n \"occupation\": \"string\",\n \"postalAddress\": {\n \"addressLine1\": \"string\",\n \"addressLine2\": \"string\",\n \"addressLine3\": \"string\",\n \"city\": \"string\",\n \"stateProvince\": \"string\",\n \"postalCode\": \"string\",\n \"country\": \"AD\"\n },\n \"subjectName\": {\n \"title\": \"string\",\n \"firstName\": \"string\",\n \"middleName\": \"string\",\n \"lastName\": \"string\",\n \"fullName\": \"string\",\n \"nativeName\": \"string\"\n }\n },\n \"senderKyc\": {\n \"birthCountry\": \"AD\",\n \"contactPhone\": \"string\",\n \"dateOfBirth\": \"2000-11-20\",\n \"emailAddress\": \"string\",\n \"employerName\": \"string\",\n \"gender\": \"m\",\n \"idDocument\": [\n {\n \"idType\": \"passport\",\n \"idNumber\": \"string\",\n \"issueDate\": \"2018-11-20\",\n \"expiryDate\": \"2018-11-20\",\n \"issuer\": \"string\",\n \"issuerPlace\": \"string\",\n \"issuerCountry\": \"AD\",\n \"otherIddescription\": \"string\"\n }\n ],\n \"nationality\": \"AD\",\n \"occupation\": \"string\",\n \"postalAddress\": {\n \"addressLine1\": \"string\",\n \"addressLine2\": \"string\",\n \"addressLine3\": \"string\",\n \"city\": \"string\",\n \"stateProvince\": \"string\",\n \"postalCode\": \"string\",\n \"country\": \"AD\"\n },\n \"subjectName\": {\n \"title\": \"string\",\n \"firstName\": \"string\",\n \"middleName\": \"string\",\n \"lastName\": \"string\",\n \"fullName\": \"string\",\n \"nativeName\": \"string\"\n }\n },\n \"requestingOrganisation\": {\n \"requestingOrganisationIdentifierType\": \"lei\",\n \"requestingOrganisationIdentifier\": \"string\"\n },\n \"sendingServiceProviderCountry\": \"AD\",\n \"requestDate\": \"2022-09-29T00:51:46.693Z\",\n \"customData\": [\n {\n \"key\": \"string\",\n \"value\": \"string\"\n }\n ],\n \"metadata\": [\n {\n \"key\": \"string\",\n \"value\": \"string\"\n }\n ]\n}" + }, + "url": { + "raw": "{{ChannelGSMAHostName}}/quotations", + "host": [ + "{{ChannelGSMAHostName}}" + ], + "path": [ + "quotations" + ] + }, + "description": "Provided with a valid object representation, this endpoint allows for a new quotation to be created." + }, + "response": [ + { + "name": "Represents an Error Caused by the Violation of a Business Rule", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/quotations", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "quotations" + ] + } + }, + "status": "Bad Request", + "code": 400, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by a General Server-Side Issue", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/quotations", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "quotations" + ] + } + }, + "status": "Internal Server Error", + "code": 500, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by a Failure to Identify the Target Resource", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/quotations", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "quotations" + ] + } + }, + "status": "Not Found", + "code": 404, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by System Unavailability", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/quotations", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "quotations" + ] + } + }, + "status": "Service Unavailable", + "code": 503, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents a Quotation response", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/quotations", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "quotations" + ] + } + }, + "status": "Created", + "code": 201, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"quotationReference\": \"\",\n \"requestDate\": \"\",\n \"debitParty\": [\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n },\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n }\n ],\n \"creditParty\": [\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n },\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n }\n ],\n \"requestAmount\": \"15.21\",\n \"requestCurrency\": \"\",\n \"senderKyc\": {\n \"nationality\": \"\",\n \"dateOfBirth\": \"2000-11-20\",\n \"occupation\": \"\",\n \"employerName\": \"\",\n \"contactPhone\": \"\",\n \"gender\": \"\",\n \"idDocument\": [\n {\n \"idType\": \"\",\n \"idNumber\": \"\",\n \"issueDate\": \"2018-11-20\",\n \"expiryDate\": \"2018-11-20\",\n \"issuer\": \"\",\n \"issuerPlace\": \"\",\n \"issuerCountry\": \"\",\n \"otherIddescription\": \"\"\n },\n {\n \"idType\": \"\",\n \"idNumber\": \"\",\n \"issueDate\": \"2018-11-20\",\n \"expiryDate\": \"2018-11-20\",\n \"issuer\": \"\",\n \"issuerPlace\": \"\",\n \"issuerCountry\": \"\",\n \"otherIddescription\": \"\"\n }\n ],\n \"postalAddress\": {\n \"country\": \"\",\n \"addressLine1\": \"\",\n \"addressLine2\": \"\",\n \"addressLine3\": \"\",\n \"city\": \"\",\n \"stateProvince\": \"\",\n \"postalCode\": \"\"\n },\n \"subjectName\": {\n \"title\": \"\",\n \"firstName\": \"\",\n \"middleName\": \"\",\n \"lastName\": \"\",\n \"fullName\": \"\",\n \"nativeName\": \"\"\n },\n \"emailAddress\": \"\",\n \"birthCountry\": \"\"\n },\n \"recipientKyc\": {\n \"nationality\": \"\",\n \"dateOfBirth\": \"2000-11-20\",\n \"occupation\": \"\",\n \"employerName\": \"\",\n \"contactPhone\": \"\",\n \"gender\": \"\",\n \"idDocument\": [\n {\n \"idType\": \"\",\n \"idNumber\": \"\",\n \"issueDate\": \"2018-11-20\",\n \"expiryDate\": \"2018-11-20\",\n \"issuer\": \"\",\n \"issuerPlace\": \"\",\n \"issuerCountry\": \"\",\n \"otherIddescription\": \"\"\n },\n {\n \"idType\": \"\",\n \"idNumber\": \"\",\n \"issueDate\": \"2018-11-20\",\n \"expiryDate\": \"2018-11-20\",\n \"issuer\": \"\",\n \"issuerPlace\": \"\",\n \"issuerCountry\": \"\",\n \"otherIddescription\": \"\"\n }\n ],\n \"postalAddress\": {\n \"country\": \"\",\n \"addressLine1\": \"\",\n \"addressLine2\": \"\",\n \"addressLine3\": \"\",\n \"city\": \"\",\n \"stateProvince\": \"\",\n \"postalCode\": \"\"\n },\n \"subjectName\": {\n \"title\": \"\",\n \"firstName\": \"\",\n \"middleName\": \"\",\n \"lastName\": \"\",\n \"fullName\": \"\",\n \"nativeName\": \"\"\n },\n \"emailAddress\": \"\",\n \"birthCountry\": \"\"\n },\n \"type\": \"\",\n \"subType\": \"\",\n \"chosenDeliveryMethod\": \"\",\n \"quotes\": [\n {\n \"quoteId\": \"\",\n \"receivingAmount\": \"15.21\",\n \"receivingCurrency\": \"\",\n \"sendingAmount\": \"15.21\",\n \"sendingCurrency\": \"\",\n \"quoteExpiryTime\": \"\",\n \"receivingServiceProvider\": \"\",\n \"fxRate\": \"1.3436\",\n \"deliveryMethod\": \"\",\n \"fees\": [\n {\n \"feeType\": \"\",\n \"feeCurrency\": \"\",\n \"feeAmount\": \"15.21\"\n },\n {\n \"feeType\": \"\",\n \"feeCurrency\": \"\",\n \"feeAmount\": \"15.21\"\n }\n ]\n },\n {\n \"quoteId\": \"\",\n \"receivingAmount\": \"15.21\",\n \"receivingCurrency\": \"\",\n \"sendingAmount\": \"15.21\",\n \"sendingCurrency\": \"\",\n \"quoteExpiryTime\": \"\",\n \"receivingServiceProvider\": \"\",\n \"fxRate\": \"1.3436\",\n \"deliveryMethod\": \"\",\n \"fees\": [\n {\n \"feeType\": \"\",\n \"feeCurrency\": \"\",\n \"feeAmount\": \"15.21\"\n },\n {\n \"feeType\": \"\",\n \"feeCurrency\": \"\",\n \"feeAmount\": \"15.21\"\n }\n ]\n }\n ],\n \"senderBlockingReason\": \"\",\n \"recipientBlockingReason\": \"\",\n \"metadata\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ],\n \"quotationStatus\": \"\",\n \"creationDate\": \"\",\n \"modificationDate\": \"\",\n \"dateCreated\": \"\",\n \"dateModified\": \"\",\n \"availableDeliveryMethod\": \"\"\n}" + }, + { + "name": "Represents an Asynchronous response", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/quotations", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "quotations" + ] + } + }, + "status": "Accepted", + "code": 202, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"notificationMethod\": \"\",\n \"serverCorrelationId\": \"\",\n \"status\": \"\",\n \"pendingReason\": \"\",\n \"objectReference\": \"\",\n \"expiryTime\": \"\",\n \"pollLimit\": \"\",\n \"error\": {\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n }\n}" + }, + { + "name": "Represents an Error Caused by an Authorisation Failure", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/quotations", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "quotations" + ] + } + }, + "status": "Unauthorized", + "code": 401, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + } + ] + }, + { + "name": "View A Quotation", + "request": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API.", + "disabled": true + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server.", + "disabled": true + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication", + "disabled": true + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server.", + "disabled": true + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed.", + "disabled": true + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", + "disabled": true + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", + "disabled": true + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App.", + "disabled": true + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header.", + "disabled": true + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header.", + "disabled": true + }, + { + "key": "Accept", + "value": "application/json", + "type": "text" + } + ], + "url": { + "raw": "{{ChannelGSMAHostName}}/quotations/{{quotationReference}}", + "host": [ + "{{ChannelGSMAHostName}}" + ], + "path": [ + "quotations", + "{{quotationReference}}" + ] + }, + "description": "This endpoint returns a specific quotation" + }, + "response": [ + { + "name": "Represents an Error Caused by a General Server-Side Issue", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/quotations/:quotationReference", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "quotations", + ":quotationReference" + ], + "variable": [ + { + "key": "quotationReference" + } + ] + } + }, + "status": "Internal Server Error", + "code": 500, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by a Failure to Identify the Target Resource", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/quotations/:quotationReference", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "quotations", + ":quotationReference" + ], + "variable": [ + { + "key": "quotationReference" + } + ] + } + }, + "status": "Not Found", + "code": 404, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by an Authorisation Failure", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/quotations/:quotationReference", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "quotations", + ":quotationReference" + ], + "variable": [ + { + "key": "quotationReference" + } + ] + } + }, + "status": "Unauthorized", + "code": 401, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by System Unavailability", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/quotations/:quotationReference", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "quotations", + ":quotationReference" + ], + "variable": [ + { + "key": "quotationReference" + } + ] + } + }, + "status": "Service Unavailable", + "code": 503, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by the Violation of a Business Rule", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/quotations/:quotationReference", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "quotations", + ":quotationReference" + ], + "variable": [ + { + "key": "quotationReference" + } + ] + } + }, + "status": "Bad Request", + "code": 400, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents a Quotation response", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/quotations/:quotationReference", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "quotations", + ":quotationReference" + ], + "variable": [ + { + "key": "quotationReference" + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"quotationReference\": \"\",\n \"requestDate\": \"\",\n \"debitParty\": [\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n },\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n }\n ],\n \"creditParty\": [\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n },\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n }\n ],\n \"requestAmount\": \"15.21\",\n \"requestCurrency\": \"\",\n \"senderKyc\": {\n \"nationality\": \"\",\n \"dateOfBirth\": \"2000-11-20\",\n \"occupation\": \"\",\n \"employerName\": \"\",\n \"contactPhone\": \"\",\n \"gender\": \"\",\n \"idDocument\": [\n {\n \"idType\": \"\",\n \"idNumber\": \"\",\n \"issueDate\": \"2018-11-20\",\n \"expiryDate\": \"2018-11-20\",\n \"issuer\": \"\",\n \"issuerPlace\": \"\",\n \"issuerCountry\": \"\",\n \"otherIddescription\": \"\"\n },\n {\n \"idType\": \"\",\n \"idNumber\": \"\",\n \"issueDate\": \"2018-11-20\",\n \"expiryDate\": \"2018-11-20\",\n \"issuer\": \"\",\n \"issuerPlace\": \"\",\n \"issuerCountry\": \"\",\n \"otherIddescription\": \"\"\n }\n ],\n \"postalAddress\": {\n \"country\": \"\",\n \"addressLine1\": \"\",\n \"addressLine2\": \"\",\n \"addressLine3\": \"\",\n \"city\": \"\",\n \"stateProvince\": \"\",\n \"postalCode\": \"\"\n },\n \"subjectName\": {\n \"title\": \"\",\n \"firstName\": \"\",\n \"middleName\": \"\",\n \"lastName\": \"\",\n \"fullName\": \"\",\n \"nativeName\": \"\"\n },\n \"emailAddress\": \"\",\n \"birthCountry\": \"\"\n },\n \"recipientKyc\": {\n \"nationality\": \"\",\n \"dateOfBirth\": \"2000-11-20\",\n \"occupation\": \"\",\n \"employerName\": \"\",\n \"contactPhone\": \"\",\n \"gender\": \"\",\n \"idDocument\": [\n {\n \"idType\": \"\",\n \"idNumber\": \"\",\n \"issueDate\": \"2018-11-20\",\n \"expiryDate\": \"2018-11-20\",\n \"issuer\": \"\",\n \"issuerPlace\": \"\",\n \"issuerCountry\": \"\",\n \"otherIddescription\": \"\"\n },\n {\n \"idType\": \"\",\n \"idNumber\": \"\",\n \"issueDate\": \"2018-11-20\",\n \"expiryDate\": \"2018-11-20\",\n \"issuer\": \"\",\n \"issuerPlace\": \"\",\n \"issuerCountry\": \"\",\n \"otherIddescription\": \"\"\n }\n ],\n \"postalAddress\": {\n \"country\": \"\",\n \"addressLine1\": \"\",\n \"addressLine2\": \"\",\n \"addressLine3\": \"\",\n \"city\": \"\",\n \"stateProvince\": \"\",\n \"postalCode\": \"\"\n },\n \"subjectName\": {\n \"title\": \"\",\n \"firstName\": \"\",\n \"middleName\": \"\",\n \"lastName\": \"\",\n \"fullName\": \"\",\n \"nativeName\": \"\"\n },\n \"emailAddress\": \"\",\n \"birthCountry\": \"\"\n },\n \"type\": \"\",\n \"subType\": \"\",\n \"chosenDeliveryMethod\": \"\",\n \"quotes\": [\n {\n \"quoteId\": \"\",\n \"receivingAmount\": \"15.21\",\n \"receivingCurrency\": \"\",\n \"sendingAmount\": \"15.21\",\n \"sendingCurrency\": \"\",\n \"quoteExpiryTime\": \"\",\n \"receivingServiceProvider\": \"\",\n \"fxRate\": \"1.3436\",\n \"deliveryMethod\": \"\",\n \"fees\": [\n {\n \"feeType\": \"\",\n \"feeCurrency\": \"\",\n \"feeAmount\": \"15.21\"\n },\n {\n \"feeType\": \"\",\n \"feeCurrency\": \"\",\n \"feeAmount\": \"15.21\"\n }\n ]\n },\n {\n \"quoteId\": \"\",\n \"receivingAmount\": \"15.21\",\n \"receivingCurrency\": \"\",\n \"sendingAmount\": \"15.21\",\n \"sendingCurrency\": \"\",\n \"quoteExpiryTime\": \"\",\n \"receivingServiceProvider\": \"\",\n \"fxRate\": \"1.3436\",\n \"deliveryMethod\": \"\",\n \"fees\": [\n {\n \"feeType\": \"\",\n \"feeCurrency\": \"\",\n \"feeAmount\": \"15.21\"\n },\n {\n \"feeType\": \"\",\n \"feeCurrency\": \"\",\n \"feeAmount\": \"15.21\"\n }\n ]\n }\n ],\n \"senderBlockingReason\": \"\",\n \"recipientBlockingReason\": \"\",\n \"metadata\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ],\n \"quotationStatus\": \"\",\n \"creationDate\": \"\",\n \"modificationDate\": \"\",\n \"dateCreated\": \"\",\n \"dateModified\": \"\",\n \"availableDeliveryMethod\": \"\"\n}" + } + ] + } + ] + }, + { + "name": "requeststates/{server Correlation Id} Copy", + "item": [ + { + "name": "View A Request State", + "request": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API.", + "disabled": true + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server.", + "disabled": true + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server.", + "disabled": true + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed.", + "disabled": true + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", + "disabled": true + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", + "disabled": true + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App.", + "disabled": true + }, + { + "key": "Accept", + "value": "application/json", + "type": "text" + } + ], + "url": { + "raw": "{{ChannelGSMAHostName}}/requeststates/{{serverCorrelationId}}", + "host": [ + "{{ChannelGSMAHostName}}" + ], + "path": [ + "requeststates", + "{{serverCorrelationId}}" + ] + }, + "description": "This endpoint returns a specific request state" + }, + "response": [ + { + "name": "Represents an Error Caused by a Failure to Identify the Target Resource", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + } + ], + "url": { + "raw": "{{baseUrl}}/requeststates/:serverCorrelationId", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "requeststates", + ":serverCorrelationId" + ], + "variable": [ + { + "key": "serverCorrelationId" + } + ] + } + }, + "status": "Not Found", + "code": 404, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by an Authorisation Failure", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + } + ], + "url": { + "raw": "{{baseUrl}}/requeststates/:serverCorrelationId", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "requeststates", + ":serverCorrelationId" + ], + "variable": [ + { + "key": "serverCorrelationId" + } + ] + } + }, + "status": "Unauthorized", + "code": 401, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Asynchronous response", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + } + ], + "url": { + "raw": "{{baseUrl}}/requeststates/:serverCorrelationId", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "requeststates", + ":serverCorrelationId" + ], + "variable": [ + { + "key": "serverCorrelationId" + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"notificationMethod\": \"\",\n \"serverCorrelationId\": \"\",\n \"status\": \"\",\n \"pendingReason\": \"\",\n \"objectReference\": \"\",\n \"expiryTime\": \"\",\n \"pollLimit\": \"\",\n \"error\": {\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n }\n}" + }, + { + "name": "Represents an Error Caused by a General Server-Side Issue", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + } + ], + "url": { + "raw": "{{baseUrl}}/requeststates/:serverCorrelationId", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "requeststates", + ":serverCorrelationId" + ], + "variable": [ + { + "key": "serverCorrelationId" + } + ] + } + }, + "status": "Internal Server Error", + "code": 500, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by the Violation of a Business Rule", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + } + ], + "url": { + "raw": "{{baseUrl}}/requeststates/:serverCorrelationId", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "requeststates", + ":serverCorrelationId" + ], + "variable": [ + { + "key": "serverCorrelationId" + } + ] + } + }, + "status": "Bad Request", + "code": 400, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by System Unavailability", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + } + ], + "url": { + "raw": "{{baseUrl}}/requeststates/:serverCorrelationId", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "requeststates", + ":serverCorrelationId" + ], + "variable": [ + { + "key": "serverCorrelationId" + } + ] + } + }, + "status": "Service Unavailable", + "code": 503, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + } + ] + }, + { + "name": "Update A Request State", + "request": { + "method": "PATCH", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API.", + "disabled": true + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID.", + "disabled": true + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server.", + "disabled": true + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server.", + "disabled": true + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed.", + "disabled": true + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", + "disabled": true + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", + "disabled": true + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App.", + "disabled": true + }, + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Accept", + "value": "application/json", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "[\n {\n \"op\": \"replace\",\n \"path\": \"string\",\n \"value\": \"string\"\n }\n]" + }, + "url": { + "raw": "{{ChannelGSMAHostName}}/requeststates/{{serverCorrelationId}}", + "host": [ + "{{ChannelGSMAHostName}}" + ], + "path": [ + "requeststates", + "{{serverCorrelationId}}" + ] + }, + "description": "This endpoint updates a specific request state. This operation is to be deprecated. Please refer to Callback definitions for the revised approach to implementing asynchronous callbacks." + }, + "response": [ + { + "name": "Represents an Error Caused by System Unavailability", + "originalRequest": { + "method": "PATCH", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + } + ], + "url": { + "raw": "{{baseUrl}}/requeststates/:serverCorrelationId", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "requeststates", + ":serverCorrelationId" + ], + "variable": [ + { + "key": "serverCorrelationId" + } + ] + } + }, + "status": "Service Unavailable", + "code": 503, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by an Authorisation Failure", + "originalRequest": { + "method": "PATCH", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + } + ], + "url": { + "raw": "{{baseUrl}}/requeststates/:serverCorrelationId", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "requeststates", + ":serverCorrelationId" + ], + "variable": [ + { + "key": "serverCorrelationId" + } + ] + } + }, + "status": "Unauthorized", + "code": 401, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by a Failure to Identify the Target Resource", + "originalRequest": { + "method": "PATCH", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + } + ], + "url": { + "raw": "{{baseUrl}}/requeststates/:serverCorrelationId", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "requeststates", + ":serverCorrelationId" + ], + "variable": [ + { + "key": "serverCorrelationId" + } + ] + } + }, + "status": "Not Found", + "code": 404, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "An empty response is returned for a synchronous successful patch.", + "originalRequest": { + "method": "PATCH", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + } + ], + "url": { + "raw": "{{baseUrl}}/requeststates/:serverCorrelationId", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "requeststates", + ":serverCorrelationId" + ], + "variable": [ + { + "key": "serverCorrelationId" + } + ] + } + }, + "status": "No Content", + "code": 204, + "_postman_previewlanguage": "text", + "header": [ + { + "key": "Content-Type", + "value": "text/plain" + } + ], + "cookie": [], + "body": "" + }, + { + "name": "Represents an Error Caused by the Violation of a Business Rule", + "originalRequest": { + "method": "PATCH", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + } + ], + "url": { + "raw": "{{baseUrl}}/requeststates/:serverCorrelationId", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "requeststates", + ":serverCorrelationId" + ], + "variable": [ + { + "key": "serverCorrelationId" + } + ] + } + }, + "status": "Bad Request", + "code": 400, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by a General Server-Side Issue", + "originalRequest": { + "method": "PATCH", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + } + ], + "url": { + "raw": "{{baseUrl}}/requeststates/:serverCorrelationId", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "requeststates", + ":serverCorrelationId" + ], + "variable": [ + { + "key": "serverCorrelationId" + } + ] + } + }, + "status": "Internal Server Error", + "code": 500, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + } + ] + } + ] + }, + { + "name": "Check API availability", + "request": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API.", + "disabled": true + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server.", + "disabled": true + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server.", + "disabled": true + }, + { + "key": "Accept", + "value": "application/json", + "type": "text" + } + ], + "url": { + "raw": "{{ChannelGSMAHostName}}/heartbeat/", + "host": [ + "{{ChannelGSMAHostName}}" + ], + "path": [ + "heartbeat", + "" + ] + }, + "description": "This endpoint returns the current status of the API" + }, + "response": [ + { + "name": "Represents an Error Caused by System Unavailability", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + } + ], + "url": { + "raw": "{{baseUrl}}/heartbeat", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "heartbeat" + ] + } + }, + "status": "Service Unavailable", + "code": 503, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by a Failure to Identify the Target Resource", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + } + ], + "url": { + "raw": "{{baseUrl}}/heartbeat", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "heartbeat" + ] + } + }, + "status": "Not Found", + "code": 404, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by a General Server-Side Issue", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + } + ], + "url": { + "raw": "{{baseUrl}}/heartbeat", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "heartbeat" + ] + } + }, + "status": "Internal Server Error", + "code": 500, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by the Violation of a Business Rule", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + } + ], + "url": { + "raw": "{{baseUrl}}/heartbeat", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "heartbeat" + ] + } + }, + "status": "Bad Request", + "code": 400, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents a Heartbeat response", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + } + ], + "url": { + "raw": "{{baseUrl}}/heartbeat", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "heartbeat" + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"serviceStatus\": \"\",\n \"delay\": \"\",\n \"plannedRestorationTime\": \"\"\n}" + }, + { + "name": "Represents an Error Caused by an Authorisation Failure", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + } + ], + "url": { + "raw": "{{baseUrl}}/heartbeat", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "heartbeat" + ] + } + }, + "status": "Unauthorized", + "code": 401, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + } + ] + }, + { + "name": "View Specific Statement", + "request": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API.", + "disabled": true + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + }, + { + "key": "Accept", + "value": "application/json", + "type": "text" + } + ], + "url": { + "raw": "{{ChannelGSMAHostName}}/statemententries/{{transactionReference}}", + "host": [ + "{{ChannelGSMAHostName}}" + ], + "path": [ + "statemententries", + "{{transactionReference}}" + ] + }, + "description": "The Statement Entries API enables generic representations of transactions to be returned. Typically, the returned representations are used for the purposes of presenting a statement to the account holder. In order to return a statement, a transaction reference must be specified." + }, + "response": [ + { + "name": "Represents an Error Caused by an Authorisation Failure", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/statemententries/:transactionReference", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "statemententries", + ":transactionReference" + ], + "variable": [ + { + "key": "transactionReference" + } + ] + } + }, + "status": "Unauthorized", + "code": 401, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by System Unavailability", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/statemententries/:transactionReference", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "statemententries", + ":transactionReference" + ], + "variable": [ + { + "key": "transactionReference" + } + ] + } + }, + "status": "Service Unavailable", + "code": 503, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by the Violation of a Business Rule", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/statemententries/:transactionReference", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "statemententries", + ":transactionReference" + ], + "variable": [ + { + "key": "transactionReference" + } + ] + } + }, + "status": "Bad Request", + "code": 400, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by a Failure to Identify the Target Resource", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/statemententries/:transactionReference", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "statemententries", + ":transactionReference" + ], + "variable": [ + { + "key": "transactionReference" + } + ] + } + }, + "status": "Not Found", + "code": 404, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by a General Server-Side Issue", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/statemententries/:transactionReference", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "statemententries", + ":transactionReference" + ], + "variable": [ + { + "key": "transactionReference" + } + ] + } + }, + "status": "Internal Server Error", + "code": 500, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represent a list of Statement Entries", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/statemententries/:transactionReference", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "statemententries", + ":transactionReference" + ], + "variable": [ + { + "key": "transactionReference" + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"amount\": \"15.21\",\n \"creditParty\": [\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n },\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n }\n ],\n \"currency\": \"\",\n \"debitParty\": [\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n },\n {\n \"key\": \"msisdn\",\n \"value\": \"+33555123456\"\n }\n ],\n \"transactionReference\": \"\",\n \"transactionStatus\": \"\",\n \"displayType\": \"\",\n \"descriptionText\": \"\",\n \"requestDate\": \"\",\n \"creationDate\": \"\",\n \"modificationDate\": \"\",\n \"dateCreated\": \"\",\n \"dateModified\": \"\",\n \"transactionReceipt\": \"\"\n}" + } + ] + }, + { + "name": "Create A Bill Payment", + "request": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API.", + "disabled": true + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + }, + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Accept", + "value": "application/json", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"serviceProviderPaymentReference\": \"string\",\n \"requestingOrganisationTransactionReference\": \"string\",\n \"paymentType\": \"partialpayment\",\n \"amountPaid\": \"15.21\",\n \"currency\": \"AED\",\n \"customerReference\": \"string\",\n \"requestingOrganisation\": \"string\",\n \"supplementaryBillReferenceDetails\": [\n {\n \"paymentReferenceType\": \"string\",\n \"paymentReferenceValue\": \"string\"\n }\n ],\n \"requestDate\": \"2022-09-29T07:45:19.744Z\",\n \"customData\": [\n {\n \"key\": \"string\",\n \"value\": \"string\"\n }\n ],\n \"metadata\": [\n {\n \"key\": \"string\",\n \"value\": \"string\"\n }\n ],\n \"paidAmount\": \"15.21\"\n}" + }, + "url": { + "raw": "{{ChannelGSMAHostName}}/bills/{{billReference}}/payments", + "host": [ + "{{ChannelGSMAHostName}}" + ], + "path": [ + "bills", + "{{billReference}}", + "payments" + ] + }, + "description": "Provided with a valid object representation, this endpoint allows for a new bill payment to be created." + }, + "response": [ + { + "name": "Represents an Error Caused by System Unavailability", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/bills/:billReference/payments", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "bills", + ":billReference", + "payments" + ], + "variable": [ + { + "key": "billReference" + } + ] + } + }, + "status": "Service Unavailable", + "code": 503, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents a Bill Payment response", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/bills/:billReference/payments", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "bills", + ":billReference", + "payments" + ], + "variable": [ + { + "key": "billReference" + } + ] + } + }, + "status": "Created", + "code": 201, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"currency\": \"\",\n \"amountPaid\": \"15.21\",\n \"billPaymentStatus\": \"\",\n \"paidAmount\": \"15.21\",\n \"serviceProviderPaymentReference\": \"\",\n \"requestingOrganisation\": \"\",\n \"requestingOrganisationTransactionReference\": \"\",\n \"customerReference\": \"\",\n \"paymentType\": \"\",\n \"serviceProviderComment\": \"\",\n \"serviceProviderNotification\": \"\",\n \"supplementaryBillReferenceDetails\": [\n {\n \"paymentReferenceType\": \"\",\n \"paymentReferenceValue\": \"\"\n },\n {\n \"paymentReferenceType\": \"\",\n \"paymentReferenceValue\": \"\"\n }\n ],\n \"metadata\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by a General Server-Side Issue", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/bills/:billReference/payments", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "bills", + ":billReference", + "payments" + ], + "variable": [ + { + "key": "billReference" + } + ] + } + }, + "status": "Internal Server Error", + "code": 500, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by the Violation of a Business Rule", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/bills/:billReference/payments", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "bills", + ":billReference", + "payments" + ], + "variable": [ + { + "key": "billReference" + } + ] + } + }, + "status": "Bad Request", + "code": 400, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Asynchronous response", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/bills/:billReference/payments", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "bills", + ":billReference", + "payments" + ], + "variable": [ + { + "key": "billReference" + } + ] + } + }, + "status": "Accepted", + "code": 202, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"notificationMethod\": \"\",\n \"serverCorrelationId\": \"\",\n \"status\": \"\",\n \"pendingReason\": \"\",\n \"objectReference\": \"\",\n \"expiryTime\": \"\",\n \"pollLimit\": \"\",\n \"error\": {\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n }\n}" + }, + { + "name": "Represents an Error Caused by an Authorisation Failure", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/bills/:billReference/payments", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "bills", + ":billReference", + "payments" + ], + "variable": [ + { + "key": "billReference" + } + ] + } + }, + "status": "Unauthorized", + "code": 401, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by a Failure to Identify the Target Resource", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-CorrelationID", + "value": "", + "description": "Header parameter to uniquely identify the request. Must be supplied as a UUID." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-User-Bearer", + "value": "", + "description": "Used to pass user’s access token when OAuth 2.0/OIDC authorisation framework is used for end-user authentication" + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + }, + { + "key": "X-Callback-URL", + "value": "https://myserver.com/send/callback/here", + "description": "The URL supplied by the client that will be used to return the callback in the form of a HTTP PUT." + }, + { + "key": "X-Account-Holding-Institution-Identifier-Type", + "value": "", + "description": "A header variable that identifies the type of the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier header." + }, + { + "key": "X-Account-Holding-Institution-Identifier", + "value": "", + "description": "A header variable that identifies the account holding institution. This header is used to support request routing and should be used in conjunction with the X-Account-Holding-Institution-Identifier-Type header." + } + ], + "url": { + "raw": "{{baseUrl}}/bills/:billReference/payments", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "bills", + ":billReference", + "payments" + ], + "variable": [ + { + "key": "billReference" + } + ] + } + }, + "status": "Not Found", + "code": 404, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + } + ] + }, + { + "name": "View A Response", + "request": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API.", + "disabled": true + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server.", + "disabled": true + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server.", + "disabled": true + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed.", + "disabled": true + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", + "disabled": true + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider.", + "disabled": true + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App.", + "disabled": true + }, + { + "key": "Accept", + "value": "application/json", + "type": "text" + } + ], + "url": { + "raw": "{{ChannelGSMAHostName}}/responses/{{clientCorrelationId}}", + "host": [ + "{{ChannelGSMAHostName}}" + ], + "path": [ + "responses", + "{{clientCorrelationId}}" + ] + }, + "description": "This endpoint returns a specific response." + }, + "response": [ + { + "name": "Represents an Error Caused by a General Server-Side Issue", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + } + ], + "url": { + "raw": "{{baseUrl}}/responses/:clientCorrelationId", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "responses", + ":clientCorrelationId" + ], + "variable": [ + { + "key": "clientCorrelationId" + } + ] + } + }, + "status": "Internal Server Error", + "code": 500, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by an Authorisation Failure", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + } + ], + "url": { + "raw": "{{baseUrl}}/responses/:clientCorrelationId", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "responses", + ":clientCorrelationId" + ], + "variable": [ + { + "key": "clientCorrelationId" + } + ] + } + }, + "status": "Unauthorized", + "code": 401, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Response object response", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + } + ], + "url": { + "raw": "{{baseUrl}}/responses/:clientCorrelationId", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "responses", + ":clientCorrelationId" + ], + "variable": [ + { + "key": "clientCorrelationId" + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"link\": \"\"\n}" + }, + { + "name": "Represents an Error Caused by the Violation of a Business Rule", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + } + ], + "url": { + "raw": "{{baseUrl}}/responses/:clientCorrelationId", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "responses", + ":clientCorrelationId" + ], + "variable": [ + { + "key": "clientCorrelationId" + } + ] + } + }, + "status": "Bad Request", + "code": 400, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by System Unavailability", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + } + ], + "url": { + "raw": "{{baseUrl}}/responses/:clientCorrelationId", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "responses", + ":clientCorrelationId" + ], + "variable": [ + { + "key": "clientCorrelationId" + } + ] + } + }, + "status": "Service Unavailable", + "code": 503, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + }, + { + "name": "Represents an Error Caused by a Failure to Identify the Target Resource", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "Header parameter to indicate the date and time that the message was originated. It is used for basic message integrity checks, to ensure the request is not stale. Note that the header was previously referenced as 'Date' in version 1.0 of the Mobile Money API." + }, + { + "key": "X-API-Key", + "value": "", + "description": "Used to pass pre-shared client's API key to the server." + }, + { + "key": "X-Client-Id", + "value": "", + "description": "Used to pass pre-shared client's identifier to the server." + }, + { + "key": "X-Content-Hash", + "value": "", + "description": "SHA-256 hex digest of the request content (encrypted or plain). Applicable only if basic data integrity checking is to be performed." + }, + { + "key": "X-User-Credential-1", + "value": "", + "description": "The end-users encrypted security credential. Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-User-Credential-2", + "value": "", + "description": "The end-users encrypted security credential Should only be used when OAuth 2.0/OIDC authorisation framework has not been implemented by the API Provider." + }, + { + "key": "X-Channel", + "value": "", + "description": "String containing the channel that was used to originate the request. For example USSD, Web, App." + } + ], + "url": { + "raw": "{{baseUrl}}/responses/:clientCorrelationId", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "responses", + ":clientCorrelationId" + ], + "variable": [ + { + "key": "clientCorrelationId" + } + ] + } + }, + "status": "Not Found", + "code": 404, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Date", + "value": "", + "description": "The date and time that the response message was sent." + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"errorCategory\": \"\",\n \"errorCode\": \"\",\n \"errordescription\": \"\",\n \"errorDateTime\": \"\",\n \"errorParameters\": [\n {\n \"key\": \"\",\n \"value\": \"\"\n },\n {\n \"key\": \"\",\n \"value\": \"\"\n }\n ]\n}" + } + ] + } + ], + "event": [ + { + "listen": "prerequest", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + }, + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "pm.test(\"Status code is 200\", function () {", + " pm.response.to.have.status(200);", + "});" + ] + } + } + ] + }, + { + "name": "GSMA API", + "item": [ + { + "name": "GSMA P2P", + "request": { + "method": "POST", + "header": [ + { + "key": "Platform-TenantId", + "value": "{{TenantName}}", + "type": "text" + }, + { + "key": "X-CorrelationID", + "value": "{{clientCorrelationId}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"requestingOrganisationTransactionReference\": \"string\",\n \"originalTransactionReference\": \"string\",\n \"subType\": \"string\",\n \"type\": \"transfer\",\n \"amount\": \"11.00\",\n \"currency\": \"USD\",\n \"descriptionText\": \"string\",\n \"fees\": [\n {\n \"feeType\": \"string\",\n \"feeAmount\": \"11\",\n \"feeCurrency\": \"USD\"\n }\n ],\n \"geoCode\": \"37.423825,-122.082900\",\n \"internationalTransferInformation\": {\n \"quotationReference\": \"string\",\n \"quoteId\": \"string\",\n \"originCountry\": \"USA\",\n \"deliveryMethod\": \"directtoaccount\",\n \"receivingCountry\": \"USA\",\n \"relationshipSender\": \"string\",\n \"remittancePurpose\": \"string\"\n },\n \"oneTimeCode\": \"string\",\n \"receiverKyc\": {\n \"birthCountry\": \"USA\",\n \"contactPhone\": \"string\",\n \"dateOfBirth\": \"2000-11-20\",\n \"emailAddress\": \"string\",\n \"employerName\": \"string\",\n \"gender\": \"m\",\n \"idDocument\": [\n {\n \"idType\": \"passport\",\n \"idNumber\": \"string\",\n \"issueDate\": \"2022-09-28T12:51:19.260+00:00\",\n \"expiryDate\": \"2022-09-28T12:51:19.260+00:00\",\n \"issuer\": \"string\",\n \"issuerPlace\": \"string\",\n \"issuerCountry\": \"USA\"\n }\n ],\n \"nationality\": \"USA\",\n \"occupation\": \"string\",\n \"postalAddress\": {\n \"addressLine1\": \"string\",\n \"addressLine2\": \"string\",\n \"addressLine3\": \"string\",\n \"city\": \"string\",\n \"stateProvince\": \"string\",\n \"postalCode\": \"string\",\n \"country\": \"USA\"\n },\n \"subjectName\": {\n \"title\": \"string\",\n \"firstName\": \"string\",\n \"middleName\": \"string\",\n \"lastName\": \"string\",\n \"nativeName\": \"string\"\n }\n },\n \"senderKyc\": {\n \"birthCountry\": \"USA\",\n \"contactPhone\": \"string\",\n \"dateOfBirth\": \"2022-09-28T12:51:19.260+00:00\",\n \"emailAddress\": \"string\",\n \"employerName\": \"string\",\n \"gender\": \"m\",\n \"idDocument\": [\n {\n \"idType\": \"passport\",\n \"idNumber\": \"string\",\n \"issueDate\": \"2022-09-28T12:51:19.260+00:00\",\n \"expiryDate\": \"2022-09-28T12:51:19.260+00:00\",\n \"issuer\": \"string\",\n \"issuerPlace\": \"string\",\n \"issuerCountry\": \"USA\"\n }\n ],\n \"nationality\": \"USA\",\n \"occupation\": \"string\",\n \"postalAddress\": {\n \"addressLine1\": \"string\",\n \"addressLine2\": \"string\",\n \"addressLine3\": \"string\",\n \"city\": \"string\",\n \"stateProvince\": \"string\",\n \"postalCode\": \"string\",\n \"country\": \"USA\"\n },\n \"subjectName\": {\n \"title\": \"string\",\n \"firstName\": \"string\",\n \"middleName\": \"string\",\n \"lastName\": \"string\",\n \"nativeName\": \"string\"\n }\n },\n \"servicingIdentity\": \"string\",\n \"requestDate\": \"2022-09-28T12:51:19.260+00:00\",\n \"metadata\": [\n {\n \"key\": \"string\",\n \"value\": \"string\"\n }\n ],\n \"creditParty\": [\n {\n \"key\": \"msisdn\",\n \"value\": \"+449999112\"\n }\n ],\n \"debitParty\": [\n {\n \"key\": \"msisdn\",\n \"value\": \"+449999999\"\n }\n ]\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{ChannelHostName}}/channel/gsma/transfer", + "host": [ + "{{ChannelHostName}}" + ], + "path": [ + "channel", + "gsma", + "transfer" + ] + } + }, + "response": [] + }, + { + "name": "GSMA Transaction", + "request": { + "method": "POST", + "header": [ + { + "key": "X-CorrelationID", + "value": "{{clientCorrelationId}}", + "type": "text" + }, + { + "key": "accountHoldingInstitutionId", + "value": "{{accountHoldingInstitutionId}}", + "type": "text" + }, + { + "key": "amsName", + "value": "{{amsName}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"requestingOrganisationTransactionReference\": \"string\",\n \"subType\": \"inbound\",\n \"type\": \"transfer\",\n \"amount\": \"11\",\n \"currency\": \"USD\",\n \"descriptionText\": \"string\",\n \"requestDate\": \"2022-09-28T12:51:19.260+00:00\",\n \"customData\": [\n {\n \"key\": \"string\",\n \"value\": \"string\"\n }\n ],\n \"payer\": [\n {\n \"partyIdType\": \"MSISDN\",\n \"partyIdIdentifier\": \"{{MSISDN}}\"\n }\n ],\n \"payee\": [\n {\n \"partyIdType\": \"accountId\",\n \"partyIdIdentifier\": \"{{accountId}}\"\n }\n ]\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{ChannelHostName}}/channel/gsma/transaction", + "host": [ + "{{ChannelHostName}}" + ], + "path": [ + "channel", + "gsma", + "transaction" + ] + } + }, + "response": [ + { + "name": "GSMA Transaction", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-CorrelationID", + "value": "{{clientCorrelationId}}", + "type": "text" + }, + { + "key": "accountHoldingInstitutionId", + "value": "{{accountHoldingInstitutionId}}", + "type": "text" + }, + { + "key": "amsName", + "value": "{{amsName}}", + "type": "text" + }, + { + "key": "X-CallbackURL", + "value": "https://webhook.site/3cb8ab56-c03d-4251-9911-520f235da8f5", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"requestingOrganisationTransactionReference\": \"string\",\n \"subType\": \"inbound\",\n \"type\": \"transfer\",\n \"amount\": \"11\",\n \"currency\": \"USD\",\n \"descriptionText\": \"string\",\n \"requestDate\": \"2022-09-28T12:51:19.260+00:00\",\n \"customData\": [\n {\n \"key\": \"string\",\n \"value\": \"string\"\n }\n ],\n \"payer\": [\n {\n \"partyIdType\": \"MSISDN\",\n \"partyIdIdentifier\": \"{{MSISDN}}\"\n }\n ],\n \"payee\": [\n {\n \"partyIdType\": \"accountId\",\n \"partyIdIdentifier\": \"{{accountId}}\"\n }\n ]\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{ChannelHostName}}/channel/gsma/transaction", + "host": [ + "{{ChannelHostName}}" + ], + "path": [ + "channel", + "gsma", + "transaction" + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Transfer-Encoding", + "value": "chunked" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Date", + "value": "Wed, 24 Apr 2024 10:22:08 GMT" + }, + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "Access-Control-Expose-Headers", + "value": "*" + }, + { + "key": "X-Kong-Upstream-Latency", + "value": "13" + }, + { + "key": "X-Kong-Proxy-Latency", + "value": "0" + }, + { + "key": "Via", + "value": "kong/3.2.1.0-enterprise-edition" + } + ], + "cookie": [], + "body": "{\n \"transactionId\": \"168e49b0-b0e9-4446-a4d8-188f2b9a42e3\"\n}" + }, + { + "name": "GSMA Transaction callback", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-CorrelationID", + "value": "{{clientCorrelationId}}", + "type": "text" + }, + { + "key": "accountHoldingInstitutionId", + "value": "{{accountHoldingInstitutionId}}", + "type": "text" + }, + { + "key": "amsName", + "value": "{{amsName}}", + "type": "text" + }, + { + "key": "X-CallbackURL", + "value": "https://webhook.site/3cb8ab56-c03d-4251-9911-520f235da8f5", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"requestingOrganisationTransactionReference\": \"string\",\n \"subType\": \"inbound\",\n \"type\": \"transfer\",\n \"amount\": \"11\",\n \"currency\": \"USD\",\n \"descriptionText\": \"string\",\n \"requestDate\": \"2022-09-28T12:51:19.260+00:00\",\n \"customData\": [\n {\n \"key\": \"string\",\n \"value\": \"string\"\n }\n ],\n \"payer\": [\n {\n \"partyIdType\": \"MSISDN\",\n \"partyIdIdentifier\": \"{{MSISDN}}\"\n }\n ],\n \"payee\": [\n {\n \"partyIdType\": \"accountId\",\n \"partyIdIdentifier\": \"{{accountId}}\"\n }\n ]\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{ChannelHostName}}/channel/gsma/transaction", + "host": [ + "{{ChannelHostName}}" + ], + "path": [ + "channel", + "gsma", + "transaction" + ] + } + }, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "name": "Content-Type", + "description": "", + "type": "text" + } + ], + "cookie": [], + "body": "{\n \"transferCode\": \"fb13887d-396b-492c-b481-f634fe0dfb03\",\n \"completedTimestamp\": \"2024-04-24T15:52:08+0530\",\n \"transactionCode\": \"168e49b0-b0e9-4446-a4d8-188f2b9a42e3\",\n \"state\": \"ACCEPTED\"\n}" + } + ] + }, + { + "name": "International Remmitance Payee", + "request": { + "method": "POST", + "header": [ + { + "key": "Platform-TenantId", + "value": "{{PayeeTenantName}}", + "type": "text" + }, + { + "key": "X-CorrelationID", + "value": "{{clientCorrelationId}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"requestingOrganisationTransactionReference\": \"string\",\n \"originalTransactionReference\": \"string\",\n \"subType\": \"string\",\n \"type\": \"transfer\",\n \"amount\": \"11.00\",\n \"currency\": \"USD\",\n \"descriptionText\": \"string\",\n \"fees\": [\n {\n \"feeType\": \"string\",\n \"feeAmount\": \"11\",\n \"feeCurrency\": \"USD\"\n }\n ],\n \"geoCode\": \"37.423825,-122.082900\",\n \"internationalTransferInformation\": {\n \"quotationReference\": \"string\",\n \"quoteId\": \"string\",\n \"originCountry\": \"USA\",\n \"deliveryMethod\": \"directtoaccount\",\n \"receivingCountry\": \"USA\",\n \"relationshipSender\": \"string\",\n \"remittancePurpose\": \"string\"\n },\n \"oneTimeCode\": \"string\",\n \"receiverKyc\": {\n \"birthCountry\": \"USA\",\n \"contactPhone\": \"string\",\n \"dateOfBirth\": \"2000-11-20\",\n \"emailAddress\": \"string\",\n \"employerName\": \"string\",\n \"gender\": \"m\",\n \"idDocument\": [\n {\n \"idType\": \"passport\",\n \"idNumber\": \"string\",\n \"issueDate\": \"2022-09-28T12:51:19.260+00:00\",\n \"expiryDate\": \"2022-09-28T12:51:19.260+00:00\",\n \"issuer\": \"string\",\n \"issuerPlace\": \"string\",\n \"issuerCountry\": \"USA\"\n }\n ],\n \"nationality\": \"USA\",\n \"occupation\": \"string\",\n \"postalAddress\": {\n \"addressLine1\": \"string\",\n \"addressLine2\": \"string\",\n \"addressLine3\": \"string\",\n \"city\": \"string\",\n \"stateProvince\": \"string\",\n \"postalCode\": \"string\",\n \"country\": \"USA\"\n },\n \"subjectName\": {\n \"title\": \"string\",\n \"firstName\": \"string\",\n \"middleName\": \"string\",\n \"lastName\": \"string\",\n \"nativeName\": \"string\"\n }\n },\n \"senderKyc\": {\n \"birthCountry\": \"USA\",\n \"contactPhone\": \"string\",\n \"dateOfBirth\": \"2022-09-28T12:51:19.260+00:00\",\n \"emailAddress\": \"string\",\n \"employerName\": \"string\",\n \"gender\": \"m\",\n \"idDocument\": [\n {\n \"idType\": \"passport\",\n \"idNumber\": \"string\",\n \"issueDate\": \"2022-09-28T12:51:19.260+00:00\",\n \"expiryDate\": \"2022-09-28T12:51:19.260+00:00\",\n \"issuer\": \"string\",\n \"issuerPlace\": \"string\",\n \"issuerCountry\": \"USA\"\n }\n ],\n \"nationality\": \"USA\",\n \"occupation\": \"string\",\n \"postalAddress\": {\n \"addressLine1\": \"string\",\n \"addressLine2\": \"string\",\n \"addressLine3\": \"string\",\n \"city\": \"string\",\n \"stateProvince\": \"string\",\n \"postalCode\": \"string\",\n \"country\": \"USA\"\n },\n \"subjectName\": {\n \"title\": \"string\",\n \"firstName\": \"string\",\n \"middleName\": \"string\",\n \"lastName\": \"string\",\n \"nativeName\": \"string\"\n }\n },\n \"servicingIdentity\": \"string\",\n \"requestDate\": \"2022-09-28T12:51:19.260+00:00\",\n \"metadata\": [\n {\n \"key\": \"string\",\n \"value\": \"string\"\n }\n ],\n \"creditParty\": [\n {\n \"key\": \"msisdn\",\n \"value\": \"+449999112\"\n }\n ],\n \"debitParty\": [\n {\n \"key\": \"msisdn\",\n \"value\": \"+449999999\"\n }\n ]\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{ChannelHostName}}/channel/gsma/deposit", + "host": [ + "{{ChannelHostName}}" + ], + "path": [ + "channel", + "gsma", + "deposit" + ] + } + }, + "response": [] + } + ] + }, + { + "name": "Transfer Query", + "request": { + "method": "GET", + "header": [ + { + "key": "Platform-TenantId", + "value": "{{PlatformTenant}}", + "type": "text" + } + ], + "url": { + "raw": "{{ChannelHostName}}/channel/transfer/{{transactionId}}", + "host": [ + "{{ChannelHostName}}" + ], + "path": [ + "channel", + "transfer", + "{{transactionId}}" + ] + } + }, + "response": [] + }, + { + "name": "Transfer", + "request": { + "method": "POST", + "header": [ + { + "key": "Platform-TenantId", + "value": "{{PlatformTenant}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"payer\": {\n \"partyIdInfo\": {\n \"partyIdType\": \"MSISDN\",\n \"partyIdentifier\": \"27710101999\"\n }\n },\n \"payee\": {\n \"partyIdInfo\": {\n \"partyIdType\": \"MSISDN\",\n \"partyIdentifier\": \"27710102999\"\n }\n },\n \"amount\": {\n \"amount\": 230,\n \"currency\": \"TZS\"\n }\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{ChannelHostName}}/channel/transfer", + "host": [ + "{{ChannelHostName}}" + ], + "path": [ + "channel", + "transfer" + ] + } + }, + "response": [] + }, + { + "name": "Transfer Request", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"payer\": {\n \"partyIdInfo\": {\n \"partyIdType\": \"MSISDN\",\n \"partyIdentifier\": \"27710203999\"\n }\n },\n \"payee\": {\n \"partyIdInfo\": {\n \"partyIdType\": \"MSISDN\",\n \"partyIdentifier\": \"27710305999\"\n }\n },\n \"amount\": {\n \"amount\": 77,\n \"currency\": \"TZS\"\n }\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{ChannelHostName}}/channel/transactionRequest", + "host": [ + "{{ChannelHostName}}" + ], + "path": [ + "channel", + "transactionRequest" + ] + } + }, + "response": [] + }, + { + "name": "Party Registration", + "request": { + "method": "POST", + "header": [ + { + "key": "Platform-TenantId", + "value": "{{TenantName}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"accountId\":\"9062b90de19b43989005\",\n \"idType\": \"EMAIL\",\n \"idValue\": \"test@test.hu\"\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{ChannelHostName}}/channel/partyRegistration", + "host": [ + "{{ChannelHostName}}" + ], + "path": [ + "channel", + "partyRegistration" + ] + } + }, + "response": [] + }, + { + "name": "Get Txn by Client Id", + "request": { + "method": "GET", + "header": [ + { + "key": "Platform-TenantId", + "value": "{{TenantName}}", + "type": "text" + }, + { + "key": "requestType", + "value": "transfers", + "type": "text" + } + ], + "url": { + "raw": "{{ChannelHostName}}/channel/txnState/{{X-CorrelationID}}", + "host": [ + "{{ChannelHostName}}" + ], + "path": [ + "channel", + "txnState", + "{{X-CorrelationID}}" + ] + } + }, + "response": [] + } + ] + }, + { + "name": "Mobile Money APIs", + "item": [ + { + "name": "Bilateral Money Transfer", + "request": { + "method": "POST", + "header": [ + { + "key": "Platform-TenantId", + "value": "tn05", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"payer\": {\n \"partyIdInfo\": {\n \"partyIdType\": \"MSISDN\",\n \"partyIdentifier\": \"+449999999\"\n }\n },\n \"payee\": {\n \"partyIdInfo\": {\n \"partyIdType\": \"MSISDN\",\n \"partyIdentifier\": \"+449999112\"\n }\n },\n \"amount\": {\n \"amount\": 6,\n \"currency\": \"TZS\"\n }\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{ChannelHostName}}/channel/{{provider}}/transfer", + "host": [ + "{{ChannelHostName}}" + ], + "path": [ + "channel", + "{{provider}}", + "transfer" + ] + } + }, + "response": [] + }, + { + "name": "MerchantPay", + "request": { + "method": "POST", + "header": [ + { + "key": "Platform-TenantId", + "value": "tn05", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"payer\": {\n \"partyIdInfo\": {\n \"partyIdType\": \"MSISDN\",\n \"partyIdentifier\": \"+449999999\"\n }\n },\n \"payee\": {\n \"partyIdInfo\": {\n \"partyIdType\": \"MSISDN\",\n \"partyIdentifier\": \"+449999112\"\n }\n },\n \"amount\": {\n \"amount\": 6,\n \"currency\": \"TZS\"\n }\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{ChannelHostName}}/channel/{{provider}}/merchantpay", + "host": [ + "{{ChannelHostName}}" + ], + "path": [ + "channel", + "{{provider}}", + "merchantpay" + ] + } + }, + "response": [] + }, + { + "name": "MerchantPay with AuthCode", + "request": { + "method": "POST", + "header": [ + { + "key": "Platform-TenantId", + "value": "tn05", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"payer\": {\n \"partyIdInfo\": {\n \"partyIdType\": \"MSISDN\",\n \"partyIdentifier\": \"+449999999\"\n }\n },\n \"payee\": {\n \"partyIdInfo\": {\n \"partyIdType\": \"MSISDN\",\n \"partyIdentifier\": \"+449999112\"\n }\n },\n \"amount\": {\n \"amount\": 6,\n \"currency\": \"TZS\"\n }\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{ChannelHostName}}/channel/{{provider}}/merchantpay/authcode/{{authorizationCode}}", + "host": [ + "{{ChannelHostName}}" + ], + "path": [ + "channel", + "{{provider}}", + "merchantpay", + "authcode", + "{{authorizationCode}}" + ] + } + }, + "response": [] + }, + { + "name": "International Transfer", + "request": { + "method": "POST", + "header": [ + { + "key": "Platform-TenantId", + "type": "text", + "value": "ibank-usa" + }, + { + "key": "Content-Type", + "type": "text", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"amount\": \"54\",\r\n \"type\": \"transfer\",\r\n \"requestingLei\": \"ibank-usa\", \r\n \"receivingLei\": \"ibank-india\",\r\n \"creditParty\": [\r\n {\r\n \"key\": \"msisdn\",\r\n \"value\": \"919900878571\"\r\n }\r\n ],\r\n \"currency\": \"USD\",\r\n \"debitParty\": [\r\n {\r\n \"key\": \"msisdn\",\r\n \"value\": \"7543010\"\r\n }\r\n ],\r\n \"internationalTransferInformation\":{\r\n \"originCountry\":\"US\",\r\n \"receivingCountry\":\"IN\",\r\n \"receivingCurrency\":\"INR\",\r\n \"currencyPair\":\"INR/USD\"\r\n }\r\n}" + }, + "url": { + "raw": "{{ChannelHostName}}/channel/{{provider}}/inttransfer", + "host": [ + "{{ChannelHostName}}" + ], + "path": [ + "channel", + "{{provider}}", + "inttransfer" + ] + } + }, + "response": [] + }, + { + "name": "Deposit Money", + "request": { + "method": "POST", + "header": [ + { + "key": "Platform-TenantId", + "value": "ibank-usa", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"amount\": \"304\",\n \"type\": \"transfer\",\n \"creditParty\": [\n {\n \"key\": \"msisdn\",\n \"value\": \"+919900878571\"\n }\n ],\n \"currency\": \"USD\"\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{ChannelHostName}}/channel/{{provider}}/deposit", + "host": [ + "{{ChannelHostName}}" + ], + "path": [ + "channel", + "{{provider}}", + "deposit" + ] + } + }, + "response": [] + } + ] + }, + { + "name": "Bulk APIs", + "item": [ + { + "name": "Bulk transfer older", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "postman.setEnvironmentVariable(\"batchId\", jsonData.pollingApi);" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "GET", + "header": [ + { + "key": "Platform-TenantId", + "value": "{{TenantName}}", + "type": "text" + }, + { + "key": "X-CorrelationID", + "value": "{{clientCorrelationId}}", + "type": "text" + } + ], + "url": { + "raw": "{{BulkHostName}}/channel/bulk/transfer/ph-ee-bulk-demo-8.csv", + "host": [ + "{{BulkHostName}}" + ], + "path": [ + "channel", + "bulk", + "transfer", + "ph-ee-bulk-demo-8.csv" + ] + } + }, + "response": [ + { + "name": "Bulk transfer older success", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "Platform-TenantId", + "value": "{{TenantName}}", + "type": "text" + } + ], + "url": { + "raw": "{{BulkHostName}}/channel/bulk/transfer/ph-ee-bulk-demo-8.csv", + "host": [ + "{{BulkHostName}}" + ], + "path": [ + "channel", + "bulk", + "transfer", + "ph-ee-bulk-demo-8.csv" + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "plain", + "header": [ + { + "key": "Date", + "value": "Fri, 07 Oct 2022 10:12:52 GMT" + }, + { + "key": "Content-Length", + "value": "36" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "X-Real-IP", + "value": "172.31.21.123" + }, + { + "key": "Accept-Encoding", + "value": "gzip, deflate, br" + }, + { + "key": "X-Forwarded-Scheme", + "value": "https" + }, + { + "key": "X-Request-ID", + "value": "14c2dd56ee9a222f75b8969e7e7bdefd" + }, + { + "key": "X-Scheme", + "value": "https" + }, + { + "key": "X-Forwarded-Port", + "value": "443" + }, + { + "key": "X-Forwarded-For", + "value": "172.31.21.123" + }, + { + "key": "Referer", + "value": "http://bulk-connector.sandbox.fynarfin.io/channel/bulk/transfer/ph-ee-bulk-demo-8.csv" + }, + { + "key": "X-Forwarded-Host", + "value": "bulk-connector.sandbox.fynarfin.io" + }, + { + "key": "Accept", + "value": "*/*" + }, + { + "key": "Postman-Token", + "value": "f8abf77b-694f-417e-a127-0b33caff7aff" + }, + { + "key": "fileName", + "value": "ph-ee-bulk-demo-8.csv" + }, + { + "key": "User-Agent", + "value": "PostmanRuntime/7.29.2" + }, + { + "key": "X-Forwarded-Proto", + "value": "https" + }, + { + "key": "Platform-TenantId", + "value": "ibank-usa" + }, + { + "key": "Strict-Transport-Security", + "value": "max-age=15724800; includeSubDomains" + } + ], + "cookie": [], + "body": "d981b089-514b-4400-a7c7-499b56ed1c37" + } + ] + }, + { + "name": "Bulk Transfer", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 200\", function () {", + " pm.response.to.have.status(200);", + " pm.expect(pm.response.text).not.equal(null)", + "});", + "var jsonData = JSON.parse(responseBody);", + "postman.setEnvironmentVariable(\"batchId\", jsonData.pollingApi);", + "", + "if(postman.getEnvironmentVariable(\"AutoTest\") == \"true\"){", + " var nextTextIndex = Number(postman.getEnvironmentVariable(\"NextTestIndex\"));", + " var apis = pm.environment.get('TestApiList');", + " var testList = JSON.parse(apis);", + " if(testList.length>nextTextIndex){", + " postman.setEnvironmentVariable(\"NextTestIndex\", 1+ nextTextIndex);", + " postman.setNextRequest(testList[nextTextIndex]); ", + " }else{", + " postman.setNextRequest(null); ", + " }", + "}" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Platform-TenantId", + "value": "{{TenantName}}" + }, + { + "key": "X-CorrelationID", + "value": "{{clientCorrelationId}}", + "type": "text" + }, + { + "key": "X-Callback-URL", + "value": "{{BulkHostName}}/simulate", + "type": "text" + } + ], + "body": { + "mode": "formdata", + "formdata": [ + { + "key": "data", + "description": "CSV file conisiting of transaction details. CSV format: \"id\", \"request_id\", \"payment_mode\", \"account_number\", \"amount\", \"currency\", \"note\" in the given order. ", + "type": "file", + "src": "{{batchFilePath}}" + }, + { + "key": "requestId", + "value": "3a4dfab5-0f4f-4e78-b6b5-1aff3859d4e8", + "description": "Request ID for client side batch correlation. ", + "type": "text", + "disabled": true + }, + { + "key": "purpose", + "value": "test payment", + "description": "Optional field stating purpose of the batch.", + "type": "text", + "disabled": true + } + ] + }, + "url": { + "raw": "{{BulkHostName}}/bulk/transfer/{{$guid}}/ph-ee-bulk-demo-6.csv", + "host": [ + "{{BulkHostName}}" + ], + "path": [ + "bulk", + "transfer", + "{{$guid}}", + "ph-ee-bulk-demo-6.csv" + ] + } + }, + "response": [ + { + "name": "Bulk Transfer", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "Platform-TenantId", + "value": "ibank-usa" + } + ], + "body": { + "mode": "formdata", + "formdata": [ + { + "key": "data", + "description": "CSV file conisiting of transaction details. CSV format: \"id\", \"request_id\", \"payment_mode\", \"account_number\", \"amount\", \"currency\", \"note\" in the given order. ", + "type": "file", + "src": "/Users/subhampramanik/Downloads/download.csv" + }, + { + "key": "requestId", + "value": "3a4dfab5-0f4f-4e78-b6b5-1aff3859d4e8", + "description": "Request ID for client side batch correlation. ", + "type": "text" + }, + { + "key": "purpose", + "value": "iliydufkgiku", + "description": "Optional field stating purpose of the batch.", + "type": "text" + } + ] + }, + "url": { + "raw": "{{ChannelHostName}}/channel/bulk/transfer", + "host": [ + "{{ChannelHostName}}" + ], + "path": [ + "channel", + "bulk", + "transfer" + ] + } + }, + "_postman_previewlanguage": "json", + "header": [], + "cookie": [], + "body": "{\n \"batch_id\": \"738bd830-3bd9-4511-bb42-3d0f5798e014\",\n \"request_id\": \"3a4dfab5-0f4f-4e78-b6b5-1aff3859d4e8\",\n \"status\": \"queued\"\n}" + } + ] + }, + { + "name": "Batch Transactions", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "var jsonData = JSON.parse(responseBody);", + "postman.setEnvironmentVariable(\"batchId\", jsonData.pollingApi);" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Purpose", + "value": "test payment", + "type": "text" + }, + { + "key": "filename", + "value": "ph-ee-bulk-demo-7.csv", + "type": "text" + }, + { + "key": "X-CorrelationID", + "value": "{{X-CorrelationId}}", + "type": "text" + }, + { + "key": "Platform-TenantId", + "value": "{{TenantName}}", + "type": "text" + }, + { + "key": "X-Signature", + "value": "{{x-signature}}", + "type": "text" + }, + { + "key": "type", + "value": "csv", + "type": "text" + } + ], + "body": { + "mode": "formdata", + "formdata": [ + { + "key": "data", + "type": "file", + "src": "/Users/ankitagarwal/fynarfin/ph-ee-bulk-demo-7.csv" + } + ] + }, + "url": { + "raw": "{{BulkHostName}}/batchtransactions", + "host": [ + "{{BulkHostName}}" + ], + "path": [ + "batchtransactions" + ], + "query": [ + { + "key": "type", + "value": "csv", + "disabled": true + } + ] + } + }, + "response": [ + { + "name": "Batch Transactions", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "Purpose", + "value": "test payment", + "type": "text" + }, + { + "key": "filename", + "value": "ph-ee-bulk-demo-6.csv", + "type": "text" + }, + { + "key": "X-CorrelationID", + "value": "{{X-CorrelationId}}", + "type": "text" + }, + { + "key": "Platform-TenantId", + "value": "{{TenantName}}", + "type": "text" + }, + { + "key": "X-Signature", + "value": "{{X-Signature}}", + "type": "text" + }, + { + "key": "type", + "value": "csv", + "type": "text" + } + ], + "body": { + "mode": "formdata", + "formdata": [ + { + "key": "data", + "type": "file", + "src": "/Users/dhavalmaniyar/Documents/projects/ph-ee-connector-integration-test/src/test/java/resources/batch_demo_csv/ph-ee-bulk-demo-6.csv" + } + ] + }, + "url": { + "raw": "{{BulkHostName}}/batchtransactions", + "host": [ + "{{BulkHostName}}" + ], + "path": [ + "batchtransactions" + ], + "query": [ + { + "key": "type", + "value": "csv", + "disabled": true + } + ] + } + }, + "status": "Accepted", + "code": 202, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Content-Length", + "value": "102" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Platform-TenantId", + "value": "gorilla" + }, + { + "key": "X-SIGNATURE", + "value": "Ta+CtpvS8KjuV9yxhjBjl+OJHwJ4x+52ha82sx7ozVELDSFIPgkjCWreEMI95urBVHorkJtY3yX0+5DJodynyShL017qoYgZOZRYZZRy3JFB15Nmi3BCtvsLQc94PMsnX4zx2Nlo2g/YTyWTTU/uAGIWXmnkjMgy7mX5/r5lBpGyVu2T0xdVHF109+/3do8YJA9MTieBlInCp6bxaCRXLLkb23DiC+T+sHhzRZ2ODj5cWcKBLvDvDCz/V4n90nYyHSaxPb6EfoxZlLU2013tSnhIXW6e95el/X4Rq8QRQ6OoZgN4mi75miF+zibDex9BvTIgxCgYSuVSjB0fS7E8FQ==" + }, + { + "key": "Date", + "value": "Fri, 15 Mar 2024 08:00:53 GMT" + }, + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "Access-Control-Expose-Headers", + "value": "*" + }, + { + "key": "X-Kong-Upstream-Latency", + "value": "136" + }, + { + "key": "X-Kong-Proxy-Latency", + "value": "1" + }, + { + "key": "Via", + "value": "kong/3.2.1.0-enterprise-edition" + } + ], + "cookie": [], + "body": "{\n \"PollingPath\": \"/batch/Summary/fc9ea097-4566-43aa-82d4-dd455ad55e99\",\n \"SuggestedCallbackSeconds\": \"120\"\n}" + }, + { + "name": "Batch Transactions Callback", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "Purpose", + "value": "test payment", + "type": "text" + }, + { + "key": "filename", + "value": "ph-ee-bulk-demo-6.csv", + "type": "text" + }, + { + "key": "X-CorrelationID", + "value": "{{X-CorrelationId}}", + "type": "text" + }, + { + "key": "Platform-TenantId", + "value": "{{TenantName}}", + "type": "text" + }, + { + "key": "X-Signature", + "value": "{{X-Signature}}", + "type": "text" + }, + { + "key": "type", + "value": "csv", + "type": "text" + } + ], + "body": { + "mode": "formdata", + "formdata": [ + { + "key": "data", + "type": "file", + "src": "/Users/dhavalmaniyar/Documents/projects/ph-ee-connector-integration-test/src/test/java/resources/batch_demo_csv/ph-ee-bulk-demo-6.csv" + } + ] + }, + "url": { + "raw": "{{BulkHostName}}/batchtransactions", + "host": [ + "{{BulkHostName}}" + ], + "path": [ + "batchtransactions" + ], + "query": [ + { + "key": "type", + "value": "csv", + "disabled": true + } + ] + } + }, + "status": "Accepted", + "code": 202, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Content-Length", + "value": "102" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Platform-TenantId", + "value": "gorilla" + }, + { + "key": "X-SIGNATURE", + "value": "Ta+CtpvS8KjuV9yxhjBjl+OJHwJ4x+52ha82sx7ozVELDSFIPgkjCWreEMI95urBVHorkJtY3yX0+5DJodynyShL017qoYgZOZRYZZRy3JFB15Nmi3BCtvsLQc94PMsnX4zx2Nlo2g/YTyWTTU/uAGIWXmnkjMgy7mX5/r5lBpGyVu2T0xdVHF109+/3do8YJA9MTieBlInCp6bxaCRXLLkb23DiC+T+sHhzRZ2ODj5cWcKBLvDvDCz/V4n90nYyHSaxPb6EfoxZlLU2013tSnhIXW6e95el/X4Rq8QRQ6OoZgN4mi75miF+zibDex9BvTIgxCgYSuVSjB0fS7E8FQ==" + }, + { + "key": "Date", + "value": "Fri, 15 Mar 2024 08:00:53 GMT" + }, + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "Access-Control-Expose-Headers", + "value": "*" + }, + { + "key": "X-Kong-Upstream-Latency", + "value": "136" + }, + { + "key": "X-Kong-Proxy-Latency", + "value": "1" + }, + { + "key": "Via", + "value": "kong/3.2.1.0-enterprise-edition" + } + ], + "cookie": [], + "body": "{\n \"clientCorrelationId\": \"2251799816458110\",\n \"batchId\": \"fc9ea097-4566-43aa-82d4-dd455ad55e99\",\n \"message\": \"The Batch Aggregation API was complete with : 100\"\n}" + } + ] + }, + { + "name": "Batch Transactions JSON", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 200\", function () {", + " pm.response.to.have.status(200);", + "});", + "var jsonData = JSON.parse(responseBody);", + "postman.setEnvironmentVariable(\"batchId\", jsonData.pollingApi);", + "", + "pm.test(\"Response value check\", function () {", + " var jsonData = pm.response.json();", + " pm.expect(jsonData.batch_id)!=null;", + " pm.expect(jsonData.status)!=null;", + " pm.expect(jsonData.request_id)!=null;", + "});", + "", + "", + "if(postman.getEnvironmentVariable(\"AutoTest\") == \"true\"){", + " var nextTextIndex = Number(postman.getEnvironmentVariable(\"NextTestIndex\"));", + " var apis = pm.environment.get('TestApiList');", + " var testList = JSON.parse(apis);", + " if(testList.length>nextTextIndex){", + " postman.setEnvironmentVariable(\"NextTestIndex\", 1+ nextTextIndex);", + " postman.setNextRequest(testList[nextTextIndex]); ", + " }else{", + " postman.setNextRequest(null); ", + " }", + "}" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Purpose", + "value": "test payment", + "type": "text" + }, + { + "key": "X-CorrelationID", + "value": "{{X-CorrelationId}}", + "type": "text" + }, + { + "key": "Platform-TenantId", + "value": "{{TenantName}}", + "type": "text" + }, + { + "key": "X-Signature", + "value": "{{x-signature}}", + "type": "text" + }, + { + "key": "type", + "value": "raw", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "[\n {\n \"creditParty\": [\n {\n \"key\": \"msisdn\",\n \"value\": \"8837461856\"\n }\n ],\n \"debitParty\": [\n {\n \"key\": \"accountnumber\",\n \"value\": \"003001003874120160\"\n }\n ],\n \"subType\": \"SLCB\",\n \"amount\": \"820.00\",\n \"currency\": \"RWF\",\n \"descriptionText\": \"Test Payment\"\n },\n {\n \"creditParty\": [\n {\n \"key\": \"msisdn\",\n \"value\": \"32131461856\"\n }\n ],\n \"debitParty\": [\n {\n \"key\": \"accountnumber\",\n \"value\": \"21314556003874120160\"\n }\n ],\n \"subType\": \"SLCB\",\n \"amount\": \"20.00\",\n \"currency\": \"RWF\",\n \"descriptionText\": \"Test Payment\"\n }\n]", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{BulkHostName}}/batchtransactions", + "host": [ + "{{BulkHostName}}" + ], + "path": [ + "batchtransactions" + ] + } + }, + "response": [] + }, + { + "name": "Bulk Account Lookup", + "request": { + "method": "POST", + "header": [ + { + "key": "Platform-TenantId", + "value": "{{TenantName}}" + }, + { + "key": "X-CorrelationID", + "value": "{{clientCorrelationId}}", + "type": "text" + } + ], + "body": { + "mode": "formdata", + "formdata": [ + { + "key": "data", + "description": "CSV file conisiting of transaction details. CSV format: \"id\", \"payment_mode\", \"account_number\", \"note\" in the given order. ", + "type": "file", + "src": "/Users/subhampramanik/Downloads/download.csv" + }, + { + "key": "requestId", + "value": "3a4dfab5-0f4f-4e78-b6b5-1aff3859d4e8", + "description": "Request ID for client side batch correlation. ", + "type": "text" + }, + { + "key": "purpose", + "value": "iliydufkgiku", + "description": "Optional field stating purpose of the batch.", + "type": "text" + } + ] + }, + "url": { + "raw": "{{ChannelHostName}}/channel/bulk/lookup", + "host": [ + "{{ChannelHostName}}" + ], + "path": [ + "channel", + "bulk", + "lookup" + ] + } + }, + "response": [ + { + "name": "Bulk Account Lookup", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "Platform-TenantId", + "value": "ibank-usa" + } + ], + "body": { + "mode": "formdata", + "formdata": [ + { + "key": "data", + "description": "CSV file conisiting of transaction details. CSV format: \"id\", \"payment_mode\", \"account_number\", \"note\" in the given order. ", + "type": "file", + "src": "/Users/subhampramanik/Downloads/download.csv" + }, + { + "key": "requestId", + "value": "3a4dfab5-0f4f-4e78-b6b5-1aff3859d4e8", + "description": "Request ID for client side batch correlation. ", + "type": "text" + }, + { + "key": "purpose", + "value": "iliydufkgiku", + "description": "Optional field stating purpose of the batch.", + "type": "text" + } + ] + }, + "url": { + "raw": "{{ChannelHostName}}/channel/bulk/lookup", + "host": [ + "{{ChannelHostName}}" + ], + "path": [ + "channel", + "bulk", + "lookup" + ] + } + }, + "_postman_previewlanguage": "json", + "header": [], + "cookie": [], + "body": "{\n \"batch_id\": \"738bd830-3bd9-4511-bb42-3d0f5798e014\",\n \"request_id\": \"3a4dfab5-0f4f-4e78-b6b5-1aff3859d4e8\",\n \"status\": \"queued\"\n}" + } + ] + }, + { + "name": "Batch Summary", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 200\", function () {", + " pm.response.to.have.status(200);", + " pm.expect(pm.response.text).not.equal(null)", + "});", + "", + "if(postman.getEnvironmentVariable(\"AutoTest\") == \"true\"){", + " var nextTextIndex = Number(postman.getEnvironmentVariable(\"NextTestIndex\"));", + " var apis = pm.environment.get('TestApiList');", + " var testList = JSON.parse(apis);", + " if(testList.length>nextTextIndex){", + " postman.setEnvironmentVariable(\"NextTestIndex\", 1+ nextTextIndex);", + " postman.setNextRequest(testList[nextTextIndex]); ", + " }else{", + " postman.setNextRequest(null); ", + " }", + "}" + ], + "type": "text/javascript" + } + } + ], + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "{{access_token}}", + "type": "string" + } + ] + }, + "method": "GET", + "header": [ + { + "key": "User-Agent", + "value": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:90.0) Gecko/20100101 Firefox/90.0", + "disabled": true + }, + { + "key": "Accept", + "value": "application/json, text/plain, */*", + "disabled": true + }, + { + "key": "Accept-Language", + "value": "en-US,en;q=0.5", + "disabled": true + }, + { + "key": "Platform-TenantId", + "value": "{{TenantName}}" + }, + { + "key": "Authorization", + "value": "Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsiaWRlbnRpdHktcHJvdmlkZXIiLCJpYmFuay11c2EiXSwic2NvcGUiOlsiaWRlbnRpdHkiXSwiZXhwIjoxNjMyNjY3MjY4LCJhdXRob3JpdGllcyI6WyJBTExfRlVOQ1RJT05TIl0sImp0aSI6InE2bklEMUZSNzlvM1JTK2U2enZVZ2hoa0c2ST0iLCJjbGllbnRfaWQiOiJjaGFubmVsLWliYW5rLXVzYSJ9.pt-az4y6ue2OEh5PIpV8cPkhHFwql_XK8OVRc_31gH-8GLwwZwtG9Q1k16LNxfTG4lsDpPYkJUO7UwabJlDuEfIzQtMhalVY3QwkFKjOr9T77c9esFHsjJ35FfQ5cVEDW3dUgFjF_1l-QsPAD1Nil1JSpYg-tXy8bJaVn1BI8VxYrN713VB-ZOs-eVJC_0zdK8iUHGmbSxuHojfhsj3INvU6vYYzo0u-jCzFfxImrIIFdia8DuL1S6sy4kd2ZM08_NCw_4rzW3hCgL9Yu0u_SfO2iJvh0BsXg4DC8iweBfq8rDqfQNR0Vzew9zCmiynZBWbp3elmkNnZDcVJU3yTww" + }, + { + "key": "Origin", + "value": "http://localhost:4200", + "disabled": true + }, + { + "key": "Connection", + "value": "keep-alive", + "disabled": true + }, + { + "key": "Referer", + "value": "http://localhost:4200/", + "disabled": true + } + ], + "url": { + "raw": "{{OperationsHostName}}/api/v1/batch?batchId={{batchId}}&X-CorrelationID={{clientCorrelationId}}", + "host": [ + "{{OperationsHostName}}" + ], + "path": [ + "api", + "v1", + "batch" + ], + "query": [ + { + "key": "direction", + "value": "OUTGOING", + "description": "INCOMING or OUTGOING direction", + "disabled": true + }, + { + "key": "status", + "value": "ONGOING", + "description": "Transaction State can be ONGOING, STARTED, FAILED", + "disabled": true + }, + { + "key": "batchId", + "value": "{{batchId}}" + }, + { + "key": "X-CorrelationID", + "value": "{{clientCorrelationId}}" + } + ] + } + }, + "response": [ + { + "name": "Batch Summary", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "User-Agent", + "value": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:90.0) Gecko/20100101 Firefox/90.0", + "disabled": true + }, + { + "key": "Accept", + "value": "application/json, text/plain, */*", + "disabled": true + }, + { + "key": "Accept-Language", + "value": "en-US,en;q=0.5", + "disabled": true + }, + { + "key": "Platform-TenantId", + "value": "ibank-usa" + }, + { + "key": "Authorization", + "value": "Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsiaWRlbnRpdHktcHJvdmlkZXIiLCJpYmFuay11c2EiXSwic2NvcGUiOlsiaWRlbnRpdHkiXSwiZXhwIjoxNjMyNjY3MjY4LCJhdXRob3JpdGllcyI6WyJBTExfRlVOQ1RJT05TIl0sImp0aSI6InE2bklEMUZSNzlvM1JTK2U2enZVZ2hoa0c2ST0iLCJjbGllbnRfaWQiOiJjaGFubmVsLWliYW5rLXVzYSJ9.pt-az4y6ue2OEh5PIpV8cPkhHFwql_XK8OVRc_31gH-8GLwwZwtG9Q1k16LNxfTG4lsDpPYkJUO7UwabJlDuEfIzQtMhalVY3QwkFKjOr9T77c9esFHsjJ35FfQ5cVEDW3dUgFjF_1l-QsPAD1Nil1JSpYg-tXy8bJaVn1BI8VxYrN713VB-ZOs-eVJC_0zdK8iUHGmbSxuHojfhsj3INvU6vYYzo0u-jCzFfxImrIIFdia8DuL1S6sy4kd2ZM08_NCw_4rzW3hCgL9Yu0u_SfO2iJvh0BsXg4DC8iweBfq8rDqfQNR0Vzew9zCmiynZBWbp3elmkNnZDcVJU3yTww" + }, + { + "key": "Origin", + "value": "http://localhost:4200", + "disabled": true + }, + { + "key": "Connection", + "value": "keep-alive", + "disabled": true + }, + { + "key": "Referer", + "value": "http://localhost:4200/", + "disabled": true + } + ], + "url": { + "raw": "{{OperationsHostName}}/api/v1/batch?batchId={{batchId}}", + "host": [ + "{{OperationsHostName}}" + ], + "path": [ + "api", + "v1", + "batch" + ], + "query": [ + { + "key": "direction", + "value": "OUTGOING", + "description": "INCOMING or OUTGOING direction", + "disabled": true + }, + { + "key": "status", + "value": "ONGOING", + "description": "Transaction State can be ONGOING, STARTED, FAILED", + "disabled": true + }, + { + "key": "batchId", + "value": "{{batchId}}" + } + ] + } + }, + "_postman_previewlanguage": "json", + "header": [], + "cookie": [], + "body": "{\n \"batchId\": \"c02a14f0-5e7e-44a1-88eb-5584a21e6f28\",\n \"requestId\": \"dhgdfe-jiae-ugir-bsjf-ndsdfsdfdfd\",\n \"totalTransactions\": 2,\n \"ongoing\": 2,\n \"failed\": 0,\n \"completed\": 0,\n \"total_amount\": 767,\n \"completed_amount\": 0,\n \"ongoing_amount\": 767,\n \"failed_amount\": 0,\n \"result_file\": null,\n \"resultGeneratedAt\": 1634955667187,\n \"note\": \"Sample Response\"\n}" + } + ] + }, + { + "name": "Batch Details", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 200\", function () {", + " pm.response.to.have.status(200);", + " pm.expect(pm.response.text).not.equal(null)", + "});", + "", + "pm.test(\"Empty Content test\", () => {", + " var jsonData = pm.response.json();", + " pm.expect(jsonData.content).to.be.an(\"array\");", + " pm.expect(jsonData.content).length.greaterThan(0);", + "});", + "", + "pm.test(\"Party and payee null data check\", () => {", + " var jsonData = pm.response.json();", + " var contentArray = jsonData.content;", + " console.log(contentArray)", + " contentArray.forEach( (transfer) => {", + " let payeeDfspId = transfer.payeeDfspId;", + " let payeePartyId = transfer.payeePartyId;", + " let payeePartyIdType = transfer.payeePartyIdType;", + " let payerDfspId = transfer.payerDfspId;", + " let payerPartyId = transfer.payerPartyId;", + " let payerPartyIdType = transfer.payerPartyIdType;", + "", + " pm.expect(payeeDfspId).not.equal(null);", + " pm.expect(payeePartyId).not.equal(null);", + " pm.expect(payeePartyIdType).not.equal(null);", + " pm.expect(payerDfspId).not.equal(null);", + " pm.expect(payerPartyId).not.equal(null);", + " pm.expect(payerPartyIdType).not.equal(null);", + " })", + "});", + "", + "if(postman.getEnvironmentVariable(\"AutoTest\") == \"true\"){", + " var nextTextIndex = Number(postman.getEnvironmentVariable(\"NextTestIndex\"));", + " var apis = pm.environment.get('TestApiList');", + " var testList = JSON.parse(apis);", + " if(testList.length>nextTextIndex){", + " postman.setEnvironmentVariable(\"NextTestIndex\", 1+ nextTextIndex);", + " postman.setNextRequest(testList[nextTextIndex]); ", + " }else{", + " postman.setNextRequest(null); ", + " }", + "}" + ], + "type": "text/javascript" + } + } + ], + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "{{access_token}}", + "type": "string" + } + ] + }, + "method": "GET", + "header": [ + { + "key": "User-Agent", + "value": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:90.0) Gecko/20100101 Firefox/90.0" + }, + { + "key": "Accept", + "value": "application/json, text/plain, */*" + }, + { + "key": "Accept-Language", + "value": "en-US,en;q=0.5" + }, + { + "key": "Platform-TenantId", + "value": "{{TenantName}}" + }, + { + "key": "Authorization", + "value": "Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsiaWRlbnRpdHktcHJvdmlkZXIiLCJpYmFuay11c2EiXSwic2NvcGUiOlsiaWRlbnRpdHkiXSwiZXhwIjoxNjMyNjMyODYyLCJhdXRob3JpdGllcyI6WyJBTExfRlVOQ1RJT05TIl0sImp0aSI6IkJ1eitMMDZQbnRQcVI4QW1kK2VWVndCVWJMST0iLCJjbGllbnRfaWQiOiJjaGFubmVsLWliYW5rLXVzYSJ9.mXseJ-W1QyGz4rWyj91Goz5LHh-rSlfbABVVRatU2ecwG4CYxkwJn1Xo-WHfvQC45L8Uw3qJqKfhkkJ7mV7cFV5Tm5E6h1aYzPefn-POlo7GBOdrWPPaNvFkBaQKBJaPtqgmcmWBpo56o_XHj6Mz-f3PuepSq57Wi7tbpC1LuLCGxpsSNIvYeWA-_jkFCReGdOhuLphiUzAc1_p0cDVT2bmzSvVaU6sKYK2ZBIBsqfYXkhA5aFvbvFrLWj4o-w2mYrTH7v9689RfvSn57W_xE6aOC2nz_JoKAwaVjraxDl6bRQ_xEmzMJCITnYaFMoJi_dKC4Rp2tVEUb9GASqQfiQ" + }, + { + "key": "Origin", + "value": "http://localhost:4200" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Referer", + "value": "http://localhost:4200/" + } + ], + "url": { + "raw": "{{OperationsHostName}}/api/v1/batch/detail?batchId={{batchId}}&pageSize={{pageSize}}&X-CorrelationID={{clientCorrelationId}}", + "host": [ + "{{OperationsHostName}}" + ], + "path": [ + "api", + "v1", + "batch", + "detail" + ], + "query": [ + { + "key": "direction", + "value": "OUTGOING", + "description": "INCOMING or OUTGOING direction", + "disabled": true + }, + { + "key": "batchId", + "value": "{{batchId}}", + "description": "Batch ID from transaction" + }, + { + "key": "pageNo", + "value": "{{pageNo}}", + "description": "Page Number", + "disabled": true + }, + { + "key": "pageSize", + "value": "{{pageSize}}", + "description": "Page Size" + }, + { + "key": "status", + "value": "{{status}}", + "description": "Transaction Status. Values can be COMPLETED, FAILED, IN_PROGRESS and ALL. By default set to ALL.", + "disabled": true + }, + { + "key": "X-CorrelationID", + "value": "{{clientCorrelationId}}" + } + ] + } + }, + "response": [ + { + "name": "Batch Details", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "User-Agent", + "value": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:90.0) Gecko/20100101 Firefox/90.0" + }, + { + "key": "Accept", + "value": "application/json, text/plain, */*" + }, + { + "key": "Accept-Language", + "value": "en-US,en;q=0.5" + }, + { + "key": "Platform-TenantId", + "value": "ibank-usa" + }, + { + "key": "Authorization", + "value": "Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsiaWRlbnRpdHktcHJvdmlkZXIiLCJpYmFuay11c2EiXSwic2NvcGUiOlsiaWRlbnRpdHkiXSwiZXhwIjoxNjMyNjMyODYyLCJhdXRob3JpdGllcyI6WyJBTExfRlVOQ1RJT05TIl0sImp0aSI6IkJ1eitMMDZQbnRQcVI4QW1kK2VWVndCVWJMST0iLCJjbGllbnRfaWQiOiJjaGFubmVsLWliYW5rLXVzYSJ9.mXseJ-W1QyGz4rWyj91Goz5LHh-rSlfbABVVRatU2ecwG4CYxkwJn1Xo-WHfvQC45L8Uw3qJqKfhkkJ7mV7cFV5Tm5E6h1aYzPefn-POlo7GBOdrWPPaNvFkBaQKBJaPtqgmcmWBpo56o_XHj6Mz-f3PuepSq57Wi7tbpC1LuLCGxpsSNIvYeWA-_jkFCReGdOhuLphiUzAc1_p0cDVT2bmzSvVaU6sKYK2ZBIBsqfYXkhA5aFvbvFrLWj4o-w2mYrTH7v9689RfvSn57W_xE6aOC2nz_JoKAwaVjraxDl6bRQ_xEmzMJCITnYaFMoJi_dKC4Rp2tVEUb9GASqQfiQ" + }, + { + "key": "Origin", + "value": "http://localhost:4200" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Referer", + "value": "http://localhost:4200/" + } + ], + "url": { + "raw": "{{OperationsHostName}}/api/v1/batch/detail?batchId={{batchId}}&pageNo={{pageNo}}&pageSize={{pageSize}}", + "host": [ + "{{OperationsHostName}}" + ], + "path": [ + "api", + "v1", + "batch", + "detail" + ], + "query": [ + { + "key": "direction", + "value": "OUTGOING", + "description": "INCOMING or OUTGOING direction", + "disabled": true + }, + { + "key": "batchId", + "value": "{{batchId}}", + "description": "Batch ID from transaction" + }, + { + "key": "pageNo", + "value": "{{pageNo}}", + "description": "Page Number" + }, + { + "key": "pageSize", + "value": "{{pageSize}}", + "description": "Page Size" + }, + { + "key": "status", + "value": "{{status}}", + "description": "Transaction Status. Values can be COMPLETED, FAILED, IN_PROGRESS and ALL. By default set to ALL.", + "disabled": true + } + ] + } + }, + "_postman_previewlanguage": "json", + "header": [], + "cookie": [], + "body": "[\n {\n \"id\": 568,\n \"workflowInstanceKey\": 2251799907439003,\n \"transactionId\": \"e5eea064-1445-4d32-bc55-bd9826c779a0\",\n \"startedAt\": 1629130966000,\n \"completedAt\": 1629130967000,\n \"status\": \"IN_PROGRESS\",\n \"statusDetail\": null,\n \"payeeDfspId\": \"ibank-india\",\n \"payeePartyId\": \"919900878571\",\n \"payeePartyIdType\": \"MSISDN\",\n \"payeeFee\": null,\n \"payeeFeeCurrency\": null,\n \"payeeQuoteCode\": null,\n \"payerDfspId\": \"ibank-usa\",\n \"payerPartyId\": \"7543010\",\n \"payerPartyIdType\": \"MSISDN\",\n \"payerFee\": null,\n \"payerFeeCurrency\": null,\n \"payerQuoteCode\": null,\n \"amount\": 448,\n \"currency\": \"USD\",\n \"direction\": \"OUTGOING\",\n \"errorInformation\": \"{\\\\\\\"errorInformation\\\\\\\":{\\\\\\\"errorDescription\\\\\\\":\\\\\\\"Invalid responseCode 500 for transfer on PAYER side, transactionId: e5eea064-1445-4d32-bc55-bd9826c779a0 Message: {\\\\\\\\\\\\\\\"timestamp\\\\\\\\\\\\\\\":1629130966891,\\\\\\\\\\\\\\\"status\\\\\\\\\\\\\\\":500,\\\\\\\\\\\\\\\"error\\\\\\\\\\\\\\\":\\\\\\\\\\\\\\\"Internal Server Error\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"message\\\\\\\\\\\\\\\":\\\\\\\\\\\\\\\"\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"path\\\\\\\\\\\\\\\":\\\\\\\\\\\\\\\"/fineract-provider/api/v1/interoperation/transfers\\\\\\\\\\\\\\\"}\\\\\\\",\\\\\\\"errorCode\\\\\\\":\\\\\\\"4101\\\\\\\"}}\",\n \"batchId\": \"c02a14f0-5e7e-44a1-88eb-5584a21e6f28\"\n },\n {\n \"id\": 569,\n \"workflowInstanceKey\": 2251799907439017,\n \"transactionId\": \"3cc88b24-1df6-48e2-8b1f-5dbd02ba96b7\",\n \"startedAt\": 1629130966000,\n \"completedAt\": 1629150766000,\n \"status\": \"IN_PROGRESS\",\n \"statusDetail\": null,\n \"payeeDfspId\": \"ibank-india\",\n \"payeePartyId\": \"919900878571\",\n \"payeePartyIdType\": \"MSISDN\",\n \"payeeFee\": null,\n \"payeeFeeCurrency\": null,\n \"payeeQuoteCode\": null,\n \"payerDfspId\": \"ibank-usa\",\n \"payerPartyId\": \"7543010\",\n \"payerPartyIdType\": \"MSISDN\",\n \"payerFee\": null,\n \"payerFeeCurrency\": null,\n \"payerQuoteCode\": null,\n \"amount\": 319,\n \"currency\": \"USD\",\n \"direction\": \"OUTGOING\",\n \"errorInformation\": null,\n \"batchId\": \"c02a14f0-5e7e-44a1-88eb-5584a21e6f28\"\n }\n]" + } + ] + }, + { + "name": "Batch Lookup Details", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 200\", function () {", + " pm.response.to.have.status(200);", + " pm.expect(pm.response.text).not.equal(null)", + "});", + "", + "if(postman.getEnvironmentVariable(\"AutoTest\") == \"true\"){", + " var nextTextIndex = Number(postman.getEnvironmentVariable(\"NextTestIndex\"));", + " var apis = pm.environment.get('TestApiList');", + " var testList = JSON.parse(apis);", + " if(testList.length>nextTextIndex){", + " postman.setEnvironmentVariable(\"NextTestIndex\", 1+ nextTextIndex);", + " postman.setNextRequest(testList[nextTextIndex]); ", + " }else{", + " postman.setNextRequest(null); ", + " }", + "}" + ], + "type": "text/javascript" + } + } + ], + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "{{access_token}}", + "type": "string" + } + ] + }, + "method": "GET", + "header": [ + { + "key": "User-Agent", + "value": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:90.0) Gecko/20100101 Firefox/90.0" + }, + { + "key": "Accept", + "value": "application/json, text/plain, */*" + }, + { + "key": "Accept-Language", + "value": "en-US,en;q=0.5" + }, + { + "key": "Platform-TenantId", + "value": "{{TenantName}}" + }, + { + "key": "Authorization", + "value": "Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsiaWRlbnRpdHktcHJvdmlkZXIiLCJpYmFuay11c2EiXSwic2NvcGUiOlsiaWRlbnRpdHkiXSwiZXhwIjoxNjMyNjMyODYyLCJhdXRob3JpdGllcyI6WyJBTExfRlVOQ1RJT05TIl0sImp0aSI6IkJ1eitMMDZQbnRQcVI4QW1kK2VWVndCVWJMST0iLCJjbGllbnRfaWQiOiJjaGFubmVsLWliYW5rLXVzYSJ9.mXseJ-W1QyGz4rWyj91Goz5LHh-rSlfbABVVRatU2ecwG4CYxkwJn1Xo-WHfvQC45L8Uw3qJqKfhkkJ7mV7cFV5Tm5E6h1aYzPefn-POlo7GBOdrWPPaNvFkBaQKBJaPtqgmcmWBpo56o_XHj6Mz-f3PuepSq57Wi7tbpC1LuLCGxpsSNIvYeWA-_jkFCReGdOhuLphiUzAc1_p0cDVT2bmzSvVaU6sKYK2ZBIBsqfYXkhA5aFvbvFrLWj4o-w2mYrTH7v9689RfvSn57W_xE6aOC2nz_JoKAwaVjraxDl6bRQ_xEmzMJCITnYaFMoJi_dKC4Rp2tVEUb9GASqQfiQ" + }, + { + "key": "Origin", + "value": "http://localhost:4200" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Referer", + "value": "http://localhost:4200/" + } + ], + "url": { + "raw": "{{OperationsHostName}}/api/v1/batch/detail?batchId={{batchId}}&pageNo={{pageNo}}&pageSize={{pageSize}}&status={{status}}&X-CorrelationID={{clientCorrelationId}}", + "host": [ + "{{OperationsHostName}}" + ], + "path": [ + "api", + "v1", + "batch", + "detail" + ], + "query": [ + { + "key": "batchId", + "value": "{{batchId}}", + "description": "Batch ID from lookup" + }, + { + "key": "pageNo", + "value": "{{pageNo}}", + "description": "Page Number" + }, + { + "key": "pageSize", + "value": "{{pageSize}}", + "description": "Page Size" + }, + { + "key": "status", + "value": "{{status}}", + "description": "Transaction Status. Values can be COMPLETED, FAILED, IN_PROGRESS and ALL. By default set to ALL." + }, + { + "key": "X-CorrelationID", + "value": "{{clientCorrelationId}}" + } + ] + } + }, + "response": [ + { + "name": "Batch Lookup Details", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "User-Agent", + "value": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:90.0) Gecko/20100101 Firefox/90.0" + }, + { + "key": "Accept", + "value": "application/json, text/plain, */*" + }, + { + "key": "Accept-Language", + "value": "en-US,en;q=0.5" + }, + { + "key": "Platform-TenantId", + "value": "ibank-usa" + }, + { + "key": "Authorization", + "value": "Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsiaWRlbnRpdHktcHJvdmlkZXIiLCJpYmFuay11c2EiXSwic2NvcGUiOlsiaWRlbnRpdHkiXSwiZXhwIjoxNjMyNjMyODYyLCJhdXRob3JpdGllcyI6WyJBTExfRlVOQ1RJT05TIl0sImp0aSI6IkJ1eitMMDZQbnRQcVI4QW1kK2VWVndCVWJMST0iLCJjbGllbnRfaWQiOiJjaGFubmVsLWliYW5rLXVzYSJ9.mXseJ-W1QyGz4rWyj91Goz5LHh-rSlfbABVVRatU2ecwG4CYxkwJn1Xo-WHfvQC45L8Uw3qJqKfhkkJ7mV7cFV5Tm5E6h1aYzPefn-POlo7GBOdrWPPaNvFkBaQKBJaPtqgmcmWBpo56o_XHj6Mz-f3PuepSq57Wi7tbpC1LuLCGxpsSNIvYeWA-_jkFCReGdOhuLphiUzAc1_p0cDVT2bmzSvVaU6sKYK2ZBIBsqfYXkhA5aFvbvFrLWj4o-w2mYrTH7v9689RfvSn57W_xE6aOC2nz_JoKAwaVjraxDl6bRQ_xEmzMJCITnYaFMoJi_dKC4Rp2tVEUb9GASqQfiQ" + }, + { + "key": "Origin", + "value": "http://localhost:4200" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Referer", + "value": "http://localhost:4200/" + } + ], + "url": { + "raw": "{{OperationsHostName}}/api/v1/batch/detail?batchId={{batchId}}&pageNo={{pageNo}}&pageSize={{pageSize}}&status={{status}}", + "host": [ + "{{OperationsHostName}}" + ], + "path": [ + "api", + "v1", + "batch", + "detail" + ], + "query": [ + { + "key": "batchId", + "value": "{{batchId}}", + "description": "Batch ID from lookup" + }, + { + "key": "pageNo", + "value": "{{pageNo}}", + "description": "Page Number" + }, + { + "key": "pageSize", + "value": "{{pageSize}}", + "description": "Page Size" + }, + { + "key": "status", + "value": "{{status}}", + "description": "Transaction Status. Values can be COMPLETED, FAILED, IN_PROGRESS and ALL. By default set to ALL." + } + ] + } + }, + "_postman_previewlanguage": "json", + "header": [], + "cookie": [], + "body": "{\n \"batchId\": \"c02a14f0-5e7e-44a1-88eb-5584a21e6f28\",\n \"requestId\": \"dhgdfe-jiae-ugir-bsjf-ndsdfsdfdfd\",\n \"totalTransactions\": 2,\n \"ongoing\": 2,\n \"failed\": 0,\n \"completed\": 0,\n \"result_file\": null,\n \"resultGeneratedAt\": 1634955667187,\n \"note\": \"Sample Response\"\n}" + } + ] + }, + { + "name": "Get All Batches", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 200\", function () {", + " pm.response.to.have.status(200);", + " pm.expect(pm.response.text).not.equal(null)", + "});", + "", + "if(postman.getEnvironmentVariable(\"AutoTest\") == \"true\"){", + " var nextTextIndex = Number(postman.getEnvironmentVariable(\"NextTestIndex\"));", + " var apis = pm.environment.get('TestApiList');", + " var testList = JSON.parse(apis);", + " if(testList.length>nextTextIndex){", + " postman.setEnvironmentVariable(\"NextTestIndex\", 1+ nextTextIndex);", + " postman.setNextRequest(testList[nextTextIndex]); ", + " }else{", + " postman.setNextRequest(null); ", + " }", + "}" + ], + "type": "text/javascript" + } + } + ], + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "{{access_token}}", + "type": "string" + } + ] + }, + "method": "GET", + "header": [ + { + "key": "Platform-TenantId", + "value": "{{TenantName}}", + "type": "text" + } + ], + "url": { + "raw": "{{OperationsHostName}}/api/v1/batches?page=2&size=10&sortedBy=requestFile&sortedOrder=asc&X-CorrelationID={{clientCorrelationId}}", + "host": [ + "{{OperationsHostName}}" + ], + "path": [ + "api", + "v1", + "batches" + ], + "query": [ + { + "key": "page", + "value": "2" + }, + { + "key": "size", + "value": "10" + }, + { + "key": "sortedBy", + "value": "requestFile" + }, + { + "key": "sortedOrder", + "value": "asc" + }, + { + "key": "X-CorrelationID", + "value": "{{clientCorrelationId}}" + } + ] + } + }, + "response": [ + { + "name": "Get All Batches", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "Platform-TenantId", + "value": "ibank-usa", + "type": "text" + } + ], + "url": { + "raw": "{{OperationsHostName}}/api/v1/batches?page=1&size=20", + "host": [ + "{{OperationsHostName}}" + ], + "path": [ + "api", + "v1", + "batches" + ], + "query": [ + { + "key": "page", + "value": "1" + }, + { + "key": "size", + "value": "20" + }, + { + "key": "sortedBy", + "value": null, + "disabled": true + }, + { + "key": "sortedOrder", + "value": null, + "disabled": true + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Date", + "value": "Tue, 13 Sep 2022 06:12:50 GMT" + }, + { + "key": "Content-Type", + "value": "application/json;charset=UTF-8" + }, + { + "key": "Transfer-Encoding", + "value": "chunked" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "X-Content-Type-Options", + "value": "nosniff" + }, + { + "key": "X-XSS-Protection", + "value": "1; mode=block" + }, + { + "key": "Cache-Control", + "value": "no-cache, no-store, max-age=0, must-revalidate" + }, + { + "key": "Pragma", + "value": "no-cache" + }, + { + "key": "Expires", + "value": "0" + }, + { + "key": "X-Frame-Options", + "value": "DENY" + }, + { + "key": "Strict-Transport-Security", + "value": "max-age=15724800; includeSubDomains" + } + ], + "cookie": [], + "body": "{\n \"content\": [\n {\n \"id\": 160,\n \"batchId\": \"589c4134-6739-4f54-b76d-567898c7e349\",\n \"subBatchId\": null,\n \"requestId\": \"3a4dfab5-0f4f-4e78-b6b5-1aff3859d4e8\",\n \"requestFile\": \"1662626306638_ph-ee-bulk-demo-6.csv\",\n \"totalTransactions\": 11,\n \"ongoing\": 0,\n \"failed\": 0,\n \"completed\": 11,\n \"totalAmount\": null,\n \"ongoingAmount\": null,\n \"failedAmount\": null,\n \"completedAmount\": null,\n \"result_file\": \"https://paymenthub-ee-dev.s3.us-east-2.amazonaws.com/1662626353290_1662626353290_response.csv\",\n \"resultGeneratedAt\": 1662626353000,\n \"note\": null,\n \"workflowKey\": null,\n \"workflowInstanceKey\": 2251799816029127,\n \"startedAt\": 1662626307000,\n \"completedAt\": null\n },\n {\n \"id\": 156,\n \"batchId\": \"9dbf00f4-f8a0-48e5-908a-154e5662d86a\",\n \"subBatchId\": null,\n \"requestId\": \"3a4dfab5-0f4f-4e78-b6b5-1aff3859d4e8\",\n \"requestFile\": \"1662625625503_ph-ee-bulk-demo-6.csv\",\n \"totalTransactions\": 11,\n \"ongoing\": 0,\n \"failed\": 0,\n \"completed\": 11,\n \"totalAmount\": null,\n \"ongoingAmount\": null,\n \"failedAmount\": null,\n \"completedAmount\": null,\n \"result_file\": \"https://paymenthub-ee-dev.s3.us-east-2.amazonaws.com/1662625671389_1662625671389_response.csv\",\n \"resultGeneratedAt\": 1662625671000,\n \"note\": null,\n \"workflowKey\": null,\n \"workflowInstanceKey\": 2251799816027861,\n \"startedAt\": 1662625626000,\n \"completedAt\": null\n },\n {\n \"id\": 152,\n \"batchId\": \"10a09f4a-61ba-4b54-ae39-ef2230f7748b\",\n \"subBatchId\": null,\n \"requestId\": \"3a4dfab5-0f4f-4e78-b6b5-1aff3859d4e8\",\n \"requestFile\": \"1662624970480_ph-ee-bulk-demo-6.csv\",\n \"totalTransactions\": 11,\n \"ongoing\": 0,\n \"failed\": 0,\n \"completed\": 11,\n \"totalAmount\": null,\n \"ongoingAmount\": null,\n \"failedAmount\": null,\n \"completedAmount\": null,\n \"result_file\": \"https://paymenthub-ee-dev.s3.us-east-2.amazonaws.com/1662625016404_1662625016404_response.csv\",\n \"resultGeneratedAt\": 1662625017000,\n \"note\": null,\n \"workflowKey\": null,\n \"workflowInstanceKey\": 2251799816026682,\n \"startedAt\": 1662624971000,\n \"completedAt\": null\n },\n {\n \"id\": 148,\n \"batchId\": \"7052b36f-594c-4d09-ad90-a69b46e956c0\",\n \"subBatchId\": null,\n \"requestId\": \"3a4dfab5-0f4f-4e78-b6b5-1aff3859d4e8\",\n \"requestFile\": \"1662624716397_ph-ee-bulk-demo-6.csv\",\n \"totalTransactions\": 11,\n \"ongoing\": 0,\n \"failed\": 0,\n \"completed\": 11,\n \"totalAmount\": null,\n \"ongoingAmount\": null,\n \"failedAmount\": null,\n \"completedAmount\": null,\n \"result_file\": \"https://paymenthub-ee-dev.s3.us-east-2.amazonaws.com/1662624764987_1662624764987_response.csv\",\n \"resultGeneratedAt\": 1662624765000,\n \"note\": null,\n \"workflowKey\": null,\n \"workflowInstanceKey\": 2251799816026063,\n \"startedAt\": 1662624718000,\n \"completedAt\": null\n },\n {\n \"id\": 144,\n \"batchId\": \"953d5a8f-d43a-4c08-801a-4f7cf9a2d5c4\",\n \"subBatchId\": null,\n \"requestId\": \"3a4dfab5-0f4f-4e78-b6b5-1aff3859d4e8\",\n \"requestFile\": \"1662624261785_ph-ee-bulk-demo-6.csv\",\n \"totalTransactions\": 11,\n \"ongoing\": 0,\n \"failed\": 0,\n \"completed\": 11,\n \"totalAmount\": null,\n \"ongoingAmount\": null,\n \"failedAmount\": null,\n \"completedAmount\": null,\n \"result_file\": \"https://paymenthub-ee-dev.s3.us-east-2.amazonaws.com/1662624307703_1662624307703_response.csv\",\n \"resultGeneratedAt\": 1662624423000,\n \"note\": null,\n \"workflowKey\": null,\n \"workflowInstanceKey\": 2251799816025171,\n \"startedAt\": 1662624262000,\n \"completedAt\": null\n },\n {\n \"id\": 140,\n \"batchId\": \"1c4d2440-0d93-4978-9d4e-bdc1621ad294\",\n \"subBatchId\": null,\n \"requestId\": \"3a4dfab5-0f4f-4e78-b6b5-1aff3859d4e8\",\n \"requestFile\": \"1662623877478_ph-ee-bulk-demo-6.csv\",\n \"totalTransactions\": 11,\n \"ongoing\": 0,\n \"failed\": 0,\n \"completed\": 11,\n \"totalAmount\": null,\n \"ongoingAmount\": null,\n \"failedAmount\": null,\n \"completedAmount\": null,\n \"result_file\": \"https://paymenthub-ee-dev.s3.us-east-2.amazonaws.com/1662623923610_1662623923610_response.csv\",\n \"resultGeneratedAt\": 1662623924000,\n \"note\": null,\n \"workflowKey\": null,\n \"workflowInstanceKey\": 2251799816024310,\n \"startedAt\": 1662623878000,\n \"completedAt\": null\n },\n {\n \"id\": 136,\n \"batchId\": \"47dfc101-6d16-4da2-b9d0-9af2a4200852\",\n \"subBatchId\": null,\n \"requestId\": \"3a4dfab5-0f4f-4e78-b6b5-1aff3859d4e8\",\n \"requestFile\": \"1662623418697_ph-ee-bulk-demo-6.csv\",\n \"totalTransactions\": 11,\n \"ongoing\": 0,\n \"failed\": 0,\n \"completed\": 11,\n \"totalAmount\": null,\n \"ongoingAmount\": null,\n \"failedAmount\": null,\n \"completedAmount\": null,\n \"result_file\": \"https://paymenthub-ee-dev.s3.us-east-2.amazonaws.com/1662623467290_1662623467290_response.csv\",\n \"resultGeneratedAt\": 1662623468000,\n \"note\": null,\n \"workflowKey\": null,\n \"workflowInstanceKey\": 2251799816023435,\n \"startedAt\": 1662623421000,\n \"completedAt\": null\n },\n {\n \"id\": 132,\n \"batchId\": \"e136647b-1fc1-481e-a187-587edada5776\",\n \"subBatchId\": null,\n \"requestId\": \"3a4dfab5-0f4f-4e78-b6b5-1aff3859d4e8\",\n \"requestFile\": \"1662555399110_ph-ee-bulk-demo-6.csv\",\n \"totalTransactions\": 11,\n \"ongoing\": 0,\n \"failed\": 0,\n \"completed\": 11,\n \"totalAmount\": null,\n \"ongoingAmount\": null,\n \"failedAmount\": null,\n \"completedAmount\": null,\n \"result_file\": \"https://paymenthub-ee-dev.s3.us-east-2.amazonaws.com/1662555448112_e136647b-1fc1-481e-a187-587edada5776.csv\",\n \"resultGeneratedAt\": 1662555513000,\n \"note\": null,\n \"workflowKey\": null,\n \"workflowInstanceKey\": 2251799815940242,\n \"startedAt\": 1662555401000,\n \"completedAt\": null\n },\n {\n \"id\": 128,\n \"batchId\": \"2d50ade8-11e1-4909-ad89-b4e002eb8f51\",\n \"subBatchId\": null,\n \"requestId\": \"3a4dfab5-0f4f-4e78-b6b5-1aff3859d4e8\",\n \"requestFile\": \"1662555121105_ph-ee-bulk-demo-6.csv\",\n \"totalTransactions\": 11,\n \"ongoing\": 0,\n \"failed\": 0,\n \"completed\": 11,\n \"totalAmount\": null,\n \"ongoingAmount\": null,\n \"failedAmount\": null,\n \"completedAmount\": null,\n \"result_file\": \"https://paymenthub-ee-dev.s3.us-east-2.amazonaws.com/1662555169739_1662555169739_response.csv\",\n \"resultGeneratedAt\": 1662555170000,\n \"note\": null,\n \"workflowKey\": null,\n \"workflowInstanceKey\": 2251799815939648,\n \"startedAt\": 1662555123000,\n \"completedAt\": null\n },\n {\n \"id\": 124,\n \"batchId\": \"0bcba65a-58d8-454b-8cb8-fab76d571309\",\n \"subBatchId\": null,\n \"requestId\": \"3a4dfab5-0f4f-4e78-b6b5-1aff3859d4e8\",\n \"requestFile\": \"1662554777301_ph-ee-bulk-demo-6.csv\",\n \"totalTransactions\": null,\n \"ongoing\": null,\n \"failed\": null,\n \"completed\": null,\n \"totalAmount\": null,\n \"ongoingAmount\": null,\n \"failedAmount\": null,\n \"completedAmount\": null,\n \"result_file\": \"https://paymenthub-ee-dev.s3.us-east-2.amazonaws.com/1662554962405_0bcba65a-58d8-454b-8cb8-fab76d571309.csv\",\n \"resultGeneratedAt\": null,\n \"note\": null,\n \"workflowKey\": null,\n \"workflowInstanceKey\": 2251799815938865,\n \"startedAt\": 1662554779000,\n \"completedAt\": null\n },\n {\n \"id\": 120,\n \"batchId\": \"f89d2977-93e4-41a6-93c4-943920eacd96\",\n \"subBatchId\": null,\n \"requestId\": \"3a4dfab5-0f4f-4e78-b6b5-1aff3859d4e8\",\n \"requestFile\": \"1662554182323_ph-ee-bulk-demo-6.csv\",\n \"totalTransactions\": null,\n \"ongoing\": null,\n \"failed\": null,\n \"completed\": null,\n \"totalAmount\": null,\n \"ongoingAmount\": null,\n \"failedAmount\": null,\n \"completedAmount\": null,\n \"result_file\": \"https://paymenthub-ee-dev.s3.us-east-2.amazonaws.com/1662554366184_f89d2977-93e4-41a6-93c4-943920eacd96.csv\",\n \"resultGeneratedAt\": null,\n \"note\": null,\n \"workflowKey\": null,\n \"workflowInstanceKey\": 2251799815937704,\n \"startedAt\": 1662554182000,\n \"completedAt\": null\n },\n {\n \"id\": 116,\n \"batchId\": \"f4148cfa-0d95-401d-8b4c-a5e52f93759e\",\n \"subBatchId\": null,\n \"requestId\": \"3a4dfab5-0f4f-4e78-b6b5-1aff3859d4e8\",\n \"requestFile\": \"1662553748996_ph-ee-bulk-demo-6.csv\",\n \"totalTransactions\": null,\n \"ongoing\": null,\n \"failed\": null,\n \"completed\": null,\n \"totalAmount\": null,\n \"ongoingAmount\": null,\n \"failedAmount\": null,\n \"completedAmount\": null,\n \"result_file\": \"https://paymenthub-ee-dev.s3.us-east-2.amazonaws.com/1662553934532_f4148cfa-0d95-401d-8b4c-a5e52f93759e.csv\",\n \"resultGeneratedAt\": null,\n \"note\": null,\n \"workflowKey\": null,\n \"workflowInstanceKey\": 2251799815936764,\n \"startedAt\": 1662553751000,\n \"completedAt\": null\n },\n {\n \"id\": 112,\n \"batchId\": \"fa83813b-12b3-4dde-b094-631cc7557\",\n \"subBatchId\": null,\n \"requestId\": \"3a4dfab5-0f4f-4e78-b6b5-1aff3859d4e8\",\n \"requestFile\": \"1662551891704_ph-ee-bulk-demo-6.csv\",\n \"totalTransactions\": null,\n \"ongoing\": null,\n \"failed\": null,\n \"completed\": null,\n \"totalAmount\": null,\n \"ongoingAmount\": null,\n \"failedAmount\": null,\n \"completedAmount\": null,\n \"result_file\": \"https://paymenthub-ee-dev.s3.us-east-2.amazonaws.com/1662552077613_fa83813b-12b3-4dde-b094-631cc7557b53.csv\",\n \"resultGeneratedAt\": null,\n \"note\": null,\n \"workflowKey\": null,\n \"workflowInstanceKey\": 2251799815933797,\n \"startedAt\": 1662551894000,\n \"completedAt\": null\n },\n {\n \"id\": 108,\n \"batchId\": \"3c937b39-0667-40af-8241-48c86da20e93\",\n \"subBatchId\": null,\n \"requestId\": \"3a4dfab5-0f4f-4e78-b6b5-1aff3859d4e8\",\n \"requestFile\": \"1662551457591_ph-ee-bulk-demo-6.csv\",\n \"totalTransactions\": null,\n \"ongoing\": null,\n \"failed\": null,\n \"completed\": null,\n \"totalAmount\": null,\n \"ongoingAmount\": null,\n \"failedAmount\": null,\n \"completedAmount\": null,\n \"result_file\": \"https://paymenthub-ee-dev.s3.us-east-2.amazonaws.com/1662551502363_3c937b39-0667-40af-8241-48c86da20e93.csv\",\n \"resultGeneratedAt\": null,\n \"note\": null,\n \"workflowKey\": null,\n \"workflowInstanceKey\": 2251799815932902,\n \"startedAt\": 1662551460000,\n \"completedAt\": null\n },\n {\n \"id\": 104,\n \"batchId\": \"568d6284-5348-4007-a349-fdb161000ddc\",\n \"subBatchId\": null,\n \"requestId\": \"3a4dfab5-0f4f-4e78-b6b5-1aff3859d4e8\",\n \"requestFile\": \"1662551342791_ph-ee-bulk-demo-6.csv\",\n \"totalTransactions\": 11,\n \"ongoing\": 0,\n \"failed\": 0,\n \"completed\": 11,\n \"totalAmount\": null,\n \"ongoingAmount\": null,\n \"failedAmount\": null,\n \"completedAmount\": null,\n \"result_file\": \"https://paymenthub-ee-dev.s3.us-east-2.amazonaws.com/1662551386540_568d6284-5348-4007-a349-fdb161000ddc.csv\",\n \"resultGeneratedAt\": 1662551417000,\n \"note\": null,\n \"workflowKey\": null,\n \"workflowInstanceKey\": 2251799815932415,\n \"startedAt\": 1662551345000,\n \"completedAt\": null\n },\n {\n \"id\": 100,\n \"batchId\": \"0756d07d-b4e3-44c8-aa88-ef593f6c7a79\",\n \"subBatchId\": null,\n \"requestId\": \"3a4dfab5-0f4f-4e78-b6b5-1aff3859d4e8\",\n \"requestFile\": \"1662551194305_ph-ee-bulk-demo-6.csv\",\n \"totalTransactions\": 11,\n \"ongoing\": 0,\n \"failed\": 0,\n \"completed\": 11,\n \"totalAmount\": null,\n \"ongoingAmount\": null,\n \"failedAmount\": null,\n \"completedAmount\": null,\n \"result_file\": \"https://paymenthub-ee-dev.s3.us-east-2.amazonaws.com/1662551237558_0756d07d-b4e3-44c8-aa88-ef593f6c7a79.csv\",\n \"resultGeneratedAt\": 1662551332000,\n \"note\": null,\n \"workflowKey\": null,\n \"workflowInstanceKey\": 2251799815931913,\n \"startedAt\": 1662551196000,\n \"completedAt\": null\n },\n {\n \"id\": 99,\n \"batchId\": \"5df60ee5-1384-4fa2-9129-3ff97cdf291b\",\n \"subBatchId\": null,\n \"requestId\": \"3a4dfab5-0f4f-4e78-b6b5-1aff3859d4e8\",\n \"requestFile\": \"1662551072705_ph-ee-bulk-demo-6.csv\",\n \"totalTransactions\": null,\n \"ongoing\": null,\n \"failed\": null,\n \"completed\": null,\n \"totalAmount\": null,\n \"ongoingAmount\": null,\n \"failedAmount\": null,\n \"completedAmount\": null,\n \"result_file\": null,\n \"resultGeneratedAt\": null,\n \"note\": null,\n \"workflowKey\": null,\n \"workflowInstanceKey\": 2251799815931659,\n \"startedAt\": 1662551075000,\n \"completedAt\": null\n },\n {\n \"id\": 95,\n \"batchId\": \"34fb9b8c-0306-45e0-a79e-ec8483e884b2\",\n \"subBatchId\": null,\n \"requestId\": \"3a4dfab5-0f4f-4e78-b6b5-1aff3859d4e8\",\n \"requestFile\": \"1662483494135_ph-ee-bulk-demo-6.csv\",\n \"totalTransactions\": 11,\n \"ongoing\": 0,\n \"failed\": 0,\n \"completed\": 11,\n \"totalAmount\": null,\n \"ongoingAmount\": null,\n \"failedAmount\": null,\n \"completedAmount\": null,\n \"result_file\": \"https://paymenthub-ee-dev.s3.us-east-2.amazonaws.com/1662483494861_34fb9b8c-0306-45e0-a79e-ec8483e884b2.csv\",\n \"resultGeneratedAt\": 1662546592000,\n \"note\": null,\n \"workflowKey\": null,\n \"workflowInstanceKey\": 2251799815848649,\n \"startedAt\": 1662483494000,\n \"completedAt\": null\n },\n {\n \"id\": 91,\n \"batchId\": \"7febdf5f-1755-4c93-9d9d-ec5437bcbba7\",\n \"subBatchId\": null,\n \"requestId\": \"3a4dfab5-0f4f-4e78-b6b5-1aff3859d4e8\",\n \"requestFile\": \"1662483121908_ph-ee-bulk-demo-6.csv\",\n \"totalTransactions\": 11,\n \"ongoing\": 0,\n \"failed\": 0,\n \"completed\": 11,\n \"totalAmount\": null,\n \"ongoingAmount\": null,\n \"failedAmount\": null,\n \"completedAmount\": null,\n \"result_file\": \"\\\"https://paymenthub-ee-dev.s3.us-east-2.amazonaws.com/1662483124546_7febdf5f-1755-4c93-9d9d-ec5437bcbba7.csv\\\"\",\n \"resultGeneratedAt\": 1662483239000,\n \"note\": null,\n \"workflowKey\": null,\n \"workflowInstanceKey\": 2251799815847922,\n \"startedAt\": 1662483123000,\n \"completedAt\": null\n },\n {\n \"id\": 87,\n \"batchId\": \"41d14ab5-a0f1-4509-868c-094941ebfb01\",\n \"subBatchId\": null,\n \"requestId\": \"3a4dfab5-0f4f-4e78-b6b5-1aff3859d4e8\",\n \"requestFile\": \"1662481892007_ph-ee-bulk-demo-6.csv\",\n \"totalTransactions\": null,\n \"ongoing\": null,\n \"failed\": null,\n \"completed\": null,\n \"totalAmount\": null,\n \"ongoingAmount\": null,\n \"failedAmount\": null,\n \"completedAmount\": null,\n \"result_file\": \"\\\"1662481894276_41d14ab5-a0f1-4509-868c-094941ebfb01\\\"\",\n \"resultGeneratedAt\": null,\n \"note\": null,\n \"workflowKey\": null,\n \"workflowInstanceKey\": 2251799815846020,\n \"startedAt\": 1662481894000,\n \"completedAt\": null\n }\n ],\n \"totalElements\": 79,\n \"totalPages\": 4,\n \"last\": false,\n \"numberOfElements\": 20,\n \"sort\": [\n {\n \"direction\": \"DESC\",\n \"property\": \"startedAt\",\n \"ignoreCase\": false,\n \"nullHandling\": \"NATIVE\",\n \"descending\": true,\n \"ascending\": false\n }\n ],\n \"first\": false,\n \"size\": 20,\n \"number\": 1\n}" + }, + { + "name": "Get All Batches all query param", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "Platform-TenantId", + "value": "ibank-usa", + "type": "text" + } + ], + "url": { + "raw": "{{OperationsHostName}}/api/v1/batches?page=2&size=2&sortedBy=requestFile&sortedOrder=asc", + "host": [ + "{{OperationsHostName}}" + ], + "path": [ + "api", + "v1", + "batches" + ], + "query": [ + { + "key": "page", + "value": "2" + }, + { + "key": "size", + "value": "2" + }, + { + "key": "sortedBy", + "value": "requestFile" + }, + { + "key": "sortedOrder", + "value": "asc" + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Date", + "value": "Tue, 13 Sep 2022 06:25:13 GMT" + }, + { + "key": "Content-Type", + "value": "application/json;charset=UTF-8" + }, + { + "key": "Transfer-Encoding", + "value": "chunked" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "X-Content-Type-Options", + "value": "nosniff" + }, + { + "key": "X-XSS-Protection", + "value": "1; mode=block" + }, + { + "key": "Cache-Control", + "value": "no-cache, no-store, max-age=0, must-revalidate" + }, + { + "key": "Pragma", + "value": "no-cache" + }, + { + "key": "Expires", + "value": "0" + }, + { + "key": "X-Frame-Options", + "value": "DENY" + }, + { + "key": "Strict-Transport-Security", + "value": "max-age=15724800; includeSubDomains" + } + ], + "cookie": [], + "body": "{\n \"content\": [\n {\n \"id\": 7,\n \"batchId\": \"acea70d3-df71-431b-992b-e5f609c62ebf\",\n \"subBatchId\": null,\n \"requestId\": \"3a4dfab5-0f4f-4e78-b6b5-1aff3859d4e8\",\n \"requestFile\": null,\n \"totalTransactions\": null,\n \"ongoing\": null,\n \"failed\": null,\n \"completed\": null,\n \"totalAmount\": null,\n \"ongoingAmount\": null,\n \"failedAmount\": null,\n \"completedAmount\": null,\n \"result_file\": null,\n \"resultGeneratedAt\": null,\n \"note\": null,\n \"workflowKey\": null,\n \"workflowInstanceKey\": 2251799819952265,\n \"startedAt\": 1661784518000,\n \"completedAt\": 1661784518000\n },\n {\n \"id\": 8,\n \"batchId\": \"b0a10f54-3efe-4ad5-aceb-700a3c831e60\",\n \"subBatchId\": null,\n \"requestId\": \"3a4dfab5-0f4f-4e78-b6b5-1aff3859d4e8\",\n \"requestFile\": null,\n \"totalTransactions\": null,\n \"ongoing\": null,\n \"failed\": null,\n \"completed\": null,\n \"totalAmount\": null,\n \"ongoingAmount\": null,\n \"failedAmount\": null,\n \"completedAmount\": null,\n \"result_file\": null,\n \"resultGeneratedAt\": null,\n \"note\": null,\n \"workflowKey\": null,\n \"workflowInstanceKey\": 2251799819961213,\n \"startedAt\": 1661785658000,\n \"completedAt\": 1661785658000\n }\n ],\n \"totalElements\": 79,\n \"totalPages\": 40,\n \"last\": false,\n \"numberOfElements\": 2,\n \"sort\": [\n {\n \"direction\": \"ASC\",\n \"property\": \"requestFile\",\n \"ignoreCase\": false,\n \"nullHandling\": \"NATIVE\",\n \"descending\": false,\n \"ascending\": true\n }\n ],\n \"first\": false,\n \"size\": 2,\n \"number\": 2\n}" + } + ] + }, + { + "name": "Batch Payment Detail", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "auth": { + "type": "noauth" + }, + "method": "GET", + "header": [ + { + "key": "User-Agent", + "value": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:90.0) Gecko/20100101 Firefox/90.0", + "disabled": true + }, + { + "key": "Accept", + "value": "application/json, text/plain, */*", + "disabled": true + }, + { + "key": "Accept-Language", + "value": "en-US,en;q=0.5", + "disabled": true + }, + { + "key": "Platform-TenantId", + "value": "{{TenantName}}" + }, + { + "key": "Authorization", + "value": "Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsiaWRlbnRpdHktcHJvdmlkZXIiLCJpYmFuay11c2EiXSwic2NvcGUiOlsiaWRlbnRpdHkiXSwiZXhwIjoxNjMyNjY3MjY4LCJhdXRob3JpdGllcyI6WyJBTExfRlVOQ1RJT05TIl0sImp0aSI6InE2bklEMUZSNzlvM1JTK2U2enZVZ2hoa0c2ST0iLCJjbGllbnRfaWQiOiJjaGFubmVsLWliYW5rLXVzYSJ9.pt-az4y6ue2OEh5PIpV8cPkhHFwql_XK8OVRc_31gH-8GLwwZwtG9Q1k16LNxfTG4lsDpPYkJUO7UwabJlDuEfIzQtMhalVY3QwkFKjOr9T77c9esFHsjJ35FfQ5cVEDW3dUgFjF_1l-QsPAD1Nil1JSpYg-tXy8bJaVn1BI8VxYrN713VB-ZOs-eVJC_0zdK8iUHGmbSxuHojfhsj3INvU6vYYzo0u-jCzFfxImrIIFdia8DuL1S6sy4kd2ZM08_NCw_4rzW3hCgL9Yu0u_SfO2iJvh0BsXg4DC8iweBfq8rDqfQNR0Vzew9zCmiynZBWbp3elmkNnZDcVJU3yTww", + "disabled": true + }, + { + "key": "Origin", + "value": "http://localhost:4200", + "disabled": true + }, + { + "key": "Connection", + "value": "keep-alive", + "disabled": true + }, + { + "key": "Referer", + "value": "http://localhost:4200/", + "disabled": true + }, + { + "key": "X-Correlation-ID", + "value": "{{clientCorrelationId}}", + "type": "text" + } + ], + "url": { + "raw": "{{OperationsHostName}}/api/v1/batches/{{batchId}}?associations=all", + "host": [ + "{{OperationsHostName}}" + ], + "path": [ + "api", + "v1", + "batches", + "{{batchId}}" + ], + "query": [ + { + "key": "direction", + "value": "OUTGOING", + "description": "INCOMING or OUTGOING direction", + "disabled": true + }, + { + "key": "status", + "value": "ONGOING", + "description": "Transaction State can be ONGOING, STARTED, FAILED", + "disabled": true + }, + { + "key": "associations", + "value": "all" + }, + { + "key": "offset", + "value": "0", + "disabled": true + }, + { + "key": "limit", + "value": "10", + "disabled": true + } + ] + } + }, + "response": [ + { + "name": "Batch Summary", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "User-Agent", + "value": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:90.0) Gecko/20100101 Firefox/90.0", + "disabled": true + }, + { + "key": "Accept", + "value": "application/json, text/plain, */*", + "disabled": true + }, + { + "key": "Accept-Language", + "value": "en-US,en;q=0.5", + "disabled": true + }, + { + "key": "Platform-TenantId", + "value": "ibank-usa" + }, + { + "key": "Authorization", + "value": "Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsiaWRlbnRpdHktcHJvdmlkZXIiLCJpYmFuay11c2EiXSwic2NvcGUiOlsiaWRlbnRpdHkiXSwiZXhwIjoxNjMyNjY3MjY4LCJhdXRob3JpdGllcyI6WyJBTExfRlVOQ1RJT05TIl0sImp0aSI6InE2bklEMUZSNzlvM1JTK2U2enZVZ2hoa0c2ST0iLCJjbGllbnRfaWQiOiJjaGFubmVsLWliYW5rLXVzYSJ9.pt-az4y6ue2OEh5PIpV8cPkhHFwql_XK8OVRc_31gH-8GLwwZwtG9Q1k16LNxfTG4lsDpPYkJUO7UwabJlDuEfIzQtMhalVY3QwkFKjOr9T77c9esFHsjJ35FfQ5cVEDW3dUgFjF_1l-QsPAD1Nil1JSpYg-tXy8bJaVn1BI8VxYrN713VB-ZOs-eVJC_0zdK8iUHGmbSxuHojfhsj3INvU6vYYzo0u-jCzFfxImrIIFdia8DuL1S6sy4kd2ZM08_NCw_4rzW3hCgL9Yu0u_SfO2iJvh0BsXg4DC8iweBfq8rDqfQNR0Vzew9zCmiynZBWbp3elmkNnZDcVJU3yTww" + }, + { + "key": "Origin", + "value": "http://localhost:4200", + "disabled": true + }, + { + "key": "Connection", + "value": "keep-alive", + "disabled": true + }, + { + "key": "Referer", + "value": "http://localhost:4200/", + "disabled": true + } + ], + "url": { + "raw": "{{OperationsHostName}}/api/v1/batch?batchId={{batchId}}", + "host": [ + "{{OperationsHostName}}" + ], + "path": [ + "api", + "v1", + "batch" + ], + "query": [ + { + "key": "direction", + "value": "OUTGOING", + "description": "INCOMING or OUTGOING direction", + "disabled": true + }, + { + "key": "status", + "value": "ONGOING", + "description": "Transaction State can be ONGOING, STARTED, FAILED", + "disabled": true + }, + { + "key": "batchId", + "value": "{{batchId}}" + } + ] + } + }, + "_postman_previewlanguage": "json", + "header": [], + "cookie": [], + "body": "{\n \"batchId\": \"c02a14f0-5e7e-44a1-88eb-5584a21e6f28\",\n \"requestId\": \"dhgdfe-jiae-ugir-bsjf-ndsdfsdfdfd\",\n \"totalTransactions\": 2,\n \"ongoing\": 2,\n \"failed\": 0,\n \"completed\": 0,\n \"total_amount\": 767,\n \"completed_amount\": 0,\n \"ongoing_amount\": 767,\n \"failed_amount\": 0,\n \"result_file\": null,\n \"resultGeneratedAt\": 1634955667187,\n \"note\": \"Sample Response\"\n}" + } + ] + }, + { + "name": "Sub Batch Payment Detail", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 200\", function () {", + " pm.response.to.have.status(200);", + " pm.expect(pm.response.text).not.equal(null)", + "});", + "", + "if(postman.getEnvironmentVariable(\"AutoTest\") == \"true\"){", + " var nextTextIndex = Number(postman.getEnvironmentVariable(\"NextTestIndex\"));", + " var apis = pm.environment.get('TestApiList');", + " var testList = JSON.parse(apis);", + " if(testList.length>nextTextIndex){", + " postman.setEnvironmentVariable(\"NextTestIndex\", 1+ nextTextIndex);", + " postman.setNextRequest(testList[nextTextIndex]); ", + " }else{", + " postman.setNextRequest(null); ", + " }", + "}" + ], + "type": "text/javascript" + } + } + ], + "request": { + "auth": { + "type": "noauth" + }, + "method": "GET", + "header": [ + { + "key": "User-Agent", + "value": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:90.0) Gecko/20100101 Firefox/90.0", + "disabled": true + }, + { + "key": "Accept", + "value": "application/json, text/plain, */*", + "disabled": true + }, + { + "key": "Accept-Language", + "value": "en-US,en;q=0.5", + "disabled": true + }, + { + "key": "Platform-TenantId", + "value": "{{TenantName}}" + }, + { + "key": "Authorization", + "value": "Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsiaWRlbnRpdHktcHJvdmlkZXIiLCJpYmFuay11c2EiXSwic2NvcGUiOlsiaWRlbnRpdHkiXSwiZXhwIjoxNjMyNjY3MjY4LCJhdXRob3JpdGllcyI6WyJBTExfRlVOQ1RJT05TIl0sImp0aSI6InE2bklEMUZSNzlvM1JTK2U2enZVZ2hoa0c2ST0iLCJjbGllbnRfaWQiOiJjaGFubmVsLWliYW5rLXVzYSJ9.pt-az4y6ue2OEh5PIpV8cPkhHFwql_XK8OVRc_31gH-8GLwwZwtG9Q1k16LNxfTG4lsDpPYkJUO7UwabJlDuEfIzQtMhalVY3QwkFKjOr9T77c9esFHsjJ35FfQ5cVEDW3dUgFjF_1l-QsPAD1Nil1JSpYg-tXy8bJaVn1BI8VxYrN713VB-ZOs-eVJC_0zdK8iUHGmbSxuHojfhsj3INvU6vYYzo0u-jCzFfxImrIIFdia8DuL1S6sy4kd2ZM08_NCw_4rzW3hCgL9Yu0u_SfO2iJvh0BsXg4DC8iweBfq8rDqfQNR0Vzew9zCmiynZBWbp3elmkNnZDcVJU3yTww", + "disabled": true + }, + { + "key": "Origin", + "value": "http://localhost:4200", + "disabled": true + }, + { + "key": "Connection", + "value": "keep-alive", + "disabled": true + }, + { + "key": "Referer", + "value": "http://localhost:4200/", + "disabled": true + }, + { + "key": "X-Correlation-ID", + "value": "{{clientCorrelationId}}", + "type": "text" + } + ], + "url": { + "raw": "{{OperationsHostName}}/api/v1/batches/{{batchId}}}/subBatches/{{subBatchId}}?offset=0&limit=5", + "host": [ + "{{OperationsHostName}}" + ], + "path": [ + "api", + "v1", + "batches", + "{{batchId}}}", + "subBatches", + "{{subBatchId}}" + ], + "query": [ + { + "key": "direction", + "value": "OUTGOING", + "description": "INCOMING or OUTGOING direction", + "disabled": true + }, + { + "key": "status", + "value": "ONGOING", + "description": "Transaction State can be ONGOING, STARTED, FAILED", + "disabled": true + }, + { + "key": "offset", + "value": "0" + }, + { + "key": "limit", + "value": "5" + } + ] + } + }, + "response": [ + { + "name": "Batch Summary", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "User-Agent", + "value": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:90.0) Gecko/20100101 Firefox/90.0", + "disabled": true + }, + { + "key": "Accept", + "value": "application/json, text/plain, */*", + "disabled": true + }, + { + "key": "Accept-Language", + "value": "en-US,en;q=0.5", + "disabled": true + }, + { + "key": "Platform-TenantId", + "value": "ibank-usa" + }, + { + "key": "Authorization", + "value": "Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsiaWRlbnRpdHktcHJvdmlkZXIiLCJpYmFuay11c2EiXSwic2NvcGUiOlsiaWRlbnRpdHkiXSwiZXhwIjoxNjMyNjY3MjY4LCJhdXRob3JpdGllcyI6WyJBTExfRlVOQ1RJT05TIl0sImp0aSI6InE2bklEMUZSNzlvM1JTK2U2enZVZ2hoa0c2ST0iLCJjbGllbnRfaWQiOiJjaGFubmVsLWliYW5rLXVzYSJ9.pt-az4y6ue2OEh5PIpV8cPkhHFwql_XK8OVRc_31gH-8GLwwZwtG9Q1k16LNxfTG4lsDpPYkJUO7UwabJlDuEfIzQtMhalVY3QwkFKjOr9T77c9esFHsjJ35FfQ5cVEDW3dUgFjF_1l-QsPAD1Nil1JSpYg-tXy8bJaVn1BI8VxYrN713VB-ZOs-eVJC_0zdK8iUHGmbSxuHojfhsj3INvU6vYYzo0u-jCzFfxImrIIFdia8DuL1S6sy4kd2ZM08_NCw_4rzW3hCgL9Yu0u_SfO2iJvh0BsXg4DC8iweBfq8rDqfQNR0Vzew9zCmiynZBWbp3elmkNnZDcVJU3yTww" + }, + { + "key": "Origin", + "value": "http://localhost:4200", + "disabled": true + }, + { + "key": "Connection", + "value": "keep-alive", + "disabled": true + }, + { + "key": "Referer", + "value": "http://localhost:4200/", + "disabled": true + } + ], + "url": { + "raw": "{{OperationsHostName}}/api/v1/batch?batchId={{batchId}}", + "host": [ + "{{OperationsHostName}}" + ], + "path": [ + "api", + "v1", + "batch" + ], + "query": [ + { + "key": "direction", + "value": "OUTGOING", + "description": "INCOMING or OUTGOING direction", + "disabled": true + }, + { + "key": "status", + "value": "ONGOING", + "description": "Transaction State can be ONGOING, STARTED, FAILED", + "disabled": true + }, + { + "key": "batchId", + "value": "{{batchId}}" + } + ] + } + }, + "_postman_previewlanguage": "json", + "header": [], + "cookie": [], + "body": "{\n \"batchId\": \"c02a14f0-5e7e-44a1-88eb-5584a21e6f28\",\n \"requestId\": \"dhgdfe-jiae-ugir-bsjf-ndsdfsdfdfd\",\n \"totalTransactions\": 2,\n \"ongoing\": 2,\n \"failed\": 0,\n \"completed\": 0,\n \"total_amount\": 767,\n \"completed_amount\": 0,\n \"ongoing_amount\": 767,\n \"failed_amount\": 0,\n \"result_file\": null,\n \"resultGeneratedAt\": 1634955667187,\n \"note\": \"Sample Response\"\n}" + } + ] + } + ] + }, + { + "name": "Collection APIs", + "item": [ + { + "name": "Collection Request", + "request": { + "method": "POST", + "header": [ + { + "key": "Platform-TenantId", + "value": "{{TenantName}}", + "type": "text" + }, + { + "key": "X-CorrelationID", + "value": "{{clientCorrelationId}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"payer\": [\n {\n \"key\": \"MSISDN\",\n \"value\": \"254708374149\"\n },\n {\n \"key\": \"ACCOUNTID\",\n \"value\": \"24450523\"\n }\n ],\n \"amount\": {\n \"amount\": \"1\",\n \"currency\": \"USD\"\n },\n \"transactionType\": {\n \"scenario\": \"MPESA\",\n \"subScenario\": \"BUYGOODS\",\n \"initiator\": \"PAYEE\",\n \"initiatorType\": \"BUSINESS\"\n }\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{ChannelHostName}}/channel/collection", + "host": [ + "{{ChannelHostName}}" + ], + "path": [ + "channel", + "collection" + ] + } + }, + "response": [] + } + ] + }, + { + "name": "Mpesa APIs", + "item": [ + { + "name": "Mpesa buygoods callback", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"Body\": {\n \"stkCallback\": {\n \"MerchantRequestID\": \"61034-2694171-1\",\n \"CheckoutRequestID\": \"ws_CO_101120211333024994\",\n \"ResultCode\": 1037,\n \"ResultDesc\": \"DS timeout.\"\n },\n \"CallbackMetadata\":{\n \"Item\":[\n {\n \"Name\":\"Amount\",\n \"Value\":10\n },\n {\n \"Name\":\"MpesaReceiptNumber\",\n \"Value\":\"MRLSJHDH9\"\n }\n ]\n }\n }\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "http://{{MpesaHostName}}/buygoods/callback", + "protocol": "http", + "host": [ + "{{MpesaHostName}}" + ], + "path": [ + "buygoods", + "callback" + ] + } + }, + "response": [] + } + ] + }, + { + "name": "Notifications APIs", + "item": [ + { + "name": "Notifications Callback", + "request": { + "method": "POST", + "header": [ + { + "key": "X-CorrelationID", + "value": "{{clientCorrelationId}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "[\n {\n \"id\": \"201\",\n \"externalId\": \"SM7b1b75ffa3f5737a\",\n \"deliveredOnDate\": \"2022-01-11\",\n \"deliveryStatus\": 300,\n \"hasError\": false,\n \"errorMessage\": null,\n \"bridgeId\": 2,\n \"tenantId\": 1\n }\n]", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{NotificationsHostName}}/sms/callback", + "host": [ + "{{NotificationsHostName}}" + ], + "path": [ + "sms", + "callback" + ] + }, + "description": "Callback from message gateway" + }, + "response": [] + }, + { + "name": "Send Message to Message Gateway", + "request": { + "method": "POST", + "header": [ + { + "key": "Fineract-Platform-TenantId", + "value": "default", + "type": "text" + }, + { + "key": "Fineract-Tenant-App-Key", + "value": "123456543234abdkdkdkd", + "type": "text" + }, + { + "key": "X-CorrelationID", + "value": "{{clientCorrelationId}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "[\n {\n \"internalId\": \"20\",\n \"mobileNumber\": \"+15005550012\",\n \"message\": \"Random Message\",\n \"providerId\": 2\n }\n]", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{MessagegatewayHostName}}/sms", + "host": [ + "{{MessagegatewayHostName}}" + ], + "path": [ + "sms" + ] + } + }, + "response": [] + } + ] + }, + { + "name": "Message Gateway APIs", + "item": [ + { + "name": "Message gateway provider callback", + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/x-www-form-urlencoded", + "type": "text" + }, + { + "key": "X-CorrelationID", + "value": "{{clientCorrelationId}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"contact_id\": \"CT190322d3246e0a2f\",\n \"contact[conversation_status]\": \"closed\",\n \"contact[id]\": \"CT190322d3246e0a2f\",\n \"contact[incoming_message_count]\": 0,\n \"contact[last_message_id]\": \"SM8edad9e1caf03b04\",\n \"contact[last_message_time]\": 1641306324,\n \"contact[last_outgoing_message_time]\": 1641306324,\n \"contact[message_count]\": 17,\n \"contact[name]\": \"+15005550012\",\n \"contact[outgoing_message_count]\": 17,\n \"contact[phone_number]\": \"+15005550012\",\n \"contact[project_id]\": \"PJ5ff552ce01d2978c\",\n \"contact[send_blocked]\": 0,\n \"contact[time_created]\": 1641227864,\n \"contact[time_updated]\": 1641227864,\n \"content\": \"The transaction for account number:$account for amount:$amount has failed on $date with following transaction id: $transactionid\",\n \"direction\": \"outgoing\",\n \"error_message\": \" \",\n \"event\": \"send_status\",\n \"from_number\": \"555-1212\",\n \"id\": \"SM8edad9e1caf03b04\",\n \"message_type\": \"sms\",\n \"phone_id\": \"PNa2d2c147eb96c34d\",\n \"priority\": 1,\n \"project_id\": \"PJ5ff552ce01d2978c\",\n \"secret\": \" \",\n \"simulated\": 1,\n \"source\": \"api\",\n \"starred\": 0,\n \"status\": \"delivered\",\n \"time_created\": 1641306324,\n \"time_sent\": 1641306324,\n \"time_updated\": 1641306324,\n \"to_number\": \"+15005550012\",\n \"track_clicks\": 0,\n \"user_id\": \"URfabcdb9eb26ca257\"\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{MessagegatewayHostName}}/telerivet/report/", + "host": [ + "{{MessagegatewayHostName}}" + ], + "path": [ + "telerivet", + "report", + "" + ] + } + }, + "response": [] + } + ] + }, + { + "name": "Zeebe Operations APIs", + "item": [ + { + "name": "Start a workflow", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"var1\": \"val1\",\n \"var2\": \"val2\",\n \"var3\": \"val3\"\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{ZeebeOpsHostName}}/channel/workflow/{{BpmnProcessId}}", + "host": [ + "{{ZeebeOpsHostName}}" + ], + "path": [ + "channel", + "workflow", + "{{BpmnProcessId}}" + ] + } + }, + "response": [] + }, + { + "name": "Upload bpmn", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "formdata", + "formdata": [ + { + "key": "file", + "type": "file", + "src": "/Users/ishan/fynarfin/phee/ph-ee-env-labs/orchestration/feel/inbound_transfer_roster-DFSPID.bpmn" + } + ] + }, + "url": { + "raw": "{{ZeebeOpsHostName}}/zeebe/upload", + "host": [ + "{{ZeebeOpsHostName}}" + ], + "path": [ + "zeebe", + "upload" + ] + } + }, + "response": [] + }, + { + "name": "Bulk cancellation of active process", + "request": { + "method": "PUT", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"processId\": [123, 456, 789]\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{ZeebeOpsHostName}}/channel/workflow/", + "host": [ + "{{ZeebeOpsHostName}}" + ], + "path": [ + "channel", + "workflow", + "" + ] + } + }, + "response": [ + { + "name": "Bulk cancellation of active process", + "originalRequest": { + "method": "PUT", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"processId\": [123, 456, 789]\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "localhost:5000/channel/workflow/", + "host": [ + "localhost" + ], + "port": "5000", + "path": [ + "channel", + "workflow", + "" + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Accept", + "value": "*/*" + }, + { + "key": "Postman-Token", + "value": "9243b64b-7c57-443f-91fc-c1ec0ee18e68" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Accept-Encoding", + "value": "gzip, deflate, br" + }, + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Content-Length", + "value": "87" + }, + { + "key": "User-Agent", + "value": "PostmanRuntime/7.28.4" + }, + { + "key": "Date", + "value": "Wed, 13 Oct 2021 18:54:34 GMT" + } + ], + "cookie": [], + "body": "{\n \"cancellationSuccessful\": 0,\n \"cancellationFailed\": 3,\n \"success\": [],\n \"failed\": [\n 123,\n 456,\n 789\n ]\n}" + } + ] + }, + { + "name": "Check ES health", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{ZeebeOpsHostName}}/es/health", + "host": [ + "{{ZeebeOpsHostName}}" + ], + "path": [ + "es", + "health" + ] + } + }, + "response": [ + { + "name": "Status-Down", + "originalRequest": { + "method": "GET", + "header": [], + "url": { + "raw": "localhost:5000/es/health", + "host": [ + "localhost" + ], + "port": "5000", + "path": [ + "es", + "health" + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "plain", + "header": [ + { + "key": "Accept", + "value": "*/*" + }, + { + "key": "Postman-Token", + "value": "87609590-28a6-4713-b58a-329444239d6a" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Accept-Encoding", + "value": "gzip, deflate, br" + }, + { + "key": "Content-Length", + "value": "47" + }, + { + "key": "User-Agent", + "value": "PostmanRuntime/7.28.4" + }, + { + "key": "Date", + "value": "Wed, 13 Oct 2021 18:57:37 GMT" + } + ], + "cookie": [], + "body": "{\"reason\":\"Connection refused\",\"status\":\"down\"}" + }, + { + "name": "Status-UP", + "originalRequest": { + "method": "GET", + "header": [], + "url": { + "raw": "localhost:5000/es/health", + "host": [ + "localhost" + ], + "port": "5000", + "path": [ + "es", + "health" + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "plain", + "header": [ + { + "key": "Accept", + "value": "*/*" + }, + { + "key": "Postman-Token", + "value": "685f2f41-459f-4d8d-aa3d-b6ecf5bf545f" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Accept-Encoding", + "value": "gzip, deflate, br" + }, + { + "key": "Content-Length", + "value": "15" + }, + { + "key": "User-Agent", + "value": "PostmanRuntime/7.28.4" + }, + { + "key": "Date", + "value": "Wed, 13 Oct 2021 18:55:51 GMT" + } + ], + "cookie": [], + "body": "{\"status\":\"UP\"}" + } + ] + }, + { + "name": "Get process definition key and name", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{ZeebeOpsHostName}}/channel/process", + "host": [ + "{{ZeebeOpsHostName}}" + ], + "path": [ + "channel", + "process" + ] + } + }, + "response": [ + { + "name": "Get process definition key and name", + "originalRequest": { + "method": "GET", + "header": [], + "url": { + "raw": "localhost:5000/channel/process", + "host": [ + "localhost" + ], + "port": "5000", + "path": [ + "channel", + "process" + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "plain", + "header": [ + { + "key": "Accept", + "value": "*/*" + }, + { + "key": "Postman-Token", + "value": "80c6f388-c4c2-4774-afdb-6268bff4ebfd" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Accept-Encoding", + "value": "gzip, deflate, br" + }, + { + "key": "Content-Length", + "value": "416" + }, + { + "key": "User-Agent", + "value": "PostmanRuntime/7.28.4" + }, + { + "key": "Date", + "value": "Wed, 13 Oct 2021 18:59:27 GMT" + } + ], + "cookie": [], + "body": "{\"bulk_processor-ibank-usa\":[2251799813685998,2251799814125425],\"international_remittance_payee_process-ibank-india\":[2251799813686276,2251799814069864],\"international_remittance_payer_process-ibank-usa\":[2251799813686414,2251799814069794],\"international_remittance_payer_process-ibank-india\":[2251799813686138,2251799814070206],\"international_remittance_payee_process-ibank-usa\":[2251799813686068,2251799814070344]}" + } + ] + }, + { + "name": "Cancel a workflow by state and retires", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"state\": \"Activity_1m5hpl9\",\n \"retries\": 12\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{ZeebeOpsHostName}}/channel/workflow/cancel", + "host": [ + "{{ZeebeOpsHostName}}" + ], + "path": [ + "channel", + "workflow", + "cancel" + ] + } + }, + "response": [] + }, + { + "name": "Cancel a process by variable name and value", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"key\": \"initiatorFspId\",\n \"value\": \"\\\"ibank-usa\\\"\"\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{ZeebeOpsHostName}}/channel/workflow/cancelbyvalue", + "host": [ + "{{ZeebeOpsHostName}}" + ], + "path": [ + "channel", + "workflow", + "cancelbyvalue" + ] + } + }, + "response": [] + }, + { + "name": "Get process variable by process instance key", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{ZeebeOpsHostName}}/channel/process/variable/{{ProcessInstanceKey}}", + "host": [ + "{{ZeebeOpsHostName}}" + ], + "path": [ + "channel", + "process", + "variable", + "{{ProcessInstanceKey}}" + ] + } + }, + "response": [ + { + "name": "Get process variable by process instance key", + "originalRequest": { + "method": "GET", + "header": [], + "url": { + "raw": "localhost:5000/channel/process/variable/2251799813783649", + "host": [ + "localhost" + ], + "port": "5000", + "path": [ + "channel", + "process", + "variable", + "2251799813783649" + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "plain", + "header": [ + { + "key": "Accept", + "value": "*/*" + }, + { + "key": "Postman-Token", + "value": "fa223624-7661-43b5-a525-ea5c3691bc09" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Accept-Encoding", + "value": "gzip, deflate, br" + }, + { + "key": "Content-Length", + "value": "1416" + }, + { + "key": "PROCESS_INSTANCE_KEY", + "value": "2251799813783649" + }, + { + "key": "User-Agent", + "value": "PostmanRuntime/7.28.4" + }, + { + "key": "Date", + "value": "Wed, 13 Oct 2021 19:06:47 GMT" + } + ], + "cookie": [], + "body": "{\"transactionType\":\"\\\"inttransfer\\\"\",\"gsmaChannelRequest\":\"\\\"{\\\\\\\"amount\\\\\\\":\\\\\\\"54\\\\\\\",\\\\\\\"currency\\\\\\\":\\\\\\\"USD\\\\\\\",\\\\\\\"type\\\\\\\":\\\\\\\"transfer\\\\\\\",\\\\\\\"debitParty\\\\\\\":[{\\\\\\\"key\\\\\\\":\\\\\\\"msisdn\\\\\\\",\\\\\\\"value\\\\\\\":\\\\\\\"7543010\\\\\\\"}],\\\\\\\"creditParty\\\\\\\":[{\\\\\\\"key\\\\\\\":\\\\\\\"msisdn\\\\\\\",\\\\\\\"value\\\\\\\":\\\\\\\"919900878571\\\\\\\"}],\\\\\\\"requestingLei\\\\\\\":\\\\\\\"ibank-usa\\\\\\\",\\\\\\\"receivingLei\\\\\\\":\\\\\\\"ibank-india\\\\\\\",\\\\\\\"internationalTransferInformation\\\\\\\":{\\\\\\\"originCountry\\\\\\\":\\\\\\\"US\\\\\\\",\\\\\\\"receivingCountry\\\\\\\":\\\\\\\"IN\\\\\\\",\\\\\\\"receivingCurrency\\\\\\\":\\\\\\\"INR\\\\\\\",\\\\\\\"senderCurrency\\\\\\\":\\\\\\\"USD\\\\\\\",\\\\\\\"currencyPair\\\\\\\":\\\\\\\"USD/INR\\\\\\\",\\\\\\\"currencyPairRate\\\\\\\":\\\\\\\"70\\\\\\\",\\\\\\\"receivingAmount\\\\\\\":\\\\\\\"3780\\\\\\\"}}\\\"\",\"partyLookupFspId\":\"\\\"ibank-india\\\"\",\"channelRequest\":\"\\\"{\\\\\\\"payer\\\\\\\":{\\\\\\\"partyIdInfo\\\\\\\":{\\\\\\\"partyIdType\\\\\\\":\\\\\\\"MSISDN\\\\\\\",\\\\\\\"partyIdentifier\\\\\\\":\\\\\\\"7543010\\\\\\\"}},\\\\\\\"payee\\\\\\\":{\\\\\\\"partyIdInfo\\\\\\\":{\\\\\\\"partyIdType\\\\\\\":\\\\\\\"MSISDN\\\\\\\",\\\\\\\"partyIdentifier\\\\\\\":\\\\\\\"919900878571\\\\\\\"}},\\\\\\\"amount\\\\\\\":{\\\\\\\"amount\\\\\\\":\\\\\\\"54\\\\\\\",\\\\\\\"currency\\\\\\\":\\\\\\\"USD\\\\\\\"},\\\\\\\"transactionType\\\\\\\":{\\\\\\\"scenario\\\\\\\":\\\\\\\"TRANSFER\\\\\\\",\\\\\\\"initiator\\\\\\\":\\\\\\\"PAYER\\\\\\\",\\\\\\\"initiatorType\\\\\\\":\\\\\\\"CONSUMER\\\\\\\"}}\\\"\",\"isRtpRequest\":\"false\",\"tenantId\":\"\\\"ibank-usa\\\"\",\"initiatorFspId\":\"\\\"ibank-usa\\\"\",\"partyIdType\":\"\\\"MSISDN\\\"\",\"partyId\":\"\\\"919900878571\\\"\",\"originDate\":\"1633441154238\",\"transactionId\":\"\\\"ae75a455-4a09-477f-8e5a-9c1ac4747a5f\\\"\"}" + } + ] + }, + { + "name": "Get list of task that are already executed by process definition key", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{ZeebeOpsHostName}}/channel/process/{{ProcessDefinitionKey}}/task/", + "host": [ + "{{ZeebeOpsHostName}}" + ], + "path": [ + "channel", + "process", + "{{ProcessDefinitionKey}}", + "task", + "" + ] + } + }, + "response": [] + }, + { + "name": "Get process current state and variable by process instance id", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{ZeebeOpsHostName}}/channel/process/{{ProcessInstanceId}}", + "host": [ + "{{ZeebeOpsHostName}}" + ], + "path": [ + "channel", + "process", + "{{ProcessInstanceId}}" + ] + } + }, + "response": [] + }, + { + "name": "Cancel a workflow by workflow instance key", + "request": { + "method": "POST", + "header": [], + "url": { + "raw": "{{ZeebeOpsHostName}}/channel/workflow/{{WorkflowInstanceKey}}/cancel", + "host": [ + "{{ZeebeOpsHostName}}" + ], + "path": [ + "channel", + "workflow", + "{{WorkflowInstanceKey}}", + "cancel" + ] + } + }, + "response": [] + } + ] + }, + { + "name": "Paybill APIs", + "item": [ + { + "name": "Validation", + "item": [ + { + "name": "MPESA-Connector Validiate Webhook", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"TransactionType\":\"Pay Bill\",\n \"TransID\":\"8335b60090979AvUefSR\",\n \"TransTime\":\"20191122063845\",\n \"TransAmount\":\"1\",\n \"BusinessShortCode\":\"24322607\",\n \"BillRefNumber\":\"24322607\",\n \"InvoiceNumber\":\"\",\n \"OrgAccountBalance\":\"49197.00\",\n \"ThirdPartyTransID\":\"\",\n \"MSISDN\":\"254797668592\",\n \"FirstName\":\"John\"\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{MpesaHostName}}/validation", + "host": [ + "{{MpesaHostName}}" + ], + "path": [ + "validation" + ] + }, + "description": "BillRefNo : (primaryIdentifier) \n Paygops - foundationalId - 24322607 \n Roster - accountId - 33272035\n\nMSISDN : \nPaygops - 254797668592 \nRoster - 2540726839144\n\nTransactionID: \nPaygops - “8335b60090979AvUefSR” \nRoster - “670d65bd-4efd-4a6c-ae2c-7fdaa8cb4d60\"" + }, + "response": [] + } + ] + }, + { + "name": "Confirmation", + "item": [ + { + "name": "MPESA-Connector Confirmation Webhook", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 200\", function () {", + " pm.response.to.have.status(200);", + " pm.expect(pm.response.text).not.equal(null)", + "});", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"TransactionType\":\"Pay Bill\",\n \"TransID\":\"8335b60090979AvUefSR\",\n \"TransTime\":\"20191122063845\",\n \"TransAmount\":\"1\",\n \"BusinessShortCode\":\"24322607\",\n \"BillRefNumber\":\"24322607\",\n \"InvoiceNumber\":\"\",\n \"OrgAccountBalance\":\"49197\",\n \"ThirdPartyTransID\":\"\",\n \"MSISDN\":\"254797668592\",\n \"FirstName\":\"John\"\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{MpesaHostName}}/confirmation", + "host": [ + "{{MpesaHostName}}" + ], + "path": [ + "confirmation" + ] + } + }, + "response": [] + } + ] + } + ], + "description": "Design Document: [https://www.notion.so/PayBill-Design-2670e8fac37a485eaac659ba942683ce](https://www.notion.so/PayBill-Design-2670e8fac37a485eaac659ba942683ce)" + }, + { + "name": "Identity Account Mapper", + "item": [ + { + "name": "Register Beneficiary", + "request": { + "method": "POST", + "header": [ + { + "key": "X-CallbackURL", + "value": "{{X-CallbackURL}}", + "type": "text" + }, + { + "key": "X-Registering-Institution-ID", + "value": "{{X-Registering-Institution-ID}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"requestID\": \"915251236706\",\n \"beneficiaries\": [\n {\n \"payeeIdentity\": \"27713803912\",\n \"paymentModality\": \"01\",\n \"financialAddress\": \"589\",\n \"bankingInstitutionCode\": \"gorilla\"\n }\n ]\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{IdentityAccountMapperHostName}}/beneficiary", + "host": [ + "{{IdentityAccountMapperHostName}}" + ], + "path": [ + "beneficiary" + ] + } + }, + "response": [ + { + "name": "Callback request body", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-CallbackURL", + "value": "{{X-CallbackURL}}", + "type": "text" + }, + { + "key": "X-Registering-Institution-ID", + "value": "{{X-Registering-Institution-ID}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"requestID\": \"915251236706\",\n \"beneficiaries\": [\n {\n \"payeeIdentity\": \"27713803912\",\n \"paymentModality\": \"01\",\n \"financialAddress\": \"589\",\n \"bankingInstitutionCode\": \"gorilla\"\n }\n ]\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{IdentityAccountMapperHostName}}/beneficiary", + "host": [ + "{{IdentityAccountMapperHostName}}" + ], + "path": [ + "beneficiary" + ] + } + }, + "status": "Accepted", + "code": 202, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Date", + "value": "Mon, 18 Mar 2024 05:07:11 GMT" + }, + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Transfer-Encoding", + "value": "chunked" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Strict-Transport-Security", + "value": "max-age=15724800; includeSubDomains" + }, + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "Access-Control-Allow-Credentials", + "value": "true" + }, + { + "key": "Access-Control-Allow-Methods", + "value": "PUT, GET, POST, OPTIONS, DELETE" + }, + { + "key": "Access-Control-Allow-Headers", + "value": "x-registering-institution-id" + }, + { + "key": "Access-Control-Max-Age", + "value": "1728000" + } + ], + "cookie": [], + "body": "{\n \"requestID\": \"171073978834\",\n \"registerRequestID\": \"915251236700\",\n \"numberFailedCases\": 0,\n \"failedCases\": []\n}" + }, + { + "name": "Register Beneficiary Already Exist", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-CallbackURL", + "value": "{{X-CallbackURL}}", + "type": "text" + }, + { + "key": "X-Registering-Institution-ID", + "value": "{{X-Registering-Institution-ID}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"requestID\": \"915251236706\",\n \"beneficiaries\": [\n {\n \"payeeIdentity\": \"27713803912\",\n \"paymentModality\": \"01\",\n \"financialAddress\": \"589\",\n \"bankingInstitutionCode\": \"gorilla\"\n }\n ]\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{IdentityAccountMapperHostName}}/beneficiary", + "host": [ + "{{IdentityAccountMapperHostName}}" + ], + "path": [ + "beneficiary" + ] + } + }, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "name": "Content-Type", + "description": "", + "type": "text" + } + ], + "cookie": [], + "body": "{\n \"requestID\": \"171073977096\",\n \"registerRequestID\": \"915251236700\",\n \"numberFailedCases\": 1,\n \"failedCases\": [\n {\n \"payeeIdentity\": \"27713803912\",\n \"paymentModality\": \"01\",\n \"failureReason\": \"Beneficiary already registered\"\n }\n ]\n}" + }, + { + "name": "Register Beneficiary 202", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-CallbackURL", + "value": "{{X-CallbackURL}}", + "type": "text" + }, + { + "key": "X-Registering-Institution-ID", + "value": "{{X-Registering-Institution-ID}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"requestID\": \"915251236706\",\n \"beneficiaries\": [\n {\n \"payeeIdentity\": \"27713803912\",\n \"paymentModality\": \"01\",\n \"financialAddress\": \"589\",\n \"bankingInstitutionCode\": \"gorilla\"\n }\n ]\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{IdentityAccountMapperHostName}}/beneficiary", + "host": [ + "{{IdentityAccountMapperHostName}}" + ], + "path": [ + "beneficiary" + ] + } + }, + "status": "Accepted", + "code": 202, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Date", + "value": "Mon, 18 Mar 2024 08:32:21 GMT" + }, + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Transfer-Encoding", + "value": "chunked" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Strict-Transport-Security", + "value": "max-age=15724800; includeSubDomains" + }, + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "Access-Control-Allow-Credentials", + "value": "true" + }, + { + "key": "Access-Control-Allow-Methods", + "value": "PUT, GET, POST, OPTIONS, DELETE" + }, + { + "key": "Access-Control-Allow-Headers", + "value": "x-registering-institution-id" + }, + { + "key": "Access-Control-Max-Age", + "value": "1728000" + } + ], + "cookie": [], + "body": "{\n \"responseCode\": \"00\",\n \"responseDescription\": \"Request successfully received by Pay-BB\",\n \"requestID\": \"915251236706\"\n}" + } + ] + }, + { + "name": "Update Beneficiary", + "request": { + "method": "PUT", + "header": [ + { + "key": "X-CallbackURL", + "value": "{{X-CallbackURL}}", + "type": "text" + }, + { + "key": "X-Registering-Institution-ID", + "value": "{{X-Registering-Institution-ID}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"requestID\": \"915251236706\",\n \"beneficiaries\": [\n {\n \"payeeIdentity\": \"27713803912\",\n \"paymentModality\": \"00\",\n \"financialAddress\": \"1233456\",\n \"bankingInstitutionCode\": \"gorilla\"\n }\n ]\n}\n", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{IdentityAccountMapperHostName}}/beneficiary", + "host": [ + "{{IdentityAccountMapperHostName}}" + ], + "path": [ + "beneficiary" + ] + } + }, + "response": [ + { + "name": "Callback request body", + "originalRequest": { + "method": "PUT", + "header": [ + { + "key": "X-CallbackURL", + "value": "{{X-CallbackURL}}", + "type": "text" + }, + { + "key": "X-Registering-Institution-ID", + "value": "{{X-Registering-Institution-ID}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"requestID\": \"915251236706\",\n \"beneficiaries\": [\n {\n \"payeeIdentity\": \"27713803912\",\n \"paymentModality\": \"00\",\n \"financialAddress\": \"1233456\",\n \"bankingInstitutionCode\": \"gorilla\"\n }\n ]\n}\n", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{IdentityAccountMapperHostName}}/beneficiary", + "host": [ + "{{IdentityAccountMapperHostName}}" + ], + "path": [ + "beneficiary" + ] + } + }, + "status": "Accepted", + "code": 202, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Date", + "value": "Mon, 18 Mar 2024 05:06:54 GMT" + }, + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Transfer-Encoding", + "value": "chunked" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Strict-Transport-Security", + "value": "max-age=15724800; includeSubDomains" + }, + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "Access-Control-Allow-Credentials", + "value": "true" + }, + { + "key": "Access-Control-Allow-Methods", + "value": "PUT, GET, POST, OPTIONS, DELETE" + }, + { + "key": "Access-Control-Allow-Headers", + "value": "x-registering-institution-id" + }, + { + "key": "Access-Control-Max-Age", + "value": "1728000" + } + ], + "cookie": [], + "body": "{\n \"requestID\": \"171073988979\",\n \"registerRequestID\": \"915251236706\",\n \"numberFailedCases\": 0,\n \"failedCases\": []\n}" + }, + { + "name": "Update Beneficiary Beneficiary not Registered", + "originalRequest": { + "method": "PUT", + "header": [ + { + "key": "X-CallbackURL", + "value": "{{X-CallbackURL}}", + "type": "text" + }, + { + "key": "X-Registering-Institution-ID", + "value": "{{X-Registering-Institution-ID}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"requestID\": \"915251236706\",\n \"beneficiaries\": [\n {\n \"payeeIdentity\": \"27713803912\",\n \"paymentModality\": \"00\",\n \"financialAddress\": \"1233456\",\n \"bankingInstitutionCode\": \"gorilla\"\n }\n ]\n}\n", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{IdentityAccountMapperHostName}}/beneficiary", + "host": [ + "{{IdentityAccountMapperHostName}}" + ], + "path": [ + "beneficiary" + ] + } + }, + "_postman_previewlanguage": "Text", + "header": [], + "cookie": [], + "body": "{\n \"requestID\": \"171074375685\",\n \"registerRequestID\": \"915251236706\",\n \"numberFailedCases\": 1,\n \"failedCases\": [\n {\n \"payeeIdentity\": \"27713803902\",\n \"paymentModality\": \"00\",\n \"failureReason\": \"Beneficiary is not registered\"\n }\n ]\n}" + }, + { + "name": "Update Beneficiary 202", + "originalRequest": { + "method": "PUT", + "header": [ + { + "key": "X-CallbackURL", + "value": "{{X-CallbackURL}}", + "type": "text" + }, + { + "key": "X-Registering-Institution-ID", + "value": "{{X-Registering-Institution-ID}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"requestID\": \"915251236706\",\n \"beneficiaries\": [\n {\n \"payeeIdentity\": \"27713803912\",\n \"paymentModality\": \"00\",\n \"financialAddress\": \"1233456\",\n \"bankingInstitutionCode\": \"gorilla\"\n }\n ]\n}\n", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{IdentityAccountMapperHostName}}/beneficiary", + "host": [ + "{{IdentityAccountMapperHostName}}" + ], + "path": [ + "beneficiary" + ] + } + }, + "status": "Accepted", + "code": 202, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Date", + "value": "Mon, 18 Mar 2024 08:32:58 GMT" + }, + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Transfer-Encoding", + "value": "chunked" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Strict-Transport-Security", + "value": "max-age=15724800; includeSubDomains" + }, + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "Access-Control-Allow-Credentials", + "value": "true" + }, + { + "key": "Access-Control-Allow-Methods", + "value": "PUT, GET, POST, OPTIONS, DELETE" + }, + { + "key": "Access-Control-Allow-Headers", + "value": "x-registering-institution-id" + }, + { + "key": "Access-Control-Max-Age", + "value": "1728000" + } + ], + "cookie": [], + "body": "{\n \"responseCode\": \"00\",\n \"responseDescription\": \"Request successfully received by Pay-BB\",\n \"requestID\": \"915251236706\"\n}" + } + ] + }, + { + "name": "Batch Account Lookup", + "request": { + "method": "POST", + "header": [ + { + "key": "X-CallbackURL", + "value": "{{X-CallbackURL}}", + "type": "text" + }, + { + "key": "X-Registering-Institution-ID", + "value": "{{X-Registering-Institution-ID}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"requestID\": \"915251236706\",\n \"beneficiaries\": [\n {\n \"payeeIdentity\": \"9404916971482891259\"\n },\n {\n \"payeeIdentity\": \"76032553265657618183\"\n },\n {\n \"payeeIdentity\": \"51498584148040549461\"\n },\n {\n \"payeeIdentity\": \"69028769626982342710\"\n },\n {\n \"payeeIdentity\": \"690287696269444382342710\"\n }\n ]\n}\n", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{IdentityAccountMapperHostName}}/accountLookup", + "host": [ + "{{IdentityAccountMapperHostName}}" + ], + "path": [ + "accountLookup" + ] + } + }, + "response": [ + { + "name": "Callback request body", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-CallbackURL", + "value": "{{X-CallbackURL}}", + "type": "text" + }, + { + "key": "X-Registering-Institution-ID", + "value": "{{X-Registering-Institution-ID}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"requestID\": \"915251236706\",\n \"beneficiaries\": [\n {\n \"payeeIdentity\": \"9404916971482891259\"\n },\n {\n \"payeeIdentity\": \"76032553265657618183\"\n },\n {\n \"payeeIdentity\": \"51498584148040549461\"\n },\n {\n \"payeeIdentity\": \"69028769626982342710\"\n },\n {\n \"payeeIdentity\": \"690287696269444382342710\"\n }\n ]\n}\n", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{IdentityAccountMapperHostName}}/accountLookup", + "host": [ + "{{IdentityAccountMapperHostName}}" + ], + "path": [ + "accountLookup" + ] + } + }, + "status": "Accepted", + "code": 202, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Date", + "value": "Mon, 18 Mar 2024 05:06:37 GMT" + }, + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Transfer-Encoding", + "value": "chunked" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Strict-Transport-Security", + "value": "max-age=15724800; includeSubDomains" + }, + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "Access-Control-Allow-Credentials", + "value": "true" + }, + { + "key": "Access-Control-Allow-Methods", + "value": "PUT, GET, POST, OPTIONS, DELETE" + }, + { + "key": "Access-Control-Allow-Headers", + "value": "x-registering-institution-id" + }, + { + "key": "Access-Control-Max-Age", + "value": "1728000" + } + ], + "cookie": [], + "body": "{\n \"responseCode\": \"00\",\n \"responseDescription\": \"Request successfully received by Pay-BB\",\n \"requestID\": \"915251236706\"\n}" + }, + { + "name": "Batch Account Lookup 202", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-CallbackURL", + "value": "{{X-CallbackURL}}", + "type": "text" + }, + { + "key": "X-Registering-Institution-ID", + "value": "{{X-Registering-Institution-ID}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"requestID\": \"915251236706\",\n \"beneficiaries\": [\n {\n \"payeeIdentity\": \"27713803912\"\n },\n {\n \"payeeIdentity\": \"76032553265657618183\"\n },\n {\n \"payeeIdentity\": \"51498584148040549461\"\n },\n {\n \"payeeIdentity\": \"69028769626982342710\"\n },\n {\n \"payeeIdentity\": \"690287696269444382342710\"\n }\n ]\n}\n", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{IdentityAccountMapperHostName}}/accountLookup", + "host": [ + "{{IdentityAccountMapperHostName}}" + ], + "path": [ + "accountLookup" + ] + } + }, + "status": "Accepted", + "code": 202, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Date", + "value": "Mon, 18 Mar 2024 08:34:34 GMT" + }, + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Transfer-Encoding", + "value": "chunked" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Strict-Transport-Security", + "value": "max-age=15724800; includeSubDomains" + }, + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "Access-Control-Allow-Credentials", + "value": "true" + }, + { + "key": "Access-Control-Allow-Methods", + "value": "PUT, GET, POST, OPTIONS, DELETE" + }, + { + "key": "Access-Control-Allow-Headers", + "value": "x-registering-institution-id" + }, + { + "key": "Access-Control-Max-Age", + "value": "1728000" + } + ], + "cookie": [], + "body": "{\n \"responseCode\": \"00\",\n \"responseDescription\": \"Request successfully received by Pay-BB\",\n \"requestID\": \"915251236706\"\n}" + } + ] + }, + { + "name": "Account Lookup", + "protocolProfileBehavior": { + "disableBodyPruning": true + }, + "request": { + "method": "GET", + "header": [ + { + "key": "X-CallbackURL", + "value": "{{X-CallbackURL}}", + "type": "text" + }, + { + "key": "X-Registering-Institution-ID", + "value": "SocialWelfare", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{IdentityAccountMapperHostName}}/beneficiary/?payeeIdentity=63310590323322234956&requestId=12345667987&paymentModality=00", + "host": [ + "{{IdentityAccountMapperHostName}}" + ], + "path": [ + "beneficiary", + "" + ], + "query": [ + { + "key": "payeeIdentity", + "value": "63310590323322234956" + }, + { + "key": "requestId", + "value": "12345667987" + }, + { + "key": "paymentModality", + "value": "00" + } + ] + } + }, + "response": [ + { + "name": "Account Lookup", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-CallbackURL", + "value": "{{X-CallbackURL}}", + "type": "text" + }, + { + "key": "X-Registering-Institution-ID", + "value": "SocialWelfare", + "type": "text" + } + ], + "url": { + "raw": "{{IdentityAccountMapperHostName}}/beneficiary/?payeeIdentity=63310590323322234956&requestId=12345667987&paymentModality=00", + "host": [ + "{{IdentityAccountMapperHostName}}" + ], + "path": [ + "beneficiary", + "" + ], + "query": [ + { + "key": "payeeIdentity", + "value": "63310590323322234956" + }, + { + "key": "requestId", + "value": "12345667987" + }, + { + "key": "paymentModality", + "value": "00" + } + ] + } + }, + "status": "Accepted", + "code": 202, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Date", + "value": "Mon, 18 Mar 2024 05:06:23 GMT" + }, + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Transfer-Encoding", + "value": "chunked" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Strict-Transport-Security", + "value": "max-age=15724800; includeSubDomains" + }, + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "Access-Control-Allow-Credentials", + "value": "true" + }, + { + "key": "Access-Control-Allow-Methods", + "value": "PUT, GET, POST, OPTIONS, DELETE" + }, + { + "key": "Access-Control-Allow-Headers", + "value": "x-registering-institution-id" + }, + { + "key": "Access-Control-Max-Age", + "value": "1728000" + } + ], + "cookie": [], + "body": "{\n \"responseCode\": \"00\",\n \"responseDescription\": \"Request successfully received by Pay-BB\",\n \"requestID\": \"12345667987\"\n}" + } + ] + }, + { + "name": "Fetch All Beneficiaries", + "request": { + "method": "GET", + "header": [ + { + "key": "X-Registering-Institution-ID", + "value": "{{X-Registering-Institution-ID}}", + "type": "text" + } + ], + "url": { + "raw": "{{IdentityAccountMapperHostName}}/beneficiaries?page=10&pageSize=5", + "host": [ + "{{IdentityAccountMapperHostName}}" + ], + "path": [ + "beneficiaries" + ], + "query": [ + { + "key": "page", + "value": "10" + }, + { + "key": "pageSize", + "value": "5" + } + ] + } + }, + "response": [ + { + "name": "Fetch All Beneficiaries", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Registering-Institution-ID", + "value": "{{X-Registering-Institution-ID}}", + "type": "text" + } + ], + "url": { + "raw": "{{IdentityAccountMapperHostName}}/beneficiaries?page=10&pageSize=5", + "host": [ + "{{IdentityAccountMapperHostName}}" + ], + "path": [ + "beneficiaries" + ], + "query": [ + { + "key": "page", + "value": "10" + }, + { + "key": "pageSize", + "value": "5" + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Date", + "value": "Mon, 18 Mar 2024 05:06:04 GMT" + }, + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Transfer-Encoding", + "value": "chunked" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Strict-Transport-Security", + "value": "max-age=15724800; includeSubDomains" + }, + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "Access-Control-Allow-Credentials", + "value": "true" + }, + { + "key": "Access-Control-Allow-Methods", + "value": "PUT, GET, POST, OPTIONS, DELETE" + }, + { + "key": "Access-Control-Allow-Headers", + "value": "x-registering-institution-id" + }, + { + "key": "Access-Control-Max-Age", + "value": "1728000" + } + ], + "cookie": [], + "body": "{\n \"content\": [],\n \"pageable\": {\n \"sort\": {\n \"empty\": true,\n \"unsorted\": true,\n \"sorted\": false\n },\n \"offset\": 50,\n \"pageNumber\": 10,\n \"pageSize\": 5,\n \"paged\": true,\n \"unpaged\": false\n },\n \"totalElements\": 1,\n \"totalPages\": 1,\n \"last\": true,\n \"size\": 5,\n \"number\": 10,\n \"sort\": {\n \"empty\": true,\n \"unsorted\": true,\n \"sorted\": false\n },\n \"numberOfElements\": 0,\n \"first\": false,\n \"empty\": true\n}" + } + ] + }, + { + "name": "Fetch Beneficiaries", + "request": { + "method": "GET", + "header": [ + { + "key": "X-Registering-Institution-ID", + "value": "{{X-Registering-Institution-ID}}", + "type": "text" + } + ], + "url": { + "raw": "{{IdentityAccountMapperHostName}}/beneficiaries/{{payeeIdentity}}", + "host": [ + "{{IdentityAccountMapperHostName}}" + ], + "path": [ + "beneficiaries", + "{{payeeIdentity}}" + ] + } + }, + "response": [ + { + "name": "Fetch Beneficiaries", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Registering-Institution-ID", + "value": "{{X-Registering-Institution-ID}}", + "type": "text" + } + ], + "url": { + "raw": "{{IdentityAccountMapperHostName}}/beneficiaries/{{payeeIdentity}}", + "host": [ + "{{IdentityAccountMapperHostName}}" + ], + "path": [ + "beneficiaries", + "{{payeeIdentity}}" + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Date", + "value": "Mon, 18 Mar 2024 05:05:51 GMT" + }, + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Transfer-Encoding", + "value": "chunked" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Strict-Transport-Security", + "value": "max-age=15724800; includeSubDomains" + }, + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "Access-Control-Allow-Credentials", + "value": "true" + }, + { + "key": "Access-Control-Allow-Methods", + "value": "PUT, GET, POST, OPTIONS, DELETE" + }, + { + "key": "Access-Control-Allow-Headers", + "value": "x-registering-institution-id" + }, + { + "key": "Access-Control-Max-Age", + "value": "1728000" + } + ], + "cookie": [], + "body": "{\n \"registeringInstitutionId\": \"123\",\n \"payeeIdentity\": \"3001003873110196\",\n \"paymentModality\": null,\n \"financialAddress\": null,\n \"bankingInstitutionCode\": null\n}" + } + ] + }, + { + "name": "Add Payment Modality", + "request": { + "method": "POST", + "header": [ + { + "key": "X-CallbackURL", + "value": "{{X-CallbackURL}}", + "type": "text" + }, + { + "key": "X-Registering-Institution-ID", + "value": "{{X-Registering-Institution-ID}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"requestID\": \"915251236706\",\n \"beneficiaries\": [\n {\n \"payeeIdentity\": \"27713803912\",\n \"paymentModality\": \"00\"\n }\n ]\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{IdentityAccountMapperHostName}}/paymentModality", + "host": [ + "{{IdentityAccountMapperHostName}}" + ], + "path": [ + "paymentModality" + ] + } + }, + "response": [ + { + "name": "Add Payment Modality", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-CallbackURL", + "value": "{{X-CallbackURL}}", + "type": "text" + }, + { + "key": "X-Registering-Institution-ID", + "value": "{{X-Registering-Institution-ID}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"requestID\": \"915251236706\",\n \"beneficiaries\": [\n {\n \"payeeIdentity\": \"27713803912\",\n \"paymentModality\": \"00\"\n }\n ]\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{IdentityAccountMapperHostName}}/paymentModality", + "host": [ + "{{IdentityAccountMapperHostName}}" + ], + "path": [ + "paymentModality" + ] + } + }, + "status": "Accepted", + "code": 202, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Date", + "value": "Mon, 18 Mar 2024 05:05:30 GMT" + }, + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Transfer-Encoding", + "value": "chunked" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Strict-Transport-Security", + "value": "max-age=15724800; includeSubDomains" + }, + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "Access-Control-Allow-Credentials", + "value": "true" + }, + { + "key": "Access-Control-Allow-Methods", + "value": "PUT, GET, POST, OPTIONS, DELETE" + }, + { + "key": "Access-Control-Allow-Headers", + "value": "x-registering-institution-id" + }, + { + "key": "Access-Control-Max-Age", + "value": "1728000" + } + ], + "cookie": [], + "body": "{\n \"requestID\": \"171074009205\",\n \"registerRequestID\": \"915251236706\",\n \"numberFailedCases\": 1,\n \"failedCases\": [\n {\n \"payeeIdentity\": \"27713803912\",\n \"paymentModality\": \"00\",\n \"failureReason\": \"Banking Institution Code Invalid\"\n }\n ]\n}" + } + ] + }, + { + "name": "Update Payment Modality", + "request": { + "method": "PUT", + "header": [ + { + "key": "X-CallbackURL", + "value": "{{X-CallbackURL}}", + "type": "text" + }, + { + "key": "X-Registering-Institution-ID", + "value": "{{X-Registering-Institution-ID}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"requestID\": \"915251236706\",\n \"beneficiaries\": [\n {\n \"payeeIdentity\": \"51498584148040549461\",\n \"paymentModality\": \"00\",\n \"financialAddress\": \"998LB283697636447147812564357\"\n }\n ]\n}\n", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{IdentityAccountMapperHostName}}/paymentModality", + "host": [ + "{{IdentityAccountMapperHostName}}" + ], + "path": [ + "paymentModality" + ] + } + }, + "response": [ + { + "name": "Failed Update Payment Modality", + "originalRequest": { + "method": "PUT", + "header": [ + { + "key": "X-CallbackURL", + "value": "{{X-CallbackURL}}", + "type": "text" + }, + { + "key": "X-Registering-Institution-ID", + "value": "{{X-Registering-Institution-ID}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"requestID\": \"915251236706\",\n \"beneficiaries\": [\n {\n \"payeeIdentity\": \"51498584148040549461\",\n \"paymentModality\": \"00\",\n \"financialAddress\": \"998LB283697636447147812564357\"\n }\n ]\n}\n", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{IdentityAccountMapperHostName}}/paymentModality", + "host": [ + "{{IdentityAccountMapperHostName}}" + ], + "path": [ + "paymentModality" + ] + } + }, + "status": "Accepted", + "code": 202, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Date", + "value": "Mon, 18 Mar 2024 05:05:11 GMT" + }, + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Transfer-Encoding", + "value": "chunked" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Strict-Transport-Security", + "value": "max-age=15724800; includeSubDomains" + }, + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "Access-Control-Allow-Credentials", + "value": "true" + }, + { + "key": "Access-Control-Allow-Methods", + "value": "PUT, GET, POST, OPTIONS, DELETE" + }, + { + "key": "Access-Control-Allow-Headers", + "value": "x-registering-institution-id" + }, + { + "key": "Access-Control-Max-Age", + "value": "1728000" + } + ], + "cookie": [], + "body": "{\n \"requestID\": \"171074011382\",\n \"registerRequestID\": \"915251236706\",\n \"numberFailedCases\": 1,\n \"failedCases\": [\n {\n \"payeeIdentity\": \"51498584148040549461\",\n \"paymentModality\": \"00\",\n \"failureReason\": \"Beneficiary is not registered\"\n }\n ]\n}" + } + ] + } + ] + }, + { + "name": "Voucher Management", + "item": [ + { + "name": "Create Voucher", + "request": { + "method": "POST", + "header": [ + { + "key": "X-CallbackURL", + "value": "{{X-CallbackURL}}", + "type": "text" + }, + { + "key": "X-Registering-Institution-ID", + "value": "{{X-Registering-Institution-ID}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"requestID\": \"849324499155\",\n \"batchID\": \"045155518258\",\n \"voucherInstructions\": [\n {\n \"instructionID\": \"1202383344325434\",\n \"groupCode\": \"021\",\n \"currency\": \"USD\",\n \"amount\": 5009,\n \"payeeFunctionalID\": \"63310590322288932633\",\n \"narration\": \"Social Support Payment for the Month of Jan\"\n }\n ]\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{VoucherManagementHostName}}/vouchers", + "host": [ + "{{VoucherManagementHostName}}" + ], + "path": [ + "vouchers" + ] + } + }, + "response": [ + { + "name": "Sample response 202", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-CallbackURL", + "value": "{{X-CallbackURL}}", + "type": "text" + }, + { + "key": "X-Registering-Institution-ID", + "value": "{{X-Registering-Institution-ID}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"requestID\": \"849324499155\",\n \"batchID\": \"045155518258\",\n \"voucherInstructions\": [\n {\n \"instructionID\": \"1202383344325434\",\n \"groupCode\": \"021\",\n \"currency\": \"USD\",\n \"amount\": 5009,\n \"payeeFunctionalID\": \"63310590322288932633\",\n \"narration\": \"Social Support Payment for the Month of Jan\"\n }\n ]\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{VoucherManagementHostName}}/vouchers", + "host": [ + "{{VoucherManagementHostName}}" + ], + "path": [ + "vouchers" + ] + } + }, + "status": "Accepted", + "code": 202, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "name": "Content-Type", + "description": "", + "type": "text" + } + ], + "cookie": [], + "body": "{\n \"responseCode\": \"00\",\n \"responseDescription\": \"Request successfully received by Pay-BB\",\n \"requestID\": \"849324499155\"\n}" + }, + { + "name": "Callback request body", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-CallbackURL", + "value": "{{X-CallbackURL}}", + "type": "text" + }, + { + "key": "X-Registering-Institution-ID", + "value": "{{X-Registering-Institution-ID}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"requestID\": \"849324499155\",\n \"batchID\": \"045155518258\",\n \"voucherInstructions\": [\n {\n \"instructionID\": \"1202383344325434\",\n \"groupCode\": \"021\",\n \"currency\": \"USD\",\n \"amount\": 5009,\n \"payeeFunctionalID\": \"63310590322288932633\",\n \"narration\": \"Social Support Payment for the Month of Jan\"\n }\n ]\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{VoucherManagementHostName}}/vouchers", + "host": [ + "{{VoucherManagementHostName}}" + ], + "path": [ + "vouchers" + ] + } + }, + "status": "Accepted", + "code": 202, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "name": "Content-Type", + "description": "", + "type": "text" + } + ], + "cookie": [], + "body": "{\n \"requestID\": \"849324499155\",\n \"batchID\": \"045155518258\",\n \"voucherInstructions\": [\n {\n \"instructionID\": \"1202383344325434\",\n \"currency\": \"USD\",\n \"amount\": 5009,\n \"narration\": \"Social Support Payment for the Month of Jan\",\n \"voucherNumber\": \"f3ONmzIfROhCCHZiAFXATQHqm2/tJjuh0ozax0ycaJp+rE32Cm4r2Ub8xIpE2AEXvvvG/42bB/DlVUbF2Fe1NQHF7HHBQPV0TMUy0AbIfE7ihf3Qp6DMsd2z2ffyKdo0KpRY8x25lZSB/D1wUM96KsdPR1OB4zyDOag+zSIZbJIbLD+jRWkzw8pJp0X7x5RtRrh4KD5gwR3M6RNA7Hpd+eYzUo2SsPx82QLHi1Vx1l79f3JFpPmc0lhdrfzbEZQQAk/6z2dj2aw89XaBOZsZXy751E9xJQGXtiitA8m9mIrFYZ3iQoWzbSIzFEygM6sIbJASgrm+YvYesWUP/pcmXw==\",\n \"serialNumber\": \"17123246904971\"\n }\n ]\n}" + } + ] + }, + { + "name": "Activate Voucher", + "request": { + "auth": { + "type": "noauth" + }, + "method": "PUT", + "header": [ + { + "key": "X-CallbackURL", + "value": "{{X-CallbackURL}}", + "type": "text" + }, + { + "key": "X-Registering-Institution-ID", + "value": "{{X-Registering-Institution-ID}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"requestID\": \"849324499155\",\n \"batchID\": \"045155518258\",\n \"voucherInstructions\": [\n {\n \"serialNumber\": \"16939790248654\",\n \"status\": \"02\"\n }\n ]\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{VoucherManagementHostName}}/vouchers?command=activate", + "host": [ + "{{VoucherManagementHostName}}" + ], + "path": [ + "vouchers" + ], + "query": [ + { + "key": "command", + "value": "activate" + } + ] + } + }, + "response": [ + { + "name": "Sample response 202", + "originalRequest": { + "method": "PUT", + "header": [ + { + "key": "X-CallbackURL", + "value": "{{X-CallbackURL}}", + "type": "text" + }, + { + "key": "X-Registering-Institution-ID", + "value": "{{X-Registering-Institution-ID}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"requestID\": \"849324499155\",\n \"batchID\": \"045155518258\",\n \"voucherInstructions\": [\n {\n \"serialNumber\": \"16939790248654\",\n \"status\": \"02\"\n }\n ]\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{VoucherManagementHostName}}/vouchers?command=activate", + "host": [ + "{{VoucherManagementHostName}}" + ], + "path": [ + "vouchers" + ], + "query": [ + { + "key": "command", + "value": "activate" + } + ] + } + }, + "status": "Accepted", + "code": 202, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "name": "Content-Type", + "description": "", + "type": "text" + } + ], + "cookie": [], + "body": "{\n \"responseCode\": \"00\",\n \"responseDescription\": \"Request successfully received by Pay-BB\",\n \"requestID\": \"849324499155\"\n}" + }, + { + "name": "Callback request body", + "originalRequest": { + "method": "PUT", + "header": [ + { + "key": "X-CallbackURL", + "value": "{{X-CallbackURL}}", + "type": "text" + }, + { + "key": "X-Registering-Institution-ID", + "value": "{{X-Registering-Institution-ID}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"requestID\": \"849324499155\",\n \"batchID\": \"045155518258\",\n \"voucherInstructions\": [\n {\n \"serialNumber\": \"16939790248654\",\n \"status\": \"02\"\n }\n ]\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{VoucherManagementHostName}}/vouchers?command=activate", + "host": [ + "{{VoucherManagementHostName}}" + ], + "path": [ + "vouchers" + ], + "query": [ + { + "key": "command", + "value": "activate" + } + ] + } + }, + "status": "Accepted", + "code": 202, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "name": "Content-Type", + "description": "", + "type": "text" + } + ], + "cookie": [], + "body": "{\n \"requestID\": \"171232475311\",\n \"registerRequestID\": \"849324499155\",\n \"numberFailedCases\": 0,\n \"failedCases\": []\n}" + } + ] + }, + { + "name": "Suspend Voucher", + "request": { + "auth": { + "type": "noauth" + }, + "method": "PUT", + "header": [ + { + "key": "X-CallbackURL", + "value": "{{X-CallbackURL}}", + "type": "text" + }, + { + "key": "X-Registering-Institution-ID", + "value": "{{X-Registering-Institution-ID}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"requestID\": \"849324499155\",\n \"batchID\": \"045155518258\",\n \"voucherInstructions\": [\n {\n \"serialNumber\": \"16895906640276\",\n \"status\": \"06\"\n }\n ]\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{VoucherManagementHostName}}/vouchers?command=suspend", + "host": [ + "{{VoucherManagementHostName}}" + ], + "path": [ + "vouchers" + ], + "query": [ + { + "key": "command", + "value": "suspend" + } + ] + } + }, + "response": [ + { + "name": "Sample response 202", + "originalRequest": { + "method": "PUT", + "header": [ + { + "key": "X-CallbackURL", + "value": "{{X-CallbackURL}}", + "type": "text" + }, + { + "key": "X-Registering-Institution-ID", + "value": "{{X-Registering-Institution-ID}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"requestID\": \"849324499155\",\n \"batchID\": \"045155518258\",\n \"voucherInstructions\": [\n {\n \"serialNumber\": \"16895906640276\",\n \"status\": \"06\"\n }\n ]\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{VoucherManagementHostName}}/vouchers?command=suspend", + "host": [ + "{{VoucherManagementHostName}}" + ], + "path": [ + "vouchers" + ], + "query": [ + { + "key": "command", + "value": "suspend" + } + ] + } + }, + "status": "Accepted", + "code": 202, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "name": "Content-Type", + "description": "", + "type": "text" + } + ], + "cookie": [], + "body": "{\n \"responseCode\": \"00\",\n \"responseDescription\": \"Request successfully received by Pay-BB\",\n \"requestID\": \"849324499155\"\n}" + }, + { + "name": "Callback request body", + "originalRequest": { + "method": "PUT", + "header": [ + { + "key": "X-CallbackURL", + "value": "{{X-CallbackURL}}", + "type": "text" + }, + { + "key": "X-Registering-Institution-ID", + "value": "{{X-Registering-Institution-ID}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"requestID\": \"849324499155\",\n \"batchID\": \"045155518258\",\n \"voucherInstructions\": [\n {\n \"serialNumber\": \"16895906640276\",\n \"status\": \"06\"\n }\n ]\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{VoucherManagementHostName}}/vouchers?command=suspend", + "host": [ + "{{VoucherManagementHostName}}" + ], + "path": [ + "vouchers" + ], + "query": [ + { + "key": "command", + "value": "suspend" + } + ] + } + }, + "status": "Accepted", + "code": 202, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "name": "Content-Type", + "description": "", + "type": "text" + } + ], + "cookie": [], + "body": "{\n \"requestID\": \"171232493718\",\n \"registerRequestID\": \"849324499155\",\n \"numberFailedCases\": 0,\n \"failedCases\": []\n}" + } + ] + }, + { + "name": "Cancel Voucher", + "request": { + "auth": { + "type": "noauth" + }, + "method": "POST", + "header": [ + { + "key": "X-CallbackURL", + "value": "{{X-CallbackURL}}", + "type": "text" + }, + { + "key": "X-Registering-Institution-ID", + "value": "{{X-Registering-Institution-ID}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"requestID\": \"849324499155\",\n \"batchID\": \"045155518258\",\n \"voucherInstructions\": [\n {\n \"serialNumber\": \"16895845478866\",\n \"status\": \"03\"\n }\n ]\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{VoucherManagementHostName}}/vouchers?command=cancel", + "host": [ + "{{VoucherManagementHostName}}" + ], + "path": [ + "vouchers" + ], + "query": [ + { + "key": "command", + "value": "cancel" + } + ] + } + }, + "response": [ + { + "name": "Sample response 202", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-CallbackURL", + "value": "{{X-CallbackURL}}", + "type": "text" + }, + { + "key": "X-Registering-Institution-ID", + "value": "{{X-Registering-Institution-ID}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"requestID\": \"849324499155\",\n \"batchID\": \"045155518258\",\n \"voucherInstructions\": [\n {\n \"serialNumber\": \"16895845478866\",\n \"status\": \"03\"\n }\n ]\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{VoucherManagementHostName}}/vouchers?command=cancel", + "host": [ + "{{VoucherManagementHostName}}" + ], + "path": [ + "vouchers" + ], + "query": [ + { + "key": "command", + "value": "cancel" + } + ] + } + }, + "status": "Accepted", + "code": 202, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "name": "Content-Type", + "description": "", + "type": "text" + } + ], + "cookie": [], + "body": "{\n \"responseCode\": \"00\",\n \"responseDescription\": \"Request successfully received by Pay-BB\",\n \"requestID\": \"849324499155\"\n}" + }, + { + "name": "Callback request body", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-CallbackURL", + "value": "{{X-CallbackURL}}", + "type": "text" + }, + { + "key": "X-Registering-Institution-ID", + "value": "{{X-Registering-Institution-ID}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"requestID\": \"849324499155\",\n \"batchID\": \"045155518258\",\n \"voucherInstructions\": [\n {\n \"serialNumber\": \"16895845478866\",\n \"status\": \"03\"\n }\n ]\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{VoucherManagementHostName}}/vouchers?command=cancel", + "host": [ + "{{VoucherManagementHostName}}" + ], + "path": [ + "vouchers" + ], + "query": [ + { + "key": "command", + "value": "cancel" + } + ] + } + }, + "status": "Accepted", + "code": 202, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "name": "Content-Type", + "description": "", + "type": "text" + } + ], + "cookie": [], + "body": "{\n \"requestID\": \"171232511656\",\n \"registerRequestID\": \"849324499155\",\n \"numberFailedCases\": 0,\n \"failedCases\": []\n}" + } + ] + }, + { + "name": "Reactivate Voucher", + "request": { + "auth": { + "type": "noauth" + }, + "method": "PUT", + "header": [ + { + "key": "X-CallbackURL", + "value": "{{X-CallbackURL}}", + "type": "text" + }, + { + "key": "X-Registering-Institution-ID", + "value": "{{X-Registering-Institution-ID}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"requestID\": \"849324499155\",\n \"batchID\": \"045155518258\",\n \"voucherInstructions\": [\n {\n \"serialNumber\": \"16895906640276\",\n \"status\": \"02\"\n }\n ]\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{VoucherManagementHostName}}/vouchers?command=reactivate", + "host": [ + "{{VoucherManagementHostName}}" + ], + "path": [ + "vouchers" + ], + "query": [ + { + "key": "command", + "value": "reactivate" + } + ] + } + }, + "response": [ + { + "name": "Sample response 202", + "originalRequest": { + "method": "PUT", + "header": [ + { + "key": "X-CallbackURL", + "value": "{{X-CallbackURL}}", + "type": "text" + }, + { + "key": "X-Registering-Institution-ID", + "value": "{{X-Registering-Institution-ID}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"requestID\": \"849324499155\",\n \"batchID\": \"045155518258\",\n \"voucherInstructions\": [\n {\n \"serialNumber\": \"16895906640276\",\n \"status\": \"02\"\n }\n ]\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{VoucherManagementHostName}}/vouchers?command=reactivate", + "host": [ + "{{VoucherManagementHostName}}" + ], + "path": [ + "vouchers" + ], + "query": [ + { + "key": "command", + "value": "reactivate" + } + ] + } + }, + "status": "Accepted", + "code": 202, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "name": "Content-Type", + "description": "", + "type": "text" + } + ], + "cookie": [], + "body": "{\n \"responseCode\": \"00\",\n \"responseDescription\": \"Request successfully received by Pay-BB\",\n \"requestID\": \"849324499155\"\n}" + }, + { + "name": "Sample request body", + "originalRequest": { + "method": "PUT", + "header": [ + { + "key": "X-CallbackURL", + "value": "{{X-CallbackURL}}", + "type": "text" + }, + { + "key": "X-Registering-Institution-ID", + "value": "{{X-Registering-Institution-ID}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"requestID\": \"849324499155\",\n \"batchID\": \"045155518258\",\n \"voucherInstructions\": [\n {\n \"serialNumber\": \"16895906640276\",\n \"status\": \"02\"\n }\n ]\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{VoucherManagementHostName}}/vouchers?command=reactivate", + "host": [ + "{{VoucherManagementHostName}}" + ], + "path": [ + "vouchers" + ], + "query": [ + { + "key": "command", + "value": "reactivate" + } + ] + } + }, + "status": "Accepted", + "code": 202, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "name": "Content-Type", + "description": "", + "type": "text" + } + ], + "cookie": [], + "body": "{\n \"requestID\": \"171233278011\",\n \"registerRequestID\": \"849324499155\",\n \"numberFailedCases\": 0,\n \"failedCases\": []\n}" + } + ] + }, + { + "name": "Redeem Voucher", + "request": { + "method": "POST", + "header": [ + { + "key": "X-CallbackURL", + "value": "{{X-CallbackURL}}", + "type": "text" + }, + { + "key": "X-Registering-Institution-ID", + "value": "{{X-Registering-Institution-ID}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"requestId\": \"849324499155\",\n \"agentId\": \"1234567890\",\n \"voucherSecretNumber\": \"168959066402710531\"\n }\n", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{VoucherManagementHostName}}/vouchers?command=redeem", + "host": [ + "{{VoucherManagementHostName}}" + ], + "path": [ + "vouchers" + ], + "query": [ + { + "key": "command", + "value": "redeem" + } + ] + } + }, + "response": [ + { + "name": "Sample response 202", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-CallbackURL", + "value": "{{X-CallbackURL}}", + "type": "text" + }, + { + "key": "X-Registering-Institution-ID", + "value": "{{X-Registering-Institution-ID}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"requestId\": \"849324499155\",\n \"agentId\": \"1234567890\",\n \"voucherSecretNumber\": \"168959066402710531\"\n }\n", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{VoucherManagementHostName}}/vouchers?command=redeem", + "host": [ + "{{VoucherManagementHostName}}" + ], + "path": [ + "vouchers" + ], + "query": [ + { + "key": "command", + "value": "redeem" + } + ] + } + }, + "status": "Accepted", + "code": 202, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "name": "Content-Type", + "description": "", + "type": "text" + } + ], + "cookie": [], + "body": "{\n \"status\": \"01\",\n \"message\": \"Voucher redemption successful!\",\n \"serialNumber\": \"H8cTUUhlO/JIqFCRZdfyeIbtxeWvzO5++5xtj+r9wcALoOnP17mG5tYThRROkWBFrW2O4xYjtuZsV9VCQk+4VrTgzwA8uafbWZQh6hppHx7zgrwJ7E/YiC6MZriMvp4vHIFSruYFbKOt5gr3RGkNFAl1xD9wTY3n0g381/qZSSAWA8ODByt61nZLyNH91of4wHyzYtCJuFCBx3UKKhICenv1XJ4FaKUKrWYyFPCMN24DIDprwzY5aAKFRucXKYK2XG4UkyJQe7lRvDfmOo/jzGtz2LmxtsgltJYvGqglZx3Q0k4zmJUkopB4O5edAb4bMzuny3zPsbqTyk2CF/GWtQ==\",\n \"value\": \"5009.00\",\n \"timestamp\": \"2024-04-05T16:01:24.271818174\",\n \"transactionId\": \"1712332884\"\n}" + } + ] + }, + { + "name": "Redeem and Pay Voucher", + "request": { + "method": "PUT", + "header": [ + { + "key": "X-CallbackURL", + "value": "{{X-CallbackURL}}", + "type": "text" + }, + { + "key": "X-Registering-Institution-ID", + "value": "{{X-Registering-Institution-ID}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"requestId\": \"849324499155\",\n \"agentId\": \"1234567890\",\n \"voucherSecretNumber\": \"168975377470710722\"\n }\n", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{VoucherManagementHostName}}/vouchers?command=redeemPay", + "host": [ + "{{VoucherManagementHostName}}" + ], + "path": [ + "vouchers" + ], + "query": [ + { + "key": "command", + "value": "redeemPay" + } + ] + } + }, + "response": [ + { + "name": "Sample response 202", + "originalRequest": { + "method": "PUT", + "header": [ + { + "key": "X-CallbackURL", + "value": "{{X-CallbackURL}}", + "type": "text" + }, + { + "key": "X-Registering-Institution-ID", + "value": "{{X-Registering-Institution-ID}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"requestId\": \"849324499155\",\n \"agentId\": \"1234567890\",\n \"voucherSecretNumber\": \"168975377470710722\"\n }\n", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{VoucherManagementHostName}}/vouchers?command=redeemPay", + "host": [ + "{{VoucherManagementHostName}}" + ], + "path": [ + "vouchers" + ], + "query": [ + { + "key": "command", + "value": "redeemPay" + } + ] + } + }, + "status": "Accepted", + "code": 202, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "name": "Content-Type", + "description": "", + "type": "text" + } + ], + "cookie": [], + "body": "{\n \"responseCode\": \"00\",\n \"responseDescription\": \"Request successfully received by Pay-BB\",\n \"requestID\": \"849324499155\"\n}" + }, + { + "name": "Sample request body", + "originalRequest": { + "method": "PUT", + "header": [ + { + "key": "X-CallbackURL", + "value": "{{X-CallbackURL}}", + "type": "text" + }, + { + "key": "X-Registering-Institution-ID", + "value": "{{X-Registering-Institution-ID}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"requestId\": \"849324499155\",\n \"agentId\": \"1234567890\",\n \"voucherSecretNumber\": \"168975377470710722\"\n }\n", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{VoucherManagementHostName}}/vouchers?command=redeemPay", + "host": [ + "{{VoucherManagementHostName}}" + ], + "path": [ + "vouchers" + ], + "query": [ + { + "key": "command", + "value": "redeemPay" + } + ] + } + }, + "status": "Accepted", + "code": 202, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "name": "Content-Type", + "description": "", + "type": "text" + } + ], + "cookie": [], + "body": "{\n \"requestID\": \"171233306861\",\n \"registerRequestID\": \"849324499155\",\n \"numberFailedCases\": 0,\n \"failedCases\": []\n}" + } + ] + }, + { + "name": "Check Validity", + "request": { + "method": "GET", + "header": [ + { + "key": "X-CallbackURL", + "value": "{{X-CallbackURL}}", + "type": "text" + }, + { + "key": "X-Registering-Institution-ID", + "value": "{{X-Registering-Institution-ID}}", + "type": "text" + } + ], + "url": { + "raw": "{{VoucherManagementHostName}}/voucher/validity?isValid=true&serialNumber=16939790248654", + "host": [ + "{{VoucherManagementHostName}}" + ], + "path": [ + "voucher", + "validity" + ], + "query": [ + { + "key": "isValid", + "value": "true" + }, + { + "key": "voucherNumber", + "value": "ffds", + "disabled": true + }, + { + "key": "groupCode", + "value": "fsfsfd", + "disabled": true + }, + { + "key": "serialNumber", + "value": "16939790248654" + } + ] + } + }, + "response": [ + { + "name": "Sample response 202", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-CallbackURL", + "value": "{{X-CallbackURL}}", + "type": "text" + }, + { + "key": "X-Registering-Institution-ID", + "value": "{{X-Registering-Institution-ID}}", + "type": "text" + } + ], + "url": { + "raw": "{{VoucherManagementHostName}}/voucher/validity?isValid=true&serialNumber=16939790248654", + "host": [ + "{{VoucherManagementHostName}}" + ], + "path": [ + "voucher", + "validity" + ], + "query": [ + { + "key": "isValid", + "value": "true" + }, + { + "key": "voucherNumber", + "value": "ffds", + "disabled": true + }, + { + "key": "groupCode", + "value": "fsfsfd", + "disabled": true + }, + { + "key": "serialNumber", + "value": "16939790248654" + } + ] + } + }, + "status": "Accepted", + "code": 202, + "_postman_previewlanguage": "Text", + "header": [], + "cookie": [], + "body": "{\n \"responseCode\": \"00\",\n \"responseDescription\": \"Request successfully received by Pay-BB\",\n \"requestID\": \"\"\n}\n" + }, + { + "name": "Callback request body", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-CallbackURL", + "value": "{{X-CallbackURL}}", + "type": "text" + }, + { + "key": "X-Registering-Institution-ID", + "value": "{{X-Registering-Institution-ID}}", + "type": "text" + } + ], + "url": { + "raw": "{{VoucherManagementHostName}}/voucher/validity?isValid=true&serialNumber=16939790248654", + "host": [ + "{{VoucherManagementHostName}}" + ], + "path": [ + "voucher", + "validity" + ], + "query": [ + { + "key": "isValid", + "value": "true" + }, + { + "key": "voucherNumber", + "value": "ffds", + "disabled": true + }, + { + "key": "groupCode", + "value": "fsfsfd", + "disabled": true + }, + { + "key": "serialNumber", + "value": "16939790248654" + } + ] + } + }, + "status": "Accepted", + "code": 202, + "_postman_previewlanguage": "Text", + "header": [], + "cookie": [], + "body": "{\n \"serialNumber\": \"17098827605447\",\n \"isValid\": true\n}" + } + ] + }, + { + "name": "Fetch Vouchers", + "protocolProfileBehavior": { + "disableBodyPruning": true + }, + "request": { + "method": "GET", + "header": [ + { + "key": "X-Registering-Institution-ID", + "value": "{{X-Registering-Institution-ID}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{VoucherManagementHostName}}/vouchers/{{voucherNumber}}", + "host": [ + "{{VoucherManagementHostName}}" + ], + "path": [ + "vouchers", + "{{voucherNumber}}" + ] + } + }, + "response": [ + { + "name": "Sample response 202", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Registering-Institution-ID", + "value": "{{X-Registering-Institution-ID}}", + "type": "text" + } + ], + "url": { + "raw": "{{VoucherManagementHostName}}/vouchers/{{voucherNumber}}", + "host": [ + "{{VoucherManagementHostName}}" + ], + "path": [ + "vouchers", + "{{voucherNumber}}" + ] + } + }, + "status": "Accepted", + "code": 202, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "name": "Content-Type", + "description": "", + "type": "text" + } + ], + "cookie": [], + "body": "{\n \"serialNumber\": \"17098827605447\",\n \"createdDate\": \"2024-03-08T07:26:01\",\n \"registeringInstitutionId\": \"123\",\n \"status\": \"02\",\n \"payeeFunctionalID\": \"63310590322288932682\"\n}" + } + ] + }, + { + "name": "Fetch All Vouchers", + "protocolProfileBehavior": { + "disableBodyPruning": true + }, + "request": { + "method": "GET", + "header": [ + { + "key": "X-Registering-Institution-ID", + "value": "{{X-Registering-Institution-ID}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{VoucherManagementHostName}}/vouchers?page=0&size=10", + "host": [ + "{{VoucherManagementHostName}}" + ], + "path": [ + "vouchers" + ], + "query": [ + { + "key": "page", + "value": "0" + }, + { + "key": "size", + "value": "10" + } + ] + } + }, + "response": [ + { + "name": "Sample response 202", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "X-Registering-Institution-ID", + "value": "{{X-Registering-Institution-ID}}", + "type": "text" + } + ], + "url": { + "raw": "{{VoucherManagementHostName}}/vouchers?page=0&size=10", + "host": [ + "{{VoucherManagementHostName}}" + ], + "path": [ + "vouchers" + ], + "query": [ + { + "key": "page", + "value": "0" + }, + { + "key": "size", + "value": "10" + } + ] + } + }, + "status": "Accepted", + "code": 202, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "name": "Content-Type", + "description": "", + "type": "text" + } + ], + "cookie": [], + "body": "{\n \"content\": [\n {\n \"serialNumber\": \"17098827605447\",\n \"createdDate\": \"2024-03-08T07:26:01\",\n \"registeringInstitutionId\": \"123\",\n \"status\": \"02\",\n \"payeeFunctionalID\": \"63310590322288932682\"\n },\n {\n \"serialNumber\": \"17098827614621\",\n \"createdDate\": \"2024-03-08T07:26:01\",\n \"registeringInstitutionId\": \"123\",\n \"status\": \"02\",\n \"payeeFunctionalID\": \"63310590322288932682\"\n },\n {\n \"serialNumber\": \"17098827623176\",\n \"createdDate\": \"2024-03-08T07:26:02\",\n \"registeringInstitutionId\": \"123\",\n \"status\": \"02\",\n \"payeeFunctionalID\": \"63310590322288932682\"\n },\n {\n \"serialNumber\": \"17098827631581\",\n \"createdDate\": \"2024-03-08T07:26:03\",\n \"registeringInstitutionId\": \"123\",\n \"status\": \"02\",\n \"payeeFunctionalID\": \"63310590322288932682\"\n },\n {\n \"serialNumber\": \"17098827640378\",\n \"createdDate\": \"2024-03-08T07:26:04\",\n \"registeringInstitutionId\": \"123\",\n \"status\": \"02\",\n \"payeeFunctionalID\": \"63310590322288932682\"\n },\n {\n \"serialNumber\": \"17098827649245\",\n \"createdDate\": \"2024-03-08T07:26:05\",\n \"registeringInstitutionId\": \"123\",\n \"status\": \"02\",\n \"payeeFunctionalID\": \"63310590322288932682\"\n },\n {\n \"serialNumber\": \"17098827658061\",\n \"createdDate\": \"2024-03-08T07:26:06\",\n \"registeringInstitutionId\": \"123\",\n \"status\": \"02\",\n \"payeeFunctionalID\": \"63310590322288932682\"\n },\n {\n \"serialNumber\": \"17098828235054\",\n \"createdDate\": \"2024-03-08T07:27:04\",\n \"registeringInstitutionId\": \"123\",\n \"status\": \"02\",\n \"payeeFunctionalID\": \"63310590322288932682\"\n },\n {\n \"serialNumber\": \"17098828244473\",\n \"createdDate\": \"2024-03-08T07:27:04\",\n \"registeringInstitutionId\": \"123\",\n \"status\": \"02\",\n \"payeeFunctionalID\": \"63310590322288932682\"\n },\n {\n \"serialNumber\": \"17098828254959\",\n \"createdDate\": \"2024-03-08T07:27:05\",\n \"registeringInstitutionId\": \"123\",\n \"status\": \"02\",\n \"payeeFunctionalID\": \"63310590322288932682\"\n }\n ],\n \"pageable\": {\n \"sort\": {\n \"empty\": true,\n \"unsorted\": true,\n \"sorted\": false\n },\n \"offset\": 0,\n \"pageNumber\": 0,\n \"pageSize\": 10,\n \"unpaged\": false,\n \"paged\": true\n },\n \"totalPages\": 103,\n \"totalElements\": 1029,\n \"last\": false,\n \"size\": 10,\n \"number\": 0,\n \"sort\": {\n \"empty\": true,\n \"unsorted\": true,\n \"sorted\": false\n },\n \"numberOfElements\": 10,\n \"first\": true,\n \"empty\": false\n}" + } + ] + } + ] + }, + { + "name": "Bill Pay APIs", + "item": [ + { + "name": "Mock APIs", + "item": [ + { + "name": "Connector-CRM", + "item": [ + { + "name": "Bill Inquiry API", + "request": { + "method": "GET", + "header": [ + { + "key": "Platform-TenantId", + "value": "{{TenantName}}", + "type": "text" + }, + { + "key": "X-CorrelationID", + "value": "f56caf0b-377d-4a1f-8ac1-715859a83eee", + "type": "text" + }, + { + "key": "X-CallbackURL", + "value": "{{X-CallbackURL}}", + "type": "text" + }, + { + "key": "X-PayerFSP-Id", + "value": "{{PayeeTenantName}}", + "type": "text" + } + ], + "url": { + "raw": "{{ConnectorCRMHostName}}/bills/{{billId}}", + "host": [ + "{{ConnectorCRMHostName}}" + ], + "path": [ + "bills", + "{{billId}}" + ] + } + }, + "response": [] + }, + { + "name": "Bill Payments API", + "request": { + "method": "POST", + "header": [ + { + "key": "Platform-TenantId", + "value": "{{TenantName}}", + "type": "text" + }, + { + "key": "X-CorrelationID", + "value": "f56caf0b-377d-4a1f-8ac1-715859a83eee", + "type": "text" + }, + { + "key": "X-PayerFSP-Id", + "value": "{{PayeeTenantName}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"billInquiryRequestId\": \"12e2cedc-7372-4208-8079-7d46d691fca4\",\n \"billId\": \"001\",\n \"paymentReferenceID\": \"8f353842-451c-4231-afc9-58289afdc396\"\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{ConnectorCRMHostName}}/paymentNotifications", + "host": [ + "{{ConnectorCRMHostName}}" + ], + "path": [ + "paymentNotifications" + ] + } + }, + "response": [] + } + ] + }, + { + "name": "Connector-Bulk", + "item": [ + { + "name": "Payer RTP Request API", + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "X-Platform-TenantId", + "value": "{{TenantName}}", + "type": "text" + }, + { + "key": "X-Client-Correlation-ID", + "value": "{{clientCorrelationId}}", + "type": "text" + }, + { + "key": "X-Callback-URL", + "value": "{{X-CallbackURL}}", + "type": "text" + }, + { + "key": "X-Biller-Id", + "value": "GovBill", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{ConnectorBulkHostName}}/billTransferRequests", + "host": [ + "{{ConnectorBulkHostName}}" + ], + "path": [ + "billTransferRequests" + ] + } + }, + "response": [ + { + "name": "Payer RTP Request API 202", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "X-Platform-TenantId", + "value": "{{TenantName}}", + "type": "text" + }, + { + "key": "X-Client-Correlation-ID", + "value": "{{clientCorrelationId}}", + "type": "text" + }, + { + "key": "X-Callback-URL", + "value": "{{X-CallbackURL}}", + "type": "text" + }, + { + "key": "X-Biller-Id", + "value": "GovBill", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{ConnectorBulkHostName}}/billTransferRequests", + "host": [ + "{{ConnectorBulkHostName}}" + ], + "path": [ + "billTransferRequests" + ] + } + }, + "status": "Accepted", + "code": 202, + "_postman_previewlanguage": null, + "header": null, + "cookie": [], + "body": "{\n \"responseCode\": \"00\",\n \"responseDescription\": \"Request successfully received by Pay-BB\",\n \"requestID\": \"12345678-6897-6798-6798-098765432134\"\n}" + } + ] + } + ] + }, + { + "name": "Payer RTP Response API", + "request": { + "method": "PUT", + "header": [ + { + "key": "X-Callback-URL", + "value": "{{X-CallbackURL}}", + "type": "text" + }, + { + "key": "X-Client-Correlation-ID", + "value": "{{clientCorrelationId}}", + "type": "text" + }, + { + "key": "X-Biller-Id", + "value": "GovBill", + "type": "text" + }, + { + "key": "X-Platform-TenantId", + "value": "{{TenantName}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"clientCorrelationId\": \"123445\",\n \"billId\": \"12345\",\n \"requestType\": \"00\",\n \"payerFspDetail\": {\n \"payerFspId\": \"lion\",\n \"financialAddress\": \"1223455\"\n },\n \"alias\": null,\n \"bill\": {\n \"billerName\": \"Test\",\n \"amount\": 100.0\n }\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{BillPayHostName}}/billTransferRequests", + "host": [ + "{{BillPayHostName}}" + ], + "path": [ + "billTransferRequests" + ] + } + }, + "response": [ + { + "name": "Payer RTP Response API 202", + "originalRequest": { + "method": "PUT", + "header": [ + { + "key": "X-Callback-URL", + "value": "{{X-CallbackURL}}", + "type": "text" + }, + { + "key": "X-Client-Correlation-ID", + "value": "{{clientCorrelationId}}", + "type": "text" + }, + { + "key": "X-Biller-Id", + "value": "GovBill", + "type": "text" + }, + { + "key": "X-Platform-TenantId", + "value": "{{TenantName}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"clientCorrelationId\": \"123445\",\n \"billId\": \"12345\",\n \"requestType\": \"00\",\n \"payerFspDetail\": {\n \"payerFspId\": \"lion\",\n \"financialAddress\": \"1223455\"\n },\n \"alias\": null,\n \"bill\": {\n \"billerName\": \"Test\",\n \"amount\": 100.0\n }\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{BillPayHostName}}/billTransferRequests", + "host": [ + "{{BillPayHostName}}" + ], + "path": [ + "billTransferRequests" + ] + } + }, + "status": "Accepted", + "code": 202, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "name": "Content-Type", + "description": "", + "type": "text" + } + ], + "cookie": [], + "body": "{\n \"responseCode\": \"00\",\n \"responseDescription\": \"Request successfully received by Pay-BB\",\n \"requestID\": \"12345678-6897-6798-6798-098765432134\"\n}" + } + ] + } + ] + }, + { + "name": "Bill Inquiry API", + "request": { + "method": "GET", + "header": [ + { + "key": "Platform-TenantId", + "value": "{{TenantName}}", + "type": "text" + }, + { + "key": "X-CorrelationID", + "value": "1234", + "type": "text" + }, + { + "key": "X-CallbackURL", + "value": "{{X-CallbackURL}}", + "type": "text" + }, + { + "key": "Payer-FSP-Id", + "value": "{{PayeeTenantName}}", + "type": "text" + } + ], + "url": { + "raw": "{{BillPayHostName}}/bills/{{billId}}", + "host": [ + "{{BillPayHostName}}" + ], + "path": [ + "bills", + "{{billId}}" + ] + } + }, + "response": [ + { + "name": "Callback request body", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "Platform-TenantId", + "value": "{{TenantName}}", + "type": "text" + }, + { + "key": "X-CorrelationID", + "value": "f56caf0b-377d-4a1f-8ac1-715859a83eee", + "type": "text" + }, + { + "key": "X-CallbackURL", + "value": "{{X-CallbackURL}}", + "type": "text" + }, + { + "key": "X-PayerFSP-Id", + "value": "{{PayeeTenantName}}", + "type": "text" + } + ], + "url": { + "raw": "{{BillPayHostName}}/bills/{{billId}}", + "host": [ + "{{BillPayHostName}}" + ], + "path": [ + "bills", + "{{billId}}" + ] + } + }, + "status": "Accepted", + "code": 202, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Date", + "value": "Mon, 18 Mar 2024 05:04:54 GMT" + }, + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Transfer-Encoding", + "value": "chunked" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Strict-Transport-Security", + "value": "max-age=15724800; includeSubDomains" + }, + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "Access-Control-Allow-Credentials", + "value": "true" + }, + { + "key": "Access-Control-Allow-Methods", + "value": "PUT, GET, POST, OPTIONS, DELETE" + }, + { + "key": "Access-Control-Allow-Headers", + "value": "DNT,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization" + }, + { + "key": "Access-Control-Max-Age", + "value": "1728000" + } + ], + "cookie": [], + "body": "{\n \"code\": \"00\",\n \"reason\": \"TRANSACTION SUCCESSFUL\",\n \"clientCorrelationId\": \"f56caf0b-377d-4a1f-8ac1-715859a83eee\",\n \"billId\": \"001\",\n \"billDetails\": {\n \"billerId\": \"001\",\n \"billerName\": \"Biller1\",\n \"billStatus\": \"PAID\",\n \"dueDate\": \"2021-07-01\",\n \"amountonDueDate\": \"1000\",\n \"amountAfterDueDate\": \"1100\"\n }\n}" + }, + { + "name": "Bill Inquiry API 202", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "Platform-TenantId", + "value": "{{TenantName}}", + "type": "text" + }, + { + "key": "X-CorrelationID", + "value": "f56caf0b-377d-4a1f-8ac1-715859a83eee", + "type": "text" + }, + { + "key": "X-CallbackURL", + "value": "{{X-CallbackURL}}", + "type": "text" + }, + { + "key": "X-PayerFSP-Id", + "value": "{{PayeeTenantName}}", + "type": "text" + } + ], + "url": { + "raw": "{{BillPayHostName}}/bills/{{billId}}", + "host": [ + "{{BillPayHostName}}" + ], + "path": [ + "bills", + "{{billId}}" + ] + } + }, + "status": "Accepted", + "code": 202, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Date", + "value": "Mon, 18 Mar 2024 08:47:54 GMT" + }, + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Transfer-Encoding", + "value": "chunked" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Strict-Transport-Security", + "value": "max-age=15724800; includeSubDomains" + }, + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "Access-Control-Allow-Credentials", + "value": "true" + }, + { + "key": "Access-Control-Allow-Methods", + "value": "PUT, GET, POST, OPTIONS, DELETE" + }, + { + "key": "Access-Control-Allow-Headers", + "value": "DNT,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization" + }, + { + "key": "Access-Control-Max-Age", + "value": "1728000" + } + ], + "cookie": [], + "body": "{\n \"transactionId\": \"33397af3-a696-460c-95c3-3b21773643f5\"\n}" + } + ] + }, + { + "name": "Bill Payments API", + "request": { + "method": "POST", + "header": [ + { + "key": "X-Platform-TenantId", + "value": "{{TenantName}}", + "type": "text" + }, + { + "key": "X-CorrelationID", + "value": "1234", + "type": "text" + }, + { + "key": "X-CallbackURL", + "value": "{{X-CallbackURL}}", + "type": "text" + }, + { + "key": "X-PayerFSP-Id", + "value": "{{PayeeTenantName}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"billInquiryRequestId\": \"12e2cedc-73\",\n \"billId\": \"001\",\n \"paymentReferenceID\": \"8f353842-451c-4\"\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{BillPayHostName}}/paymentNotifications", + "host": [ + "{{BillPayHostName}}" + ], + "path": [ + "paymentNotifications" + ] + } + }, + "response": [ + { + "name": "Callback request body", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "Platform-TenantId", + "value": "{{TenantName}}", + "type": "text" + }, + { + "key": "X-CorrelationID", + "value": "f56caf0b-377d-4a1f-8ac1-715859a83eee", + "type": "text" + }, + { + "key": "X-CallbackURL", + "value": "{{X-CallbackURL}}", + "type": "text" + }, + { + "key": "X-PayerFSP-Id", + "value": "{{PayeeTenantName}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"billInquiryRequestId\": \"12e2cedc-7372-4208-8079-7d46d691fca4\",\n \"billId\": \"001\",\n \"paymentReferenceID\": \"8f353842-451c-4231-afc9-58289afdc396\"\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{BillPayHostName}}/paymentNotifications", + "host": [ + "{{BillPayHostName}}" + ], + "path": [ + "paymentNotifications" + ] + } + }, + "status": "Accepted", + "code": 202, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Date", + "value": "Mon, 18 Mar 2024 05:04:39 GMT" + }, + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Transfer-Encoding", + "value": "chunked" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Strict-Transport-Security", + "value": "max-age=15724800; includeSubDomains" + }, + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "Access-Control-Allow-Credentials", + "value": "true" + }, + { + "key": "Access-Control-Allow-Methods", + "value": "PUT, GET, POST, OPTIONS, DELETE" + }, + { + "key": "Access-Control-Allow-Headers", + "value": "DNT,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization" + }, + { + "key": "Access-Control-Max-Age", + "value": "1728000" + } + ], + "cookie": [], + "body": "{\n \"code\": \"00\",\n \"reason\": \"TRANSACTION SUCCESSFUL\",\n \"requestID\": \"f56caf0b-377d-4a1f-8ac1-715859a83eee\",\n \"billId\": \"001\",\n \"status\": \"ACK\"\n}" + }, + { + "name": "Bill Payments API 202", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "Platform-TenantId", + "value": "{{TenantName}}", + "type": "text" + }, + { + "key": "X-CorrelationID", + "value": "f56caf0b-377d-4a1f-8ac1-715859a83eee", + "type": "text" + }, + { + "key": "X-CallbackURL", + "value": "{{X-CallbackURL}}", + "type": "text" + }, + { + "key": "X-PayerFSP-Id", + "value": "{{PayeeTenantName}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"billInquiryRequestId\": \"12e2cedc-7372-4208-8079-7d46d691fca4\",\n \"billId\": \"001\",\n \"paymentReferenceID\": \"8f353842-451c-4231-afc9-58289afdc396\"\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{BillPayHostName}}/paymentNotifications", + "host": [ + "{{BillPayHostName}}" + ], + "path": [ + "paymentNotifications" + ] + } + }, + "status": "Accepted", + "code": 202, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Date", + "value": "Mon, 18 Mar 2024 08:48:26 GMT" + }, + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Transfer-Encoding", + "value": "chunked" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Strict-Transport-Security", + "value": "max-age=15724800; includeSubDomains" + }, + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "Access-Control-Allow-Credentials", + "value": "true" + }, + { + "key": "Access-Control-Allow-Methods", + "value": "PUT, GET, POST, OPTIONS, DELETE" + }, + { + "key": "Access-Control-Allow-Headers", + "value": "DNT,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization" + }, + { + "key": "Access-Control-Max-Age", + "value": "1728000" + } + ], + "cookie": [], + "body": "{\n \"transactionId\": \"f183aea3-a75d-43e3-a7c1-830a10d72956\"\n}" + } + ] + }, + { + "name": "Biller RTP Request API", + "request": { + "method": "POST", + "header": [ + { + "key": "X-Callback-URL", + "value": "{{X-CallbackURL}}", + "type": "text" + }, + { + "key": "X-Client-Correlation-ID", + "value": "{{clientCorrelationId}}", + "type": "text" + }, + { + "key": "X-Biller-Id", + "value": "GovBill", + "type": "text" + }, + { + "key": "X-Platform-TenantId", + "value": "{{TenantName}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"clientCorrelationId\": \"123445\",\n \"billID\": \"12345\",\n \"requestType\": \"00\",\n \"payerFspDetails\": {\n \"payerFSPID\": \"lion\",\n \"financialAddress\": \"1223455\"\n },\n \"alias\": null,\n \"billDetails\": {\n \"billerName\": \"Test\",\n \"amount\": 100.0\n }\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{BillPayHostName}}/billTransferRequests", + "host": [ + "{{BillPayHostName}}" + ], + "path": [ + "billTransferRequests" + ] + } + }, + "response": [ + { + "name": "Callback request body", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Callback-URL", + "value": "{{X-CallbackURL}}", + "type": "text" + }, + { + "key": "X-Client-Correlation-ID", + "value": "{{clientCorrelationId}}", + "type": "text" + }, + { + "key": "X-Biller-Id", + "value": "GovBill", + "type": "text" + }, + { + "key": "X-Platform-TenantId", + "value": "{{TenantName}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"clientCorrelationId\": \"123445\",\n \"billId\": \"12345\",\n \"requestType\": \"00\",\n \"payerFspDetail\": {\n \"payerFspId\": \"lion\",\n \"financialAddress\": \"1223455\"\n },\n \"alias\": null,\n \"bill\": {\n \"billerName\": \"Test\",\n \"amount\": 100.0\n }\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{BillPayHostName}}/billTransferRequests", + "host": [ + "{{BillPayHostName}}" + ], + "path": [ + "billTransferRequests" + ] + } + }, + "status": "Accepted", + "code": 202, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Date", + "value": "Mon, 18 Mar 2024 05:04:01 GMT" + }, + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Transfer-Encoding", + "value": "chunked" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Strict-Transport-Security", + "value": "max-age=15724800; includeSubDomains" + }, + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "Access-Control-Allow-Credentials", + "value": "true" + }, + { + "key": "Access-Control-Allow-Methods", + "value": "PUT, GET, POST, OPTIONS, DELETE" + }, + { + "key": "Access-Control-Allow-Headers", + "value": "DNT,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization" + }, + { + "key": "Access-Control-Max-Age", + "value": "1728000" + } + ], + "cookie": [], + "body": "{\n \"requestId\": \"12345678-6897-6798-6798-098765432134\",\n \"rtpId\": \"123456\",\n \"billId\": \"12345\",\n \"rtpStatus\": \"00\",\n \"rejectReason\": null\n}" + }, + { + "name": "Biller RTP Request API", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "X-Callback-URL", + "value": "{{X-CallbackURL}}", + "type": "text" + }, + { + "key": "X-Client-Correlation-ID", + "value": "{{clientCorrelationId}}", + "type": "text" + }, + { + "key": "X-Biller-Id", + "value": "GovBill", + "type": "text" + }, + { + "key": "X-Platform-TenantId", + "value": "{{TenantName}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"clientCorrelationId\": \"123445\",\n \"billId\": \"12345\",\n \"requestType\": \"00\",\n \"payerFspDetail\": {\n \"payerFspId\": \"lion\",\n \"financialAddress\": \"1223455\"\n },\n \"alias\": null,\n \"bill\": {\n \"billerName\": \"Test\",\n \"amount\": 100.0\n }\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{BillPayHostName}}/billTransferRequests", + "host": [ + "{{BillPayHostName}}" + ], + "path": [ + "billTransferRequests" + ] + } + }, + "status": "Accepted", + "code": 202, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Date", + "value": "Mon, 18 Mar 2024 08:48:51 GMT" + }, + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Transfer-Encoding", + "value": "chunked" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Strict-Transport-Security", + "value": "max-age=15724800; includeSubDomains" + }, + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "Access-Control-Allow-Credentials", + "value": "true" + }, + { + "key": "Access-Control-Allow-Methods", + "value": "PUT, GET, POST, OPTIONS, DELETE" + }, + { + "key": "Access-Control-Allow-Headers", + "value": "DNT,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization" + }, + { + "key": "Access-Control-Max-Age", + "value": "1728000" + } + ], + "cookie": [], + "body": "{\n \"responseCode\": \"00\",\n \"responseDescription\": \"Request successfully received by Pay-BB\",\n \"requestID\": \"12345678-6897-6798-6798-098765432134\"\n}" + } + ] + } + ] + } + ], + "variable": [ + { + "key": "TenantName", + "value": "ibank-india" + } + ] +} \ No newline at end of file diff --git a/ph-ee-env-template/PostmanCollections/SLCB_postman_collection.json b/ph-ee-env-template/PostmanCollections/SLCB_postman_collection.json new file mode 100644 index 000000000..dd3f2cc3a --- /dev/null +++ b/ph-ee-env-template/PostmanCollections/SLCB_postman_collection.json @@ -0,0 +1,577 @@ +{ + "info": { + "_postman_id": "1eb87610-6a4e-4a61-a7a8-2ecfb4b2ece1", + "name": "SLCB", + "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json", + "_exporter_id": "17902615" + }, + "item": [ + { + "name": "Auth", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "var jsonData = JSON.parse(responseBody);", + "postman.setEnvironmentVariable(\"access_token\", jsonData.token);" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"username\": \"DSTI01\",\n \"password\": \"y,T$XG4\",\n \"expiresIn\": 0\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{auth-url}}", + "host": [ + "{{auth-url}}" + ] + } + }, + "response": [ + { + "name": "Sucessful Auth", + "originalRequest": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{ \"Username\":\"DSTI01\", \"Password\":\"Cuu)!!7\" }", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "https://g2p-test.slcb.com:8443/api/auth", + "protocol": "https", + "host": [ + "g2p-test", + "slcb", + "com" + ], + "port": "8443", + "path": [ + "api", + "auth" + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Transfer-Encoding", + "value": "chunked" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "key": "Server", + "value": "Microsoft-IIS/10.0" + }, + { + "key": "X-Powered-By", + "value": "ASP.NET" + }, + { + "key": "Date", + "value": "Fri, 20 May 2022 11:10:39 GMT" + } + ], + "cookie": [], + "body": "{\n \"username\": \"DSTI01\",\n \"token\": \"eyJhbGciOiJSUzI1NiIsImtpZCI6IjdBQjQ5NjgxMDdBMzAyQjcxQzc3QTU1MDdENEM5NjQ5IiwidHlwIjoiYXQrand0In0.eyJuYmYiOjE2NTMwNDUwMzksImV4cCI6MTY1NjY0NTAzOSwiaXNzIjoiaHR0cHM6Ly9nMnAtdGVzdC5zbGNiLmNvbTo4NDQzIiwiYXVkIjoiZVRyYXgiLCJjbGllbnRfaWQiOiJlVHJheF9BcHAiLCJzdWIiOiI5NjVlNzA4ZC1hN2I2LTQ5Y2YtOGEzOC1jMGM4MzExMDhhNmMiLCJhdXRoX3RpbWUiOjE2NTMwNDUwMzksImlkcCI6ImxvY2FsIiwicGhvbmVfbnVtYmVyX3ZlcmlmaWVkIjoiRmFsc2UiLCJlbWFpbCI6ImF2aWtAZnluYXJmaW4uaW8iLCJlbWFpbF92ZXJpZmllZCI6IkZhbHNlIiwibmFtZSI6IkRTVEkwMSIsImlhdCI6MTY1MzA0NTAzOSwic2NvcGUiOlsiZVRyYXgiXSwiYW1yIjpbInB3ZCJdfQ.HVihulps0nJgS1Gsg4O_7m2FoFI3nFpnQR9MtFcZmokkZ_5qWR5FtFtGsMb1Hn68Qaj3HHTaXUVVHfNQSDNIFrmlwW_EN1UreojM7imB2CWTNWiM2TZDnmItPBaMvB2pH1fraLANqm9KuryzeNbNbGhFi19eCB1e2cLWPUlufnjHsWMbAB2hweahbVNsIVCNvZLInKSP339X45RxsTp7SHNvw56VbDyTDL-MrCjZTUN0fxJS38r91wO-IkcwzfmpAS-OJJXSusByilnLphRQvIJq4ianX8p15IxWSIF5RpBigJklZzC3N5pp6SkyYy_0VXYOayzqSkDK5mXg0d9vvQ\",\n \"expiresIn\": 3600000\n}" + } + ] + }, + { + "name": "Transaction Request", + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "{{access_token}}", + "type": "string" + } + ] + }, + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"ID\": null,\n \"AccountType\": 0,\n \"AuthorizationCode\": \"yoWYLKjSPl4C746p+pzEFl9hQ6ZZpq2JcvNItmC9ZowWRTB1V4Cx+bk0YkTLBSHc\",\n \"BatchID\": \"987\",\n \"InstitutionCode\": \"SLCB\",\n \"Purpose\": \"Test Payment\",\n \"RequestDate\": \"2022-10-03T06:03:30.45+05:30\",\n \"SourceAccount\": \"003001003879112168\",\n \"Status\": null,\n \"TotalAmountPaid\": 0.0,\n \"TotalAmountToBePaid\": 500.00,\n \"Payees\": [\n {\n \"ID\": null,\n \"Account\": \"003001003873110196\",\n \"AccountType\": 0,\n \"Amount\": 250.00,\n \"ExternalTransactionId\": 0,\n \"FirstName\": \"Test\",\n \"LastName\": \"Account 4\",\n \"Purpose\": \"Test Payee Payment\",\n \"Status\": {\n \"Code\": 0,\n \"Description\": null\n },\n \"StatusMessage\": null,\n \"TransactionId\": null\n },\n {\n \"ID\": null,\n \"Account\": \"003001003874120160\",\n \"AccountType\": 0,\n \"Amount\": 250.00,\n \"ExternalTransactionId\": 1,\n \"FirstName\": \"Test\",\n \"LastName\": \"Account\",\n \"Purpose\": \"Test Payee Payment 2\",\n \"Status\": {\n \"Code\": 0,\n \"Description\": null\n },\n \"StatusMessage\": null,\n \"TransactionId\": null\n }\n ]\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{txnrequest-url}}", + "host": [ + "{{txnrequest-url}}" + ] + } + }, + "response": [ + { + "name": "Transaction Request Success", + "originalRequest": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"ID\": null,\n \"AccountType\": 0,\n \"AuthorizationCode\": \"y7mDYZ34xLUzuIifRa7B/2CRoETLOoSb+QIQlVHPqwQGGLYL9hWY61oS1hooXMz4TuhG8HtrHxEevOr9Dio+kSfoJZFxroYNmm5Icww3rIfonMPIH5ovYYXdOAP8wy/ISN7HLor0pV/rhmCPMmpMROByid4+EFK85rXH6pXr5tzF6RyRYAcu1wCiASGMTiIZedpV11VJp1vH3whmBHWhfE5fo2NP7FiJ8Uv3Aw3sCcCj7hQ1OKkq9lMLV1F8YrjoKbMbdBEnTPWxwdTrGN8MWTS/j0ofiE3Thyog/fmAwfsDNN2MNEz/GvVGABZALkQ9tc/4UACx4iQBu0JqfKVT9wYKd3LojvEFXDaeLXORyRH/gdxhG+UQq+2JtUjNNOP6fs/VrBwizMRkuG3qg/wDhoOeVnq1mtIcTUCPEO54t2caMGvHnvMcPK1kBlYryliIbcfRTsoserCsg5clZWfs0IBB6evmWDSN+PXJ9+VDvBheecaXLHeTgv7vZPjVp00oGJDGA63pH1XONWRBSZKo5FnidTzQs6/53QthEFfJSmPY45NV/e7OLjp2FVoV7Lutuc+aT4m5AsuYISsNX+Zlqm8K/KcnODokrP/gCjNWnAOvlRiUKfMw1tp2PxtFqDDUC1Sr25w8E0qhMd/HwfuRc7NHZYy+ez4tpFVRj2EvqRGA76G+tl/hMMCpsr0dZavEjBSOInGcDxhDdzT+QMLYtjgOEzLTn+6AFxwMC0FU+7Srxg3f8ljkYH5US2Pn0+oZ05OmDSgefsYRhjcKmU96owCPSNXdEfTT6PYz9JMBBPhoCGTAzlnK3lU4GawtT7fLI5QD+wS3OYYKOrjubRQ4tFx4Qlb3amqri/FckS9GMfnk1wUwhjdPhxC+7W6UvfHrXrfe4QmC8fWzOENUWXA4JlRxezylEG7wUHB7+d9c90cgqAzOEEHL1FGEB+uPqfljI6NjE2VFFahskD3mFEEuUprsmNyvAzTBN2LLt11nwjPku3IMoHj9NZcMTexlr9HyJUjC5xEPui3rQ5FUdLM5mcOm9NQQBGSkGgwHGVInoXdWUH/oVwhWBPwB+dnR9gMrP29rkJ1JlOsNDDmHdxRJQRlSQe937CiSzL4T5d/uZvFxqbTl/GFFxv65TCGsxGVNM64Nyp0xZtGh/jafhcwvSRq/xDuWss0Uin3c5nSkoOb8IwS01uNO4J1/j2vFXDCBHRRYSmh8HtFuOvaRVQcX6bSxd6d3Indsy//T+IsFZmk/wMOPM3fnLUeFhDx57LpP72/qonB0XZspNUN4tif2vORWUEU3DpP8bzw5saaSk2RqBDNeosMaqAAPo9lwrYeyfPIJ69F2iqiaP0XUNpzaQqSGhP50fL92DfXiHpJxRfBhXdH5Eu8OjqdqwewZEZHkqi20vQm02yGfXJZ8peQPmLIJQg84v8TVbEqM9KWHJrSjaIjTFxxAaIqDVkjElSSz8uDMr40HbDUlKnwNJUoMIwTKfypr60em3k1lDoOs4bFbG2Zl+NXt5WmyhBJNPHKuAyUdaQBEx7eDR7fptLjo8oo9W29EIlridVSPO1scH5Q9xECjs4GwfcfWp2Optk/g\",\n \"BatchID\": \"1\",\n \"InstitutionCode\": \"SLCB\",\n \"Purpose\": \"Test Payment\",\n \"RequestDate\": \"2022-05-30T07:20:09.9260323-04:00\",\n \"SourceAccount\": \"003001003878112195\",\n \"Status\": null,\n \"TotalAmountPaid\": 0.0,\n \"TotalAmountToBePaid\": 350000.00,\n \"Payees\": [\n {\n \"ID\": null,\n \"Account\": \"003001003873110196\",\n \"AccountType\": 0,\n \"Amount\": 100000.00,\n \"ExternalTransactionId\": 0,\n \"FirstName\": \"Test\",\n \"LastName\": \"Account 4\",\n \"Purpose\": \"Test Payee Payment\",\n \"Status\": {\n \"Code\": 0,\n \"Description\": null\n },\n \"StatusMessage\": null,\n \"TransactionId\": null\n },\n {\n \"ID\": null,\n \"Account\": \"003001003874120160\",\n \"AccountType\": 0,\n \"Amount\": 250000.00,\n \"ExternalTransactionId\": 0,\n \"FirstName\": \"Test\",\n \"LastName\": \"Account\",\n \"Purpose\": \"Test Payee Payment 2\",\n \"Status\": {\n \"Code\": 0,\n \"Description\": null\n },\n \"StatusMessage\": null,\n \"TransactionId\": null\n }\n \n ]\n}\n", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{txnrequest-url}}", + "host": [ + "{{txnrequest-url}}" + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Transfer-Encoding", + "value": "chunked" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "key": "Server", + "value": "Microsoft-IIS/10.0" + }, + { + "key": "X-Powered-By", + "value": "ASP.NET" + }, + { + "key": "Date", + "value": "Tue, 24 May 2022 15:03:35 GMT" + } + ], + "cookie": [], + "body": "{\n \"id\": null,\n \"accountType\": 0,\n \"authorizationCode\": \"y7mDYZ34xLUzuIifRa7B/2CRoETLOoSb+QIQlVHPqwQGGLYL9hWY61oS1hooXMz4TuhG8HtrHxEevOr9Dio+kSfoJZFxroYNmm5Icww3rIfonMPIH5ovYYXdOAP8wy/ISN7HLor0pV/rhmCPMmpMROByid4+EFK85rXH6pXr5tzF6RyRYAcu1wCiASGMTiIZedpV11VJp1vH3whmBHWhfE5fo2NP7FiJ8Uv3Aw3sCcCj7hQ1OKkq9lMLV1F8YrjoKbMbdBEnTPWxwdTrGN8MWTS/j0ofiE3Thyog/fmAwfsDNN2MNEz/GvVGABZALkQ9tc/4UACx4iQBu0JqfKVT9wYKd3LojvEFXDaeLXORyRH/gdxhG+UQq+2JtUjNNOP6fs/VrBwizMRkuG3qg/wDhoOeVnq1mtIcTUCPEO54t2caMGvHnvMcPK1kBlYryliIbcfRTsoserCsg5clZWfs0IBB6evmWDSN+PXJ9+VDvBheecaXLHeTgv7vZPjVp00oGJDGA63pH1XONWRBSZKo5FnidTzQs6/53QthEFfJSmPY45NV/e7OLjp2FVoV7Lutuc+aT4m5AsuYISsNX+Zlqm8K/KcnODokrP/gCjNWnAOvlRiUKfMw1tp2PxtFqDDUC1Sr25w8E0qhMd/HwfuRc7NHZYy+ez4tpFVRj2EvqRGA76G+tl/hMMCpsr0dZavEjBSOInGcDxhDdzT+QMLYtjgOEzLTn+6AFxwMC0FU+7Srxg3f8ljkYH5US2Pn0+oZ05OmDSgefsYRhjcKmU96owCPSNXdEfTT6PYz9JMBBPhoCGTAzlnK3lU4GawtT7fLI5QD+wS3OYYKOrjubRQ4tFx4Qlb3amqri/FckS9GMfnk1wUwhjdPhxC+7W6UvfHrXrfe4QmC8fWzOENUWXA4JlRxezylEG7wUHB7+d9c90cgqAzOEEHL1FGEB+uPqfljI6NjE2VFFahskD3mFEEuUprsmNyvAzTBN2LLt11nwjPku3IMoHj9NZcMTexlr9HyJUjC5xEPui3rQ5FUdLM5mcOm9NQQBGSkGgwHGVInoXdWUH/oVwhWBPwB+dnR9gMrP29rkJ1JlOsNDDmHdxRJQRlSQe937CiSzL4T5d/uZvFxqbTl/GFFxv65TCGsxGVNM64Nyp0xZtGh/jafhcwvSRq/xDuWss0Uin3c5nSkoOb8IwS01uNO4J1/j2vFXDCBHRRYSmh8HtFuOvaRVQcX6bSxd6d3Indsy//T+IsFZmk/wMOPM3fnLUeFhDx57LpP72/qonB0XZspNUN4tif2vORWUEU3DpP8bzw5saaSk2RqBDNeosMaqAAPo9lwrYeyfPIJ69F2iqiaP0XUNpzaQqSGhP50fL92DfXiHpJxRfBhXdH5Eu8OjqdqwewZEZHkqi20vQm02yGfXJZ8peQPmLIJQg84v8TVbEqM9KWHJrSjaIjTFxxAaIqDVkjElSSz8uDMr40HbDUlKnwNJUoMIwTKfypr60em3k1lDoOs4bFbG2Zl+NXt5WmyhBJNPHKuAyUdaQBEx7eDR7fptLjo8oo9W29EIlridVSPO1scH5Q9xECjs4GwfcfWp2Optk/g\",\n \"batchID\": \"1\",\n \"institutionCode\": \"SLCB\",\n \"purpose\": \"Test Payment\",\n \"requestDate\": \"2022-05-30T11:20:09.9260323+00:00\",\n \"sourceAccount\": \"003001003878112195\",\n \"status\": {\n \"code\": 0,\n \"description\": \"The operation completed successfully\"\n },\n \"totalAmountPaid\": 350000,\n \"totalAmountToBePaid\": 350000,\n \"payees\": [\n {\n \"id\": \"50\",\n \"account\": \"003001003873110196\",\n \"accountType\": 0,\n \"amount\": 100000,\n \"externalTransactionId\": 0,\n \"firstName\": \"Test\",\n \"lastName\": \"Account 4\",\n \"purpose\": \"Test Payee Payment\",\n \"status\": {\n \"code\": 0,\n \"description\": \"The operation completed successfully\"\n },\n \"statusMessage\": \"The operation completed successfully\",\n \"transactionId\": \"1847142054\"\n },\n {\n \"id\": \"52\",\n \"account\": \"003001003874120160\",\n \"accountType\": 0,\n \"amount\": 250000,\n \"externalTransactionId\": 0,\n \"firstName\": \"Test\",\n \"lastName\": \"Account\",\n \"purpose\": \"Test Payee Payment 2\",\n \"status\": {\n \"code\": 0,\n \"description\": \"The operation completed successfully\"\n },\n \"statusMessage\": \"The operation completed successfully\",\n \"transactionId\": \"2468598674\"\n }\n ]\n}" + }, + { + "name": "Transaction Request strange 003001003879112168", + "originalRequest": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"ID\": null,\n \"AccountType\": 0,\n \"AuthorizationCode\": \"NoXFMivy98TASCZOhVUidG75uCM3N+/l3+7FkxH8BZjZYysROYSdRMgQ0vATHP5rK8c8w0BRw9mbBS3cX1X7wYz5teSzZ75P5IS+kWsrAO+ZGKIhi60SL5eICFfees47bVCHwxm5jDiLn1eN/PgM6GTpGK0OwtxxLDkm79wcjyTHZHaxHpezmmuJWbziWTo84zFHuHxREtX/6mI6sRh1qOrC9P0az0IrgeNNrG7CLgBKjgTI5bIAqfU2Eer4hE7hCBVfFFEIF+JxGcVneNujubB2gcVhLNLVQK+AqfJWaVrOZydIlYa6G70a745J1DiAnmNOIdGHdN6Ad8WWFUwJ2g==\",\n \"BatchID\": \"1\",\n \"InstitutionCode\": \"SLCB\",\n \"Purpose\": \"Test Payment\",\n \"RequestDate\": \"2022-07-26T07:20:09.9260323-04:00\",\n \"SourceAccount\": \"003001003879112168\",\n \"Status\": null,\n \"TotalAmountPaid\": 0.0,\n \"TotalAmountToBePaid\": 350000.00,\n \"Payees\": [\n {\n \"ID\": null,\n \"Account\": \"003001003873110196\",\n \"AccountType\": 0,\n \"Amount\": 100000.00,\n \"ExternalTransactionId\": 0,\n \"FirstName\": \"Test\",\n \"LastName\": \"Account 4\",\n \"Purpose\": \"Test Payee Payment\",\n \"Status\": {\n \"Code\": 0,\n \"Description\": null\n },\n \"StatusMessage\": null,\n \"TransactionId\": null\n },\n {\n \"ID\": null,\n \"Account\": \"003001003874120160\",\n \"AccountType\": 0,\n \"Amount\": 250000.00,\n \"ExternalTransactionId\": 0,\n \"FirstName\": \"Test\",\n \"LastName\": \"Account\",\n \"Purpose\": \"Test Payee Payment 2\",\n \"Status\": {\n \"Code\": 0,\n \"Description\": null\n },\n \"StatusMessage\": null,\n \"TransactionId\": null\n }\n ]\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{txnrequest-url}}", + "host": [ + "{{txnrequest-url}}" + ] + } + }, + "status": "Bad Request", + "code": 400, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Cache-Control", + "value": "no-cache" + }, + { + "key": "Pragma", + "value": "no-cache" + }, + { + "key": "Transfer-Encoding", + "value": "chunked" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "key": "Expires", + "value": "-1" + }, + { + "key": "Server", + "value": "Microsoft-IIS/10.0" + }, + { + "key": "X-Powered-By", + "value": "ASP.NET" + }, + { + "key": "Date", + "value": "Fri, 29 Jul 2022 10:42:01 GMT" + } + ], + "cookie": [], + "body": "{\"Message\":\"Error Code:-23 - Description: Insufficient funds\",\"StatusCode\":\"400\"}{\"Message\":\"Insufficient funds\",\"StatusCode\":\"-23\"}" + }, + { + "name": "Transaction Request Internal error", + "originalRequest": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"ID\": null,\n \"AccountType\": 0,\n \"AuthorizationCode\": \"yoWYLKjSPl4C746p+pzEFl9hQ6ZZpq2JcvNItmC9ZowWRTB1V4Cx+bk0YkTLBSHc\",\n \"BatchID\": \"1\",\n \"InstitutionCode\": \"SLCB\",\n \"Purpose\": \"Test Payment\",\n \"RequestDate\": \"2022-08-08T05:56:48+05:30\",\n \"SourceAccount\": \"003001003873110196\",\n \"Status\": null,\n \"TotalAmountPaid\": 0.0,\n \"TotalAmountToBePaid\": 500.00,\n \"Payees\": [\n {\n \"ID\": null,\n \"Account\": \"003001003873110196\",\n \"AccountType\": 0,\n \"Amount\": 250.00,\n \"ExternalTransactionId\": 0,\n \"FirstName\": \"Test\",\n \"LastName\": \"Account 4\",\n \"Purpose\": \"Test Payee Payment\",\n \"Status\": {\n \"Code\": 0,\n \"Description\": null\n },\n \"StatusMessage\": null,\n \"TransactionId\": null\n },\n {\n \"ID\": null,\n \"Account\": \"003001003874120160\",\n \"AccountType\": 0,\n \"Amount\": 250.00,\n \"ExternalTransactionId\": 1,\n \"FirstName\": \"Test\",\n \"LastName\": \"Account\",\n \"Purpose\": \"Test Payee Payment 2\",\n \"Status\": {\n \"Code\": 0,\n \"Description\": null\n },\n \"StatusMessage\": null,\n \"TransactionId\": null\n }\n ]\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{txnrequest-url}}", + "host": [ + "{{txnrequest-url}}" + ] + } + }, + "status": "Internal Server Error", + "code": 500, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Transfer-Encoding", + "value": "chunked" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "key": "Server", + "value": "Microsoft-IIS/10.0" + }, + { + "key": "_AbpErrorFormat", + "value": "true" + }, + { + "key": "X-Powered-By", + "value": "ASP.NET" + }, + { + "key": "Date", + "value": "Thu, 01 Sep 2022 11:03:52 GMT" + } + ], + "cookie": [], + "body": "{\n \"error\": {\n \"code\": null,\n \"message\": \"An internal error occurred during your request!\",\n \"details\": null,\n \"data\": {},\n \"validationErrors\": null\n }\n}" + }, + { + "name": "Transaction Request -999", + "originalRequest": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"ID\": null,\n \"AccountType\": 0,\n \"AuthorizationCode\": \"yoWYLKjSPl4C746p+pzEFl9hQ6ZZpq2JcvNItmC9ZowWRTB1V4Cx+bk0YkTLBSHc\",\n \"BatchID\": \"1\",\n \"InstitutionCode\": \"SLCB\",\n \"Purpose\": \"Test Payment\",\n \"RequestDate\": \"2022-08-08T05:56:48+05:30\",\n \"SourceAccount\": \"003001003873110196\",\n \"Status\": null,\n \"TotalAmountPaid\": 0.0,\n \"TotalAmountToBePaid\": 500.00,\n \"Payees\": [\n {\n \"ID\": null,\n \"Account\": \"003001003873110196\",\n \"AccountType\": 0,\n \"Amount\": 250.00,\n \"ExternalTransactionId\": 0,\n \"FirstName\": \"Test\",\n \"LastName\": \"Account 4\",\n \"Purpose\": \"Test Payee Payment\",\n \"Status\": {\n \"Code\": 0,\n \"Description\": null\n },\n \"StatusMessage\": null,\n \"TransactionId\": null\n },\n {\n \"ID\": null,\n \"Account\": \"003001003874120160\",\n \"AccountType\": 0,\n \"Amount\": 250.00,\n \"ExternalTransactionId\": 1,\n \"FirstName\": \"Test\",\n \"LastName\": \"Account\",\n \"Purpose\": \"Test Payee Payment 2\",\n \"Status\": {\n \"Code\": 0,\n \"Description\": null\n },\n \"StatusMessage\": null,\n \"TransactionId\": null\n }\n ]\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{txnrequest-url}}", + "host": [ + "{{txnrequest-url}}" + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Transfer-Encoding", + "value": "chunked" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "key": "Server", + "value": "Microsoft-IIS/10.0" + }, + { + "key": "X-Powered-By", + "value": "ASP.NET" + }, + { + "key": "Date", + "value": "Fri, 02 Sep 2022 11:14:06 GMT" + } + ], + "cookie": [], + "body": "{\n \"id\": null,\n \"accountType\": 0,\n \"authorizationCode\": \"yoWYLKjSPl4C746p+pzEFl9hQ6ZZpq2JcvNItmC9ZowWRTB1V4Cx+bk0YkTLBSHc\",\n \"batchID\": \"1\",\n \"institutionCode\": \"SLCB\",\n \"purpose\": \"Test Payment\",\n \"requestDate\": \"2022-08-08T00:26:48+00:00\",\n \"sourceAccount\": \"003001003873110196\",\n \"status\": {\n \"code\": -999,\n \"description\": \"There was an error while processing the request. Processing aborted.\"\n },\n \"totalAmountPaid\": 0,\n \"totalAmountToBePaid\": 500,\n \"payees\": [\n {\n \"id\": null,\n \"account\": \"003001003873110196\",\n \"accountType\": 0,\n \"amount\": 250,\n \"externalTransactionId\": 0,\n \"firstName\": \"Test\",\n \"lastName\": \"Account 4\",\n \"purpose\": \"Test Payee Payment\",\n \"status\": {\n \"code\": 0,\n \"description\": null\n },\n \"statusMessage\": null,\n \"transactionId\": null\n },\n {\n \"id\": null,\n \"account\": \"003001003874120160\",\n \"accountType\": 0,\n \"amount\": 250,\n \"externalTransactionId\": 1,\n \"firstName\": \"Test\",\n \"lastName\": \"Account\",\n \"purpose\": \"Test Payee Payment 2\",\n \"status\": {\n \"code\": 0,\n \"description\": null\n },\n \"statusMessage\": null,\n \"transactionId\": null\n }\n ]\n}" + } + ] + }, + { + "name": "Reconcoliation", + "protocolProfileBehavior": { + "disableBodyPruning": true + }, + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "{{access_token}}", + "type": "string" + } + ] + }, + "method": "GET", + "header": [], + "body": { + "mode": "urlencoded", + "urlencoded": [ + { + "key": "from", + "value": "2022-09-21T05:56:47+05:30", + "description": "2022-09-21T15:03:47.9773109", + "type": "text" + }, + { + "key": "to", + "value": "2022-09-22T05:56:48+05:30", + "description": "2022-09-21T15:03:47.9793763", + "type": "text" + }, + { + "key": "authorizationCode", + "value": "yoWYLKjSPl4C746p+pzEFl9hQ6ZZpq2JcvNItmC9ZowWRTB1V4Cx+bk0YkTLBSHc", + "type": "text" + }, + { + "key": "bban", + "value": "003001003879112168", + "type": "text" + }, + { + "key": "pageNumber", + "value": "1", + "type": "text" + }, + { + "key": "pageSize", + "value": "20", + "type": "text" + } + ] + }, + "url": { + "raw": "{{recon-url}}", + "host": [ + "{{recon-url}}" + ] + } + }, + "response": [ + { + "name": "Reconconciliation Success", + "originalRequest": { + "method": "GET", + "header": [], + "body": { + "mode": "urlencoded", + "urlencoded": [ + { + "key": "from", + "value": "2022-07-26T11:20:09.9260323+00:00", + "type": "text" + }, + { + "key": "to", + "value": "2022-07-27T11:20:09.9260323+00:00", + "type": "text" + }, + { + "key": "AuthorizationCode", + "value": "NoXFMivy98TASCZOhVUidG75uCM3N+/l3+7FkxH8BZjZYysROYSdRMgQ0vATHP5rK8c8w0BRw9mbBS3cX1X7wYz5teSzZ75P5IS+kWsrAO+ZGKIhi60SL5eICFfees47bVCHwxm5jDiLn1eN/PgM6GTpGK0OwtxxLDkm79wcjyTHZHaxHpezmmuJWbziWTo84zFHuHxREtX/6mI6sRh1qOrC9P0az0IrgeNNrG7CLgBKjgTI5bIAqfU2Eer4hE7hCBVfFFEIF+JxGcVneNujubB2gcVhLNLVQK+AqfJWaVrOZydIlYa6G70a745J1DiAnmNOIdGHdN6Ad8WWFUwJ2g==", + "type": "text" + }, + { + "key": "bban", + "value": "003001003879112168", + "type": "text" + } + ] + }, + "url": { + "raw": "{{recon-url}}", + "host": [ + "{{recon-url}}" + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Transfer-Encoding", + "value": "chunked" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "key": "Server", + "value": "Microsoft-IIS/10.0" + }, + { + "key": "X-Powered-By", + "value": "ASP.NET" + }, + { + "key": "Date", + "value": "Sun, 07 Aug 2022 16:59:09 GMT" + } + ], + "cookie": [], + "body": "{\n \"from\": \"2022-07-26T11:20:09.9260323Z\",\n \"to\": \"2022-07-27T11:20:09.9260323Z\",\n \"pageSize\": 200,\n \"pageCount\": 1,\n \"pageNumber\": 0,\n \"totalCount\": 12,\n \"bban\": \"003001003879112168\",\n \"transactions\": [\n {\n \"id\": 220,\n \"batchId\": \"1\",\n \"transactionDate\": \"2022-08-05T20:21:37.7514429\",\n \"credit\": 1000,\n \"debit\": 0,\n \"eTraxReferenceNumber\": 0,\n \"externalReferenceNumber\": 0,\n \"cbsDocumentNumber\": null,\n \"crossReferenceNumber\": 0,\n \"postedBy\": \"7a9e783c-0756-4754-9753-fb3c10c4bff9\",\n \"postedFrom\": \"102.176.189.6\",\n \"accountNumber\": \"003001003879112168\",\n \"ipAddress\": \"102.176.189.6\",\n \"notes\": \"eTrax: Transaction Request\",\n \"userId\": \"7a9e783c-0756-4754-9753-fb3c10c4bff9\",\n \"username\": \"falcoln\"\n },\n {\n \"id\": 218,\n \"batchId\": \"1\",\n \"transactionDate\": \"2022-08-05T20:05:05.3600922\",\n \"credit\": 1000,\n \"debit\": 0,\n \"eTraxReferenceNumber\": 0,\n \"externalReferenceNumber\": 0,\n \"cbsDocumentNumber\": null,\n \"crossReferenceNumber\": 0,\n \"postedBy\": \"7a9e783c-0756-4754-9753-fb3c10c4bff9\",\n \"postedFrom\": \"102.176.189.6\",\n \"accountNumber\": \"003001003879112168\",\n \"ipAddress\": \"102.176.189.6\",\n \"notes\": \"eTrax: Transaction Request\",\n \"userId\": \"7a9e783c-0756-4754-9753-fb3c10c4bff9\",\n \"username\": \"falcoln\"\n },\n {\n \"id\": 214,\n \"batchId\": \"1\",\n \"transactionDate\": \"2022-08-05T16:52:25.0407673\",\n \"credit\": 0,\n \"debit\": 250,\n \"eTraxReferenceNumber\": 0,\n \"externalReferenceNumber\": 0,\n \"cbsDocumentNumber\": null,\n \"crossReferenceNumber\": 0,\n \"postedBy\": \"965e708d-a7b6-49cf-8a38-c0c831108a6c\",\n \"postedFrom\": \"103.121.204.133\",\n \"accountNumber\": \"003001003879112168\",\n \"ipAddress\": \"103.121.204.133\",\n \"notes\": \"eTrax: Transaction Request\",\n \"userId\": \"965e708d-a7b6-49cf-8a38-c0c831108a6c\",\n \"username\": \"DSTI01\"\n },\n {\n \"id\": 212,\n \"batchId\": \"1\",\n \"transactionDate\": \"2022-08-05T16:52:24.7821909\",\n \"credit\": 0,\n \"debit\": 250,\n \"eTraxReferenceNumber\": 0,\n \"externalReferenceNumber\": 0,\n \"cbsDocumentNumber\": null,\n \"crossReferenceNumber\": 0,\n \"postedBy\": \"965e708d-a7b6-49cf-8a38-c0c831108a6c\",\n \"postedFrom\": \"103.121.204.133\",\n \"accountNumber\": \"003001003879112168\",\n \"ipAddress\": \"103.121.204.133\",\n \"notes\": \"eTrax: Transaction Request\",\n \"userId\": \"965e708d-a7b6-49cf-8a38-c0c831108a6c\",\n \"username\": \"DSTI01\"\n },\n {\n \"id\": 210,\n \"batchId\": \"1\",\n \"transactionDate\": \"2022-08-01T13:40:33.9013463\",\n \"credit\": 0,\n \"debit\": 250,\n \"eTraxReferenceNumber\": 0,\n \"externalReferenceNumber\": 0,\n \"cbsDocumentNumber\": null,\n \"crossReferenceNumber\": 0,\n \"postedBy\": \"965e708d-a7b6-49cf-8a38-c0c831108a6c\",\n \"postedFrom\": \"103.121.204.133\",\n \"accountNumber\": \"003001003879112168\",\n \"ipAddress\": \"103.121.204.133\",\n \"notes\": \"eTrax: Transaction Request\",\n \"userId\": \"965e708d-a7b6-49cf-8a38-c0c831108a6c\",\n \"username\": \"DSTI01\"\n },\n {\n \"id\": 208,\n \"batchId\": \"1\",\n \"transactionDate\": \"2022-08-01T13:40:33.8874229\",\n \"credit\": 0,\n \"debit\": 250,\n \"eTraxReferenceNumber\": 0,\n \"externalReferenceNumber\": 0,\n \"cbsDocumentNumber\": null,\n \"crossReferenceNumber\": 0,\n \"postedBy\": \"965e708d-a7b6-49cf-8a38-c0c831108a6c\",\n \"postedFrom\": \"103.121.204.133\",\n \"accountNumber\": \"003001003879112168\",\n \"ipAddress\": \"103.121.204.133\",\n \"notes\": \"eTrax: Transaction Request\",\n \"userId\": \"965e708d-a7b6-49cf-8a38-c0c831108a6c\",\n \"username\": \"DSTI01\"\n },\n {\n \"id\": 206,\n \"batchId\": \"1\",\n \"transactionDate\": \"2022-08-01T13:40:14.810255\",\n \"credit\": 0,\n \"debit\": 250000,\n \"eTraxReferenceNumber\": 0,\n \"externalReferenceNumber\": 0,\n \"cbsDocumentNumber\": null,\n \"crossReferenceNumber\": 0,\n \"postedBy\": \"965e708d-a7b6-49cf-8a38-c0c831108a6c\",\n \"postedFrom\": \"103.121.204.133\",\n \"accountNumber\": \"003001003879112168\",\n \"ipAddress\": \"103.121.204.133\",\n \"notes\": \"eTrax: Transaction Request\",\n \"userId\": \"965e708d-a7b6-49cf-8a38-c0c831108a6c\",\n \"username\": \"DSTI01\"\n },\n {\n \"id\": 204,\n \"batchId\": \"1\",\n \"transactionDate\": \"2022-08-01T13:40:14.6400784\",\n \"credit\": 0,\n \"debit\": 100000,\n \"eTraxReferenceNumber\": 0,\n \"externalReferenceNumber\": 0,\n \"cbsDocumentNumber\": null,\n \"crossReferenceNumber\": 0,\n \"postedBy\": \"965e708d-a7b6-49cf-8a38-c0c831108a6c\",\n \"postedFrom\": \"103.121.204.133\",\n \"accountNumber\": \"003001003879112168\",\n \"ipAddress\": \"103.121.204.133\",\n \"notes\": \"eTrax: Transaction Request\",\n \"userId\": \"965e708d-a7b6-49cf-8a38-c0c831108a6c\",\n \"username\": \"DSTI01\"\n },\n {\n \"id\": 202,\n \"batchId\": \"1\",\n \"transactionDate\": \"2022-07-29T14:48:04.4982544\",\n \"credit\": 0,\n \"debit\": 250000,\n \"eTraxReferenceNumber\": 0,\n \"externalReferenceNumber\": 0,\n \"cbsDocumentNumber\": null,\n \"crossReferenceNumber\": 0,\n \"postedBy\": \"965e708d-a7b6-49cf-8a38-c0c831108a6c\",\n \"postedFrom\": \"103.121.204.133\",\n \"accountNumber\": \"003001003879112168\",\n \"ipAddress\": \"103.121.204.133\",\n \"notes\": \"eTrax: Transaction Request\",\n \"userId\": \"965e708d-a7b6-49cf-8a38-c0c831108a6c\",\n \"username\": \"DSTI01\"\n },\n {\n \"id\": 200,\n \"batchId\": \"1\",\n \"transactionDate\": \"2022-07-29T14:48:04.2474515\",\n \"credit\": 0,\n \"debit\": 100000,\n \"eTraxReferenceNumber\": 0,\n \"externalReferenceNumber\": 0,\n \"cbsDocumentNumber\": null,\n \"crossReferenceNumber\": 0,\n \"postedBy\": \"965e708d-a7b6-49cf-8a38-c0c831108a6c\",\n \"postedFrom\": \"103.121.204.133\",\n \"accountNumber\": \"003001003879112168\",\n \"ipAddress\": \"103.121.204.133\",\n \"notes\": \"eTrax: Transaction Request\",\n \"userId\": \"965e708d-a7b6-49cf-8a38-c0c831108a6c\",\n \"username\": \"DSTI01\"\n },\n {\n \"id\": 199,\n \"batchId\": null,\n \"transactionDate\": \"2022-07-29T11:38:49.0708892\",\n \"credit\": 5000000,\n \"debit\": 0,\n \"eTraxReferenceNumber\": 0,\n \"externalReferenceNumber\": 0,\n \"cbsDocumentNumber\": null,\n \"crossReferenceNumber\": 0,\n \"postedBy\": \"eb85fa53-0d7e-a585-b2b3-3a03a6a76323\",\n \"postedFrom\": null,\n \"accountNumber\": \"003001003879112168\",\n \"ipAddress\": null,\n \"notes\": null,\n \"userId\": \"eb85fa53-0d7e-a585-b2b3-3a03a6a76323\",\n \"username\": \"admin\"\n },\n {\n \"id\": 197,\n \"batchId\": null,\n \"transactionDate\": \"2022-07-29T11:37:36.2823965\",\n \"credit\": 5000000,\n \"debit\": 0,\n \"eTraxReferenceNumber\": 0,\n \"externalReferenceNumber\": 0,\n \"cbsDocumentNumber\": null,\n \"crossReferenceNumber\": 0,\n \"postedBy\": \"eb85fa53-0d7e-a585-b2b3-3a03a6a76323\",\n \"postedFrom\": null,\n \"accountNumber\": \"003001003879112168\",\n \"ipAddress\": null,\n \"notes\": null,\n \"userId\": \"eb85fa53-0d7e-a585-b2b3-3a03a6a76323\",\n \"username\": \"admin\"\n }\n ]\n}" + }, + { + "name": "Reconcoliation", + "originalRequest": { + "method": "GET", + "header": [], + "body": { + "mode": "urlencoded", + "urlencoded": [ + { + "key": "from", + "value": "08/08/2022", + "type": "text" + }, + { + "key": "to", + "value": "09/08/2022", + "type": "text" + }, + { + "key": "authorizationCode", + "value": "yoWYLKjSPl4C746p+pzEFl9hQ6ZZpq2JcvNItmC9ZowWRTB1V4Cx+bk0YkTLBSHc", + "type": "text" + }, + { + "key": "bban", + "value": "003001003879112168", + "type": "text" + }, + { + "key": "pageNumber", + "value": "1", + "type": "text" + }, + { + "key": "pageSize", + "value": "20", + "type": "text" + } + ] + }, + "url": { + "raw": "{{recon-url}}", + "host": [ + "{{recon-url}}" + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Transfer-Encoding", + "value": "chunked" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "key": "Server", + "value": "Microsoft-IIS/10.0" + }, + { + "key": "X-Powered-By", + "value": "ASP.NET" + }, + { + "key": "Date", + "value": "Fri, 02 Sep 2022 12:01:21 GMT" + } + ], + "cookie": [], + "body": "{\n \"from\": \"2022-08-08T00:00:00\",\n \"to\": \"2022-09-08T00:00:00\",\n \"pageSize\": 20,\n \"pageCount\": 2,\n \"pageNumber\": 1,\n \"totalCount\": 32,\n \"bban\": \"003001003879112168\",\n \"comment\": null,\n \"isError\": false,\n \"transactions\": [\n {\n \"id\": 60,\n \"batchId\": \"1\",\n \"transactionDate\": \"2022-09-02T11:35:16.9948387\",\n \"credit\": 2000,\n \"debit\": 0,\n \"eTraxReferenceNumber\": 0,\n \"externalReferenceNumber\": 0,\n \"cbsDocumentNumber\": \"N/A\",\n \"crossReferenceNumber\": 59,\n \"postedBy\": \"7f95c766-6681-4cff-acde-8f4aab6bed53\",\n \"postedFrom\": \"102.176.189.6\",\n \"accountNumber\": \"003001003874120160\",\n \"ipAddress\": \"102.176.189.6\",\n \"notes\": \"eTrax: Internal Transaction Request (CREDIT)\",\n \"userId\": \"7f95c766-6681-4cff-acde-8f4aab6bed53\",\n \"username\": \"DSTI01\"\n },\n {\n \"id\": 59,\n \"batchId\": \"1\",\n \"transactionDate\": \"2022-09-02T11:35:16.9920637\",\n \"credit\": 0,\n \"debit\": 2000,\n \"eTraxReferenceNumber\": 0,\n \"externalReferenceNumber\": 0,\n \"cbsDocumentNumber\": \"N/A\",\n \"crossReferenceNumber\": 59,\n \"postedBy\": \"7f95c766-6681-4cff-acde-8f4aab6bed53\",\n \"postedFrom\": \"102.176.189.6\",\n \"accountNumber\": \"003001003879112168\",\n \"ipAddress\": \"102.176.189.6\",\n \"notes\": \"eTrax: Internal Transaction Request (DEBIT)\",\n \"userId\": \"7f95c766-6681-4cff-acde-8f4aab6bed53\",\n \"username\": \"DSTI01\"\n },\n {\n \"id\": 59,\n \"batchId\": \"1\",\n \"transactionDate\": \"2022-09-02T11:35:16.9920637\",\n \"credit\": 0,\n \"debit\": 2000,\n \"eTraxReferenceNumber\": 0,\n \"externalReferenceNumber\": 0,\n \"cbsDocumentNumber\": \"N/A\",\n \"crossReferenceNumber\": 59,\n \"postedBy\": \"7f95c766-6681-4cff-acde-8f4aab6bed53\",\n \"postedFrom\": \"102.176.189.6\",\n \"accountNumber\": \"003001003879112168\",\n \"ipAddress\": \"102.176.189.6\",\n \"notes\": \"eTrax: Internal Transaction Request (DEBIT)\",\n \"userId\": \"7f95c766-6681-4cff-acde-8f4aab6bed53\",\n \"username\": \"DSTI01\"\n },\n {\n \"id\": 58,\n \"batchId\": \"1\",\n \"transactionDate\": \"2022-09-02T11:34:58.1952072\",\n \"credit\": 1000,\n \"debit\": 0,\n \"eTraxReferenceNumber\": 0,\n \"externalReferenceNumber\": 0,\n \"cbsDocumentNumber\": \"N/A\",\n \"crossReferenceNumber\": 57,\n \"postedBy\": \"7f95c766-6681-4cff-acde-8f4aab6bed53\",\n \"postedFrom\": \"102.176.189.6\",\n \"accountNumber\": \"003001003874120160\",\n \"ipAddress\": \"102.176.189.6\",\n \"notes\": \"eTrax: Internal Transaction Request (CREDIT)\",\n \"userId\": \"7f95c766-6681-4cff-acde-8f4aab6bed53\",\n \"username\": \"DSTI01\"\n },\n {\n \"id\": 57,\n \"batchId\": \"1\",\n \"transactionDate\": \"2022-09-02T11:34:58.1918194\",\n \"credit\": 0,\n \"debit\": 1000,\n \"eTraxReferenceNumber\": 0,\n \"externalReferenceNumber\": 0,\n \"cbsDocumentNumber\": \"N/A\",\n \"crossReferenceNumber\": 57,\n \"postedBy\": \"7f95c766-6681-4cff-acde-8f4aab6bed53\",\n \"postedFrom\": \"102.176.189.6\",\n \"accountNumber\": \"003001003879112168\",\n \"ipAddress\": \"102.176.189.6\",\n \"notes\": \"eTrax: Internal Transaction Request (DEBIT)\",\n \"userId\": \"7f95c766-6681-4cff-acde-8f4aab6bed53\",\n \"username\": \"DSTI01\"\n },\n {\n \"id\": 57,\n \"batchId\": \"1\",\n \"transactionDate\": \"2022-09-02T11:34:58.1918194\",\n \"credit\": 0,\n \"debit\": 1000,\n \"eTraxReferenceNumber\": 0,\n \"externalReferenceNumber\": 0,\n \"cbsDocumentNumber\": \"N/A\",\n \"crossReferenceNumber\": 57,\n \"postedBy\": \"7f95c766-6681-4cff-acde-8f4aab6bed53\",\n \"postedFrom\": \"102.176.189.6\",\n \"accountNumber\": \"003001003879112168\",\n \"ipAddress\": \"102.176.189.6\",\n \"notes\": \"eTrax: Internal Transaction Request (DEBIT)\",\n \"userId\": \"7f95c766-6681-4cff-acde-8f4aab6bed53\",\n \"username\": \"DSTI01\"\n },\n {\n \"id\": 56,\n \"batchId\": \"1\",\n \"transactionDate\": \"2022-09-02T11:30:43.9429779\",\n \"credit\": 1000,\n \"debit\": 0,\n \"eTraxReferenceNumber\": 0,\n \"externalReferenceNumber\": 0,\n \"cbsDocumentNumber\": \"N/A\",\n \"crossReferenceNumber\": 55,\n \"postedBy\": \"7f95c766-6681-4cff-acde-8f4aab6bed53\",\n \"postedFrom\": \"102.176.189.6\",\n \"accountNumber\": \"003001003879112168\",\n \"ipAddress\": \"102.176.189.6\",\n \"notes\": \"eTrax: Internal Transaction Request (CREDIT)\",\n \"userId\": \"7f95c766-6681-4cff-acde-8f4aab6bed53\",\n \"username\": \"DSTI01\"\n },\n {\n \"id\": 56,\n \"batchId\": \"1\",\n \"transactionDate\": \"2022-09-02T11:30:43.9429779\",\n \"credit\": 1000,\n \"debit\": 0,\n \"eTraxReferenceNumber\": 0,\n \"externalReferenceNumber\": 0,\n \"cbsDocumentNumber\": \"N/A\",\n \"crossReferenceNumber\": 55,\n \"postedBy\": \"7f95c766-6681-4cff-acde-8f4aab6bed53\",\n \"postedFrom\": \"102.176.189.6\",\n \"accountNumber\": \"003001003879112168\",\n \"ipAddress\": \"102.176.189.6\",\n \"notes\": \"eTrax: Internal Transaction Request (CREDIT)\",\n \"userId\": \"7f95c766-6681-4cff-acde-8f4aab6bed53\",\n \"username\": \"DSTI01\"\n },\n {\n \"id\": 55,\n \"batchId\": \"1\",\n \"transactionDate\": \"2022-09-02T11:30:43.9397666\",\n \"credit\": 0,\n \"debit\": 1000,\n \"eTraxReferenceNumber\": 0,\n \"externalReferenceNumber\": 0,\n \"cbsDocumentNumber\": \"N/A\",\n \"crossReferenceNumber\": 55,\n \"postedBy\": \"7f95c766-6681-4cff-acde-8f4aab6bed53\",\n \"postedFrom\": \"102.176.189.6\",\n \"accountNumber\": \"003001003879112168\",\n \"ipAddress\": \"102.176.189.6\",\n \"notes\": \"eTrax: Internal Transaction Request (DEBIT)\",\n \"userId\": \"7f95c766-6681-4cff-acde-8f4aab6bed53\",\n \"username\": \"DSTI01\"\n },\n {\n \"id\": 55,\n \"batchId\": \"1\",\n \"transactionDate\": \"2022-09-02T11:30:43.9397666\",\n \"credit\": 0,\n \"debit\": 1000,\n \"eTraxReferenceNumber\": 0,\n \"externalReferenceNumber\": 0,\n \"cbsDocumentNumber\": \"N/A\",\n \"crossReferenceNumber\": 55,\n \"postedBy\": \"7f95c766-6681-4cff-acde-8f4aab6bed53\",\n \"postedFrom\": \"102.176.189.6\",\n \"accountNumber\": \"003001003879112168\",\n \"ipAddress\": \"102.176.189.6\",\n \"notes\": \"eTrax: Internal Transaction Request (DEBIT)\",\n \"userId\": \"7f95c766-6681-4cff-acde-8f4aab6bed53\",\n \"username\": \"DSTI01\"\n },\n {\n \"id\": 54,\n \"batchId\": \"1\",\n \"transactionDate\": \"2022-09-02T11:20:40.7743261\",\n \"credit\": 250,\n \"debit\": 0,\n \"eTraxReferenceNumber\": 0,\n \"externalReferenceNumber\": 0,\n \"cbsDocumentNumber\": \"N/A\",\n \"crossReferenceNumber\": 53,\n \"postedBy\": \"7f95c766-6681-4cff-acde-8f4aab6bed53\",\n \"postedFrom\": \"203.81.242.121\",\n \"accountNumber\": \"003001003874120160\",\n \"ipAddress\": \"203.81.242.121\",\n \"notes\": \"eTrax: Internal Transaction Request (CREDIT)\",\n \"userId\": \"7f95c766-6681-4cff-acde-8f4aab6bed53\",\n \"username\": \"DSTI01\"\n },\n {\n \"id\": 53,\n \"batchId\": \"1\",\n \"transactionDate\": \"2022-09-02T11:20:40.7719825\",\n \"credit\": 0,\n \"debit\": 250,\n \"eTraxReferenceNumber\": 0,\n \"externalReferenceNumber\": 0,\n \"cbsDocumentNumber\": \"N/A\",\n \"crossReferenceNumber\": 53,\n \"postedBy\": \"7f95c766-6681-4cff-acde-8f4aab6bed53\",\n \"postedFrom\": \"203.81.242.121\",\n \"accountNumber\": \"003001003879112168\",\n \"ipAddress\": \"203.81.242.121\",\n \"notes\": \"eTrax: Internal Transaction Request (DEBIT)\",\n \"userId\": \"7f95c766-6681-4cff-acde-8f4aab6bed53\",\n \"username\": \"DSTI01\"\n },\n {\n \"id\": 53,\n \"batchId\": \"1\",\n \"transactionDate\": \"2022-09-02T11:20:40.7719825\",\n \"credit\": 0,\n \"debit\": 250,\n \"eTraxReferenceNumber\": 0,\n \"externalReferenceNumber\": 0,\n \"cbsDocumentNumber\": \"N/A\",\n \"crossReferenceNumber\": 53,\n \"postedBy\": \"7f95c766-6681-4cff-acde-8f4aab6bed53\",\n \"postedFrom\": \"203.81.242.121\",\n \"accountNumber\": \"003001003879112168\",\n \"ipAddress\": \"203.81.242.121\",\n \"notes\": \"eTrax: Internal Transaction Request (DEBIT)\",\n \"userId\": \"7f95c766-6681-4cff-acde-8f4aab6bed53\",\n \"username\": \"DSTI01\"\n },\n {\n \"id\": 52,\n \"batchId\": \"1\",\n \"transactionDate\": \"2022-09-02T11:20:40.7170309\",\n \"credit\": 250,\n \"debit\": 0,\n \"eTraxReferenceNumber\": 0,\n \"externalReferenceNumber\": 0,\n \"cbsDocumentNumber\": \"N/A\",\n \"crossReferenceNumber\": 51,\n \"postedBy\": \"7f95c766-6681-4cff-acde-8f4aab6bed53\",\n \"postedFrom\": \"203.81.242.121\",\n \"accountNumber\": \"003001003873110196\",\n \"ipAddress\": \"203.81.242.121\",\n \"notes\": \"eTrax: Internal Transaction Request (CREDIT)\",\n \"userId\": \"7f95c766-6681-4cff-acde-8f4aab6bed53\",\n \"username\": \"DSTI01\"\n },\n {\n \"id\": 51,\n \"batchId\": \"1\",\n \"transactionDate\": \"2022-09-02T11:20:40.5814167\",\n \"credit\": 0,\n \"debit\": 250,\n \"eTraxReferenceNumber\": 0,\n \"externalReferenceNumber\": 0,\n \"cbsDocumentNumber\": \"N/A\",\n \"crossReferenceNumber\": 51,\n \"postedBy\": \"7f95c766-6681-4cff-acde-8f4aab6bed53\",\n \"postedFrom\": \"203.81.242.121\",\n \"accountNumber\": \"003001003879112168\",\n \"ipAddress\": \"203.81.242.121\",\n \"notes\": \"eTrax: Internal Transaction Request (DEBIT)\",\n \"userId\": \"7f95c766-6681-4cff-acde-8f4aab6bed53\",\n \"username\": \"DSTI01\"\n },\n {\n \"id\": 51,\n \"batchId\": \"1\",\n \"transactionDate\": \"2022-09-02T11:20:40.5814167\",\n \"credit\": 0,\n \"debit\": 250,\n \"eTraxReferenceNumber\": 0,\n \"externalReferenceNumber\": 0,\n \"cbsDocumentNumber\": \"N/A\",\n \"crossReferenceNumber\": 51,\n \"postedBy\": \"7f95c766-6681-4cff-acde-8f4aab6bed53\",\n \"postedFrom\": \"203.81.242.121\",\n \"accountNumber\": \"003001003879112168\",\n \"ipAddress\": \"203.81.242.121\",\n \"notes\": \"eTrax: Internal Transaction Request (DEBIT)\",\n \"userId\": \"7f95c766-6681-4cff-acde-8f4aab6bed53\",\n \"username\": \"DSTI01\"\n },\n {\n \"id\": 50,\n \"batchId\": \"1\",\n \"transactionDate\": \"2022-09-02T02:46:18.9079563\",\n \"credit\": 1000,\n \"debit\": 0,\n \"eTraxReferenceNumber\": 0,\n \"externalReferenceNumber\": 0,\n \"cbsDocumentNumber\": \"N/A\",\n \"crossReferenceNumber\": 49,\n \"postedBy\": \"7a9e783c-0756-4754-9753-fb3c10c4bff9\",\n \"postedFrom\": \"102.176.189.6\",\n \"accountNumber\": \"003001003879112168\",\n \"ipAddress\": \"102.176.189.6\",\n \"notes\": \"eTrax: Internal Transaction Request (CREDIT)\",\n \"userId\": \"7a9e783c-0756-4754-9753-fb3c10c4bff9\",\n \"username\": \"falcoln\"\n },\n {\n \"id\": 48,\n \"batchId\": \"13340d58-a2f3-4641-869d-5edf74fb6cf9\",\n \"transactionDate\": \"2022-08-31T13:44:02.5427481\",\n \"credit\": 100,\n \"debit\": 0,\n \"eTraxReferenceNumber\": 0,\n \"externalReferenceNumber\": 0,\n \"cbsDocumentNumber\": \"N/A\",\n \"crossReferenceNumber\": 47,\n \"postedBy\": \"7f95c766-6681-4cff-acde-8f4aab6bed53\",\n \"postedFrom\": \"102.223.155.55\",\n \"accountNumber\": \"003001003873110196\",\n \"ipAddress\": \"102.223.155.55\",\n \"notes\": \"eTrax: Internal Transaction Request (CREDIT)\",\n \"userId\": \"7f95c766-6681-4cff-acde-8f4aab6bed53\",\n \"username\": \"DSTI01\"\n },\n {\n \"id\": 47,\n \"batchId\": \"13340d58-a2f3-4641-869d-5edf74fb6cf9\",\n \"transactionDate\": \"2022-08-31T13:44:02.3553769\",\n \"credit\": 0,\n \"debit\": 100,\n \"eTraxReferenceNumber\": 0,\n \"externalReferenceNumber\": 0,\n \"cbsDocumentNumber\": \"N/A\",\n \"crossReferenceNumber\": 47,\n \"postedBy\": \"7f95c766-6681-4cff-acde-8f4aab6bed53\",\n \"postedFrom\": \"102.223.155.55\",\n \"accountNumber\": \"003001003879112168\",\n \"ipAddress\": \"102.223.155.55\",\n \"notes\": \"eTrax: Internal Transaction Request (DEBIT)\",\n \"userId\": \"7f95c766-6681-4cff-acde-8f4aab6bed53\",\n \"username\": \"DSTI01\"\n },\n {\n \"id\": 47,\n \"batchId\": \"13340d58-a2f3-4641-869d-5edf74fb6cf9\",\n \"transactionDate\": \"2022-08-31T13:44:02.3553769\",\n \"credit\": 0,\n \"debit\": 100,\n \"eTraxReferenceNumber\": 0,\n \"externalReferenceNumber\": 0,\n \"cbsDocumentNumber\": \"N/A\",\n \"crossReferenceNumber\": 47,\n \"postedBy\": \"7f95c766-6681-4cff-acde-8f4aab6bed53\",\n \"postedFrom\": \"102.223.155.55\",\n \"accountNumber\": \"003001003879112168\",\n \"ipAddress\": \"102.223.155.55\",\n \"notes\": \"eTrax: Internal Transaction Request (DEBIT)\",\n \"userId\": \"7f95c766-6681-4cff-acde-8f4aab6bed53\",\n \"username\": \"DSTI01\"\n }\n ]\n}" + } + ] + } + ], + "event": [ + { + "listen": "prerequest", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + }, + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "pm.test(\"Status code is 200\", function () {", + " pm.response.to.have.status(200);", + " pm.expect(pm.response.text).not.equal(null);", + "});" + ] + } + } + ] +} \ No newline at end of file diff --git a/ph-ee-env-template/PostmanCollections/ph-ee-bulk-demo-11.csv b/ph-ee-env-template/PostmanCollections/ph-ee-bulk-demo-11.csv new file mode 100644 index 000000000..1a7317fdd --- /dev/null +++ b/ph-ee-env-template/PostmanCollections/ph-ee-bulk-demo-11.csv @@ -0,0 +1,6 @@ +id,request_id,payment_mode,payer_identifier_type,payer_identifier,payee_identifier_type,payee_identifier,amount,currency,note +0,f1e22fe3-9740-4fba-97b6-78f43bfa7f2f,mojaloop,msisdn,835322416,msisdn,27713803912,10,USD,Moja bulk test 1 +1,39f6ac4d052e-72aa3ea4-e6f6-4880-877f,mojaloop,msisdn,835322416,msisdn,27713803912,10,USD,Moja bulk test 2 +2,a27631f6-6dd4-4d69-b4fc-8932bd721913,mojaloop,msisdn,835322416,msisdn,27713803912,10,USD,Moja bulk test 3 +3,3d21e6ea-c583-44ed-b94f-af909fa7616e,mojaloop,msisdn,835322416,msisdn,27713803912,10,USD,Moja bulk test 4 +4,15f9a0b0-2299-436d-8433-da564140ba66,mojaloop,msisdn,835322416,msisdn,27713803912,10,USD,Moja bulk test 5 \ No newline at end of file diff --git a/ph-ee-env-template/PostmanCollections/ph-ee-bulk-demo-5.csv b/ph-ee-env-template/PostmanCollections/ph-ee-bulk-demo-5.csv new file mode 100644 index 000000000..b68ea3696 --- /dev/null +++ b/ph-ee-env-template/PostmanCollections/ph-ee-bulk-demo-5.csv @@ -0,0 +1,13 @@ +id,request_id,payment_mode,payer_identifier_type,payer_identifier,payee_identifier_type,payee_identifier,amount,currency,note +0,f1e22fe3-9740-4fba-97b6-78f43bfa7f2f,slcb,accountNumber,003001003879112168,accountNumber,003001003873110196,850,USD,Test Payee Payment +1,72aa3ea4-e6f6-4880-877f-39f6ac4d052e,slcb,accountNumber,003001003879112168,accountNumber,003001003874120160,222,USD,Test Payee Payment +2,f1e22fe3-9740-4fba-97b6-78f43bfa7f2f,slcb,accountNumber,003001003879112168,accountNumber,003001003873110196,850,USD,Test Payee Payment +3,72aa3ea4-e6f6-4880-877f-39f6ac4d052e,slcb,accountNumber,003001003879112168,accountNumber,003001003874120160,222,USD,Test Payee Payment +4,f1e22fe3-9740-4fba-97b6-78f43bfa7f2f,slcb,accountNumber,003001003879112168,accountNumber,003001003873110196,850,USD,Test Payee Payment +5,72aa3ea4-e6f6-4880-877f-39f6ac4d052e,slcb,accountNumber,003001003879112168,accountNumber,003001003874120160,222,USD,Test Payee Payment +6,f1e22fe3-9740-4fba-97b6-78f43bfa7f2f,slcb,accountNumber,003001003879112168,accountNumber,003001003873110196,850,USD,Test Payee Payment +7,72aa3ea4-e6f6-4880-877f-39f6ac4d052e,slcb,accountNumber,003001003879112168,accountNumber,003001003874120160,222,USD,Test Payee Payment +8,f1e22fe3-9740-4fba-97b6-78f43bfa7f2f,slcb,accountNumber,003001003879112168,accountNumber,003001003873110196,850,USD,Test Payee Payment +9,72aa3ea4-e6f6-4880-877f-39f6ac4d052e,slcb,accountNumber,003001003879112168,accountNumber,003001003874120160,222,USD,Test Payee Payment +10,f1e22fe3-9740-4fba-97b6-78f43bfa7f2f,slcb,accountNumber,003001003879112168,accountNumber,003001003873110196,850,USD,Test Payee Payment +11,72aa3ea4-e6f6-4880-877f-39f6ac4d052e,slcb,accountNumber,003001003879112168,accountNumber,003001003874120160,222,USD,Test Payee Payment \ No newline at end of file diff --git a/ph-ee-env-template/PostmanCollections/ph-ee-bulk-demo-6.csv b/ph-ee-env-template/PostmanCollections/ph-ee-bulk-demo-6.csv new file mode 100644 index 000000000..587194d6c --- /dev/null +++ b/ph-ee-env-template/PostmanCollections/ph-ee-bulk-demo-6.csv @@ -0,0 +1,6 @@ +id,request_id,payment_mode,payer_identifier_type,payer_identifier,payee_identifier_type,payee_identifier,amount,currency,note +0,f1e22fe3-9740-4fba-97b6-78f43bfa7f2f,gsma,msisdn,449999999,msisdn,449999112,852,USD,Test Payee Payment +1,39f6ac4d052e-72aa3ea4-e6f6-4880-877f,gsma,msisdn,449999999,msisdn,449999112,278,USD,Test Payee Payment +2,a27631f6-6dd4-4d69-b4fc-8932bd721913,gsma,msisdn,449999999,msisdn,449999112,898,USD,Test Payee Payment +3,3d21e6ea-c583-44ed-b94f-af909fa7616e,gsma,msisdn,449999999,msisdn,449999112,987,USD,Test Payee Payment +4,15f9a0b0-2299-436d-8433-da564140ba66,gsma,msisdn,449999999,msisdn,449999112,777,USD,Test Payee Payment \ No newline at end of file diff --git a/ph-ee-env-template/PostmanCollections/workspace.postman_globals.json b/ph-ee-env-template/PostmanCollections/workspace.postman_globals.json new file mode 100644 index 000000000..cf4b01391 --- /dev/null +++ b/ph-ee-env-template/PostmanCollections/workspace.postman_globals.json @@ -0,0 +1,34 @@ +{ + "id": "cf8daf1c-c37b-4729-8366-97af3fd1d7a3", + "values": [ + { + "key": "NotificationsHostName", + "value": "paymenthub.qa.oneacrefund.org/notifications", + "enabled": true + }, + { + "key": "ChannelHostName", + "value": "paymenthub.qa.oneacrefund.org/channel/", + "enabled": true + }, + { + "key": "MpesaHostName", + "value": "paymenthub.qa.oneacrefund.org/mpesa", + "enabled": true + }, + { + "key": "MessagegatewayHostName", + "value": "paymenthub.qa.oneacrefund.org/messages", + "enabled": true + }, + { + "key": "TenantName", + "value": "oaf", + "enabled": true + } + ], + "name": "Globals", + "_postman_variable_scope": "globals", + "_postman_exported_at": "2022-01-20T11:28:24.614Z", + "_postman_exported_using": "Postman/9.5.0" +} \ No newline at end of file diff --git a/ph-ee-env-template/README.md b/ph-ee-env-template/README.md new file mode 100644 index 000000000..b43699854 --- /dev/null +++ b/ph-ee-env-template/README.md @@ -0,0 +1,19 @@ +# payment-hub-ee +Payment Hub Enterprise Edition middleware for integration to real-time payment systems. + +# Links + +### **Payment Hub** +- [Postman](https://www.getpostman.com/collections/b503484fc231b5857306) +- [Swagger](https://app.swaggerhub.com/apis/myapi943/payment-hub_ap_is/1.0) + +### **Mobile Money Simulator** +- [Postman](https://www.getpostman.com/collections/29f67aa60b516de44b5a) +- [Swagger](https://app.swaggerhub.com/apis/rrkas/mobile-money_simulator_api/1.0) + + +## Auto-Trigger ph-ee-env-template +- trigger pipeline on commit/push (check) + +## MojaloopHub_Setup.postman_collection.json +- [Mojaloop postman collection ] (https://github.com/mojaloop/postman) \ No newline at end of file diff --git a/ph-ee-env-template/Utility/Python/in.txt b/ph-ee-env-template/Utility/Python/in.txt new file mode 100644 index 000000000..e69de29bb diff --git a/ph-ee-env-template/Utility/Python/main.py b/ph-ee-env-template/Utility/Python/main.py new file mode 100644 index 000000000..21f6544fa --- /dev/null +++ b/ph-ee-env-template/Utility/Python/main.py @@ -0,0 +1,20 @@ +data = [] +with open('in.txt', 'r') as f: + for i in f.readlines(): + data.append(int(i.replace("\n", ""))) + +new = [] + +for i in data: + new.append("\"{}\"".format(str(i+1))) + new.append("\"{}\"".format(str(i-1))) + new.append("\"{}\"".format(str(i+2))) + new.append("\"{}\"".format(str(i-2))) + +with open('out.txt', 'w') as f: + for i in new: + f.write(i) + f.write(",\n") + for i in data: + f.write("\"{}\"".format(i)) + f.write(",\n") \ No newline at end of file diff --git a/ph-ee-env-template/fetch-release-tag.sh b/ph-ee-env-template/fetch-release-tag.sh new file mode 100644 index 000000000..17a405bc4 --- /dev/null +++ b/ph-ee-env-template/fetch-release-tag.sh @@ -0,0 +1,6 @@ +#!/bin/bash +nm=`grep "name:" helm/ph-ee-engine/Chart.yaml |cut -d ' ' -f 2` +ver=`grep "version:" helm/ph-ee-engine/Chart.yaml |cut -d ' ' -f 2` +phee_engine_release_tag=`echo $nm-$ver` +export phee_engine_release_tag +echo $phee_engine_release_tag diff --git a/ph-ee-env-template/grafana.json b/ph-ee-env-template/grafana.json new file mode 100644 index 000000000..8f49afc90 --- /dev/null +++ b/ph-ee-env-template/grafana.json @@ -0,0 +1,9424 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "gnetId": null, + "graphTooltip": 1, + "id": 1, + "iteration": 1617996012895, + "links": [], + "panels": [ + { + "collapsed": false, + "datasource": "Prometheus", + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 56, + "panels": [], + "title": "General Overview", + "type": "row" + }, + { + "datasource": "$DS_PROMETHEUS", + "fieldConfig": { + "defaults": { + "custom": {}, + "displayName": "", + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "red", + "value": null + }, + { + "color": "green", + "value": 100 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 12, + "x": 0, + "y": 1 + }, + "id": 137, + "links": [], + "options": { + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showThresholdLabels": false, + "showThresholdMarkers": true, + "text": {} + }, + "pluginVersion": "7.4.2", + "targets": [ + { + "expr": "sum(rate(zeebe_stream_processor_events_total{namespace=~\"$namespace\",partition=~\"$partition\",pod=~\"$pod\", action=~\"processed\"}[5m])) by (pod, partition, processor, action)", + "format": "time_series", + "instant": true, + "interval": "", + "intervalFactor": 1, + "legendFormat": "{{pod}}-{{partition}}", + "refId": "A" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Processing per Partition", + "type": "gauge" + }, + { + "datasource": "$DS_PROMETHEUS", + "fieldConfig": { + "defaults": { + "custom": {}, + "displayName": "", + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "red", + "value": null + }, + { + "color": "green", + "value": 100 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 12, + "x": 12, + "y": 1 + }, + "id": 138, + "links": [], + "options": { + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "last" + ], + "fields": "", + "values": false + }, + "showThresholdLabels": false, + "showThresholdMarkers": true, + "text": {} + }, + "pluginVersion": "7.4.2", + "targets": [ + { + "expr": "sum(rate(zeebe_exporter_events_total{namespace=~\"$namespace\",partition=~\"$partition\",pod=~\"$pod\"}[5m])) by (pod, partition, exporter)", + "format": "time_series", + "hide": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "{{pod}}-{{partition}}", + "refId": "B" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Exporting per Partition", + "type": "gauge" + }, + { + "columns": [ + { + "text": "Current", + "value": "current" + } + ], + "datasource": "$DS_PROMETHEUS", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fontSize": "100%", + "gridPos": { + "h": 9, + "w": 5, + "x": 0, + "y": 7 + }, + "id": 68, + "links": [], + "pageSize": null, + "scroll": true, + "showHeader": true, + "sort": { + "col": 1, + "desc": true + }, + "styles": [ + { + "alias": "Time", + "align": "auto", + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "link": false, + "pattern": "Time", + "type": "date" + }, + { + "alias": "Broker - Partition", + "align": "auto", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "decimals": 2, + "link": false, + "mappingType": 1, + "pattern": "Metric", + "preserveFormat": false, + "sanitize": false, + "thresholds": [], + "type": "string", + "unit": "short", + "valueMaps": [] + }, + { + "alias": "Role", + "align": "auto", + "colorMode": "value", + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "mappingType": 1, + "pattern": "Current", + "thresholds": [ + "0", + "3" + ], + "type": "string", + "unit": "short", + "valueMaps": [ + { + "text": "Follower", + "value": "1" + }, + { + "text": "Leader", + "value": "3" + }, + { + "text": "Candidate", + "value": "2" + } + ] + }, + { + "alias": "test", + "align": "auto", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "mappingType": 1, + "pattern": "Current", + "thresholds": [], + "type": "number", + "unit": "short" + } + ], + "targets": [ + { + "expr": "atomix_role{namespace=~\"$namespace\", pod=~\"$pod\", partition=~\"$partition\"}", + "format": "time_series", + "instant": true, + "intervalFactor": 1, + "legendFormat": "{{pod}} {{partitionGroupName}} {{partition}}", + "refId": "A" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Current Roles", + "transform": "timeseries_aggregations", + "type": "table-old" + }, + { + "aliasColors": {}, + "bars": false, + "cacheTimeout": null, + "dashLength": 10, + "dashes": false, + "datasource": "$DS_PROMETHEUS", + "description": "Shows when and how often a pod was restarted. The graph is zero when the pod is ready. With this it is also possible to determine how long it take for the pod to come ready again.", + "fieldConfig": { + "defaults": { + "custom": {}, + "links": [] + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 9, + "w": 9, + "x": 5, + "y": 7 + }, + "hiddenSeries": false, + "id": 116, + "legend": { + "avg": false, + "current": false, + "hideEmpty": false, + "hideZero": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null as zero", + "options": { + "alertThreshold": true + }, + "percentage": true, + "pluginVersion": "7.4.2", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "1 - kube_pod_container_status_ready{pod=~\".*\", pod!~\"curator.*|worker.*|starter.*\", namespace=\"$namespace\"}", + "format": "time_series", + "hide": false, + "instant": false, + "legendFormat": "{{pod}} restart", + "refId": "A" + }, + { + "expr": "sum(rate(kube_pod_container_status_ready{container=\"worker\",namespace=\"$namespace\"}[1m])) or vector(1)", + "hide": false, + "legendFormat": "Worker restart", + "refId": "M" + }, + { + "expr": "sum(rate(kube_pod_container_status_ready{container=\"starter\",namespace=\"$namespace\"}[1m])) or vector(1)", + "legendFormat": "Starter Restart", + "refId": "N" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Pod Restarts", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": 0, + "format": "short", + "label": "", + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "columns": [ + { + "text": "Current", + "value": "current" + } + ], + "datasource": "Prometheus", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fontSize": "100%", + "gridPos": { + "h": 9, + "w": 5, + "x": 14, + "y": 7 + }, + "id": 129, + "pageSize": null, + "scroll": true, + "showHeader": true, + "sort": { + "col": null, + "desc": false + }, + "styles": [ + { + "alias": "Time", + "align": "auto", + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "pattern": "Time", + "type": "date" + }, + { + "alias": "", + "align": "auto", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "mappingType": 1, + "pattern": "", + "thresholds": [], + "type": "number", + "unit": "short" + }, + { + "alias": "Broker Partition", + "align": "auto", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "decimals": 2, + "pattern": "Metric", + "thresholds": [], + "type": "number", + "unit": "short" + }, + { + "alias": "Status", + "align": "auto", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "mappingType": 1, + "pattern": "Current", + "thresholds": [], + "type": "string", + "unit": "short", + "valueMaps": [ + { + "text": "Healthy", + "value": "1" + }, + { + "text": "Unhealthy", + "value": "0" + } + ] + } + ], + "targets": [ + { + "expr": "zeebe_health{namespace=~\"$namespace\", partition=~\"$partition\", pod=~\"$pod\"}", + "instant": true, + "legendFormat": "{{pod}} {{partition}}", + "refId": "A" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Partition health ", + "transform": "timeseries_aggregations", + "type": "table-old" + }, + { + "columns": [ + { + "text": "Current", + "value": "current" + } + ], + "datasource": "$DS_PROMETHEUS", + "description": "Displays the current running pods in the namespace.", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fontSize": "100%", + "gridPos": { + "h": 9, + "w": 5, + "x": 19, + "y": 7 + }, + "id": 54, + "pageSize": null, + "scroll": true, + "showHeader": true, + "sort": { + "col": 0, + "desc": true + }, + "styles": [ + { + "alias": "Time", + "align": "auto", + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "pattern": "Time", + "type": "date" + }, + { + "alias": "Pod", + "align": "auto", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "decimals": 2, + "pattern": "Metric", + "thresholds": [], + "type": "string", + "unit": "short" + }, + { + "alias": "Status", + "align": "auto", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "mappingType": 1, + "pattern": "Current", + "thresholds": [], + "type": "string", + "unit": "short", + "valueMaps": [ + { + "text": "Ready", + "value": "1" + }, + { + "text": "Not Ready", + "value": "0" + } + ] + } + ], + "targets": [ + { + "expr": "kube_pod_container_status_ready{namespace=~\"$namespace\"}", + "format": "time_series", + "hide": false, + "instant": true, + "legendFormat": "{{pod}}", + "refId": "A" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Running", + "transform": "timeseries_aggregations", + "type": "table-old" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$DS_PROMETHEUS", + "fieldConfig": { + "defaults": { + "custom": {}, + "links": [] + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 1, + "gridPos": { + "h": 8, + "w": 10, + "x": 0, + "y": 16 + }, + "hiddenSeries": false, + "id": 58, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideEmpty": false, + "hideZero": false, + "max": false, + "min": false, + "rightSide": true, + "show": false, + "sideWidth": 250, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "7.4.2", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(zeebe_stream_processor_events_total{namespace=~\"$namespace\",partition=~\"$partition\",pod=~\"$pod\", action=~\"written|processed\"}[5m])) by (pod, partition, processor, action)", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "{{pod}}-{{partition}}-{{processor}}-{{action}}", + "refId": "A" + }, + { + "expr": "sum(rate(zeebe_exporter_events_total{namespace=~\"$namespace\",partition=~\"$partition\",pod=~\"$pod\"}[5m])) by (pod, partition, exporter)", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "{{pod}}-{{partition}}-{{exporter}}", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Processing per Partition", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "datasource": "$DS_PROMETHEUS", + "description": "Takes the avg of all completed processes per second over the given time range.", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 4, + "w": 5, + "x": 10, + "y": 16 + }, + "id": 117, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false, + "ymax": null, + "ymin": null + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(rate(zeebe_element_instance_events_total{namespace=~\"$namespace\",partition=~\"$partition\",pod=~\"$pod\", action=\"completed\", type=\"PROCESS\"}[5m]))", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "{{type}} {{action}}", + "refId": "A" + } + ], + "thresholds": "", + "timeFrom": null, + "timeShift": null, + "title": "Completed Processes in avg overtime per sec", + "type": "singlestat", + "valueFontSize": "110%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$DS_PROMETHEUS", + "fieldConfig": { + "defaults": { + "custom": {}, + "links": [] + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 8, + "w": 9, + "x": 15, + "y": 16 + }, + "hiddenSeries": false, + "id": 74, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "7.4.2", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(zeebe_element_instance_events_total{namespace=~\"$namespace\",partition=~\"$partition\",pod=~\"$pod\"}[5m])) by (type, action)", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "{{type}} {{action}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Current Events", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "datasource": "$DS_PROMETHEUS", + "description": "Takes the avg of all completed tasks per second over the given time range.", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 4, + "w": 5, + "x": 10, + "y": 20 + }, + "id": 118, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false, + "ymax": null, + "ymin": null + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(rate(zeebe_element_instance_events_total{namespace=~\"$namespace\",partition=~\"$partition\",pod=~\"$pod\", action=\"completed\", type=\"SERVICE_TASK\"}[5m]))", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "{{type}} {{action}}", + "refId": "A" + } + ], + "thresholds": "", + "timeFrom": null, + "timeShift": null, + "title": "Completed Tasks in avg overtime per sec", + "type": "singlestat", + "valueFontSize": "110%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "datasource": "Prometheus", + "fieldConfig": { + "defaults": { + "custom": {}, + "displayName": "", + "mappings": [], + "max": 100, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 40 + } + ] + }, + "unit": "percent" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 7, + "x": 0, + "y": 24 + }, + "id": 189, + "links": [], + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "center", + "orientation": "vertical", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "text": {}, + "textMode": "auto" + }, + "pluginVersion": "7.4.2", + "targets": [ + { + "expr": "(sum(rate(zeebe_dropped_request_count_total{namespace=~\"$namespace\", partition=~\"$partition\"}[1m])) by (partition) / sum(rate(zeebe_received_request_count_total{namespace=~\"$namespace\", partition=~\"$partition\"}[1m])) by (partition) ) * 100", + "interval": "", + "legendFormat": "Partition {{partition}}", + "refId": "A" + }, + { + "expr": "", + "interval": "", + "legendFormat": "", + "refId": "B" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Backpressure Dropping Requests [1m]", + "type": "stat" + }, + { + "datasource": "Prometheus", + "description": "Shows how many records the stream processor has not processed yet.", + "fieldConfig": { + "defaults": { + "custom": {}, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 1000 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 7, + "x": 0, + "y": 24 + }, + "id": 189, + "options": { + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "last" + ], + "fields": "", + "values": false + }, + "showThresholdLabels": false, + "showThresholdMarkers": true, + "text": {} + }, + "pluginVersion": "7.4.2", + "targets": [ + { + "expr": "zeebe_log_appender_last_committed_position{namespace=~\"$namespace\", partition=~\"$partition\"} - zeebe_stream_processor_last_processed_position{namespace=~\"$namespace\", partition=~\"$partition\"}", + "format": "time_series", + "instant": true, + "interval": "", + "intervalFactor": 1, + "legendFormat": "Partition {{partition}}", + "refId": "A" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Number of records not processed", + "type": "gauge" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$DS_PROMETHEUS", + "fieldConfig": { + "defaults": { + "custom": {}, + "links": [] + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 8, + "w": 8, + "x": 7, + "y": 24 + }, + "hiddenSeries": false, + "id": 87, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "7.4.2", + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(zeebe_deferred_append_count_total{namespace=~\"$namespace\",partition=~\"$partition\",pod=~\"$pod\"}[1m])) by (partition)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "deferred-{{partition}}", + "refId": "A" + }, + { + "expr": "sum(rate(zeebe_try_to_append_total{namespace=~\"$namespace\",partition=~\"$partition\",pod=~\"$pod\"}[1m])) by (partition)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "try-to-append-{{partition}}", + "refId": "B" + }, + { + "expr": "sum(zeebe_backpressure_append_limit{namespace=~\"$namespace\",partition=~\"$partition\",pod=~\"$pod\"}) by (partition)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "queue-limit-{{partition}}", + "refId": "C" + }, + { + "expr": "zeebe_backpressure_inflight_append_count{namespace=~\"$namespace\",partition=~\"$partition\",pod=~\"$pod\"} ", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Inflight-for-{{partition}}", + "refId": "D" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Append Backpressure", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$DS_PROMETHEUS", + "fieldConfig": { + "defaults": { + "custom": {}, + "links": [] + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 8, + "w": 9, + "x": 15, + "y": 24 + }, + "hiddenSeries": false, + "id": 31, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "7.4.2", + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(zeebe_dropped_request_count_total{namespace=~\"$namespace\",partition=~\"$partition\",pod=~\"$pod\"}[1m])) by (partition)", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "dropped-{{partition}}", + "refId": "A" + }, + { + "expr": "sum(rate(zeebe_received_request_count_total{namespace=~\"$namespace\",partition=~\"$partition\",pod=~\"$pod\"}[1m])) by (partition)", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "received-{{partition}}", + "refId": "B" + }, + { + "expr": "sum(zeebe_backpressure_requests_limit{namespace=~\"$namespace\",partition=~\"$partition\",pod=~\"$pod\"}) by (partition)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "queue-limit-{{partition}}", + "refId": "C" + }, + { + "expr": "zeebe_backpressure_inflight_requests_count{namespace=~\"$namespace\",partition=~\"$partition\",pod=~\"$pod\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "inflight-{{partition}}", + "refId": "D" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Command API Backpressure", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$DS_PROMETHEUS", + "fieldConfig": { + "defaults": { + "custom": {}, + "links": [] + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 9, + "w": 12, + "x": 0, + "y": 32 + }, + "hiddenSeries": false, + "id": 62, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "7.4.2", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(grpc_server_handled_total{namespace=~\"$namespace\"}[5m])) by (grpc_method)", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "{{grpc_method}} Request", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "GRPC Requests handled per sec", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$DS_PROMETHEUS", + "fieldConfig": { + "defaults": { + "custom": {}, + "links": [] + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 9, + "w": 12, + "x": 12, + "y": 32 + }, + "hiddenSeries": false, + "id": 93, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "7.4.2", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(grpc_client_started_total{namespace=~\"$namespace\"}[5m])) by (grpc_method)", + "format": "time_series", + "hide": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "{{grpc_method}}", + "refId": "A" + }, + { + "expr": "sum(rate(grpc_client_completed{namespace=~\"$namespace\"}[5m])) by (grpc_method, code)", + "format": "time_series", + "hide": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "{{grpc_method}} ({{code}})", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Client Requests", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "datasource": "Prometheus", + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 41 + }, + "id": 203, + "panels": [], + "title": "Processing", + "type": "row" + }, + { + "datasource": "Prometheus", + "description": "Shows how many positions are not updated by exporters per partition. Means what is the difference between last committed exporter position and committed log position.", + "fieldConfig": { + "defaults": { + "custom": {}, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 1000 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 12, + "x": 0, + "y": 42 + }, + "id": 192, + "options": { + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "last" + ], + "fields": "", + "values": false + }, + "showThresholdLabels": false, + "showThresholdMarkers": true, + "text": {} + }, + "pluginVersion": "7.4.2", + "targets": [ + { + "expr": "zeebe_exporter_last_exported_position{namespace=~\"$namespace\", partition=~\"$partition\"} - zeebe_exporter_last_updated_exported_position{namespace=~\"$namespace\", partition=~\"$partition\"}", + "format": "time_series", + "instant": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "{{exporter}} {{partition}}", + "refId": "A" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Number of records exported but not acknowledged", + "type": "gauge" + }, + { + "columns": [], + "datasource": "Prometheus", + "description": "Shows the position, which was appended last by the leader per partition.", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fontSize": "80%", + "gridPos": { + "h": 4, + "w": 4, + "x": 12, + "y": 42 + }, + "id": 196, + "pageSize": null, + "showHeader": true, + "sort": { + "col": 0, + "desc": true + }, + "styles": [ + { + "alias": "Time", + "align": "auto", + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "pattern": "Time", + "type": "hidden" + }, + { + "alias": "Position", + "align": "center", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "decimals": 2, + "pattern": "Value", + "thresholds": [], + "type": "string", + "unit": "short" + }, + { + "alias": "Partition", + "align": "center", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 0, + "mappingType": 1, + "pattern": "partition", + "thresholds": [], + "type": "number", + "unit": "short" + } + ], + "targets": [ + { + "expr": "sum by (partition) (zeebe_log_appender_last_appended_position{namespace=~\"$namespace\", partition=~\"$partition\"})", + "format": "table", + "instant": true, + "interval": "", + "legendFormat": "", + "refId": "A" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Last appended position", + "transform": "table", + "type": "table-old" + }, + { + "columns": [], + "datasource": "Prometheus", + "description": "Shows the last committed log position.", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fontSize": "80%", + "gridPos": { + "h": 4, + "w": 4, + "x": 16, + "y": 42 + }, + "id": 200, + "pageSize": null, + "showHeader": true, + "sort": { + "col": 0, + "desc": true + }, + "styles": [ + { + "alias": "Time", + "align": "auto", + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "pattern": "Time", + "type": "hidden" + }, + { + "alias": "Position", + "align": "center", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "decimals": 2, + "pattern": "Value", + "thresholds": [], + "type": "string", + "unit": "short" + }, + { + "alias": "Partition", + "align": "center", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 0, + "mappingType": 1, + "pattern": "partition", + "thresholds": [], + "type": "number", + "unit": "short" + } + ], + "targets": [ + { + "expr": "sum by (partition) (zeebe_log_appender_last_committed_position{namespace=~\"$namespace\", partition=~\"$partition\"})", + "format": "table", + "instant": true, + "interval": "", + "legendFormat": "", + "refId": "A" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Last committed position", + "transform": "table", + "type": "table-old" + }, + { + "columns": [], + "datasource": "Prometheus", + "description": "Shows the last processed position by the stream processor per partition.", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fontSize": "80%", + "gridPos": { + "h": 4, + "w": 4, + "x": 20, + "y": 42 + }, + "id": 198, + "pageSize": null, + "showHeader": true, + "sort": { + "col": 0, + "desc": true + }, + "styles": [ + { + "alias": "Time", + "align": "auto", + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "pattern": "Time", + "type": "hidden" + }, + { + "alias": "Position", + "align": "center", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "decimals": 2, + "pattern": "Value", + "thresholds": [], + "type": "string", + "unit": "short" + }, + { + "alias": "Partition", + "align": "center", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 0, + "mappingType": 1, + "pattern": "partition", + "thresholds": [], + "type": "number", + "unit": "short" + } + ], + "targets": [ + { + "expr": "sum by (partition) (zeebe_stream_processor_last_processed_position{namespace=~\"$namespace\", partition=~\"$partition\"})", + "format": "table", + "instant": true, + "interval": "", + "legendFormat": "", + "refId": "A" + }, + { + "expr": "", + "interval": "", + "legendFormat": "", + "refId": "B" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Last processed position", + "transform": "table", + "type": "table-old" + }, + { + "datasource": "Prometheus", + "description": "Shows how many records are not exported yet.", + "fieldConfig": { + "defaults": { + "custom": {}, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 1000 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 46 + }, + "id": 194, + "options": { + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "mean" + ], + "fields": "", + "values": false + }, + "showThresholdLabels": false, + "showThresholdMarkers": true, + "text": {} + }, + "pluginVersion": "7.4.2", + "targets": [ + { + "expr": "sum (zeebe_log_appender_last_committed_position{namespace=~\"$namespace\", partition=~\"$partition\"}) by (partition) - sum (zeebe_exporter_last_exported_position{namespace=~\"$namespace\", partition=~\"$partition\", exporter=\"elasticsearch\"}) by (partition)", + "format": "time_series", + "instant": false, + "interval": "", + "legendFormat": "Exporter {{partition}}", + "refId": "A" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Number of records not exported", + "type": "gauge" + }, + { + "columns": [], + "datasource": "Prometheus", + "description": "Shows the last exported position which was committed by the given exporter per partition.", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fontSize": "80%", + "gridPos": { + "h": 6, + "w": 7, + "x": 12, + "y": 46 + }, + "id": 199, + "pageSize": null, + "showHeader": true, + "sort": { + "col": 0, + "desc": true + }, + "styles": [ + { + "alias": "Time", + "align": "auto", + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "pattern": "Time", + "type": "hidden" + }, + { + "alias": "Position", + "align": "center", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "decimals": 2, + "pattern": "Value", + "thresholds": [], + "type": "string", + "unit": "short" + }, + { + "alias": "Partition", + "align": "center", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 0, + "mappingType": 1, + "pattern": "partition", + "thresholds": [], + "type": "number", + "unit": "short" + } + ], + "targets": [ + { + "expr": "sum by (exporter, partition) (zeebe_exporter_last_updated_exported_position{namespace=~\"$namespace\", partition=~\"$partition\"})", + "format": "table", + "instant": true, + "interval": "", + "legendFormat": "", + "refId": "A" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Last updated exported position", + "transform": "table", + "type": "table-old" + }, + { + "columns": [], + "datasource": "Prometheus", + "description": "Shows the last exported position per partition.", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fontSize": "80%", + "gridPos": { + "h": 6, + "w": 5, + "x": 19, + "y": 46 + }, + "id": 201, + "pageSize": null, + "showHeader": true, + "sort": { + "col": 0, + "desc": true + }, + "styles": [ + { + "alias": "Time", + "align": "auto", + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "pattern": "Time", + "type": "hidden" + }, + { + "alias": "Position", + "align": "center", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "decimals": 2, + "pattern": "Value", + "thresholds": [], + "type": "string", + "unit": "short" + }, + { + "alias": "Partition", + "align": "center", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 0, + "mappingType": 1, + "pattern": "partition", + "thresholds": [], + "type": "number", + "unit": "short" + } + ], + "targets": [ + { + "expr": "sum by (partition) (zeebe_exporter_last_exported_position{namespace=~\"$namespace\", partition=~\"$partition\", exporter=\"elasticsearch\"})", + "format": "table", + "instant": true, + "interval": "", + "legendFormat": "", + "refId": "A" + }, + { + "expr": "", + "interval": "", + "legendFormat": "", + "refId": "B" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Last exported position", + "transform": "table", + "type": "table-old" + }, + { + "collapsed": false, + "datasource": "Prometheus", + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 56 + }, + "id": 44, + "panels": [], + "title": "Throughput", + "type": "row" + }, + { + "columns": [], + "datasource": null, + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fontSize": "100%", + "gridPos": { + "h": 5, + "w": 12, + "x": 0, + "y": 57 + }, + "hideTimeOverride": false, + "id": 12, + "links": [], + "pageSize": null, + "scroll": true, + "showHeader": true, + "sort": { + "col": 1, + "desc": false + }, + "styles": [ + { + "alias": "Time", + "align": "auto", + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "pattern": "Time", + "type": "date" + }, + { + "alias": "", + "align": "auto", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "decimals": 2, + "pattern": "/.*/", + "thresholds": [], + "type": "number", + "unit": "short" + } + ], + "targets": [ + { + "expr": "sum(rate(zeebe_element_instance_events_total{namespace=~\"$namespace\",partition=~\"$partition\",pod=~\"$pod\", type=\"PROCESS\"}[5m])) by (action)\n", + "format": "table", + "instant": true, + "interval": "", + "intervalFactor": 1, + "legendFormat": "", + "refId": "A" + } + ], + "title": "Workflow Instance Events per second (range = 5m)", + "transform": "table", + "type": "table-old" + }, + { + "columns": [], + "datasource": "$DS_PROMETHEUS", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fontSize": "100%", + "gridPos": { + "h": 5, + "w": 12, + "x": 12, + "y": 57 + }, + "hideTimeOverride": false, + "id": 13, + "links": [], + "pageSize": null, + "scroll": true, + "showHeader": true, + "sort": { + "col": 1, + "desc": false + }, + "styles": [ + { + "alias": "Time", + "align": "auto", + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "pattern": "Time", + "type": "date" + }, + { + "alias": "", + "align": "auto", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "decimals": 2, + "pattern": "/.*/", + "thresholds": [], + "type": "number", + "unit": "short" + } + ], + "targets": [ + { + "expr": "sum(rate(zeebe_job_events_total{namespace=~\"$namespace\",partition=~\"$partition\",pod=~\"$pod\"}[5m])) by (action)", + "format": "table", + "instant": true, + "interval": "", + "intervalFactor": 1, + "legendFormat": "Stream Processor", + "refId": "A" + } + ], + "title": "Job events per second (range = 5m)", + "transform": "table", + "type": "table-old" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$DS_PROMETHEUS", + "fieldConfig": { + "defaults": { + "custom": {}, + "links": [] + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 6, + "w": 12, + "x": 0, + "y": 62 + }, + "hiddenSeries": false, + "id": 2, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "7.4.2", + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(zeebe_element_instance_events_total{namespace=~\"$namespace\",partition=~\"$partition\",pod=~\"$pod\", type=\"PROCESS\"}) by (action)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Workflow Instance ({{action}})", + "refId": "A" + }, + { + "expr": "sum(zeebe_job_events_total{namespace=~\"$namespace\",partition=~\"$partition\",pod=~\"$pod\"}) by (action)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Job ({{action}})", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Workflow Instance Events", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$DS_PROMETHEUS", + "fieldConfig": { + "defaults": { + "custom": {}, + "links": [] + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 6, + "w": 12, + "x": 12, + "y": 62 + }, + "hiddenSeries": false, + "id": 3, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "7.4.2", + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(zeebe_element_instance_events_total{namespace=~\"$namespace\",partition=~\"$partition\",pod=~\"$pod\", type=\"PROCESS\"}[5m])) by (action)", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "Workflow Instance ({{action}})", + "refId": "A" + }, + { + "expr": "sum(rate(zeebe_job_events_total{namespace=~\"$namespace\",partition=~\"$partition\",pod=~\"$pod\"}[5m])) by (action)", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "Job ({{action}})", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Workflow Instance Events per second (range = 5m)", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$DS_PROMETHEUS", + "fieldConfig": { + "defaults": { + "custom": {}, + "links": [] + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 6, + "w": 12, + "x": 0, + "y": 68 + }, + "hiddenSeries": false, + "id": 4, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "7.4.2", + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(zeebe_stream_processor_events_total{namespace=~\"$namespace\",partition=~\"$partition\",pod=~\"$pod\"}) by (action, processor)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{processor}} ({{action}})", + "refId": "A" + }, + { + "expr": "sum(zeebe_exporter_events_total{namespace=~\"$namespace\",partition=~\"$partition\",pod=~\"$pod\"}) by (action, processor)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "exporter ({{action}})", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Stream Processor Events", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$DS_PROMETHEUS", + "fieldConfig": { + "defaults": { + "custom": {}, + "links": [] + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 6, + "w": 12, + "x": 12, + "y": 68 + }, + "hiddenSeries": false, + "id": 5, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "7.4.2", + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(zeebe_stream_processor_events_total{namespace=~\"$namespace\",partition=~\"$partition\",pod=~\"$pod\"}[5m])) by (action, processor)", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "{{processor}} ({{action}})", + "refId": "A" + }, + { + "expr": "sum(rate(zeebe_exporter_events_total{namespace=~\"$namespace\",partition=~\"$partition\",pod=~\"$pod\"}[5m])) by (action, processor)", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "exporter ({{action}})", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Stream Processor Events per second (range = 1m)", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$DS_PROMETHEUS", + "fieldConfig": { + "defaults": { + "custom": {}, + "links": [] + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 5, + "w": 12, + "x": 0, + "y": 74 + }, + "hiddenSeries": false, + "id": 15, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "7.4.2", + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(zeebe_running_workflow_instances_total{namespace=~\"$namespace\",partition=~\"$partition\",pod=~\"$pod\"})", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Workflow Instance", + "refId": "A" + }, + { + "expr": "sum(zeebe_pending_jobs_total{namespace=~\"$namespace\",partition=~\"$partition\",pod=~\"$pod\"})", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Jobs", + "refId": "B" + }, + { + "expr": "sum(zeebe_pending_incidents_total{namespace=~\"$namespace\",partition=~\"$partition\",pod=~\"$pod\"})", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Incidents", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Running Workflow Instances", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$DS_PROMETHEUS", + "fieldConfig": { + "defaults": { + "custom": {}, + "links": [] + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 5, + "w": 12, + "x": 12, + "y": 74 + }, + "hiddenSeries": false, + "id": 18, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "7.4.2", + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(zeebe_stream_processor_events_total{namespace=~\"$namespace\", action=~\"skipped|processed\", partition=~\"$partition\", pod=~\"$pod\"}) - sum(zeebe_exporter_events_total{namespace=~\"$namespace\", partition=~\"$partition\", pod=~\"$pod\"})", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Events processed but not exported", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Stream Processor vs Exporter", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": true, + "datasource": "Prometheus", + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 79 + }, + "id": 100, + "panels": [ + { + "aliasColors": {}, + "bars": false, + "cacheTimeout": null, + "dashLength": 10, + "dashes": false, + "datasource": "$DS_PROMETHEUS", + "description": "Total number of committed snapshots on disk", + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 66 + }, + "hiddenSeries": false, + "id": 102, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pluginVersion": "6.3.5", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "rate(zeebe_snapshot_count{namespace=~\"$namespace\",pod=~\"$pod\",partition=~\"$partition\"}[1m])", + "interval": "", + "legendFormat": "{{pod}} p{{partition}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Snapshot Count", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "cards": { + "cardPadding": null, + "cardRound": null + }, + "color": { + "cardColor": "#b4ff00", + "colorScale": "sqrt", + "colorScheme": "interpolateOranges", + "exponent": 0.5, + "mode": "opacity" + }, + "dataFormat": "tsbuckets", + "datasource": "$DS_PROMETHEUS", + "description": "Approximate duration of taking a single snapshot from the processor point-of-view (without replication or committing).", + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 66 + }, + "heatmap": {}, + "hideZeroBuckets": true, + "highlightCards": true, + "id": 112, + "legend": { + "show": false + }, + "reverseYBuckets": false, + "targets": [ + { + "expr": "sum(increase(zeebe_snapshot_duration_bucket{namespace=~\"$namespace\",pod=~\"$pod\",partition=~\"$partition\"}[30s])) by (le)", + "format": "heatmap", + "interval": "", + "legendFormat": "{{le}}", + "refId": "A" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Snapshot Operation Duration", + "tooltip": { + "show": true, + "showHistogram": false + }, + "type": "heatmap", + "xAxis": { + "show": true + }, + "xBucketNumber": null, + "xBucketSize": null, + "yAxis": { + "decimals": null, + "format": "dtdurations", + "logBase": 1, + "max": null, + "min": null, + "show": true, + "splitFactor": null + }, + "yBucketBound": "auto", + "yBucketNumber": null, + "yBucketSize": null + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$DS_PROMETHEUS", + "description": "Size in bytes of snapshots on disk", + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 74 + }, + "hiddenSeries": false, + "id": 105, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "zeebe_snapshot_size_bytes{namespace=~\"$namespace\",pod=~\"$pod\",partition=~\"$partition\"}", + "legendFormat": "{{pod}} p{{partition}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Snapshot Size", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "decbytes", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "cards": { + "cardPadding": null, + "cardRound": null + }, + "color": { + "cardColor": "#b4ff00", + "colorScale": "sqrt", + "colorScheme": "interpolateSpectral", + "exponent": 0.5, + "mode": "spectrum" + }, + "dataFormat": "tsbuckets", + "datasource": "$DS_PROMETHEUS", + "description": "Distribution of snapshot file sizes - each snapshot may be comprised of many files, and this shows approximately how \"big\" files there are and how many \"small\" files.", + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 74 + }, + "heatmap": {}, + "hideZeroBuckets": true, + "highlightCards": true, + "id": 106, + "legend": { + "show": false + }, + "reverseYBuckets": false, + "targets": [ + { + "expr": "sum(increase(zeebe_snapshot_file_size_megabytes_bucket{namespace=~\"$namespace\",pod=~\"$pod\",partition=~\"$partition\"}[1m])) by (le)", + "format": "heatmap", + "legendFormat": "{{le}}", + "refId": "A" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Snapshot Files Sizes (1m)", + "tooltip": { + "show": true, + "showHistogram": false + }, + "type": "heatmap", + "xAxis": { + "show": true + }, + "xBucketNumber": null, + "xBucketSize": null, + "yAxis": { + "decimals": null, + "format": "decmbytes", + "logBase": 1, + "max": null, + "min": null, + "show": true, + "splitFactor": null + }, + "yBucketBound": "auto", + "yBucketNumber": null, + "yBucketSize": null + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 82 + }, + "hiddenSeries": false, + "id": 182, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "zeebe_snapshot_chunks_count{namespace=~\"$namespace\", pod=~\"$pod\"}", + "interval": "", + "legendFormat": "{{pod}} {{partition}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Number of files in a snapshot", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$DS_PROMETHEUS", + "description": "Approximate duration of replicating a snapshot, from the receiver point-of-view.", + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 82 + }, + "hiddenSeries": false, + "id": 110, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "zeebe_snapshot_replication_duration_milliseconds{namespace=~\"$namespace\",pod=~\"$pod\",partition=~\"$partition\"}", + "legendFormat": "{{pod}} p{{partition}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Snapshot Replication Duration", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "ms", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$DS_PROMETHEUS", + "description": "On-going snapshot replications from the receiver point-of-view.", + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 8, + "w": 24, + "x": 0, + "y": 90 + }, + "hiddenSeries": false, + "id": 108, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "zeebe_snapshot_replication_count{namespace=~\"$namespace\",pod=~\"$pod\",partition=~\"$partition\"}", + "legendFormat": "{{pod}} p{{partition}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Snapshot Replications", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + } + ], + "title": "Snapshots", + "type": "row" + }, + { + "collapsed": false, + "datasource": "Prometheus", + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 80 + }, + "id": 42, + "panels": [], + "title": "Resources", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$DS_PROMETHEUS", + "fieldConfig": { + "defaults": { + "custom": {}, + "links": [] + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 81 + }, + "hiddenSeries": false, + "id": 33, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "7.4.2", + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "container_memory_rss{namespace=~\"$namespace\",pod=~\".*zeebe.*\", container=~\"zeebe.*\"}", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "{{pod}} RSS", + "refId": "A" + } + ], + "thresholds": [ + { + "colorMode": "critical", + "fill": true, + "fillColor": "rgba(50, 116, 217, 0.2)", + "line": true, + "lineColor": "rgba(31, 96, 196, 0.6)", + "op": "gt", + "value": 16000000000, + "yaxis": "left" + } + ], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Process memory usage", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "decbytes", + "label": null, + "logBase": 1, + "max": "16000000000", + "min": "1000000000", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$DS_PROMETHEUS", + "fieldConfig": { + "defaults": { + "custom": {}, + "links": [] + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 81 + }, + "hiddenSeries": false, + "id": 98, + "legend": { + "avg": false, + "current": false, + "hideEmpty": false, + "hideZero": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "7.4.2", + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "jvm_memory_bytes_used{namespace=~\"$namespace\",pod=~\"$pod\",area=\"nonheap\"}", + "format": "time_series", + "hide": true, + "intervalFactor": 1, + "legendFormat": "{{pod}} JVM direct", + "refId": "B" + }, + { + "expr": "jvm_memory_bytes_used{namespace=~\"$namespace\",pod=~\"$pod\",area=\"heap\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{pod}} JVM heap", + "refId": "C" + } + ], + "thresholds": [ + { + "colorMode": "critical", + "fill": true, + "fillColor": "rgba(50, 116, 217, 0.2)", + "line": true, + "lineColor": "rgba(31, 96, 196, 0.6)", + "op": "gt", + "value": 4000000000, + "yaxis": "left" + } + ], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "JVM Memory usage", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "decbytes", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": null, + "fieldConfig": { + "defaults": { + "custom": {}, + "links": [] + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 1, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 89 + }, + "hiddenSeries": false, + "id": 64, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "7.4.2", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum by (pod_name) (rate(container_cpu_usage_seconds_total{namespace=~\"$namespace\", image!=\"\", pod_name=~\"$pod\"}[5m]))", + "interval": "", + "legendFormat": "{{pod_name}}", + "refId": "A" + } + ], + "thresholds": [ + { + "colorMode": "critical", + "fill": true, + "line": true, + "op": "gt", + "value": 7, + "yaxis": "left" + } + ], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "CPU usage", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$DS_PROMETHEUS", + "fieldConfig": { + "defaults": { + "custom": {}, + "links": [] + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 89 + }, + "hiddenSeries": false, + "id": 35, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "7.4.2", + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum (jvm_buffer_pool_used_bytes{namespace=~\"$namespace\",pod=~\"$pod\"}) by (namespace,pod,pool)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Used {{pod}}:{{pool}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Buffer Pool Memory Usage", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "decbytes", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$DS_PROMETHEUS", + "fieldConfig": { + "defaults": { + "custom": {}, + "links": [] + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 97 + }, + "hiddenSeries": false, + "id": 37, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "7.4.2", + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "(process_open_fds{namespace=~\"$namespace\",pod=~\"$pod\"} / process_max_fds{namespace=~\"$namespace\",pod=~\"$pod\"}) * 100", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{pod}} used fds", + "refId": "A" + }, + { + "expr": "", + "format": "time_series", + "intervalFactor": 1, + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "File descriptors", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "percent", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$DS_PROMETHEUS", + "fieldConfig": { + "defaults": { + "custom": {}, + "links": [] + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 97 + }, + "hiddenSeries": false, + "id": 40, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "7.4.2", + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "kubelet_volume_stats_available_bytes{namespace=~\"$namespace\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{persistentvolumeclaim}} ({{namespace}})", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "PVC Disk Available", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "bytes", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$DS_PROMETHEUS", + "fieldConfig": { + "defaults": { + "custom": {}, + "links": [] + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 24, + "x": 0, + "y": 105 + }, + "hiddenSeries": false, + "id": 39, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "7.4.2", + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "(kubelet_volume_stats_used_bytes{namespace=~\"$namespace\", persistentvolumeclaim=~\".*zeebe.*\"} / kubelet_volume_stats_capacity_bytes{namespace=~\"$namespace\", persistentvolumeclaim=~\".*zeebe.*\"})", + "legendFormat": "{{persistentvolumeclaim}}", + "refId": "B" + } + ], + "thresholds": [ + { + "colorMode": "critical", + "fill": true, + "line": true, + "op": "gt", + "value": 0.8, + "yaxis": "left" + } + ], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "PVC Disk Usage", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "percentunit", + "label": null, + "logBase": 1, + "max": "1", + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "datasource": "Prometheus", + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 112 + }, + "id": 120, + "panels": [], + "title": "IO", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$DS_PROMETHEUS", + "description": "Shows the bytes read per second for the zeebe pods in the select namespace.", + "fieldConfig": { + "defaults": { + "custom": {}, + "links": [] + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 113 + }, + "hiddenSeries": false, + "id": 122, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "7.4.2", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(container_fs_reads_bytes_total{namespace=~\"$namespace\", pod=~\"$namespace.*\"}[1m])) by (pod)", + "legendFormat": "{{pod}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Read bytes/s [1m]", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$DS_PROMETHEUS", + "description": "Shows the written bytes per second by the Zeebe pods in the selected namespace.", + "fieldConfig": { + "defaults": { + "custom": {}, + "links": [] + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 113 + }, + "hiddenSeries": false, + "id": 124, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "7.4.2", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(container_fs_writes_bytes_total{namespace=~\"$namespace\", pod=~\"$namespace.*\"}[1m])) by (pod)", + "legendFormat": "{{pod}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Written bytes/s [1m]", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$DS_PROMETHEUS", + "description": "Shows how many bytes the Zeebe Pods transmit per second in the selected namespace.", + "fieldConfig": { + "defaults": { + "custom": {}, + "links": [] + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 121 + }, + "hiddenSeries": false, + "id": 126, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "7.4.2", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(container_network_transmit_bytes_total{namespace=~\"$namespace\", pod=~\"$namespace.*\"}[1m])) by (pod)", + "legendFormat": "{{pod}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Network bytes/s transmitted [1m]", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$DS_PROMETHEUS", + "description": "Shows how many bytes the Zeebe Pods have received per second in the selected namespace.", + "fieldConfig": { + "defaults": { + "custom": {}, + "links": [] + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 121 + }, + "hiddenSeries": false, + "id": 127, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "7.4.2", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(container_network_receive_bytes_total{namespace=~\"$namespace\", pod=~\"$namespace.*\"}[1m])) by (pod)", + "legendFormat": "{{pod}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Network bytes/s received [1m]", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "datasource": "Prometheus", + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 129 + }, + "id": 46, + "panels": [], + "title": "Processing Latency", + "type": "row" + }, + { + "cards": { + "cardPadding": null, + "cardRound": null + }, + "color": { + "cardColor": "#ef843c", + "colorScale": "sqrt", + "colorScheme": "interpolateSpectral", + "exponent": 0.5, + "mode": "spectrum" + }, + "dataFormat": "tsbuckets", + "datasource": "$DS_PROMETHEUS", + "description": "Shows the time (latency) between writing the command on the dispatcher and processing it.", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 12, + "x": 0, + "y": 130 + }, + "heatmap": {}, + "hideZeroBuckets": true, + "highlightCards": true, + "id": 28, + "legend": { + "show": false + }, + "links": [], + "reverseYBuckets": false, + "targets": [ + { + "expr": "sum(increase(zeebe_stream_processor_latency_bucket{namespace=~\"$namespace\",partition=~\"$partition\", recordType=\"COMMAND\"}[5m])) by (le)", + "format": "heatmap", + "interval": "30s", + "intervalFactor": 1, + "legendFormat": "{{le}}", + "refId": "A" + } + ], + "title": "Processing Latency (Command)", + "tooltip": { + "show": true, + "showHistogram": false + }, + "type": "heatmap", + "xAxis": { + "show": true + }, + "xBucketNumber": null, + "xBucketSize": null, + "yAxis": { + "decimals": null, + "format": "dtdurations", + "logBase": 1, + "max": null, + "min": null, + "show": true, + "splitFactor": null + }, + "yBucketBound": "auto", + "yBucketNumber": null, + "yBucketSize": null + }, + { + "cards": { + "cardPadding": null, + "cardRound": null + }, + "color": { + "cardColor": "#ef843c", + "colorScale": "sqrt", + "colorScheme": "interpolateSpectral", + "exponent": 0.5, + "mode": "spectrum" + }, + "dataFormat": "tsbuckets", + "datasource": "$DS_PROMETHEUS", + "description": "Shows the time (latency) between writing the event on the dispatcher and processing it.", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 12, + "x": 12, + "y": 130 + }, + "heatmap": {}, + "hideZeroBuckets": true, + "highlightCards": true, + "id": 29, + "legend": { + "show": false + }, + "links": [], + "reverseYBuckets": false, + "targets": [ + { + "expr": "sum(increase(zeebe_stream_processor_latency_bucket{namespace=~\"$namespace\",partition=~\"$partition\", recordType=\"EVENT\"}[5m])) by (le)", + "format": "heatmap", + "interval": "30s", + "intervalFactor": 1, + "legendFormat": "{{le}}", + "refId": "A" + } + ], + "title": "Processing Latency (Event)", + "tooltip": { + "show": true, + "showHistogram": false + }, + "type": "heatmap", + "xAxis": { + "show": true + }, + "xBucketNumber": null, + "xBucketSize": null, + "yAxis": { + "decimals": null, + "format": "dtdurations", + "logBase": 1, + "max": null, + "min": null, + "show": true, + "splitFactor": null + }, + "yBucketBound": "auto", + "yBucketNumber": null, + "yBucketSize": null + }, + { + "cards": { + "cardPadding": null, + "cardRound": null + }, + "color": { + "cardColor": "#ef843c", + "colorScale": "sqrt", + "colorScheme": "interpolateSpectral", + "exponent": 0.5, + "mode": "spectrum" + }, + "dataFormat": "tsbuckets", + "datasource": "$DS_PROMETHEUS", + "description": "Shows the execution time of a process instance. This means the time (latency) between creating the instance and completing it.", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 24, + "x": 0, + "y": 137 + }, + "heatmap": {}, + "hideZeroBuckets": true, + "highlightCards": true, + "id": 132, + "legend": { + "show": false + }, + "links": [], + "reverseYBuckets": false, + "targets": [ + { + "expr": "sum(increase(zeebe_workflow_instance_execution_time_bucket{namespace=~\"$namespace\",partition=~\"$partition\"}[5m])) by (le)", + "format": "heatmap", + "interval": "30s", + "intervalFactor": 1, + "legendFormat": "{{le}}", + "refId": "A" + } + ], + "title": "Processing Execution Time", + "tooltip": { + "show": true, + "showHistogram": false + }, + "type": "heatmap", + "xAxis": { + "show": true + }, + "xBucketNumber": null, + "xBucketSize": null, + "yAxis": { + "decimals": null, + "format": "dtdurations", + "logBase": 1, + "max": null, + "min": null, + "show": true, + "splitFactor": null + }, + "yBucketBound": "auto", + "yBucketNumber": null, + "yBucketSize": null + }, + { + "cards": { + "cardPadding": null, + "cardRound": null + }, + "color": { + "cardColor": "#ef843c", + "colorScale": "sqrt", + "colorScheme": "interpolateSpectral", + "exponent": 0.5, + "mode": "spectrum" + }, + "dataFormat": "tsbuckets", + "datasource": "$DS_PROMETHEUS", + "description": "Shows the time (latency) between creating the job and activating it.", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 145 + }, + "heatmap": {}, + "hideZeroBuckets": true, + "highlightCards": true, + "id": 133, + "legend": { + "show": false + }, + "links": [], + "reverseYBuckets": false, + "targets": [ + { + "expr": "sum(increase(zeebe_job_activation_time_bucket{namespace=~\"$namespace\",partition=~\"$partition\"}[5m])) by (le)", + "format": "heatmap", + "interval": "30s", + "intervalFactor": 1, + "legendFormat": "{{le}}", + "refId": "A" + } + ], + "title": "Job Activation Time", + "tooltip": { + "show": true, + "showHistogram": false + }, + "type": "heatmap", + "xAxis": { + "show": true + }, + "xBucketNumber": null, + "xBucketSize": null, + "yAxis": { + "decimals": null, + "format": "dtdurations", + "logBase": 1, + "max": null, + "min": null, + "show": true, + "splitFactor": null + }, + "yBucketBound": "auto", + "yBucketNumber": null, + "yBucketSize": null + }, + { + "cards": { + "cardPadding": null, + "cardRound": null + }, + "color": { + "cardColor": "#ef843c", + "colorScale": "sqrt", + "colorScheme": "interpolateSpectral", + "exponent": 0.5, + "mode": "spectrum" + }, + "dataFormat": "tsbuckets", + "datasource": "$DS_PROMETHEUS", + "description": "Shows the complete lifetime of an job. This means the time (latency) between creating the job and completing it.", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 145 + }, + "heatmap": {}, + "hideZeroBuckets": true, + "highlightCards": true, + "id": 135, + "legend": { + "show": false + }, + "links": [], + "reverseYBuckets": false, + "targets": [ + { + "expr": "sum(increase(zeebe_job_life_time_bucket{namespace=~\"$namespace\",partition=~\"$partition\"}[5m])) by (le)", + "format": "heatmap", + "interval": "30s", + "intervalFactor": 1, + "legendFormat": "{{le}}", + "refId": "A" + } + ], + "title": "Job Life Time", + "tooltip": { + "show": true, + "showHistogram": false + }, + "type": "heatmap", + "xAxis": { + "show": true + }, + "xBucketNumber": null, + "xBucketSize": null, + "yAxis": { + "decimals": null, + "format": "dtdurations", + "logBase": 1, + "max": null, + "min": null, + "show": true, + "splitFactor": null + }, + "yBucketBound": "auto", + "yBucketNumber": null, + "yBucketSize": null + }, + { + "collapsed": false, + "datasource": "Prometheus", + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 153 + }, + "id": 48, + "panels": [], + "title": "gRPC", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$DS_PROMETHEUS", + "fieldConfig": { + "defaults": { + "custom": {}, + "links": [] + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 12, + "x": 0, + "y": 154 + }, + "hiddenSeries": false, + "id": 26, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "7.4.2", + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(grpc_server_handled_total{namespace=~\"$namespace\", pod=~\"$pod\"}) by (grpc_method, code)", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "{{grpc_method}} ({{code}})", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "gRPC requests", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$DS_PROMETHEUS", + "fieldConfig": { + "defaults": { + "custom": {}, + "links": [] + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 12, + "x": 12, + "y": 154 + }, + "hiddenSeries": false, + "id": 27, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "7.4.2", + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(grpc_server_handled_total{namespace=~\"$namespace\", pod=~\"$pod\"}[5m])) by (grpc_method, code)", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "{{grpc_method}} ({{code}})", + "refId": "A" + }, + { + "expr": "sum(rate(grpc_server_handled_total{namespace=~\"$namespace\", pod=~\"$pod\"}[5m]))", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "Total requests completed", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "gRPC requests per second (range = 1m)", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "cards": { + "cardPadding": null, + "cardRound": null + }, + "color": { + "cardColor": "#ef843c", + "colorScale": "sqrt", + "colorScheme": "interpolateSpectral", + "exponent": 0.5, + "mode": "spectrum" + }, + "dataFormat": "tsbuckets", + "datasource": null, + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "gridPos": { + "h": 9, + "w": 8, + "x": 0, + "y": 161 + }, + "heatmap": {}, + "hideZeroBuckets": true, + "highlightCards": true, + "id": 22, + "legend": { + "show": false + }, + "links": [], + "reverseYBuckets": false, + "targets": [ + { + "expr": "sum(increase(grpc_server_handled_latency_seconds_bucket{namespace=~\"$namespace\", pod=~\"$pod\", grpc_method=\"CreateWorkflowInstance\"}[5m])) by (le)", + "format": "heatmap", + "interval": "30s", + "intervalFactor": 1, + "legendFormat": "{{le}}", + "refId": "A" + } + ], + "title": "Create Workflow Instance Latency (gRPC)", + "tooltip": { + "show": true, + "showHistogram": false + }, + "type": "heatmap", + "xAxis": { + "show": true + }, + "xBucketNumber": null, + "xBucketSize": null, + "yAxis": { + "decimals": null, + "format": "dtdurations", + "logBase": 1, + "max": null, + "min": null, + "show": true, + "splitFactor": null + }, + "yBucketBound": "auto", + "yBucketNumber": null, + "yBucketSize": null + }, + { + "cards": { + "cardPadding": null, + "cardRound": null + }, + "color": { + "cardColor": "#ef843c", + "colorScale": "sqrt", + "colorScheme": "interpolateSpectral", + "exponent": 0.5, + "mode": "spectrum" + }, + "dataFormat": "tsbuckets", + "datasource": "$DS_PROMETHEUS", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "gridPos": { + "h": 9, + "w": 8, + "x": 8, + "y": 161 + }, + "heatmap": {}, + "hideZeroBuckets": true, + "highlightCards": true, + "id": 23, + "legend": { + "show": false + }, + "links": [], + "reverseYBuckets": false, + "targets": [ + { + "expr": "sum(increase(grpc_server_handled_latency_seconds_bucket{namespace=~\"$namespace\", pod=~\"$pod\", grpc_method=\"ActivateJobs\"}[5m])) by (le)", + "format": "heatmap", + "interval": "30s", + "intervalFactor": 1, + "legendFormat": "{{le}}", + "refId": "A" + } + ], + "title": "Activate Jobs Latency (gRPC)", + "tooltip": { + "show": true, + "showHistogram": false + }, + "type": "heatmap", + "xAxis": { + "show": true + }, + "xBucketNumber": null, + "xBucketSize": null, + "yAxis": { + "decimals": null, + "format": "dtdurations", + "logBase": 1, + "max": null, + "min": null, + "show": true, + "splitFactor": null + }, + "yBucketBound": "auto", + "yBucketNumber": null, + "yBucketSize": null + }, + { + "cards": { + "cardPadding": null, + "cardRound": null + }, + "color": { + "cardColor": "#ef843c", + "colorScale": "sqrt", + "colorScheme": "interpolateSpectral", + "exponent": 0.5, + "mode": "spectrum" + }, + "dataFormat": "tsbuckets", + "datasource": "$DS_PROMETHEUS", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "gridPos": { + "h": 9, + "w": 8, + "x": 16, + "y": 161 + }, + "heatmap": {}, + "hideZeroBuckets": true, + "highlightCards": true, + "id": 24, + "legend": { + "show": false + }, + "links": [], + "reverseYBuckets": false, + "targets": [ + { + "expr": "sum(increase(grpc_server_handled_latency_seconds_bucket{namespace=~\"$namespace\", pod=~\"$pod\", grpc_method=\"CompleteJob\"}[5m])) by (le)", + "format": "heatmap", + "interval": "30s", + "intervalFactor": 1, + "legendFormat": "{{le}}", + "refId": "A" + } + ], + "title": "Complete Job Latency (gRPC)", + "tooltip": { + "show": true, + "showHistogram": false + }, + "type": "heatmap", + "xAxis": { + "show": true + }, + "xBucketNumber": null, + "xBucketSize": null, + "yAxis": { + "decimals": null, + "format": "dtdurations", + "logBase": 1, + "max": null, + "min": null, + "show": true, + "splitFactor": null + }, + "yBucketBound": "auto", + "yBucketNumber": null, + "yBucketSize": null + }, + { + "collapsed": false, + "datasource": "Prometheus", + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 170 + }, + "id": 162, + "panels": [], + "title": "Gateway", + "type": "row" + }, + { + "cards": { + "cardPadding": null, + "cardRound": null + }, + "color": { + "cardColor": "#b4ff00", + "colorScale": "sqrt", + "colorScheme": "interpolateSpectral", + "exponent": 0.5, + "mode": "spectrum" + }, + "dataFormat": "tsbuckets", + "datasource": "$DS_PROMETHEUS", + "description": "Shows the latency (RTT) of a sent from the gateway to the broker.", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 24, + "x": 0, + "y": 171 + }, + "heatmap": {}, + "hideZeroBuckets": true, + "highlightCards": true, + "id": 164, + "legend": { + "show": false + }, + "reverseYBuckets": false, + "targets": [ + { + "expr": "sum(increase(zeebe_gateway_request_latency_bucket{namespace=~\"$namespace\",partition=~\"$partition\"}[5m])) by (le)", + "format": "heatmap", + "interval": "30s", + "legendFormat": "{{le}}", + "refId": "A" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Gateway Request Latency", + "tooltip": { + "show": true, + "showHistogram": false + }, + "type": "heatmap", + "xAxis": { + "show": true + }, + "xBucketNumber": null, + "xBucketSize": null, + "yAxis": { + "decimals": null, + "format": "dtdurations", + "logBase": 1, + "max": null, + "min": null, + "show": true, + "splitFactor": null + }, + "yBucketBound": "auto", + "yBucketNumber": null, + "yBucketSize": null + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": null, + "description": "Shows rate of each error type.", + "fieldConfig": { + "defaults": { + "custom": {}, + "links": [] + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 179 + }, + "hiddenSeries": false, + "id": 166, + "legend": { + "avg": false, + "current": false, + "hideZero": true, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "7.4.2", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "rate(zeebe_gateway_failed_requests{namespace=~\"$namespace\", partition=~\"$partition\", error=~\".*\"}[5m]) / rate(zeebe_gateway_failed_requests{namespace=~\"$namespace\", partition=~\"$partition\"}[5m])", + "interval": "", + "legendFormat": "{{error}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Failure Error Code", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "percentunit", + "label": null, + "logBase": 1, + "max": "1", + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": null, + "description": "Shows failure rate of requests sent from gateway to the broker.", + "fieldConfig": { + "defaults": { + "custom": {}, + "links": [] + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 179 + }, + "hiddenSeries": false, + "id": 168, + "legend": { + "avg": false, + "current": false, + "hideZero": true, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "7.4.2", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum by (requestType) (rate(zeebe_gateway_failed_requests{namespace=~\"$namespace\", partition=~\"$partition\"}[5m])) / \nsum by (requestType) (rate(zeebe_gateway_total_requests{namespace=~\"$namespace\", partition=~\"$partition\"}[5m]))", + "interval": "", + "legendFormat": "{{requestType}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Failure Rate by Request Type", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "percentunit", + "label": null, + "logBase": 1, + "max": "1", + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": true, + "datasource": "Prometheus", + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 187 + }, + "id": 76, + "panels": [ + { + "cards": { + "cardPadding": null, + "cardRound": null + }, + "color": { + "cardColor": "#b4ff00", + "colorScale": "sqrt", + "colorScheme": "interpolateSpectral", + "exponent": 0.5, + "mode": "spectrum" + }, + "dataFormat": "tsbuckets", + "datasource": "$DS_PROMETHEUS", + "gridPos": { + "h": 6, + "w": 12, + "x": 0, + "y": 10 + }, + "heatmap": {}, + "hideZeroBuckets": true, + "highlightCards": true, + "id": 78, + "legend": { + "show": false + }, + "links": [], + "reverseYBuckets": false, + "targets": [ + { + "expr": "sum(increase(atomix_compaction_time_ms_bucket{namespace=~\"$namespace\", pod=~\"$pod\", partition=~\"$partition\"}[5m])) by (le)", + "format": "heatmap", + "intervalFactor": 1, + "legendFormat": "{{le}}", + "refId": "A" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Compacting time", + "tooltip": { + "show": true, + "showHistogram": false + }, + "type": "heatmap", + "xAxis": { + "show": true + }, + "xBucketNumber": null, + "xBucketSize": null, + "yAxis": { + "decimals": null, + "format": "dtdurations", + "logBase": 1, + "max": null, + "min": null, + "show": true, + "splitFactor": null + }, + "yBucketBound": "auto", + "yBucketNumber": null, + "yBucketSize": null + }, + { + "cards": { + "cardPadding": null, + "cardRound": null + }, + "color": { + "cardColor": "#b4ff00", + "colorScale": "sqrt", + "colorScheme": "interpolateSpectral", + "exponent": 0.5, + "mode": "spectrum" + }, + "dataFormat": "tsbuckets", + "datasource": "$DS_PROMETHEUS", + "gridPos": { + "h": 6, + "w": 12, + "x": 12, + "y": 10 + }, + "heatmap": {}, + "hideZeroBuckets": true, + "highlightCards": true, + "id": 81, + "legend": { + "show": false + }, + "links": [], + "reverseYBuckets": false, + "targets": [ + { + "expr": "sum(increase(atomix_segment_creation_time_bucket{namespace=~\"$namespace\", pod=~\"$pod\", partition=~\"$partition\"}[1m])) by (le)", + "format": "heatmap", + "intervalFactor": 1, + "legendFormat": "{{le}}", + "refId": "A" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Segment Creation Time", + "tooltip": { + "show": true, + "showHistogram": false + }, + "type": "heatmap", + "xAxis": { + "show": true + }, + "xBucketNumber": null, + "xBucketSize": null, + "yAxis": { + "decimals": null, + "format": "dtdurations", + "logBase": 1, + "max": null, + "min": null, + "show": true, + "splitFactor": null + }, + "yBucketBound": "auto", + "yBucketNumber": null, + "yBucketSize": null + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$DS_PROMETHEUS", + "description": "Approximate Install RPC as measured by the follower.", + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 12, + "x": 0, + "y": 16 + }, + "hiddenSeries": false, + "id": 79, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "atomix_snapshot_replication_duration_milliseconds{namespace=~\"$namespace\",pod=~\"$pod\",partition=~\"$partition\"}", + "format": "time_series", + "instant": false, + "intervalFactor": 1, + "legendFormat": "{{pod}} p{{partition}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Snapshot Replication Duration", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "ms", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$DS_PROMETHEUS", + "description": "Ongoing snapshot replications per partition, from the follower point-of-view.", + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 12, + "x": 12, + "y": 16 + }, + "hiddenSeries": false, + "id": 114, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "atomix_snapshot_replication_count{namespace=~\"$namespace\",pod=~\"$pod\",partition=~\"$partition\"}", + "legendFormat": "{{pod}} {{partitionGroupName}}-{{partition}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Snapshot Replications", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "cards": { + "cardPadding": null, + "cardRound": null + }, + "color": { + "cardColor": "#b4ff00", + "colorScale": "sqrt", + "colorScheme": "interpolateSpectral", + "exponent": 0.5, + "mode": "spectrum" + }, + "dataFormat": "tsbuckets", + "datasource": "$DS_PROMETHEUS", + "gridPos": { + "h": 7, + "w": 12, + "x": 0, + "y": 23 + }, + "heatmap": {}, + "hideZeroBuckets": true, + "highlightCards": true, + "id": 89, + "legend": { + "show": false + }, + "links": [], + "reverseYBuckets": false, + "targets": [ + { + "expr": "sum(increase(atomix_segment_flush_time_bucket{namespace=~\"$namespace\", pod=~\"$pod\", partition=~\"$partition\"}[1m])) by (le)", + "format": "heatmap", + "intervalFactor": 1, + "legendFormat": "{{le}}", + "refId": "A" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Segment Flush Latency", + "tooltip": { + "show": true, + "showHistogram": false + }, + "type": "heatmap", + "xAxis": { + "show": true + }, + "xBucketNumber": null, + "xBucketSize": null, + "yAxis": { + "decimals": null, + "format": "dtdurations", + "logBase": 1, + "max": null, + "min": null, + "show": true, + "splitFactor": null + }, + "yBucketBound": "auto", + "yBucketNumber": null, + "yBucketSize": null + }, + { + "cards": { + "cardPadding": null, + "cardRound": null + }, + "color": { + "cardColor": "#b4ff00", + "colorScale": "sqrt", + "colorScheme": "interpolateSpectral", + "exponent": 0.5, + "mode": "spectrum" + }, + "dataFormat": "tsbuckets", + "datasource": "$DS_PROMETHEUS", + "gridPos": { + "h": 7, + "w": 12, + "x": 12, + "y": 23 + }, + "heatmap": {}, + "hideZeroBuckets": true, + "highlightCards": true, + "id": 86, + "legend": { + "show": false + }, + "links": [], + "reverseYBuckets": false, + "targets": [ + { + "expr": "sum(increase(atomix_append_entries_latency_bucket{namespace=~\"$namespace\", pod=~\"$pod\", partition=~\"$partition\"}[1m])) by (le)", + "format": "heatmap", + "intervalFactor": 1, + "legendFormat": "{{le}}", + "refId": "A" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Append Entry Latency", + "tooltip": { + "show": true, + "showHistogram": false + }, + "type": "heatmap", + "xAxis": { + "show": true + }, + "xBucketNumber": null, + "xBucketSize": null, + "yAxis": { + "decimals": null, + "format": "dtdurations", + "logBase": 1, + "max": null, + "min": null, + "show": true, + "splitFactor": null + }, + "yBucketBound": "auto", + "yBucketNumber": null, + "yBucketSize": null + }, + { + "cards": { + "cardPadding": null, + "cardRound": null + }, + "color": { + "cardColor": "#b4ff00", + "colorScale": "sqrt", + "colorScheme": "interpolateSpectral", + "exponent": 0.5, + "min": null, + "mode": "spectrum" + }, + "dataFormat": "tsbuckets", + "datasource": "$DS_PROMETHEUS", + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 30 + }, + "heatmap": {}, + "hideZeroBuckets": true, + "highlightCards": true, + "id": 70, + "legend": { + "show": true + }, + "links": [], + "reverseYBuckets": false, + "targets": [ + { + "expr": "sum(increase(atomix_heartbeat_time_in_s_bucket{namespace=~\"$namespace\", pod=~\"$pod\", partition=~\"$partition\"}[1m])) by (le)", + "format": "heatmap", + "instant": false, + "interval": "1m", + "intervalFactor": 1, + "legendFormat": "{{le}}", + "refId": "A" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Time Between Heartbeats", + "tooltip": { + "show": true, + "showHistogram": false + }, + "type": "heatmap", + "xAxis": { + "show": true + }, + "xBucketNumber": null, + "xBucketSize": null, + "yAxis": { + "decimals": null, + "format": "dtdurations", + "logBase": 1, + "max": null, + "min": null, + "show": true, + "splitFactor": null + }, + "yBucketBound": "auto", + "yBucketNumber": null, + "yBucketSize": null + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$DS_PROMETHEUS", + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 30 + }, + "hiddenSeries": false, + "id": 72, + "legend": { + "avg": false, + "current": false, + "hideZero": true, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "sideWidth": 100, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(increase(atomix_heartbeat_miss_count{namespace=~\"$namespace\", partition=~\"$partition\", pod=~\"$pod\"}[1m])) by (pod, partition)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{pod}} - {{partition}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Heartbeat Miss Counts", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "cacheTimeout": null, + "dashLength": 10, + "dashes": false, + "datasource": "$DS_PROMETHEUS", + "decimals": 0, + "fill": 0, + "fillGradient": 0, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 38 + }, + "hiddenSeries": false, + "id": 95, + "legend": { + "alignAsTable": true, + "avg": false, + "current": true, + "hideEmpty": false, + "hideZero": true, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "sideWidth": 300, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pluginVersion": "6.3.5", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "atomix_role{namespace=~\"$namespace\", pod=~\"$pod\", partition=~\"$partition\"}", + "format": "time_series", + "hide": false, + "instant": false, + "intervalFactor": 1, + "legendFormat": "{{pod}} {{partition}} {{partitionGroupName}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Role Changes", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": 0, + "format": "short", + "label": "Role", + "logBase": 1, + "max": "3", + "min": "1", + "show": true + }, + { + "decimals": null, + "format": "short", + "label": "", + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": 1 + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "description": "", + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 38 + }, + "hiddenSeries": false, + "id": 180, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "atomix_segment_count{namespace=~\"$namespace\", pod=~\"$pod\"}", + "interval": "", + "legendFormat": "{{pod}} {{partition}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Number of log segements", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "columns": [ + { + "text": "Current", + "value": "current" + } + ], + "datasource": "$DS_PROMETHEUS", + "fontSize": "100%", + "gridPos": { + "h": 5, + "w": 8, + "x": 0, + "y": 46 + }, + "id": 205, + "maxPerRow": 6, + "pageSize": null, + "pluginVersion": "6.7.1", + "repeat": "partition", + "repeatDirection": "h", + "scopedVars": { + "partition": { + "selected": false, + "text": "1", + "value": "1" + } + }, + "showHeader": true, + "sort": { + "col": 0, + "desc": true + }, + "styles": [ + { + "alias": "Time", + "align": "auto", + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "pattern": "Time", + "type": "date" + }, + { + "alias": "Commit index", + "align": "right", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "decimals": 2, + "mappingType": 1, + "pattern": "Current", + "thresholds": [], + "type": "string", + "unit": "short" + } + ], + "targets": [ + { + "expr": "atomix_partition_raft_commit_index{namespace=~\"$namespace\", pod=~\"$pod\", partition=~\"$partition\"}", + "format": "time_series", + "instant": true, + "interval": "", + "legendFormat": "{{pod}} p{{partition}} ", + "refId": "A" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Commit Index", + "transform": "timeseries_aggregations", + "type": "table-old" + }, + { + "columns": [ + { + "text": "Current", + "value": "current" + } + ], + "datasource": "$DS_PROMETHEUS", + "fontSize": "100%", + "gridPos": { + "h": 5, + "w": 8, + "x": 8, + "y": 46 + }, + "id": 218, + "maxPerRow": 6, + "pageSize": null, + "pluginVersion": "6.7.1", + "repeat": null, + "repeatDirection": "h", + "repeatIteration": 1598954942580, + "repeatPanelId": 205, + "scopedVars": { + "partition": { + "selected": false, + "text": "2", + "value": "2" + } + }, + "showHeader": true, + "sort": { + "col": 0, + "desc": true + }, + "styles": [ + { + "alias": "Time", + "align": "auto", + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "pattern": "Time", + "type": "date" + }, + { + "alias": "Commit index", + "align": "right", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "decimals": 2, + "mappingType": 1, + "pattern": "Current", + "thresholds": [], + "type": "string", + "unit": "short" + } + ], + "targets": [ + { + "expr": "atomix_partition_raft_commit_index{namespace=~\"$namespace\", pod=~\"$pod\", partition=~\"$partition\"}", + "format": "time_series", + "instant": true, + "interval": "", + "legendFormat": "{{pod}} p{{partition}} ", + "refId": "A" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Commit Index", + "transform": "timeseries_aggregations", + "type": "table-old" + }, + { + "columns": [ + { + "text": "Current", + "value": "current" + } + ], + "datasource": "$DS_PROMETHEUS", + "fontSize": "100%", + "gridPos": { + "h": 5, + "w": 8, + "x": 16, + "y": 46 + }, + "id": 219, + "maxPerRow": 6, + "pageSize": null, + "pluginVersion": "6.7.1", + "repeat": null, + "repeatDirection": "h", + "repeatIteration": 1598954942580, + "repeatPanelId": 205, + "scopedVars": { + "partition": { + "selected": false, + "text": "3", + "value": "3" + } + }, + "showHeader": true, + "sort": { + "col": 0, + "desc": true + }, + "styles": [ + { + "alias": "Time", + "align": "auto", + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "pattern": "Time", + "type": "date" + }, + { + "alias": "Commit index", + "align": "right", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "decimals": 2, + "mappingType": 1, + "pattern": "Current", + "thresholds": [], + "type": "string", + "unit": "short" + } + ], + "targets": [ + { + "expr": "atomix_partition_raft_commit_index{namespace=~\"$namespace\", pod=~\"$pod\", partition=~\"$partition\"}", + "format": "time_series", + "instant": true, + "interval": "", + "legendFormat": "{{pod}} p{{partition}} ", + "refId": "A" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Commit Index", + "transform": "timeseries_aggregations", + "type": "table-old" + }, + { + "columns": [ + { + "text": "Current", + "value": "current" + } + ], + "datasource": "$DS_PROMETHEUS", + "fontSize": "100%", + "gridPos": { + "h": 5, + "w": 8, + "x": 0, + "y": 51 + }, + "id": 209, + "maxPerRow": 6, + "pageSize": null, + "pluginVersion": "6.7.1", + "repeat": "partition", + "repeatDirection": "h", + "scopedVars": { + "partition": { + "selected": false, + "text": "1", + "value": "1" + } + }, + "showHeader": true, + "sort": { + "col": 0, + "desc": true + }, + "styles": [ + { + "alias": "Time", + "align": "auto", + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "pattern": "Time", + "type": "date" + }, + { + "alias": "Last appended index", + "align": "right", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "decimals": 2, + "mappingType": 1, + "pattern": "Current", + "thresholds": [], + "type": "string", + "unit": "short" + } + ], + "targets": [ + { + "expr": "atomix_partition_raft_append_index{namespace=~\"$namespace\", pod=~\"$pod\", partition=~\"$partition\"}", + "format": "time_series", + "instant": true, + "interval": "", + "legendFormat": "{{pod}}-p{{partition}}", + "refId": "A" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Index of last appended entry", + "transform": "timeseries_aggregations", + "type": "table-old" + }, + { + "columns": [ + { + "text": "Current", + "value": "current" + } + ], + "datasource": "$DS_PROMETHEUS", + "fontSize": "100%", + "gridPos": { + "h": 5, + "w": 8, + "x": 8, + "y": 51 + }, + "id": 220, + "maxPerRow": 6, + "pageSize": null, + "pluginVersion": "6.7.1", + "repeat": null, + "repeatDirection": "h", + "repeatIteration": 1598954942580, + "repeatPanelId": 209, + "scopedVars": { + "partition": { + "selected": false, + "text": "2", + "value": "2" + } + }, + "showHeader": true, + "sort": { + "col": 0, + "desc": true + }, + "styles": [ + { + "alias": "Time", + "align": "auto", + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "pattern": "Time", + "type": "date" + }, + { + "alias": "Last appended index", + "align": "right", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "decimals": 2, + "mappingType": 1, + "pattern": "Current", + "thresholds": [], + "type": "string", + "unit": "short" + } + ], + "targets": [ + { + "expr": "atomix_partition_raft_append_index{namespace=~\"$namespace\", pod=~\"$pod\", partition=~\"$partition\"}", + "format": "time_series", + "instant": true, + "interval": "", + "legendFormat": "{{pod}}-p{{partition}}", + "refId": "A" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Index of last appended entry", + "transform": "timeseries_aggregations", + "type": "table-old" + }, + { + "columns": [ + { + "text": "Current", + "value": "current" + } + ], + "datasource": "$DS_PROMETHEUS", + "fontSize": "100%", + "gridPos": { + "h": 5, + "w": 8, + "x": 16, + "y": 51 + }, + "id": 221, + "maxPerRow": 6, + "pageSize": null, + "pluginVersion": "6.7.1", + "repeat": null, + "repeatDirection": "h", + "repeatIteration": 1598954942580, + "repeatPanelId": 209, + "scopedVars": { + "partition": { + "selected": false, + "text": "3", + "value": "3" + } + }, + "showHeader": true, + "sort": { + "col": 0, + "desc": true + }, + "styles": [ + { + "alias": "Time", + "align": "auto", + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "pattern": "Time", + "type": "date" + }, + { + "alias": "Last appended index", + "align": "right", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "decimals": 2, + "mappingType": 1, + "pattern": "Current", + "thresholds": [], + "type": "string", + "unit": "short" + } + ], + "targets": [ + { + "expr": "atomix_partition_raft_append_index{namespace=~\"$namespace\", pod=~\"$pod\", partition=~\"$partition\"}", + "format": "time_series", + "instant": true, + "interval": "", + "legendFormat": "{{pod}}-p{{partition}}", + "refId": "A" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Index of last appended entry", + "transform": "timeseries_aggregations", + "type": "table-old" + }, + { + "datasource": "$DS_PROMETHEUS", + "gridPos": { + "h": 5, + "w": 12, + "x": 0, + "y": 56 + }, + "id": 215, + "options": { + "fieldOptions": { + "calcs": [ + "mean" + ], + "defaults": { + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 300 + } + ] + } + }, + "overrides": [], + "values": false + }, + "orientation": "auto", + "showThresholdLabels": false, + "showThresholdMarkers": true + }, + "pluginVersion": "6.7.1", + "targets": [ + { + "expr": "max(atomix_partition_raft_append_index{namespace=~\"$namespace\",partition=~\"$partition\"}) by (partition, namespace) - max(atomix_partition_raft_commit_index{namespace=~\"$namespace\",partition=~\"$partition\"}) by (partition, namespace)", + "interval": "", + "legendFormat": "Partition {{partition}} ({{namespace}})", + "refId": "A" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Number of records appended on the leader but not committed", + "type": "gauge" + }, + { + "datasource": "$DS_PROMETHEUS", + "gridPos": { + "h": 5, + "w": 12, + "x": 12, + "y": 56 + }, + "id": 217, + "options": { + "fieldOptions": { + "calcs": [ + "last" + ], + "defaults": { + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 1000 + } + ] + } + }, + "overrides": [], + "values": false + }, + "orientation": "auto", + "showThresholdLabels": false, + "showThresholdMarkers": true + }, + "pluginVersion": "6.7.1", + "repeat": null, + "repeatDirection": "h", + "targets": [ + { + "expr": "max(atomix_partition_raft_commit_index{namespace=~\"$namespace\",partition=~\"$partition\"}) by (partition, namespace) - min(atomix_partition_raft_commit_index{namespace=~\"$namespace\",partition=~\"$partition\"}) by (partition, namespace)", + "interval": "", + "legendFormat": "Partition {{partition}} ({{namespace}})", + "refId": "A" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Number of records by which the slowest follower is lagging behind", + "type": "gauge" + } + ], + "title": "Atomix", + "type": "row" + }, + { + "collapsed": true, + "datasource": "Prometheus", + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 188 + }, + "id": 140, + "panels": [ + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "description": "Sum of memtable, table reader and cache memory capacity.", + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 12, + "w": 12, + "x": 0, + "y": 10 + }, + "hiddenSeries": false, + "id": 154, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "(sum(zeebe_rocksdb_memory_estimate_table_readers_mem{namespace=~\"$namespace\", pod=~\"$pod\", partition=~\"$partition\"}) by (pod, partition)) + (sum(zeebe_rocksdb_memory_size_all_mem_tables{namespace=~\"$namespace\",pod=~\"$pod\", partition=~\"$partition\"}) by (pod, partition)) + (sum(zeebe_rocksdb_memory_block_cache_capacity{namespace=~\"$namespace\", pod=~\"$pod\", partition=~\"$partition\"}) by (pod, partition))", + "interval": "", + "legendFormat": "{{pod}} Table Reader {{partition}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "RocksDB Memory usage", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "bytes", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "description": "Estimated total number of keys in the database per column family", + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 6, + "w": 12, + "x": 12, + "y": 10 + }, + "hiddenSeries": false, + "id": 144, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "zeebe_rocksdb_live_estimate_num_keys{namespace=~\"$namespace\", partition=~\"$partition\", pod=~\"$pod\"}", + "interval": "", + "legendFormat": "{{pod}} {{partition}} keys {{columnFamilyName}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Estimated Number of Keys", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "description": "Estimated amount of live data in bytes per column family", + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 6, + "w": 12, + "x": 12, + "y": 16 + }, + "hiddenSeries": false, + "id": 142, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "sum(zeebe_rocksdb_live_estimate_live_data_size{namespace=~\"$namespace\", partition=~\"$partition\", pod=~\"$pod\"}) by (pod, partition)", + "interval": "", + "legendFormat": "{{pod}} live data {{partition}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Estimated Live Data", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "bytes", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "description": "Returns approximate size of active, unflushed immutable, and pinned immutable memtables (bytes) per partition.\n\nhttps://github.com/facebook/rocksdb/blob/e66199d848cd484b816d07359f1dc0f0b99e5351/include/rocksdb/db.h#L807", + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 12, + "w": 12, + "x": 0, + "y": 22 + }, + "hiddenSeries": false, + "id": 151, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "sum(zeebe_rocksdb_memory_size_all_mem_tables{namespace=~\"$namespace\", partition=~\"$partition\", pod=~\"$pod\"}) by (pod, partition)", + "interval": "", + "legendFormat": "{{pod}} All Memtable's {{partition}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Approx. size of all mem tables", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "bytes", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "description": "Approximate size of active and unflushed immutable memtables (bytes) per partition.\n\nhttps://github.com/facebook/rocksdb/blob/e66199d848cd484b816d07359f1dc0f0b99e5351/include/rocksdb/db.h#L803", + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 6, + "w": 12, + "x": 12, + "y": 22 + }, + "hiddenSeries": false, + "id": 152, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "sum(zeebe_rocksdb_memory_cur_size_all_mem_tables{namespace=~\"$namespace\",pod=~\"$pod\", partition=~\"$partition\"}) by (pod, partition)", + "interval": "", + "legendFormat": "{{pod}} Memtable {{partition}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Approx. current all mem table size", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "bytes", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "description": "Approximate size of active memtable (bytes) per partition.\n\nhttps://github.com/facebook/rocksdb/blob/e66199d848cd484b816d07359f1dc0f0b99e5351/include/rocksdb/db.h#L799", + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 6, + "w": 12, + "x": 12, + "y": 28 + }, + "hiddenSeries": false, + "id": 150, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "sum(zeebe_rocksdb_memory_cur_size_active_mem_table{namespace=~\"$namespace\", partition=~\"$partition\", pod=~\"$pod\"}) by (pod, partition)", + "interval": "", + "legendFormat": "{{pod}} Memtable {{partition}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Approx. current active mem table size", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "bytes", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "description": "The block cache capacity per column family", + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 13, + "w": 12, + "x": 0, + "y": 34 + }, + "hiddenSeries": false, + "id": 147, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "sum(zeebe_rocksdb_memory_block_cache_capacity{namespace=~\"$namespace\", partition=~\"$partition\", pod=~\"$pod\"}) by (pod, partition)", + "interval": "", + "legendFormat": "{{pod}} Block cache {{partition}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Block cache capacity", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "bytes", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "description": "The current usage of the block cache per column family\n\nhttps://github.com/facebook/rocksdb/blob/618bf638aabce21262228509e9f99c1c13de2b57/include/rocksdb/cache.h#L261", + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 12, + "x": 12, + "y": 34 + }, + "hiddenSeries": false, + "id": 149, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pluginVersion": "6.7.1", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "sum(zeebe_rocksdb_memory_block_cache_usage{namespace=~\"$namespace\", partition=~\"$partition\", pod=~\"$pod\"}) by (pod, partition)", + "interval": "", + "legendFormat": "{{pod}} Block cache usage {{partition}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Block cache usage", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "bytes", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "description": "The current pinned usage of the block cache per column family\n\nhttps://github.com/facebook/rocksdb/blob/618bf638aabce21262228509e9f99c1c13de2b57/include/rocksdb/cache.h#L261", + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 6, + "w": 12, + "x": 12, + "y": 41 + }, + "hiddenSeries": false, + "id": 148, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(zeebe_rocksdb_memory_block_cache_pinned_usage{namespace=~\"$namespace\", partition=~\"$partition\", pod=~\"$pod\"}) by (pod, partition)", + "interval": "", + "legendFormat": "{{pod}} pinned cache {{partition}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Pinned block cache usage", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "bytes", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "description": "Total size (bytes) of all SST files belong to the latest LSM tree.\n\nhttps://github.com/facebook/rocksdb/blob/e66199d848cd484b816d07359f1dc0f0b99e5351/include/rocksdb/db.h#L882", + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 47 + }, + "hiddenSeries": false, + "id": 155, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "sum(zeebe_rocksdb_sst_live_sst_files_size{namespace=~\"$namespace\", partition=~\"$partition\", pod=~\"$pod\"}) by (pod, partition)", + "interval": "", + "legendFormat": "{{pod}} live sst {{partition}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Total size of live SST files", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "bytes", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "description": "Total size (bytes) of all SST files.\n\nWARNING: may slow down online queries if there are too many files.\n\nhttps://github.com/facebook/rocksdb/blob/e66199d848cd484b816d07359f1dc0f0b99e5351/include/rocksdb/db.h#L878", + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 47 + }, + "hiddenSeries": false, + "id": 156, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "sum(zeebe_rocksdb_sst_total_sst_files_size{namespace=~\"$namespace\", partition=~\"$partition\", pod=~\"$pod\"}) by (pod, partition)", + "interval": "", + "legendFormat": "{{pod}} total sst {{partition}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Total size of all SST files", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "bytes", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "columns": [ + { + "text": "Current", + "value": "current" + } + ], + "datasource": "Prometheus", + "description": "Return 1 if write has been stopped.\n\nhttps://github.com/facebook/rocksdb/blob/e66199d848cd484b816d07359f1dc0f0b99e5351/include/rocksdb/db.h#L908", + "fontSize": "100%", + "gridPos": { + "h": 6, + "w": 6, + "x": 0, + "y": 55 + }, + "id": 158, + "pageSize": null, + "pluginVersion": "6.7.1", + "showHeader": true, + "sort": { + "col": 0, + "desc": true + }, + "styles": [ + { + "alias": "Time", + "align": "", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "pattern": "Time", + "thresholds": [], + "type": "date", + "unit": "short" + }, + { + "alias": "Pod", + "align": "", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "mappingType": 1, + "pattern": "Metric", + "thresholds": [], + "type": "number", + "unit": "short" + }, + { + "alias": "Stopped", + "align": "", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "mappingType": 1, + "pattern": "Current", + "thresholds": [ + "0" + ], + "type": "string", + "unit": "short", + "valueMaps": [ + { + "text": "Running", + "value": "0" + }, + { + "text": "Stopped", + "value": "1" + } + ] + } + ], + "targets": [ + { + "expr": "sum(zeebe_rocksdb_writes_is_write_stopped{namespace=~\"$namespace\", partition=~\"$partition\", pod=~\"$pod\"}) by (pod, partition)", + "instant": true, + "interval": "", + "legendFormat": "{{pod}} stopped write {{partition}}", + "refId": "A" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Write stopped", + "transform": "timeseries_aggregations", + "type": "table-old" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "description": "The current actual delayed write rate. 0 means no delay.\n\nhttps://github.com/facebook/rocksdb/blob/e66199d848cd484b816d07359f1dc0f0b99e5351/include/rocksdb/db.h#L905", + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 6, + "w": 6, + "x": 6, + "y": 55 + }, + "hiddenSeries": false, + "id": 157, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "zeebe_rocksdb_writes_actual_delayed_write_rate{namespace=~\"$namespace\", partition=~\"$partition\", pod=~\"$pod\"}", + "interval": "", + "legendFormat": "{{pod}} delayed write {{partition}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Actual write delay rate", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "bytes", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "description": " Return sum of number of entries in all the immutable mem tables.", + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 6, + "w": 12, + "x": 12, + "y": 55 + }, + "hiddenSeries": false, + "id": 146, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "zeebe_rocksdb_live_num_entries_imm_mem_tables{namespace=~\"$namespace\", partition=~\"$partition\", pod=~\"$pod\"}", + "interval": "", + "legendFormat": "{{columnFamilyName}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Number of entries in immutable mem Tables", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "description": "Returns the number of currently running flushes.\n\nhttps://github.com/facebook/rocksdb/blob/e66199d848cd484b816d07359f1dc0f0b99e5351/include/rocksdb/db.h#L783", + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 6, + "x": 0, + "y": 61 + }, + "hiddenSeries": false, + "id": 159, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "sum(zeebe_rocksdb_writes_num_running_flushes{namespace=~\"$namespace\", partition=~\"$partition\", pod=~\"$pod\"}) by (pod, partition)", + "interval": "", + "legendFormat": "{{pod}} flush {{partition}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Running flush", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "description": "The number of currently running compactions.\n\nhttps://github.com/facebook/rocksdb/blob/e66199d848cd484b816d07359f1dc0f0b99e5351/include/rocksdb/db.h#L791", + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 6, + "x": 6, + "y": 61 + }, + "hiddenSeries": false, + "id": 160, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "sum(zeebe_rocksdb_writes_num_running_compactions{namespace=~\"$namespace\", partition=~\"$partition\", pod=~\"$pod\"}) by (pod, partition)", + "interval": "", + "legendFormat": "{{pod}} compaction {{partition}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Running compactions", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "description": "Returns estimated memory used for reading SST tables, excluding memory used in block cache (e.g., filter and index blocks).\n\nhttps://github.com/facebook/rocksdb/blob/e66199d848cd484b816d07359f1dc0f0b99e5351/include/rocksdb/db.h#L832", + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 12, + "x": 12, + "y": 61 + }, + "hiddenSeries": false, + "id": 153, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "sum(zeebe_rocksdb_memory_estimate_table_readers_mem{namespace=~\"$namespace\", partition=~\"$partition\", pod=~\"$pod\"}) by (pod, partition)", + "interval": "", + "legendFormat": "{{pod}} Table Reader {{partition}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Table Reader Memory ", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "bytes", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + } + ], + "title": "RocksDB", + "type": "row" + }, + { + "collapsed": true, + "datasource": "Prometheus", + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 189 + }, + "id": 50, + "panels": [ + { + "cards": { + "cardPadding": null, + "cardRound": null + }, + "color": { + "cardColor": "#ef843c", + "colorScale": "sqrt", + "colorScheme": "interpolateSpectral", + "exponent": 0.5, + "mode": "spectrum" + }, + "dataFormat": "tsbuckets", + "datasource": "$DS_PROMETHEUS", + "gridPos": { + "h": 10, + "w": 8, + "x": 0, + "y": 51 + }, + "heatmap": {}, + "hideZeroBuckets": true, + "highlightCards": true, + "id": 20, + "legend": { + "show": false + }, + "links": [], + "reverseYBuckets": false, + "targets": [ + { + "expr": "sum(increase(zeebe_elasticsearch_exporter_flush_duration_seconds_bucket{namespace=~\"$namespace\", partition=~\"$partition\"}[30s])) by (le)", + "format": "heatmap", + "interval": "30s", + "intervalFactor": 1, + "legendFormat": "{{le}}", + "refId": "A" + } + ], + "title": "Elasticsearch Exporter (Flush Duration)", + "tooltip": { + "show": true, + "showHistogram": false + }, + "type": "heatmap", + "xAxis": { + "show": true + }, + "xBucketNumber": null, + "xBucketSize": null, + "yAxis": { + "decimals": null, + "format": "dtdurations", + "logBase": 1, + "max": null, + "min": null, + "show": true, + "splitFactor": null + }, + "yBucketBound": "auto", + "yBucketNumber": null, + "yBucketSize": null + }, + { + "cards": { + "cardPadding": null, + "cardRound": null + }, + "color": { + "cardColor": "#ef843c", + "colorScale": "sqrt", + "colorScheme": "interpolateSpectral", + "exponent": 0.5, + "mode": "spectrum" + }, + "dataFormat": "tsbuckets", + "datasource": "$DS_PROMETHEUS", + "gridPos": { + "h": 10, + "w": 8, + "x": 8, + "y": 51 + }, + "heatmap": {}, + "hideZeroBuckets": true, + "highlightCards": true, + "id": 21, + "legend": { + "show": false + }, + "links": [], + "reverseYBuckets": false, + "targets": [ + { + "expr": "sum(increase(zeebe_elasticsearch_exporter_bulk_size_bucket{namespace=~\"$namespace\", partition=~\"$partition\"}[30s])) by (le)", + "format": "heatmap", + "interval": "30s", + "intervalFactor": 1, + "legendFormat": "{{le}}", + "refId": "A" + } + ], + "title": "Elasticsearch Exporter (Bulk Size)", + "tooltip": { + "show": true, + "showHistogram": false + }, + "type": "heatmap", + "xAxis": { + "show": true + }, + "xBucketNumber": null, + "xBucketSize": null, + "yAxis": { + "decimals": null, + "format": "short", + "logBase": 1, + "max": null, + "min": null, + "show": true, + "splitFactor": null + }, + "yBucketBound": "auto", + "yBucketNumber": null, + "yBucketSize": null + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$DS_PROMETHEUS", + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 10, + "w": 8, + "x": 16, + "y": 51 + }, + "hiddenSeries": false, + "id": 185, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "zeebe_elasticsearch_exporter_bulk_memory_size{namespace=~\"$namespace\",pod=~\"$pod\",partition=~\"$partition\"}", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "{{pod}} p{{partition}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Elasticsearch Exporter (Bulk Memory Size)", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "bytes", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$DS_PROMETHEUS", + "editable": true, + "error": false, + "fill": 1, + "fillGradient": 0, + "grid": {}, + "gridPos": { + "h": 10, + "w": 24, + "x": 0, + "y": 61 + }, + "height": "400", + "hiddenSeries": false, + "id": 52, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "hideEmpty": false, + "hideZero": false, + "max": true, + "min": true, + "rightSide": false, + "show": true, + "sort": "current", + "sortDesc": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "connected", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "(kubelet_volume_stats_used_bytes{namespace=~\"$namespace\", persistentvolumeclaim=~\"elastic.*\"} / kubelet_volume_stats_capacity_bytes{namespace=~\"$namespace\", persistentvolumeclaim=~\"elastic.*\"})", + "legendFormat": "{{persistentvolumeclaim}}", + "refId": "B" + } + ], + "thresholds": [ + { + "colorMode": "custom", + "fill": true, + "fillColor": "rgba(216, 200, 27, 0.27)", + "op": "gt", + "value": 0.8 + }, + { + "colorMode": "custom", + "fill": true, + "fillColor": "rgba(234, 112, 112, 0.22)", + "op": "gt", + "value": 0.9 + } + ], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Elasticsearch disk usage", + "tooltip": { + "msResolution": false, + "shared": true, + "sort": 2, + "value_type": "cumulative" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "percentunit", + "label": "Disk Usage %", + "logBase": 1, + "max": 1, + "min": 0, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + } + ], + "title": "Elasticsearch Exporter", + "type": "row" + }, + { + "collapsed": true, + "datasource": "Prometheus", + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 190 + }, + "id": 176, + "panels": [ + { + "datasource": "Prometheus", + "description": "Time taken to start and bootstrap partition servers.", + "gridPos": { + "h": 6, + "w": 8, + "x": 0, + "y": 12 + }, + "id": 170, + "maxPerRow": 6, + "options": { + "displayMode": "basic", + "fieldOptions": { + "calcs": [ + "last" + ], + "defaults": { + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "#EAB839", + "value": 60000 + }, + { + "color": "red", + "value": 120000 + } + ] + }, + "unit": "dtdurationms" + }, + "overrides": [], + "values": false + }, + "orientation": "horizontal", + "showUnfilled": true + }, + "pluginVersion": "6.7.1", + "repeat": "pod", + "repeatDirection": "h", + "scopedVars": { + "pod": { + "selected": false, + "text": "dd-test-startup-metrics-zeebe-0", + "value": "dd-test-startup-metrics-zeebe-0" + } + }, + "targets": [ + { + "expr": "atomix_partition_server_startup_time{namespace=~\"$namespace\", pod=~\"$pod\", partition=~\"$partition\"}", + "interval": "", + "legendFormat": " Start {{pod}} p{{partition}}", + "refId": "A" + }, + { + "expr": "atomix_partition_server_bootstrap_time{namespace=~\"$namespace\", pod=~\"$pod\", partition=~\"$partition\"}", + "interval": "", + "legendFormat": "Bootstrap {{pod}} p{{partition}}", + "refId": "B" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Atomix Partition Server Startup time", + "type": "bargauge" + }, + { + "datasource": "Prometheus", + "description": "Time taken to start and bootstrap partition servers.", + "gridPos": { + "h": 6, + "w": 8, + "x": 8, + "y": 12 + }, + "id": 183, + "maxPerRow": 6, + "options": { + "displayMode": "basic", + "fieldOptions": { + "calcs": [ + "last" + ], + "defaults": { + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "#EAB839", + "value": 60000 + }, + { + "color": "red", + "value": 120000 + } + ] + }, + "unit": "dtdurationms" + }, + "overrides": [], + "values": false + }, + "orientation": "horizontal", + "showUnfilled": true + }, + "pluginVersion": "6.7.1", + "repeat": null, + "repeatDirection": "h", + "repeatIteration": 1596122668847, + "repeatPanelId": 170, + "scopedVars": { + "pod": { + "selected": false, + "text": "dd-test-startup-metrics-zeebe-1", + "value": "dd-test-startup-metrics-zeebe-1" + } + }, + "targets": [ + { + "expr": "atomix_partition_server_startup_time{namespace=~\"$namespace\", pod=~\"$pod\", partition=~\"$partition\"}", + "interval": "", + "legendFormat": " Start {{pod}} p{{partition}}", + "refId": "A" + }, + { + "expr": "atomix_partition_server_bootstrap_time{namespace=~\"$namespace\", pod=~\"$pod\", partition=~\"$partition\"}", + "interval": "", + "legendFormat": "Bootstrap {{pod}} p{{partition}}", + "refId": "B" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Atomix Partition Server Startup time", + "type": "bargauge" + }, + { + "datasource": "Prometheus", + "description": "Time taken to start and bootstrap partition servers.", + "gridPos": { + "h": 6, + "w": 8, + "x": 16, + "y": 12 + }, + "id": 184, + "maxPerRow": 6, + "options": { + "displayMode": "basic", + "fieldOptions": { + "calcs": [ + "last" + ], + "defaults": { + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "#EAB839", + "value": 60000 + }, + { + "color": "red", + "value": 120000 + } + ] + }, + "unit": "dtdurationms" + }, + "overrides": [], + "values": false + }, + "orientation": "horizontal", + "showUnfilled": true + }, + "pluginVersion": "6.7.1", + "repeat": null, + "repeatDirection": "h", + "repeatIteration": 1596122668847, + "repeatPanelId": 170, + "scopedVars": { + "pod": { + "selected": false, + "text": "dd-test-startup-metrics-zeebe-2", + "value": "dd-test-startup-metrics-zeebe-2" + } + }, + "targets": [ + { + "expr": "atomix_partition_server_startup_time{namespace=~\"$namespace\", pod=~\"$pod\", partition=~\"$partition\"}", + "interval": "", + "legendFormat": " Start {{pod}} p{{partition}}", + "refId": "A" + }, + { + "expr": "atomix_partition_server_bootstrap_time{namespace=~\"$namespace\", pod=~\"$pod\", partition=~\"$partition\"}", + "interval": "", + "legendFormat": "Bootstrap {{pod}} p{{partition}}", + "refId": "B" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Atomix Partition Server Startup time", + "type": "bargauge" + }, + { + "datasource": "Prometheus", + "description": "Time taken to recover and reprocess events", + "gridPos": { + "h": 5, + "w": 24, + "x": 0, + "y": 18 + }, + "id": 174, + "options": { + "displayMode": "basic", + "fieldOptions": { + "calcs": [ + "last" + ], + "defaults": { + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 60000 + } + ] + }, + "unit": "dtdurationms" + }, + "overrides": [], + "values": false + }, + "orientation": "horizontal", + "showUnfilled": true + }, + "pluginVersion": "6.7.1", + "targets": [ + { + "expr": "zeebe_stream_processor_startup_recovery_time{namespace=~\"$namespace\", pod=~\"$pod\", partition=~\"$partition\"}", + "interval": "", + "legendFormat": "{{pod}} p{{partition}}", + "refId": "A" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Streamprocessor Recovery Time", + "type": "bargauge" + } + ], + "title": "Start up", + "type": "row" + } + ], + "refresh": "5s", + "schemaVersion": 27, + "style": "dark", + "tags": [], + "templating": { + "list": [ + { + "current": { + "selected": true, + "text": "Prometheus", + "value": "Prometheus" + }, + "description": null, + "error": null, + "hide": 0, + "includeAll": false, + "label": "datasource", + "multi": false, + "name": "DS_PROMETHEUS", + "options": [], + "query": "prometheus", + "queryValue": "", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "type": "datasource" + }, + { + "allValue": ".*", + "current": { + "selected": false, + "text": "All", + "value": "$__all" + }, + "datasource": "Prometheus", + "definition": "label_values(atomix_role, namespace)", + "description": null, + "error": null, + "hide": 0, + "includeAll": true, + "label": null, + "multi": false, + "name": "namespace", + "options": [], + "query": { + "query": "label_values(atomix_role, namespace)", + "refId": "Prometheus-namespace-Variable-Query" + }, + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 1, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": ".*", + "current": { + "selected": false, + "text": "All", + "value": "$__all" + }, + "datasource": "Prometheus", + "definition": "label_values(atomix_role{namespace=~\"$namespace\"}, pod)", + "description": null, + "error": null, + "hide": 0, + "includeAll": true, + "label": null, + "multi": true, + "name": "pod", + "options": [], + "query": { + "query": "label_values(atomix_role{namespace=~\"$namespace\"}, pod)", + "refId": "Prometheus-pod-Variable-Query" + }, + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 1, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": ".*", + "current": { + "selected": true, + "text": [ + "All" + ], + "value": [ + "$__all" + ] + }, + "datasource": "Prometheus", + "definition": "label_values(atomix_role{namespace=~\"$namespace\", pod=~\"$pod\"}, partition)", + "description": null, + "error": null, + "hide": 0, + "includeAll": true, + "label": null, + "multi": true, + "name": "partition", + "options": [], + "query": { + "query": "label_values(atomix_role{namespace=~\"$namespace\", pod=~\"$pod\"}, partition)", + "refId": "Prometheus-partition-Variable-Query" + }, + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 1, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + } + ] + }, + "time": { + "from": "now-1h", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "", + "title": "Zeebe", + "uid": "I4lo7_EZk", + "version": 13 +} \ No newline at end of file diff --git a/ph-ee-env-template/helm/g2p-sandbox-security/Chart.yaml b/ph-ee-env-template/helm/g2p-sandbox-security/Chart.yaml new file mode 100644 index 000000000..488d74917 --- /dev/null +++ b/ph-ee-env-template/helm/g2p-sandbox-security/Chart.yaml @@ -0,0 +1,14 @@ +apiVersion: v2 +description: PaymentHub EE Barebone Edition +type: application +name: ph-ee-g2psandbox-security +version: 0.0.0 +appVersion: 0.0.0 + +dependencies: +- name: ph-ee-engine + repository: https://fynarfin.io/images/ph-ee-engine-0.0.0-SNAPSHOT + version: 0.0.0-SNAPSHOT +- name: konga + version: 1.0.0 + repository: https://fynarfin.io/images/konga/ diff --git a/ph-ee-env-template/helm/g2p-sandbox-security/README.md b/ph-ee-env-template/helm/g2p-sandbox-security/README.md new file mode 100644 index 000000000..5f69c0ac8 --- /dev/null +++ b/ph-ee-env-template/helm/g2p-sandbox-security/README.md @@ -0,0 +1,2 @@ +Helm Upgrade command ----> +hehelm upgrade -f helm/g2p-sandbox-security/values.yaml g2p-sandbox-security helm/g2p-sandbox-security --install --create-namespace --namespace security \ No newline at end of file diff --git a/ph-ee-env-template/helm/g2p-sandbox-security/templates/config.yml b/ph-ee-env-template/helm/g2p-sandbox-security/templates/config.yml new file mode 100644 index 000000000..98f65ae95 --- /dev/null +++ b/ph-ee-env-template/helm/g2p-sandbox-security/templates/config.yml @@ -0,0 +1,6 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: ph-ee-config +data: +{{ (.Files.Glob "config/**.properties").AsConfig | nindent 2 }} diff --git a/ph-ee-env-template/helm/g2p-sandbox-security/values.yaml b/ph-ee-env-template/helm/g2p-sandbox-security/values.yaml new file mode 100644 index 000000000..cb950ae33 --- /dev/null +++ b/ph-ee-env-template/helm/g2p-sandbox-security/values.yaml @@ -0,0 +1,123 @@ +ph-ee-engine: + ingress: + apiversion: "networking.k8s.io/v1" + + deployment: + apiversion: "apps/v1" + + service: + apiversion: "v1" + + secret: + apiversion: "v1" + + configmap: + apiversion: "v1" + + camunda-platform-helm: + enabled: false + + zeebe-operate-helm: + enabled: false + + ph_ee_connector_gsma: + enabled: false + + notifications: + enabled: false + + channel: + enabled: false + ingress: + enabled: false + + operations_web: + enabled: false + ingress: + enabled: false + + operations_app: + enabled: false + ingress: + enabled: false + + operations: + mysql: + enabled: false + + connector_bulk: + enabled: false + ingress: + enabled: false + + importer_es: + enabled: false + + importer_rdbms: + enabled: false + + zeebe_ops: + enabled: false + + elasticsearch: + enabled: false + + mockpayment: + enabled: false + + kibana: + enabled: false + + redis: + enabled: false + + keycloak: + enabled: true + ingress: + enabled: false + ingressClassName: "kong" + rules: + - host: 'keycloak.sandbox.mifos.io' + paths: + - path: / + pathType: Prefix + tls: [] + + kong: + enabled: true + image: + repository: revomatico/docker-kong-oidc + tag: "latest" + env: + plugins: "bundled,oidc" + admin: + enabled: true + http: + enabled: true + tls: + enabled: false + ingress: + enabled: false + hostname: admin-kong.sandbox.mifos.io + gateway: + serviceMonitor: + enabled: true + ingressController: # enable Kong as an Ingress controller + enabled: true + env: + kong_admin_tls_skip_verify: false + installCRDs: false + podAnnotations: + prometheus.io/scrape: "true" # Ask Prometheus to scrape the + prometheus.io/port: "8100" # Kong pods for metrics + + kafka: + enabled: false + provisioning: + enabled: false + + post_installation_job: + enabled: false + + minio: + enabled: false diff --git a/ph-ee-env-template/helm/g2p-sandbox/Chart.yaml b/ph-ee-env-template/helm/g2p-sandbox/Chart.yaml new file mode 100644 index 000000000..dd32fe183 --- /dev/null +++ b/ph-ee-env-template/helm/g2p-sandbox/Chart.yaml @@ -0,0 +1,15 @@ +apiVersion: v2 +description: PaymentHub EE Barebone Edition +type: application +name: ph-ee-g2psandbox +version: 0.0.0 +appVersion: 0.0.0 + +dependencies: +- name: ph-ee-engine + repository: https://fynarfin.io/images/ph-ee-engine-0.0.0-SNAPSHOT + version: 0.0.0-SNAPSHOT + +- name: account_mapper + version: 1.0.0 + repository: "file://../identity-account-mapper/account-mapper" diff --git a/ph-ee-env-template/helm/g2p-sandbox/README.md b/ph-ee-env-template/helm/g2p-sandbox/README.md new file mode 100644 index 000000000..0c53c5dab --- /dev/null +++ b/ph-ee-env-template/helm/g2p-sandbox/README.md @@ -0,0 +1,19 @@ +Helm Upgrade command ----> +helm upgrade -f helm/g2p-sandbox/values.yaml g2pconnect helm/g2p-sandbox --install --create-namespace --namespace paymenthub + +Known Issue +Migration script race condition Operation app startup issue work around +1. port forward ops-mysql -3307 +2. connect the mysql with root passwrod +3. delete tenants +4. Run the SQL scripts which didn’t run successfully + +CREATE DATABASE `tenants`; +GRANT ALL PRIVILEGES ON `tenants`.* TO 'mifos'; +CREATE DATABASE `rhino`; +CREATE DATABASE `gorilla`; +GRANT ALL PRIVILEGES ON `rhino`.* TO 'mifos'; +GRANT ALL PRIVILEGES ON `gorilla`.* TO 'mifos'; +GRANT ALL ON *.* TO 'root'@'%'; + +5. restart ops-app pod diff --git a/ph-ee-env-template/helm/g2p-sandbox/config/application-bb.properties b/ph-ee-env-template/helm/g2p-sandbox/config/application-bb.properties new file mode 100644 index 000000000..420765525 --- /dev/null +++ b/ph-ee-env-template/helm/g2p-sandbox/config/application-bb.properties @@ -0,0 +1,9 @@ +store.local.interop.host=https://rhino.mifos.g2pconnect.io +store.local.customer.host=https://rhino.mifos.g2pconnect.io +zeebe.broker.contactpoint={{ .Release.Name }}-zeebe-gateway:26500 + +security.oauth2.resource.jwt.key-uri=http://ops-bk.mifos.g2pconnect.io/oauth/token_key +rest.authorization.enabled=false +rest.authorization.host=http://ops-bk.mifos.g2pconnect.io + +dfspids=rhino, gorilla diff --git a/ph-ee-env-template/helm/g2p-sandbox/config/application-fin12.properties b/ph-ee-env-template/helm/g2p-sandbox/config/application-fin12.properties new file mode 100644 index 000000000..f31c09b5e --- /dev/null +++ b/ph-ee-env-template/helm/g2p-sandbox/config/application-fin12.properties @@ -0,0 +1,2 @@ +ams.localenabled=true +zeebe.broker.contactpoint={{ .Release.Name }}-zeebe-gateway:26500 \ No newline at end of file diff --git a/ph-ee-env-template/helm/g2p-sandbox/config/application-tenants.properties b/ph-ee-env-template/helm/g2p-sandbox/config/application-tenants.properties new file mode 100644 index 000000000..11db7207e --- /dev/null +++ b/ph-ee-env-template/helm/g2p-sandbox/config/application-tenants.properties @@ -0,0 +1,8 @@ +bpmns.tenants[0].id= rhino +bpmns.tenants[0].flows.payment-transfer= minimal_mock_fund_transfer_account_lookup-{dfspid} +bpmns.tenants[1].id= gorilla +bpmns.tenants[1].flows.payment-transfer= minimal_mock_fund_transfer-{dfspid} +bpmns.tenants[1].flows.outbound-transfer-request= minimal_mock_transfer_request-{dfspid} +bpmns.tenants[2].id= wakanda +bpmns.tenants[2].flows.payment-transfer= PayerFundTransfer-{dfspid} +bpmns.tenants[2].flows.outbound-transfer-request= {ps}_flow_{ams}-{dfspid} diff --git a/ph-ee-env-template/helm/g2p-sandbox/config/application-tenantsConnection.properties b/ph-ee-env-template/helm/g2p-sandbox/config/application-tenantsConnection.properties new file mode 100644 index 000000000..e47580a31 --- /dev/null +++ b/ph-ee-env-template/helm/g2p-sandbox/config/application-tenantsConnection.properties @@ -0,0 +1,156 @@ +tenants.connections[0].auto_update=true +tenants.connections[0].deadlock_max_retries=0 +tenants.connections[0].deadlock_max_retry_interval=1 +tenants.connections[0].driver_class=com.mysql.cj.jdbc.Driver +tenants.connections[0].jdbcProtocol=jdbc +tenants.connections[0].jdbcSubProtocol=mysql +tenants.connections[0].name=gorilla +tenants.connections[0].pool_abandon_when_percentage_full=50 +tenants.connections[0].pool_initial_size=5 +tenants.connections[0].pool_log_abandoned=1 +tenants.connections[0].pool_max_active=40 +tenants.connections[0].pool_max_idle=10 +tenants.connections[0].pool_min_evictable_idle_time_millis=60000 +tenants.connections[0].pool_min_idle=20 +tenants.connections[0].pool_remove_abandoned=1 +tenants.connections[0].pool_remove_abandoned_timeout=60 +tenants.connections[0].pool_suspect_timeout=60 +tenants.connections[0].pool_test_on_borrow=1 +tenants.connections[0].pool_time_between_eviction_runs_millis=34000 +tenants.connections[0].pool_validation_interval=30000 +tenants.connections[0].schema_connection_parameters=null +tenants.connections[0].schema_name=gorilla +tenants.connections[0].schema_password=password +tenants.connections[0].schema_server=operationsmysql +tenants.connections[0].schema_server_port=3306 +tenants.connections[0].schema_username=mifos +tenants.connections[1].auto_update=true +tenants.connections[1].deadlock_max_retries=0 +tenants.connections[1].deadlock_max_retry_interval=1 +tenants.connections[1].driver_class=com.mysql.cj.jdbc.Driver +tenants.connections[1].jdbcProtocol=jdbc +tenants.connections[1].jdbcSubProtocol=mysql +tenants.connections[1].name=rhino +tenants.connections[1].pool_abandon_when_percentage_full=50 +tenants.connections[1].pool_initial_size=5 +tenants.connections[1].pool_log_abandoned=1 +tenants.connections[1].pool_max_active=40 +tenants.connections[1].pool_max_idle=10 +tenants.connections[1].pool_min_evictable_idle_time_millis=60000 +tenants.connections[1].pool_min_idle=20 +tenants.connections[1].pool_remove_abandoned=1 +tenants.connections[1].pool_remove_abandoned_timeout=60 +tenants.connections[1].pool_suspect_timeout=60 +tenants.connections[1].pool_test_on_borrow=1 +tenants.connections[1].pool_time_between_eviction_runs_millis=34000 +tenants.connections[1].pool_validation_interval=30000 +tenants.connections[1].schema_connection_parameters=null +tenants.connections[1].schema_name=rhino +tenants.connections[1].schema_password=password +tenants.connections[1].schema_server=operationsmysql +tenants.connections[1].schema_server_port=3306 +tenants.connections[1].schema_username=mifos +tenants.connections[2].auto_update=true +tenants.connections[2].deadlock_max_retries=0 +tenants.connections[2].deadlock_max_retry_interval=1 +tenants.connections[2].driver_class=com.mysql.cj.jdbc.Driver +tenants.connections[2].jdbcProtocol=jdbc +tenants.connections[2].jdbcSubProtocol=mysql +tenants.connections[2].name=wakanda +tenants.connections[2].pool_abandon_when_percentage_full=50 +tenants.connections[2].pool_initial_size=5 +tenants.connections[2].pool_log_abandoned=1 +tenants.connections[2].pool_max_active=40 +tenants.connections[2].pool_max_idle=10 +tenants.connections[2].pool_min_evictable_idle_time_millis=60000 +tenants.connections[2].pool_min_idle=20 +tenants.connections[2].pool_remove_abandoned=1 +tenants.connections[2].pool_remove_abandoned_timeout=60 +tenants.connections[2].pool_suspect_timeout=60 +tenants.connections[2].pool_test_on_borrow=1 +tenants.connections[2].pool_time_between_eviction_runs_millis=34000 +tenants.connections[2].pool_validation_interval=30000 +tenants.connections[2].schema_connection_parameters=null +tenants.connections[2].schema_name=wakanda +tenants.connections[2].schema_password=password +tenants.connections[2].schema_server=operationsmysql +tenants.connections[2].schema_server_port=3306 +tenants.connections[2].schema_username=mifos +tenants.connections[3].auto_update=true +tenants.connections[3].deadlock_max_retries=0 +tenants.connections[3].deadlock_max_retry_interval=1 +tenants.connections[3].driver_class=com.mysql.cj.jdbc.Driver +tenants.connections[3].jdbcProtocol=jdbc +tenants.connections[3].jdbcSubProtocol=mysql +tenants.connections[3].name=pluto +tenants.connections[3].pool_abandon_when_percentage_full=50 +tenants.connections[3].pool_initial_size=5 +tenants.connections[3].pool_log_abandoned=1 +tenants.connections[3].pool_max_active=40 +tenants.connections[3].pool_max_idle=10 +tenants.connections[3].pool_min_evictable_idle_time_millis=60000 +tenants.connections[3].pool_min_idle=20 +tenants.connections[3].pool_remove_abandoned=1 +tenants.connections[3].pool_remove_abandoned_timeout=60 +tenants.connections[3].pool_suspect_timeout=60 +tenants.connections[3].pool_test_on_borrow=1 +tenants.connections[3].pool_time_between_eviction_runs_millis=34000 +tenants.connections[3].pool_validation_interval=30000 +tenants.connections[3].schema_connection_parameters=null +tenants.connections[3].schema_name=pluto +tenants.connections[3].schema_password=password +tenants.connections[3].schema_server=operationsmysql +tenants.connections[3].schema_server_port=3306 +tenants.connections[3].schema_username=mifos +tenants.connections[4].auto_update=true +tenants.connections[4].deadlock_max_retries=0 +tenants.connections[4].deadlock_max_retry_interval=1 +tenants.connections[4].driver_class=com.mysql.cj.jdbc.Driver +tenants.connections[4].jdbcProtocol=jdbc +tenants.connections[4].jdbcSubProtocol=mysql +tenants.connections[4].name=venus +tenants.connections[4].pool_abandon_when_percentage_full=50 +tenants.connections[4].pool_initial_size=5 +tenants.connections[4].pool_log_abandoned=1 +tenants.connections[4].pool_max_active=40 +tenants.connections[4].pool_max_idle=10 +tenants.connections[4].pool_min_evictable_idle_time_millis=60000 +tenants.connections[4].pool_min_idle=20 +tenants.connections[4].pool_remove_abandoned=1 +tenants.connections[4].pool_remove_abandoned_timeout=60 +tenants.connections[4].pool_suspect_timeout=60 +tenants.connections[4].pool_test_on_borrow=1 +tenants.connections[4].pool_time_between_eviction_runs_millis=34000 +tenants.connections[4].pool_validation_interval=30000 +tenants.connections[4].schema_connection_parameters=null +tenants.connections[4].schema_name=venus +tenants.connections[4].schema_password=password +tenants.connections[4].schema_server=operationsmysql +tenants.connections[4].schema_server_port=3306 +tenants.connections[4].schema_username=mifos +tenants.connections[5].auto_update=true +tenants.connections[5].deadlock_max_retries=0 +tenants.connections[5].deadlock_max_retry_interval=1 +tenants.connections[5].driver_class=com.mysql.cj.jdbc.Driver +tenants.connections[5].jdbcProtocol=jdbc +tenants.connections[5].jdbcSubProtocol=mysql +tenants.connections[5].name=jupiter +tenants.connections[5].pool_abandon_when_percentage_full=50 +tenants.connections[5].pool_initial_size=5 +tenants.connections[5].pool_log_abandoned=1 +tenants.connections[5].pool_max_active=40 +tenants.connections[5].pool_max_idle=10 +tenants.connections[5].pool_min_evictable_idle_time_millis=60000 +tenants.connections[5].pool_min_idle=20 +tenants.connections[5].pool_remove_abandoned=1 +tenants.connections[5].pool_remove_abandoned_timeout=60 +tenants.connections[5].pool_suspect_timeout=60 +tenants.connections[5].pool_test_on_borrow=1 +tenants.connections[5].pool_time_between_eviction_runs_millis=34000 +tenants.connections[5].pool_validation_interval=30000 +tenants.connections[5].schema_connection_parameters=null +tenants.connections[5].schema_name=jupiter +tenants.connections[5].schema_password=password +tenants.connections[5].schema_server=operationsmysql +tenants.connections[5].schema_server_port=3306 +tenants.connections[5].schema_username=mifos diff --git a/ph-ee-env-template/helm/g2p-sandbox/templates/config.yml b/ph-ee-env-template/helm/g2p-sandbox/templates/config.yml new file mode 100644 index 000000000..98f65ae95 --- /dev/null +++ b/ph-ee-env-template/helm/g2p-sandbox/templates/config.yml @@ -0,0 +1,6 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: ph-ee-config +data: +{{ (.Files.Glob "config/**.properties").AsConfig | nindent 2 }} diff --git a/ph-ee-env-template/helm/g2p-sandbox/values.yaml b/ph-ee-env-template/helm/g2p-sandbox/values.yaml new file mode 100644 index 000000000..96f5fdb00 --- /dev/null +++ b/ph-ee-env-template/helm/g2p-sandbox/values.yaml @@ -0,0 +1,651 @@ +ph-ee-engine: + ingress: + apiversion: "networking.k8s.io/v1" + + deployment: + apiversion: "apps/v1" + + service: + apiversion: "v1" + + secret: + apiversion: "v1" + + configmap: + apiversion: "v1" + + global: + SPRING_PROFILES_ACTIVE: "bb" + imagePullPolicy: "Always" + LOGGING_LEVEL_ROOT: "INFO" + LOGGING_PATTERN_CONSOLE: "%d{dd-MM-yyyy HH:mm:ss.SSS} %magenta([%thread]) %highlight(%-5level) %logger.%M - %msg%n" + tenants: "rhino,gorilla,wakanda,pluto,venus,jupiter" + DFSPIDS: "wakanda,pluto,venus,jupiter,gorilla" + + zeebe-operate-helm: + enabled: true + image: + repository: camunda/operate + tag: 1.1.0 + global: + elasticsearch: + host: "ph-ee-elasticsearch" + clusterName: "ph-ee-elasticsearch" + ingress: + enabled: false + annotations: + kubernetes.io/ingress.class: nginx + path: / + host: operate.sandbox.mifos.io + tls: + enabled: true + + elasticsearch: + enabled: true + #Single Node Solution + clusterHealthCheckParams: "wait_for_status=yellow&timeout=100s" + protocol: http + master: + readinessProbe: + httpGet: + allow-insecure: true + username: elastic + password: "{{ .Env.ELASTIC_PASSWORD }}" + path: /_cluster/health?wait_for_status=yellow&timeout=5s + port: 9200 + initialDelaySeconds: 30 + data: + readinessProbe: + httpGet: + allow-insecure: true + username: elastic + password: "{{ .Env.ELASTIC_PASSWORD }}" + path: /_cluster/health?wait_for_status=yellow&timeout=5s + port: 9200 + initialDelaySeconds: 30 + # Shrink default JVM heap. + esJavaOpts: "-Xmx512m -Xms512m" + # Allocate smaller chunks of memory per pod. + resources: + requests: + cpu: "100m" + memory: "1024M" + limits: + cpu: "1000m" + memory: "1024M" + volumeClaimTemplate: + accessModes: [ "ReadWriteOnce" ] + storageClassName: "gp2" + resources: + requests: + storage: 10Gi + + kibana: + enabled: true + readinessProbe: + initialDelaySeconds: 45 + timeoutSeconds: 15 + successThreshold: 1 + protocol: http + ingress: + enabled: false + className: "nginx" + pathtype: "Prefix" + annotations: {} + # kubernetes.io/ingress.class: nginx + # kubernetes.io/tls-acme: "true" + hosts: + - host: analytics.sandbox.mifos.io + paths: + - path: / + #tls: [] + # - secretName: chart-example-tls + # hosts: + # - chart-example.local + + operations: + enabled: true + + operationsmysql: + auth: + database: "tenants" + username: "mifos" + password: "password" + rootPassword: "ethieTieCh8ahv" + initdbScripts: + setup.sql: |- + CREATE DATABASE messagegateway; + CREATE DATABASE `rhino`; + CREATE DATABASE `gorilla`; + CREATE DATABASE `wakanda`; + CREATE DATABASE `identity_account_mapper`; + CREATE DATABASE `voucher_management`; + CREATE DATABASE `pluto`; + CREATE DATABASE `venus`; + CREATE DATABASE `jupiter`; + GRANT ALL PRIVILEGES ON `rhino`.* TO 'mifos'; + GRANT ALL PRIVILEGES ON `gorilla`.* TO 'mifos'; + GRANT ALL PRIVILEGES ON `wakanda`.* TO 'mifos'; + GRANT ALL ON *.* TO 'root'@'%'; + GRANT ALL PRIVILEGES ON messagegateway.* TO 'mifos'; + GRANT ALL PRIVILEGES ON `identity_account_mapper`.* TO 'mifos'; + GRANT ALL PRIVILEGES ON `voucher_management`.* TO 'mifos'; + GRANT ALL PRIVILEGES ON `pluto`.* TO 'mifos'; + GRANT ALL PRIVILEGES ON `venus`.* TO 'mifos'; + GRANT ALL PRIVILEGES ON `jupiter`.* TO 'mifos'; + + + ph_ee_connector_ams_mifos: + enabled: true + image: docker.io/openmf/ph-ee-connector-ams-mifos:latest + SPRING_PROFILES_ACTIVE: "fin12,bb" + ams_local_enabled: true + ams_local_interop_host: "https://fynams.sandbox.mifos.io/" + ams_local_account_host: "https://fynams.sandbox.mifos.io/" + ams_local_customer_host: "https://fynams.sandbox.mifos.io/" + ams_local_auth_host: "https://fynams.sandbox.mifos.io/" + ingress: + enabled: false + annotations: + kubernetes.io/ingress.class: nginx + tls: + - secretName: sandbox-secret + hosts: + - host: ams-mifos.sandbox.mifos.io + paths: + - path: "/" + backend: + service: + name: ph-ee-connector-ams-mifos + port: + number: 80 + deployment: + annotations: + deployTime: "{{ .Values.deployTime }}" + + ph_ee_connector_mojaloop: + enabled: true + image: docker.io/openmf/ph-ee-connector-mojaloop:latest + SPRING_PROFILES_ACTIVE: "bb" + hostname: "mojaloop.sandbox.mifos.io" + ingress: + enabled: false + annotations: + kubernetes.io/ingress.class: nginx + tls: + - secretName: sandbox-secret + hosts: + - host: mojaloop.sandbox.mifos.io + paths: + - path: "/" + backend: + service: + name: ph-ee-connector-mojaloop-java + port: + number: 80 + deployment: + annotations: + deployTime: "{{ .Values.deployTime }}" + + mockpayment: + enabled: true + limits: + memory: "768M" + ingress: + enabled: false + hosts: + - host: "" + paths: + - path: "/" + backend: + service: + name: ph-ee-connector-mock-payment-schema + port: + number: 80 + + channel: + enabled: true + image: docker.io/openmf/ph-ee-connector-channel:latest + hostname: "channel.sandbox.mifos.io" + stub_hostname: "channel-gsma.sandbox.mifos.io" + SPRING_PROFILES_ACTIVE: "bb,tenants" + tenantPrimary: + clientId: "mifos" + clientSecret: "password" + tenant: "rhino" + tenantSecondary: + clientId: "mifos" + clientSecret: "password" + tenant: "gorilla" + server: + ssl: + keyPassword: "password" + keyStorePassword: "password" + ingress: + enabled: false + tls: + - secretName: sandbox-secret + hosts: + - host: channel.sandbox.mifos.io + paths: + - path: "/" + backend: + service: + name: "ph-ee-connector-channel" + port: + number: 8443 + - host: channel-gsma.sandbox.mifos.io + paths: + - path: "/" + backend: + service: + name: "ph-ee-connector-channel-gsma" + port: + number: 82 + deployment: + annotations: + deployTime: "{{ .Values.deployTime }}" + + + operations_app: + enabled: true + image: docker.io/openmf/ph-ee-operations-app:latest + hostname: "ops-bk.sandbox.mifos.io" + datasource: + username: "mifos" + password: "password" + host: "operationsmysql" + port: 3306 + schema: "tenants" + ingress: + enabled: false + annotations: + kubernetes.io/ingress.class: nginx + nginx.ingress.kubernetes.io/cors-allow-headers: 'platform-tenantid, x-correlation-id' + nginx.ingress.kubernetes.io/cors-allow-methods: PUT, GET, POST, OPTIONS, DELETE + nginx.ingress.kubernetes.io/cors-allow-origin: '*' + nginx.ingress.kubernetes.io/enable-cors: "true" + tls: + - secretName: sandbox-secret + hosts: + - host: ops-bk.sandbox.mifos.io + paths: + - path: "/" + backend: + service: + name: "ph-ee-operations-app" + port: + number: 80 + deployment: + annotations: + deployTime: "{{ .Values.deployTime }}" + + operations_web: + enabled: true + image: docker.io/openmf/ph-ee-operations-web:latest + hostname: "ops.sandbox.mifos.io" + ingress: + enabled: false + tls: + - secretName: sandbox-secret + hosts: + - host: ops.sandbox.mifos.io + paths: + - path: "/" + backend: + service: + name: "ph-ee-operations-web" + port: + number: 4200 + + identity: + hostname: "ops-bk.sandbox.mifos.io" + + ph_ee_connector_gsma: + enabled: true + image: docker.io/openmf/ph-ee-connector-gsma:latest + SPRING_PROFILES_ACTIVE: "bb" + limits: + cpu: "500m" + memory: "512M" + requests: + cpu: "100m" + memory: "256M" + deployment: + annotations: + deployTime: "{{ .Values.deployTime }}" + + ph_ee_connector_slcb: + enabled: false + + mpesa: + enabled: false + + roster_connector: + enabled: false + + paygops_connector: + enabled: false + + notifications: + enabled: true + image: docker.io/openmf/ph-ee-notifications:latest + imagePullPolicy: "Always" + SPRING_PROFILES_ACTIVE: "bb" + LOGGING_LEVEL_ROOT: "INFO" + MESSAGEGATEWAYCONFIG_HOST: "message-gateway" + NOTIFICATION_LOCAL_HOST: "ph-ee-connector-notifications" + NOTIFICATION_SUCCESS_ENABLED: "false" + NOTIFICATION_FAILURE_ENABLED: "true" + hostname: "notifications.sandbox.mifos.io" + ingress: + enabled: false + annotations: + kubernetes.io/ingress.class: nginx + tls: + - secretName: sandbox-secret + hosts: + - host: notifications.sandbox.mifos.io + paths: + - path: "/" + backend: + service: + name: "ph-ee-connector-notifications" + port: + number: 80 + deployment: + annotations: + deployTime: "{{ .Values.deployTime }}" + + connector_bulk: + enabled: true + image: docker.io/openmf/ph-ee-bulk-processor:latest + tenant: "rhino,gorilla" + hostname: bulk-connector.sandbox.mifos.io + operations_app: + contactpoint: "http://ph-ee-operations-app:80" + endpoints: + batch_transaction: "/api/v1/batch/transactions" + identity_account_mapper: + hostname: "http://ph-ee-identity-account-mapper:80" + service: + annotations: + konghq.com/protocol: "https" + ingress: + enabled: false + annotations: + konghq.com/plugins: cors + kubernetes.io/ingress.class: kong + tls: + - secretName: sandbox-secret + hosts: + - host: bulk-connector.sandbox.mifos.io + paths: + - path: "/" + backend: + service: + name: "ph-ee-connector-bulk" + port: + number: 8443 + deployment: + annotations: + deployTime: "{{ .Values.deployTime }}" + + zeebe_ops: + enabled: true + image: docker.io/openmf/ph-ee-zeebe-ops:latest + hostname: "zeebeops.sandbox.mifos.io" + ingress: + enabled: false + annotations: + kubernetes.io/ingress.class: nginx + tls: + - secretName: sandbox-secret + hosts: + - host: zeebeops.sandbox.mifos.io + paths: + - path: "/" + backend: + service: + name: "ph-ee-zeebe-ops" + port: + number: 80 + deployment: + annotations: + deployTime: "{{ .Values.deployTime }}" + + messagegateway: + enabled: true + image: docker.io/openmf/message-gateway:latest + secret: + value: + api_key: "" + project_id: "" + hostname: "messagegateway.sandbox.mifos.io" + ingress: + enabled: false + annotations: + kubernetes.io/ingress.class: nginx + tls: + - secretName: sandbox-secret + hosts: + - host: messagegateway.sandbox.mifos.io + paths: + - path: "/" + backend: + service: + name: "message-gateway" + port: + number: 80 + deployment: + annotations: + deployTime: "{{ .Values.deployTime }}" + + importer_es: + enabled: true + image: docker.io/openmf/ph-ee-importer-es:latest + elasticsearch_sslverification: false + elasticsearch_security_enabled: false + reporting: + enabled: false + + importer_rdbms: + enabled: true + image: docker.io/openmf/ph-ee-importer-rdbms:latest + LOGGING_LEVEL_ROOT: "DEBUG" + + keycloak: + enabled: false + ingress: + enabled: false + ingressClassName: "kong" + rules: + - host: 'keycloak.sandbox.mifos.io' + paths: + - path: / + pathType: Prefix + tls: [] + + kong: + enabled: false + image: + repository: revomatico/docker-kong-oidc + tag: "latest" + env: + plugins: "bundled,oidc" + admin: + enabled: true + http: + enabled: true + tls: + enabled: false + ingress: + enabled: false + hostname: admin-kong.sandbox.mifos.io + + vouchers: + enabled: true + image: docker.io/openmf/ph-ee-vouchers:latest + ingress: + enabled: false + annotations: + nginx.ingress.kubernetes.io/access-control-allow-origin: 'true' + nginx.ingress.kubernetes.io/cors-allow-headers: 'x-registering-institution-id, content-type, X-CallbackURL' + nginx.ingress.kubernetes.io/cors-allow-methods: PUT, GET, POST, OPTIONS, DELETE + nginx.ingress.kubernetes.io/cors-allow-origin: '*' + nginx.ingress.kubernetes.io/enable-cors: 'true' + tls: + - secretName: sandbox-secret + hosts: + - host: vouchers.sandbox.mifos.io + paths: + - path: "/" + backend: + service: + name: ph-ee-vouchers + port: + number: 80 + deployment: + annotations: + deployTime: "{{ .Values.deployTime }}" + integration_test: + enabled: true + gradle: + command: ./gradlew test -Dcucumber.filter.tags="@gov" + + billPay: + enabled: true + image: docker.io/openmf/ph-ee-bill-pay:latest + hostname: "bill-pay.sandbox.mifos.io" + stub_hostname: "bill-pay.sandbox.mifos.io" + SPRING_PROFILES_ACTIVE: "bb,tenants" + operations: + url: "http://ph-ee-operations-app:80" + ingress: + enabled: false + annotations: + nginx.ingress.kubernetes.io/access-control-allow-origin: 'true' + nginx.ingress.kubernetes.io/cors-allow-methods: PUT, GET, POST, OPTIONS, DELETE + nginx.ingress.kubernetes.io/cors-allow-origin: '*' + nginx.ingress.kubernetes.io/enable-cors: 'true' + tls: + - secretName: sandbox-secret + hosts: + - host: bill-pay.sandbox.mifos.io + paths: + - path: "/" + backend: + service: + name: "ph-ee-bill-pay" + port: + number: 8080 + deployment: + annotations: + deployTime: "{{ .Values.deployTime }}" + + crm: + enabled: true + image: docker.io/openmf/ph-ee-connector-crm:latest + hostname: "crm.sandbox.mifos.io" + stub_hostname: "crm.sandbox.mifos.io" + SPRING_PROFILES_ACTIVE: "bb,tenants" + ingress: + enabled: false + annotations: + nginx.ingress.kubernetes.io/access-control-allow-origin: 'true' + nginx.ingress.kubernetes.io/cors-allow-methods: PUT, GET, POST, OPTIONS, DELETE + nginx.ingress.kubernetes.io/cors-allow-origin: '*' + nginx.ingress.kubernetes.io/enable-cors: 'true' + tls: + - secretName: sandbox-secret + hosts: + - host: crm.sandbox.mifos.io + paths: + - path: "/" + backend: + service: + name: "ph-ee-connector-crm" + port: + number: 8080 + deployment: + annotations: + deployTime: "{{ .Values.deployTime }}" + + ph-ee-connector: + enabled: true + image: docker.io/openmf/ph-ee-connector-bulk:latest + aws: + region: "ap-south-1" + access_key: "aws-access-key" + secret_key: "aws-secret-key" + hostname: "connector.sandbox.mifos.io" + ingress: + enabled: true + annotations: + nginx.ingress.kubernetes.io/access-control-allow-origin: 'true' + nginx.ingress.kubernetes.io/cors-allow-methods: PUT, GET, POST, OPTIONS, DELETE + nginx.ingress.kubernetes.io/cors-allow-origin: '*' + nginx.ingress.kubernetes.io/enable-cors: 'true' + + deployment: + annotations: + deployTime: "{{ .Values.deployTime }}" + + post_installation_job: + enabled: true + minio: + enabled: true + +account_mapper: + enabled: true + image: docker.io/openmf/ph-ee-identity-account-mapper:latest + hostname: "identity-mapper.sandbox.mifos.io" + LOGGING_LEVEL_ROOT: INFO + livenessProbe: + initialDelaySeconds: 20 + periodSeconds: 30 + readinessProbe: + initialDelaySeconds: 180 + periodSeconds: 30 + ingress: + enabled: false + pathtype: Prefix + annotations: + nginx.ingress.kubernetes.io/access-control-allow-origin: 'true' + nginx.ingress.kubernetes.io/cors-allow-headers: 'x-registering-institution-id' + nginx.ingress.kubernetes.io/cors-allow-methods: PUT, GET, POST, OPTIONS, DELETE + nginx.ingress.kubernetes.io/cors-allow-origin: '*' + nginx.ingress.kubernetes.io/enable-cors: 'true' + tls: + - secretName: sandbox-secret + hosts: + - host: identity-mapper.sandbox.mifos.io + paths: + - path: "/" + backend: + service: + name: "ph-ee-identity-account-mapper" + port: + number: 80 + deployment: + annotations: + deployTime: "{{ .Values.deployTime }}" + async: + core_pool_size: 10 + max_pool_size: 10 + queue_capacity: 100 + account_validation_enabled: "false" + account_validator_connector: "gsma" + spring: + cache: + time_to_live: 30 + time_to_idle: 30 + max_entries_heap: 1000 + max_byte_off_heap: 10 + max_byte_disk: 10 + datasource: + url: jdbc:mysql://operationsmysql:3306/identity_account_mapper + username: mifos + password: password + + diff --git a/ph-ee-env-template/helm/identity-account-mapper/Chart.yaml b/ph-ee-env-template/helm/identity-account-mapper/Chart.yaml new file mode 100644 index 000000000..0fe7b3c3f --- /dev/null +++ b/ph-ee-env-template/helm/identity-account-mapper/Chart.yaml @@ -0,0 +1,5 @@ +apiVersion: v1 +appVersion: 1.0.0 +description: Identity Account Mapper +name: identity-account-mapper +version: 1.0.0-SNAPSHOT \ No newline at end of file diff --git a/ph-ee-env-template/helm/identity-account-mapper/account-mapper/Chart.yaml b/ph-ee-env-template/helm/identity-account-mapper/account-mapper/Chart.yaml new file mode 100644 index 000000000..d58770c0b --- /dev/null +++ b/ph-ee-env-template/helm/identity-account-mapper/account-mapper/Chart.yaml @@ -0,0 +1,5 @@ +apiVersion: v1 +description: ph_ee_identity_account_mapper +name: account_mapper +version: 1.0.0 +appVersion: "1.0.0" \ No newline at end of file diff --git a/ph-ee-env-template/helm/identity-account-mapper/account-mapper/templates/clusterrole.yaml b/ph-ee-env-template/helm/identity-account-mapper/account-mapper/templates/clusterrole.yaml new file mode 100644 index 000000000..1b4284f4e --- /dev/null +++ b/ph-ee-env-template/helm/identity-account-mapper/account-mapper/templates/clusterrole.yaml @@ -0,0 +1,11 @@ +{{- if .Values.managedServiceAccount }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + # "namespace" omitted since ClusterRoles are not namespaced + name: ph-ee-identity-account-mapper-c-role +rules: +- apiGroups: [""] + resources: ["secrets"] + verbs: ["get", "watch", "list"] +{{- end -}} \ No newline at end of file diff --git a/ph-ee-env-template/helm/identity-account-mapper/account-mapper/templates/clusterrolebinding.yaml b/ph-ee-env-template/helm/identity-account-mapper/account-mapper/templates/clusterrolebinding.yaml new file mode 100644 index 000000000..4a4b2b70b --- /dev/null +++ b/ph-ee-env-template/helm/identity-account-mapper/account-mapper/templates/clusterrolebinding.yaml @@ -0,0 +1,15 @@ +{{- if .Values.managedServiceAccount }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: ph-ee-identity-account-mapper-c-role-binding +subjects: +- kind: ServiceAccount + name: ph-ee-identity-account-mapper # name of your service account + namespace: {{ .Release.Namespace }} # this is the namespace your service account is in +roleRef: # referring to your ClusterRole + kind: ClusterRole + name: ph-ee-identity-account-mapper-c-role + apiGroup: rbac.authorization.k8s.io + +{{- end -}} \ No newline at end of file diff --git a/ph-ee-env-template/helm/identity-account-mapper/account-mapper/templates/deployment.yaml b/ph-ee-env-template/helm/identity-account-mapper/account-mapper/templates/deployment.yaml new file mode 100644 index 000000000..d3b2fc471 --- /dev/null +++ b/ph-ee-env-template/helm/identity-account-mapper/account-mapper/templates/deployment.yaml @@ -0,0 +1,99 @@ +{{- if .Values.enabled -}} + +apiVersion: apps/v1 +kind: Deployment +metadata: + name: ph-ee-identity-account-mapper + labels: + app: ph-ee-identity-account-mapper +spec: + replicas: {{ .Values.replicas }} + selector: + matchLabels: + app: ph-ee-identity-account-mapper + template: + metadata: + labels: + app: ph-ee-identity-account-mapper + annotations: +{{- if .Values.deployment.annotations }} +{{ toYaml .Values.deployment.annotations | indent 8 }} +{{- end }} + spec: + initContainers: + #During this Pod's initialization, check that operationsmysql service is up and running before starting this pod + - name: check-operationsmysql-ready + image: busybox:latest + command: [ 'sh', '-c','until nc -vz operationsmysql 3306; do echo "Waiting for operationsmysql service"; sleep 2; done;' ] + containers: + - name: ph-ee-identity-account-mapper + image: "{{ .Values.image}}" + imagePullPolicy: "{{ .Values.imagePullPolicy }}" + ports: + - containerPort: 8080 + resources: + limits: + memory: "{{ .Values.limits.memory }}" + cpu: "{{ .Values.limits.cpu }}" + requests: + memory: "{{ .Values.requests.memory }}" + cpu: "{{ .Values.requests.cpu }}" + livenessProbe: + httpGet: + path: /actuator/health/liveness + port: 8080 + initialDelaySeconds: {{.Values.livenessProbe.initialDelaySeconds}} + periodSeconds: {{.Values.livenessProbe.periodSeconds}} + readinessProbe: + httpGet: + path: /actuator/health/readiness + port: 8080 + initialDelaySeconds: {{.Values.readinessProbe.initialDelaySeconds}} + periodSeconds: {{.Values.readinessProbe.periodSeconds}} + env: + - name: "ZEEBE_BROKER_CONTACTPOINT" + value: "{{ .Release.Name }}-zeebe-gateway:26500" + - name: "ZEEBE_CLIENT_MAX-EXECUTION-THREADS" + value: "{{ .Values.global.max_execution_threads}}" + - name: "ZEEBE_CLIENT_POLL-INTERVAL" + value: "{{ .Values.global.poll_interval}}" + - name: "SPRING_CACHE_TIME_TO_LIVE" + value: "{{ .Values.spring.cache.time_to_live }}" + - name: "SPRING_CACHE_TIME_TO_IDLE" + value: "{{ .Values.spring.cache.time_to_idle }}" + - name: "SPRING_CACHE_MAX_ENTRIES_HEAP" + value: "{{ .Values.spring.cache.max_entries_heap }}" + - name: "SPRING_CACHE_MAX_BYTE_OFF_HEAP" + value: "{{ .Values.spring.cache.max_byte_off_heap }}" + - name: "SPRING_CACHE_MAX_BYTE_DISK" + value: "{{ .Values.spring.cache.max_byte_disk }}" + - name: "SPRING_DATASOURCE_URL" + value: "{{ .Values.spring.datasource.url }}" + - name: "SPRING_DATASOURCE_USERNAME" + value: "{{ .Values.spring.datasource.username }}" + - name: "SPRING_DATASOURCE_PASSWORD" + value: "{{ .Values.spring.datasource.password }}" + - name: "LOGGING_LEVEL_ROOT" + value: "{{ .Values.global.LOGGING_LEVEL_ROOT }}" + - name: "ACCOUNT_VALIDATION_ENABLED" + value: "{{ .Values.account_validation_enabled }}" + - name: "ACCOUNT_VALIDATOR_CONNECTOR" + value: "{{ .Values.account_validator_connector }}" + - name: "CALLBACK_ENABLED" + value: "{{ .Values.callback_enabled }}" + - name: "ISEXTERNALLOOKUP" + value: "{{.Values.is_external_lookup}}" + +{{- if .Values.extraEnvs | default .Values.deployment.extraEnvs }} +{{ toYaml ( .Values.extraEnvs | default .Values.deployment.extraEnvs ) | indent 10 }} +{{- end }} + envFrom: {{ toYaml ( .Values.envFrom | default .Values.deployment.envFrom ) | nindent 12 }} + securityContext: {{ toYaml ( .Values.podSecurityContext | default .Values.deployment.securityContext ) | nindent 12 }} + volumeMounts: + - name: ph-ee-config + mountPath: "/config" + volumes: + - name: ph-ee-config + configMap: + name: ph-ee-config +{{- end }} diff --git a/ph-ee-env-template/helm/identity-account-mapper/account-mapper/templates/ingress.yaml b/ph-ee-env-template/helm/identity-account-mapper/account-mapper/templates/ingress.yaml new file mode 100644 index 000000000..f47a57a06 --- /dev/null +++ b/ph-ee-env-template/helm/identity-account-mapper/account-mapper/templates/ingress.yaml @@ -0,0 +1,49 @@ +{{- if .Values.ingress.enabled -}} +{{- $pathtype := .Values.ingress.pathtype -}} +{{- $ingressPath := .Values.ingress.path -}} +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: ph-ee-identity-account-mapper + labels: + app: {{ .Chart.Name }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +{{- with .Values.ingress.annotations }} + annotations: +{{ toYaml . | indent 4 }} +{{- end }} +spec: + {{- if .Values.ingress.className }} + ingressClassName: {{ .Values.ingress.className | quote }} + {{- end }} +{{- if .Values.ingress.tls }} + tls: + {{- if .ingressPath }} + {{- range .Values.ingress.tls }} + - hosts: + {{- range .hosts }} + - {{ . }} + {{- end }} + secretName: {{ .secretName }} + {{- end }} +{{- else }} +{{ toYaml .Values.ingress.tls | indent 4 }} + {{- end }} +{{- end}} + rules: + {{- range .Values.ingress.hosts }} + - host: {{ .host }} + http: + paths: + {{- range .paths }} + - path: {{ .path }} + pathType: {{ $pathtype }} + backend: + service: + name: {{ .backend.service.name}} + port: + number: {{ .backend.service.port.number}} + {{- end }} + {{- end }} + {{- end }} \ No newline at end of file diff --git a/ph-ee-env-template/helm/identity-account-mapper/account-mapper/templates/rolebinding.yaml b/ph-ee-env-template/helm/identity-account-mapper/account-mapper/templates/rolebinding.yaml new file mode 100644 index 000000000..68eea9b8b --- /dev/null +++ b/ph-ee-env-template/helm/identity-account-mapper/account-mapper/templates/rolebinding.yaml @@ -0,0 +1,15 @@ +{{- if .Values.managedServiceAccount }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: ph-ee-operator-role-binding + namespace: {{ .Release.Namespace }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: ph-ee-operator-role +subjects: + - kind: ServiceAccount + name: payment-hub + namespace: {{ .Release.Namespace }} + {{- end -}} \ No newline at end of file diff --git a/ph-ee-env-template/helm/identity-account-mapper/account-mapper/templates/service.yaml b/ph-ee-env-template/helm/identity-account-mapper/account-mapper/templates/service.yaml new file mode 100644 index 000000000..7b8c0ecf9 --- /dev/null +++ b/ph-ee-env-template/helm/identity-account-mapper/account-mapper/templates/service.yaml @@ -0,0 +1,18 @@ +{{- if .Values.enabled -}} +apiVersion: {{ .Values.service.apiVersion }} +kind: Service +metadata: + labels: + app: ph-ee-identity-account-mapper + name: ph-ee-identity-account-mapper +spec: + ports: + - name: port + port: 80 + protocol: TCP + targetPort: 8080 + selector: + app: ph-ee-identity-account-mapper + sessionAffinity: None + type: ClusterIP + {{- end }} \ No newline at end of file diff --git a/ph-ee-env-template/helm/identity-account-mapper/account-mapper/templates/serviceaccount.yaml b/ph-ee-env-template/helm/identity-account-mapper/account-mapper/templates/serviceaccount.yaml new file mode 100644 index 000000000..796f17646 --- /dev/null +++ b/ph-ee-env-template/helm/identity-account-mapper/account-mapper/templates/serviceaccount.yaml @@ -0,0 +1,15 @@ +{{- if .Values.managedServiceAccount }} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: "ph-ee-identity-account-mapper" + annotations: + {{- with .Values.serviceAccountAnnotations }} + {{- toYaml . | nindent 4 }} + {{- end }} + labels: + app: "ph-ee-identity-account-mapper" + chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" + heritage: {{ .Release.Service | quote }} + release: {{ .Release.Name | quote }} + {{- end -}} \ No newline at end of file diff --git a/ph-ee-env-template/helm/identity-account-mapper/account-mapper/values.yaml b/ph-ee-env-template/helm/identity-account-mapper/account-mapper/values.yaml new file mode 100644 index 000000000..e2c16c280 --- /dev/null +++ b/ph-ee-env-template/helm/identity-account-mapper/account-mapper/values.yaml @@ -0,0 +1,67 @@ +service: + apiVersion: "v1" + +secret: + apiVersion: "v1" + +configmap: + apiVersion: "v1" + +enabled: true +image: docker.io/openmf/ph-ee-identity-account-mapper:latest +imagePullPolicy: "Always" +hostname: "identity-mapper.sandbox.mifos.io" +limits: + cpu: "500m" + memory: "384M" +requests: + cpu: "100m" + memory: "256M" +LOGGING_LEVEL_ROOT: INFO + +async: + core_pool_size: 10 + max_pool_size: 10 + queue_capacity: 100 +account_validation_enabled: "false" +account_validator_connector: "gsma" + +spring: + cache: + time_to_live: 30 + time_to_idle: 30 + max_entries_heap: 1000 + max_byte_off_heap: 10 + max_byte_disk: 10 + datasource: + url: jdbc:mysql:thin://operationsmysql:3306/identity_account_mapper + username: mifos + password: password + + + + +ingress: + enabled: true + annotations: {} + # kubernetes.io/ingress.class: "nginx" + pathtype: Prefix + hosts: + - host: "" + paths: + - path: / + tls: [] + # - secretName: sandbox-secret + # hosts: + # - chart-example.local +is_external_lookup: true +deployment: + apiVersion: "apps/v1" + annotations: + deployTime: "{{ .Values.deployTime }}" +livenessProbe: + initialDelaySeconds: 20 + periodSeconds: 30 +readinessProbe: + initialDelaySeconds: 20 + periodSeconds: 30 diff --git a/ph-ee-env-template/helm/identity-account-mapper/requirements.yaml b/ph-ee-env-template/helm/identity-account-mapper/requirements.yaml new file mode 100644 index 000000000..03ddce90c --- /dev/null +++ b/ph-ee-env-template/helm/identity-account-mapper/requirements.yaml @@ -0,0 +1,26 @@ +dependencies: + - name: zeebe-cluster-helm + repository: https://helm.camunda.io + version: 1.0.0 + - name: zeebe-operate-helm + repository: https://helm.camunda.io + version: 1.2.0 + condition: "zeebe-operate-helm.enabled" + - name: elasticsearch + repository: http://helm.elastic.co + version: 7.16.3 + - name: kibana + repository: http://helm.elastic.co + version: 7.16.3 + condition: "kibana.enabled" + - name: mysql + version: 9.4.5 + repository: "https://charts.bitnami.com/bitnami" + alias: idmappermysql + condition: "idmappermysql.enabled" + - name: kafka + version: 1.0.0 + repository: "file://../ph-ee-engine/kafka" + - name: ph_ee_identity_account_mapper + version: 1.0.0 + repository: "file://./account-mapper" \ No newline at end of file diff --git a/ph-ee-env-template/helm/identity-account-mapper/values.yaml b/ph-ee-env-template/helm/identity-account-mapper/values.yaml new file mode 100644 index 000000000..420d709c8 --- /dev/null +++ b/ph-ee-env-template/helm/identity-account-mapper/values.yaml @@ -0,0 +1,219 @@ +deployment: + apiVersion: "apps/v1" + +ingress: + enabled: true + apiVersion: networking.k8s.io/v1 + +service: + apiVersion: "v1" + +secret: + apiVersion: "v1" + +configmap: + apiVersion: "v1" + +global: + max_execution_threads: 50 + poll_interval: 10 + +zeebe: + broker: + contactpoint: "zeebe-zeebe-gateway:26500" +zeebe-cluster-helm: + enabled: true + global: + elasticsearch: + host: "ph-ee-elasticsearch" + image: + repository: camunda/zeebe + tag: 1.1.0 + + clusterSize: "1" + partitionCount: "1" + replicationFactor: "1" + JavaOpts: "-Xms8g -Xmx8g -XX:+UseParallelGC -XX:MinHeapFreeRatio=5 -XX:MaxHeapFreeRatio=10 -XX:MaxRAMPercentage=25.0 -XX:GCTimeRatio=4 -XX:AdaptiveSizePolicyWeight=90 -XX:+PrintFlagsFinal" + + elasticsearch: + enabled: false + kibana: + enabled: false + + extraInitContainers: | + - name: init-ph-ee-kafka-exporter + image: busybox:1.28 + command: ['/bin/sh', '-c'] + args: ['wget -O /exporters/ph-ee-kafka-exporter.jar "https://paymenthub-ee.s3.ap-south-1.amazonaws.com/jars/exporter-1.0.0-SNAPSHOT.jar"; ls -al /exporters/'] + volumeMounts: + - name: exporters + mountPath: /exporters/ + +zeebe-operate-helm: + enabled: true + image: + repository: camunda/operate + tag: 1.1.0 + global: + elasticsearch: + host: "ph-ee-elasticsearch" + clusterName: "ph-ee-elasticsearch" + ingress: + enabled: false + annotations: + kubernetes.io/ingress.class: nginx + path: / + host: operate.sandbox.mifos.io + tls: + enabled: true + +elasticsearch: + enabled: true + + #Single Node Solution + clusterHealthCheckParams: "wait_for_status=yellow&timeout=100s" + protocol: http + master: + readinessProbe: + httpGet: + allow-insecure: true + username: elastic + password: "{{ .Env.ELASTIC_PASSWORD }}" + path: /_cluster/health?wait_for_status=yellow&timeout=5s + port: 9200 + initialDelaySeconds: 30 + data: + readinessProbe: + httpGet: + allow-insecure: true + username: elastic + password: "{{ .Env.ELASTIC_PASSWORD }}" + path: /_cluster/health?wait_for_status=yellow&timeout=5s + port: 9200 + initialDelaySeconds: 30 + # Shrink default JVM heap. + esJavaOpts: "-Xmx512m -Xms512m" + + # Allocate smaller chunks of memory per pod. + resources: + requests: + cpu: "100m" + memory: "1024M" + limits: + cpu: "1000m" + memory: "1024M" + volumeClaimTemplate: + accessModes: [ "ReadWriteOnce" ] + storageClassName: "gp2" + resources: + requests: + storage: 10Gi + +kibana: + enabled: true + readinessProbe: + initialDelaySeconds: 45 + timeoutSeconds: 15 + successThreshold: 1 + protocol: http + ingress: + enabled: true + className: "nginx" + pathtype: "Prefix" + annotations: {} + # kubernetes.io/ingress.class: nginx + # kubernetes.io/tls-acme: "true" + hosts: + - host: analytics.sandbox.mifos.io + paths: + - path: / + #tls: [] + # - secretName: chart-example-tls + # hosts: + # - chart-example.local + +operations: + enabled: true + +idmappermysql: + enabled: true + fullnameOverride: "idmappermysql" + image: + tag: "5.7" + debug: false + auth: + database: "tenants" + username: "idmapper" + password: "password" + rootPassword: "ethieTieCh8ahv" + initdbScripts: + setup.sql: |- + CREATE DATABASE IF NOT EXISTS IdentityAccountMapper; + GRANT ALL ON *.* TO 'root'@'%'; + GRANT ALL PRIVILEGES ON IdentityAccountMapper.* TO 'idmapper'; + +kafka: + enabled: true + replicas: 1 + image: "spotify/kafka" + imagePullPolicy: "Always" + advertised: + host: "kafka" + port: "9092" + limits: + memory: "512M" + cpu: "500m" + requests: + memory: "512M" + cpu: "100m" + deployment: + annotations: + deployTime: "{{ .Values.deployTime }}" + +account_mapper: + enabled: true + image: docker.io/openmf/ph-ee-identity-account-mapper:latest + hostname: "identity-mapper.sandbox.mifos.io" + ingress: + enabled: true + annotations: + kubernetes.io/ingress.class: nginx + tls: + - secretName: sandbox-secret + hosts: + - host: identity-mapper.sandbox.mifos.io + paths: + - path: "/" + backend: + service: + name: "ph-ee-identity-account-mapper" + port: + number: 80 + deployment: + annotations: + deployTime: "{{ .Values.deployTime }}" + + logging: + level: + ROOT: INFO + + async: + core_pool_size: 10 + max_pool_size: 10 + queue_capacity: 100 + + account_validation_enabled: "false" + account_validator_connector: "gsma" + + spring: + cache: + time_to_live: 30 + time_to_idle: 30 + max_entries_heap: 1000 + max_byte_off_heap: 10 + max_byte_disk: 10 + datasource: + url: jdbc:mysql:thin://operationsmysql:3306/identity_account_mapper + username: mifos + password: password + diff --git a/ph-ee-env-template/helm/package.sh b/ph-ee-env-template/helm/package.sh new file mode 100755 index 000000000..8fd46119e --- /dev/null +++ b/ph-ee-env-template/helm/package.sh @@ -0,0 +1,16 @@ +#!/bin/bash +cd ph-ee-engine +#rm charts/* +helm dep up +cd - + +helm package ph-ee-engine +helm repo index . + +cp *.tgz index.yaml /usr/share/nginx/html/ +#rm ph-ee-engine*.tgz +echo "deployed to local repo" + +scp index.yaml ph-ee-engine-1.0.0-SNAPSHOT.tgz jenkins.mifos.io:/srv/data/helm-charts/ +echo "deployed to remote helm repo" + diff --git a/ph-ee-env-template/helm/ph-ee-engine/.helmignore b/ph-ee-env-template/helm/ph-ee-engine/.helmignore new file mode 100644 index 000000000..50af03172 --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/.helmignore @@ -0,0 +1,22 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ diff --git a/ph-ee-env-template/helm/ph-ee-engine/Chart.yaml b/ph-ee-env-template/helm/ph-ee-engine/Chart.yaml new file mode 100644 index 000000000..d5e5e4a24 --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/Chart.yaml @@ -0,0 +1,5 @@ +apiVersion: v1 +appVersion: 0.0.0 +description: PaymentHub EE Engine +name: ph-ee-engine +version: 0.0.0-SNAPSHOT diff --git a/ph-ee-env-template/helm/ph-ee-engine/README.md b/ph-ee-env-template/helm/ph-ee-engine/README.md new file mode 100644 index 000000000..9bf2f548d --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/README.md @@ -0,0 +1,1149 @@ +# ph-ee-engine + +![Version: 1.7.2-SNAPSHOT](https://img.shields.io/badge/Version-1.7.2--SNAPSHOT-informational?style=flat-square) ![AppVersion: 1.7.2](https://img.shields.io/badge/AppVersion-1.7.2-informational?style=flat-square) + +PaymentHub EE Engine + +## Requirements + +| Repository | Name | Version | +|------------|------|---------| +| file://./ams-paygops | paygops_connector | 1.0.0 | +| file://./ams-roster | roster_connector | 1.0.0 | +| file://./connector-ams-mifos | ph_ee_connector_ams_mifos | 1.0.0 | +| file://./connector-bulk | connector_bulk | 1.0.0 | +| file://./connector-channel | channel | 1.0.0 | +| file://./connector-gsma | ph_ee_connector_gsma | 1.0.0 | +| file://./connector-mojaloop | ph_ee_connector_mojaloop | 1.0.0 | +| file://./connector-mpesa | mpesa | 1.0.0 | +| file://./connector-notifications | notifications | 1.0.0 | +| file://./connector-slcb | ph_ee_connector_slcb | 1.0.0 | +| file://./kafka | kafka | 1.0.0 | +| file://./message-gateway | messagegateway | 1.0.0 | +| file://./operations-app | operations_app | 1.0.0 | +| file://./operations-importer-es | importer_es | 1.0.0 | +| file://./operations-importer-rdbms | importer_rdbms | 1.0.0 | +| file://./operations-web | operations_web | 1.0.0 | +| file://./zeebe-ops | zeebe_ops | 1.0.0 | +| http://helm.elastic.co | elasticsearch | 7.16.3 | +| http://helm.elastic.co | kibana | 7.16.3 | +| https://charts.bitnami.com/bitnami | operationsmysql(mysql) | 9.4.5 | +| https://charts.bitnami.com/bitnami | redis | 17.9.3 | +| https://charts.konghq.com | kong | 2.13.1 | +| https://codecentric.github.io/helm-charts | keycloak | 18.1.1 | +| https://helm.camunda.io | zeebe-cluster-helm | 1.0.0 | +| https://helm.camunda.io | zeebe-operate-helm | 1.2.0 | + +## Values + +| Key | Type | Default | Description | +|-----|------|---------|-------------| +| channel.DFSPIDS | string | `""` | | +| channel.LOGGING_LEVEL_ROOT | string | `"INFO"` | | +| channel.LOGGING_PATTERN_CONSOLE | string | `"%d{dd-MM-yyyy HH:mm:ss.SSS} %magenta([%thread]) %highlight(%-5level) %logger.%M - %msg%n"` | | +| channel.SPRING_PROFILES_ACTIVE | string | `""` | | +| channel.TRANSACTION_ID_LENGTH | int | `20` | | +| channel.deployment.affinity | object | `{}` | | +| channel.deployment.annotations | object | `{}` | | +| channel.deployment.envFrom | list | `[]` | | +| channel.deployment.extraEnvs | string | `""` | | +| channel.deployment.nodeSelector | object | `{}` | | +| channel.deployment.resources.limits.cpu | string | `"500m"` | | +| channel.deployment.resources.limits.memory | string | `"512M"` | | +| channel.deployment.resources.requests.cpu | string | `"100m"` | | +| channel.deployment.resources.requests.memory | string | `"512M"` | | +| channel.deployment.securityContext.privileged | bool | `false` | | +| channel.deployment.securityContext.runAsUser | int | `0` | | +| channel.deployment.tolerations | list | `[]` | | +| channel.enabled | bool | `true` | | +| channel.envFrom | list | `[]` | | +| channel.extraEnvs | string | `""` | | +| channel.gsma_payee_tenant | string | `""` | | +| channel.hostname | string | `""` | | +| channel.image | string | `""` | | +| channel.imagePullPolicy | string | `"Always"` | | +| channel.imageTag | string | `"v1.5.0"` | | +| channel.ingress.annotations | object | `{}` | | +| channel.ingress.backend | object | `{}` | | +| channel.ingress.enabled | bool | `true` | | +| channel.ingress.path | string | `"/channel"` | | +| channel.ingress.stub_backend | object | `{}` | | +| channel.livenessProbe.failureThreshold | int | `3` | | +| channel.livenessProbe.httpGet.path | string | `"/actuator/health/liveness"` | | +| channel.livenessProbe.httpGet.port | int | `9191` | | +| channel.livenessProbe.initialDelaySeconds | int | `120` | | +| channel.livenessProbe.periodSeconds | int | `30` | | +| channel.livenessProbe.timeoutSeconds | int | `5` | | +| channel.managedServiceAccount | bool | `true` | | +| channel.operations.authEnabled | bool | `false` | | +| channel.operations.url | string | `""` | | +| channel.priorityClassName | string | `""` | | +| channel.readinessProbe.failureThreshold | int | `3` | | +| channel.readinessProbe.httpGet.path | string | `"/actuator/health/readiness"` | | +| channel.readinessProbe.httpGet.port | int | `9191` | | +| channel.readinessProbe.initialDelaySeconds | int | `120` | | +| channel.readinessProbe.periodSeconds | int | `30` | | +| channel.readinessProbe.timeoutSeconds | int | `5` | | +| channel.redis.host | string | `"127.0.0.1"` | | +| channel.redis.idempotency.apiList | string | `"/channel/transfer,/channel/collection,/channel/gsma/transaction,/channel/transactionRequest"` | | +| channel.redis.idempotency.enabled | bool | `true` | | +| channel.redis.idempotency.keyFormat | string | `"clientCorrelationId_tenant_api"` | | +| channel.redis.password | string | `""` | | +| channel.redis.port | int | `6379` | | +| channel.replicas | int | `1` | | +| channel.resources.limits.cpu | string | `"500m"` | | +| channel.resources.limits.memory | string | `"512M"` | | +| channel.resources.requests.cpu | string | `"100m"` | | +| channel.resources.requests.memory | string | `"512M"` | | +| channel.securityContext.privileged | bool | `false` | | +| channel.securityContext.runAsUser | int | `0` | | +| channel.serviceAccount | string | `"channel"` | | +| channel.serviceAccountAnnotations | object | `{}` | | +| channel.stub_hostname | string | `""` | | +| channel.tenantPrimary.clientId | string | `""` | | +| channel.tenantPrimary.clientSecret | string | `""` | | +| channel.tenantPrimary.tenant | string | `""` | | +| channel.tenantSecondary.clientId | string | `""` | | +| channel.tenantSecondary.clientSecret | string | `""` | | +| channel.tenantSecondary.tenant | string | `""` | | +| channel.terminationGracePeriod | int | `30` | | +| configmap.apiversion | string | `"v1"` | | +| connector_bulk.SPRING_PROFILES_ACTIVE | string | `""` | | +| connector_bulk.aws.access_key | string | `""` | | +| connector_bulk.aws.region | string | `""` | | +| connector_bulk.aws.secret_key | string | `""` | | +| connector_bulk.bucket_name | string | `"paymenthub-ee-dev"` | | +| connector_bulk.camel_disable_ssl | bool | `true` | | +| connector_bulk.channel.hostname | string | `""` | | +| connector_bulk.config.approval.enable | bool | `false` | | +| connector_bulk.config.backpressure.enable | bool | `false` | | +| connector_bulk.config.completion_threshold_check.completion_rate | int | `95` | | +| connector_bulk.config.completion_threshold_check.enable | bool | `true` | | +| connector_bulk.config.formatting.enable | bool | `false` | | +| connector_bulk.config.formatting.standard | string | `"DEFAULT"` | | +| connector_bulk.config.mergeback.enable | bool | `true` | | +| connector_bulk.config.ordering.enable | bool | `false` | | +| connector_bulk.config.ordering.field | string | `""` | | +| connector_bulk.config.partylookup.enable | bool | `false` | | +| connector_bulk.config.splitting.enable | bool | `true` | | +| connector_bulk.config.splitting.sub_batch_size | int | `5` | | +| connector_bulk.deployment.affinity | object | `{}` | | +| connector_bulk.deployment.annotations | object | `{}` | | +| connector_bulk.deployment.envFrom | list | `[]` | | +| connector_bulk.deployment.extraEnvs | string | `""` | | +| connector_bulk.deployment.nodeSelector | object | `{}` | | +| connector_bulk.deployment.resources.limits.cpu | string | `"500m"` | | +| connector_bulk.deployment.resources.limits.memory | string | `"512M"` | | +| connector_bulk.deployment.resources.requests.cpu | string | `"100m"` | | +| connector_bulk.deployment.resources.requests.memory | string | `"512M"` | | +| connector_bulk.deployment.securityContext.privileged | bool | `false` | | +| connector_bulk.deployment.securityContext.runAsUser | int | `0` | | +| connector_bulk.deployment.tolerations | list | `[]` | | +| connector_bulk.enabled | bool | `false` | | +| connector_bulk.envFrom | list | `[]` | | +| connector_bulk.extraEnvs | string | `""` | | +| connector_bulk.hostname | string | `""` | | +| connector_bulk.image | string | `""` | | +| connector_bulk.imagePullPolicy | string | `"Always"` | | +| connector_bulk.imageTag | string | `"v1.5.0"` | | +| connector_bulk.ingress.enabled | bool | `false` | | +| connector_bulk.livenessProbe.failureThreshold | int | `3` | | +| connector_bulk.livenessProbe.httpGet.path | string | `"/actuator/health/liveness"` | | +| connector_bulk.livenessProbe.httpGet.port | int | `9191` | | +| connector_bulk.livenessProbe.initialDelaySeconds | int | `120` | | +| connector_bulk.livenessProbe.periodSeconds | int | `30` | | +| connector_bulk.livenessProbe.timeoutSeconds | int | `5` | | +| connector_bulk.managedServiceAccount | bool | `true` | | +| connector_bulk.operations_app.contactpoint | string | `"https://ops-bk.sandbox.mifos.io/"` | | +| connector_bulk.operations_app.endpoints.batch_transaction | string | `"/api/v1/batch/transactions"` | | +| connector_bulk.pollingApi.timer | string | `"180"` | | +| connector_bulk.priorityClassName | string | `""` | | +| connector_bulk.readinessProbe.failureThreshold | int | `3` | | +| connector_bulk.readinessProbe.httpGet.path | string | `"/actuator/health/readiness"` | | +| connector_bulk.readinessProbe.httpGet.port | int | `9191` | | +| connector_bulk.readinessProbe.initialDelaySeconds | int | `120` | | +| connector_bulk.readinessProbe.periodSeconds | int | `30` | | +| connector_bulk.readinessProbe.timeoutSeconds | int | `5` | | +| connector_bulk.replicas | int | `1` | | +| connector_bulk.resources.limits.cpu | string | `"500m"` | | +| connector_bulk.resources.limits.memory | string | `"512M"` | | +| connector_bulk.resources.requests.cpu | string | `"100m"` | | +| connector_bulk.resources.requests.memory | string | `"512M"` | | +| connector_bulk.securityContext.privileged | bool | `false` | | +| connector_bulk.securityContext.runAsUser | int | `0` | | +| connector_bulk.serviceAccount | string | `""` | | +| connector_bulk.serviceAccountAnnotations | object | `{}` | | +| connector_bulk.tenants | string | `""` | | +| connector_bulk.terminationGracePeriod | int | `30` | | +| connector_bulk.zeebe_broker_contactpoint | string | `"zeebe-zeebe-gateway:26500"` | | +| deployment.apiversion | string | `"apps/v1"` | | +| elasticsearch.clusterName | string | `"ph-ee-elasticsearch"` | | +| elasticsearch.enabled | bool | `true` | | +| elasticsearch.esConfig."elasticsearch.yml" | string | `"xpack.security.enabled: false\nxpack.security.transport.ssl.enabled: false\nxpack.security.transport.ssl.verification_mode: certificate\nxpack.security.transport.ssl.keystore.path: /usr/share/elasticsearch/config/certs/elastic-certificates.p12\nxpack.security.transport.ssl.truststore.path: /usr/share/elasticsearch/config/certs/elastic-certificates.p12\nxpack.security.http.ssl.enabled: false\nxpack.security.http.ssl.truststore.path: /usr/share/elasticsearch/config/certs/elastic-certificates.p12\nxpack.security.http.ssl.keystore.path: /usr/share/elasticsearch/config/certs/elastic-certificates.p12\n"` | | +| elasticsearch.extraEnvs[0].name | string | `"ELASTIC_PASSWORD"` | | +| elasticsearch.extraEnvs[0].valueFrom.secretKeyRef.key | string | `"password"` | | +| elasticsearch.extraEnvs[0].valueFrom.secretKeyRef.name | string | `"elastic-credentials"` | | +| elasticsearch.fullnameOverride | string | `"ph-ee-elasticsearch"` | | +| elasticsearch.imageTag | string | `"7.16.3"` | | +| elasticsearch.minimumMasterNodes | int | `1` | | +| elasticsearch.protocol | string | `"http"` | | +| elasticsearch.replicas | int | `1` | | +| elasticsearch.secretMounts[0].name | string | `"elastic-certificates"` | | +| elasticsearch.secretMounts[0].path | string | `"/usr/share/elasticsearch/config/certs"` | | +| elasticsearch.secretMounts[0].secretName | string | `"elastic-certificates"` | | +| identity.hostname | string | `""` | | +| importer_es.deployment.annotations | object | `{}` | | +| importer_es.elasticsearch_security_enabled | bool | `false` | | +| importer_es.elasticsearch_sslverification | bool | `false` | | +| importer_es.enabled | bool | `true` | | +| importer_es.envFrom | list | `[]` | | +| importer_es.extraEnvs | string | `""` | | +| importer_es.image | string | `""` | | +| importer_es.imagePullPolicy | string | `"Always"` | | +| importer_es.imageTag | string | `"v1.4.0"` | | +| importer_es.importer_elasticsearch_url | string | `"http://ph-ee-elasticsearch:9200/"` | | +| importer_es.javaToolOptions | string | `"-Xmx256M"` | | +| importer_es.livenessProbe.failureThreshold | int | `3` | | +| importer_es.livenessProbe.httpGet.path | string | `"/actuator/health/liveness"` | | +| importer_es.livenessProbe.httpGet.port | int | `9191` | | +| importer_es.livenessProbe.initialDelaySeconds | int | `120` | | +| importer_es.livenessProbe.periodSeconds | int | `30` | | +| importer_es.livenessProbe.timeoutSeconds | int | `5` | | +| importer_es.logging.level.root | string | `"INFO"` | | +| importer_es.logging.pattern.console | string | `"%d{dd-MM-yyyy HH:mm:ss.SSS} %magenta([%thread]) %highlight(%-5level) %logger.%M - %msg%n"` | | +| importer_es.managedServiceAccount | bool | `true` | | +| importer_es.priorityClassName | string | `""` | | +| importer_es.readinessProbe.failureThreshold | int | `3` | | +| importer_es.readinessProbe.httpGet.path | string | `"/actuator/health/readiness"` | | +| importer_es.readinessProbe.httpGet.port | int | `9191` | | +| importer_es.readinessProbe.initialDelaySeconds | int | `120` | | +| importer_es.readinessProbe.periodSeconds | int | `30` | | +| importer_es.readinessProbe.timeoutSeconds | int | `5` | | +| importer_es.replicas | int | `1` | | +| importer_es.reporting.enabled | bool | `false` | | +| importer_es.reporting.fields.accountId | bool | `false` | | +| importer_es.reporting.fields.amount | bool | `false` | | +| importer_es.reporting.fields.ams | bool | `false` | | +| importer_es.reporting.fields.clientCorrelationId | bool | `false` | | +| importer_es.reporting.fields.confirmationReceived | bool | `false` | | +| importer_es.reporting.fields.currency | bool | `false` | | +| importer_es.reporting.fields.customData | bool | `false` | | +| importer_es.reporting.fields.errorCode | bool | `false` | | +| importer_es.reporting.fields.errorDescription | bool | `false` | | +| importer_es.reporting.fields.errorInformation | bool | `false` | | +| importer_es.reporting.fields.externalId | bool | `false` | | +| importer_es.reporting.fields.initiator | bool | `false` | | +| importer_es.reporting.fields.initiatorType | bool | `false` | | +| importer_es.reporting.fields.isNotificationsFailureEnabled | bool | `false` | | +| importer_es.reporting.fields.isNotificationsSuccessEnabled | bool | `false` | | +| importer_es.reporting.fields.mpesaTransactionId | bool | `false` | | +| importer_es.reporting.fields.mpesaTransactionStatusRetryCount | bool | `false` | | +| importer_es.reporting.fields.originDate | bool | `false` | | +| importer_es.reporting.fields.partyLookupFailed | bool | `false` | | +| importer_es.reporting.fields.phoneNumber | bool | `false` | | +| importer_es.reporting.fields.processDefinitionKey | bool | `false` | | +| importer_es.reporting.fields.processInstanceKey | bool | `false` | | +| importer_es.reporting.fields.scenario | bool | `false` | | +| importer_es.reporting.fields.tenantId | bool | `false` | | +| importer_es.reporting.fields.timer | bool | `false` | | +| importer_es.reporting.fields.timestamp | bool | `false` | | +| importer_es.reporting.fields.transactionFailed | bool | `false` | | +| importer_es.reporting.fields.transactionId | bool | `false` | | +| importer_es.reporting.fields.transferCreateFailed | bool | `false` | | +| importer_es.reporting.fields.transferResponseCREATE | bool | `false` | | +| importer_es.reporting.fields.transferSettlementFailed | bool | `false` | | +| importer_es.resources.limits.cpu | string | `"500m"` | | +| importer_es.resources.limits.memory | string | `"512M"` | | +| importer_es.resources.requests.cpu | string | `"100m"` | | +| importer_es.resources.requests.memory | string | `"512M"` | | +| importer_es.securityContext.privileged | bool | `false` | | +| importer_es.securityContext.runAsUser | int | `0` | | +| importer_es.serviceAccount | string | `""` | | +| importer_es.serviceAccountAnnotations | object | `{}` | | +| importer_es.terminationGracePeriod | int | `30` | | +| importer_rdbms.LOGGING_LEVEL_ROOT | string | `"INFO"` | | +| importer_rdbms.LOGGING_PATTERN_CONSOLE | string | `"%d{dd-MM-yyyy HH:mm:ss.SSS} %magenta([%thread]) %highlight(%-5level) %logger.%M - %msg%n"` | | +| importer_rdbms.datasource.host | string | `"operationsmysql"` | | +| importer_rdbms.datasource.password | string | `"password"` | | +| importer_rdbms.datasource.port | int | `3306` | | +| importer_rdbms.datasource.schema | string | `"tenants"` | | +| importer_rdbms.datasource.username | string | `"mifos"` | | +| importer_rdbms.deployment.affinity | object | `{}` | | +| importer_rdbms.deployment.annotations | object | `{}` | | +| importer_rdbms.deployment.envFrom | list | `[]` | | +| importer_rdbms.deployment.extraEnvs | string | `""` | | +| importer_rdbms.deployment.nodeSelector | object | `{}` | | +| importer_rdbms.deployment.resources.limits.cpu | string | `"500m"` | | +| importer_rdbms.deployment.resources.limits.memory | string | `"512M"` | | +| importer_rdbms.deployment.resources.requests.cpu | string | `"100m"` | | +| importer_rdbms.deployment.resources.requests.memory | string | `"512M"` | | +| importer_rdbms.deployment.securityContext.privileged | bool | `false` | | +| importer_rdbms.deployment.securityContext.runAsUser | int | `0` | | +| importer_rdbms.deployment.tolerations | list | `[]` | | +| importer_rdbms.enabled | bool | `true` | | +| importer_rdbms.envFrom | list | `[]` | | +| importer_rdbms.extraEnvs | string | `""` | | +| importer_rdbms.image | string | `""` | | +| importer_rdbms.imagePullPolicy | string | `"Always"` | | +| importer_rdbms.imageTag | string | `"v1.3.1"` | | +| importer_rdbms.javaToolOptions | string | `"-Xmx256M"` | | +| importer_rdbms.livenessProbe.failureThreshold | int | `3` | | +| importer_rdbms.livenessProbe.httpGet.path | string | `"/actuator/health/liveness"` | | +| importer_rdbms.livenessProbe.httpGet.port | int | `9191` | | +| importer_rdbms.livenessProbe.initialDelaySeconds | int | `120` | | +| importer_rdbms.livenessProbe.periodSeconds | int | `30` | | +| importer_rdbms.livenessProbe.timeoutSeconds | int | `5` | | +| importer_rdbms.managedServiceAccount | bool | `true` | | +| importer_rdbms.priorityClassName | string | `""` | | +| importer_rdbms.readinessProbe.failureThreshold | int | `3` | | +| importer_rdbms.readinessProbe.httpGet.path | string | `"/actuator/health/readiness"` | | +| importer_rdbms.readinessProbe.httpGet.port | int | `9191` | | +| importer_rdbms.readinessProbe.initialDelaySeconds | int | `120` | | +| importer_rdbms.readinessProbe.periodSeconds | int | `30` | | +| importer_rdbms.readinessProbe.timeoutSeconds | int | `5` | | +| importer_rdbms.replicas | int | `1` | | +| importer_rdbms.resources.limits.cpu | string | `"500m"` | | +| importer_rdbms.resources.limits.memory | string | `"512M"` | | +| importer_rdbms.resources.requests.cpu | string | `"100m"` | | +| importer_rdbms.resources.requests.memory | string | `"512M"` | | +| importer_rdbms.securityContext.privileged | bool | `false` | | +| importer_rdbms.securityContext.runAsUser | int | `0` | | +| importer_rdbms.serviceAccount | string | `""` | | +| importer_rdbms.serviceAccountAnnotations | object | `{}` | | +| importer_rdbms.terminationGracePeriod | int | `30` | | +| ingress.apiversion | string | `"networking.k8s.io/v1"` | | +| kafka.advertised.host | string | `"kafka"` | | +| kafka.advertised.port | string | `"9092"` | | +| kafka.deployment.annotations.deployTime | string | `"{{ .Values.deployTime }}"` | | +| kafka.enabled | bool | `true` | | +| kafka.image | string | `"spotify/kafka"` | | +| kafka.imagePullPolicy | string | `"Always"` | | +| kafka.limits.cpu | string | `"500m"` | | +| kafka.limits.memory | string | `"512M"` | | +| kafka.replicas | int | `1` | | +| kafka.requests.cpu | string | `"100m"` | | +| kafka.requests.memory | string | `"512M"` | | +| keycloak.enabled | bool | `true` | | +| keycloak.extraEnv | string | `"- name: KEYCLOAK_IMPORT\n value: /realm/kong-keycloak-realm.json\n"` | | +| keycloak.ingress.enabled | bool | `false` | | +| keycloak.ingress.ingressClassName | string | `"kong"` | | +| keycloak.ingress.rules[0].host | string | `"keycloak.mifos.io"` | | +| keycloak.ingress.tls | list | `[]` | | +| kibana.elasticsearchHosts | string | `"http://ph-ee-elasticsearch:9200/"` | | +| kibana.enabled | bool | `true` | | +| kibana.extraEnvs[0].name | string | `"ELASTICSEARCH_USERNAME"` | | +| kibana.extraEnvs[0].valueFrom.secretKeyRef.key | string | `"username"` | | +| kibana.extraEnvs[0].valueFrom.secretKeyRef.name | string | `"elastic-credentials"` | | +| kibana.extraEnvs[1].name | string | `"ELASTICSEARCH_PASSWORD"` | | +| kibana.extraEnvs[1].valueFrom.secretKeyRef.key | string | `"password"` | | +| kibana.extraEnvs[1].valueFrom.secretKeyRef.name | string | `"elastic-credentials"` | | +| kibana.extraEnvs[2].name | string | `"KIBANA_ENCRYPTION_KEY"` | | +| kibana.extraEnvs[2].valueFrom.secretKeyRef.key | string | `"encryptionkey"` | | +| kibana.extraEnvs[2].valueFrom.secretKeyRef.name | string | `"kibana"` | | +| kibana.fullnameOverride | string | `"ph-ee-kibana"` | | +| kibana.imageTag | string | `"7.16.3"` | | +| kibana.kibanaConfig."kibana.yml" | string | `"monitoring.enabled: false\nxpack.encryptedSavedObjects.encryptionKey: 5f4dcc3b5aa765d61d8327deb882cf99\nserver.ssl:\n enabled: false\n key: /usr/share/kibana/config/certs/elastic-certificate.pem\n certificate: /usr/share/kibana/config/certs/elastic-certificate.pem\nxpack.security.encryptionKey: ${KIBANA_ENCRYPTION_KEY}\nelasticsearch.ssl:\n certificateAuthorities: /usr/share/kibana/config/certs/elastic-certificate.pem\n verificationMode: certificate\n"` | | +| kibana.protocol | string | `"http"` | | +| kibana.secretMounts[0].name | string | `"elastic-certificate-pem"` | | +| kibana.secretMounts[0].path | string | `"/usr/share/kibana/config/certs"` | | +| kibana.secretMounts[0].secretName | string | `"elastic-certificate-pem"` | | +| kong.admin.enabled | bool | `true` | | +| kong.admin.http.enabled | bool | `true` | | +| kong.admin.ingress.enabled | bool | `true` | | +| kong.admin.ingress.hostname | string | `"kong-admin.mifos.io"` | | +| kong.admin.ingress.ingressClassName | string | `"kong"` | | +| kong.admin.tls.enabled | bool | `false` | | +| kong.enabled | bool | `false` | | +| kong.env.plugins | string | `"bundled,oidc"` | | +| kong.extraObjects[0].apiVersion | string | `"configuration.konghq.com/v1"` | | +| kong.extraObjects[0].config.remove.headers[0] | string | `"cookie"` | | +| kong.extraObjects[0].config.remove.headers[1] | string | `"x-id-token"` | | +| kong.extraObjects[0].disabled | bool | `false` | | +| kong.extraObjects[0].kind | string | `"KongClusterPlugin"` | | +| kong.extraObjects[0].metadata.annotations."kubernetes.io/ingress.class" | string | `"kong"` | | +| kong.extraObjects[0].metadata.labels.global | string | `"false"` | | +| kong.extraObjects[0].metadata.name | string | `"request-transformer"` | | +| kong.extraObjects[0].plugin | string | `"request-transformer"` | | +| kong.extraObjects[1].apiVersion | string | `"configuration.konghq.com/v1"` | | +| kong.extraObjects[1].config.credentials | bool | `true` | | +| kong.extraObjects[1].config.exposed_headers[0] | string | `"X-Auth-Token"` | | +| kong.extraObjects[1].config.max_age | int | `3600` | | +| kong.extraObjects[1].config.origins[0] | string | `"*"` | | +| kong.extraObjects[1].config.preflight_continue | bool | `false` | | +| kong.extraObjects[1].disabled | bool | `false` | | +| kong.extraObjects[1].kind | string | `"KongClusterPlugin"` | | +| kong.extraObjects[1].metadata.annotations."kubernetes.io/ingress.class" | string | `"kong"` | | +| kong.extraObjects[1].metadata.labels.global | string | `"true"` | | +| kong.extraObjects[1].metadata.name | string | `"cors"` | | +| kong.extraObjects[1].plugin | string | `"cors"` | | +| kong.extraObjects[2].apiVersion | string | `"configuration.konghq.com/v1"` | | +| kong.extraObjects[2].config.client_id | string | `"kong-oidc"` | | +| kong.extraObjects[2].config.client_secret | string | `"xxxxxxxx"` | | +| kong.extraObjects[2].config.discovery | string | `"https://keycloak.localhost/auth/realms/kong-oidc/.well-known/openid-configuration"` | | +| kong.extraObjects[2].config.realm | string | `"kong"` | | +| kong.extraObjects[2].config.scope | string | `"openid"` | | +| kong.extraObjects[2].disabled | bool | `false` | | +| kong.extraObjects[2].kind | string | `"KongClusterPlugin"` | | +| kong.extraObjects[2].metadata.annotations."kubernetes.io/ingress.class" | string | `"kong"` | | +| kong.extraObjects[2].metadata.labels.global | string | `"false"` | | +| kong.extraObjects[2].metadata.name | string | `"oidc"` | | +| kong.extraObjects[2].plugin | string | `"oidc"` | | +| kong.image.repository | string | `"revomatico/docker-kong-oidc"` | | +| kong.image.tag | string | `"latest"` | | +| messagegateway.CALLBACKCONFIG_HOST | string | `"ph-ee-connector-notifications"` | | +| messagegateway.DATASOURCE_URL | string | `"jdbc:mysql:thin://operationsmysql:3306/messagegateway"` | | +| messagegateway.HOSTCONFIG_HOST | string | `"message-gateway"` | | +| messagegateway.LOGGING_LEVEL_ROOT | string | `"INFO"` | | +| messagegateway.MYSQL_PASSWORD | string | `"password"` | | +| messagegateway.MYSQL_USERNAME | string | `"mifos"` | | +| messagegateway.PROVIDERSOURCE_FROMDATABASE | string | `"disabled"` | | +| messagegateway.PROVIDERSOURCE_FROMYML | string | `"enabled"` | | +| messagegateway.deployment.affinity | object | `{}` | | +| messagegateway.deployment.annotations | object | `{}` | | +| messagegateway.deployment.envFrom | list | `[]` | | +| messagegateway.deployment.extraEnvs | string | `""` | | +| messagegateway.deployment.nodeSelector | object | `{}` | | +| messagegateway.deployment.resources.limits.cpu | string | `"500m"` | | +| messagegateway.deployment.resources.limits.memory | string | `"512M"` | | +| messagegateway.deployment.resources.requests.cpu | string | `"100m"` | | +| messagegateway.deployment.resources.requests.memory | string | `"512M"` | | +| messagegateway.deployment.securityContext.privileged | bool | `false` | | +| messagegateway.deployment.securityContext.runAsUser | int | `0` | | +| messagegateway.deployment.tolerations | list | `[]` | | +| messagegateway.enabled | bool | `false` | | +| messagegateway.envFrom | list | `[]` | | +| messagegateway.extraEnvs | string | `""` | | +| messagegateway.hostname | string | `""` | | +| messagegateway.image | string | `""` | | +| messagegateway.imagePullPolicy | string | `"Always"` | | +| messagegateway.imageTag | string | `"v1.0.0"` | | +| messagegateway.ingress.annotations | object | `{}` | | +| messagegateway.ingress.backend | object | `{}` | | +| messagegateway.ingress.enabled | bool | `false` | | +| messagegateway.ingress.path | string | `"/messages"` | | +| messagegateway.livenessProbe.failureThreshold | int | `3` | | +| messagegateway.livenessProbe.httpGet.path | string | `"/actuator/health/liveness"` | | +| messagegateway.livenessProbe.httpGet.port | int | `9191` | | +| messagegateway.livenessProbe.initialDelaySeconds | int | `120` | | +| messagegateway.livenessProbe.periodSeconds | int | `30` | | +| messagegateway.livenessProbe.timeoutSeconds | int | `5` | | +| messagegateway.managedServiceAccount | bool | `true` | | +| messagegateway.priorityClassName | string | `""` | | +| messagegateway.readinessProbe.failureThreshold | int | `3` | | +| messagegateway.readinessProbe.httpGet.path | string | `"/actuator/health/readiness"` | | +| messagegateway.readinessProbe.httpGet.port | int | `9191` | | +| messagegateway.readinessProbe.initialDelaySeconds | int | `120` | | +| messagegateway.readinessProbe.periodSeconds | int | `30` | | +| messagegateway.readinessProbe.timeoutSeconds | int | `5` | | +| messagegateway.replicas | int | `1` | | +| messagegateway.resources.limits.cpu | string | `"500m"` | | +| messagegateway.resources.limits.memory | string | `"512M"` | | +| messagegateway.resources.requests.cpu | string | `"100m"` | | +| messagegateway.resources.requests.memory | string | `"512M"` | | +| messagegateway.secret.key.telerivet_api_key | string | `""` | | +| messagegateway.secret.name | string | `""` | | +| messagegateway.secret.value.api_key | string | `""` | | +| messagegateway.secret.value.project_id | string | `""` | | +| messagegateway.securityContext.privileged | bool | `false` | | +| messagegateway.securityContext.runAsUser | int | `0` | | +| messagegateway.serviceAccount | string | `""` | | +| messagegateway.serviceAccountAnnotations | object | `{}` | | +| messagegateway.terminationGracePeriod | int | `30` | | +| mock_oracle.deployment.annotations | object | `{}` | | +| mock_oracle.enabled | bool | `false` | | +| mock_oracle.hostname | string | `""` | | +| mock_oracle.image | string | `""` | | +| mock_oracle.imagePullPolicy | string | `"Always"` | | +| mock_oracle.ingress.annotations | object | `{}` | | +| mock_oracle.ingress.backend | object | `{}` | | +| mock_oracle.ingress.enabled | bool | `true` | | +| mock_oracle.ingress.path | string | `"/"` | | +| mock_oracle.limits.cpu | string | `"500m"` | | +| mock_oracle.limits.memory | string | `"512M"` | | +| mock_oracle.replicas | int | `1` | | +| mock_oracle.requests.cpu | string | `"100m"` | | +| mock_oracle.requests.memory | string | `"512M"` | | +| mock_oracle.service.targetport | int | `4100` | | +| mpesa.LOGGING_LEVEL_ROOT | string | `"INFO"` | | +| mpesa.SPRING_PROFILES_ACTIVE | string | `""` | | +| mpesa.accounts.default.api_host | string | `"https://sandbox.safaricom.co.ke"` | | +| mpesa.accounts.default.auth_host | string | `"https://sandbox.safaricom.co.ke/oauth/v1/generate"` | | +| mpesa.accounts.default.business_short_code | string | `"7385028"` | | +| mpesa.accounts.default.client_key | string | `"0pLxbN83FrOl5Nd0Fh9Zi5BQlMxSL2n5"` | | +| mpesa.accounts.default.client_secret | string | `"YzuGNoJxeub8ZC6d"` | | +| mpesa.accounts.default.name | string | `"default"` | | +| mpesa.accounts.default.pass_key | string | `"bfb279f9aa9bdbcf158e97dd71a467cd2e0c893059b10f78e6b72ada1ed2c919"` | | +| mpesa.accounts.default.till | string | `"1234567"` | | +| mpesa.accounts.paygops.api_host | string | `"https://sandbox.safaricom.co.ke"` | | +| mpesa.accounts.paygops.auth_host | string | `"https://sandbox.safaricom.co.ke/oauth/v1/generate"` | | +| mpesa.accounts.paygops.business_short_code | string | `"174379"` | | +| mpesa.accounts.paygops.client_key | string | `"0pLxbN83FrOl5Nd0Fh9Zi5BQlMxSL2n5"` | | +| mpesa.accounts.paygops.client_secret | string | `"YzuGNoJxeub8ZC6d"` | | +| mpesa.accounts.paygops.name | string | `"paygops"` | | +| mpesa.accounts.paygops.pass_key | string | `"bfb279f9aa9bdbcf158e97dd71a467cd2e0c893059b10f78e6b72ada1ed2c919"` | | +| mpesa.accounts.paygops.till | string | `"9347335"` | | +| mpesa.accounts.roster.api_host | string | `"https://sandbox.safaricom.co.ke"` | | +| mpesa.accounts.roster.auth_host | string | `"https://sandbox.safaricom.co.ke/oauth/v1/generate"` | | +| mpesa.accounts.roster.business_short_code | string | `"7385028"` | | +| mpesa.accounts.roster.client_key | string | `"0pLxbN83FrOl5Nd0Fh9Zi5BQlMxSL2n5"` | | +| mpesa.accounts.roster.client_secret | string | `"YzuGNoJxeub8ZC6d"` | | +| mpesa.accounts.roster.name | string | `"roster"` | | +| mpesa.accounts.roster.pass_key | string | `"bfb279f9aa9bdbcf158e97dd71a467cd2e0c893059b10f78e6b72ada1ed2c919"` | | +| mpesa.accounts.roster.till | string | `"1234567"` | | +| mpesa.callback_host | string | `""` | | +| mpesa.channel.host | string | `""` | | +| mpesa.deployment.affinity | object | `{}` | | +| mpesa.deployment.annotations | object | `{}` | | +| mpesa.deployment.envFrom | list | `[]` | | +| mpesa.deployment.extraEnvs | string | `""` | | +| mpesa.deployment.nodeSelector | object | `{}` | | +| mpesa.deployment.resources.limits.cpu | string | `"500m"` | | +| mpesa.deployment.resources.limits.memory | string | `"512M"` | | +| mpesa.deployment.resources.requests.cpu | string | `"100m"` | | +| mpesa.deployment.resources.requests.memory | string | `"512M"` | | +| mpesa.deployment.securityContext.privileged | bool | `false` | | +| mpesa.deployment.securityContext.runAsUser | int | `0` | | +| mpesa.deployment.tolerations | list | `[]` | | +| mpesa.enabled | bool | `false` | | +| mpesa.envFrom | list | `[]` | | +| mpesa.extraEnvs | string | `""` | | +| mpesa.hostname | string | `""` | | +| mpesa.image | string | `""` | | +| mpesa.imagePullPolicy | string | `"Always"` | | +| mpesa.imageTag | string | `"v1.4.1"` | | +| mpesa.ingress.annotations | object | `{}` | | +| mpesa.ingress.backend | object | `{}` | | +| mpesa.ingress.enabled | bool | `false` | | +| mpesa.ingress.path | string | `"/mpesa"` | | +| mpesa.livenessProbe.failureThreshold | int | `3` | | +| mpesa.livenessProbe.httpGet.path | string | `"/actuator/health/liveness"` | | +| mpesa.livenessProbe.httpGet.port | int | `9191` | | +| mpesa.livenessProbe.initialDelaySeconds | int | `120` | | +| mpesa.livenessProbe.periodSeconds | int | `30` | | +| mpesa.livenessProbe.timeoutSeconds | int | `5` | | +| mpesa.managedServiceAccount | bool | `true` | | +| mpesa.paybill.accountHoldingInstitutionId | string | `"default"` | | +| mpesa.paybill.paygops.business_short_code | string | `"24322607"` | | +| mpesa.paybill.paygops.currency | string | `"KES"` | | +| mpesa.paybill.roster.business_short_code | string | `"12345678"` | | +| mpesa.paybill.roster.currency | string | `"KES"` | | +| mpesa.paygops.host | string | `""` | | +| mpesa.priorityClassName | string | `""` | | +| mpesa.readinessProbe.failureThreshold | int | `3` | | +| mpesa.readinessProbe.httpGet.path | string | `"/actuator/health/readiness"` | | +| mpesa.readinessProbe.httpGet.port | int | `9191` | | +| mpesa.readinessProbe.initialDelaySeconds | int | `120` | | +| mpesa.readinessProbe.periodSeconds | int | `30` | | +| mpesa.readinessProbe.timeoutSeconds | int | `5` | | +| mpesa.replicas | int | `1` | | +| mpesa.resources.limits.cpu | string | `"500m"` | | +| mpesa.resources.limits.memory | string | `"512M"` | | +| mpesa.resources.requests.cpu | string | `"100m"` | | +| mpesa.resources.requests.memory | string | `"512M"` | | +| mpesa.roster.host | string | `""` | | +| mpesa.securityContext.privileged | bool | `false` | | +| mpesa.securityContext.runAsUser | int | `0` | | +| mpesa.serviceAccount | string | `""` | | +| mpesa.serviceAccountAnnotations | object | `{}` | | +| mpesa.serviceAccountName | string | `""` | | +| mpesa.tenant | string | `""` | | +| mpesa.terminationGracePeriod | int | `30` | | +| mpesa.zeebe_broker_contactpoint | string | `"zeebe-zeebe-gateway:26500"` | | +| mpesa.zeebe_init_transfer_wait_timer | int | `10` | | +| notifications.LOGGING_LEVEL_ROOT | string | `"INFO"` | | +| notifications.MESSAGEGATEWAYCONFIG_HOST | string | `"message-gateway"` | | +| notifications.NOTIFICATION_FAILURE_ENABLED | string | `"true"` | | +| notifications.NOTIFICATION_LOCAL_HOST | string | `"ph-ee-connector-notifications"` | | +| notifications.NOTIFICATION_SUCCESS_ENABLED | string | `"false"` | | +| notifications.SPRING_PROFILES_ACTIVE | string | `""` | | +| notifications.deployment.affinity | object | `{}` | | +| notifications.deployment.annotations | object | `{}` | | +| notifications.deployment.envFrom | list | `[]` | | +| notifications.deployment.extraEnvs | string | `""` | | +| notifications.deployment.nodeSelector | object | `{}` | | +| notifications.deployment.resources.limits.cpu | string | `"500m"` | | +| notifications.deployment.resources.limits.memory | string | `"512M"` | | +| notifications.deployment.resources.requests.cpu | string | `"100m"` | | +| notifications.deployment.resources.requests.memory | string | `"512"` | | +| notifications.deployment.securityContext.privileged | bool | `false` | | +| notifications.deployment.securityContext.runAsUser | int | `0` | | +| notifications.deployment.tolerations | list | `[]` | | +| notifications.enabled | bool | `true` | | +| notifications.envFrom | list | `[]` | | +| notifications.extraEnvs | string | `""` | | +| notifications.hostconfig.host | string | `""` | | +| notifications.hostconfig.port | string | `""` | | +| notifications.hostname | string | `""` | | +| notifications.image | string | `""` | | +| notifications.imagePullPolicy | string | `"Always"` | | +| notifications.imageTag | string | `"v1.1.0"` | | +| notifications.ingress.annotations | object | `{}` | | +| notifications.ingress.backend | object | `{}` | | +| notifications.ingress.enabled | bool | `false` | | +| notifications.ingress.path | string | `"/notifications"` | | +| notifications.livenessProbe.failureThreshold | int | `3` | | +| notifications.livenessProbe.httpGet.path | string | `"/actuator/health/liveness"` | | +| notifications.livenessProbe.httpGet.port | int | `9191` | | +| notifications.livenessProbe.initialDelaySeconds | int | `120` | | +| notifications.livenessProbe.periodSeconds | int | `30` | | +| notifications.livenessProbe.timeoutSeconds | int | `5` | | +| notifications.managedServiceAccount | bool | `true` | | +| notifications.priorityClassName | string | `""` | | +| notifications.readinessProbe.failureThreshold | int | `3` | | +| notifications.readinessProbe.httpGet.path | string | `"/actuator/health/readiness"` | | +| notifications.readinessProbe.httpGet.port | int | `9191` | | +| notifications.readinessProbe.initialDelaySeconds | int | `120` | | +| notifications.readinessProbe.periodSeconds | int | `30` | | +| notifications.readinessProbe.timeoutSeconds | int | `5` | | +| notifications.replicas | int | `1` | | +| notifications.resources.limits.cpu | string | `"500m"` | | +| notifications.resources.limits.memory | string | `"512M"` | | +| notifications.resources.requests.cpu | string | `"100m"` | | +| notifications.resources.requests.memory | string | `"512M"` | | +| notifications.securityContext.privileged | bool | `false` | | +| notifications.securityContext.runAsUser | int | `0` | | +| notifications.serviceAccount | string | `""` | | +| notifications.serviceAccountAnnotations | object | `{}` | | +| notifications.terminationGracePeriod | int | `30` | | +| notifications.zeebe_broker_contactpoint | string | `"zeebe-zeebe-gateway:26500"` | | +| operations.enabled | bool | `true` | | +| operations.mysql.enabled | bool | `true` | | +| operations_app.LOGGING_LEVEL_ROOT | string | `"INFO"` | | +| operations_app.LOGGING_PATTERN_CONSOLE | string | `"%d{dd-MM-yyyy HH:mm:ss.SSS} %magenta([%thread]) %highlight(%-5level) %logger.%M - %msg%n"` | | +| operations_app.SPRING_PROFILES_ACTIVE | string | `""` | | +| operations_app.datasource.host | string | `"operationsmysql"` | | +| operations_app.datasource.password | string | `"password"` | | +| operations_app.datasource.port | int | `3306` | | +| operations_app.datasource.schema | string | `"tenants"` | | +| operations_app.datasource.username | string | `"mifos"` | | +| operations_app.deployment.affinity | object | `{}` | | +| operations_app.deployment.annotations | object | `{}` | | +| operations_app.deployment.envFrom | list | `[]` | | +| operations_app.deployment.extraEnvs | string | `""` | | +| operations_app.deployment.nodeSelector | object | `{}` | | +| operations_app.deployment.resources.limits.cpu | string | `"500m"` | | +| operations_app.deployment.resources.limits.memory | string | `"512M"` | | +| operations_app.deployment.resources.requests.cpu | string | `"100m"` | | +| operations_app.deployment.resources.requests.memory | string | `"512M"` | | +| operations_app.deployment.securityContext.privileged | bool | `false` | | +| operations_app.deployment.securityContext.runAsUser | int | `0` | | +| operations_app.deployment.tolerations | list | `[]` | | +| operations_app.enabled | bool | `true` | | +| operations_app.envFrom | list | `[]` | | +| operations_app.extraEnvs | string | `""` | | +| operations_app.hostname | string | `""` | | +| operations_app.image | string | `""` | | +| operations_app.imagePullPolicy | string | `"Always"` | | +| operations_app.imageTag | string | `"v1.4.0"` | | +| operations_app.ingress.annotations | object | `{}` | | +| operations_app.ingress.backend | object | `{}` | | +| operations_app.ingress.enabled | bool | `false` | | +| operations_app.ingress.path | string | `"/opsapp"` | | +| operations_app.livenessProbe.failureThreshold | int | `3` | | +| operations_app.livenessProbe.httpGet.path | string | `"/actuator/health/liveness"` | | +| operations_app.livenessProbe.httpGet.port | int | `9191` | | +| operations_app.livenessProbe.initialDelaySeconds | int | `120` | | +| operations_app.livenessProbe.periodSeconds | int | `30` | | +| operations_app.livenessProbe.timeoutSeconds | int | `5` | | +| operations_app.managedServiceAccount | bool | `true` | | +| operations_app.priorityClassName | string | `""` | | +| operations_app.readinessProbe.failureThreshold | int | `3` | | +| operations_app.readinessProbe.httpGet.path | string | `"/actuator/health/readiness"` | | +| operations_app.readinessProbe.httpGet.port | int | `9191` | | +| operations_app.readinessProbe.initialDelaySeconds | int | `120` | | +| operations_app.readinessProbe.periodSeconds | int | `30` | | +| operations_app.readinessProbe.timeoutSeconds | int | `5` | | +| operations_app.replicas | int | `1` | | +| operations_app.resources.limits.cpu | string | `"500m"` | | +| operations_app.resources.limits.memory | string | `"512M"` | | +| operations_app.resources.requests.cpu | string | `"100m"` | | +| operations_app.resources.requests.memory | string | `"512M"` | | +| operations_app.securityContext.privileged | bool | `false` | | +| operations_app.securityContext.runAsUser | int | `0` | | +| operations_app.serviceAccount | string | `""` | | +| operations_app.serviceAccountAnnotations | object | `{}` | | +| operations_app.tenants | string | `""` | | +| operations_app.terminationGracePeriod | int | `30` | | +| operations_app.token_client_channel_secret | string | `""` | | +| operations_web.deployment.affinity | object | `{}` | | +| operations_web.deployment.annotations | object | `{}` | | +| operations_web.deployment.config[0].mountPath | string | `"/usr/share/nginx/html/assets/configuration.properties"` | | +| operations_web.deployment.config[0].name | string | `"ph-ee-operations-web-config"` | | +| operations_web.deployment.config[0].subPath | string | `"configuration.properties"` | | +| operations_web.deployment.envFrom | list | `[]` | | +| operations_web.deployment.extraEnvs | string | `""` | | +| operations_web.deployment.nodeSelector | object | `{}` | | +| operations_web.deployment.resources.limits.cpu | string | `"500m"` | | +| operations_web.deployment.resources.limits.memory | string | `"512M"` | | +| operations_web.deployment.resources.requests.cpu | string | `"100m"` | | +| operations_web.deployment.resources.requests.memory | string | `"512M"` | | +| operations_web.deployment.securityContext.privileged | bool | `false` | | +| operations_web.deployment.securityContext.runAsUser | int | `0` | | +| operations_web.deployment.tolerations | list | `[]` | | +| operations_web.enabled | bool | `true` | | +| operations_web.envFrom | list | `[]` | | +| operations_web.extraEnvs | string | `""` | | +| operations_web.hostname | string | `""` | | +| operations_web.image | string | `""` | | +| operations_web.imagePullPolicy | string | `"Always"` | | +| operations_web.imagePullSecrets | list | `[]` | | +| operations_web.imageTag | string | `"v1.3.2"` | | +| operations_web.ingress.annotations."konghq.com/plugins" | string | `"request-transformer,oidc"` | | +| operations_web.ingress.annotations."kubernetes.io/ingress.class" | string | `"kong"` | | +| operations_web.ingress.backend | object | `{}` | | +| operations_web.ingress.enabled | bool | `false` | | +| operations_web.ingress.path | string | `"/"` | | +| operations_web.livenessProbe.failureThreshold | int | `3` | | +| operations_web.livenessProbe.httpGet.path | string | `"/actuator/health/liveness"` | | +| operations_web.livenessProbe.httpGet.port | int | `9191` | | +| operations_web.livenessProbe.initialDelaySeconds | int | `120` | | +| operations_web.livenessProbe.periodSeconds | int | `30` | | +| operations_web.livenessProbe.timeoutSeconds | int | `5` | | +| operations_web.managedServiceAccount | bool | `true` | | +| operations_web.priorityClassName | string | `""` | | +| operations_web.readinessProbe.failureThreshold | int | `3` | | +| operations_web.readinessProbe.httpGet.path | string | `"/actuator/health/readiness"` | | +| operations_web.readinessProbe.httpGet.port | int | `9191` | | +| operations_web.readinessProbe.initialDelaySeconds | int | `120` | | +| operations_web.readinessProbe.periodSeconds | int | `30` | | +| operations_web.readinessProbe.timeoutSeconds | int | `5` | | +| operations_web.replicas | int | `1` | | +| operations_web.resources.limits.cpu | string | `"500m"` | | +| operations_web.resources.limits.memory | string | `"512M"` | | +| operations_web.resources.requests.cpu | string | `"100m"` | | +| operations_web.resources.requests.memory | string | `"512M"` | | +| operations_web.securityContext.privileged | bool | `false` | | +| operations_web.securityContext.runAsUser | int | `0` | | +| operations_web.serviceAccount | string | `""` | | +| operations_web.serviceAccountAnnotations | object | `{}` | | +| operations_web.terminationGracePeriod | int | `30` | | +| operations_web.webhost | string | `""` | | +| operationsmysql.auth.database | string | `"tenants"` | | +| operationsmysql.auth.password | string | `"password"` | | +| operationsmysql.auth.rootPassword | string | `"4ET6ywqlGt"` | | +| operationsmysql.auth.username | string | `"mifos"` | | +| operationsmysql.fullnameOverride | string | `"operationsmysql"` | | +| operationsmysql.image.debug | bool | `false` | | +| operationsmysql.image.tag | string | `"5.7"` | | +| operationsmysql.initdbScripts."setup.sql" | string | `"CREATE DATABASE IF NOT EXISTS phdefault;\nCREATE DATABASE IF NOT EXISTS messagegateway;\nGRANT ALL ON *.* TO 'root'@'%';\nGRANT ALL PRIVILEGES ON messagegateway.* TO 'mifos';\nGRANT ALL PRIVILEGES ON phdefault.* TO 'mifos';"` | | +| paygops_connector.LOGGING_LEVEL_ROOT | string | `"INFO"` | | +| paygops_connector.SPRING_PROFILES_ACTIVE | string | `""` | | +| paygops_connector.ams.local.enabled | string | `""` | | +| paygops_connector.containerPort | int | `5000` | | +| paygops_connector.deployment.affinity | object | `{}` | | +| paygops_connector.deployment.annotations | object | `{}` | | +| paygops_connector.deployment.envFrom | list | `[]` | | +| paygops_connector.deployment.extraEnvs | string | `""` | | +| paygops_connector.deployment.nodeSelector | object | `{}` | | +| paygops_connector.deployment.resources.limits.cpu | string | `"500m"` | | +| paygops_connector.deployment.resources.limits.memory | string | `"512M"` | | +| paygops_connector.deployment.resources.requests.cpu | string | `"100m"` | | +| paygops_connector.deployment.resources.requests.memory | string | `"512M"` | | +| paygops_connector.deployment.securityContext.privileged | bool | `false` | | +| paygops_connector.deployment.securityContext.runAsUser | int | `0` | | +| paygops_connector.deployment.tolerations | list | `[]` | | +| paygops_connector.enabled | bool | `false` | | +| paygops_connector.envFrom | list | `[]` | | +| paygops_connector.extraEnvs | string | `""` | | +| paygops_connector.image | string | `""` | | +| paygops_connector.imagePullPolicy | string | `"Always"` | | +| paygops_connector.imageTag | string | `"v1.5.0"` | | +| paygops_connector.livenessProbe.failureThreshold | int | `3` | | +| paygops_connector.livenessProbe.httpGet.path | string | `"/actuator/health/liveness"` | | +| paygops_connector.livenessProbe.httpGet.port | int | `9191` | | +| paygops_connector.livenessProbe.initialDelaySeconds | int | `120` | | +| paygops_connector.livenessProbe.periodSeconds | int | `30` | | +| paygops_connector.livenessProbe.timeoutSeconds | int | `5` | | +| paygops_connector.managedServiceAccount | bool | `true` | | +| paygops_connector.paygops.authheader | string | `""` | | +| paygops_connector.priorityClassName | string | `""` | | +| paygops_connector.readinessProbe.failureThreshold | int | `3` | | +| paygops_connector.readinessProbe.httpGet.path | string | `"/actuator/health/readiness"` | | +| paygops_connector.readinessProbe.httpGet.port | int | `9191` | | +| paygops_connector.readinessProbe.initialDelaySeconds | int | `120` | | +| paygops_connector.readinessProbe.periodSeconds | int | `30` | | +| paygops_connector.readinessProbe.timeoutSeconds | int | `5` | | +| paygops_connector.replicas | int | `1` | | +| paygops_connector.resources.limits.cpu | string | `"500m"` | | +| paygops_connector.resources.limits.memory | string | `"512M"` | | +| paygops_connector.resources.requests.cpu | string | `"100m"` | | +| paygops_connector.resources.requests.memory | string | `"512M"` | | +| paygops_connector.securityContext.privileged | bool | `false` | | +| paygops_connector.securityContext.runAsUser | int | `0` | | +| paygops_connector.serviceAccount | string | `""` | | +| paygops_connector.serviceAccountAnnotations | object | `{}` | | +| paygops_connector.terminationGracePeriod | int | `30` | | +| ph_ee_connector_ams_mifos.SPRING_PROFILES_ACTIVE | string | `""` | | +| ph_ee_connector_ams_mifos.ams_local_account_host | string | `""` | | +| ph_ee_connector_ams_mifos.ams_local_auth_host | string | `""` | | +| ph_ee_connector_ams_mifos.ams_local_customer_host | string | `""` | | +| ph_ee_connector_ams_mifos.ams_local_enabled | bool | `false` | | +| ph_ee_connector_ams_mifos.ams_local_interop_host | string | `""` | | +| ph_ee_connector_ams_mifos.ams_local_loan_host | string | `""` | | +| ph_ee_connector_ams_mifos.ams_local_tenants | string | `""` | | +| ph_ee_connector_ams_mifos.deployment.affinity | object | `{}` | | +| ph_ee_connector_ams_mifos.deployment.annotations | object | `{}` | | +| ph_ee_connector_ams_mifos.deployment.envFrom | list | `[]` | | +| ph_ee_connector_ams_mifos.deployment.extraEnvs | string | `""` | | +| ph_ee_connector_ams_mifos.deployment.nodeSelector | object | `{}` | | +| ph_ee_connector_ams_mifos.deployment.resources.limits.cpu | string | `"500m"` | | +| ph_ee_connector_ams_mifos.deployment.resources.limits.memory | string | `"512M"` | | +| ph_ee_connector_ams_mifos.deployment.resources.requests.cpu | string | `"100m"` | | +| ph_ee_connector_ams_mifos.deployment.resources.requests.memory | string | `"512M"` | | +| ph_ee_connector_ams_mifos.deployment.securityContext.privileged | bool | `false` | | +| ph_ee_connector_ams_mifos.deployment.securityContext.runAsUser | int | `0` | | +| ph_ee_connector_ams_mifos.deployment.tolerations | list | `[]` | | +| ph_ee_connector_ams_mifos.enabled | bool | `true` | | +| ph_ee_connector_ams_mifos.envFrom | list | `[]` | | +| ph_ee_connector_ams_mifos.extraEnvs | string | `""` | | +| ph_ee_connector_ams_mifos.image | string | `""` | | +| ph_ee_connector_ams_mifos.imagePullPolicy | string | `"Always"` | | +| ph_ee_connector_ams_mifos.imageTag | string | `"v1.2.2"` | | +| ph_ee_connector_ams_mifos.ingress.annotations | object | `{}` | | +| ph_ee_connector_ams_mifos.ingress.backend | object | `{}` | | +| ph_ee_connector_ams_mifos.ingress.enabled | bool | `false` | | +| ph_ee_connector_ams_mifos.ingress.path | string | `"/"` | | +| ph_ee_connector_ams_mifos.managedServiceAccount | bool | `true` | | +| ph_ee_connector_ams_mifos.priorityClassName | string | `""` | | +| ph_ee_connector_ams_mifos.replicas | int | `1` | | +| ph_ee_connector_ams_mifos.resources.limits.cpu | string | `"500m"` | | +| ph_ee_connector_ams_mifos.resources.limits.memory | string | `"512M"` | | +| ph_ee_connector_ams_mifos.resources.requests.cpu | string | `"100m"` | | +| ph_ee_connector_ams_mifos.resources.requests.memory | string | `"512M"` | | +| ph_ee_connector_ams_mifos.securityContext.privileged | bool | `false` | | +| ph_ee_connector_ams_mifos.securityContext.runAsUser | int | `0` | | +| ph_ee_connector_ams_mifos.serviceAccount | string | `""` | | +| ph_ee_connector_ams_mifos.serviceAccountAnnotations | object | `{}` | | +| ph_ee_connector_ams_mifos.terminationGracePeriod | int | `30` | | +| ph_ee_connector_gsma.SPRING_PROFILES_ACTIVE | string | `""` | | +| ph_ee_connector_gsma.deployment.affinity | object | `{}` | | +| ph_ee_connector_gsma.deployment.annotations | object | `{}` | | +| ph_ee_connector_gsma.deployment.envFrom | list | `[]` | | +| ph_ee_connector_gsma.deployment.extraEnvs | string | `""` | | +| ph_ee_connector_gsma.deployment.nodeSelector | object | `{}` | | +| ph_ee_connector_gsma.deployment.resources.limits.cpu | string | `"500m"` | | +| ph_ee_connector_gsma.deployment.resources.limits.memory | string | `"512M"` | | +| ph_ee_connector_gsma.deployment.resources.requests.cpu | string | `"100m"` | | +| ph_ee_connector_gsma.deployment.resources.requests.memory | string | `"512M"` | | +| ph_ee_connector_gsma.deployment.securityContext.privileged | bool | `false` | | +| ph_ee_connector_gsma.deployment.securityContext.runAsUser | int | `0` | | +| ph_ee_connector_gsma.deployment.tolerations | list | `[]` | | +| ph_ee_connector_gsma.enabled | bool | `true` | | +| ph_ee_connector_gsma.envFrom | list | `[]` | | +| ph_ee_connector_gsma.extraEnvs | string | `""` | | +| ph_ee_connector_gsma.image | string | `""` | | +| ph_ee_connector_gsma.imagePullPolicy | string | `"Always"` | | +| ph_ee_connector_gsma.imageTag | string | `"v1.0.0"` | | +| ph_ee_connector_gsma.managedServiceAccount | bool | `true` | | +| ph_ee_connector_gsma.priorityClassName | string | `""` | | +| ph_ee_connector_gsma.replicas | int | `1` | | +| ph_ee_connector_gsma.resources.limits.cpu | string | `"500m"` | | +| ph_ee_connector_gsma.resources.limits.memory | string | `"512M"` | | +| ph_ee_connector_gsma.resources.requests.cpu | string | `"100m"` | | +| ph_ee_connector_gsma.resources.requests.memory | string | `"512M"` | | +| ph_ee_connector_gsma.securityContext.privileged | bool | `false` | | +| ph_ee_connector_gsma.securityContext.runAsUser | int | `0` | | +| ph_ee_connector_gsma.serviceAccount | string | `""` | | +| ph_ee_connector_gsma.serviceAccountAnnotations | object | `{}` | | +| ph_ee_connector_gsma.terminationGracePeriod | int | `30` | | +| ph_ee_connector_mojaloop.SPRING_PROFILES_ACTIVE | string | `""` | | +| ph_ee_connector_mojaloop.deployment.affinity | object | `{}` | | +| ph_ee_connector_mojaloop.deployment.annotations | object | `{}` | | +| ph_ee_connector_mojaloop.deployment.envFrom | list | `[]` | | +| ph_ee_connector_mojaloop.deployment.extraEnvs | string | `""` | | +| ph_ee_connector_mojaloop.deployment.nodeSelector | object | `{}` | | +| ph_ee_connector_mojaloop.deployment.resources.limits.cpu | string | `"500m"` | | +| ph_ee_connector_mojaloop.deployment.resources.limits.memory | string | `"512M"` | | +| ph_ee_connector_mojaloop.deployment.resources.requests.cpu | string | `"100m"` | | +| ph_ee_connector_mojaloop.deployment.resources.requests.memory | string | `"512M"` | | +| ph_ee_connector_mojaloop.deployment.securityContext.privileged | bool | `false` | | +| ph_ee_connector_mojaloop.deployment.securityContext.runAsUser | int | `0` | | +| ph_ee_connector_mojaloop.deployment.tolerations | list | `[]` | | +| ph_ee_connector_mojaloop.enabled | bool | `false` | | +| ph_ee_connector_mojaloop.envFrom | list | `[]` | | +| ph_ee_connector_mojaloop.extraEnvs | string | `""` | | +| ph_ee_connector_mojaloop.image | string | `""` | | +| ph_ee_connector_mojaloop.imagePullPolicy | string | `"Always"` | | +| ph_ee_connector_mojaloop.imageTag | string | `"v1.1.0"` | | +| ph_ee_connector_mojaloop.ingress.annotations | object | `{}` | | +| ph_ee_connector_mojaloop.ingress.backend | object | `{}` | | +| ph_ee_connector_mojaloop.ingress.enabled | bool | `true` | | +| ph_ee_connector_mojaloop.ingress.path | string | `"/"` | | +| ph_ee_connector_mojaloop.livenessProbe.failureThreshold | int | `3` | | +| ph_ee_connector_mojaloop.livenessProbe.httpGet.path | string | `"/actuator/health/liveness"` | | +| ph_ee_connector_mojaloop.livenessProbe.httpGet.port | int | `9191` | | +| ph_ee_connector_mojaloop.livenessProbe.initialDelaySeconds | int | `120` | | +| ph_ee_connector_mojaloop.livenessProbe.periodSeconds | int | `30` | | +| ph_ee_connector_mojaloop.livenessProbe.timeoutSeconds | int | `5` | | +| ph_ee_connector_mojaloop.managedServiceAccount | bool | `true` | | +| ph_ee_connector_mojaloop.priorityClassName | string | `""` | | +| ph_ee_connector_mojaloop.readinessProbe.failureThreshold | int | `3` | | +| ph_ee_connector_mojaloop.readinessProbe.httpGet.path | string | `"/actuator/health/readiness"` | | +| ph_ee_connector_mojaloop.readinessProbe.httpGet.port | int | `9191` | | +| ph_ee_connector_mojaloop.readinessProbe.initialDelaySeconds | int | `120` | | +| ph_ee_connector_mojaloop.readinessProbe.periodSeconds | int | `30` | | +| ph_ee_connector_mojaloop.readinessProbe.timeoutSeconds | int | `5` | | +| ph_ee_connector_mojaloop.replicas | int | `1` | | +| ph_ee_connector_mojaloop.resources.limits.cpu | string | `"500m"` | | +| ph_ee_connector_mojaloop.resources.limits.memory | string | `"512M"` | | +| ph_ee_connector_mojaloop.resources.requests.cpu | string | `"100m"` | | +| ph_ee_connector_mojaloop.resources.requests.memory | string | `"512M"` | | +| ph_ee_connector_mojaloop.securityContext.privileged | bool | `false` | | +| ph_ee_connector_mojaloop.securityContext.runAsUser | int | `0` | | +| ph_ee_connector_mojaloop.serviceAccount | string | `""` | | +| ph_ee_connector_mojaloop.serviceAccountAnnotations | object | `{}` | | +| ph_ee_connector_mojaloop.switch.als.host | string | `""` | | +| ph_ee_connector_mojaloop.switch.als.service | string | `""` | | +| ph_ee_connector_mojaloop.switch.oracle.host | string | `""` | | +| ph_ee_connector_mojaloop.switch.quotes.host | string | `""` | | +| ph_ee_connector_mojaloop.switch.quotes.service | string | `""` | | +| ph_ee_connector_mojaloop.switch.transactions.host | string | `""` | | +| ph_ee_connector_mojaloop.switch.transactions.service | string | `""` | | +| ph_ee_connector_mojaloop.switch.transfers.host | string | `""` | | +| ph_ee_connector_mojaloop.switch.transfers.service | string | `""` | | +| ph_ee_connector_mojaloop.terminationGracePeriod | int | `30` | | +| ph_ee_connector_slcb.SPRING_PROFILES_ACTIVE | string | `""` | | +| ph_ee_connector_slcb.account_number | string | `"003001003879112168"` | | +| ph_ee_connector_slcb.account_type | int | `0` | | +| ph_ee_connector_slcb.api_host | string | `"https://g2p-test.slcb.com:8443"` | | +| ph_ee_connector_slcb.auth_host | string | `"https://g2p-test.slcb.com:8443"` | | +| ph_ee_connector_slcb.config.date_format | string | `"yyyy-MM-dd'T'hh:mm:ssXXX"` | | +| ph_ee_connector_slcb.config.reconciliation.enable | bool | `false` | | +| ph_ee_connector_slcb.deployment.affinity | object | `{}` | | +| ph_ee_connector_slcb.deployment.annotations | object | `{}` | | +| ph_ee_connector_slcb.deployment.envFrom | list | `[]` | | +| ph_ee_connector_slcb.deployment.extraEnvs | string | `""` | | +| ph_ee_connector_slcb.deployment.nodeSelector | object | `{}` | | +| ph_ee_connector_slcb.deployment.resources.limits.cpu | string | `"500m"` | | +| ph_ee_connector_slcb.deployment.resources.limits.memory | string | `"512M"` | | +| ph_ee_connector_slcb.deployment.resources.requests.cpu | string | `"100m"` | | +| ph_ee_connector_slcb.deployment.resources.requests.memory | string | `"512M"` | | +| ph_ee_connector_slcb.deployment.securityContext.privileged | bool | `false` | | +| ph_ee_connector_slcb.deployment.securityContext.runAsUser | int | `0` | | +| ph_ee_connector_slcb.deployment.tolerations | list | `[]` | | +| ph_ee_connector_slcb.enabled | bool | `true` | | +| ph_ee_connector_slcb.endpoint.account_balance | string | `"/accountBalance"` | | +| ph_ee_connector_slcb.endpoint.auth | string | `"/api/auth"` | | +| ph_ee_connector_slcb.endpoint.reconciliation | string | `"/reconciliation"` | | +| ph_ee_connector_slcb.endpoint.transaction_request | string | `"/api/transactionRequest"` | | +| ph_ee_connector_slcb.envFrom | list | `[]` | | +| ph_ee_connector_slcb.extraEnvs | string | `""` | | +| ph_ee_connector_slcb.image | string | `""` | | +| ph_ee_connector_slcb.imagePullPolicy | string | `"Always"` | | +| ph_ee_connector_slcb.imageTag | string | `"v1.1.1"` | | +| ph_ee_connector_slcb.institutioncode | string | `"SLCB"` | | +| ph_ee_connector_slcb.livenessProbe.failureThreshold | int | `3` | | +| ph_ee_connector_slcb.livenessProbe.httpGet.path | string | `"/actuator/health/liveness"` | | +| ph_ee_connector_slcb.livenessProbe.httpGet.port | int | `9191` | | +| ph_ee_connector_slcb.livenessProbe.initialDelaySeconds | int | `120` | | +| ph_ee_connector_slcb.livenessProbe.periodSeconds | int | `30` | | +| ph_ee_connector_slcb.livenessProbe.timeoutSeconds | int | `5` | | +| ph_ee_connector_slcb.managedServiceAccount | bool | `true` | | +| ph_ee_connector_slcb.password | string | `"password"` | | +| ph_ee_connector_slcb.priorityClassName | string | `""` | | +| ph_ee_connector_slcb.readinessProbe.failureThreshold | int | `3` | | +| ph_ee_connector_slcb.readinessProbe.httpGet.path | string | `"/actuator/health/readiness"` | | +| ph_ee_connector_slcb.readinessProbe.httpGet.port | int | `9191` | | +| ph_ee_connector_slcb.readinessProbe.initialDelaySeconds | int | `120` | | +| ph_ee_connector_slcb.readinessProbe.periodSeconds | int | `30` | | +| ph_ee_connector_slcb.readinessProbe.timeoutSeconds | int | `5` | | +| ph_ee_connector_slcb.replicas | int | `1` | | +| ph_ee_connector_slcb.resources.limits.cpu | string | `"500m"` | | +| ph_ee_connector_slcb.resources.limits.memory | string | `"512M"` | | +| ph_ee_connector_slcb.resources.requests.cpu | string | `"100m"` | | +| ph_ee_connector_slcb.resources.requests.memory | string | `"512M"` | | +| ph_ee_connector_slcb.securityContext.privileged | bool | `false` | | +| ph_ee_connector_slcb.securityContext.runAsUser | int | `0` | | +| ph_ee_connector_slcb.serviceAccount | string | `""` | | +| ph_ee_connector_slcb.serviceAccountAnnotations | object | `{}` | | +| ph_ee_connector_slcb.signature_key | string | `"long_segnature_key"` | | +| ph_ee_connector_slcb.terminationGracePeriod | int | `30` | | +| ph_ee_connector_slcb.username | string | `"username"` | | +| ph_ee_connector_slcb.zeebe_broker_contactpoint | string | `"zeebe-zeebe-gateway:26500"` | | +| redis.enabled | bool | `false` | | +| redis.replica.replicaCount | int | `0` | | +| roster_connector.LOGGING_LEVEL_ROOT | string | `"INFO"` | | +| roster_connector.SPRING_PROFILES_ACTIVE | string | `""` | | +| roster_connector.ams.local.enabled | string | `""` | | +| roster_connector.containerPort | int | `5000` | | +| roster_connector.deployment.affinity | object | `{}` | | +| roster_connector.deployment.annotations | object | `{}` | | +| roster_connector.deployment.envFrom | list | `[]` | | +| roster_connector.deployment.extraEnvs | string | `""` | | +| roster_connector.deployment.nodeSelector | object | `{}` | | +| roster_connector.deployment.resources.limits.cpu | string | `"500m"` | | +| roster_connector.deployment.resources.limits.memory | string | `"512M"` | | +| roster_connector.deployment.resources.requests.cpu | string | `"100m"` | | +| roster_connector.deployment.resources.requests.memory | string | `"512M"` | | +| roster_connector.deployment.securityContext.privileged | bool | `false` | | +| roster_connector.deployment.securityContext.runAsUser | int | `0` | | +| roster_connector.deployment.tolerations | list | `[]` | | +| roster_connector.enabled | bool | `false` | | +| roster_connector.envFrom | list | `[]` | | +| roster_connector.extraEnvs | string | `""` | | +| roster_connector.image | string | `""` | | +| roster_connector.imagePullPolicy | string | `"Always"` | | +| roster_connector.imageTag | string | `"v1.2.0"` | | +| roster_connector.livenessProbe.failureThreshold | int | `3` | | +| roster_connector.livenessProbe.httpGet.path | string | `"/actuator/health/liveness"` | | +| roster_connector.livenessProbe.httpGet.port | int | `9191` | | +| roster_connector.livenessProbe.initialDelaySeconds | int | `120` | | +| roster_connector.livenessProbe.periodSeconds | int | `30` | | +| roster_connector.livenessProbe.timeoutSeconds | int | `5` | | +| roster_connector.managedServiceAccount | bool | `true` | | +| roster_connector.pesacore.auth_header | string | `""` | | +| roster_connector.priorityClassName | string | `""` | | +| roster_connector.readinessProbe.failureThreshold | int | `3` | | +| roster_connector.readinessProbe.httpGet.path | string | `"/actuator/health/readiness"` | | +| roster_connector.readinessProbe.httpGet.port | int | `9191` | | +| roster_connector.readinessProbe.initialDelaySeconds | int | `120` | | +| roster_connector.readinessProbe.periodSeconds | int | `30` | | +| roster_connector.readinessProbe.timeoutSeconds | int | `5` | | +| roster_connector.replicas | int | `1` | | +| roster_connector.resources.limits.cpu | string | `"500m"` | | +| roster_connector.resources.limits.memory | string | `"512M"` | | +| roster_connector.resources.requests.cpu | string | `"100m"` | | +| roster_connector.resources.requests.memory | string | `"512M"` | | +| roster_connector.securityContext.privileged | bool | `false` | | +| roster_connector.securityContext.runAsUser | int | `0` | | +| roster_connector.serviceAccount | string | `""` | | +| roster_connector.serviceAccountAnnotations | object | `{}` | | +| roster_connector.terminationGracePeriod | int | `30` | | +| secret.apiversion | string | `"v1"` | | +| service.apiversion | string | `"v1"` | | +| tls | string | `""` | | +| wildcardhostname | string | `""` | | +| zeebe-cluster-helm.annotations."prometheus.io/path" | string | `"/metrics"` | | +| zeebe-cluster-helm.annotations."prometheus.io/port" | string | `"9600"` | | +| zeebe-cluster-helm.annotations."prometheus.io/scrape" | string | `"true"` | | +| zeebe-cluster-helm.clusterSize | string | `"1"` | | +| zeebe-cluster-helm.cpuThreadCount | string | `"2"` | | +| zeebe-cluster-helm.elasticsearch.clusterName | string | `"zeebe-elasticsearch"` | | +| zeebe-cluster-helm.elasticsearch.enabled | bool | `false` | | +| zeebe-cluster-helm.elasticsearch.fullnameOverride | string | `"zeebe-elasticsearch"` | | +| zeebe-cluster-helm.env[0].name | string | `"ZEEBE_BROKER_EXECUTION_METRICS_EXPORTER_ENABLED"` | | +| zeebe-cluster-helm.env[0].value | string | `"true"` | | +| zeebe-cluster-helm.env[10].name | string | `"ZEEBE_BROKER_EXPORTERS_KAFKA_ARGS_INDEX_PROCESSINSTANCE"` | | +| zeebe-cluster-helm.env[10].value | string | `"true"` | | +| zeebe-cluster-helm.env[11].name | string | `"ZEEBE_BROKER_EXPORTERS_KAFKA_ARGS_INDEX_PROCESS"` | | +| zeebe-cluster-helm.env[11].value | string | `"true"` | | +| zeebe-cluster-helm.env[12].name | string | `"ZEEBE_BROKER_EXPORTERS_KAFKA_ARGS_INDEX_INCIDENT"` | | +| zeebe-cluster-helm.env[12].value | string | `"true"` | | +| zeebe-cluster-helm.env[13].name | string | `"ZEEBE_BROKER_EXPORTERS_KAFKA_ARGS_INDEX_DEPLOYMENT"` | | +| zeebe-cluster-helm.env[13].value | string | `"false"` | | +| zeebe-cluster-helm.env[14].name | string | `"ZEEBE_BROKER_EXPORTERS_KAFKA_ARGS_INDEX_ERROR"` | | +| zeebe-cluster-helm.env[14].value | string | `"false"` | | +| zeebe-cluster-helm.env[15].name | string | `"ZEEBE_BROKER_EXPORTERS_KAFKA_ARGS_INDEX_JOB"` | | +| zeebe-cluster-helm.env[15].value | string | `"false"` | | +| zeebe-cluster-helm.env[16].name | string | `"ZEEBE_BROKER_EXPORTERS_KAFKA_ARGS_INDEX_VARIABLEDOCUMENT"` | | +| zeebe-cluster-helm.env[16].value | string | `"false"` | | +| zeebe-cluster-helm.env[17].name | string | `"ZEEBE_BROKER_EXPORTERS_KAFKA_ARGS_INDEX_WORKFLOWINSTANCE"` | | +| zeebe-cluster-helm.env[17].value | string | `"false"` | | +| zeebe-cluster-helm.env[18].name | string | `"ZEEBE_BROKER_EXPORTERS_KAFKA_ARGS_INDEX_CREATETEMPLATE"` | | +| zeebe-cluster-helm.env[18].value | string | `"false"` | | +| zeebe-cluster-helm.env[1].name | string | `"ZEEBE_BROKER_EXPORTERS_ELASTICSEARCH_CLASSNAME"` | | +| zeebe-cluster-helm.env[1].value | string | `"hu.dpc.rt.kafkastreamer.exporter.NoOpExporter"` | | +| zeebe-cluster-helm.env[2].name | string | `"ZEEBE_BROKER_EXPORTERS_ELASTICSEARCH_JARPATH"` | | +| zeebe-cluster-helm.env[2].value | string | `"/exporters/ph-ee-kafka-exporter.jar"` | | +| zeebe-cluster-helm.env[3].name | string | `"ZEEBE_BROKER_EXPORTERS_KAFKA_JARPATH"` | | +| zeebe-cluster-helm.env[3].value | string | `"/exporters/ph-ee-kafka-exporter.jar"` | | +| zeebe-cluster-helm.env[4].name | string | `"ZEEBE_BROKER_EXPORTERS_KAFKA_CLASSNAME"` | | +| zeebe-cluster-helm.env[4].value | string | `"hu.dpc.rt.kafkastreamer.exporter.KafkaExporter"` | | +| zeebe-cluster-helm.env[5].name | string | `"ZEEBE_BROKER_BACKPRESSURE_VEGAS_INITIALLIMIT"` | | +| zeebe-cluster-helm.env[5].value | string | `"1000"` | | +| zeebe-cluster-helm.env[6].name | string | `"ZEEBE_BROKER_BACKPRESSURE_VEGAS_ALPHA"` | | +| zeebe-cluster-helm.env[6].value | string | `"2"` | | +| zeebe-cluster-helm.env[7].name | string | `"ZEEBE_BROKER_BACKPRESSURE_VEGAS_BETA"` | | +| zeebe-cluster-helm.env[7].value | string | `"8"` | | +| zeebe-cluster-helm.env[8].name | string | `"ZEEBE_BROKER_EXPORTERS_KAFKA_ARGS_INDEX_EVENT"` | | +| zeebe-cluster-helm.env[8].value | string | `"true"` | | +| zeebe-cluster-helm.env[9].name | string | `"ZEEBE_BROKER_EXPORTERS_KAFKA_ARGS_INDEX_VARIABLE"` | | +| zeebe-cluster-helm.env[9].value | string | `"true"` | | +| zeebe-cluster-helm.extraInitContainers | string | `"- name: init-ph-ee-kafka-exporter\n image: busybox:1.28\n command: ['/bin/sh', '-c']\n args: ['wget -O /exporters/ph-ee-kafka-exporter.jar \"https://fynarfin.io/images/exporter-1.1.0-SNAPSHOT.jar\"; ls -al /exporters/']\n volumeMounts:\n - name: exporters\n mountPath: /exporters/\n"` | | +| zeebe-cluster-helm.gateway.env[0].name | string | `"ZEEBE_GATEWAY_THREADS_MANAGEMENTTHREADS"` | | +| zeebe-cluster-helm.gateway.env[0].value | string | `"4"` | | +| zeebe-cluster-helm.gateway.env[1].name | string | `"ZEEBE_GATEWAY_MONITORING_ENABLED"` | | +| zeebe-cluster-helm.gateway.env[1].value | string | `"true"` | | +| zeebe-cluster-helm.gateway.logLevel | string | `"warn"` | | +| zeebe-cluster-helm.gateway.replicas | int | `1` | | +| zeebe-cluster-helm.global.elasticsearch.host | string | `"ph-ee-elasticsearch"` | | +| zeebe-cluster-helm.global.zeebe | string | `"zeebe-zeebe"` | | +| zeebe-cluster-helm.image.repository | string | `"camunda/zeebe"` | | +| zeebe-cluster-helm.image.tag | string | `"1.1.0"` | | +| zeebe-cluster-helm.ioThreadCount | string | `"2"` | | +| zeebe-cluster-helm.kibana.elasticsearchHosts | string | `"http://zeebe-elasticsearch:9200/"` | | +| zeebe-cluster-helm.kibana.enabled | bool | `false` | | +| zeebe-cluster-helm.kibana.fullnameOverride | string | `"zeebee-kibana"` | | +| zeebe-cluster-helm.partitionCount | string | `"1"` | | +| zeebe-cluster-helm.prometheus.enabled | bool | `false` | | +| zeebe-cluster-helm.pvcAccessModes[0] | string | `"ReadWriteOnce"` | | +| zeebe-cluster-helm.pvcSize | string | `"10Gi"` | | +| zeebe-cluster-helm.replicationFactor | string | `"1"` | | +| zeebe-cluster-helm.resources.requests.cpu | string | `"100m"` | | +| zeebe-operate-helm.enabled | bool | `false` | | +| zeebe-operate-helm.fullnameOverride | string | `"zeebe-operate"` | | +| zeebe-operate-helm.global.elasticsearch.clusterName | string | `"zeebe-elasticsearch"` | | +| zeebe-operate-helm.global.elasticsearch.host | string | `"zeebe-elasticsearch"` | | +| zeebe-operate-helm.global.zeebe | string | `"zeebe-zeebe"` | | +| zeebe-operate-helm.image.repository | string | `"camunda/operate"` | | +| zeebe-operate-helm.image.tag | string | `"1.1.0"` | | +| zeebe.broker.contactpoint | string | `"zeebe-zeebe-gateway:26500"` | | +| zeebe_ops.LOGGING_LEVEL_ROOT | string | `"INFO"` | | +| zeebe_ops.SPRING_PROFILES_ACTIVE | string | `""` | | +| zeebe_ops.deployment.affinity | object | `{}` | | +| zeebe_ops.deployment.annotations | object | `{}` | | +| zeebe_ops.deployment.envFrom | list | `[]` | | +| zeebe_ops.deployment.extraEnvs | string | `""` | | +| zeebe_ops.deployment.nodeSelector | object | `{}` | | +| zeebe_ops.deployment.resources.limits.cpu | string | `"500m"` | | +| zeebe_ops.deployment.resources.limits.memory | string | `"512M"` | | +| zeebe_ops.deployment.resources.requests.cpu | string | `"100m"` | | +| zeebe_ops.deployment.resources.requests.memory | string | `"512M"` | | +| zeebe_ops.deployment.securityContext.privileged | bool | `false` | | +| zeebe_ops.deployment.securityContext.runAsUser | int | `0` | | +| zeebe_ops.deployment.tolerations | list | `[]` | | +| zeebe_ops.elasticsearch_contactpoint | string | `"ph-ee-elasticsearch:9200"` | | +| zeebe_ops.elasticsearch_security_enabled | bool | `false` | | +| zeebe_ops.elasticsearch_sslverification | bool | `false` | | +| zeebe_ops.elasticsearch_url | string | `"http://ph-ee-elasticsearch:9200/"` | | +| zeebe_ops.enabled | bool | `true` | | +| zeebe_ops.envFrom | list | `[]` | | +| zeebe_ops.extraEnvs | string | `""` | | +| zeebe_ops.hostname | string | `""` | | +| zeebe_ops.image | string | `""` | | +| zeebe_ops.imagePullPolicy | string | `"Always"` | | +| zeebe_ops.imagePullSecrets | list | `[]` | | +| zeebe_ops.imageTag | string | `"v1.0.1"` | | +| zeebe_ops.ingress.annotations | object | `{}` | | +| zeebe_ops.ingress.backend | object | `{}` | | +| zeebe_ops.ingress.enabled | bool | `false` | | +| zeebe_ops.ingress.path | string | `"/zeebeops"` | | +| zeebe_ops.livenessProbe.failureThreshold | int | `3` | | +| zeebe_ops.livenessProbe.httpGet.path | string | `"/actuator/health/liveness"` | | +| zeebe_ops.livenessProbe.httpGet.port | int | `9191` | | +| zeebe_ops.livenessProbe.initialDelaySeconds | int | `120` | | +| zeebe_ops.livenessProbe.periodSeconds | int | `30` | | +| zeebe_ops.livenessProbe.timeoutSeconds | int | `5` | | +| zeebe_ops.managedServiceAccount | bool | `true` | | +| zeebe_ops.priorityClassName | string | `""` | | +| zeebe_ops.readinessProbe.failureThreshold | int | `3` | | +| zeebe_ops.readinessProbe.httpGet.path | string | `"/actuator/health/readiness"` | | +| zeebe_ops.readinessProbe.httpGet.port | int | `9191` | | +| zeebe_ops.readinessProbe.initialDelaySeconds | int | `120` | | +| zeebe_ops.readinessProbe.periodSeconds | int | `30` | | +| zeebe_ops.readinessProbe.timeoutSeconds | int | `5` | | +| zeebe_ops.replicas | int | `1` | | +| zeebe_ops.resources.limits.cpu | string | `"500m"` | | +| zeebe_ops.resources.limits.memory | string | `"512M"` | | +| zeebe_ops.resources.requests.cpu | string | `"100m"` | | +| zeebe_ops.resources.requests.memory | string | `"512M"` | | +| zeebe_ops.securityContext.privileged | bool | `false` | | +| zeebe_ops.securityContext.runAsUser | int | `0` | | +| zeebe_ops.serviceAccount | string | `""` | | +| zeebe_ops.serviceAccountAnnotations | object | `{}` | | +| zeebe_ops.tenants | string | `""` | | +| zeebe_ops.terminationGracePeriod | int | `30` | | +| zeebe_ops.zeebe_broker_contactpoint | string | `"zeebe-zeebe-gateway:26500"` | | + +---------------------------------------------- +Autogenerated from chart metadata using [helm-docs v1.11.0](https://github.com/norwoodj/helm-docs/releases/v1.11.0) diff --git a/ph-ee-env-template/helm/ph-ee-engine/ams-paygops/Chart.yaml b/ph-ee-env-template/helm/ph-ee-engine/ams-paygops/Chart.yaml new file mode 100644 index 000000000..9517ad0b1 --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/ams-paygops/Chart.yaml @@ -0,0 +1,5 @@ +apiVersion: v1 +description: paygops_connector +name: paygops_connector +version: 1.0.0 +appVersion: "1.0.0" \ No newline at end of file diff --git a/ph-ee-env-template/helm/ph-ee-engine/ams-paygops/README.md b/ph-ee-env-template/helm/ph-ee-engine/ams-paygops/README.md new file mode 100644 index 000000000..27c1d3a8d --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/ams-paygops/README.md @@ -0,0 +1,31 @@ +# paygops_connector + +![Version: 1.0.0](https://img.shields.io/badge/Version-1.0.0-informational?style=flat-square) ![AppVersion: 1.0.0](https://img.shields.io/badge/AppVersion-1.0.0-informational?style=flat-square) + +paygops_connector + +## Values + +| Key | Type | Default | Description | +|-----|------|---------|-------------| +| LOGGING_LEVEL_ROOT | string | `"INFO"` | | +| SPRING_PROFILES_ACTIVE | string | `"bb"` | | +| ams.local.enabled | bool | `false` | | +| configmap.apiversion | string | `"v1"` | | +| deployment.annotations.deployTime | string | `"{{ .Values.deployTime }}"` | | +| deployment.apiVersion | string | `"apps/v1"` | | +| enabled | bool | `true` | | +| image | string | `""` | | +| imageTag | string | `"latest"` | | +| ingress.apiversion | string | `"networking.k8s.io/v1"` | | +| limits.cpu | string | `"500m"` | | +| limits.memory | string | `"512M"` | | +| paygops.authheader | string | `"PaymentHubTest"` | | +| paygops.base_url | string | `"https://feature-test1.paygops.com/"` | | +| requests.cpu | string | `"100m"` | | +| requests.memory | string | `"256M"` | | +| secret.apiversion | string | `"v1"` | | +| service.apiversion | string | `"v1"` | | + +---------------------------------------------- +Autogenerated from chart metadata using [helm-docs v1.11.0](https://github.com/norwoodj/helm-docs/releases/v1.11.0) diff --git a/ph-ee-env-template/helm/ph-ee-engine/ams-paygops/templates/clusterrole.yaml b/ph-ee-env-template/helm/ph-ee-engine/ams-paygops/templates/clusterrole.yaml new file mode 100644 index 000000000..eb5fcd207 --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/ams-paygops/templates/clusterrole.yaml @@ -0,0 +1,11 @@ +{{- if .Values.managedServiceAccount }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + # "namespace" omitted since ClusterRoles are not namespaced + name: ph-ee-connector-ams-paygops-c-role +rules: +- apiGroups: [""] + resources: ["secrets"] + verbs: ["get", "watch", "list"] +{{- end -}} \ No newline at end of file diff --git a/ph-ee-env-template/helm/ph-ee-engine/ams-paygops/templates/clusterrolebinding.yaml b/ph-ee-env-template/helm/ph-ee-engine/ams-paygops/templates/clusterrolebinding.yaml new file mode 100644 index 000000000..b920b59ee --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/ams-paygops/templates/clusterrolebinding.yaml @@ -0,0 +1,15 @@ +{{- if .Values.managedServiceAccount }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: ph-ee-connector-ams-paygops-c-role-binding +subjects: +- kind: ServiceAccount + name: ph-ee-connector-ams-paygops # name of your service account + namespace: {{ .Release.Namespace }} # this is the namespace your service account is in +roleRef: # referring to your ClusterRole + kind: ClusterRole + name: ph-ee-connector-ams-paygops-c-role + apiGroup: rbac.authorization.k8s.io + +{{- end -}} \ No newline at end of file diff --git a/ph-ee-env-template/helm/ph-ee-engine/ams-paygops/templates/deployment.yaml b/ph-ee-env-template/helm/ph-ee-engine/ams-paygops/templates/deployment.yaml new file mode 100644 index 000000000..9006680d0 --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/ams-paygops/templates/deployment.yaml @@ -0,0 +1,69 @@ +{{- if .Values.enabled -}} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: "ph-ee-connector-ams-paygops" + labels: + app: ph-ee-connector-ams-paygops +spec: + replicas: {{ .Values.replicas }} + selector: + matchLabels: + app: ph-ee-connector-ams-paygops + template: + metadata: + labels: + app: ph-ee-connector-ams-paygops + annotations: +{{- if .Values.deployment.annotations }} +{{ toYaml .Values.deployment.annotations | indent 8 }} +{{- end }} + spec: + containers: + - name: ph-ee-connector-ams-paygops + image: "{{ .Values.image }}:{{ .Values.imageTag }}" + ports: + - containerPort: 5000 + imagePullPolicy: "{{ .Values.global.imagePullPolicy }}" + livenessProbe: + httpGet: + path: /actuator/health/liveness + port: 8080 + initialDelaySeconds: {{.Values.livenessProbe.initialDelaySeconds}} + periodSeconds: {{.Values.livenessProbe.periodSeconds}} + readinessProbe: + httpGet: + path: /actuator/health/readiness + port: 8080 + initialDelaySeconds: {{.Values.readinessProbe.initialDelaySeconds}} + periodSeconds: {{.Values.readinessProbe.periodSeconds}} + env: + - name: "SPRING_PROFILES_ACTIVE" + value: "{{ .Values.global.SPRING_PROFILES_ACTIVE }}" + - name: "ZEEBE_BROKER_CONTACTPOINT" + value: "{{ .Release.Name }}-zeebe-gateway:26500" + - name: "AMS_LOCAL_ENABLED" + value: "{{ .Values.ams.local.enabled }}" + - name: "PAYGOPS_AUTHHEADER" + value: null + valueFrom: + secretKeyRef: + name: "paygops-secret" + key: "auth-token" + - name: "PAYGOPS_BASE-URL" + value: "{{ .Values.paygops.base_url }}" + - name: "LOGGING_LEVEL_ROOT" + value: "{{ .Values.global.LOGGING_LEVEL_ROOT }}" +{{- if .Values.extraEnvs | default .Values.deployment.extraEnvs }} +{{ toYaml ( .Values.extraEnvs | default .Values.deployment.extraEnvs ) | indent 10 }} +{{- end }} + envFrom: {{ toYaml ( .Values.envFrom | default .Values.deployment.envFrom ) | nindent 12 }} + securityContext: {{ toYaml ( .Values.podSecurityContext | default .Values.deployment.securityContext ) | nindent 12 }} + resources: + limits: + memory: "{{ .Values.limits.memory }}" + cpu: "{{ .Values.limits.cpu }}" + requests: + memory: "{{ .Values.requests.memory }}" + cpu: "{{ .Values.requests.cpu }}" +{{- end }} diff --git a/ph-ee-env-template/helm/ph-ee-engine/ams-paygops/templates/role.yaml b/ph-ee-env-template/helm/ph-ee-engine/ams-paygops/templates/role.yaml new file mode 100644 index 000000000..9c76b0631 --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/ams-paygops/templates/role.yaml @@ -0,0 +1,14 @@ +{{- if .Values.managedServiceAccount }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: ph-ee-connector-ams-paygops-role + namespace: {{ .Release.Namespace }} +rules: +- apiGroups: + - "" + resources: + - pods + - configmaps + verbs: ["get", "create", "update"] +{{- end -}} \ No newline at end of file diff --git a/ph-ee-env-template/helm/ph-ee-engine/ams-paygops/templates/rolebinding.yaml b/ph-ee-env-template/helm/ph-ee-engine/ams-paygops/templates/rolebinding.yaml new file mode 100644 index 000000000..82db18fd8 --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/ams-paygops/templates/rolebinding.yaml @@ -0,0 +1,15 @@ +{{- if .Values.managedServiceAccount }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: ph-ee-connector-ams-paygops-role-binding + namespace: {{ .Release.Namespace }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: ph-ee-connector-ams-paygops-role +subjects: +- kind: ServiceAccount + name: ph-ee-connector-ams-paygops + namespace: {{ .Release.Namespace }} +{{- end -}} \ No newline at end of file diff --git a/ph-ee-env-template/helm/ph-ee-engine/ams-paygops/templates/secret.yaml b/ph-ee-env-template/helm/ph-ee-engine/ams-paygops/templates/secret.yaml new file mode 100644 index 000000000..7a17a47fa --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/ams-paygops/templates/secret.yaml @@ -0,0 +1,9 @@ +{{- if .Values.enabled -}} +apiVersion: {{ .Values.secret.apiversion }} +kind: Secret +metadata: + name: paygops-secret +type: Opaque +data: + auth-token: {{ .Values.paygops.authheader | b64enc }} +{{- end }} diff --git a/ph-ee-env-template/helm/ph-ee-engine/ams-paygops/templates/service.yaml b/ph-ee-env-template/helm/ph-ee-engine/ams-paygops/templates/service.yaml new file mode 100644 index 000000000..3bc153ed4 --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/ams-paygops/templates/service.yaml @@ -0,0 +1,22 @@ +{{- if .Values.enabled -}} +apiVersion: {{ .Values.service.apiversion }} +kind: Service +metadata: + labels: + app: ph-ee-connector-ams-paygops + name: ph-ee-connector-ams-paygops +spec: + ports: + - name: port + port: 80 + protocol: TCP + targetPort: 5000 + - name: http + port: 82 + protocol: TCP + targetPort: 8080 + selector: + app: ph-ee-connector-ams-paygops + sessionAffinity: None + type: ClusterIP +{{- end }} \ No newline at end of file diff --git a/ph-ee-env-template/helm/ph-ee-engine/ams-paygops/templates/serviceaccount.yaml b/ph-ee-env-template/helm/ph-ee-engine/ams-paygops/templates/serviceaccount.yaml new file mode 100644 index 000000000..6b62902e3 --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/ams-paygops/templates/serviceaccount.yaml @@ -0,0 +1,15 @@ +{{- if .Values.managedServiceAccount }} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: "ph-ee-connector-ams-paygops" + annotations: + {{- with .Values.serviceAccountAnnotations }} + {{- toYaml . | nindent 4 }} + {{- end }} + labels: + app: "ph-ee-connector-ams-paygops" + chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" + heritage: {{ .Release.Service | quote }} + release: {{ .Release.Name | quote }} +{{- end -}} \ No newline at end of file diff --git a/ph-ee-env-template/helm/ph-ee-engine/ams-paygops/values.yaml b/ph-ee-env-template/helm/ph-ee-engine/ams-paygops/values.yaml new file mode 100644 index 000000000..a3ee841e9 --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/ams-paygops/values.yaml @@ -0,0 +1,40 @@ +ingress: + apiversion: networking.k8s.io/v1 + +service: + apiversion: "v1" + +secret: + apiversion: "v1" + +configmap: + apiversion: "v1" + + +enabled: false +image: "" +imageTag: latest +SPRING_PROFILES_ACTIVE: "bb" +LOGGING_LEVEL_ROOT: "INFO" +ams: + local: + enabled: false +paygops: + authheader: "" + base_url: "https://feature-test1.paygops.com/" +limits: + cpu: "500m" + memory: "512M" +requests: + cpu: "100m" + memory: "256M" +deployment: + apiVersion: "apps/v1" + annotations: + deployTime: "{{ .Values.deployTime }}" +livenessProbe: + initialDelaySeconds: 20 + periodSeconds: 30 +readinessProbe: + initialDelaySeconds: 20 + periodSeconds: 30 diff --git a/ph-ee-env-template/helm/ph-ee-engine/ams-roster/Chart.yaml b/ph-ee-env-template/helm/ph-ee-engine/ams-roster/Chart.yaml new file mode 100644 index 000000000..ae81d840d --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/ams-roster/Chart.yaml @@ -0,0 +1,5 @@ +apiVersion: v1 +description: ph-ee-connector-ams-roster +name: roster_connector +version: 1.0.0 +appVersion: "1.0.0" \ No newline at end of file diff --git a/ph-ee-env-template/helm/ph-ee-engine/ams-roster/README.md b/ph-ee-env-template/helm/ph-ee-engine/ams-roster/README.md new file mode 100644 index 000000000..d76a81885 --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/ams-roster/README.md @@ -0,0 +1,29 @@ +# roster_connector + +![Version: 1.0.0](https://img.shields.io/badge/Version-1.0.0-informational?style=flat-square) ![AppVersion: 1.0.0](https://img.shields.io/badge/AppVersion-1.0.0-informational?style=flat-square) + +ph-ee-connector-ams-roster + +## Values + +| Key | Type | Default | Description | +|-----|------|---------|-------------| +| SPRING_PROFILES_ACTIVE | string | `""` | | +| ams.local.enabled | bool | `true` | | +| configmap.apiversion | string | `"v1"` | | +| deployment.annotations.deployTime | string | `"{{ .Values.deployTime }}"` | | +| deployment.apiVersion | string | `"apps/v1"` | | +| enabled | bool | `true` | | +| image | string | `""` | | +| imageTag | string | `"latest"` | | +| ingress.apiversion | string | `"networking.k8s.io/v1"` | | +| limits.cpu | string | `"500m"` | | +| limits.memory | string | `"512M"` | | +| pesacore.auth_header | string | `"PaymentHub"` | | +| requests.cpu | string | `"100m"` | | +| requests.memory | string | `"256M"` | | +| secret.apiversion | string | `"v1"` | | +| service.apiversion | string | `"v1"` | | + +---------------------------------------------- +Autogenerated from chart metadata using [helm-docs v1.11.0](https://github.com/norwoodj/helm-docs/releases/v1.11.0) diff --git a/ph-ee-env-template/helm/ph-ee-engine/ams-roster/templates/clusterrole.yaml b/ph-ee-env-template/helm/ph-ee-engine/ams-roster/templates/clusterrole.yaml new file mode 100644 index 000000000..e1f8a424e --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/ams-roster/templates/clusterrole.yaml @@ -0,0 +1,11 @@ +{{- if .Values.managedServiceAccount }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + # "namespace" omitted since ClusterRoles are not namespaced + name: ph-ee-connector-ams-roster-c-role +rules: +- apiGroups: [""] + resources: ["secrets"] + verbs: ["get", "watch", "list"] +{{- end -}} \ No newline at end of file diff --git a/ph-ee-env-template/helm/ph-ee-engine/ams-roster/templates/clusterrolebinding.yaml b/ph-ee-env-template/helm/ph-ee-engine/ams-roster/templates/clusterrolebinding.yaml new file mode 100644 index 000000000..7765802b4 --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/ams-roster/templates/clusterrolebinding.yaml @@ -0,0 +1,15 @@ +{{- if .Values.managedServiceAccount }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: ph-ee-connector-ams-roster-c-role-binding +subjects: +- kind: ServiceAccount + name: ph-ee-connector-ams-roster # name of your service account + namespace: {{ .Release.Namespace }} # this is the namespace your service account is in +roleRef: # referring to your ClusterRole + kind: ClusterRole + name: ph-ee-connector-ams-roster-c-role + apiGroup: rbac.authorization.k8s.io + +{{- end -}} \ No newline at end of file diff --git a/ph-ee-env-template/helm/ph-ee-engine/ams-roster/templates/deployment.yaml b/ph-ee-env-template/helm/ph-ee-engine/ams-roster/templates/deployment.yaml new file mode 100644 index 000000000..5c122ea72 --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/ams-roster/templates/deployment.yaml @@ -0,0 +1,69 @@ +{{- if .Values.enabled -}} + +apiVersion: apps/v1 +kind: Deployment +metadata: + name: ph-ee-connector-ams-roster + labels: + app: ph-ee-connector-ams-roster +spec: + replicas: {{ .Values.replicas }} + selector: + matchLabels: + app: ph-ee-connector-ams-roster + template: + metadata: + labels: + app: ph-ee-connector-ams-roster + annotations: +{{- if .Values.deployment.annotations }} +{{ toYaml .Values.deployment.annotations | indent 8 }} +{{- end }} + spec: + containers: + - name: ph-ee-connector-ams-roster + image: "{{ .Values.image }}:{{ .Values.imageTag }}" + ports: + - containerPort: 5000 + imagePullPolicy: "{{ .Values.global.imagePullPolicy }}" + livenessProbe: + httpGet: + path: /actuator/health/liveness + port: 8080 + initialDelaySeconds: {{.Values.livenessProbe.initialDelaySeconds}} + periodSeconds: {{.Values.livenessProbe.periodSeconds}} + readinessProbe: + httpGet: + path: /actuator/health/readiness + port: 8080 + initialDelaySeconds: {{.Values.readinessProbe.initialDelaySeconds}} + periodSeconds: {{.Values.readinessProbe.periodSeconds}} + env: + - name: "SPRING_PROFILES_ACTIVE" + value: "{{ .Values.global.SPRING_PROFILES_ACTIVE }}" + - name: "ZEEBE_BROKER_CONTACTPOINT" + value: "{{ .Release.Name }}-zeebe-gateway:26500" + - name: "AMS_LOCAL_ENABLED" + value: "{{ .Values.ams.local.enabled }}" + - name: "PESACORE_AUTH-HEADER" + valueFrom: + secretKeyRef: + name: "roster-secret" + key: "auth-token" + - name: "PESACORE_BASE-URL" + value: "{{ .Values.pesacore.base_url }}" + - name: "LOGGING_LEVEL_ROOT" + value: "{{ .Values.global.LOGGING_LEVEL_ROOT }}" +{{- if .Values.extraEnvs | default .Values.deployment.extraEnvs }} +{{ toYaml ( .Values.extraEnvs | default .Values.deployment.extraEnvs ) | indent 10 }} +{{- end }} + envFrom: {{ toYaml ( .Values.envFrom | default .Values.deployment.envFrom ) | nindent 12 }} + securityContext: {{ toYaml ( .Values.podSecurityContext | default .Values.deployment.securityContext ) | nindent 12 }} + resources: + limits: + memory: "{{ .Values.limits.memory }}" + cpu: "{{ .Values.limits.cpu }}" + requests: + memory: "{{ .Values.requests.memory }}" + cpu: "{{ .Values.requests.cpu }}" +{{- end }} diff --git a/ph-ee-env-template/helm/ph-ee-engine/ams-roster/templates/role.yaml b/ph-ee-env-template/helm/ph-ee-engine/ams-roster/templates/role.yaml new file mode 100644 index 000000000..5a069d04c --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/ams-roster/templates/role.yaml @@ -0,0 +1,14 @@ +{{- if .Values.managedServiceAccount }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: ph-ee-connector-ams-roster-role + namespace: {{ .Release.Namespace }} +rules: +- apiGroups: + - "" + resources: + - pods + - configmaps + verbs: ["get", "create", "update"] +{{- end -}} \ No newline at end of file diff --git a/ph-ee-env-template/helm/ph-ee-engine/ams-roster/templates/rolebinding.yaml b/ph-ee-env-template/helm/ph-ee-engine/ams-roster/templates/rolebinding.yaml new file mode 100644 index 000000000..34079bae7 --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/ams-roster/templates/rolebinding.yaml @@ -0,0 +1,15 @@ +{{- if .Values.managedServiceAccount }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: ph-ee-connector-ams-roster-role-binding + namespace: {{ .Release.Namespace }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: ph-ee-connector-ams-roster-role +subjects: +- kind: ServiceAccount + name: ph-ee-connector-ams-roster + namespace: {{ .Release.Namespace }} +{{- end -}} \ No newline at end of file diff --git a/ph-ee-env-template/helm/ph-ee-engine/ams-roster/templates/secret.yaml b/ph-ee-env-template/helm/ph-ee-engine/ams-roster/templates/secret.yaml new file mode 100644 index 000000000..1bfd83168 --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/ams-roster/templates/secret.yaml @@ -0,0 +1,9 @@ +{{- if .Values.enabled -}} +apiVersion: {{ .Values.secret.apiversion }} +kind: Secret +metadata: + name: roster-secret +type: Opaque +data: + auth-token: {{ .Values.pesacore.auth_header | b64enc }} +{{- end }} diff --git a/ph-ee-env-template/helm/ph-ee-engine/ams-roster/templates/service.yaml b/ph-ee-env-template/helm/ph-ee-engine/ams-roster/templates/service.yaml new file mode 100644 index 000000000..10bfd9a72 --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/ams-roster/templates/service.yaml @@ -0,0 +1,22 @@ +{{- if .Values.enabled -}} +apiVersion: {{ .Values.service.apiversion }} +kind: Service +metadata: + labels: + app: ph-ee-connector-ams-roster + name: ph-ee-connector-ams-roster +spec: + ports: + - name: port + port: 80 + protocol: TCP + targetPort: 5000 + - name: http + port: 82 + protocol: TCP + targetPort: 8080 + selector: + app: ph-ee-connector-ams-roster + sessionAffinity: None + type: ClusterIP +{{- end }} \ No newline at end of file diff --git a/ph-ee-env-template/helm/ph-ee-engine/ams-roster/templates/serviceaccount.yaml b/ph-ee-env-template/helm/ph-ee-engine/ams-roster/templates/serviceaccount.yaml new file mode 100644 index 000000000..785d4305a --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/ams-roster/templates/serviceaccount.yaml @@ -0,0 +1,15 @@ +{{- if .Values.managedServiceAccount }} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: ph-ee-connector-ams-roster + annotations: + {{- with .Values.serviceAccountAnnotations }} + {{- toYaml . | nindent 4 }} + {{- end }} + labels: + app: ph-ee-connector-ams-roster + chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" + heritage: {{ .Release.Service | quote }} + release: {{ .Release.Name | quote }} +{{- end -}} \ No newline at end of file diff --git a/ph-ee-env-template/helm/ph-ee-engine/ams-roster/values.yaml b/ph-ee-env-template/helm/ph-ee-engine/ams-roster/values.yaml new file mode 100644 index 000000000..4955976fc --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/ams-roster/values.yaml @@ -0,0 +1,37 @@ +ingress: + apiversion: networking.k8s.io/v1 + +service: + apiversion: "v1" + +secret: + apiversion: "v1" + +configmap: + apiversion: "v1" + +enabled: false +image: "" +imageTag: latest +SPRING_PROFILES_ACTIVE: "" +ams: + local: + enabled: true +pesacore: + auth_header: "PaymentHub" +limits: + cpu: "500m" + memory: "512M" +requests: + cpu: "100m" + memory: "256M" +deployment: + apiVersion: "apps/v1" + annotations: + deployTime: "{{ .Values.deployTime }}" +livenessProbe: + initialDelaySeconds: 20 + periodSeconds: 30 +readinessProbe: + initialDelaySeconds: 20 + periodSeconds: 30 diff --git a/ph-ee-env-template/helm/ph-ee-engine/connector-ams-mifos/Chart.yaml b/ph-ee-env-template/helm/ph-ee-engine/connector-ams-mifos/Chart.yaml new file mode 100644 index 000000000..5467cb786 --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/connector-ams-mifos/Chart.yaml @@ -0,0 +1,5 @@ +apiVersion: v1 +description: ph_ee_connector_ams_mifos +name: ph_ee_connector_ams_mifos +version: 1.0.0 +appVersion: "1.0.0" \ No newline at end of file diff --git a/ph-ee-env-template/helm/ph-ee-engine/connector-ams-mifos/README.md b/ph-ee-env-template/helm/ph-ee-engine/connector-ams-mifos/README.md new file mode 100644 index 000000000..d2569bee2 --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/connector-ams-mifos/README.md @@ -0,0 +1,47 @@ +# ph_ee_connector_ams_mifos + +![Version: 1.0.0](https://img.shields.io/badge/Version-1.0.0-informational?style=flat-square) ![AppVersion: 1.0.0](https://img.shields.io/badge/AppVersion-1.0.0-informational?style=flat-square) + +ph_ee_connector_ams_mifos + +## Values + +| Key | Type | Default | Description | +|-----|------|---------|-------------| +| SPRING_PROFILES_ACTIVE | string | `""` | | +| ams_local_account_host | string | `"https://fynams.sandbox.mifos.io"` | | +| ams_local_auth_host | string | `"https://fynams.sandbox.mifos.io"` | | +| ams_local_customer_host | string | `"https://fynams.sandbox.mifos.io"` | | +| ams_local_enabled | bool | `true` | | +| ams_local_interop_host | string | `"https://fynams.sandbox.mifos.io"` | | +| ams_local_loan_host | string | `"https://fynams.sandbox.mifos.io/"` | | +| configmap.apiversion | string | `"v1"` | | +| deployment.annotations.deployTime | string | `"{{ .Values.deployTime }}"` | | +| deployment.apiVersion | string | `"apps/v1"` | | +| dfspids | string | `"gorilla,rhino"` | | +| enabled | bool | `true` | | +| extraInitContainers | string | `""` | | +| hostname | string | `"amsmifos.sandbox.mifos.io"` | | +| image | string | `""` | | +| imagePullPolicy | string | `"Always"` | | +| imageTag | string | `"latest"` | | +| ingress.annotations."kubernetes.io/ingress.class" | string | `"nginx"` | | +| ingress.apiversion | string | `"networking.k8s.io/v1"` | | +| ingress.backend.service.name | string | `"ph-ee-connector-ams-mifos"` | | +| ingress.backend.service.port.number | int | `80` | | +| ingress.enabled | bool | `true` | | +| ingress.path | string | `"/"` | | +| ingress.tls[0].hosts | string | `"amsmifos.sandbox.mifos.io"` | | +| ingress.tls[1].secretName | string | `"sandbox-secret"` | | +| keycloak.enabled | bool | `true` | | +| limits.cpu | string | `"500m"` | | +| limits.memory | string | `"512M"` | | +| operations_app.datasource.host | string | `"operationsmysql"` | | +| requests.cpu | string | `"100m"` | | +| requests.memory | string | `"256M"` | | +| secret.apiversion | string | `"v1"` | | +| service.apiversion | string | `"v1"` | | +| wildcardhostname | string | `"amsmifos.sandbox.mifos.io"` | | + +---------------------------------------------- +Autogenerated from chart metadata using [helm-docs v1.11.0](https://github.com/norwoodj/helm-docs/releases/v1.11.0) diff --git a/ph-ee-env-template/helm/ph-ee-engine/connector-ams-mifos/templates/clusterrole.yaml b/ph-ee-env-template/helm/ph-ee-engine/connector-ams-mifos/templates/clusterrole.yaml new file mode 100644 index 000000000..7d30025b1 --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/connector-ams-mifos/templates/clusterrole.yaml @@ -0,0 +1,11 @@ +{{- if .Values.managedServiceAccount }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + # "namespace" omitted since ClusterRoles are not namespaced + name: ph-ee-connector-ams-mifos-c-role +rules: +- apiGroups: [""] + resources: ["secrets"] + verbs: ["get", "watch", "list"] +{{- end -}} \ No newline at end of file diff --git a/ph-ee-env-template/helm/ph-ee-engine/connector-ams-mifos/templates/clusterrolebinding.yaml b/ph-ee-env-template/helm/ph-ee-engine/connector-ams-mifos/templates/clusterrolebinding.yaml new file mode 100644 index 000000000..17fd129e8 --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/connector-ams-mifos/templates/clusterrolebinding.yaml @@ -0,0 +1,15 @@ +{{- if .Values.managedServiceAccount }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: ph-ee-connector-ams-mifos-c-role-binding +subjects: +- kind: ServiceAccount + name: ph-ee-connector-ams-mifos # name of your service account + namespace: {{ .Release.Namespace }} # this is the namespace your service account is in +roleRef: # referring to your ClusterRole + kind: ClusterRole + name: ph-ee-connector-ams-mifos-c-role + apiGroup: rbac.authorization.k8s.io + +{{- end -}} \ No newline at end of file diff --git a/ph-ee-env-template/helm/ph-ee-engine/connector-ams-mifos/templates/deployment.yaml b/ph-ee-env-template/helm/ph-ee-engine/connector-ams-mifos/templates/deployment.yaml new file mode 100644 index 000000000..6054d747d --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/connector-ams-mifos/templates/deployment.yaml @@ -0,0 +1,98 @@ +{{- if .Values.enabled -}} + +apiVersion: apps/v1 +kind: Deployment +metadata: + name: ph-ee-connector-ams-mifos + labels: + app: ph-ee-connector-ams-mifos +spec: + replicas: {{ .Values.replicas }} + selector: + matchLabels: + app: ph-ee-connector-ams-mifos + template: + metadata: + labels: + app: ph-ee-connector-ams-mifos + annotations: +{{- if .Values.deployment.annotations }} +{{ toYaml .Values.deployment.annotations | indent 8 }} +{{- end }} + spec: + initContainers: + #During this Pod's initialization, check that zeebe-gateway service is up and running before starting this pod + - name: check-zeebe-gateway-ready + image: busybox:latest + command: [ 'sh', '-c','until nc -vz {{ .Release.Name }}-zeebe-gateway 26500; do echo "Waiting for zeebe-gateway service"; sleep 2; done;' ] + affinity: {{ toYaml .Values.deployment.affinity | nindent 8 }} + nodeSelector: {{ toYaml .Values.deployment.nodeSelector | nindent 8 }} + tolerations: {{ toYaml ( .Values.tolerations | default .Values.deployment.tolerations ) | nindent 8 }} + {{- if .Values.priorityClassName }} + priorityClassName: {{ .Values.priorityClassName }} + {{- end }} + serviceAccountName: ph-ee-connector-ams-mifos + terminationGracePeriodSeconds: {{ .Values.terminationGracePeriod }} + containers: + - name: ph-ee-connector-ams-mifos + image: "{{ .Values.image}}" + imagePullPolicy: "{{ .Values.global.imagePullPolicy }}" + ports: + - containerPort: 5000 + resources: {{ toYaml ( .Values.resources | default .Values.deployment.resources ) | nindent 10 }} + {{- if .Values.imagePullSecrets }} + imagePullSecrets: + {{ toYaml .Values.imagePullSecrets | indent 8 }} + {{- end }} + env: + - name: "SPRING_PROFILES_ACTIVE" + value: "{{ .Values.SPRING_PROFILES_ACTIVE }}" + - name: "ams_local_enabled" + value: "{{ .Values.ams_local_enabled }}" + - name: "ams_local_interop_host" + value: "{{ .Values.ams_local_interop_host }}" + - name: "ams_local_customer_host" + value: "{{ .Values.ams_local_customer_host }}" + - name: "ams_local_account_host" + value: "{{ .Values.ams_local_account_host }}" + - name: "ams_local_auth_host" + value: "{{ .Values.ams_local_auth_host }}" + - name: "ams_local_loan_host" + value: "{{ .Values.ams_local_loan_host }}" + - name: "DFSPIDS" + value: "{{ .Values.global.DFSPIDS }}" + - name: "ZEEBE_BROKER_CONTACTPOINT" + value: "{{ .Release.Name }}-zeebe-gateway:26500" + - name: "ZEEBE_CLIENT_MAX-EXECUTION-THREADS" + value: "{{ .Values.global.max_execution_threads}}" + - name: "ZEEBE_CLIENT_POLL-INTERVAL" + value: "{{ .Values.global.poll_interval}}" +{{- if .Values.extraEnvs | default .Values.deployment.extraEnvs }} +{{ toYaml ( .Values.extraEnvs | default .Values.deployment.extraEnvs ) | indent 8 }} +{{- end }} + envFrom: {{ toYaml ( .Values.envFrom | default .Values.deployment.envFrom ) | nindent 10 }} + securityContext: {{ toYaml ( .Values.podSecurityContext | default .Values.deployment.securityContext ) | nindent 10 }} + + volumeMounts: + - name: ph-ee-config + mountPath: "/config" +# {{- if .Values.deployment.config }} +# {{ toYaml .Values.deployment.config | indent 12 }} +# {{- end }} + initContainers: + - name: wait-db + image: jwilder/dockerize + imagePullPolicy: IfNotPresent + args: + - -timeout=120s + - -wait + - tcp://{{ .Values.operations_app.datasource.host }}:3306 + volumes: + - name: ph-ee-config + configMap: + name: ph-ee-config + {{- if .Values.extraContainers }} + {{ tpl .Values.extraContainers . | indent 6 }} + {{- end }} + +{{- end }} diff --git a/ph-ee-env-template/helm/ph-ee-engine/connector-ams-mifos/templates/ingress.yaml b/ph-ee-env-template/helm/ph-ee-engine/connector-ams-mifos/templates/ingress.yaml new file mode 100644 index 000000000..ff1d048b2 --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/connector-ams-mifos/templates/ingress.yaml @@ -0,0 +1,50 @@ +{{- if .Values.ingress.enabled -}} +{{- $pathtype := .Values.ingress.pathtype -}} +{{- $ingressPath := .Values.ingress.path -}} +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: ph-ee-connector-ams-mifos + labels: + app: {{ .Chart.Name }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +{{- with .Values.ingress.annotations }} + annotations: +{{ toYaml . | indent 4 }} +{{- end }} +spec: + {{- if .Values.ingress.className }} + ingressClassName: {{ .Values.ingress.className | quote }} + {{- end }} +{{- if .Values.ingress.tls }} + tls: + {{- if .ingressPath }} + {{- range .Values.ingress.tls }} + - hosts: + {{- range .hosts }} + - {{ . }} + {{- end }} + secretName: {{ .secretName }} + {{- end }} +{{- else }} +{{ toYaml .Values.ingress.tls | indent 4 }} + {{- end }} +{{- end}} + rules: + {{- range .Values.ingress.hosts }} + - host: {{ .host }} + http: + paths: + {{- range .paths }} + - path: {{ .path }} + pathType: {{ $pathtype }} + backend: + service: + name: {{ .backend.service.name}} + port: + number: {{ .backend.service.port.number}} + {{- end }} + {{- end }} + {{- end }} + \ No newline at end of file diff --git a/ph-ee-env-template/helm/ph-ee-engine/connector-ams-mifos/templates/role.yaml b/ph-ee-env-template/helm/ph-ee-engine/connector-ams-mifos/templates/role.yaml new file mode 100644 index 000000000..19bce2125 --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/connector-ams-mifos/templates/role.yaml @@ -0,0 +1,14 @@ +{{- if .Values.managedServiceAccount }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: ph-ee-connector-ams-mifos-role + namespace: {{ .Release.Namespace }} +rules: +- apiGroups: + - "" + resources: + - pods + - configmaps + verbs: ["get", "create", "update"] +{{- end -}} \ No newline at end of file diff --git a/ph-ee-env-template/helm/ph-ee-engine/connector-ams-mifos/templates/rolebinding.yaml b/ph-ee-env-template/helm/ph-ee-engine/connector-ams-mifos/templates/rolebinding.yaml new file mode 100644 index 000000000..53a631108 --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/connector-ams-mifos/templates/rolebinding.yaml @@ -0,0 +1,15 @@ +{{- if .Values.managedServiceAccount }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: ph-ee-connector-ams-mifos-role-binding + namespace: {{ .Release.Namespace }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: ph-ee-connector-ams-mifos-role +subjects: +- kind: ServiceAccount + name: ph-ee-connector-ams-mifos + namespace: {{ .Release.Namespace }} +{{- end -}} \ No newline at end of file diff --git a/ph-ee-env-template/helm/ph-ee-engine/connector-ams-mifos/templates/service.yaml b/ph-ee-env-template/helm/ph-ee-engine/connector-ams-mifos/templates/service.yaml new file mode 100644 index 000000000..8dcc31d18 --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/connector-ams-mifos/templates/service.yaml @@ -0,0 +1,22 @@ +{{- if .Values.enabled -}} +apiVersion: {{ .Values.service.apiversion }} +kind: Service +metadata: + labels: + app: ph-ee-connector-ams-mifos + name: ph-ee-connector-ams-mifos +spec: + ports: + - name: port + port: 80 + protocol: TCP + targetPort: 5000 + - name: http + port: 70 + protocol: TCP + targetPort: 7070 + selector: + app: ph-ee-connector-ams-mifos + sessionAffinity: None + type: ClusterIP +{{- end }} \ No newline at end of file diff --git a/ph-ee-env-template/helm/ph-ee-engine/connector-ams-mifos/templates/serviceaccount.yaml b/ph-ee-env-template/helm/ph-ee-engine/connector-ams-mifos/templates/serviceaccount.yaml new file mode 100644 index 000000000..2ea3fcc0b --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/connector-ams-mifos/templates/serviceaccount.yaml @@ -0,0 +1,15 @@ +{{- if .Values.managedServiceAccount }} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: ph-ee-connector-ams-mifos + annotations: + {{- with .Values.serviceAccountAnnotations }} + {{- toYaml . | nindent 4 }} + {{- end }} + labels: + app: ph-ee-connector-ams-mifos + chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" + heritage: {{ .Release.Service | quote }} + release: {{ .Release.Name | quote }} +{{- end -}} \ No newline at end of file diff --git a/ph-ee-env-template/helm/ph-ee-engine/connector-ams-mifos/values.yaml b/ph-ee-env-template/helm/ph-ee-engine/connector-ams-mifos/values.yaml new file mode 100644 index 000000000..deeda43fa --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/connector-ams-mifos/values.yaml @@ -0,0 +1,52 @@ +service: + apiversion: "v1" + +secret: + apiversion: "v1" + +configmap: + apiversion: "v1" + +enabled: true +image: "" +imageTag: "" +imagePullPolicy: "" +SPRING_PROFILES_ACTIVE: "" +hostname: "" +ams_local_enabled: true +ams_local_interop_host : "" +ams_local_customer_host : "" +ams_local_account_host : "" +ams_local_auth_host : "" +ams_local_loan_host : "" +dfspids: "" +extraInitContainers: "" +## tenants properties have been moved to fin12 +limits: + cpu: "500m" + memory: "384M" +requests: + cpu: "100m" + memory: "256M" +ingress: + enabled: false + annotations: {} + # kubernetes.io/ingress.class: "nginx" + pathtype: ImplementationSpecific + hosts: + - host: "" + paths: + - path: / + tls: [] + # - secretName: sandbox-secret + # hosts: + # - chart-example.local + +deployment: + apiVersion: "apps/v1" + annotations: + deployTime: "{{ .Values.deployTime }}" + +operations_app: + datasource: + host: "operationsmysql" diff --git a/ph-ee-env-template/helm/ph-ee-engine/connector-bill-pay/Chart.yaml b/ph-ee-env-template/helm/ph-ee-engine/connector-bill-pay/Chart.yaml new file mode 100644 index 000000000..64b395da8 --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/connector-bill-pay/Chart.yaml @@ -0,0 +1,5 @@ +apiVersion: v1 +description: ph-ee-connector-bill-pay +name: billPay +version: 1.0.0 +appVersion: "1.0.0" diff --git a/ph-ee-env-template/helm/ph-ee-engine/connector-bill-pay/README.md b/ph-ee-env-template/helm/ph-ee-engine/connector-bill-pay/README.md new file mode 100644 index 000000000..ae5232724 --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/connector-bill-pay/README.md @@ -0,0 +1,48 @@ +# bill-pay + +![Version: 1.0.0](https://img.shields.io/badge/Version-1.0.0-informational?style=flat-square) ![AppVersion: 1.0.0](https://img.shields.io/badge/AppVersion-1.0.0-informational?style=flat-square) + +ph-ee-connector-bill-pay + +## Values + +| Key | Type | Default | Description | +|---------------------------------------------------|--------|------------------------------------|-------------| +| DFSPIDS | string | `""` | | +| LOGGING_LEVEL_ROOT | string | `"INFO"` | | +| SPRING_PROFILES_ACTIVE | string | `"bb,tenants"` | | +| configmap.apiversion | string | `"v1"` | | +| deployment.annotations.deployTime | string | `"{{ .Values.deployTime }}"` | | +| deployment.apiVersion | string | `"apps/v1"` | | +| enabled | bool | `true` | | +| hostname | string | `"billPay.sandbox.mifos.io"` | | +| image | string | `""` | | +| imagePullPolicy | string | `"Always"` | | +| imageTag | string | `"latest"` | | +| ingress.annotations."kubernetes.io/ingress.class" | string | `"nginx"` | | +| ingress.apiversion | string | `"networking.k8s.io/v1"` | | +| ingress.backend.service.name | string | `"ph-ee-connector-bill-pay"` | | +| ingress.backend.service.port.number | int | `80` | | +| ingress.className | string | `"nginx"` | | +| ingress.enabled | bool | `true` | | +| ingress.path | string | `"/"` | | +| ingress.stub_backend.service.name | string | `"ph-ee-connector-bill-pay"` | | +| ingress.stub_backend.service.port.number | int | `82` | | +| ingress.tls[0].hosts | string | `"notifications.sandbox.mifos.io"` | | +| ingress.tls[1].secretName | string | `"sandbox-secret"` | | +| limits.cpu | string | `"500m"` | | +| limits.memory | string | `"512M"` | | +| livenessProbe.httpGet.path | string | `"/actuator/health/liveness"` | | +| livenessProbe.httpGet.port | int | `8080` | | +| livenessProbe.initialDelaySeconds | int | `20` | | +| livenessProbe.periodSeconds | int | `30` | | +| readinessProbe.httpGet.path | string | `"/actuator/health/readiness"` | | +| readinessProbe.httpGet.port | int | `8080` | | +| readinessProbe.initialDelaySeconds | int | `20` | | +| readinessProbe.periodSeconds | int | `30` | | +| requests.cpu | string | `"100m"` | | +| requests.memory | string | `"256M"` | | +| service.apiversion | string | `"v1"` | | +| stub_hostname | string | `"bill-pay.sandbox.mifos.io"` | | +---------------------------------------------- +Autogenerated from chart metadata using [helm-docs v1.11.0](https://github.com/norwoodj/helm-docs/releases/v1.11.0) diff --git a/ph-ee-env-template/helm/ph-ee-engine/connector-bill-pay/templates/clusterrole.yaml b/ph-ee-env-template/helm/ph-ee-engine/connector-bill-pay/templates/clusterrole.yaml new file mode 100644 index 000000000..6dd8a015d --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/connector-bill-pay/templates/clusterrole.yaml @@ -0,0 +1,11 @@ +{{- if .Values.managedServiceAccount }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + # "namespace" omitted since ClusterRoles are not namespaced + name: ph-ee-connector-bill-pay-c-role +rules: +- apiGroups: [""] + resources: ["secrets"] + verbs: ["get", "watch", "list"] +{{- end -}} \ No newline at end of file diff --git a/ph-ee-env-template/helm/ph-ee-engine/connector-bill-pay/templates/clusterrolebinding.yaml b/ph-ee-env-template/helm/ph-ee-engine/connector-bill-pay/templates/clusterrolebinding.yaml new file mode 100644 index 000000000..6a74c39ad --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/connector-bill-pay/templates/clusterrolebinding.yaml @@ -0,0 +1,15 @@ +{{- if .Values.managedServiceAccount }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: ph-ee-connector-bill-pay-c-role-binding +subjects: +- kind: ServiceAccount + name: ph-ee-connector-bill-pay # name of your service account + namespace: {{ .Release.Namespace }} # this is the namespace your service account is in +roleRef: # referring to your ClusterRole + kind: ClusterRole + name: ph-ee-connector-bill-pay-c-role + apiGroup: rbac.authorization.k8s.io + +{{- end -}} \ No newline at end of file diff --git a/ph-ee-env-template/helm/ph-ee-engine/connector-bill-pay/templates/deployment.yaml b/ph-ee-env-template/helm/ph-ee-engine/connector-bill-pay/templates/deployment.yaml new file mode 100644 index 000000000..0cbbab377 --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/connector-bill-pay/templates/deployment.yaml @@ -0,0 +1,79 @@ +{{- if .Values.enabled -}} + +apiVersion: apps/v1 +kind: Deployment +metadata: + name: ph-ee-connector-bill-pay + labels: + app: ph-ee-connector-bill-pay +spec: + replicas: {{ .Values.replicas }} + selector: + matchLabels: + app: ph-ee-connector-bill-pay + template: + metadata: + labels: + app: ph-ee-connector-bill-pay + annotations: +{{- if .Values.deployment.annotations }} +{{ toYaml .Values.deployment.annotations | indent 8 }} +{{- end }} + spec: + initContainers: + #During this Pod's initialization, check that zeebe-gateway service is up and running before starting this pod + - name: check-zeebe-gateway-ready + image: busybox:latest + command: [ 'sh', '-c','until nc -vz {{ .Release.Name }}-zeebe-gateway 26500; do echo "Waiting for zeebe-gateway service"; sleep 2; done;' ] + terminationGracePeriodSeconds: {{ .Values.terminationGracePeriod }} + containers: + - name: ph-ee-connector-bill-pay + image: "{{ .Values.image }}" + ports: + - containerPort: 8080 + imagePullPolicy: "{{ .Values.global.imagePullPolicy }}" + resources: + limits: + memory: "{{ .Values.limits.memory }}" + cpu: "{{ .Values.limits.cpu }}" + requests: + memory: "{{ .Values.requests.memory }}" + cpu: "{{ .Values.requests.cpu }}" +# livenessProbe: +# httpGet: +# path: /actuator/health/liveness +# port: 8443 +# scheme: HTTPS +# initialDelaySeconds: 20 +# periodSeconds: 180 +# readinessProbe: +# httpGet: +# path: /actuator/health/readiness +# port: 8443 +# scheme: HTTPS +# initialDelaySeconds: 20 +# periodSeconds: 180 + env: + - name: "SPRING_PROFILES_ACTIVE" + value: "{{ .Values.SPRING_PROFILES_ACTIVE }}" + - name: "ZEEBE_BROKER_CONTACTPOINT" + value: "{{ .Release.Name }}-zeebe-gateway:26500" + - name: "DFSPIDS" + value: "{{ .Values.global.DFSPIDS }}" + - name: "CONNECTOR_CONTACTPOINT" + value: "{{ .Values.connector.contactpoint }}" + - name: "BILLPAY_CONTACTPOINT" + value: "{{ .Values.billpay.contactpoint }}" +{{- if .Values.extraEnvs | default .Values.deployment.extraEnvs }} +{{ toYaml ( .Values.extraEnvs | default .Values.deployment.extraEnvs ) | indent 10 }} +{{- end }} + envFrom: {{ toYaml ( .Values.envFrom | default .Values.deployment.envFrom ) | nindent 12 }} + securityContext: {{ toYaml ( .Values.podSecurityContext | default .Values.deployment.securityContext ) | nindent 12 }} + volumeMounts: + - name: ph-ee-config + mountPath: "/config" + volumes: + - name: ph-ee-config + configMap: + name: ph-ee-config +{{- end }} diff --git a/ph-ee-env-template/helm/ph-ee-engine/connector-bill-pay/templates/ingress.yaml b/ph-ee-env-template/helm/ph-ee-engine/connector-bill-pay/templates/ingress.yaml new file mode 100644 index 000000000..40bed737e --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/connector-bill-pay/templates/ingress.yaml @@ -0,0 +1,49 @@ +{{- if .Values.ingress.enabled -}} +{{- $pathtype := .Values.ingress.pathtype -}} +{{- $ingressPath := .Values.ingress.path -}} +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: ph-ee-connector-bill-pay + labels: + app: {{ .Chart.Name }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +{{- with .Values.ingress.annotations }} + annotations: +{{ toYaml . | indent 4 }} +{{- end }} +spec: + {{- if .Values.ingress.className }} + ingressClassName: {{ .Values.ingress.className | quote }} + {{- end }} +{{- if .Values.ingress.tls }} + tls: + {{- if .ingressPath }} + {{- range .Values.ingress.tls }} + - hosts: + {{- range .hosts }} + - {{ . }} + {{- end }} + secretName: {{ .secretName }} + {{- end }} +{{- else }} +{{ toYaml .Values.ingress.tls | indent 4 }} + {{- end }} +{{- end}} + rules: + {{- range .Values.ingress.hosts }} + - host: {{ .host }} + http: + paths: + {{- range .paths }} + - path: {{ .path }} + pathType: {{ $pathtype }} + backend: + service: + name: {{ .backend.service.name}} + port: + number: {{ .backend.service.port.number}} + {{- end }} + {{- end }} + {{- end }} diff --git a/ph-ee-env-template/helm/ph-ee-engine/connector-bill-pay/templates/role.yaml b/ph-ee-env-template/helm/ph-ee-engine/connector-bill-pay/templates/role.yaml new file mode 100644 index 000000000..814d27f2f --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/connector-bill-pay/templates/role.yaml @@ -0,0 +1,14 @@ +{{- if .Values.managedServiceAccount }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: ph-ee-connector-bill-pay-role + namespace: {{ .Release.Namespace }} +rules: +- apiGroups: + - "" + resources: + - pods + - configmaps + verbs: ["get", "create", "update"] +{{- end -}} \ No newline at end of file diff --git a/ph-ee-env-template/helm/ph-ee-engine/connector-bill-pay/templates/rolebinding.yaml b/ph-ee-env-template/helm/ph-ee-engine/connector-bill-pay/templates/rolebinding.yaml new file mode 100644 index 000000000..d5388cb4f --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/connector-bill-pay/templates/rolebinding.yaml @@ -0,0 +1,15 @@ +{{- if .Values.managedServiceAccount }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: ph-ee-connector-bill-pay-role-binding + namespace: {{ .Release.Namespace }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: ph-ee-connector-bill-pay-role +subjects: +- kind: ServiceAccount + name: ph-ee-connector-bill-pay + namespace: {{ .Release.Namespace }} +{{- end -}} \ No newline at end of file diff --git a/ph-ee-env-template/helm/ph-ee-engine/connector-bill-pay/templates/service.yaml b/ph-ee-env-template/helm/ph-ee-engine/connector-bill-pay/templates/service.yaml new file mode 100644 index 000000000..cc43c98d3 --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/connector-bill-pay/templates/service.yaml @@ -0,0 +1,22 @@ +{{- if .Values.enabled -}} +apiVersion: {{ .Values.service.apiversion }} +kind: Service +metadata: + labels: + app: ph-ee-connector-bill-pay + name: ph-ee-connector-bill-pay +{{- with .Values.service.annotations }} + annotations: +{{ toYaml . | indent 4 }} +{{- end }} +spec: + ports: + - name: port + port: 8080 + protocol: TCP + targetPort: 8080 + selector: + app: ph-ee-connector-bill-pay + sessionAffinity: None + type: ClusterIP +{{- end }} \ No newline at end of file diff --git a/ph-ee-env-template/helm/ph-ee-engine/connector-bill-pay/templates/serviceaccount.yaml b/ph-ee-env-template/helm/ph-ee-engine/connector-bill-pay/templates/serviceaccount.yaml new file mode 100644 index 000000000..76d9693fe --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/connector-bill-pay/templates/serviceaccount.yaml @@ -0,0 +1,15 @@ +{{- if .Values.managedServiceAccount }} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: "ph-ee-connector-bill-pay" + annotations: + {{- with .Values.serviceAccountAnnotations }} + {{- toYaml . | nindent 4 }} + {{- end }} + labels: + app: "ph-ee-connector-bill-pay" + chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" + heritage: {{ .Release.Service | quote }} + release: {{ .Release.Name | quote }} +{{- end -}} \ No newline at end of file diff --git a/ph-ee-env-template/helm/ph-ee-engine/connector-bill-pay/values.yaml b/ph-ee-env-template/helm/ph-ee-engine/connector-bill-pay/values.yaml new file mode 100644 index 000000000..4a4e7312b --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/connector-bill-pay/values.yaml @@ -0,0 +1,51 @@ +service: + apiversion: "v1" + annotations: {} + +secret: + apiversion: "v1" + +configmap: + apiversion: "v1" + +enabled: true +image: "" +imageTag: latest +imagePullPolicy: "Always" +SPRING_PROFILES_ACTIVE: "bb,tenants" +LOGGING_LEVEL_ROOT: "INFO" +billpay: + contactpoint: "" +connector: + contactpoint: "" +DFSPIDS: "" +operations: + url: "" +limits: + cpu: "500m" + memory: "512M" +requests: + cpu: "100m" + memory: "256M" + initialDelaySeconds: 20 + periodSeconds: 30 +# Enabling this will publicly expose your channel instance. +# Only enable this if you have security enabled on your cluster +ingress: + enabled: true + annotations: {} + # kubernetes.io/ingress.class: "nginx" + pathtype: Prefix + hosts: + - host: "" + paths: + - path: / + tls: [] + # - secretName: sandbox-secret + # hosts: + # - chart-example.local + +deployment: + apiVersion: "apps/v1" + annotations: + deployTime: "{{ .Values.deployTime }}" diff --git a/ph-ee-env-template/helm/ph-ee-engine/connector-bulk/Chart.yaml b/ph-ee-env-template/helm/ph-ee-engine/connector-bulk/Chart.yaml new file mode 100644 index 000000000..572b5631b --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/connector-bulk/Chart.yaml @@ -0,0 +1,5 @@ +apiVersion: v1 +description: ph-ee-connector-bulk +name: connector_bulk +version: 1.0.0 +appVersion: "1.0.0" \ No newline at end of file diff --git a/ph-ee-env-template/helm/ph-ee-engine/connector-bulk/README.md b/ph-ee-env-template/helm/ph-ee-engine/connector-bulk/README.md new file mode 100644 index 000000000..116016e3a --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/connector-bulk/README.md @@ -0,0 +1,60 @@ +# connector_bulk + +![Version: 1.0.0](https://img.shields.io/badge/Version-1.0.0-informational?style=flat-square) ![AppVersion: 1.0.0](https://img.shields.io/badge/AppVersion-1.0.0-informational?style=flat-square) + +ph-ee-connector-bulk + +## Values + +| Key | Type | Default | Description | +|-----|------|---------|-------------| +| SPRING_PROFILES_ACTIVE | string | `""` | | +| aws.access_key | string | `""` | | +| aws.region | string | `""` | | +| aws.secret_key | string | `""` | | +| bucket_name | string | `"paymenthub-ee-dev"` | | +| camel_disable_ssl | bool | `true` | | +| config.approval.enable | bool | `false` | | +| config.backpressure.enable | bool | `false` | | +| config.completion_threshold_check.completion_rate | int | `95` | | +| config.completion_threshold_check.enable | bool | `true` | | +| config.formatting.enable | bool | `false` | | +| config.formatting.standard | string | `"DEFAULT"` | | +| config.mergeback.enable | bool | `true` | | +| config.ordering.enable | bool | `false` | | +| config.ordering.field | string | `""` | | +| config.partylookup.enable | bool | `false` | | +| config.splitting.enable | bool | `true` | | +| config.splitting.sub_batch_size | int | `5` | | +| configmap.apiversion | string | `"v1"` | | +| deployment.annotations.deployTime | string | `"{{ .Values.deployTime }}"` | | +| deployment.apiVersion | string | `"apps/v1"` | | +| enabled | bool | `true` | | +| hostname | string | `"bulk-connector.sandbox.mifos.io"` | | +| image | string | `""` | | +| imagePullPolicy | string | `""` | | +| imageTag | string | `"latest"` | | +| ingress.annotations."konghq.com/plugins" | string | `"cors"` | | +| ingress.annotations."kubernetes.io/ingress.class" | string | `"nginx"` | | +| ingress.apiversion | string | `"networking.k8s.io/v1"` | | +| ingress.backend.service.name | string | `"ph-ee-connector-bulk"` | | +| ingress.backend.service.port.number | int | `80` | | +| ingress.className | string | `"kong"` | | +| ingress.enabled | bool | `true` | | +| ingress.path | string | `"/"` | | +| ingress.tls[0].hosts | string | `"bulk-connector.sandbox.mifos.io"` | | +| ingress.tls[1].secretName | string | `"sandbox-secret"` | | +| limits.cpu | string | `"500m"` | | +| limits.memory | string | `"512M"` | | +| operations_app.contactpoint | string | `""` | | +| operations_app.endpoints.batch_transaction | string | `""` | | +| requests.cpu | string | `"100m"` | | +| requests.memory | string | `"256M"` | | +| secret.apiversion | string | `"v1"` | | +| service.apiversion | string | `"v1"` | | +| tenants | string | `""` | | +| wildcardhostname | string | `"bulk-connector.sandbox.mifos.io"` | | +| zeebe_broker_contactpoint | string | `"zeebe-zeebe-gateway:26500"` | | + +---------------------------------------------- +Autogenerated from chart metadata using [helm-docs v1.11.0](https://github.com/norwoodj/helm-docs/releases/v1.11.0) diff --git a/ph-ee-env-template/helm/ph-ee-engine/connector-bulk/templates/clusterrole.yaml b/ph-ee-env-template/helm/ph-ee-engine/connector-bulk/templates/clusterrole.yaml new file mode 100644 index 000000000..605109307 --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/connector-bulk/templates/clusterrole.yaml @@ -0,0 +1,11 @@ +{{- if .Values.managedServiceAccount }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + # "namespace" omitted since ClusterRoles are not namespaced + name: ph-ee-connector-bulk-c-role +rules: +- apiGroups: [""] + resources: ["secrets"] + verbs: ["get", "watch", "list"] +{{- end -}} \ No newline at end of file diff --git a/ph-ee-env-template/helm/ph-ee-engine/connector-bulk/templates/clusterrolebinding.yaml b/ph-ee-env-template/helm/ph-ee-engine/connector-bulk/templates/clusterrolebinding.yaml new file mode 100644 index 000000000..c1b14a188 --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/connector-bulk/templates/clusterrolebinding.yaml @@ -0,0 +1,15 @@ +{{- if .Values.managedServiceAccount }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: ph-ee-connector-bulk-c-role-binding +subjects: +- kind: ServiceAccount + name: ph-ee-connector-bulk # name of your service account + namespace: {{ .Release.Namespace }} # this is the namespace your service account is in +roleRef: # referring to your ClusterRole + kind: ClusterRole + name: ph-ee-connector-bulk-c-role + apiGroup: rbac.authorization.k8s.io + +{{- end -}} \ No newline at end of file diff --git a/ph-ee-env-template/helm/ph-ee-engine/connector-bulk/templates/deployment.yaml b/ph-ee-env-template/helm/ph-ee-engine/connector-bulk/templates/deployment.yaml new file mode 100644 index 000000000..7699c4bcb --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/connector-bulk/templates/deployment.yaml @@ -0,0 +1,118 @@ +{{- if .Values.enabled -}} + +apiVersion: apps/v1 +kind: Deployment +metadata: + name: ph-ee-connector-bulk + labels: + app: ph-ee-connector-bulk +spec: + replicas: {{ .Values.replicas }} + selector: + matchLabels: + app: ph-ee-connector-bulk + template: + metadata: + labels: + app: ph-ee-connector-bulk + annotations: +{{- if .Values.deployment.annotations }} +{{ toYaml .Values.deployment.annotations | indent 8 }} +{{- end }} + spec: + initContainers: + #During this Pod's initialization, check that zeebe-gateway service is up and running before starting this pod + - name: check-zeebe-gateway-ready + image: busybox:latest + command: [ 'sh', '-c','until nc -vz {{ .Release.Name }}-zeebe-gateway 26500; do echo "Waiting for zeebe-gateway service"; sleep 2; done;' ] + terminationGracePeriodSeconds: {{ .Values.terminationGracePeriod }} + containers: + - name: ph-ee-connector-bulk + image: "{{ .Values.image}}" + imagePullPolicy: "{{ .Values.imagePullPolicy }}" + ports: + - containerPort: 5000 + resources: + limits: + memory: "{{ .Values.limits.memory }}" + cpu: "{{ .Values.limits.cpu }}" + requests: + memory: "{{ .Values.requests.memory }}" + cpu: "{{ .Values.requests.cpu }}" + env: + - name: "SPRING_PROFILES_ACTIVE" + value: "{{ .Values.global.SPRING_PROFILES_ACTIVE }}" + - name: "CAMEL_DISABLE-SSL" + value: "{{ .Values.camel_disable_ssl }}" + - name: "ZEEBE_BROKER_CONTACTPOINT" + value: "{{ .Release.Name }}-zeebe-gateway:26500" + - name: "ZEEBE_CLIENT_MAX-EXECUTION-THREADS" + value: "{{ .Values.global.max_execution_threads}}" + - name: "ZEEBE_CLIENT_POLL-INTERVAL" + value: "{{ .Values.global.poll_interval}}" + - name: "TENANTS" + value: "{{ .Values.global.tenants }}" + - name: "APPLICATION_BUCKET-NAME" + value: "{{ .Values.global.bucket_name }}" + - name: "OPERATIONS-APP_CONTACTPOINT" + value: "{{ .Values.operations_app.contactpoint }}" + - name: "OPERATIONS-APP_ENDPOINTS_BATCH-TRANSACTION" + value: "{{ .Values.operations_app.endpoints.batch_transaction }}" + - name: "CONFIG_PARTYLOOKUP_ENABLE" + value: "{{ .Values.config.partylookup.enable }}" + - name: "CONFIG_APPROVAL_ENABLE" + value: "{{ .Values.config.approval.enable }}" + - name: "CONFIG_ORDERING_ENABLE" + value: "{{ .Values.config.ordering.enable }}" + - name: "CONFIG_ORDERING_FIELD" + value: "{{ .Values.config.ordering.field }}" + - name: "CONFIG_SPLITTING_ENABLE" + value: "{{ .Values.config.splitting.enable }}" + - name: "CONFIG_SPLITTING_SUB_BATCH_SIZE" + value: "{{ .Values.config.splitting.sub_batch_size }}" + - name: "CONFIG_FORMATTING_ENABLE" + value: "{{ .Values.config.formatting.enable }}" + - name: "CONFIG_FORMATTING_STANDARD" + value: "{{ .Values.config.formatting.standard }}" + - name: "CONFIG_MERGEBACK_ENABLE" + value: "{{ .Values.config.mergeback.enable }}" + - name: "CONFIG_BACKPRESSURE_ENABLE" + value: "{{ .Values.config.backpressure.enable }}" + - name: "CONFIG_COMPLETION-THRESHOLD-CHECK_ENABLE" + value: "{{ .Values.config.completion_threshold_check.enable }}" + - name: "CONFIG_COMPLETION-THRESHOLD-CHECK_COMPLETION-RATE" + value: "{{ .Values.config.completion_threshold_check.completion_rate }}" + - name: "CLOUD_AWS_REGION_STATIC" + valueFrom: + secretKeyRef: + name: "bulk-processor-secret" + key: "aws-region" + - name: "BP_JAVA_OPTS" + value: "-Xmx400m -Xms400m" + - name: "CLOUD_AWS_S3BASEURL" + value: {{.Values.global.s3BaseUrl}} + - name: "AWS_ACCESS_KEY" + valueFrom: + secretKeyRef: + name: "bulk-processor-secret" + key: "aws-access-key" + - name: "AWS_SECRET_KEY" + valueFrom: + secretKeyRef: + name: "bulk-processor-secret" + key: "aws-secret-key" + - name: "IDENTITY_MAPPER_CONTACTPOINT" + value: "{{ .Values.identity_account_mapper.hostname }}" +{{- if .Values.extraEnvs | default .Values.deployment.extraEnvs }} +{{ toYaml ( .Values.extraEnvs | default .Values.deployment.extraEnvs ) | indent 10 }} +{{- end }} + envFrom: {{ toYaml ( .Values.envFrom | default .Values.deployment.envFrom ) | nindent 12 }} + securityContext: {{ toYaml ( .Values.podSecurityContext | default .Values.deployment.securityContext ) | nindent 12 }} + volumeMounts: + - name: ph-ee-config + mountPath: "/config" + volumes: + - name: ph-ee-config + configMap: + name: ph-ee-config +{{- end }} diff --git a/ph-ee-env-template/helm/ph-ee-engine/connector-bulk/templates/ingress.yaml b/ph-ee-env-template/helm/ph-ee-engine/connector-bulk/templates/ingress.yaml new file mode 100644 index 000000000..b4fa902b4 --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/connector-bulk/templates/ingress.yaml @@ -0,0 +1,50 @@ +{{- if .Values.ingress.enabled -}} +{{- $pathtype := .Values.ingress.pathtype -}} +{{- $ingressPath := .Values.ingress.path -}} +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: ph-ee-connector-bulk + labels: + app: {{ .Chart.Name }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +{{- with .Values.ingress.annotations }} + annotations: +{{ toYaml . | indent 4 }} +{{- end }} +spec: + {{- if .Values.ingress.className }} + ingressClassName: {{ .Values.ingress.className | quote }} + {{- end }} +{{- if .Values.ingress.tls }} + tls: + {{- if .ingressPath }} + {{- range .Values.ingress.tls }} + - hosts: + {{- range .hosts }} + - {{ . }} + {{- end }} + secretName: {{ .secretName }} + {{- end }} +{{- else }} +{{ toYaml .Values.ingress.tls | indent 4 }} + {{- end }} +{{- end}} + rules: + {{- range .Values.ingress.hosts }} + - host: {{ .host }} + http: + paths: + {{- range .paths }} + - path: {{ .path }} + pathType: {{ $pathtype }} + backend: + service: + name: {{ .backend.service.name}} + port: + number: {{ .backend.service.port.number}} + {{- end }} + {{- end }} + {{- end }} + \ No newline at end of file diff --git a/ph-ee-env-template/helm/ph-ee-engine/connector-bulk/templates/role.yaml b/ph-ee-env-template/helm/ph-ee-engine/connector-bulk/templates/role.yaml new file mode 100644 index 000000000..07d402c51 --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/connector-bulk/templates/role.yaml @@ -0,0 +1,14 @@ +{{- if .Values.managedServiceAccount }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: ph-ee-connector-bulk-role + namespace: {{ .Release.Namespace }} +rules: +- apiGroups: + - "" + resources: + - pods + - configmaps + verbs: ["get", "create", "update"] +{{- end -}} \ No newline at end of file diff --git a/ph-ee-env-template/helm/ph-ee-engine/connector-bulk/templates/rolebinding.yaml b/ph-ee-env-template/helm/ph-ee-engine/connector-bulk/templates/rolebinding.yaml new file mode 100644 index 000000000..b32ca9733 --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/connector-bulk/templates/rolebinding.yaml @@ -0,0 +1,15 @@ +{{- if .Values.managedServiceAccount }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: ph-ee-connector-bulk-role-binding + namespace: {{ .Release.Namespace }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: ph-ee-connector-bulk-role +subjects: +- kind: ServiceAccount + name: ph-ee-connector-bulk + namespace: {{ .Release.Namespace }} +{{- end -}} \ No newline at end of file diff --git a/ph-ee-env-template/helm/ph-ee-engine/connector-bulk/templates/secret.yaml b/ph-ee-env-template/helm/ph-ee-engine/connector-bulk/templates/secret.yaml new file mode 100644 index 000000000..a08ca401d --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/connector-bulk/templates/secret.yaml @@ -0,0 +1,11 @@ +{{- if .Values.enabled -}} +apiVersion: {{ .Values.secret.apiversion }} +kind: Secret +metadata: + name: bulk-processor-secret +type: Opaque +data: + aws-region: {{ .Values.global.region | b64enc }} + aws-access-key: {{ .Values.aws.access_key | b64enc }} + aws-secret-key: {{ .Values.aws.secret_key | b64enc }} +{{- end }} diff --git a/ph-ee-env-template/helm/ph-ee-engine/connector-bulk/templates/service.yaml b/ph-ee-env-template/helm/ph-ee-engine/connector-bulk/templates/service.yaml new file mode 100644 index 000000000..657940af7 --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/connector-bulk/templates/service.yaml @@ -0,0 +1,22 @@ +{{- if .Values.enabled -}} +apiVersion: {{ .Values.service.apiversion }} +kind: Service +metadata: + labels: + app: ph-ee-connector-bulk + name: ph-ee-connector-bulk +{{- with .Values.service.annotations }} + annotations: +{{ toYaml . | indent 4 }} +{{- end }} +spec: + ports: + - name: port + port: 8443 + protocol: TCP + targetPort: 8443 + selector: + app: ph-ee-connector-bulk + sessionAffinity: None + type: ClusterIP +{{- end }} diff --git a/ph-ee-env-template/helm/ph-ee-engine/connector-bulk/templates/serviceaccount.yaml b/ph-ee-env-template/helm/ph-ee-engine/connector-bulk/templates/serviceaccount.yaml new file mode 100644 index 000000000..a7603fc83 --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/connector-bulk/templates/serviceaccount.yaml @@ -0,0 +1,15 @@ +{{- if .Values.managedServiceAccount }} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: ph-ee-connector-bulk + annotations: + {{- with .Values.serviceAccountAnnotations }} + {{- toYaml . | nindent 4 }} + {{- end }} + labels: + app: ph-ee-connector-bulk + chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" + heritage: {{ .Release.Service | quote }} + release: {{ .Release.Name | quote }} +{{- end -}} \ No newline at end of file diff --git a/ph-ee-env-template/helm/ph-ee-engine/connector-bulk/values.yaml b/ph-ee-env-template/helm/ph-ee-engine/connector-bulk/values.yaml new file mode 100644 index 000000000..92e2a3584 --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/connector-bulk/values.yaml @@ -0,0 +1,73 @@ +service: + apiversion: "v1" + annotations: {} + +secret: + apiversion: "v1" + +configmap: + apiversion: "v1" + +enabled: "" +image: "" +imageTag: "" +imagePullPolicy: "" +SPRING_PROFILES_ACTIVE: "" +camel_disable_ssl: true +tenants: "" +bucket_name: "paymenthub-ee-dev" +operations_app: + contactpoint: "" + endpoints: + batch_transaction: "" +identity_account_mapper: + hostname : "" +config: + partylookup: + enable: false + approval: + enable: false + ordering: + enable: false + field: "" + splitting: + enable: true + sub_batch_size: 5 + formatting: + enable: false + standard: "DEFAULT" + mergeback: + enable: true + backpressure: + enable: false + completion_threshold_check: + enable: true + completion_rate: 95 + deduplication: + enabled: true +limits: + cpu: "256m" + memory: "384M" +requests: + cpu: "100m" + memory: "256M" +# Enabling this will publicly expose your Elasticsearch instance. +# Only enable this if you have security enabled on your cluster +ingress: + enabled: false + annotations: {} + # kubernetes.io/ingress.class: "nginx" + pathtype: ImplementationSpecific + hosts: + - host: "" + paths: + - path: / + tls: [] + # - secretName: sandbox-secret + # hosts: + # - chart-example.local + +deployment: + apiVersion: "apps/v1" + annotations: + deployTime: "{{ .Values.deployTime }}" diff --git a/ph-ee-env-template/helm/ph-ee-engine/connector-channel/Chart.yaml b/ph-ee-env-template/helm/ph-ee-engine/connector-channel/Chart.yaml new file mode 100644 index 000000000..1dbd1615c --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/connector-channel/Chart.yaml @@ -0,0 +1,5 @@ +apiVersion: v1 +description: ph-ee-connector-channel +name: channel +version: 1.0.0 +appVersion: "1.0.0" diff --git a/ph-ee-env-template/helm/ph-ee-engine/connector-channel/README.md b/ph-ee-env-template/helm/ph-ee-engine/connector-channel/README.md new file mode 100644 index 000000000..5ee0325b5 --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/connector-channel/README.md @@ -0,0 +1,67 @@ +# channel + +![Version: 1.0.0](https://img.shields.io/badge/Version-1.0.0-informational?style=flat-square) ![AppVersion: 1.0.0](https://img.shields.io/badge/AppVersion-1.0.0-informational?style=flat-square) + +ph-ee-connector-channel + +## Values + +| Key | Type | Default | Description | +|-----|------|---------|-------------| +| DFSPIDS | string | `""` | | +| LOGGING_LEVEL_ROOT | string | `"INFO"` | | +| SPRING_PROFILES_ACTIVE | string | `"bb,tenants"` | | +| configmap.apiversion | string | `"v1"` | | +| deployment.annotations.deployTime | string | `"{{ .Values.deployTime }}"` | | +| deployment.apiVersion | string | `"apps/v1"` | | +| enabled | bool | `true` | | +| hostname | string | `"channel.sandbox.mifos.io"` | | +| image | string | `""` | | +| imagePullPolicy | string | `"Always"` | | +| imageTag | string | `"latest"` | | +| ingress.annotations."kubernetes.io/ingress.class" | string | `"nginx"` | | +| ingress.apiversion | string | `"networking.k8s.io/v1"` | | +| ingress.backend.service.name | string | `"ph-ee-connector-channel"` | | +| ingress.backend.service.port.number | int | `80` | | +| ingress.className | string | `"nginx"` | | +| ingress.enabled | bool | `true` | | +| ingress.path | string | `"/"` | | +| ingress.stub_backend.service.name | string | `"ph-ee-connector-channel"` | | +| ingress.stub_backend.service.port.number | int | `82` | | +| ingress.tls[0].hosts | string | `"notifications.sandbox.mifos.io"` | | +| ingress.tls[1].secretName | string | `"sandbox-secret"` | | +| limits.cpu | string | `"500m"` | | +| limits.memory | string | `"512M"` | | +| livenessProbe.httpGet.path | string | `"/actuator/health/liveness"` | | +| livenessProbe.httpGet.port | int | `8080` | | +| livenessProbe.initialDelaySeconds | int | `20` | | +| livenessProbe.periodSeconds | int | `30` | | +| notifications.NOTIFICATION_FAILURE_ENABLED | string | `"false"` | | +| notifications.NOTIFICATION_SUCCESS_ENABLED | string | `"false"` | | +| operations.authEnabled | bool | `false` | | +| operations.url | string | `"http://ops-bk.sandbox.mifos.io/api/v1"` | | +| readinessProbe.httpGet.path | string | `"/actuator/health/readiness"` | | +| readinessProbe.httpGet.port | int | `8080` | | +| readinessProbe.initialDelaySeconds | int | `20` | | +| readinessProbe.periodSeconds | int | `30` | | +| redis.host | string | `"127.0.0.1"` | | +| redis.idempotency.apiList | string | `"/channel/transfer,/channel/collection,/channel/gsma/transaction,/channel/transactionRequest"` | | +| redis.idempotency.enabled | bool | `true` | | +| redis.idempotency.keyFormat | string | `"clientCorrelationId_tenant_api"` | | +| redis.password | string | `""` | | +| redis.port | int | `6379` | | +| requests.cpu | string | `"100m"` | | +| requests.memory | string | `"256M"` | | +| secret.apiversion | string | `"v1"` | | +| service.apiversion | string | `"v1"` | | +| stub_hostname | string | `"channel-gsma.sandbox.mifos.io"` | | +| tenantPrimary.clientId | string | `"mifos"` | | +| tenantPrimary.clientSecret | string | `"password"` | | +| tenantPrimary.tenant | string | `"rhino"` | | +| tenantSecondary.clientId | string | `"mifos"` | | +| tenantSecondary.clientSecret | string | `"password"` | | +| tenantSecondary.tenant | string | `"gorilla"` | | +| wildcardhostname | string | `"channel.sandbox.mifos.io"` | | + +---------------------------------------------- +Autogenerated from chart metadata using [helm-docs v1.11.0](https://github.com/norwoodj/helm-docs/releases/v1.11.0) diff --git a/ph-ee-env-template/helm/ph-ee-engine/connector-channel/templates/clusterrole.yaml b/ph-ee-env-template/helm/ph-ee-engine/connector-channel/templates/clusterrole.yaml new file mode 100644 index 000000000..f0455391b --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/connector-channel/templates/clusterrole.yaml @@ -0,0 +1,11 @@ +{{- if .Values.managedServiceAccount }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + # "namespace" omitted since ClusterRoles are not namespaced + name: ph-ee-connector-channel-c-role +rules: +- apiGroups: [""] + resources: ["secrets"] + verbs: ["get", "watch", "list"] +{{- end -}} \ No newline at end of file diff --git a/ph-ee-env-template/helm/ph-ee-engine/connector-channel/templates/clusterrolebinding.yaml b/ph-ee-env-template/helm/ph-ee-engine/connector-channel/templates/clusterrolebinding.yaml new file mode 100644 index 000000000..7036cc777 --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/connector-channel/templates/clusterrolebinding.yaml @@ -0,0 +1,15 @@ +{{- if .Values.managedServiceAccount }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: ph-ee-connector-channel-c-role-binding +subjects: +- kind: ServiceAccount + name: ph-ee-connector-channel # name of your service account + namespace: {{ .Release.Namespace }} # this is the namespace your service account is in +roleRef: # referring to your ClusterRole + kind: ClusterRole + name: ph-ee-connector-channel-c-role + apiGroup: rbac.authorization.k8s.io + +{{- end -}} \ No newline at end of file diff --git a/ph-ee-env-template/helm/ph-ee-engine/connector-channel/templates/deployment.yaml b/ph-ee-env-template/helm/ph-ee-engine/connector-channel/templates/deployment.yaml new file mode 100644 index 000000000..f67253b55 --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/connector-channel/templates/deployment.yaml @@ -0,0 +1,132 @@ +{{- if .Values.enabled -}} + +apiVersion: apps/v1 +kind: Deployment +metadata: + name: ph-ee-connector-channel + labels: + app: ph-ee-connector-channel +spec: + replicas: {{ .Values.replicas }} + selector: + matchLabels: + app: ph-ee-connector-channel + template: + metadata: + labels: + app: ph-ee-connector-channel + annotations: +{{- if .Values.deployment.annotations }} +{{ toYaml .Values.deployment.annotations | indent 8 }} +{{- end }} + spec: + initContainers: + #During this Pod's initialization, check that zeebe-gateway service is up and running before starting this pod + - name: check-zeebe-gateway-ready + image: busybox:latest + command: [ 'sh', '-c','until nc -vz {{ .Release.Name }}-zeebe-gateway 26500; do echo "Waiting for zeebe-gateway service"; sleep 2; done;' ] + #During this Pod's initialization, check that redis is up and running before starting this pod + - name: check-redis-ready + image: busybox:latest + command: [ 'sh', '-c','until nc -vz {{ .Release.Name }}-redis-master 6379; do echo "Waiting for redis-master service"; sleep 2; done;' ] + terminationGracePeriodSeconds: {{ .Values.terminationGracePeriod }} + containers: + - name: ph-ee-connector-channel + image: "{{ .Values.image }}" + ports: + - containerPort: 8443 + imagePullPolicy: "{{ .Values.global.imagePullPolicy }}" + resources: + limits: + memory: "{{ .Values.limits.memory }}" + cpu: "{{ .Values.limits.cpu }}" + requests: + memory: "{{ .Values.requests.memory }}" + cpu: "{{ .Values.requests.cpu }}" + livenessProbe: + httpGet: + path: /actuator/health/liveness + port: 8443 + scheme: HTTPS + initialDelaySeconds: {{.Values.livenessProbe.initialDelaySeconds}} + periodSeconds: {{.Values.livenessProbe.periodSeconds}} + readinessProbe: + httpGet: + path: /actuator/health/readiness + port: 8443 + scheme: HTTPS + initialDelaySeconds: {{.Values.readinessProbe.initialDelaySeconds}} + periodSeconds: {{.Values.readinessProbe.periodSeconds}} + env: + - name: "SPRING_PROFILES_ACTIVE" + value: "{{ .Values.SPRING_PROFILES_ACTIVE }}" + - name: "DEFAULT_HEADERS" + value: "{{ .Values.DEFAULT_HEADERS }}" + - name: "ZEEBE_BROKER_CONTACTPOINT" + value: "{{ .Release.Name }}-zeebe-gateway:26500" + - name: "DFSPIDS" + value: "{{ .Values.global.DFSPIDS }}" + - name: "TRANSACTION-ID-LENGTH" + value: "{{ .Values.TRANSACTION_ID_LENGTH }}" + - name: "MPESA_NOTIFICATION_SUCCESS_ENABLED" + value: "{{ .Values.notifications.NOTIFICATION_SUCCESS_ENABLED }}" + - name: "MPESA_NOTIFICATION_FAILURE_ENABLED" + value: "{{ .Values.notifications.NOTIFICATION_FAILURE_ENABLED }}" + - name: "LOGGING_LEVEL_ROOT" + value: "{{ .Values.global.LOGGING_LEVEL_ROOT }}" + - name: "AMS" + value: "{{ .Values.AMS }}" + - name: "LOGGING_PATTERN_CONSOLE" + value: "{{ .Values.global.LOGGING_PATTERN_CONSOLE }}" + - name: "gsma_payee_tenant" + value: "{{ .Values.gsma_payee_tenant }}" + - name: "operations_url" + value: "{{ .Values.operations.url }}" + - name: "operations_auth-enabled" + value: "{{ .Values.operations.authEnabled }}" + - name: "CHANNEL_TENANTPRIMARY_CLIENTID" + value: "{{ .Values.tenantPrimary.clientId }}" + - name: "CHANNEL_TENANTPRIMARY_CLIENTSECRET" + value: "{{ .Values.tenantPrimary.clientSecret }}" + - name: "CHANNEL_TENANTPRIMARY_TENANT" + value: "{{ .Values.tenantPrimary.tenant }}" + - name: "CHANNEL_TENANTSECONDARY_CLIENTID" + value: "{{ .Values.tenantSecondary.clientId }}" + - name: "CHANNEL_TENANTSECONDARY_CLIENTSECRET" + value: "{{ .Values.tenantSecondary.clientSecret }}" + - name: "CHANNEL_TENANTSECONDARY_TENANT" + value: "{{ .Values.tenantSecondary.tenant }}" +{{- if .Values.redis.idempotency.enabled }} + - name: "redis_idempotency_enabled" + value: "{{ .Values.redis.idempotency.enabled }}" + - name: "redis_host" + value: "{{ .Values.redis.host }}" + - name: "redis_port" + value: "{{ .Values.redis.port }}" + - name: "redis_idempotency_keyFormat" + value: "{{ .Values.redis_idempotency_keyFormat }}" + - name: "redis_idempotency_apiList" + value: "{{ .Values.redis_idempotency_apiList }}" + - name: "redis_password" + valueFrom: + secretKeyRef: + name: "{{ .Release.Name }}-redis" + key: "redis-password" +{{end}} + - name: "server_ssl_key-password" + value: "{{ .Values.server.ssl.keyPassword }}" + - name: "server_ssl_key-store-password" + value: "{{ .Values.server.ssl.keyStorePassword }}" +{{- if .Values.extraEnvs | default .Values.deployment.extraEnvs }} +{{ toYaml ( .Values.extraEnvs | default .Values.deployment.extraEnvs ) | indent 10 }} +{{- end }} + envFrom: {{ toYaml ( .Values.envFrom | default .Values.deployment.envFrom ) | nindent 12 }} + securityContext: {{ toYaml ( .Values.podSecurityContext | default .Values.deployment.securityContext ) | nindent 12 }} + volumeMounts: + - name: ph-ee-config + mountPath: "/config" + volumes: + - name: ph-ee-config + configMap: + name: ph-ee-config +{{- end }} diff --git a/ph-ee-env-template/helm/ph-ee-engine/connector-channel/templates/ingress.yaml b/ph-ee-env-template/helm/ph-ee-engine/connector-channel/templates/ingress.yaml new file mode 100644 index 000000000..7cc612a54 --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/connector-channel/templates/ingress.yaml @@ -0,0 +1,49 @@ +{{- if .Values.ingress.enabled -}} +{{- $pathtype := .Values.ingress.pathtype -}} +{{- $ingressPath := .Values.ingress.path -}} +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: ph-ee-connector-channel + labels: + app: {{ .Chart.Name }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +{{- with .Values.ingress.annotations }} + annotations: +{{ toYaml . | indent 4 }} +{{- end }} +spec: + {{- if .Values.ingress.className }} + ingressClassName: {{ .Values.ingress.className | quote }} + {{- end }} +{{- if .Values.ingress.tls }} + tls: + {{- if .ingressPath }} + {{- range .Values.ingress.tls }} + - hosts: + {{- range .hosts }} + - {{ . }} + {{- end }} + secretName: {{ .secretName }} + {{- end }} +{{- else }} +{{ toYaml .Values.ingress.tls | indent 4 }} + {{- end }} +{{- end}} + rules: + {{- range .Values.ingress.hosts }} + - host: {{ .host }} + http: + paths: + {{- range .paths }} + - path: {{ .path }} + pathType: {{ $pathtype }} + backend: + service: + name: {{ .backend.service.name}} + port: + number: {{ .backend.service.port.number}} + {{- end }} + {{- end }} + {{- end }} diff --git a/ph-ee-env-template/helm/ph-ee-engine/connector-channel/templates/role.yaml b/ph-ee-env-template/helm/ph-ee-engine/connector-channel/templates/role.yaml new file mode 100644 index 000000000..c26649b03 --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/connector-channel/templates/role.yaml @@ -0,0 +1,14 @@ +{{- if .Values.managedServiceAccount }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: ph-ee-connector-channel-role + namespace: {{ .Release.Namespace }} +rules: +- apiGroups: + - "" + resources: + - pods + - configmaps + verbs: ["get", "create", "update"] +{{- end -}} \ No newline at end of file diff --git a/ph-ee-env-template/helm/ph-ee-engine/connector-channel/templates/rolebinding.yaml b/ph-ee-env-template/helm/ph-ee-engine/connector-channel/templates/rolebinding.yaml new file mode 100644 index 000000000..a2a0924c1 --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/connector-channel/templates/rolebinding.yaml @@ -0,0 +1,15 @@ +{{- if .Values.managedServiceAccount }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: ph-ee-connector-channel-role-binding + namespace: {{ .Release.Namespace }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: ph-ee-connector-channel-role +subjects: +- kind: ServiceAccount + name: ph-ee-connector-channel + namespace: {{ .Release.Namespace }} +{{- end -}} \ No newline at end of file diff --git a/ph-ee-env-template/helm/ph-ee-engine/connector-channel/templates/service.yaml b/ph-ee-env-template/helm/ph-ee-engine/connector-channel/templates/service.yaml new file mode 100644 index 000000000..9b0b5dbe8 --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/connector-channel/templates/service.yaml @@ -0,0 +1,26 @@ +{{- if .Values.enabled -}} +apiVersion: {{ .Values.service.apiversion }} +kind: Service +metadata: + labels: + app: ph-ee-connector-channel + name: ph-ee-connector-channel +{{- with .Values.service.annotations }} + annotations: +{{ toYaml . | indent 4 }} +{{- end }} +spec: + ports: + - name: port + port: 8443 + protocol: TCP + targetPort: 8443 + - name: http + port: 82 + protocol: TCP + targetPort: 8443 + selector: + app: ph-ee-connector-channel + sessionAffinity: None + type: ClusterIP +{{- end }} \ No newline at end of file diff --git a/ph-ee-env-template/helm/ph-ee-engine/connector-channel/templates/serviceaccount.yaml b/ph-ee-env-template/helm/ph-ee-engine/connector-channel/templates/serviceaccount.yaml new file mode 100644 index 000000000..8339ef95a --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/connector-channel/templates/serviceaccount.yaml @@ -0,0 +1,15 @@ +{{- if .Values.managedServiceAccount }} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: "ph-ee-connector-channel" + annotations: + {{- with .Values.serviceAccountAnnotations }} + {{- toYaml . | nindent 4 }} + {{- end }} + labels: + app: "ph-ee-connector-channel" + chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" + heritage: {{ .Release.Service | quote }} + release: {{ .Release.Name | quote }} +{{- end -}} \ No newline at end of file diff --git a/ph-ee-env-template/helm/ph-ee-engine/connector-channel/values.yaml b/ph-ee-env-template/helm/ph-ee-engine/connector-channel/values.yaml new file mode 100644 index 000000000..8e582f85f --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/connector-channel/values.yaml @@ -0,0 +1,83 @@ +service: + apiversion: "v1" + annotations: {} + +secret: + apiversion: "v1" + +configmap: + apiversion: "v1" + +enabled: true +image: "" +imageTag: latest +imagePullPolicy: "Always" +SPRING_PROFILES_ACTIVE: "bb,tenants" +DEFAULT_HEADERS: "user-agent,accept,postman-token,host,accept-encoding,connection,content-type,content-length,x-request-id,x-real-ip,x-forwarded-host,x-forwarded-port,x-forwarded-proto,x-forwarded-scheme,x-scheme,x-forwarded-path" +LOGGING_LEVEL_ROOT: "INFO" +DFSPIDS: "" +operations: + url: "http://ops-bk.sandbox.mifos.io/api/v1" + authEnabled: false +redis: + host: "127.0.0.1" + port: 6379 + password: "" + idempotency: + enabled: true + keyFormat: "clientCorrelationId_tenant_api" + apiList: "/channel/transfer,/channel/collection,/channel/gsma/transaction,/channel/transactionRequest" +#key-store values are getting overridden from application.yaml +tenantPrimary: + clientId: "mifos" + clientSecret: "password" + tenant: "rhino" +tenantSecondary: + clientId: "mifos" + clientSecret: "password" + tenant: "gorilla" +notifications: + NOTIFICATION_SUCCESS_ENABLED: "false" + NOTIFICATION_FAILURE_ENABLED: "false" +server: + ssl: + keyPassword: "" + keyStorePassword: "" +limits: + cpu: "500m" + memory: "512M" +requests: + cpu: "100m" + memory: "256M" +livenessProbe: + httpGet: + path: /actuator/health/liveness + port: 8443 + initialDelaySeconds: 20 + periodSeconds: 30 +readinessProbe: + httpGet: + path: /actuator/health/readiness + port: 8443 + initialDelaySeconds: 20 + periodSeconds: 30 +# Enabling this will publicly expose your channel instance. +# Only enable this if you have security enabled on your cluster +ingress: + enabled: true + annotations: {} + # kubernetes.io/ingress.class: "nginx" + pathtype: Prefix + hosts: + - host: "" + paths: + - path: / + tls: [] + # - secretName: sandbox-secret + # hosts: + # - chart-example.local + +deployment: + apiVersion: "apps/v1" + annotations: + deployTime: "{{ .Values.deployTime }}" diff --git a/ph-ee-env-template/helm/ph-ee-engine/connector-crm/Chart.yaml b/ph-ee-env-template/helm/ph-ee-engine/connector-crm/Chart.yaml new file mode 100644 index 000000000..7ea95f335 --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/connector-crm/Chart.yaml @@ -0,0 +1,5 @@ +apiVersion: v1 +description: ph-ee-connector-crm +name: crm +version: 1.0.0 +appVersion: "1.0.0" diff --git a/ph-ee-env-template/helm/ph-ee-engine/connector-crm/README.md b/ph-ee-env-template/helm/ph-ee-engine/connector-crm/README.md new file mode 100644 index 000000000..5c73ccda7 --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/connector-crm/README.md @@ -0,0 +1,48 @@ +# connector-crm + +![Version: 1.0.0](https://img.shields.io/badge/Version-1.0.0-informational?style=flat-square) ![AppVersion: 1.0.0](https://img.shields.io/badge/AppVersion-1.0.0-informational?style=flat-square) + +ph-ee-connector-crm + +## Values + +| Key | Type | Default | Description | +|---------------------------------------------------|--------|------------------------------------|-------------| +| DFSPIDS | string | `""` | | +| LOGGING_LEVEL_ROOT | string | `"INFO"` | | +| SPRING_PROFILES_ACTIVE | string | `"bb,tenants"` | | +| configmap.apiversion | string | `"v1"` | | +| deployment.annotations.deployTime | string | `"{{ .Values.deployTime }}"` | | +| deployment.apiVersion | string | `"apps/v1"` | | +| enabled | bool | `true` | | +| hostname | string | `"crm.sandbox.mifos.io"` | | +| image | string | `""` | | +| imagePullPolicy | string | `"Always"` | | +| imageTag | string | `"latest"` | | +| ingress.annotations."kubernetes.io/ingress.class" | string | `"nginx"` | | +| ingress.apiversion | string | `"networking.k8s.io/v1"` | | +| ingress.backend.service.name | string | `"ph-ee-connector-crm"` | | +| ingress.backend.service.port.number | int | `80` | | +| ingress.className | string | `"nginx"` | | +| ingress.enabled | bool | `true` | | +| ingress.path | string | `"/"` | | +| ingress.stub_backend.service.name | string | `"ph-ee-connector-crm"` | | +| ingress.stub_backend.service.port.number | int | `82` | | +| ingress.tls[0].hosts | string | `"notifications.sandbox.mifos.io"` | | +| ingress.tls[1].secretName | string | `"sandbox-secret"` | | +| limits.cpu | string | `"500m"` | | +| limits.memory | string | `"512M"` | | +| livenessProbe.httpGet.path | string | `"/actuator/health/liveness"` | | +| livenessProbe.httpGet.port | int | `8080` | | +| livenessProbe.initialDelaySeconds | int | `20` | | +| livenessProbe.periodSeconds | int | `30` | | +| readinessProbe.httpGet.path | string | `"/actuator/health/readiness"` | | +| readinessProbe.httpGet.port | int | `8080` | | +| readinessProbe.initialDelaySeconds | int | `20` | | +| readinessProbe.periodSeconds | int | `30` | | +| requests.cpu | string | `"100m"` | | +| requests.memory | string | `"256M"` | | +| service.apiversion | string | `"v1"` | | +| stub_hostname | string | `"crm.sandbox.mifos.io"` | | +---------------------------------------------- +Autogenerated from chart metadata using [helm-docs v1.11.0](https://github.com/norwoodj/helm-docs/releases/v1.11.0) diff --git a/ph-ee-env-template/helm/ph-ee-engine/connector-crm/templates/clusterrole.yaml b/ph-ee-env-template/helm/ph-ee-engine/connector-crm/templates/clusterrole.yaml new file mode 100644 index 000000000..363969072 --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/connector-crm/templates/clusterrole.yaml @@ -0,0 +1,11 @@ +{{- if .Values.managedServiceAccount }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + # "namespace" omitted since ClusterRoles are not namespaced + name: ph-ee-connector-crm-c-role +rules: +- apiGroups: [""] + resources: ["secrets"] + verbs: ["get", "watch", "list"] +{{- end -}} \ No newline at end of file diff --git a/ph-ee-env-template/helm/ph-ee-engine/connector-crm/templates/clusterrolebinding.yaml b/ph-ee-env-template/helm/ph-ee-engine/connector-crm/templates/clusterrolebinding.yaml new file mode 100644 index 000000000..adab53acc --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/connector-crm/templates/clusterrolebinding.yaml @@ -0,0 +1,15 @@ +{{- if .Values.managedServiceAccount }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: ph-ee-connector-crm-c-role-binding +subjects: +- kind: ServiceAccount + name: ph-ee-connector-crm # name of your service account + namespace: {{ .Release.Namespace }} # this is the namespace your service account is in +roleRef: # referring to your ClusterRole + kind: ClusterRole + name: ph-ee-connector-crm-c-role + apiGroup: rbac.authorization.k8s.io + +{{- end -}} \ No newline at end of file diff --git a/ph-ee-env-template/helm/ph-ee-engine/connector-crm/templates/deployment.yaml b/ph-ee-env-template/helm/ph-ee-engine/connector-crm/templates/deployment.yaml new file mode 100644 index 000000000..44d19f16a --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/connector-crm/templates/deployment.yaml @@ -0,0 +1,75 @@ +{{- if .Values.enabled -}} + +apiVersion: apps/v1 +kind: Deployment +metadata: + name: ph-ee-connector-crm + labels: + app: ph-ee-connector-crm +spec: + replicas: {{ .Values.replicas }} + selector: + matchLabels: + app: ph-ee-connector-crm + template: + metadata: + labels: + app: ph-ee-connector-crm + annotations: +{{- if .Values.deployment.annotations }} +{{ toYaml .Values.deployment.annotations | indent 8 }} +{{- end }} + spec: + initContainers: + #During this Pod's initialization, check that zeebe-gateway service is up and running before starting this pod + - name: check-zeebe-gateway-ready + image: busybox:latest + command: [ 'sh', '-c','until nc -vz {{ .Release.Name }}-zeebe-gateway 26500; do echo "Waiting for zeebe-gateway service"; sleep 2; done;' ] + terminationGracePeriodSeconds: {{ .Values.terminationGracePeriod }} + containers: + - name: ph-ee-connector-crm + image: "{{ .Values.image }}" + ports: + - containerPort: 8080 + imagePullPolicy: "{{ .Values.global.imagePullPolicy }}" + resources: + limits: + memory: "{{ .Values.limits.memory }}" + cpu: "{{ .Values.limits.cpu }}" + requests: + memory: "{{ .Values.requests.memory }}" + cpu: "{{ .Values.requests.cpu }}" +# livenessProbe: +# httpGet: +# path: /actuator/health/liveness +# port: 8443 +# scheme: HTTPS +# initialDelaySeconds: 20 +# periodSeconds: 180 +# readinessProbe: +# httpGet: +# path: /actuator/health/readiness +# port: 8443 +# scheme: HTTPS +# initialDelaySeconds: 20 +# periodSeconds: 180 + env: + - name: "SPRING_PROFILES_ACTIVE" + value: "{{ .Values.SPRING_PROFILES_ACTIVE }}" + - name: "ZEEBE_BROKER_CONTACTPOINT" + value: "{{ .Release.Name }}-zeebe-gateway:26500" + - name: "DFSPIDS" + value: "{{ .Values.global.DFSPIDS }}" +{{- if .Values.extraEnvs | default .Values.deployment.extraEnvs }} +{{ toYaml ( .Values.extraEnvs | default .Values.deployment.extraEnvs ) | indent 10 }} +{{- end }} + envFrom: {{ toYaml ( .Values.envFrom | default .Values.deployment.envFrom ) | nindent 12 }} + securityContext: {{ toYaml ( .Values.podSecurityContext | default .Values.deployment.securityContext ) | nindent 12 }} + volumeMounts: + - name: ph-ee-config + mountPath: "/config" + volumes: + - name: ph-ee-config + configMap: + name: ph-ee-config +{{- end }} diff --git a/ph-ee-env-template/helm/ph-ee-engine/connector-crm/templates/ingress.yaml b/ph-ee-env-template/helm/ph-ee-engine/connector-crm/templates/ingress.yaml new file mode 100644 index 000000000..061b0dad5 --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/connector-crm/templates/ingress.yaml @@ -0,0 +1,49 @@ +{{- if .Values.ingress.enabled -}} +{{- $pathtype := .Values.ingress.pathtype -}} +{{- $ingressPath := .Values.ingress.path -}} +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: ph-ee-connector-crm + labels: + app: {{ .Chart.Name }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +{{- with .Values.ingress.annotations }} + annotations: +{{ toYaml . | indent 4 }} +{{- end }} +spec: + {{- if .Values.ingress.className }} + ingressClassName: {{ .Values.ingress.className | quote }} + {{- end }} +{{- if .Values.ingress.tls }} + tls: + {{- if .ingressPath }} + {{- range .Values.ingress.tls }} + - hosts: + {{- range .hosts }} + - {{ . }} + {{- end }} + secretName: {{ .secretName }} + {{- end }} +{{- else }} +{{ toYaml .Values.ingress.tls | indent 4 }} + {{- end }} +{{- end}} + rules: + {{- range .Values.ingress.hosts }} + - host: {{ .host }} + http: + paths: + {{- range .paths }} + - path: {{ .path }} + pathType: {{ $pathtype }} + backend: + service: + name: {{ .backend.service.name}} + port: + number: {{ .backend.service.port.number}} + {{- end }} + {{- end }} + {{- end }} diff --git a/ph-ee-env-template/helm/ph-ee-engine/connector-crm/templates/role.yaml b/ph-ee-env-template/helm/ph-ee-engine/connector-crm/templates/role.yaml new file mode 100644 index 000000000..229618fe6 --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/connector-crm/templates/role.yaml @@ -0,0 +1,14 @@ +{{- if .Values.managedServiceAccount }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: ph-ee-connector-crm-role + namespace: {{ .Release.Namespace }} +rules: +- apiGroups: + - "" + resources: + - pods + - configmaps + verbs: ["get", "create", "update"] +{{- end -}} \ No newline at end of file diff --git a/ph-ee-env-template/helm/ph-ee-engine/connector-crm/templates/rolebinding.yaml b/ph-ee-env-template/helm/ph-ee-engine/connector-crm/templates/rolebinding.yaml new file mode 100644 index 000000000..b5d0b051a --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/connector-crm/templates/rolebinding.yaml @@ -0,0 +1,15 @@ +{{- if .Values.managedServiceAccount }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: ph-ee-connector-crm-role-binding + namespace: {{ .Release.Namespace }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: ph-ee-connector-crm-role +subjects: +- kind: ServiceAccount + name: ph-ee-connector-crm + namespace: {{ .Release.Namespace }} +{{- end -}} \ No newline at end of file diff --git a/ph-ee-env-template/helm/ph-ee-engine/connector-crm/templates/service.yaml b/ph-ee-env-template/helm/ph-ee-engine/connector-crm/templates/service.yaml new file mode 100644 index 000000000..dba62b18b --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/connector-crm/templates/service.yaml @@ -0,0 +1,22 @@ +{{- if .Values.enabled -}} +apiVersion: {{ .Values.service.apiversion }} +kind: Service +metadata: + labels: + app: ph-ee-connector-crm + name: ph-ee-connector-crm +{{- with .Values.service.annotations }} + annotations: +{{ toYaml . | indent 4 }} +{{- end }} +spec: + ports: + - name: port + port: 8080 + protocol: TCP + targetPort: 8080 + selector: + app: ph-ee-connector-crm + sessionAffinity: None + type: ClusterIP +{{- end }} \ No newline at end of file diff --git a/ph-ee-env-template/helm/ph-ee-engine/connector-crm/templates/serviceaccount.yaml b/ph-ee-env-template/helm/ph-ee-engine/connector-crm/templates/serviceaccount.yaml new file mode 100644 index 000000000..a38d3ce7f --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/connector-crm/templates/serviceaccount.yaml @@ -0,0 +1,15 @@ +{{- if .Values.managedServiceAccount }} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: "ph-ee-connector-crm" + annotations: + {{- with .Values.serviceAccountAnnotations }} + {{- toYaml . | nindent 4 }} + {{- end }} + labels: + app: "ph-ee-connector-crm" + chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" + heritage: {{ .Release.Service | quote }} + release: {{ .Release.Name | quote }} +{{- end -}} \ No newline at end of file diff --git a/ph-ee-env-template/helm/ph-ee-engine/connector-crm/values.yaml b/ph-ee-env-template/helm/ph-ee-engine/connector-crm/values.yaml new file mode 100644 index 000000000..0cf89d3db --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/connector-crm/values.yaml @@ -0,0 +1,45 @@ +service: + apiversion: "v1" + annotations: {} + +secret: + apiversion: "v1" + +configmap: + apiversion: "v1" + +enabled: true +image: "" +imageTag: latest +imagePullPolicy: "Always" +SPRING_PROFILES_ACTIVE: "bb,tenants" +LOGGING_LEVEL_ROOT: "INFO" +DFSPIDS: "" +limits: + cpu: "500m" + memory: "512M" +requests: + cpu: "100m" + memory: "256M" + initialDelaySeconds: 20 + periodSeconds: 30 +# Enabling this will publicly expose your channel instance. +# Only enable this if you have security enabled on your cluster +ingress: + enabled: true + annotations: {} + # kubernetes.io/ingress.class: "nginx" + pathtype: Prefix + hosts: + - host: "" + paths: + - path: / + tls: [] + # - secretName: sandbox-secret + # hosts: + # - chart-example.local + +deployment: + apiVersion: "apps/v1" + annotations: + deployTime: "{{ .Values.deployTime }}" diff --git a/ph-ee-env-template/helm/ph-ee-engine/connector-gsma/Chart.yaml b/ph-ee-env-template/helm/ph-ee-engine/connector-gsma/Chart.yaml new file mode 100644 index 000000000..eb9a6447b --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/connector-gsma/Chart.yaml @@ -0,0 +1,5 @@ +apiVersion: v1 +description: ph-ee-connector-gsma +name: ph_ee_connector_gsma +version: 1.0.0 +appVersion: "1.0.0" \ No newline at end of file diff --git a/ph-ee-env-template/helm/ph-ee-engine/connector-gsma/README.md b/ph-ee-env-template/helm/ph-ee-engine/connector-gsma/README.md new file mode 100644 index 000000000..89b95e154 --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/connector-gsma/README.md @@ -0,0 +1,29 @@ +# ph_ee_connector_gsma + +![Version: 1.0.0](https://img.shields.io/badge/Version-1.0.0-informational?style=flat-square) ![AppVersion: 1.0.0](https://img.shields.io/badge/AppVersion-1.0.0-informational?style=flat-square) + +ph-ee-connector-gsma + +## Values + +| Key | Type | Default | Description | +|-----|------|---------|-------------| +| SPRING_PROFILES_ACTIVE | string | `"bb"` | | +| api.channel | string | `"http://ph-ee-connector-channel"` | | +| configmap.apiversion | string | `"v1"` | | +| deployment.annotations.deployTime | string | `"{{ .Values.deployTime }}"` | | +| deployment.apiVersion | string | `"apps/v1"` | | +| enabled | bool | `true` | | +| image | string | `""` | | +| imageTag | string | `"latest"` | | +| ingress.apiversion | string | `"networking.k8s.io/v1"` | | +| limits.cpu | string | `"500m"` | | +| limits.memory | string | `"512M"` | | +| replicas | int | `1` | | +| requests.cpu | string | `"100m"` | | +| requests.memory | string | `"256M"` | | +| secret.apiversion | string | `"v1"` | | +| service.apiversion | string | `"v1"` | | + +---------------------------------------------- +Autogenerated from chart metadata using [helm-docs v1.11.0](https://github.com/norwoodj/helm-docs/releases/v1.11.0) diff --git a/ph-ee-env-template/helm/ph-ee-engine/connector-gsma/templates/clusterrole.yaml b/ph-ee-env-template/helm/ph-ee-engine/connector-gsma/templates/clusterrole.yaml new file mode 100644 index 000000000..ba1d3f023 --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/connector-gsma/templates/clusterrole.yaml @@ -0,0 +1,11 @@ +{{- if .Values.managedServiceAccount }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + # "namespace" omitted since ClusterRoles are not namespaced + name: ph-ee-connector-gsma-c-role +rules: +- apiGroups: [""] + resources: ["secrets"] + verbs: ["get", "watch", "list"] +{{- end -}} \ No newline at end of file diff --git a/ph-ee-env-template/helm/ph-ee-engine/connector-gsma/templates/clusterrolebinding.yaml b/ph-ee-env-template/helm/ph-ee-engine/connector-gsma/templates/clusterrolebinding.yaml new file mode 100644 index 000000000..39120f641 --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/connector-gsma/templates/clusterrolebinding.yaml @@ -0,0 +1,15 @@ +{{- if .Values.managedServiceAccount }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: ph-ee-connector-gsma-c-role-binding +subjects: +- kind: ServiceAccount + name: ph-ee-connector-gsma # name of your service account + namespace: {{ .Release.Namespace }} # this is the namespace your service account is in +roleRef: # referring to your ClusterRole + kind: ClusterRole + name: ph-ee-connector-gsma-c-role + apiGroup: rbac.authorization.k8s.io + +{{- end -}} \ No newline at end of file diff --git a/ph-ee-env-template/helm/ph-ee-engine/connector-gsma/templates/deployment.yaml b/ph-ee-env-template/helm/ph-ee-engine/connector-gsma/templates/deployment.yaml new file mode 100644 index 000000000..77d3faf1f --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/connector-gsma/templates/deployment.yaml @@ -0,0 +1,58 @@ +{{- if .Values.enabled -}} + +apiVersion: apps/v1 +kind: Deployment +metadata: + name: "ph-ee-connector-gsma" + labels: + app: "ph-ee-connector-gsma" +spec: + replicas: {{ .Values.replicas }} + selector: + matchLabels: + app: "ph-ee-connector-gsma" + template: + metadata: + labels: + app: "ph-ee-connector-gsma" + annotations: +{{- if .Values.deployment.annotations }} +{{ toYaml .Values.deployment.annotations | indent 8 }} +{{- end }} + spec: + initContainers: + #During this Pod's initialization, check that zeebe-gateway service is up and running before starting this pod + - name: check-zeebe-gateway-ready + image: busybox:latest + command: [ 'sh', '-c','until nc -vz {{ .Release.Name }}-zeebe-gateway 26500; do echo "Waiting for zeebe-gateway service"; sleep 2; done;' ] + containers: + - name: "ph-ee-connector-gsma-mm" + image: "{{ .Values.image }}" + imagePullPolicy: "{{ .Values.global.imagePullPolicy }}" + ports: + - containerPort: 5000 + resources: + limits: + memory: "{{ .Values.limits.memory }}" + cpu: "{{ .Values.limits.cpu }}" + requests: + memory: "{{ .Values.requests.memory }}" + cpu: "{{ .Values.requests.cpu }}" + env: + - name: "SPRING_PROFILES_ACTIVE" + value: "{{ .Values.global.SPRING_PROFILES_ACTIVE }}" + - name: "ZEEBE_BROKER_CONTACTPOINT" + value: "{{ .Release.Name }}-zeebe-gateway:26500" +{{- if .Values.extraEnvs | default .Values.deployment.extraEnvs }} +{{ toYaml ( .Values.extraEnvs | default .Values.deployment.extraEnvs ) | indent 10 }} +{{- end }} + envFrom: {{ toYaml ( .Values.envFrom | default .Values.deployment.envFrom ) | nindent 12 }} + securityContext: {{ toYaml ( .Values.podSecurityContext | default .Values.deployment.securityContext ) | nindent 12 }} + volumeMounts: + - name: ph-ee-config + mountPath: "/config" + volumes: + - name: ph-ee-config + configMap: + name: ph-ee-config +{{- end }} diff --git a/ph-ee-env-template/helm/ph-ee-engine/connector-gsma/templates/role.yaml b/ph-ee-env-template/helm/ph-ee-engine/connector-gsma/templates/role.yaml new file mode 100644 index 000000000..d130ce0b3 --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/connector-gsma/templates/role.yaml @@ -0,0 +1,14 @@ +{{- if .Values.managedServiceAccount }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: ph-ee-connector-gsma-role + namespace: {{ .Release.Namespace }} +rules: +- apiGroups: + - "" + resources: + - pods + - configmaps + verbs: ["get", "create", "update"] +{{- end -}} \ No newline at end of file diff --git a/ph-ee-env-template/helm/ph-ee-engine/connector-gsma/templates/rolebinding.yaml b/ph-ee-env-template/helm/ph-ee-engine/connector-gsma/templates/rolebinding.yaml new file mode 100644 index 000000000..f8eb1c4b1 --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/connector-gsma/templates/rolebinding.yaml @@ -0,0 +1,15 @@ +{{- if .Values.managedServiceAccount }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: ph-ee-connector-gsma-role-binding + namespace: {{ .Release.Namespace }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: ph-ee-connector-gsma-role +subjects: +- kind: ServiceAccount + name: ph-ee-connector-gsma + namespace: {{ .Release.Namespace }} +{{- end -}} \ No newline at end of file diff --git a/ph-ee-env-template/helm/ph-ee-engine/connector-gsma/templates/service.yaml b/ph-ee-env-template/helm/ph-ee-engine/connector-gsma/templates/service.yaml new file mode 100644 index 000000000..f0d634cb7 --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/connector-gsma/templates/service.yaml @@ -0,0 +1,22 @@ +{{- if .Values.enabled -}} +apiVersion: {{ .Values.service.apiversion }} +kind: Service +metadata: + labels: + app: ph-ee-connector-gsma + name: ph-ee-connector-gsma +spec: + ports: + - name: port + port: 80 + protocol: TCP + targetPort: 5000 + - name: actuator + protocol: TCP + port: 8080 # Port where Actuator endpoints are exposed + targetPort: 8080 + selector: + app: ph-ee-connector-gsma + sessionAffinity: None + type: ClusterIP +{{- end }} diff --git a/ph-ee-env-template/helm/ph-ee-engine/connector-gsma/templates/serviceaccount.yaml b/ph-ee-env-template/helm/ph-ee-engine/connector-gsma/templates/serviceaccount.yaml new file mode 100644 index 000000000..fc1ae874a --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/connector-gsma/templates/serviceaccount.yaml @@ -0,0 +1,15 @@ +{{- if .Values.managedServiceAccount }} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: ph-ee-connector-gsma + annotations: + {{- with .Values.serviceAccountAnnotations }} + {{- toYaml . | nindent 4 }} + {{- end }} + labels: + app: ph-ee-connector-gsma + chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" + heritage: {{ .Release.Service | quote }} + release: {{ .Release.Name | quote }} +{{- end -}} \ No newline at end of file diff --git a/ph-ee-env-template/helm/ph-ee-engine/connector-gsma/values.yaml b/ph-ee-env-template/helm/ph-ee-engine/connector-gsma/values.yaml new file mode 100644 index 000000000..eaa54656b --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/connector-gsma/values.yaml @@ -0,0 +1,29 @@ +ingress: + apiversion: networking.k8s.io/v1 + +service: + apiversion: "v1" + +secret: + apiversion: "v1" + +configmap: + apiversion: "v1" + +enabled: true +replicas: 1 +image: "" +imageTag: latest +SPRING_PROFILES_ACTIVE: "bb" +api: + channel: "http://ph-ee-connector-channel" +limits: + cpu: "500m" + memory: "512M" +requests: + cpu: "100m" + memory: "256M" +deployment: + apiVersion: "apps/v1" + annotations: + deployTime: "{{ .Values.deployTime }}" \ No newline at end of file diff --git a/ph-ee-env-template/helm/ph-ee-engine/connector-mock-payment-schema/Chart.yaml b/ph-ee-env-template/helm/ph-ee-engine/connector-mock-payment-schema/Chart.yaml new file mode 100644 index 000000000..fcc6842b5 --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/connector-mock-payment-schema/Chart.yaml @@ -0,0 +1,5 @@ +apiVersion: v1 +description: ph-ee-connector-mock-payment-schema +name: mockpayment +version: 1.0.0 +appVersion: "1.0.0" diff --git a/ph-ee-env-template/helm/ph-ee-engine/connector-mock-payment-schema/templates/deployment.yaml b/ph-ee-env-template/helm/ph-ee-engine/connector-mock-payment-schema/templates/deployment.yaml new file mode 100644 index 000000000..80ae08c51 --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/connector-mock-payment-schema/templates/deployment.yaml @@ -0,0 +1,82 @@ +{{- if .Values.enabled -}} + +apiVersion: apps/v1 +kind: Deployment +metadata: + name: "ph-ee-connector-mock-payment-schema" + labels: + app: ph-ee-connector-mock-payment-schema +spec: + replicas: {{ .Values.replicas }} + selector: + matchLabels: + app: ph-ee-connector-mock-payment-schema + template: + metadata: + labels: + app: ph-ee-connector-mock-payment-schema + annotations: +{{- if .Values.deployment.annotations }} +{{ toYaml .Values.deployment.annotations | indent 8 }} +{{- end }} + spec: + initContainers: + #During this Pod's initialization, check that zeebe-gateway service is up and running before starting this pod + - name: check-zeebe-gateway-ready + image: busybox:latest + command: [ 'sh', '-c','until nc -vz {{ .Release.Name }}-zeebe-gateway 26500; do echo "Waiting for zeebe-gateway service"; sleep 2; done;' ] + terminationGracePeriodSeconds: {{ .Values.terminationGracePeriod }} + containers: + - name: ph-ee-connector-mock-payment-schema + image: "{{ .Values.image }}" + ports: + - containerPort: 8080 + imagePullPolicy: "{{ .Values.global.imagePullPolicy }}" + resources: + limits: + memory: "{{ .Values.limits.memory }}" + cpu: "{{ .Values.limits.cpu }}" + requests: + memory: "{{ .Values.requests.memory }}" + cpu: "{{ .Values.requests.cpu }}" + livenessProbe: + httpGet: + path: /actuator/health/liveness + port: 8080 + initialDelaySeconds: {{.Values.livenessProbe.initialDelaySeconds}} + periodSeconds: {{.Values.livenessProbe.periodSeconds}} + readinessProbe: + httpGet: + path: /actuator/health/readiness + port: 8080 + initialDelaySeconds: {{.Values.readinessProbe.initialDelaySeconds}} + periodSeconds: {{.Values.readinessProbe.periodSeconds}} + env: + - name: "SPRING_PROFILES_ACTIVE" + value: "{{ .Values.global.SPRING_PROFILES_ACTIVE }}" + - name: "DFSPIDS" + value: "{{ .Values.global.DFSPIDS }}" + - name: "LOGGING_LEVEL_ROOT" + value: "{{ .Values.global.LOGGING_LEVEL_ROOT }}" + - name: "ZEEBE_BROKER_CONTACTPOINT" + value: "{{ .Release.Name }}-zeebe-gateway:26500" + - name: "ZEEBE_CLIENT_MAX-EXECUTION-THREADS" + value: "{{ .Values.global.max_execution_threads}}" + - name: "ZEEBE_CLIENT_POLL-INTERVAL" + value: "{{ .Values.global.poll_interval}}" + - name : "mockFailure_percentage" + value: "{{ .Values.mockFailure.percentage }}" +{{- if .Values.extraEnvs | default .Values.deployment.extraEnvs }} +{{ toYaml ( .Values.extraEnvs | default .Values.deployment.extraEnvs ) | indent 12 }} +{{- end }} + envFrom: {{ toYaml ( .Values.envFrom | default .Values.deployment.envFrom ) | nindent 12 }} + securityContext: {{ toYaml ( .Values.podSecurityContext | default .Values.deployment.securityContext ) | nindent 12 }} + volumeMounts: + - name: ph-ee-config + mountPath: "/config" + volumes: + - name: ph-ee-config + configMap: + name: ph-ee-config +{{- end }} + diff --git a/ph-ee-env-template/helm/ph-ee-engine/connector-mock-payment-schema/templates/ingress.yaml b/ph-ee-env-template/helm/ph-ee-engine/connector-mock-payment-schema/templates/ingress.yaml new file mode 100644 index 000000000..07b6b8885 --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/connector-mock-payment-schema/templates/ingress.yaml @@ -0,0 +1,50 @@ +{{- if .Values.ingress.enabled -}} +{{- $pathtype := .Values.ingress.pathtype -}} +{{- $ingressPath := .Values.ingress.path -}} +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: "ph-ee-connector-mock-payment-schema" + labels: + app: {{ .Chart.Name }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +{{- with .Values.ingress.annotations }} + annotations: +{{ toYaml . | indent 4 }} +{{- end }} +spec: + {{- if .Values.ingress.className }} + ingressClassName: {{ .Values.ingress.className | quote }} + {{- end }} +{{- if .Values.ingress.tls }} + tls: + {{- if .ingressPath }} + {{- range .Values.ingress.tls }} + - hosts: + {{- range .hosts }} + - {{ . }} + {{- end }} + secretName: {{ .secretName }} + {{- end }} +{{- else }} +{{ toYaml .Values.ingress.tls | indent 4 }} + {{- end }} +{{- end}} + rules: + {{- range .Values.ingress.hosts }} + - host: {{ .host }} + http: + paths: + {{- range .paths }} + - path: {{ .path }} + pathType: {{ $pathtype }} + backend: + service: + name: {{ .backend.service.name}} + port: + number: {{ .backend.service.port.number}} + {{- end }} + {{- end }} + {{- end }} + \ No newline at end of file diff --git a/ph-ee-env-template/helm/ph-ee-engine/connector-mock-payment-schema/templates/service.yaml b/ph-ee-env-template/helm/ph-ee-engine/connector-mock-payment-schema/templates/service.yaml new file mode 100644 index 000000000..fed4e9354 --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/connector-mock-payment-schema/templates/service.yaml @@ -0,0 +1,18 @@ +{{- if .Values.enabled -}} +apiVersion: {{ .Values.service.apiversion }} +kind: Service +metadata: + labels: + app: ph-ee-connector-mock-payment-schema + name: ph-ee-connector-mock-payment-schema +spec: + ports: + - name: port + port: 8080 + protocol: TCP + targetPort: 8080 + selector: + app: ph-ee-connector-mock-payment-schema + sessionAffinity: None + type: LoadBalancer +{{- end }} diff --git a/ph-ee-env-template/helm/ph-ee-engine/connector-mock-payment-schema/templates/serviceaccount.yaml b/ph-ee-env-template/helm/ph-ee-engine/connector-mock-payment-schema/templates/serviceaccount.yaml new file mode 100644 index 000000000..0e29a924c --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/connector-mock-payment-schema/templates/serviceaccount.yaml @@ -0,0 +1,15 @@ +{{- if .Values.managedServiceAccount }} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: "ph-ee-connector-mock-payment-schema" + annotations: + {{- with .Values.serviceAccountAnnotations }} + {{- toYaml . | nindent 4 }} + {{- end }} + labels: + app: "ph-ee-connector-mock-payment-schema" + chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" + heritage: {{ .Release.Service | quote }} + release: {{ .Release.Name | quote }} +{{- end }} \ No newline at end of file diff --git a/ph-ee-env-template/helm/ph-ee-engine/connector-mock-payment-schema/values.yaml b/ph-ee-env-template/helm/ph-ee-engine/connector-mock-payment-schema/values.yaml new file mode 100644 index 000000000..874e99be5 --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/connector-mock-payment-schema/values.yaml @@ -0,0 +1,46 @@ +service: + apiversion: "v1" + +secret: + apiversion: "v1" + +configmap: + apiversion: "v1" + + +enabled: false +replicas: 1 +image: "" +imagePullPolicy: "Always" +SPRING_PROFILES_ACTIVE: "" +LOGGING_LEVEL_ROOT: "INFO" +DFSPIDS: "" +mockFailure: + percentage: "0" +limits: + memory: "384M" + cpu: "500m" +requests: + memory: "256M" + cpu: "100m" +deployment: + annotations: { } +ingress: + enabled: true + annotations: { } + # kubernetes.io/ingress.class: "nginx" + pathtype: ImplementationSpecific + hosts: + - host: "" + paths: + - path: / + tls: [ ] + # - secretName: sandbox-secret + # hosts: + # - chart-example.local +livenessProbe: + initialDelaySeconds: 20 + periodSeconds: 30 +readinessProbe: + initialDelaySeconds: 20 + periodSeconds: 30 diff --git a/ph-ee-env-template/helm/ph-ee-engine/connector-mojaloop/Chart.yaml b/ph-ee-env-template/helm/ph-ee-engine/connector-mojaloop/Chart.yaml new file mode 100644 index 000000000..2a8e423bd --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/connector-mojaloop/Chart.yaml @@ -0,0 +1,5 @@ +apiVersion: v1 +description: ph_ee_connector_mojaloop +name: ph_ee_connector_mojaloop +version: 1.0.0 +appVersion: "1.0.0" \ No newline at end of file diff --git a/ph-ee-env-template/helm/ph-ee-engine/connector-mojaloop/README.md b/ph-ee-env-template/helm/ph-ee-engine/connector-mojaloop/README.md new file mode 100644 index 000000000..fae7545f1 --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/connector-mojaloop/README.md @@ -0,0 +1,47 @@ +# ph_ee_connector_mojaloop + +![Version: 1.0.0](https://img.shields.io/badge/Version-1.0.0-informational?style=flat-square) ![AppVersion: 1.0.0](https://img.shields.io/badge/AppVersion-1.0.0-informational?style=flat-square) + +ph_ee_connector_mojaloop + +## Values + +| Key | Type | Default | Description | +|-----|------|---------|-------------| +| DFSPIDS | string | `"gorilla,rhino"` | | +| SPRING_PROFILES_ACTIVE | string | `""` | | +| configmap.apiversion | string | `"v1"` | | +| deployment.annotations.deployTime | string | `"{{ .Values.deployTime }}"` | | +| deployment.apiVersion | string | `"apps/v1"` | | +| enabled | bool | `true` | | +| hostname | string | `"mojaloop.sandbox.mifos.io"` | | +| image | string | `""` | | +| imageTag | string | `"latest"` | | +| ingress.annotations."kubernetes.io/ingress.class" | string | `"nginx"` | | +| ingress.apiversion | string | `"networking.k8s.io/v1"` | | +| ingress.backend.service.name | string | `"ph-ee-connector-mojaloop-java"` | | +| ingress.backend.service.port.number | int | `80` | | +| ingress.className | string | `"nginx"` | | +| ingress.enabled | bool | `true` | | +| ingress.path | string | `"/"` | | +| ingress.tls[0].hosts | string | `"mojaloop.sandbox.mifos.io"` | | +| ingress.tls[1].secretName | string | `"sandbox-secret"` | | +| limits.cpu | string | `"500m"` | | +| limits.memory | string | `"512M"` | | +| requests.cpu | string | `"100m"` | | +| requests.memory | string | `"256M"` | | +| secret.apiversion | string | `"v1"` | | +| service.apiversion | string | `"v1"` | | +| switch.als.host | string | `"http://account-lookup-service.sandbox.mifos.io"` | | +| switch.als.service | string | `"account-lookup-service.local"` | | +| switch.oracle.host | string | `"http://moja-simulator.sandbox.mifos.io"` | | +| switch.quotes.host | string | `"http://quoting-service.sandbox.mifos.io"` | | +| switch.quotes.service | string | `"quoting-service.sandbox.mifos.io"` | | +| switch.transactions.host | string | `"http://ml-api-adapter.sandbox.mifos.io"` | | +| switch.transactions.service | string | `"ml-api-adapter.sandbox.mifos.io"` | | +| switch.transfers.host | string | `"http://api-adapter.sandbox.mifos.io"` | | +| switch.transfers.service | string | `"api-adapter.sandbox.mifos.io"` | | +| wildcardhostname | string | `"mojaloop.sandbox.mifos.io"` | | + +---------------------------------------------- +Autogenerated from chart metadata using [helm-docs v1.11.0](https://github.com/norwoodj/helm-docs/releases/v1.11.0) diff --git a/ph-ee-env-template/helm/ph-ee-engine/connector-mojaloop/templates/clusterrole.yaml b/ph-ee-env-template/helm/ph-ee-engine/connector-mojaloop/templates/clusterrole.yaml new file mode 100644 index 000000000..18abf3285 --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/connector-mojaloop/templates/clusterrole.yaml @@ -0,0 +1,11 @@ +{{- if .Values.managedServiceAccount }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + # "namespace" omitted since ClusterRoles are not namespaced + name: ph-ee-connector-mojaloop-java-c-role +rules: +- apiGroups: [""] + resources: ["secrets"] + verbs: ["get", "watch", "list"] +{{- end -}} \ No newline at end of file diff --git a/ph-ee-env-template/helm/ph-ee-engine/connector-mojaloop/templates/clusterrolebinding.yaml b/ph-ee-env-template/helm/ph-ee-engine/connector-mojaloop/templates/clusterrolebinding.yaml new file mode 100644 index 000000000..97206a19b --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/connector-mojaloop/templates/clusterrolebinding.yaml @@ -0,0 +1,15 @@ +{{- if .Values.managedServiceAccount }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: ph-ee-connector-mojaloop-java-c-role-binding +subjects: +- kind: ServiceAccount + name: ph-ee-connector-mojaloop-java # name of your service account + namespace: {{ .Release.Namespace }} # this is the namespace your service account is in +roleRef: # referring to your ClusterRole + kind: ClusterRole + name: ph-ee-connector-mojaloop-java-c-role + apiGroup: rbac.authorization.k8s.io + +{{- end -}} \ No newline at end of file diff --git a/ph-ee-env-template/helm/ph-ee-engine/connector-mojaloop/templates/deployment.yaml b/ph-ee-env-template/helm/ph-ee-engine/connector-mojaloop/templates/deployment.yaml new file mode 100644 index 000000000..25b59db12 --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/connector-mojaloop/templates/deployment.yaml @@ -0,0 +1,96 @@ +{{- if .Values.enabled -}} + +apiVersion: apps/v1 +kind: Deployment +metadata: + name: ph-ee-connector-mojaloop-java + labels: + app: ph-ee-connector-mojaloop-java +spec: + replicas: {{ .Values.replicas }} + selector: + matchLabels: + app: ph-ee-connector-mojaloop-java + template: + metadata: + labels: + app: ph-ee-connector-mojaloop-java + annotations: +{{- if .Values.deployment.annotations }} +{{ toYaml .Values.deployment.annotations | indent 8 }} +{{- end }} + spec: + initContainers: + #During this Pod's initialization, check that zeebe-gateway service is up and running before starting this pod + - name: check-zeebe-gateway-ready + image: busybox:latest + command: [ 'sh', '-c','until nc -vz {{ .Release.Name }}-zeebe-gateway 26500; do echo "Waiting for zeebe-gateway service"; sleep 2; done;' ] + containers: + - name: ph-ee-connector-mojaloop-java + image: "{{ .Values.image }}" + imagePullPolicy: "{{ .Values.global.imagePullPolicy }}" + ports: + - containerPort: 5000 + resources: + limits: + memory: "{{ .Values.limits.memory }}" + cpu: "{{ .Values.limits.cpu }}" + requests: + memory: "{{ .Values.requests.memory }}" + cpu: "{{ .Values.requests.cpu }}" + env: + - name: "SPRING_PROFILES_ACTIVE" + value: "{{ .Values.global.SPRING_PROFILES_ACTIVE }}" + + - name: "DFSPIDS" + value: "{{ .Values.global.DFSPIDS }}" + + - name: "SWITCH_quotes-host" + value: "{{ .Values.switch.quotes.host }}" + + - name: "SWITCH_quote-service" + value: "{{ .Values.switch.quotes.service }}" + + - name: "SWITCH_als-host" + value: "{{ .Values.switch.als.host }}" + + - name: "SWITCH_account-lookup-service" + value: "{{ .Values.switch.als.service }}" + + - name: "SWITCH_transfers-host" + value: "{{ .Values.switch.transfers.host }}" + + - name: "SWITCH_transfers-service" + value: "{{ .Values.switch.transfers.service }}" + + - name: "SWITCH_transactions-host" + value: "{{ .Values.switch.transactions.host }}" + + - name: "SWITCH_transaction-request-service" + value: "{{ .Values.switch.transactions.service }}" + + - name: "SWITCH_oracle-host" + value: "{{ .Values.switch.oracle.host }}" + + - name: "ZEEBE_BROKER_CONTACTPOINT" + value: "{{ .Release.Name }}-zeebe-gateway:26500" + + - name: "ZEEBE_CLIENT_MAX-EXECUTION-THREADS" + value: "{{ .Values.global.max_execution_threads}}" + + - name: "ZEEBE_CLIENT_POLL-INTERVAL" + value: "{{ .Values.global.poll_interval}}" +{{- if .Values.extraEnvs | default .Values.deployment.extraEnvs }} +{{ toYaml ( .Values.extraEnvs | default .Values.deployment.extraEnvs ) | indent 12 }} +{{- end }} + envFrom: {{ toYaml ( .Values.envFrom | default .Values.deployment.envFrom ) | nindent 12 }} + securityContext: {{ toYaml ( .Values.podSecurityContext | default .Values.deployment.securityContext ) | nindent 12 }} + + volumeMounts: + - name: ph-ee-config + mountPath: "/config" + volumes: + - name: ph-ee-config + configMap: + name: ph-ee-config +{{- end }} diff --git a/ph-ee-env-template/helm/ph-ee-engine/connector-mojaloop/templates/ingress.yaml b/ph-ee-env-template/helm/ph-ee-engine/connector-mojaloop/templates/ingress.yaml new file mode 100644 index 000000000..8cdd06d7a --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/connector-mojaloop/templates/ingress.yaml @@ -0,0 +1,56 @@ +{{- if .Values.ingress.enabled -}} +{{- $pathtype := .Values.ingress.pathtype -}} +{{- $ingressPath := .Values.ingress.path -}} +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: ph-ee-connector-mojaloop-java + labels: + app: {{ .Chart.Name }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +{{- with .Values.ingress.annotations }} + annotations: +{{ toYaml . | indent 4 }} +{{- end }} +spec: + {{- if .Values.ingress.className }} + ingressClassName: {{ .Values.ingress.className | quote }} + {{- end }} +{{- if .Values.ingress.tls }} + tls: + {{- if .ingressPath }} + {{- range .Values.ingress.tls }} + - hosts: + {{- range .hosts }} + - {{ . }} + {{- end }} + secretName: {{ .secretName }} + {{- end }} +{{- else }} +{{ toYaml .Values.ingress.tls | indent 4 }} + {{- end }} +{{- end}} + rules: + {{- range .Values.ingress.hosts }} + - host: {{ .host }} + http: + paths: + {{- range .paths }} + - path: {{ .path }} + pathType: {{ $pathtype }} + backend: + service: + name: {{ .backend.service.name}} + port: + number: {{ .backend.service.port.number}} + {{- end }} + - path: /actuator + pathType: Prefix + backend: + service: + name: ph-ee-connector-mojaloop-java + port: + number: 8080 + {{- end }} + {{- end }} diff --git a/ph-ee-env-template/helm/ph-ee-engine/connector-mojaloop/templates/role.yaml b/ph-ee-env-template/helm/ph-ee-engine/connector-mojaloop/templates/role.yaml new file mode 100644 index 000000000..709a39ac5 --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/connector-mojaloop/templates/role.yaml @@ -0,0 +1,14 @@ +{{- if .Values.managedServiceAccount }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: ph-ee-connector-mojaloop-java-role + namespace: {{ .Release.Namespace }} +rules: +- apiGroups: + - "" + resources: + - pods + - configmaps + verbs: ["get", "create", "update"] +{{- end -}} \ No newline at end of file diff --git a/ph-ee-env-template/helm/ph-ee-engine/connector-mojaloop/templates/rolebinding.yaml b/ph-ee-env-template/helm/ph-ee-engine/connector-mojaloop/templates/rolebinding.yaml new file mode 100644 index 000000000..a2f3fa693 --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/connector-mojaloop/templates/rolebinding.yaml @@ -0,0 +1,15 @@ +{{- if .Values.managedServiceAccount }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: ph-ee-connector-mojaloop-java-role-binding + namespace: {{ .Release.Namespace }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: ph-ee-connector-mojaloop-java-role +subjects: +- kind: ServiceAccount + name: ph-ee-connector-mojaloop-java + namespace: {{ .Release.Namespace }} +{{- end -}} \ No newline at end of file diff --git a/ph-ee-env-template/helm/ph-ee-engine/connector-mojaloop/templates/service.yaml b/ph-ee-env-template/helm/ph-ee-engine/connector-mojaloop/templates/service.yaml new file mode 100644 index 000000000..6c010223d --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/connector-mojaloop/templates/service.yaml @@ -0,0 +1,22 @@ +{{- if .Values.enabled -}} +apiVersion: {{ .Values.service.apiversion }} +kind: Service +metadata: + labels: + app: ph-ee-connector-mojaloop-java + name: ph-ee-connector-mojaloop-java +spec: + ports: + - name: port + port: 80 + protocol: TCP + targetPort: 5000 + - name: actuator + protocol: TCP + port: 8080 # Port where Actuator endpoints are exposed + targetPort: 8080 + selector: + app: ph-ee-connector-mojaloop-java + sessionAffinity: None + type: ClusterIP +{{- end }} diff --git a/ph-ee-env-template/helm/ph-ee-engine/connector-mojaloop/templates/serviceaccount.yaml b/ph-ee-env-template/helm/ph-ee-engine/connector-mojaloop/templates/serviceaccount.yaml new file mode 100644 index 000000000..bf833b49e --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/connector-mojaloop/templates/serviceaccount.yaml @@ -0,0 +1,15 @@ +{{- if .Values.managedServiceAccount }} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: "ph-ee-connector-mojaloop-java" + annotations: + {{- with .Values.serviceAccountAnnotations }} + {{- toYaml . | nindent 4 }} + {{- end }} + labels: + app: "ph-ee-connector-mojaloop-java" + chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" + heritage: {{ .Release.Service | quote }} + release: {{ .Release.Name | quote }} +{{- end -}} \ No newline at end of file diff --git a/ph-ee-env-template/helm/ph-ee-engine/connector-mojaloop/values.yaml b/ph-ee-env-template/helm/ph-ee-engine/connector-mojaloop/values.yaml new file mode 100644 index 000000000..42af49fb7 --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/connector-mojaloop/values.yaml @@ -0,0 +1,55 @@ +service: + apiversion: "v1" + +secret: + apiversion: "v1" + +configmap: + apiversion: "v1" + +enabled: true +image: "" +imageTag: "latest" +SPRING_PROFILES_ACTIVE: "" +DFSPIDS: "gorilla,rhino" +switch: + quotes: + host: "http://quoting-service.sandbox.mifos.io" + service: "quoting-service.sandbox.mifos.io" + als: + host: "http://account-lookup-service.sandbox.mifos.io" + service: "account-lookup-service.local" + transfers: + host: "http://api-adapter.sandbox.mifos.io" + service: "api-adapter.sandbox.mifos.io" + transactions: + host: "http://ml-api-adapter.sandbox.mifos.io" + service: "ml-api-adapter.sandbox.mifos.io" + oracle: + host: "http://moja-simulator.sandbox.mifos.io" +limits: + cpu: "500m" + memory: "384M" +requests: + cpu: "100m" + memory: "256M" +# Enabling this will publicly expose your Elasticsearch instance. +# Only enable this if you have security enabled on your cluster +ingress: + enabled: false + annotations: {} + # kubernetes.io/ingress.class: "nginx" + pathtype: ImplementationSpecific + hosts: + - host: "" + paths: + - path: / + tls: [] + # - secretName: sandbox-secret + # hosts: + # - chart-example.local + +deployment: + apiVersion: "apps/v1" + annotations: + deployTime: "{{ .Values.deployTime }}" \ No newline at end of file diff --git a/ph-ee-env-template/helm/ph-ee-engine/connector-mpesa/Chart.yaml b/ph-ee-env-template/helm/ph-ee-engine/connector-mpesa/Chart.yaml new file mode 100644 index 000000000..314823c73 --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/connector-mpesa/Chart.yaml @@ -0,0 +1,5 @@ +apiVersion: v1 +description: ph-ee-connector-mpesa +name: mpesa +version: 1.0.0 +appVersion: "1.0.0" \ No newline at end of file diff --git a/ph-ee-env-template/helm/ph-ee-engine/connector-mpesa/README.md b/ph-ee-env-template/helm/ph-ee-engine/connector-mpesa/README.md new file mode 100644 index 000000000..a38a495ec --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/connector-mpesa/README.md @@ -0,0 +1,69 @@ +# mpesa + +![Version: 1.0.0](https://img.shields.io/badge/Version-1.0.0-informational?style=flat-square) ![AppVersion: 1.0.0](https://img.shields.io/badge/AppVersion-1.0.0-informational?style=flat-square) + +ph-ee-connector-mpesa + +## Values + +| Key | Type | Default | Description | +|-----|------|---------|-------------| +| LOGGING_LEVEL_ROOT | string | `"INFO"` | | +| SPRING_PROFILES_ACTIVE | string | `""` | | +| accounts.paygops.api_host | string | `"https://sandbox.safaricom.co.ke"` | | +| accounts.paygops.auth_host | string | `"https://sandbox.safaricom.co.ke/oauth/v1/generate"` | | +| accounts.paygops.business_short_code | string | `""` | | +| accounts.paygops.client_key | string | `""` | | +| accounts.paygops.client_secret | string | `""` | | +| accounts.paygops.name | string | `"paygops"` | | +| accounts.paygops.pass_key | string | `""` | | +| accounts.paygops.till | string | `""` | | +| accounts.roster.api_host | string | `"https://sandbox.safaricom.co.ke"` | | +| accounts.roster.auth_host | string | `"https://sandbox.safaricom.co.ke/oauth/v1/generate"` | | +| accounts.roster.business_short_code | string | `""` | | +| accounts.roster.client_key | string | `""` | | +| accounts.roster.client_secret | string | `""` | | +| accounts.roster.name | string | `"roster"` | | +| accounts.roster.pass_key | string | `""` | | +| accounts.roster.till | string | `""` | | +| api_timeout | int | `60000` | | +| callback_host | string | `"https://mpesa.sandbox.mifos.io/"` | | +| channel.host | string | `"http://ph-ee-connector-channel"` | | +| configmap.apiversion | string | `"v1"` | | +| deployment.annotations.deployTime | string | `"{{ .Values.deployTime }}"` | | +| deployment.apiVersion | string | `"apps/v1"` | | +| enabled | bool | `true` | | +| hostname | string | `"mpesa.sandbox.mifos.io"` | | +| image | string | `""` | | +| imageTag | string | `"latest"` | | +| ingress.annotations."kubernetes.io/ingress.class" | string | `"nginx"` | | +| ingress.apiversion | string | `"networking.k8s.io/v1"` | | +| ingress.backend.service.name | string | `"ph-ee-connector-mpesa"` | | +| ingress.backend.service.port.number | int | `80` | | +| ingress.className | string | `"nginx"` | | +| ingress.enabled | bool | `true` | | +| ingress.path | string | `"/"` | | +| ingress.tls[0].hosts | string | `"mpesa.sandbox.mifos.io"` | | +| ingress.tls[1].secretName | string | `"sandbox-secret"` | | +| limits.cpu | string | `"500m"` | | +| limits.memory | string | `"512M"` | | +| paybill.accountHoldingInstitutionId | string | `"gorilla"` | | +| paybill.paygops.business_short_code | string | `""` | | +| paybill.paygops.currency | string | `"KES"` | | +| paybill.roster.business_short_code | string | `""` | | +| paybill.roster.currency | string | `"KES"` | | +| paygops.host | string | `"http://ph-ee-connector-ams-paygops"` | | +| requests.cpu | string | `"100m"` | | +| requests.memory | string | `"256M"` | | +| retry_count | int | `3` | | +| roster.host | string | `"http://ph-ee-connector-ams-roster"` | | +| secret.apiversion | string | `"v1"` | | +| service.apiversion | string | `"v1"` | | +| skip.enabled | bool | `false` | | +| tenant | string | `"lion"` | | +| wildcardhostname | string | `"mpesa.sandbox.mifos.io"` | | +| zeebe_broker_contactpoint | string | `"zeebe-zeebe-gateway:26500"` | | +| zeebe_init_transfer_wait_timer | int | `10` | | + +---------------------------------------------- +Autogenerated from chart metadata using [helm-docs v1.11.0](https://github.com/norwoodj/helm-docs/releases/v1.11.0) diff --git a/ph-ee-env-template/helm/ph-ee-engine/connector-mpesa/templates/clusterrole.yaml b/ph-ee-env-template/helm/ph-ee-engine/connector-mpesa/templates/clusterrole.yaml new file mode 100644 index 000000000..7e1e4e127 --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/connector-mpesa/templates/clusterrole.yaml @@ -0,0 +1,11 @@ +{{- if .Values.managedServiceAccount }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + # "namespace" omitted since ClusterRoles are not namespaced + name: ph-ee-connector-mpesa-c-role +rules: +- apiGroups: [""] + resources: ["secrets"] + verbs: ["get", "watch", "list"] +{{- end -}} \ No newline at end of file diff --git a/ph-ee-env-template/helm/ph-ee-engine/connector-mpesa/templates/clusterrolebinding.yaml b/ph-ee-env-template/helm/ph-ee-engine/connector-mpesa/templates/clusterrolebinding.yaml new file mode 100644 index 000000000..5bec3d9a2 --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/connector-mpesa/templates/clusterrolebinding.yaml @@ -0,0 +1,15 @@ +{{- if .Values.managedServiceAccount }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: ph-ee-connector-mpesa-c-role-binding +subjects: +- kind: ServiceAccount + name: ph-ee-connector-mpesa # name of your service account + namespace: {{ .Release.Namespace }} # this is the namespace your service account is in +roleRef: # referring to your ClusterRole + kind: ClusterRole + name: ph-ee-connector-mpesa-c-role + apiGroup: rbac.authorization.k8s.io + +{{- end -}} \ No newline at end of file diff --git a/ph-ee-env-template/helm/ph-ee-engine/connector-mpesa/templates/deployment.yaml b/ph-ee-env-template/helm/ph-ee-engine/connector-mpesa/templates/deployment.yaml new file mode 100644 index 000000000..c9e611b32 --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/connector-mpesa/templates/deployment.yaml @@ -0,0 +1,140 @@ +{{- if .Values.enabled -}} + +apiVersion: apps/v1 +kind: Deployment +metadata: + name: ph-ee-connector-mpesa + labels: + app: ph-ee-connector-mpesa +spec: + replicas: {{ .Values.replicas }} + selector: + matchLabels: + app: ph-ee-connector-mpesa + template: + metadata: + labels: + app: ph-ee-connector-mpesa + annotations: +{{- if .Values.deployment.annotations }} +{{ toYaml .Values.deployment.annotations | indent 8 }} +{{- end }} + spec: + initContainers: + #During this Pod's initialization, check that zeebe-gateway service is up and running before starting this pod + - name: check-zeebe-gateway-ready + image: busybox:latest + command: [ 'sh', '-c','until nc -vz {{ .Release.Name }}-zeebe-gateway 26500; do echo "Waiting for zeebe-gateway service"; sleep 2; done;' ] + containers: + - name: ph-ee-connector-mpesa + image: "{{ .Values.image }}" + ports: + - containerPort: 5000 + imagePullPolicy: "{{ .Values.imagePullPolicy }}" + livenessProbe: + httpGet: + path: /actuator/health/liveness + port: 8080 + initialDelaySeconds: {{.Values.livenessProbe.initialDelaySeconds}} + periodSeconds: {{.Values.livenessProbe.periodSeconds}} + readinessProbe: + httpGet: + path: /actuator/health/readiness + port: 8080 + initialDelaySeconds: {{.Values.readinessProbe.initialDelaySeconds}} + periodSeconds: {{.Values.readinessProbe.periodSeconds}} + resources: + limits: + memory: "{{ .Values.limits.memory }}" + cpu: "{{ .Values.limits.cpu }}" + requests: + memory: "{{ .Values.requests.memory }}" + cpu: "{{ .Values.requests.cpu }}" + env: + - name: "SPRING_PROFILES_ACTIVE" + value: "{{ .Values.global.SPRING_PROFILES_ACTIVE }}" + - name: "ZEEBE_BROKER_CONTACTPOINT" + value: "{{ .Release.Name }}-zeebe-gateway:26500" + - name: "ZEEBE_INIT-TRANSFER_WAIT-TIMER" + value: "{{ .Values.zeebe_init_transfer_wait_timer }}" + - name: "MPESA_LOCAL_HOST" + value: "{{ .Values.callback_host }}" + - name: "MPESA_API_TIMEOUT" + value: "{{ .Values.api_timeout }}" + - name: "MPESA_MAX-RETRY-COUNT" + value: "{{ .Values.retry_count }}" + - name: "TENANT" + value: "{{ .Values.tenant }}" + - name: "LOGGING_LEVEL_ROOT" + value: "{{ .Values.global.LOGGING_LEVEL_ROOT }}" + - name: "ACCOUNTS_ROSTER_SHORTCODE" + value: "{{ .Values.accounts.roster.business_short_code }}" + - name: "ACCOUNTS_ROSTER_TILL" + value: "{{ .Values.accounts.roster.till }}" + - name: "ACCOUNTS_ROSTER_AUTHHOST" + value: "{{ .Values.accounts.roster.auth_host }}" + - name: "ACCOUNTS_ROSTER_APIHOST" + value: "{{ .Values.accounts.roster.api_host }}" + - name: "ACCOUNTS_ROSTER_CLIENTKEY" + valueFrom: + secretKeyRef: + name: "mpesa-secret-roster" + key: "client-key" + - name: "ACCOUNTS_ROSTER_CLIENTSECRET" + valueFrom: + secretKeyRef: + name: "mpesa-secret-roster" + key: "client-secret" + - name: "ACCOUNTS_ROSTER_PASSKEY" + valueFrom: + secretKeyRef: + name: "mpesa-secret-roster" + key: "pass-key" + - name: "ACCOUNTS_PAYGOPS_SHORTCODE" + value: "{{ .Values.accounts.paygops.business_short_code}}" + - name: "ACCOUNTS_PAYGOPS_TILL" + value: "{{ .Values.accounts.paygops.till }}" + - name: "ACCOUNTS_PAYGOPS_AUTHHOST" + value: "{{ .Values.accounts.paygops.auth_host }}" + - name: "ACCOUNTS_PAYGOPS_APIHOST" + value: "{{ .Values.accounts.paygops.api_host }}" + - name: "ACCOUNTS_PAYGOPS_CLIENTKEY" + valueFrom: + secretKeyRef: + name: "mpesa-secret-paygops" + key: "client-key" + - name: "ACCOUNTS_PAYGOPS_CLIENTSECRET" + valueFrom: + secretKeyRef: + name: "mpesa-secret-paygops" + key: "client-secret" + - name: "ACCOUNTS_PAYGOPS_PASSKEY" + valueFrom: + secretKeyRef: + name: "mpesa-secret-paygops" + key: "pass-key" + - name: "SKIP_ENABLED" + value: "{{ .Values.skip.enabled }}" + - name: "PAYGOPS_HOST" + value: "{{ .Values.paygops.host }}" + - name: "ROSTER_HOST" + value: "{{ .Values.roster.host }}" + - name: "CHANNEL_HOST" + value: "{{ .Values.channel.host }}" + - name: "ACCOUNTS_PAYGOPS_PAYBILL_SHORTCODE" + value: "{{ .Values.paybill.paygops.business_short_code }}" + - name: "ACCOUNTS_PAYGOPS_CURRENCY" + value: "{{ .Values.paybill.paygops.currency }}" + - name: "ACCOUNTS_ROSTER_PAYBILL_SHORTCODE" + value: "{{ .Values.paybill.roster.business_short_code }}" + - name: "ACCOUNTS_ROSTER_CURRENCY" + value: "{{ .Values.paybill.roster.currency }}" + - name: "paybill_accountHoldingInstitutionId" + value: "{{ .Values.paybill.accountHoldingInstitutionId }}" +{{- if .Values.extraEnvs | default .Values.deployment.extraEnvs }} +{{ toYaml ( .Values.extraEnvs | default .Values.deployment.extraEnvs ) | indent 10 }} +{{- end }} + envFrom: {{ toYaml ( .Values.envFrom | default .Values.deployment.envFrom ) | nindent 12 }} + securityContext: {{ toYaml ( .Values.podSecurityContext | default .Values.deployment.securityContext ) | nindent 12 }} + +{{- end }} diff --git a/ph-ee-env-template/helm/ph-ee-engine/connector-mpesa/templates/ingress.yaml b/ph-ee-env-template/helm/ph-ee-engine/connector-mpesa/templates/ingress.yaml new file mode 100644 index 000000000..da1f6b257 --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/connector-mpesa/templates/ingress.yaml @@ -0,0 +1,50 @@ +{{- if .Values.ingress.enabled -}} +{{- $pathtype := .Values.ingress.pathtype -}} +{{- $ingressPath := .Values.ingress.path -}} +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: ph-ee-connector-mpesa + labels: + app: {{ .Chart.Name }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +{{- with .Values.ingress.annotations }} + annotations: +{{ toYaml . | indent 4 }} +{{- end }} +spec: + {{- if .Values.ingress.className }} + ingressClassName: {{ .Values.ingress.className | quote }} + {{- end }} +{{- if .Values.ingress.tls }} + tls: + {{- if .ingressPath }} + {{- range .Values.ingress.tls }} + - hosts: + {{- range .hosts }} + - {{ . }} + {{- end }} + secretName: {{ .secretName }} + {{- end }} +{{- else }} +{{ toYaml .Values.ingress.tls | indent 4 }} + {{- end }} +{{- end}} + rules: + {{- range .Values.ingress.hosts }} + - host: {{ .host }} + http: + paths: + {{- range .paths }} + - path: {{ .path }} + pathType: {{ $pathtype }} + backend: + service: + name: {{ .backend.service.name}} + port: + number: {{ .backend.service.port.number}} + {{- end }} + {{- end }} + {{- end }} + \ No newline at end of file diff --git a/ph-ee-env-template/helm/ph-ee-engine/connector-mpesa/templates/role.yaml b/ph-ee-env-template/helm/ph-ee-engine/connector-mpesa/templates/role.yaml new file mode 100644 index 000000000..d03f86564 --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/connector-mpesa/templates/role.yaml @@ -0,0 +1,14 @@ +{{- if .Values.managedServiceAccount }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: ph-ee-connector-mpesa-role + namespace: {{ .Release.Namespace }} +rules: +- apiGroups: + - "" + resources: + - pods + - configmaps + verbs: ["get", "create", "update"] +{{- end -}} \ No newline at end of file diff --git a/ph-ee-env-template/helm/ph-ee-engine/connector-mpesa/templates/rolebinding.yaml b/ph-ee-env-template/helm/ph-ee-engine/connector-mpesa/templates/rolebinding.yaml new file mode 100644 index 000000000..0716855d9 --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/connector-mpesa/templates/rolebinding.yaml @@ -0,0 +1,15 @@ +{{- if .Values.managedServiceAccount }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: ph-ee-connector-mpesa-role-binding + namespace: {{ .Release.Namespace }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: ph-ee-connector-mpesa-role +subjects: +- kind: ServiceAccount + name: ph-ee-connector-mpesa + namespace: {{ .Release.Namespace }} +{{- end -}} \ No newline at end of file diff --git a/ph-ee-env-template/helm/ph-ee-engine/connector-mpesa/templates/secret.yaml b/ph-ee-env-template/helm/ph-ee-engine/connector-mpesa/templates/secret.yaml new file mode 100644 index 000000000..c1c9ba66e --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/connector-mpesa/templates/secret.yaml @@ -0,0 +1,24 @@ +{{- if .Values.enabled -}} +apiVersion: {{ .Values.secret.apiversion }} +kind: Secret +metadata: + name: mpesa-secret-roster +type: Opaque +data: + client-key: {{ .Values.accounts.roster.client_key | b64enc }} + client-secret: {{ .Values.accounts.roster.client_secret | b64enc }} + pass-key: {{ .Values.accounts.roster.pass_key | b64enc }} +{{- end }} + +--- +{{- if .Values.enabled -}} +apiVersion: {{ .Values.secret.apiversion }} +kind: Secret +metadata: + name: mpesa-secret-paygops +type: Opaque +data: + client-key: {{ .Values.accounts.paygops.client_key | b64enc }} + client-secret: {{ .Values.accounts.paygops.client_secret | b64enc }} + pass-key: {{ .Values.accounts.paygops.pass_key | b64enc }} +{{- end }} \ No newline at end of file diff --git a/ph-ee-env-template/helm/ph-ee-engine/connector-mpesa/templates/service.yaml b/ph-ee-env-template/helm/ph-ee-engine/connector-mpesa/templates/service.yaml new file mode 100644 index 000000000..88dc16489 --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/connector-mpesa/templates/service.yaml @@ -0,0 +1,18 @@ +{{- if .Values.enabled -}} +apiVersion: {{ .Values.service.apiversion }} +kind: Service +metadata: + labels: + app: ph-ee-connector-mpesa + name: ph-ee-connector-mpesa +spec: + ports: + - name: port + port: 80 + protocol: TCP + targetPort: 5000 + selector: + app: ph-ee-connector-mpesa + sessionAffinity: None + type: ClusterIP +{{- end }} \ No newline at end of file diff --git a/ph-ee-env-template/helm/ph-ee-engine/connector-mpesa/templates/serviceaccount.yaml b/ph-ee-env-template/helm/ph-ee-engine/connector-mpesa/templates/serviceaccount.yaml new file mode 100644 index 000000000..cadbac867 --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/connector-mpesa/templates/serviceaccount.yaml @@ -0,0 +1,12 @@ +{{- if .Values.managedServiceAccount }} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: ph-ee-connector-mpesa + annotations: + {{- with .Values.serviceAccountAnnotations }} + {{- toYaml . | nindent 4 }} + {{- end }} + labels: + app: ph-ee-connector-mpesa +{{- end -}} \ No newline at end of file diff --git a/ph-ee-env-template/helm/ph-ee-engine/connector-mpesa/values.yaml b/ph-ee-env-template/helm/ph-ee-engine/connector-mpesa/values.yaml new file mode 100644 index 000000000..d53c68b49 --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/connector-mpesa/values.yaml @@ -0,0 +1,87 @@ +service: + apiversion: "v1" + +secret: + apiversion: "v1" + +configmap: + apiversion: "v1" + + +enabled: false +image: "" +imageTag: latest +SPRING_PROFILES_ACTIVE: "" +LOGGING_LEVEL_ROOT: "INFO" +zeebe_init_transfer_wait_timer: 10 +tenant: "lion" +callback_host: "https://mpesa.sandbox.mifos.io/" +retry_count: 3 +api_timeout: 60000 +channel: + host: "http://ph-ee-connector-channel" +paygops: + host: "http://ph-ee-connector-ams-paygops" +roster: + host: "http://ph-ee-connector-ams-roster" +accounts: + roster: + name: "roster" + business_short_code: "" + till: "" + auth_host: "https://sandbox.safaricom.co.ke/oauth/v1/generate" + api_host: "https://sandbox.safaricom.co.ke" + client_key: "" + client_secret: "" + pass_key: "" + paygops: + name: "paygops" + business_short_code: "" + till: "" + auth_host: "https://sandbox.safaricom.co.ke/oauth/v1/generate" + api_host: "https://sandbox.safaricom.co.ke" + client_key: "" + client_secret: "" + pass_key: "" +paybill: + accountHoldingInstitutionId: "gorilla" + paygops: + business_short_code: "" + currency: "KES" + roster: + business_short_code: "" + currency: "KES" +limits: + cpu: "500m" + memory: "512M" +requests: + cpu: "100m" + memory: "256M" +# Enabling this will publicly expose your Elasticsearch instance. +# Only enable this if you have security enabled on your cluster +ingress: + enabled: false + annotations: {} + # kubernetes.io/ingress.class: "nginx" + pathtype: ImplementationSpecific + hosts: + - host: "" + paths: + - path: / + tls: [] + # - secretName: sandbox-secret + # hosts: + # - chart-example.local + +deployment: + apiVersion: "apps/v1" + annotations: + deployTime: "{{ .Values.deployTime }}" +skip: + enabled: false +livenessProbe: + initialDelaySeconds: 20 + periodSeconds: 30 +readinessProbe: + initialDelaySeconds: 20 + periodSeconds: 30 diff --git a/ph-ee-env-template/helm/ph-ee-engine/connector-notifications/Chart.yaml b/ph-ee-env-template/helm/ph-ee-engine/connector-notifications/Chart.yaml new file mode 100644 index 000000000..59b070586 --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/connector-notifications/Chart.yaml @@ -0,0 +1,5 @@ +apiVersion: v1 +description: ph-ee-connector-notifications +name: notifications +version: 1.0.0 +appVersion: "1.0.0" \ No newline at end of file diff --git a/ph-ee-env-template/helm/ph-ee-engine/connector-notifications/README.md b/ph-ee-env-template/helm/ph-ee-engine/connector-notifications/README.md new file mode 100644 index 000000000..0d0bd946f --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/connector-notifications/README.md @@ -0,0 +1,43 @@ +# notifications + +![Version: 1.0.0](https://img.shields.io/badge/Version-1.0.0-informational?style=flat-square) ![AppVersion: 1.0.0](https://img.shields.io/badge/AppVersion-1.0.0-informational?style=flat-square) + +ph-ee-connector-notifications + +## Values + +| Key | Type | Default | Description | +|-----|------|---------|-------------| +| MESSAGEGATEWAYCONFIG_HOST | string | `"message-gateway"` | | +| NOTIFICATION_FAILURE_ENABLED | string | `"false"` | | +| NOTIFICATION_LOCAL_HOST | string | `"ph-ee-connector-notifications"` | | +| NOTIFICATION_SUCCESS_ENABLED | string | `"false"` | | +| SPRING_PROFILES_ACTIVE | string | `""` | | +| configmap.apiversion | string | `"v1"` | | +| deployment.annotations.deployTime | string | `"{{ .Values.deployTime }}"` | | +| deployment.apiVersion | string | `"apps/v1"` | | +| enabled | bool | `true` | | +| hostconfig.host | string | `"message-gateway"` | | +| hostconfig.port | int | `80` | | +| hostname | string | `"notifications.sandbox.mifos.io"` | | +| image | string | `""` | | +| imageTag | string | `"latest"` | | +| ingress.annotations."kubernetes.io/ingress.class" | string | `"nginx"` | | +| ingress.apiversion | string | `"networking.k8s.io/v1"` | | +| ingress.backend.service.name | string | `"ph-ee-connector-notifications"` | | +| ingress.backend.service.port.number | int | `80` | | +| ingress.enabled | bool | `true` | | +| ingress.path | string | `"/"` | | +| ingress.tls[0].hosts | string | `"notifications.sandbox.mifos.io"` | | +| ingress.tls[1].secretName | string | `"sandbox-secret"` | | +| limits.cpu | string | `"500m"` | | +| limits.memory | string | `"512M"` | | +| requests.cpu | string | `"100m"` | | +| requests.memory | string | `"256M"` | | +| secret.apiversion | string | `"v1"` | | +| service.apiversion | string | `"v1"` | | +| wildcardhostname | string | `"notifications.sandbox.mifos.io"` | | +| zeebe_broker_contactpoint | string | `"zeebe-zeebe-gateway:26500"` | | + +---------------------------------------------- +Autogenerated from chart metadata using [helm-docs v1.11.0](https://github.com/norwoodj/helm-docs/releases/v1.11.0) diff --git a/ph-ee-env-template/helm/ph-ee-engine/connector-notifications/templates/clusterrole.yaml b/ph-ee-env-template/helm/ph-ee-engine/connector-notifications/templates/clusterrole.yaml new file mode 100644 index 000000000..b3417dd93 --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/connector-notifications/templates/clusterrole.yaml @@ -0,0 +1,11 @@ +{{- if .Values.managedServiceAccount }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + # "namespace" omitted since ClusterRoles are not namespaced + name: ph-ee-connector-notification-c-role +rules: +- apiGroups: [""] + resources: ["secrets"] + verbs: ["get", "watch", "list"] +{{- end -}} \ No newline at end of file diff --git a/ph-ee-env-template/helm/ph-ee-engine/connector-notifications/templates/clusterrolebinding.yaml b/ph-ee-env-template/helm/ph-ee-engine/connector-notifications/templates/clusterrolebinding.yaml new file mode 100644 index 000000000..8108188f8 --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/connector-notifications/templates/clusterrolebinding.yaml @@ -0,0 +1,15 @@ +{{- if .Values.managedServiceAccount }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: ph-ee-connector-notification-c-role-binding +subjects: +- kind: ServiceAccount + name: ph-ee-connector-notification # name of your service account + namespace: {{ .Release.Namespace }} # this is the namespace your service account is in +roleRef: # referring to your ClusterRole + kind: ClusterRole + name: ph-ee-connector-notification-c-role + apiGroup: rbac.authorization.k8s.io + +{{- end -}} \ No newline at end of file diff --git a/ph-ee-env-template/helm/ph-ee-engine/connector-notifications/templates/deployment.yaml b/ph-ee-env-template/helm/ph-ee-engine/connector-notifications/templates/deployment.yaml new file mode 100644 index 000000000..f4ea5a0b5 --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/connector-notifications/templates/deployment.yaml @@ -0,0 +1,78 @@ +{{- if .Values.enabled -}} + +apiVersion: apps/v1 +kind: Deployment +metadata: + name: ph-ee-connector-notifications + labels: + app: ph-ee-connector-notifications +spec: + replicas: {{ .Values.replicas }} + selector: + matchLabels: + app: ph-ee-connector-notifications + template: + metadata: + labels: + app: ph-ee-connector-notifications + annotations: +{{- if .Values.deployment.annotations }} +{{ toYaml .Values.deployment.annotations | indent 8 }} +{{- end }} + spec: + initContainers: + #During this Pod's initialization, check that zeebe-gateway service is up and running before starting this pod + - name: check-zeebe-gateway-ready + image: busybox:latest + command: [ 'sh', '-c','until nc -vz {{ .Release.Name }}-zeebe-gateway 26500; do echo "Waiting for zeebe-gateway service"; sleep 2; done;' ] + containers: + - name: "ph-ee-connector-notifications" + image: "{{ .Values.image }}" + imagePullPolicy: "{{ .Values.global.imagePullPolicy }}" + resources: + limits: + memory: "{{ .Values.limits.memory }}" + cpu: "{{ .Values.limits.cpu }}" + requests: + memory: "{{ .Values.requests.memory }}" + cpu: "{{ .Values.requests.cpu }}" + ports: + - containerPort: 5000 + livenessProbe: + httpGet: + path: /actuator/health/liveness + port: 8080 + initialDelaySeconds: {{.Values.livenessProbe.initialDelaySeconds}} + periodSeconds: {{.Values.livenessProbe.periodSeconds}} + readinessProbe: + httpGet: + path: /actuator/health/readiness + port: 8080 + initialDelaySeconds: {{.Values.readinessProbe.initialDelaySeconds}} + periodSeconds: {{.Values.readinessProbe.periodSeconds}} + env: + - name: "SPRING_PROFILES_ACTIVE" + value: "{{ .Values.global.SPRING_PROFILES_ACTIVE }}" + - name: "ZEEBE_BROKER_CONTACTPOINT" + value: "{{ .Release.Name }}-zeebe-gateway:26500" + - name: "HOSTCONFIG_HOST" + value: "{{ .Values.hostconfig.host }}" + - name: "HOSTCONFIG_PORT" + value: "{{ .Values.hostconfig.port }}" + - name: "MESSAGEGATEWAYCONFIG_HOST" + value: "{{ .Values.MESSAGEGATEWAYCONFIG_HOST }}" + - name: "NOTIFICATION_LOCAL_HOST" + value: "{{ .Values.NOTIFICATION_LOCAL_HOST }}" + - name: "NOTIFICATION_SUCCESS_ENABLED" + value: "{{ .Values.NOTIFICATION_SUCCESS_ENABLED }}" + - name: "NOTIFICATION_FAILURE_ENABLED" + value: "{{ .Values.NOTIFICATION_FAILURE_ENABLED }}" + - name: "LOGGING_LEVEL_ROOT" + value: "{{ .Values.global.LOGGING_LEVEL_ROOT }}" +{{- if .Values.extraEnvs | default .Values.deployment.extraEnvs }} +{{ toYaml ( .Values.extraEnvs | default .Values.deployment.extraEnvs ) | indent 10 }} +{{- end }} + envFrom: {{ toYaml ( .Values.envFrom | default .Values.deployment.envFrom ) | nindent 12 }} + securityContext: {{ toYaml ( .Values.podSecurityContext | default .Values.deployment.securityContext ) | nindent 12 }} + +{{- end }} diff --git a/ph-ee-env-template/helm/ph-ee-engine/connector-notifications/templates/ingress.yaml b/ph-ee-env-template/helm/ph-ee-engine/connector-notifications/templates/ingress.yaml new file mode 100644 index 000000000..9c8a7606a --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/connector-notifications/templates/ingress.yaml @@ -0,0 +1,56 @@ +{{- if .Values.ingress.enabled -}} +{{- $pathtype := .Values.ingress.pathtype -}} +{{- $ingressPath := .Values.ingress.path -}} +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: ph-ee-notifications + labels: + app: {{ .Chart.Name }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +{{- with .Values.ingress.annotations }} + annotations: +{{ toYaml . | indent 4 }} +{{- end }} +spec: + {{- if .Values.ingress.className }} + ingressClassName: {{ .Values.ingress.className | quote }} + {{- end }} +{{- if .Values.ingress.tls }} + tls: + {{- if .ingressPath }} + {{- range .Values.ingress.tls }} + - hosts: + {{- range .hosts }} + - {{ . }} + {{- end }} + secretName: {{ .secretName }} + {{- end }} +{{- else }} +{{ toYaml .Values.ingress.tls | indent 4 }} + {{- end }} +{{- end}} + rules: + {{- range .Values.ingress.hosts }} + - host: {{ .host }} + http: + paths: + {{- range .paths }} + - path: {{ .path }} + pathType: {{ $pathtype }} + backend: + service: + name: {{ .backend.service.name}} + port: + number: {{ .backend.service.port.number}} + {{- end }} + - path: /actuator + pathType: Prefix + backend: + service: + name: ph-ee-notifications + port: + number: 8080 + {{- end }} + {{- end }} diff --git a/ph-ee-env-template/helm/ph-ee-engine/connector-notifications/templates/role.yaml b/ph-ee-env-template/helm/ph-ee-engine/connector-notifications/templates/role.yaml new file mode 100644 index 000000000..499fbe3e5 --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/connector-notifications/templates/role.yaml @@ -0,0 +1,14 @@ +{{- if .Values.managedServiceAccount }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: ph-ee-connector-notification-role + namespace: {{ .Release.Namespace }} +rules: +- apiGroups: + - "" + resources: + - pods + - configmaps + verbs: ["get", "create", "update"] +{{- end -}} \ No newline at end of file diff --git a/ph-ee-env-template/helm/ph-ee-engine/connector-notifications/templates/rolebinding.yaml b/ph-ee-env-template/helm/ph-ee-engine/connector-notifications/templates/rolebinding.yaml new file mode 100644 index 000000000..0023c24dc --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/connector-notifications/templates/rolebinding.yaml @@ -0,0 +1,15 @@ +{{- if .Values.managedServiceAccount }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: ph-ee-connector-notification-role-binding + namespace: {{ .Release.Namespace }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: ph-ee-connector-notification-role +subjects: +- kind: ServiceAccount + name: ph-ee-connector-notification + namespace: {{ .Release.Namespace }} +{{- end -}} \ No newline at end of file diff --git a/ph-ee-env-template/helm/ph-ee-engine/connector-notifications/templates/service.yaml b/ph-ee-env-template/helm/ph-ee-engine/connector-notifications/templates/service.yaml new file mode 100644 index 000000000..9eceb7f10 --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/connector-notifications/templates/service.yaml @@ -0,0 +1,22 @@ +{{- if .Values.enabled -}} +apiVersion: {{ .Values.service.apiversion }} +kind: Service +metadata: + labels: + app: ph-ee-connector-notifications + name: ph-ee-connector-notifications +spec: + ports: + - name: port + port: 80 + protocol: TCP + targetPort: 5000 + - name: actuator + protocol: TCP + port: 8080 # Port where Actuator endpoints are exposed + targetPort: 8080 + selector: + app: ph-ee-connector-notifications + sessionAffinity: None + type: ClusterIP +{{- end }} diff --git a/ph-ee-env-template/helm/ph-ee-engine/connector-notifications/templates/serviceaccount.yaml b/ph-ee-env-template/helm/ph-ee-engine/connector-notifications/templates/serviceaccount.yaml new file mode 100644 index 000000000..d09d72c0c --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/connector-notifications/templates/serviceaccount.yaml @@ -0,0 +1,15 @@ +{{- if .Values.managedServiceAccount }} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: ph-ee-connector-notification + annotations: + {{- with .Values.serviceAccountAnnotations }} + {{- toYaml . | nindent 4 }} + {{- end }} + labels: + app: ph-ee-connector-notification + chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" + heritage: {{ .Release.Service | quote }} + release: {{ .Release.Name | quote }} +{{- end -}} \ No newline at end of file diff --git a/ph-ee-env-template/helm/ph-ee-engine/connector-notifications/values.yaml b/ph-ee-env-template/helm/ph-ee-engine/connector-notifications/values.yaml new file mode 100644 index 000000000..d358aaf70 --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/connector-notifications/values.yaml @@ -0,0 +1,52 @@ +service: + apiversion: "v1" + +secret: + apiversion: "v1" + +configmap: + apiversion: "v1" + +enabled: true +image: "" +imageTag: latest +SPRING_PROFILES_ACTIVE: "" +MESSAGEGATEWAYCONFIG_HOST: "message-gateway" +NOTIFICATION_LOCAL_HOST: "ph-ee-connector-notifications" +NOTIFICATION_SUCCESS_ENABLED: "false" +NOTIFICATION_FAILURE_ENABLED: "false" +hostconfig: + host: "message-gateway" + port: 80 +limits: + cpu: "500m" + memory: "512M" +requests: + cpu: "100m" + memory: "256M" +# Enabling this will publicly expose your Elasticsearch instance. +# Only enable this if you have security enabled on your cluster +ingress: + enabled: false + annotations: {} + # kubernetes.io/ingress.class: "nginx" + pathtype: ImplementationSpecific + hosts: + - host: "" + paths: + - path: / + tls: [] + # - secretName: sandbox-secret + # hosts: + # - chart-example.local +deployment: + apiVersion: "apps/v1" + annotations: + deployTime: "{{ .Values.deployTime }}" + +livenessProbe: + initialDelaySeconds: 20 + periodSeconds: 30 +readinessProbe: + initialDelaySeconds: 20 + periodSeconds: 30 diff --git a/ph-ee-env-template/helm/ph-ee-engine/connector-ph-ee-bulk/Chart.yaml b/ph-ee-env-template/helm/ph-ee-engine/connector-ph-ee-bulk/Chart.yaml new file mode 100644 index 000000000..2bb268ff3 --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/connector-ph-ee-bulk/Chart.yaml @@ -0,0 +1,5 @@ +apiVersion: v1 +description: ph-ee-connector +name: ph-ee-connector +version: 1.0.0 +appVersion: "1.0.0" \ No newline at end of file diff --git a/ph-ee-env-template/helm/ph-ee-engine/connector-ph-ee-bulk/templates/clusterrole.yaml b/ph-ee-env-template/helm/ph-ee-engine/connector-ph-ee-bulk/templates/clusterrole.yaml new file mode 100644 index 000000000..560d9b44a --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/connector-ph-ee-bulk/templates/clusterrole.yaml @@ -0,0 +1,11 @@ +{{- if .Values.managedServiceAccount }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + # "namespace" omitted since ClusterRoles are not namespaced + name: ph-ee-connector-c-role +rules: +- apiGroups: [""] + resources: ["secrets"] + verbs: ["get", "watch", "list"] +{{- end -}} \ No newline at end of file diff --git a/ph-ee-env-template/helm/ph-ee-engine/connector-ph-ee-bulk/templates/clusterrolebinding.yaml b/ph-ee-env-template/helm/ph-ee-engine/connector-ph-ee-bulk/templates/clusterrolebinding.yaml new file mode 100644 index 000000000..257c9bc51 --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/connector-ph-ee-bulk/templates/clusterrolebinding.yaml @@ -0,0 +1,15 @@ +{{- if .Values.managedServiceAccount }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: ph-ee-connector-c-role-binding +subjects: +- kind: ServiceAccount + name: ph-ee-connector # name of your service account + namespace: {{ .Release.Namespace }} # this is the namespace your service account is in +roleRef: # referring to your ClusterRole + kind: ClusterRole + name: ph-ee-connector-c-role + apiGroup: rbac.authorization.k8s.io + +{{- end -}} \ No newline at end of file diff --git a/ph-ee-env-template/helm/ph-ee-engine/connector-ph-ee-bulk/templates/deployment.yaml b/ph-ee-env-template/helm/ph-ee-engine/connector-ph-ee-bulk/templates/deployment.yaml new file mode 100644 index 000000000..4c64525d7 --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/connector-ph-ee-bulk/templates/deployment.yaml @@ -0,0 +1,101 @@ +{{- if .Values.enabled -}} + +apiVersion: apps/v1 +kind: Deployment +metadata: + name: ph-ee-connector + labels: + app: ph-ee-connector +spec: + replicas: {{ .Values.replicas }} + selector: + matchLabels: + app: ph-ee-connector + template: + metadata: + labels: + app: ph-ee-connector + annotations: +{{- if .Values.deployment.annotations }} +{{ toYaml .Values.deployment.annotations | indent 8 }} +{{- end }} + spec: + initContainers: + #During this Pod's initialization, check that zeebe-gateway service is up and running before starting this pod + - name: check-zeebe-gateway-ready + image: busybox:latest + command: [ 'sh', '-c','until nc -vz {{ .Release.Name }}-zeebe-gateway 26500; do echo "Waiting for zeebe-gateway service"; sleep 2; done;' ] + containers: + - name: ph-ee-connector + image: "{{ .Values.image }}" + ports: + - containerPort: 8080 + imagePullPolicy: "{{ .Values.global.imagePullPolicy }}" + resources: + limits: + memory: "{{ .Values.limits.memory }}" + cpu: "{{ .Values.limits.cpu }}" + requests: + memory: "{{ .Values.requests.memory }}" + cpu: "{{ .Values.requests.cpu }}" + + env: + - name: "SPRING_PROFILES_ACTIVE" + value: "{{ .Values.global.SPRING_PROFILES_ACTIVE }}" + - name: "CAMEL_DISABLE-SSL" + value: "{{ .Values.camel_disable_ssl }}" + - name: "ZEEBE_BROKER_CONTACTPOINT" + value: "{{ .Release.Name }}-zeebe-gateway:26500" + - name: "TENANTS" + value: "{{ .Values.tenants }}" + - name: "CLOUD_AWS_BUCKET-NAME" + value: "{{ .Values.global.bucket_name }}" + - name: "OPERATIONS-APP_CONTACTPOINT" + value: "{{ .Values.operations_app.contactpoint }}" + - name: "OPERATIONS-APP_ENDPOINTS_BATCH-SUMMARY" + value: "{{ .Values.operations_app.endpoints.batch_summary }}" + - name: "OPERATIONS-APP_ENDPOINTS_BATCH-DETAIL" + value: "{{ .Values.operations_app.endpoints.batch_detail }}" + - name: "MOCK-PAYMENT-SCHEMA_CONTACTPOINT" + value: "{{ .Values.mock_payment_schema.contactpoint }}" + - name: "MOCK-PAYMENT-SCHEMA_ENDPOINTS_BATCH-SUMMARY" + value: "{{ .Values.mock_payment_schema.endpoints.batch_summary }}" + - name: "MOCK-PAYMENT-SCHEMA_ENDPOINTS_BATCH-DETAIL" + value: "{{ .Values.mock_payment_schema.endpoints.batch_detail }}" + - name: "BULK-PROCESSOR_CONTACTPOINT" + value: "{{ .Values.bulk_processor.contactpoint }}" + - name: "BULK-PROCESSOR_ENDPOINTS_BATCH-TRANSACTION" + value: "{{ .Values.bulk_processor.endpoints.batch_transaction }}" + - name: "TENANT" + value: "{{ .Values.global.tenant }}" + - name: "CLOUD_AWS_REGION_STATIC" + valueFrom: + secretKeyRef: + name: "bulk-processor-secret" + key: "aws-region" + - name: "CLOUD_AWS_S3BASEURL" + value: {{.Values.global.s3BaseUrl}} + - name: "AWS_ACCESS_KEY" + valueFrom: + secretKeyRef: + name: "bulk-processor-secret" + key: "aws-access-key" + - name: "AWS_SECRET_KEY" + valueFrom: + secretKeyRef: + name: "bulk-processor-secret" + key: "aws-secret-key" + +{{- if .Values.extraEnvs | default .Values.deployment.extraEnvs }} +{{ toYaml ( .Values.extraEnvs | default .Values.deployment.extraEnvs ) | indent 10 }} +{{- end }} + envFrom: {{ toYaml ( .Values.envFrom | default .Values.deployment.envFrom ) | nindent 12 }} + securityContext: {{ toYaml ( .Values.podSecurityContext | default .Values.deployment.securityContext ) | nindent 12 }} + volumeMounts: + - name: ph-ee-config + mountPath: "/config" + volumes: + - name: ph-ee-config + configMap: + name: ph-ee-config +{{- end }} diff --git a/ph-ee-env-template/helm/ph-ee-engine/connector-ph-ee-bulk/templates/ingress.yaml b/ph-ee-env-template/helm/ph-ee-engine/connector-ph-ee-bulk/templates/ingress.yaml new file mode 100644 index 000000000..690e241f6 --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/connector-ph-ee-bulk/templates/ingress.yaml @@ -0,0 +1,49 @@ +{{- if .Values.ingress.enabled -}} +{{- $pathtype := .Values.ingress.pathtype -}} +{{- $ingressPath := .Values.ingress.path -}} +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: ph-ee-connector + labels: + app: {{ .Chart.Name }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +{{- with .Values.ingress.annotations }} + annotations: +{{ toYaml . | indent 4 }} +{{- end }} +spec: + {{- if .Values.ingress.className }} + ingressClassName: {{ .Values.ingress.className | quote }} + {{- end }} +{{- if .Values.ingress.tls }} + tls: + {{- if .ingressPath }} + {{- range .Values.ingress.tls }} + - hosts: + {{- range .hosts }} + - {{ . }} + {{- end }} + secretName: {{ .secretName }} + {{- end }} +{{- else }} +{{ toYaml .Values.ingress.tls | indent 4 }} + {{- end }} +{{- end}} + rules: + {{- range .Values.ingress.hosts }} + - host: {{ .host }} + http: + paths: + {{- range .paths }} + - path: {{ .path }} + pathType: {{ $pathtype }} + backend: + service: + name: {{ .backend.service.name}} + port: + number: {{ .backend.service.port.number}} + {{- end }} + {{- end }} + {{- end }} diff --git a/ph-ee-env-template/helm/ph-ee-engine/connector-ph-ee-bulk/templates/rolebinding.yaml b/ph-ee-env-template/helm/ph-ee-engine/connector-ph-ee-bulk/templates/rolebinding.yaml new file mode 100644 index 000000000..68eea9b8b --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/connector-ph-ee-bulk/templates/rolebinding.yaml @@ -0,0 +1,15 @@ +{{- if .Values.managedServiceAccount }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: ph-ee-operator-role-binding + namespace: {{ .Release.Namespace }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: ph-ee-operator-role +subjects: + - kind: ServiceAccount + name: payment-hub + namespace: {{ .Release.Namespace }} + {{- end -}} \ No newline at end of file diff --git a/ph-ee-env-template/helm/ph-ee-engine/connector-ph-ee-bulk/templates/secret.yaml b/ph-ee-env-template/helm/ph-ee-engine/connector-ph-ee-bulk/templates/secret.yaml new file mode 100644 index 000000000..e7a3a32ce --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/connector-ph-ee-bulk/templates/secret.yaml @@ -0,0 +1,10 @@ +{{- if .Values.enabled -}} +apiVersion: {{ .Values.secret.apiversion }} +kind: Secret +metadata: + name: bulk-closedloop-secret +type: Opaque +data: + aws-access-key: {{ .Values.aws.access_key | b64enc }} + aws-secret-key: {{ .Values.aws.secret_key | b64enc }} +{{- end }} \ No newline at end of file diff --git a/ph-ee-env-template/helm/ph-ee-engine/connector-ph-ee-bulk/templates/service.yaml b/ph-ee-env-template/helm/ph-ee-engine/connector-ph-ee-bulk/templates/service.yaml new file mode 100644 index 000000000..f62c97b6a --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/connector-ph-ee-bulk/templates/service.yaml @@ -0,0 +1,19 @@ +{{- if .Values.enabled -}} +apiVersion: {{ .Values.service.apiversion }} +kind: Service +metadata: + labels: + app: ph-ee-connector + name: ph-ee-connector +spec: + ports: + - name: port + port: 80 + protocol: TCP + targetPort: 8080 + + selector: + app: ph-ee-connector + sessionAffinity: None + type: ClusterIP +{{- end }} \ No newline at end of file diff --git a/ph-ee-env-template/helm/ph-ee-engine/connector-ph-ee-bulk/templates/serviceaccount.yaml b/ph-ee-env-template/helm/ph-ee-engine/connector-ph-ee-bulk/templates/serviceaccount.yaml new file mode 100644 index 000000000..09cf6b2ab --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/connector-ph-ee-bulk/templates/serviceaccount.yaml @@ -0,0 +1,15 @@ +{{- if .Values.managedServiceAccount }} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: ph-ee-connector + annotations: + {{- with .Values.serviceAccountAnnotations }} + {{- toYaml . | nindent 4 }} + {{- end }} + labels: + app: ph-ee-connector + chart: "connector-{{ .Chart.Version }}" + heritage: {{ .Release.Service | quote }} + release: {{ .Release.Name | quote }} +{{- end -}} \ No newline at end of file diff --git a/ph-ee-env-template/helm/ph-ee-engine/connector-ph-ee-bulk/values.yaml b/ph-ee-env-template/helm/ph-ee-engine/connector-ph-ee-bulk/values.yaml new file mode 100644 index 000000000..f86b1a9af --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/connector-ph-ee-bulk/values.yaml @@ -0,0 +1,65 @@ +service: + apiversion: "v1" + +secret: + apiversion: "v1" + +configmap: + apiversion: "v1" + +enabled: "" +image: "" +imagePullPolicy: "" +SPRING_PROFILES_ACTIVE: "" +LOGGING_LEVEL_ROOT: "INFO" +camel_disable_ssl: true +application: + bucket_name: "paymenthub-ee-dev" +zeebe: + broker: + contactpoint: "" +operations_app: + contactpoint: "http://ph-ee-operations-app:5000" + endpoints: + batch_summary: "/api/v1/batch" + batch_detail: "/api/v1/batch/detail" +mock_payment_schema: + contactpoint: "http://ph-ee-connector-mock-payment-schema:8080" + endpoints: + batch_summary: "/mockapi/v1/batch" + batch_detail: "/mockapi/v1/batch/detail" +bulk_processor: + contactpoint: "https://ph-ee-connector-bulk:8443" + endpoints: + batch_transaction: "/batchtransactions" +aws: + region: "" + access_key: "" + secret_key: "" +limits: + cpu: "500m" + memory: "512M" +requests: + cpu: "100m" + memory: "512M" + +# Enabling this will publicly expose your Elasticsearch instance. +# Only enable this if you have security enabled on your cluster +ingress: + enabled: false + annotations: {} + # kubernetes.io/ingress.class: "nginx" + pathtype: ImplementationSpecific + hosts: + - host: "" + paths: + - path: / + tls: [] + # - secretName: sandbox-secret + # hosts: + # - chart-example.local + +deployment: + apiVersion: "apps/v1" + annotations: + deployTime: "{{ .Values.deployTime }}" diff --git a/ph-ee-env-template/helm/ph-ee-engine/connector-slcb/Chart.yaml b/ph-ee-env-template/helm/ph-ee-engine/connector-slcb/Chart.yaml new file mode 100644 index 000000000..d9cb2cb0e --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/connector-slcb/Chart.yaml @@ -0,0 +1,5 @@ +apiVersion: v1 +description: ph-ee-connector-slcb +name: ph_ee_connector_slcb +version: 1.0.0 +appVersion: "1.0.0" \ No newline at end of file diff --git a/ph-ee-env-template/helm/ph-ee-engine/connector-slcb/README.md b/ph-ee-env-template/helm/ph-ee-engine/connector-slcb/README.md new file mode 100644 index 000000000..7574f6cad --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/connector-slcb/README.md @@ -0,0 +1,49 @@ +# ph_ee_connector_slcb + +![Version: 1.0.0](https://img.shields.io/badge/Version-1.0.0-informational?style=flat-square) ![AppVersion: 1.0.0](https://img.shields.io/badge/AppVersion-1.0.0-informational?style=flat-square) + +ph-ee-connector-slcb + +## Values + +| Key | Type | Default | Description | +|-----|------|---------|-------------| +| SPRING_PROFILES_ACTIVE | string | `""` | | +| account_number | string | `""` | | +| account_type | int | `0` | | +| api_host | string | `"https://g2p-test.slcb.com:8443"` | | +| auth_host | string | `"https://g2p-test.slcb.com:8443"` | | +| aws.bucket_name | string | `""` | | +| aws.region | string | `""` | | +| config.date_format | string | `"yyyy-MM-dd'T'hh:mm:ssXXX"` | | +| config.reconciliation.enable | bool | `false` | | +| configmap.apiversion | string | `"v1"` | | +| deployment.annotations.deployTime | string | `"{{ .Values.deployTime }}"` | | +| deployment.apiVersion | string | `"apps/v1"` | | +| enabled | bool | `true` | | +| endpoint.account_balance | string | `"/accountBalance"` | | +| endpoint.auth | string | `"/api/auth"` | | +| endpoint.reconciliation | string | `"/reconciliation"` | | +| endpoint.transaction_request | string | `"/api/transactionRequest"` | | +| image | string | `""` | | +| imageTag | string | `"latest"` | | +| ingress.apiversion | string | `"networking.k8s.io/v1"` | | +| institutioncode | string | `"SLCB"` | | +| limits.cpu | string | `"500m"` | | +| limits.memory | string | `"512M"` | | +| password | string | `""` | | +| requests.cpu | string | `"100m"` | | +| requests.memory | string | `"256M"` | | +| secret.apiversion | string | `"v1"` | | +| secret.connector_bulk.aws.access_key | string | `""` | | +| secret.connector_bulk.aws.secret_key | string | `""` | | +| secret.password | string | `""` | | +| secret.signature_key | string | `""` | | +| secret.username | string | `""` | | +| service.apiversion | string | `"v1"` | | +| signature_key | string | `""` | | +| username | string | `""` | | +| zeebe_broker_contactpoint | string | `"zeebe-zeebe-gateway:26500"` | | + +---------------------------------------------- +Autogenerated from chart metadata using [helm-docs v1.11.0](https://github.com/norwoodj/helm-docs/releases/v1.11.0) diff --git a/ph-ee-env-template/helm/ph-ee-engine/connector-slcb/templates/clusterrole.yaml b/ph-ee-env-template/helm/ph-ee-engine/connector-slcb/templates/clusterrole.yaml new file mode 100644 index 000000000..5cd112eb1 --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/connector-slcb/templates/clusterrole.yaml @@ -0,0 +1,11 @@ +{{- if .Values.managedServiceAccount }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + # "namespace" omitted since ClusterRoles are not namespaced + name: ph-ee-connector-slcb-c-role +rules: +- apiGroups: [""] + resources: ["secrets"] + verbs: ["get", "watch", "list"] +{{- end -}} \ No newline at end of file diff --git a/ph-ee-env-template/helm/ph-ee-engine/connector-slcb/templates/clusterrolebinding.yaml b/ph-ee-env-template/helm/ph-ee-engine/connector-slcb/templates/clusterrolebinding.yaml new file mode 100644 index 000000000..f0b3eeabf --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/connector-slcb/templates/clusterrolebinding.yaml @@ -0,0 +1,15 @@ +{{- if .Values.managedServiceAccount }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: ph-ee-connector-slcb-c-role-binding +subjects: +- kind: ServiceAccount + name: ph-ee-connector-slcb # name of your service account + namespace: {{ .Release.Namespace }} # this is the namespace your service account is in +roleRef: # referring to your ClusterRole + kind: ClusterRole + name: ph-ee-connector-slcb-c-role + apiGroup: rbac.authorization.k8s.io + +{{- end -}} \ No newline at end of file diff --git a/ph-ee-env-template/helm/ph-ee-engine/connector-slcb/templates/deployment.yaml b/ph-ee-env-template/helm/ph-ee-engine/connector-slcb/templates/deployment.yaml new file mode 100644 index 000000000..dda465858 --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/connector-slcb/templates/deployment.yaml @@ -0,0 +1,110 @@ +{{- if .Values.enabled -}} + +apiVersion: apps/v1 +kind: Deployment +metadata: + name: ph-ee-connector-slcb + labels: + app: ph-ee-connector-slcb +spec: + replicas: {{ .Values.replicas }} + selector: + matchLabels: + app: ph-ee-connector-slcb + template: + metadata: + labels: + app: ph-ee-connector-slcb + annotations: +{{- if .Values.deployment.annotations }} +{{ toYaml .Values.deployment.annotations | indent 8 }} +{{- end }} + spec: + initContainers: + #During this Pod's initialization, check that zeebe-gateway service is up and running before starting this pod + - name: check-zeebe-gateway-ready + image: busybox:latest + command: [ 'sh', '-c','until nc -vz {{ .Release.Name }}-zeebe-gateway 26500; do echo "Waiting for zeebe-gateway service"; sleep 2; done;' ] + containers: + - name: ph-ee-connector-slcb-mm + image: "{{ .Values.image }}" + imagePullPolicy: "{{ .Values.global.imagePullPolicy }}" + ports: + - containerPort: 5000 + resources: + limits: + memory: "{{ .Values.limits.memory }}" + cpu: "{{ .Values.limits.cpu }}" + requests: + memory: "{{ .Values.requests.memory }}" + cpu: "{{ .Values.requests.cpu }}" + env: + - name: "SPRING_PROFILES_ACTIVE" + value: "{{ .Values.global.SPRING_PROFILES_ACTIVE }}" + - name: "ZEEBE_BROKER_CONTACTPOINT" + value: "{{ .Release.Name }}-zeebe-gateway:26500" + - name: "SLCB_AUTH_HOST" + value: "{{ .Values.auth_host }}" + - name: "SLCB_AUTH_AUTH-ENDPOINT" + value: "{{ .Values.endpoint.auth }}" + - name: "SLCB_API_HOST" + value: "{{ .Values.api_host }}" + - name: "SLCB_API_TRANSACTION-REQUEST-ENDPOINT" + value: "{{ .Values.endpoint.transaction_request }}" + - name: "SLCB_API_RECONCILIATION-ENDPOINT" + value: "{{ .Values.endpoint.reconciliation }}" + - name: "SLCB_API_ACCOUNT-BALANCE-ENDPOINT" + value: "{{ .Values.endpoint.account_balance }}" + - name: "SLCB_CONFIG_DATE-FROMAT" + value: "{{ .Values.config.date_format }}" + - name: "SLCB_CONFIG_RECONCILIATION_ENABLE" + value: "{{ .Values.config.reconciliation.enable }}" + - name: "SLCB_ACCOUNT_NUMBER" + value: "{{ .Values.account_number }}" + - name: "SLCB_ACCOUNT_TYPE" + value: "{{ .Values.account_type }}" + - name: "SLCB_INSTITUTIONCODE" + value: "{{ .Values.institutioncode }}" + - name: "AWS_BUCKET_NAME" + value: "{{ .Values.aws.bucket_name }}" + - name: "CLOUD_AWS_REGION_STATIC" + value: "{{ .Values.aws.region }}" + - name: "AWS_ACCESS_KEY" + valueFrom: + secretKeyRef: + name: "slcb-secret" + key: "aws-access-key" + - name: "AWS_SECRET_KEY" + valueFrom: + secretKeyRef: + name: "slcb-secret" + key: "aws-secret-key" + - name: "SLCB_AUTH_USERNAME" + valueFrom: + secretKeyRef: + name: "slcb-secret" + key: "slcb-username" + - name: "SLCB_AUTH_PASSWORD" + valueFrom: + secretKeyRef: + name: "slcb-secret" + key: "slcb-password" + - name: "SLCB_SIGNATURE_KEY" + valueFrom: + secretKeyRef: + name: "slcb-secret" + key: "slcb-signature-key" +{{- if .Values.extraEnvs | default .Values.deployment.extraEnvs }} +{{ toYaml ( .Values.extraEnvs | default .Values.deployment.extraEnvs ) | indent 10 }} +{{- end }} + envFrom: {{ toYaml ( .Values.envFrom | default .Values.deployment.envFrom ) | nindent 12 }} + securityContext: {{ toYaml ( .Values.podSecurityContext | default .Values.deployment.securityContext ) | nindent 12 }} + + volumeMounts: + - name: ph-ee-config + mountPath: "/config" + volumes: + - name: ph-ee-config + configMap: + name: ph-ee-config +{{- end }} diff --git a/ph-ee-env-template/helm/ph-ee-engine/connector-slcb/templates/role.yaml b/ph-ee-env-template/helm/ph-ee-engine/connector-slcb/templates/role.yaml new file mode 100644 index 000000000..7d2d9b149 --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/connector-slcb/templates/role.yaml @@ -0,0 +1,14 @@ +{{- if .Values.managedServiceAccount }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: ph-ee-connector-slcb-role + namespace: {{ .Release.Namespace }} +rules: +- apiGroups: + - "" + resources: + - pods + - configmaps + verbs: ["get", "create", "update"] +{{- end -}} \ No newline at end of file diff --git a/ph-ee-env-template/helm/ph-ee-engine/connector-slcb/templates/rolebinding.yaml b/ph-ee-env-template/helm/ph-ee-engine/connector-slcb/templates/rolebinding.yaml new file mode 100644 index 000000000..1ebc2f243 --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/connector-slcb/templates/rolebinding.yaml @@ -0,0 +1,15 @@ +{{- if .Values.managedServiceAccount }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: ph-ee-connector-slcb-role-binding + namespace: {{ .Release.Namespace }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: ph-ee-connector-slcb-role +subjects: +- kind: ServiceAccount + name: ph-ee-connector-slcb + namespace: {{ .Release.Namespace }} +{{- end -}} \ No newline at end of file diff --git a/ph-ee-env-template/helm/ph-ee-engine/connector-slcb/templates/secret.yaml b/ph-ee-env-template/helm/ph-ee-engine/connector-slcb/templates/secret.yaml new file mode 100644 index 000000000..17058d7af --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/connector-slcb/templates/secret.yaml @@ -0,0 +1,13 @@ +{{- if .Values.enabled -}} +apiVersion: {{ .Values.secret.apiversion }} +kind: Secret +metadata: + name: slcb-secret +type: Opaque +data: + aws-access-key: {{ .Values.secret.connector_bulk.aws.access_key | b64enc }} + aws-secret-key: {{ .Values.secret.connector_bulk.aws.secret_key | b64enc }} + slcb-username: {{ .Values.secret.username | b64enc }} + slcb-password: {{ .Values.secret.password | b64enc }} + slcb-signature-key: {{ .Values.secret.signature_key | b64enc }} +{{- end }} \ No newline at end of file diff --git a/ph-ee-env-template/helm/ph-ee-engine/connector-slcb/templates/service.yaml b/ph-ee-env-template/helm/ph-ee-engine/connector-slcb/templates/service.yaml new file mode 100644 index 000000000..3aa62e48b --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/connector-slcb/templates/service.yaml @@ -0,0 +1,18 @@ +{{- if .Values.enabled -}} +apiVersion: {{ .Values.service.apiversion }} +kind: Service +metadata: + labels: + app: ph-ee-connector-slcb + name: ph-ee-connector-slcb +spec: + ports: + - name: port + port: 80 + protocol: TCP + targetPort: 5000 + selector: + app: ph-ee-connector-slcb + sessionAffinity: None + type: ClusterIP +{{- end }} \ No newline at end of file diff --git a/ph-ee-env-template/helm/ph-ee-engine/connector-slcb/templates/serviceaccount.yaml b/ph-ee-env-template/helm/ph-ee-engine/connector-slcb/templates/serviceaccount.yaml new file mode 100644 index 000000000..44bf3984e --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/connector-slcb/templates/serviceaccount.yaml @@ -0,0 +1,15 @@ +{{- if .Values.managedServiceAccount }} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: ph-ee-connector-slcb + annotations: + {{- with .Values.serviceAccountAnnotations }} + {{- toYaml . | nindent 4 }} + {{- end }} + labels: + app: ph-ee-connector-slcb + chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" + heritage: {{ .Release.Service | quote }} + release: {{ .Release.Name | quote }} +{{- end -}} \ No newline at end of file diff --git a/ph-ee-env-template/helm/ph-ee-engine/connector-slcb/values.yaml b/ph-ee-env-template/helm/ph-ee-engine/connector-slcb/values.yaml new file mode 100644 index 000000000..6df503c30 --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/connector-slcb/values.yaml @@ -0,0 +1,53 @@ +ingress: + apiversion: networking.k8s.io/v1 + +service: + apiversion: "v1" + +configmap: + apiversion: "v1" + +enabled: false +image: "" +imageTag: latest +SPRING_PROFILES_ACTIVE: "" +username: "" +password: "" +signature_key: "" +auth_host: "https://g2p-test.slcb.com:8443" +api_host: "https://g2p-test.slcb.com:8443" +account_number: "" +account_type: 0 +institutioncode: "SLCB" +aws: + bucket_name: "" + region: "" +endpoint: + auth: "/api/auth" + transaction_request: "/api/transactionRequest" + reconciliation: "/reconciliation" + account_balance: "/accountBalance" +config: + date_format: "yyyy-MM-dd'T'hh:mm:ssXXX" + reconciliation: + enable: false +limits: + cpu: "500m" + memory: "512M" +requests: + cpu: "100m" + memory: "256M" +deployment: + apiVersion: "apps/v1" + annotations: + deployTime: "{{ .Values.deployTime }}" + +secret: + apiversion: "v1" + username: "" + password: "" + signature_key: "" + connector_bulk: + aws: + access_key: "" + secret_key: "" \ No newline at end of file diff --git a/ph-ee-env-template/helm/ph-ee-engine/message-gateway/Chart.yaml b/ph-ee-env-template/helm/ph-ee-engine/message-gateway/Chart.yaml new file mode 100644 index 000000000..194256343 --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/message-gateway/Chart.yaml @@ -0,0 +1,5 @@ +apiVersion: v1 +description: messagegateway +name: messagegateway +version: 1.0.0 +appVersion: "1.0.0" \ No newline at end of file diff --git a/ph-ee-env-template/helm/ph-ee-engine/message-gateway/README.md b/ph-ee-env-template/helm/ph-ee-engine/message-gateway/README.md new file mode 100644 index 000000000..a895bdf47 --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/message-gateway/README.md @@ -0,0 +1,46 @@ +# messagegateway + +![Version: 1.0.0](https://img.shields.io/badge/Version-1.0.0-informational?style=flat-square) ![AppVersion: 1.0.0](https://img.shields.io/badge/AppVersion-1.0.0-informational?style=flat-square) + +messagegateway + +## Values + +| Key | Type | Default | Description | +|-----|------|---------|-------------| +| CALLBACKCONFIG_HOST | string | `"ph-ee-connector-notifications"` | | +| DATASOURCE_URL | string | `"jdbc:mysql:thin://operationsmysql:3306/messagegateway"` | | +| HOSTCONFIG_HOST | string | `"message-gateway"` | | +| MYSQL_PASSWORD | string | `"password"` | | +| MYSQL_USERNAME | string | `"mifos"` | | +| PROVIDERSOURCE_FROMDATABASE | string | `"disabled"` | | +| PROVIDERSOURCE_FROMYML | string | `"enabled"` | | +| configmap.apiversion | string | `"v1"` | | +| deployment.annotations.deployTime | string | `"{{ .Values.deployTime }}"` | | +| deployment.apiVersion | string | `"apps/v1"` | | +| enabled | bool | `true` | | +| hostname | string | `"messagegateway.sandbox.mifos.io"` | | +| image | string | `""` | | +| imageTag | string | `""` | | +| ingress.annotations."kubernetes.io/ingress.class" | string | `"nginx"` | | +| ingress.apiversion | string | `"networking.k8s.io/v1"` | | +| ingress.backend.service.name | string | `"message-gateway"` | | +| ingress.backend.service.port.number | int | `80` | | +| ingress.className | string | `"nginx"` | | +| ingress.enabled | bool | `true` | | +| ingress.path | string | `"/"` | | +| ingress.tls[0].hosts | string | `"messagegateway.sandbox.mifos.io"` | | +| ingress.tls[1].secretName | string | `"sandbox-secret"` | | +| limits.cpu | string | `"500m"` | | +| limits.memory | string | `"512M"` | | +| operations_app.datasource.host | string | `"operationsmysql"` | | +| requests.cpu | string | `"100m"` | | +| requests.memory | string | `"256M"` | | +| secret.apiversion | string | `"v1"` | | +| secret.value.api_key | string | `""` | | +| secret.value.project_id | string | `""` | | +| service.apiversion | string | `"v1"` | | +| wildcardhostname | string | `"messagegateway.sandbox.mifos.io"` | | + +---------------------------------------------- +Autogenerated from chart metadata using [helm-docs v1.11.0](https://github.com/norwoodj/helm-docs/releases/v1.11.0) diff --git a/ph-ee-env-template/helm/ph-ee-engine/message-gateway/templates/clusterrole.yaml b/ph-ee-env-template/helm/ph-ee-engine/message-gateway/templates/clusterrole.yaml new file mode 100644 index 000000000..e89142a88 --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/message-gateway/templates/clusterrole.yaml @@ -0,0 +1,11 @@ +{{- if .Values.managedServiceAccount }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + # "namespace" omitted since ClusterRoles are not namespaced + name: message-gateway-c-role +rules: +- apiGroups: [""] + resources: ["secrets"] + verbs: ["get", "watch", "list"] +{{- end -}} \ No newline at end of file diff --git a/ph-ee-env-template/helm/ph-ee-engine/message-gateway/templates/clusterrolebinding.yaml b/ph-ee-env-template/helm/ph-ee-engine/message-gateway/templates/clusterrolebinding.yaml new file mode 100644 index 000000000..ffe0763ad --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/message-gateway/templates/clusterrolebinding.yaml @@ -0,0 +1,15 @@ +{{- if .Values.managedServiceAccount }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: message-gateway-c-role-binding +subjects: +- kind: ServiceAccount + name: message-gateway # name of your service account + namespace: {{ .Release.Namespace }} # this is the namespace your service account is in +roleRef: # referring to your ClusterRole + kind: ClusterRole + name: message-gateway-c-role + apiGroup: rbac.authorization.k8s.io + +{{- end -}} \ No newline at end of file diff --git a/ph-ee-env-template/helm/ph-ee-engine/message-gateway/templates/deployment.yaml b/ph-ee-env-template/helm/ph-ee-engine/message-gateway/templates/deployment.yaml new file mode 100644 index 000000000..e91547f74 --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/message-gateway/templates/deployment.yaml @@ -0,0 +1,110 @@ +{{- if .Values.enabled -}} + +apiVersion: apps/v1 +kind: Deployment +metadata: + name: message-gateway + labels: + app: message-gateway +spec: + replicas: {{ .Values.replicas }} + selector: + matchLabels: + app: message-gateway + template: + metadata: + labels: + app: message-gateway + annotations: +{{- if .Values.deployment.annotations }} +{{ toYaml .Values.deployment.annotations | indent 8 }} +{{- end }} + spec: + initContainers: + #During this Pod's initialization, check that zeebe-gateway service is up and running before starting this pod + - name: check-zeebe-gateway-ready + image: busybox:latest + command: [ 'sh', '-c','until nc -vz {{ .Release.Name }}-zeebe-gateway 26500; do echo "Waiting for zeebe-gateway service"; sleep 2; done;' ] + containers: + - name: message-gateway + image: "{{ .Values.image }}" + ports: + - containerPort: 9191 + imagePullPolicy: "{{ .Values.global.imagePullPolicy }}" + resources: + limits: + memory: "{{ .Values.limits.memory }}" + cpu: "{{ .Values.limits.cpu }}" + requests: + memory: "{{ .Values.requests.memory }}" + cpu: "{{ .Values.requests.cpu }}" + livenessProbe: + httpGet: + path: /actuator/health/liveness + port: 9191 + initialDelaySeconds: {{.Values.livenessProbe.initialDelaySeconds}} + periodSeconds: {{.Values.livenessProbe.periodSeconds}} + readinessProbe: + httpGet: + path: /actuator/health/readiness + port: 9191 + initialDelaySeconds: {{.Values.readinessProbe.initialDelaySeconds}} + periodSeconds: {{.Values.readinessProbe.periodSeconds}} + + env: + - name: "SPRING_DATASOURCE_URL" + value: "{{ .Values.DATASOURCE_URL }}" + - name: "MYSQL_USERNAME" + value: "{{ .Values.MYSQL_USERNAME }}" + - name: "ZEEBE_BROKER_CONTACTPOINT" + value: "{{ .Release.Name }}-zeebe-gateway:26500" + - name: "MYSQL_PASSWORD" + valueFrom: + secretKeyRef: + name: "messagegateway-secret" + key: "database-password" + - name: "CALLBACKCONFIG_HOST" + value: "{{ .Values.CALLBACKCONFIG_HOST }}" + - name: "HOSTCONFIG_HOST" + value: "{{ .Values.HOSTCONFIG_HOST }}" + - name: "PROVIDERSOURCE_FROMDATABASE" + value: "{{ .Values.PROVIDERSOURCE_FROMDATABASE }}" + - name: "PROVIDERSOURCE_FROMYML" + value: "{{ .Values.PROVIDERSOURCE_FROMYML }}" + - name: "LOGGING_LEVEL_ROOT" + value: "{{ .Values.global.LOGGING_LEVEL_ROOT }}" + - name: "PROVIDERKEYS_TELERIVETAPIKEY" + valueFrom: + secretKeyRef: + name: "messagegateway-secret" + key: "api-key" + - name: "PROVIDERKEYS_TELERIVETPROJECTID" + valueFrom: + secretKeyRef: + name: "messagegateway-secret" + key: "project-id" + - name : "ZEEBE_BROKER_CONTACTPOINT" + value: "{{ .Release.Name }}-zeebe-gateway:26500" + +{{- if .Values.extraEnvs | default .Values.deployment.extraEnvs }} +{{ toYaml ( .Values.extraEnvs | default .Values.deployment.extraEnvs ) | indent 10 }} +{{- end }} + envFrom: {{ toYaml ( .Values.envFrom | default .Values.deployment.envFrom ) | nindent 12 }} + securityContext: {{ toYaml ( .Values.podSecurityContext | default .Values.deployment.securityContext ) | nindent 12 }} + + volumeMounts: + - name: ph-ee-config + mountPath: "/config" + initContainers: + - name: wait-db + image: jwilder/dockerize + imagePullPolicy: IfNotPresent + args: + - -timeout=120s + - -wait + - tcp://{{ .Values.operations_app.datasource.host }}:3306 + volumes: + - name: ph-ee-config + configMap: + name: ph-ee-config +{{- end }} diff --git a/ph-ee-env-template/helm/ph-ee-engine/message-gateway/templates/ingress.yaml b/ph-ee-env-template/helm/ph-ee-engine/message-gateway/templates/ingress.yaml new file mode 100644 index 000000000..38ca6b903 --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/message-gateway/templates/ingress.yaml @@ -0,0 +1,49 @@ +{{- if .Values.ingress.enabled -}} +{{- $pathtype := .Values.ingress.pathtype -}} +{{- $ingressPath := .Values.ingress.path -}} +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: message-gateway + labels: + app: {{ .Chart.Name }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +{{- with .Values.ingress.annotations }} + annotations: +{{ toYaml . | indent 4 }} +{{- end }} +spec: + {{- if .Values.ingress.className }} + ingressClassName: {{ .Values.ingress.className | quote }} + {{- end }} +{{- if .Values.ingress.tls }} + tls: + {{- if .ingressPath }} + {{- range .Values.ingress.tls }} + - hosts: + {{- range .hosts }} + - {{ . }} + {{- end }} + secretName: {{ .secretName }} + {{- end }} +{{- else }} +{{ toYaml .Values.ingress.tls | indent 4 }} + {{- end }} +{{- end}} + rules: + {{- range .Values.ingress.hosts }} + - host: {{ .host }} + http: + paths: + {{- range .paths }} + - path: {{ .path }} + pathType: {{ $pathtype }} + backend: + service: + name: {{ .backend.service.name}} + port: + number: {{ .backend.service.port.number}} + {{- end }} + {{- end }} + {{- end }} diff --git a/ph-ee-env-template/helm/ph-ee-engine/message-gateway/templates/role.yaml b/ph-ee-env-template/helm/ph-ee-engine/message-gateway/templates/role.yaml new file mode 100644 index 000000000..786156aab --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/message-gateway/templates/role.yaml @@ -0,0 +1,14 @@ +{{- if .Values.managedServiceAccount }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: message-gateway-role + namespace: {{ .Release.Namespace }} +rules: +- apiGroups: + - "" + resources: + - pods + - configmaps + verbs: ["get", "create", "update"] +{{- end -}} \ No newline at end of file diff --git a/ph-ee-env-template/helm/ph-ee-engine/message-gateway/templates/rolebinding.yaml b/ph-ee-env-template/helm/ph-ee-engine/message-gateway/templates/rolebinding.yaml new file mode 100644 index 000000000..0da8a9717 --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/message-gateway/templates/rolebinding.yaml @@ -0,0 +1,15 @@ +{{- if .Values.managedServiceAccount }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: message-gateway-role-binding + namespace: {{ .Release.Namespace }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: message-gateway-role +subjects: +- kind: ServiceAccount + name: message-gateway + namespace: {{ .Release.Namespace }} +{{- end -}} \ No newline at end of file diff --git a/ph-ee-env-template/helm/ph-ee-engine/message-gateway/templates/secret.yaml b/ph-ee-env-template/helm/ph-ee-engine/message-gateway/templates/secret.yaml new file mode 100644 index 000000000..e1b83ac8d --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/message-gateway/templates/secret.yaml @@ -0,0 +1,11 @@ +{{- if .Values.enabled -}} +apiVersion: {{ .Values.secret.apiversion }} +kind: Secret +metadata: + name: messagegateway-secret +type: Opaque +data: + api-key: "{{ .Values.secret.value.api_key | b64enc }}" + project-id: "{{ .Values.secret.value.project_id | b64enc }}" + database-password: "{{ .Values.MYSQL_PASSWORD | b64enc }}" +{{- end }} \ No newline at end of file diff --git a/ph-ee-env-template/helm/ph-ee-engine/message-gateway/templates/service.yaml b/ph-ee-env-template/helm/ph-ee-engine/message-gateway/templates/service.yaml new file mode 100644 index 000000000..c9f412f5d --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/message-gateway/templates/service.yaml @@ -0,0 +1,18 @@ +{{- if .Values.enabled -}} +apiVersion: {{ .Values.service.apiversion }} +kind: Service +metadata: + labels: + app: message-gateway + name: message-gateway +spec: + ports: + - name: port + port: 80 + protocol: TCP + targetPort: 9191 + selector: + app: message-gateway + sessionAffinity: None + type: ClusterIP +{{- end }} \ No newline at end of file diff --git a/ph-ee-env-template/helm/ph-ee-engine/message-gateway/templates/serviceaccount.yaml b/ph-ee-env-template/helm/ph-ee-engine/message-gateway/templates/serviceaccount.yaml new file mode 100644 index 000000000..768f10c15 --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/message-gateway/templates/serviceaccount.yaml @@ -0,0 +1,15 @@ +{{- if .Values.managedServiceAccount }} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: message-gateway + annotations: + {{- with .Values.serviceAccountAnnotations }} + {{- toYaml . | nindent 4 }} + {{- end }} + labels: + app: message-gateway + chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" + heritage: {{ .Release.Service | quote }} + release: {{ .Release.Name | quote }} +{{- end -}} \ No newline at end of file diff --git a/ph-ee-env-template/helm/ph-ee-engine/message-gateway/values.yaml b/ph-ee-env-template/helm/ph-ee-engine/message-gateway/values.yaml new file mode 100644 index 000000000..ee263fe4b --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/message-gateway/values.yaml @@ -0,0 +1,57 @@ +service: + apiversion: "v1" + +configmap: + apiversion: "v1" + +enabled: true +image: "" +imageTag: "" +secret: + apiversion: "v1" + value: + api_key: "" + project_id: "" +CALLBACKCONFIG_HOST: "ph-ee-connector-notifications" +HOSTCONFIG_HOST: "message-gateway" +MYSQL_USERNAME: "mifos" +MYSQL_PASSWORD: "password" +DATASOURCE_URL: jdbc:mysql:thin://operationsmysql:3306/messagegateway +PROVIDERSOURCE_FROMDATABASE: "disabled" +PROVIDERSOURCE_FROMYML: "enabled" +limits: + cpu: "500m" + memory: "512M" +requests: + cpu: "100m" + memory: "256M" +# Enabling this will publicly expose your Elasticsearch instance. +# Only enable this if you have security enabled on your cluster +ingress: + enabled: false + annotations: {} + # kubernetes.io/ingress.class: "nginx" + pathtype: ImplementationSpecific + hosts: + - host: "" + paths: + - path: / + tls: [] + # - secretName: sandbox-secret + # hosts: + # - chart-example.local +deployment: + apiVersion: "apps/v1" + annotations: + deployTime: "{{ .Values.deployTime }}" + +operations_app: + datasource: + host: "operationsmysql" + +livenessProbe: + initialDelaySeconds: 20 + periodSeconds: 30 +readinessProbe: + initialDelaySeconds: 20 + periodSeconds: 30 diff --git a/ph-ee-env-template/helm/ph-ee-engine/operations-app/Chart.yaml b/ph-ee-env-template/helm/ph-ee-engine/operations-app/Chart.yaml new file mode 100644 index 000000000..c6edb4134 --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/operations-app/Chart.yaml @@ -0,0 +1,5 @@ +apiVersion: v1 +description: ph-ee-operations-app +name: operations_app +version: 1.0.0 +appVersion: "1.0.0" \ No newline at end of file diff --git a/ph-ee-env-template/helm/ph-ee-engine/operations-app/README.md b/ph-ee-env-template/helm/ph-ee-engine/operations-app/README.md new file mode 100644 index 000000000..e931e10c4 --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/operations-app/README.md @@ -0,0 +1,48 @@ +# operations_app + +![Version: 1.0.0](https://img.shields.io/badge/Version-1.0.0-informational?style=flat-square) ![AppVersion: 1.0.0](https://img.shields.io/badge/AppVersion-1.0.0-informational?style=flat-square) + +ph-ee-operations-app + +## Values + +| Key | Type | Default | Description | +|-----|------|---------|-------------| +| SPRING_PROFILES_ACTIVE | string | `""` | | +| configmap.apiversion | string | `"v1"` | | +| deployment.annotations.deployTime | string | `"{{ .Values.deployTime }}"` | | +| deployment.apiVersion | string | `"apps/v1"` | | +| enabled | bool | `true` | | +| hostname | string | `"ops-bk.sandbox.mifos.io"` | | +| image | string | `""` | | +| imageTag | string | `""` | | +| ingress.annotations."kubernetes.io/ingress.class" | string | `"nginx"` | | +| ingress.annotations."nginx.ingress.kubernetes.io/configuration-snippet" | string | `"more_set_headers \"Access-Control-Allow-Origin: *\";\nmore_set_headers \"Platform-TenantId: *\";\n"` | | +| ingress.annotations."nginx.ingress.kubernetes.io/cors-allow-credentials" | string | `"true"` | | +| ingress.annotations."nginx.ingress.kubernetes.io/cors-allow-headers" | string | `"DNT,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization,Platform-TenantId"` | | +| ingress.annotations."nginx.ingress.kubernetes.io/cors-allow-methods" | string | `"PUT, GET, POST, OPTIONS, DELETE, PATCH"` | | +| ingress.annotations."nginx.ingress.kubernetes.io/enable-cors" | string | `"true"` | | +| ingress.apiversion | string | `"networking.k8s.io/v1"` | | +| ingress.backend.service.name | string | `"ph-ee-operations-app"` | | +| ingress.backend.service.port.number | int | `80` | | +| ingress.className | string | `"kong"` | | +| ingress.enabled | bool | `true` | | +| ingress.path | string | `"/"` | | +| ingress.tls[0].hosts | string | `"ops-bk.sandbox.mifos.io"` | | +| ingress.tls[1].secretName | string | `"sandbox-secret"` | | +| limits.cpu | string | `"500m"` | | +| limits.memory | string | `"512M"` | | +| requests.cpu | string | `"100m"` | | +| requests.memory | string | `"256M"` | | +| secret.apiversion | string | `"v1"` | | +| secret.datasource.host | string | `"operationsmysql"` | | +| secret.datasource.password | string | `"password"` | | +| secret.datasource.port | int | `3306` | | +| secret.datasource.schema | string | `"tenants"` | | +| secret.datasource.username | string | `"mifos"` | | +| service.apiversion | string | `"v1"` | | +| tenants | string | `""` | | +| wildcardhostname | string | `"ops-bk.sandbox.mifos.io"` | | + +---------------------------------------------- +Autogenerated from chart metadata using [helm-docs v1.11.0](https://github.com/norwoodj/helm-docs/releases/v1.11.0) diff --git a/ph-ee-env-template/helm/ph-ee-engine/operations-app/templates/clusterrole.yaml b/ph-ee-env-template/helm/ph-ee-engine/operations-app/templates/clusterrole.yaml new file mode 100644 index 000000000..afd3fa706 --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/operations-app/templates/clusterrole.yaml @@ -0,0 +1,11 @@ +{{- if .Values.managedServiceAccount }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + # "namespace" omitted since ClusterRoles are not namespaced + name: ph-ee-operations-app-c-role +rules: +- apiGroups: [""] + resources: ["secrets"] + verbs: ["get", "watch", "list"] +{{- end -}} \ No newline at end of file diff --git a/ph-ee-env-template/helm/ph-ee-engine/operations-app/templates/clusterrolebinding.yaml b/ph-ee-env-template/helm/ph-ee-engine/operations-app/templates/clusterrolebinding.yaml new file mode 100644 index 000000000..f38ccaeae --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/operations-app/templates/clusterrolebinding.yaml @@ -0,0 +1,15 @@ +{{- if .Values.managedServiceAccount }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: ph-ee-operations-app-c-role-binding +subjects: +- kind: ServiceAccount + name: ph-ee-operations-app # name of your service account + namespace: {{ .Release.Namespace }} # this is the namespace your service account is in +roleRef: # referring to your ClusterRole + kind: ClusterRole + name: ph-ee-operations-app-c-role + apiGroup: rbac.authorization.k8s.io + +{{- end -}} \ No newline at end of file diff --git a/ph-ee-env-template/helm/ph-ee-engine/operations-app/templates/deployment.yaml b/ph-ee-env-template/helm/ph-ee-engine/operations-app/templates/deployment.yaml new file mode 100644 index 000000000..609f87995 --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/operations-app/templates/deployment.yaml @@ -0,0 +1,114 @@ +{{- if .Values.enabled -}} + +apiVersion: apps/v1 +kind: Deployment +metadata: + name: ph-ee-operations-app + labels: + app: ph-ee-operations-app +spec: + replicas: {{ .Values.replicas }} + selector: + matchLabels: + app: ph-ee-operations-app + template: + metadata: + labels: + app: ph-ee-operations-app + annotations: +{{- if .Values.deployment.annotations }} +{{ toYaml .Values.deployment.annotations | indent 8 }} +{{- end }} + spec: + initContainers: + #During this Pod's initialization, check that operationsmysql service is up and running before starting this pod + - name: check-operationsmysql-ready + image: busybox:latest + command: [ 'sh', '-c','until nc -vz operationsmysql 3306; do echo "Waiting for operationsmysql service"; sleep 2; done;' ] + terminationGracePeriodSeconds: {{ .Values.terminationGracePeriod }} + containers: + - name: ph-ee-operations-app + image: "{{ .Values.image }}" + imagePullPolicy: "{{ .Values.global.imagePullPolicy }}" + ports: + - containerPort: 5000 + readinessProbe: + httpGet: + path: /oauth/token_key + port: 5000 + initialDelaySeconds: {{.Values.readinessProbe.initialDelaySeconds}} + periodSeconds: {{.Values.readinessProbe.periodSeconds}} + resources: + limits: + memory: "{{ .Values.limits.memory }}" + cpu: "{{ .Values.limits.cpu }}" + requests: + memory: "{{ .Values.requests.memory }}" + cpu: "{{ .Values.requests.cpu }}" + env: + - name: "FINERACT_DATASOURCE_CORE_USERNAME" + value: "{{ .Values.datasource.username }}" + - name: "FINERACT_DATASOURCE_CORE_PASSWORD" + valueFrom: + secretKeyRef: + name: "operations-app-secret" + key: "database-password" + - name: "FINERACT_DATASOURCE_CORE_HOST" + value: "{{ .Values.datasource.host }}" + - name: "FINERACT_DATASOURCE_CORE_PORT" + value: "{{ .Values.datasource.port }}" + - name: "FINERACT_DATASOURCE_CORE_SCHEMA" + value: "{{ .Values.datasource.schema }}" + - name: "SPRING_PROFILES_ACTIVE" + value: "{{ .Values.global.SPRING_PROFILES_ACTIVE }}" + - name: "CLOUD_AWS_MINIO_PUBLIC_HOST" + value: "{{ .Values.minio_public_host}}" + - name: "TOKEN_CLIENT_CHANNEL_SECRET" + value: "{{ .Values.token_client_channel_secret }}" + - name: "TENANTS" + value: "{{ .Values.global.tenants }}" + - name: "AWS_ACCESS_KEY" + valueFrom: + secretKeyRef: + name: bulk-processor-secret + key: aws-access-key + - name: "AWS_SECRET_KEY" + valueFrom: + secretKeyRef: + name: bulk-processor-secret + key: aws-secret-key + - name: "CLOUD_AWS_REGION" + valueFrom: + secretKeyRef: + name: "bulk-processor-secret" + key: "aws-region" + - name: "CLOUD_AWS_S3BASEURL" + value: {{.Values.global.s3BaseUrl}} + - name: "APPLICATION_BUCKET_NAME" + value: "{{ .Values.global.bucket_name }}" + - name: "LOGGING_LEVEL_ROOT" + value: "{{ .Values.global.LOGGING_LEVEL_ROOT }}" + - name: "LOGGING_PATTERN_CONSOLE" + value: "{{ .Values.global.LOGGING_PATTERN_CONSOLE }}" +{{- if .Values.extraEnvs | default .Values.deployment.extraEnvs }} +{{ toYaml ( .Values.extraEnvs | default .Values.deployment.extraEnvs ) | indent 10 }} +{{- end }} + envFrom: {{ toYaml ( .Values.envFrom | default .Values.deployment.envFrom ) | nindent 12 }} + securityContext: {{ toYaml ( .Values.podSecurityContext | default .Values.deployment.securityContext ) | nindent 12 }} + + volumeMounts: + - name: ph-ee-config + mountPath: "/config" + initContainers: + - name: wait-db + image: jwilder/dockerize + imagePullPolicy: IfNotPresent + args: + - -timeout=120s + - -wait + - tcp://{{ .Values.secret.datasource.host }}:3306 + volumes: + - name: ph-ee-config + configMap: + name: ph-ee-config +{{- end }} diff --git a/ph-ee-env-template/helm/ph-ee-engine/operations-app/templates/ingress.yaml b/ph-ee-env-template/helm/ph-ee-engine/operations-app/templates/ingress.yaml new file mode 100644 index 000000000..f674027f3 --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/operations-app/templates/ingress.yaml @@ -0,0 +1,49 @@ +{{- if .Values.ingress.enabled -}} +{{- $pathtype := .Values.ingress.pathtype -}} +{{- $ingressPath := .Values.ingress.path -}} +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: ph-ee-operations-app + labels: + app: {{ .Chart.Name }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +{{- with .Values.ingress.annotations }} + annotations: +{{ toYaml . | indent 4 }} +{{- end }} +spec: + {{- if .Values.ingress.className }} + ingressClassName: {{ .Values.ingress.className | quote }} + {{- end }} +{{- if .Values.ingress.tls }} + tls: + {{- if .ingressPath }} + {{- range .Values.ingress.tls }} + - hosts: + {{- range .hosts }} + - {{ . }} + {{- end }} + secretName: {{ .secretName }} + {{- end }} +{{- else }} +{{ toYaml .Values.ingress.tls | indent 4 }} + {{- end }} +{{- end}} + rules: + {{- range .Values.ingress.hosts }} + - host: {{ .host }} + http: + paths: + {{- range .paths }} + - path: {{ .path }} + pathType: {{ $pathtype }} + backend: + service: + name: {{ .backend.service.name}} + port: + number: {{ .backend.service.port.number}} + {{- end }} + {{- end }} + {{- end }} diff --git a/ph-ee-env-template/helm/ph-ee-engine/operations-app/templates/role.yaml b/ph-ee-env-template/helm/ph-ee-engine/operations-app/templates/role.yaml new file mode 100644 index 000000000..6e3963b3e --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/operations-app/templates/role.yaml @@ -0,0 +1,14 @@ +{{- if .Values.managedServiceAccount }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: ph-ee-operations-app-role + namespace: {{ .Release.Namespace }} +rules: +- apiGroups: + - "" + resources: + - pods + - configmaps + verbs: ["get", "create", "update"] +{{- end -}} \ No newline at end of file diff --git a/ph-ee-env-template/helm/ph-ee-engine/operations-app/templates/rolebinding.yaml b/ph-ee-env-template/helm/ph-ee-engine/operations-app/templates/rolebinding.yaml new file mode 100644 index 000000000..c5a24ef3c --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/operations-app/templates/rolebinding.yaml @@ -0,0 +1,15 @@ +{{- if .Values.managedServiceAccount }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: ph-ee-operations-app-role-binding + namespace: {{ .Release.Namespace }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: ph-ee-operations-app-role +subjects: +- kind: ServiceAccount + name: ph-ee-operations-app + namespace: {{ .Release.Namespace }} +{{- end -}} \ No newline at end of file diff --git a/ph-ee-env-template/helm/ph-ee-engine/operations-app/templates/secret.yaml b/ph-ee-env-template/helm/ph-ee-engine/operations-app/templates/secret.yaml new file mode 100644 index 000000000..6d2f1932c --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/operations-app/templates/secret.yaml @@ -0,0 +1,9 @@ +{{- if .Values.enabled -}} +apiVersion: {{ .Values.secret.apiversion }} +kind: Secret +metadata: + name: operations-app-secret +type: Opaque +data: + database-password: {{ .Values.datasource.password | b64enc }} +{{- end }} \ No newline at end of file diff --git a/ph-ee-env-template/helm/ph-ee-engine/operations-app/templates/service.yaml b/ph-ee-env-template/helm/ph-ee-engine/operations-app/templates/service.yaml new file mode 100644 index 000000000..60fcc7fb4 --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/operations-app/templates/service.yaml @@ -0,0 +1,18 @@ +{{- if .Values.enabled -}} +apiVersion: {{ .Values.service.apiversion }} +kind: Service +metadata: + labels: + app: ph-ee-operations-app + name: ph-ee-operations-app +spec: + ports: + - name: port + port: 80 + protocol: TCP + targetPort: 5000 + selector: + app: ph-ee-operations-app + sessionAffinity: None + type: ClusterIP +{{- end }} \ No newline at end of file diff --git a/ph-ee-env-template/helm/ph-ee-engine/operations-app/templates/serviceaccount.yaml b/ph-ee-env-template/helm/ph-ee-engine/operations-app/templates/serviceaccount.yaml new file mode 100644 index 000000000..e08d65c56 --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/operations-app/templates/serviceaccount.yaml @@ -0,0 +1,15 @@ +{{- if .Values.managedServiceAccount }} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: ph-ee-operations-app + annotations: + {{- with .Values.serviceAccountAnnotations }} + {{- toYaml . | nindent 4 }} + {{- end }} + labels: + app: ph-ee-operations-app + chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" + heritage: {{ .Release.Service | quote }} + release: {{ .Release.Name | quote }} +{{- end -}} \ No newline at end of file diff --git a/ph-ee-env-template/helm/ph-ee-engine/operations-app/values.yaml b/ph-ee-env-template/helm/ph-ee-engine/operations-app/values.yaml new file mode 100644 index 000000000..b1b13f4b7 --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/operations-app/values.yaml @@ -0,0 +1,52 @@ +service: + apiversion: "v1" + +configmap: + apiversion: "v1" + +enabled: true +image: "" +imageTag: "" +SPRING_PROFILES_ACTIVE: "" +tenants: "" +secret: + apiversion: "v1" + datasource: + username: "mifos" + password: "password" + host: "operationsmysql" + port: 3306 + schema: "tenants" +limits: + cpu: "500m" + memory: "512M" +requests: + cpu: "100m" + memory: "256M" +# Enabling this will publicly expose your Elasticsearch instance. +# Only enable this if you have security enabled on your cluster +ingress: + enabled: false + annotations: {} + # kubernetes.io/ingress.class: "nginx" + pathtype: ImplementationSpecific + hosts: + - host: "" + paths: + - path: / + tls: [] + # - secretName: sandbox-secret + # hosts: + # - chart-example.local +minio_public_host: "" +deployment: + apiVersion: "apps/v1" + annotations: + deployTime: "{{ .Values.deployTime }}" + +livenessProbe: + initialDelaySeconds: 20 + periodSeconds: 30 +readinessProbe: + initialDelaySeconds: 20 + periodSeconds: 30 diff --git a/ph-ee-env-template/helm/ph-ee-engine/operations-importer-es/Chart.yaml b/ph-ee-env-template/helm/ph-ee-engine/operations-importer-es/Chart.yaml new file mode 100644 index 000000000..ff2710575 --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/operations-importer-es/Chart.yaml @@ -0,0 +1,5 @@ +apiVersion: v1 +description: ph-ee-importer-es +name: importer_es +version: 1.0.0 +appVersion: "1.0.0" \ No newline at end of file diff --git a/ph-ee-env-template/helm/ph-ee-engine/operations-importer-es/README.md b/ph-ee-env-template/helm/ph-ee-engine/operations-importer-es/README.md new file mode 100644 index 000000000..c444cd2e8 --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/operations-importer-es/README.md @@ -0,0 +1,63 @@ +# importer_es + +![Version: 1.0.0](https://img.shields.io/badge/Version-1.0.0-informational?style=flat-square) ![AppVersion: 1.0.0](https://img.shields.io/badge/AppVersion-1.0.0-informational?style=flat-square) + +ph-ee-importer-es + +## Values + +| Key | Type | Default | Description | +|-----|------|---------|-------------| +| configmap.apiversion | string | `"v1"` | | +| deployment.apiVersion | string | `"apps/v1"` | | +| elasticsearch_security_enabled | bool | `false` | | +| elasticsearch_sslverification | bool | `false` | | +| enabled | bool | `true` | | +| image | string | `""` | | +| imageTag | string | `"latest"` | | +| importer_elasticsearch_url | string | `"http://ph-ee-elasticsearch:9200/"` | | +| ingress.apiversion | string | `"networking.k8s.io/v1"` | | +| javaToolOptions | string | `nil` | | +| limits.cpu | string | `"500m"` | | +| limits.memory | string | `"512M"` | | +| logging.level.root | string | `"INFO"` | | +| logging.pattern.console | string | `"%d{dd-MM-yyyy HH:mm:ss.SSS} %magenta([%thread]) %highlight(%-5level) %logger.%M - %msg%n"` | | +| reporting.enabled | bool | `true` | | +| reporting.fields.accountId | bool | `true` | | +| reporting.fields.amount | bool | `true` | | +| reporting.fields.ams | bool | `true` | | +| reporting.fields.clientCorrelationId | bool | `true` | | +| reporting.fields.confirmationReceived | bool | `true` | | +| reporting.fields.currency | bool | `true` | | +| reporting.fields.customData | bool | `true` | | +| reporting.fields.errorCode | bool | `false` | | +| reporting.fields.errorDescription | bool | `true` | | +| reporting.fields.errorInformation | bool | `true` | | +| reporting.fields.externalId | bool | `true` | | +| reporting.fields.initiator | bool | `false` | | +| reporting.fields.initiatorType | bool | `false` | | +| reporting.fields.isNotificationsFailureEnabled | bool | `false` | | +| reporting.fields.isNotificationsSuccessEnabled | bool | `false` | | +| reporting.fields.mpesaTransactionId | bool | `false` | | +| reporting.fields.mpesaTransactionStatusRetryCount | bool | `false` | | +| reporting.fields.originDate | bool | `false` | | +| reporting.fields.partyLookupFailed | bool | `false` | | +| reporting.fields.phoneNumber | bool | `true` | | +| reporting.fields.processDefinitionKey | bool | `false` | | +| reporting.fields.processInstanceKey | bool | `true` | | +| reporting.fields.scenario | bool | `false` | | +| reporting.fields.tenantId | bool | `false` | | +| reporting.fields.timer | bool | `false` | | +| reporting.fields.timestamp | bool | `true` | | +| reporting.fields.transactionFailed | bool | `false` | | +| reporting.fields.transactionId | bool | `false` | | +| reporting.fields.transferCreateFailed | bool | `false` | | +| reporting.fields.transferResponseCREATE | bool | `false` | | +| reporting.fields.transferSettlementFailed | bool | `false` | | +| requests.cpu | string | `"100m"` | | +| requests.memory | string | `"256M"` | | +| secret.apiversion | string | `"v1"` | | +| service.apiversion | string | `"v1"` | | + +---------------------------------------------- +Autogenerated from chart metadata using [helm-docs v1.11.0](https://github.com/norwoodj/helm-docs/releases/v1.11.0) diff --git a/ph-ee-env-template/helm/ph-ee-engine/operations-importer-es/templates/clusterrole.yaml b/ph-ee-env-template/helm/ph-ee-engine/operations-importer-es/templates/clusterrole.yaml new file mode 100644 index 000000000..05858f64a --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/operations-importer-es/templates/clusterrole.yaml @@ -0,0 +1,11 @@ +{{- if .Values.managedServiceAccount }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + # "namespace" omitted since ClusterRoles are not namespaced + name: ph-ee-importer-es-c-role +rules: +- apiGroups: [""] + resources: ["secrets"] + verbs: ["get", "watch", "list"] +{{- end -}} \ No newline at end of file diff --git a/ph-ee-env-template/helm/ph-ee-engine/operations-importer-es/templates/clusterrolebinding.yaml b/ph-ee-env-template/helm/ph-ee-engine/operations-importer-es/templates/clusterrolebinding.yaml new file mode 100644 index 000000000..05ac79462 --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/operations-importer-es/templates/clusterrolebinding.yaml @@ -0,0 +1,15 @@ +{{- if .Values.managedServiceAccount }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: ph-ee-importer-es-c-role-binding +subjects: +- kind: ServiceAccount + name: ph-ee-importer-es # name of your service account + namespace: {{ .Release.Namespace }} # this is the namespace your service account is in +roleRef: # referring to your ClusterRole + kind: ClusterRole + name: ph-ee-importer-es-c-role + apiGroup: rbac.authorization.k8s.io + +{{- end -}} \ No newline at end of file diff --git a/ph-ee-env-template/helm/ph-ee-engine/operations-importer-es/templates/deployment.yaml b/ph-ee-env-template/helm/ph-ee-engine/operations-importer-es/templates/deployment.yaml new file mode 100644 index 000000000..c821c0f79 --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/operations-importer-es/templates/deployment.yaml @@ -0,0 +1,129 @@ +{{- if .Values.enabled -}} + +apiVersion: apps/v1 +kind: Deployment +metadata: + name: ph-ee-importer-es + labels: + app: ph-ee-importer-es +spec: + replicas: {{ .Values.replicas }} + selector: + matchLabels: + app: ph-ee-importer-es + template: + metadata: + labels: + app: ph-ee-importer-es + spec: + initContainers: + #During this Pod's initialization, check that ph-ee-elasticsearch service is up and running before starting this pod + - name: check-ph-ee-elasticsearch-ready + image: busybox:latest + command: [ 'sh', '-c','until nc -vz ph-ee-elasticsearch 9200; do echo "Waiting for ph-ee-elasticsearch service"; sleep 2; done;' ] + containers: + - name: ph-ee-importer-es + image: "{{ .Values.image }}" + imagePullPolicy: "{{ .Values.global.imagePullPolicy }}" + resources: + limits: + memory: "{{ .Values.limits.memory }}" + cpu: "{{ .Values.limits.cpu }}" + requests: + memory: "{{ .Values.requests.memory }}" + cpu: "{{ .Values.requests.cpu }}" + env: + - name: "reporting.enabled" + value: "{{ .Values.reporting.enabled }}" + - name: "LOGGING_LEVEL_ROOT" + value: "{{ .Values.global.LOGGING_LEVEL_ROOT }}" + - name: "importer_elasticsearch_url" + value: "{{ .Values.importer_elasticsearch_url }}" + - name: "JAVA_TOOL_OPTIONS" + value: "{{ .Values.javaToolOptions}}" + - name: "LOGGING_PATTERN_CONSOLE" + value: "{{ .Values.global.LOGGING_PATTERN_CONSOLE}}" + - name: "reporting.fields.amount" + value: "{{ .Values.reporting.fields.amount }}" + - name: "reporting.fields.accountId" + value: "{{ .Values.reporting.fields.accountId }}" + - name: "reporting.fields.errorCode" + value: "{{ .Values.reporting.fields.errorCode }}" + - name: "reporting.fields.errorDescription" + value: "{{ .Values.reporting.fields.errorDescription }}" + - name: "reporting.fields.externalId" + value: "{{ .Values.reporting.fields.externalId }}" + - name: "reporting.fields.initiator" + value: "{{ .Values.reporting.fields.initiator }}" + - name: "reporting.fields.initiatorType" + value: "{{ .Values.reporting.fields.initiatorType }}" + - name: "reporting.fields.isNotificationsFailureEnabled" + value: "{{ .Values.reporting.fields.isNotificationsFailureEnabled }}" + - name: "reporting.fields.isNotificationsSuccessEnabled" + value: "{{ .Values.reporting.fields.isNotificationsSuccessEnabled }}" + - name: "reporting.fields.mpesaTransactionId" + value: "{{ .Values.reporting.fields.mpesaTransactionId }}" + - name: "reporting.fields.mpesaTransactionStatusRetryCount" + value: "{{ .Values.reporting.fields.mpesaTransactionStatusRetryCount }}" + - name: "reporting.fields.originDate" + value: "{{ .Values.reporting.fields.originDate }}" + - name: "reporting.fields.partyLookupFailed" + value: "{{ .Values.reporting.fields.partyLookupFailed }}" + - name: "reporting.fields.phoneNumber" + value: "{{ .Values.reporting.fields.phoneNumber }}" + - name: "reporting.fields.processDefinitionKey" + value: "{{ .Values.reporting.fields.processDefinitionKey }}" + - name: "reporting.fields.processInstanceKey" + value: "{{ .Values.reporting.fields.processInstanceKey }}" + - name: "reporting.fields.scenario" + value: "{{ .Values.reporting.fields.scenario }}" + - name: "reporting.fields.tenantId" + value: "{{ .Values.reporting.fields.tenantId }}" + - name: "reporting.fields.timer" + value: "{{ .Values.reporting.fields.timer }}" + - name: "reporting.fields.timestamp" + value: "{{ .Values.reporting.fields.timestamp }}" + - name: "reporting.fields.transactionFailed" + value: "{{ .Values.reporting.fields.transactionFailed }}" + - name: "reporting.fields.transactionId" + value: "{{ .Values.reporting.fields.transactionId }}" + - name: "reporting.fields.transferCreateFailed" + value: "{{ .Values.reporting.fields.transferCreateFailed }}" + - name: "reporting.fields.transferSettlementFailed" + value: "{{ .Values.reporting.fields.transferSettlementFailed }}" + - name: "reporting.fields.transferResponseCREATE" + value: "{{ .Values.reporting.fields.transferResponseCREATE }}" + - name: "reporting.fields.ams" + value: "{{ .Values.reporting.fields.ams }}" + - name: "reporting.fields.currency" + value: "{{ .Values.reporting.fields.currency }}" + - name: "reporting.fields.clientCorrelationId" + value: "{{ .Values.reporting.fields.clientCorrelationId }}" + - name: "reporting.fields.errorInformation" + value: "{{ .Values.reporting.fields.errorInformation }}" + - name: "reporting.fields.customData" + value: "{{ .Values.reporting.fields.customData }}" + - name: "reporting.fields.confirmationReceived" + value: "{{ .Values.reporting.fields.confirmationReceived }}" + - name: "ELASTICSEARCH_SECURITY_ENABLED" + value: "{{ .Values.elasticsearch_security_enabled }}" + - name: "ELASTICSEARCH_SSLVERIFICATION" + value: "{{ .Values.elasticsearch_sslverification }}" + - name: "ELASTICSEARCH_USERNAME" + valueFrom: + secretKeyRef: + name: elastic-credentials + key: username + - name: "ELASTICSEARCH_PASSWORD" + valueFrom: + secretKeyRef: + name: elastic-credentials + key: password +{{- if .Values.extraEnvs | default .Values.deployment.extraEnvs }} +{{ toYaml ( .Values.extraEnvs | default .Values.deployment.extraEnvs ) | indent 10 }} +{{- end }} + envFrom: {{ toYaml ( .Values.envFrom | default .Values.deployment.envFrom ) | nindent 12 }} + securityContext: {{ toYaml ( .Values.podSecurityContext | default .Values.deployment.securityContext ) | nindent 12 }} + + +{{- end }} diff --git a/ph-ee-env-template/helm/ph-ee-engine/operations-importer-es/templates/role.yaml b/ph-ee-env-template/helm/ph-ee-engine/operations-importer-es/templates/role.yaml new file mode 100644 index 000000000..c28bb2b7c --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/operations-importer-es/templates/role.yaml @@ -0,0 +1,14 @@ +{{- if .Values.managedServiceAccount }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: ph-ee-importer-es-role + namespace: {{ .Release.Namespace }} +rules: +- apiGroups: + - "" + resources: + - pods + - configmaps + verbs: ["get", "create", "update"] +{{- end -}} \ No newline at end of file diff --git a/ph-ee-env-template/helm/ph-ee-engine/operations-importer-es/templates/rolebinding.yaml b/ph-ee-env-template/helm/ph-ee-engine/operations-importer-es/templates/rolebinding.yaml new file mode 100644 index 000000000..61cdcb9ca --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/operations-importer-es/templates/rolebinding.yaml @@ -0,0 +1,15 @@ +{{- if .Values.managedServiceAccount }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: ph-ee-importer-es-role-binding + namespace: {{ .Release.Namespace }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: ph-ee-importer-es-role +subjects: +- kind: ServiceAccount + name: ph-ee-importer-es + namespace: {{ .Release.Namespace }} +{{- end -}} \ No newline at end of file diff --git a/ph-ee-env-template/helm/ph-ee-engine/operations-importer-es/templates/serviceaccount.yaml b/ph-ee-env-template/helm/ph-ee-engine/operations-importer-es/templates/serviceaccount.yaml new file mode 100644 index 000000000..3963b2eea --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/operations-importer-es/templates/serviceaccount.yaml @@ -0,0 +1,15 @@ +{{- if .Values.managedServiceAccount }} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: ph-ee-importer-es + annotations: + {{- with .Values.serviceAccountAnnotations }} + {{- toYaml . | nindent 4 }} + {{- end }} + labels: + app: ph-ee-importer-es + chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" + heritage: {{ .Release.Service | quote }} + release: {{ .Release.Name | quote }} +{{- end -}} \ No newline at end of file diff --git a/ph-ee-env-template/helm/ph-ee-engine/operations-importer-es/values.yaml b/ph-ee-env-template/helm/ph-ee-engine/operations-importer-es/values.yaml new file mode 100644 index 000000000..f9652cd20 --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/operations-importer-es/values.yaml @@ -0,0 +1,67 @@ +deployment: + apiVersion: "apps/v1" + +ingress: + apiversion: networking.k8s.io/v1 + +service: + apiversion: "v1" + +secret: + apiversion: "v1" + +configmap: + apiversion: "v1" + +enabled: true +image: "" +imageTag: latest +elasticsearch_sslverification: false +elasticsearch_security_enabled: false +importer_elasticsearch_url: "http://ph-ee-elasticsearch:9200/" +javaToolOptions: +logging: + level: + root: "INFO" + pattern: + console: "%d{dd-MM-yyyy HH:mm:ss.SSS} %magenta([%thread]) %highlight(%-5level) %logger.%M - %msg%n" +reporting: + enabled: true + fields: + amount: true + accountId: true + ams: true + clientCorrelationId: true + currency: true + customData: true + confirmationReceived: true + errorInformation: true + errorCode: false + errorDescription: true + externalId: true + initiator: false + initiatorType: false + isNotificationsFailureEnabled: false + isNotificationsSuccessEnabled: false + mpesaTransactionId: false + mpesaTransactionStatusRetryCount: false + originDate: false + partyLookupFailed: false + phoneNumber: true + processDefinitionKey: false + processInstanceKey: true + scenario: false + tenantId: false + timer: false + timestamp: true + transactionFailed: false + transactionId: false + transferCreateFailed: false + transferSettlementFailed: false + transferResponseCREATE: false +limits: + cpu: "500m" + memory: "512M" +requests: + cpu: "100m" + memory: "256M" \ No newline at end of file diff --git a/ph-ee-env-template/helm/ph-ee-engine/operations-importer-rdbms/Chart.yaml b/ph-ee-env-template/helm/ph-ee-engine/operations-importer-rdbms/Chart.yaml new file mode 100644 index 000000000..b4c5cfbba --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/operations-importer-rdbms/Chart.yaml @@ -0,0 +1,5 @@ +apiVersion: v1 +description: operations-importer-rdbms +name: importer_rdbms +version: 1.0.0 +appVersion: "1.0.0" \ No newline at end of file diff --git a/ph-ee-env-template/helm/ph-ee-engine/operations-importer-rdbms/README.md b/ph-ee-env-template/helm/ph-ee-engine/operations-importer-rdbms/README.md new file mode 100644 index 000000000..576af292a --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/operations-importer-rdbms/README.md @@ -0,0 +1,35 @@ +# importer_rdbms + +![Version: 1.0.0](https://img.shields.io/badge/Version-1.0.0-informational?style=flat-square) ![AppVersion: 1.0.0](https://img.shields.io/badge/AppVersion-1.0.0-informational?style=flat-square) + +operations-importer-rdbms + +## Values + +| Key | Type | Default | Description | +|-----|------|---------|-------------| +| LOGGING_LEVEL_ROOT | string | `"INFO"` | | +| LOGGING_PATTERN_CONSOLE | string | `"%d{dd-MM-yyyy HH:mm:ss.SSS} %magenta([%thread]) %highlight(%-5level) %logger.%M - %msg%n"` | | +| configmap.apiversion | string | `"v1"` | | +| datasource.host | string | `"operationsmysql"` | | +| datasource.password | string | `"password"` | | +| datasource.port | int | `3306` | | +| datasource.schema | string | `"tenants"` | | +| datasource.username | string | `"mifos"` | | +| deployment.annotations.deployTime | string | `"{{ .Values.deployTime }}"` | | +| deployment.apiVersion | string | `"apps/v1"` | | +| enabled | bool | `true` | | +| image | string | `""` | | +| imageTag | string | `""` | | +| ingress.apiversion | string | `"networking.k8s.io/v1"` | | +| javaToolOptions | string | `"-Xmx256M"` | | +| limits.cpu | string | `"500m"` | | +| limits.memory | string | `"512M"` | | +| operations.SPRING_PROFILES_ACTIVE | string | `"bb"` | | +| requests.cpu | string | `"100m"` | | +| requests.memory | string | `"256M"` | | +| secret.apiversion | string | `"v1"` | | +| service.apiversion | string | `"v1"` | | + +---------------------------------------------- +Autogenerated from chart metadata using [helm-docs v1.11.0](https://github.com/norwoodj/helm-docs/releases/v1.11.0) diff --git a/ph-ee-env-template/helm/ph-ee-engine/operations-importer-rdbms/templates/clusterrole.yaml b/ph-ee-env-template/helm/ph-ee-engine/operations-importer-rdbms/templates/clusterrole.yaml new file mode 100644 index 000000000..a9778fc74 --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/operations-importer-rdbms/templates/clusterrole.yaml @@ -0,0 +1,11 @@ +{{- if .Values.managedServiceAccount }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + # "namespace" omitted since ClusterRoles are not namespaced + name: ph-ee-importer-rdbms-c-role +rules: +- apiGroups: [""] + resources: ["secrets"] + verbs: ["get", "watch", "list"] +{{- end -}} \ No newline at end of file diff --git a/ph-ee-env-template/helm/ph-ee-engine/operations-importer-rdbms/templates/clusterrolebinding.yaml b/ph-ee-env-template/helm/ph-ee-engine/operations-importer-rdbms/templates/clusterrolebinding.yaml new file mode 100644 index 000000000..f9c8aabeb --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/operations-importer-rdbms/templates/clusterrolebinding.yaml @@ -0,0 +1,15 @@ +{{- if .Values.managedServiceAccount }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: ph-ee-importer-rdbms-c-role-binding +subjects: +- kind: ServiceAccount + name: ph-ee-importer-rdbms # name of your service account + namespace: {{ .Release.Namespace }} # this is the namespace your service account is in +roleRef: # referring to your ClusterRole + kind: ClusterRole + name: ph-ee-importer-rdbms-c-role + apiGroup: rbac.authorization.k8s.io + +{{- end -}} \ No newline at end of file diff --git a/ph-ee-env-template/helm/ph-ee-engine/operations-importer-rdbms/templates/deployment.yaml b/ph-ee-env-template/helm/ph-ee-engine/operations-importer-rdbms/templates/deployment.yaml new file mode 100644 index 000000000..92c5d0203 --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/operations-importer-rdbms/templates/deployment.yaml @@ -0,0 +1,95 @@ +{{- if .Values.enabled -}} + +apiVersion: apps/v1 +kind: Deployment +metadata: + name: ph-ee-importer-rdbms + labels: + app: ph-ee-importer-rdbms +spec: + replicas: {{ .Values.replicas }} + selector: + matchLabels: + app: ph-ee-importer-rdbms + template: + metadata: + labels: + app: ph-ee-importer-rdbms + annotations: +{{- if .Values.deployment.annotations }} +{{ toYaml .Values.deployment.annotations | indent 8 }} +{{- end }} + spec: + initContainers: + #During this Pod's initialization, check that operationsmysql service is up and running before starting this pod + - name: check-operationsmysql-ready + image: busybox:latest + command: [ 'sh', '-c','until nc -vz operationsmysql 3306; do echo "Waiting for operationsmysql service"; sleep 2; done;' ] + containers: + - name: ph-ee-importer-rdbms + image: "{{ .Values.image }}" + imagePullPolicy: "{{ .Values.global.imagePullPolicy }}" + ports: + - containerPort: 8000 + env: + - name: "SPRING_PROFILES_ACTIVE" + value: "{{ .Values.SPRING_PROFILES_ACTIVE }}" + - name: "DATASOURCE_CORE_USERNAME" + value: "{{ .Values.datasource.username }}" + - name: "DATASOURCE_CORE_PASSWORD" + valueFrom: + secretKeyRef: + name: "importer-rdbms-secret" + key: "database-password" + - name: "DATASOURCE_CORE_HOST" + value: "{{ .Values.datasource.host }}" + - name: "DATASOURCE_CORE_PORT" + value: "{{ .Values.datasource.port }}" + - name: "DATASOURCE_CORE_SCHEMA" + value: "{{ .Values.datasource.schema }}" + - name: "LOGGING_LEVEL_ROOT" + value: "{{ .Values.global.LOGGING_LEVEL_ROOT }}" + - name: "LOGGING_PATTERN_CONSOLE" + value: "{{ .Values.global.LOGGING_PATTERN_CONSOLE }}" + - name: "JAVA_TOOL_OPTIONS" + value: "{{ .Values.javaToolOptions}}" + - name: "APPLICATION_BUCKET-NAME" + value: "{{ .Values.global.bucket_name }}" + - name: "CLOUD_AWS_S3BASEURL" + value: {{.Values.global.s3BaseUrl}} + - name: "CLOUD_AWS_REGION_STATIC" + valueFrom: + secretKeyRef: + name: "bulk-processor-secret" + key: "aws-region" + - name: "AWS_ACCESS_KEY" + valueFrom: + secretKeyRef: + name: "bulk-processor-secret" + key: "aws-access-key" + - name: "AWS_SECRET_KEY" + valueFrom: + secretKeyRef: + name: "bulk-processor-secret" + key: "aws-secret-key" +{{- if .Values.extraEnvs | default .Values.deployment.extraEnvs }} +{{ toYaml ( .Values.extraEnvs | default .Values.deployment.extraEnvs ) | indent 10 }} +{{- end }} + envFrom: {{ toYaml ( .Values.envFrom | default .Values.deployment.envFrom ) | nindent 12 }} + securityContext: {{ toYaml ( .Values.podSecurityContext | default .Values.deployment.securityContext ) | nindent 12 }} + + volumeMounts: + - name: ph-ee-config + mountPath: "/config" + resources: + limits: + memory: "{{ .Values.limits.memory }}" + cpu: "{{ .Values.limits.cpu }}" + requests: + memory: "{{ .Values.requests.memory }}" + cpu: "{{ .Values.requests.cpu }}" + volumes: + - name: ph-ee-config + configMap: + name: ph-ee-config +{{- end }} diff --git a/ph-ee-env-template/helm/ph-ee-engine/operations-importer-rdbms/templates/role.yaml b/ph-ee-env-template/helm/ph-ee-engine/operations-importer-rdbms/templates/role.yaml new file mode 100644 index 000000000..628145655 --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/operations-importer-rdbms/templates/role.yaml @@ -0,0 +1,14 @@ +{{- if .Values.managedServiceAccount }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: ph-ee-importer-rdbms-role + namespace: {{ .Release.Namespace }} +rules: +- apiGroups: + - "" + resources: + - pods + - configmaps + verbs: ["get", "create", "update"] +{{- end -}} \ No newline at end of file diff --git a/ph-ee-env-template/helm/ph-ee-engine/operations-importer-rdbms/templates/rolebinding.yaml b/ph-ee-env-template/helm/ph-ee-engine/operations-importer-rdbms/templates/rolebinding.yaml new file mode 100644 index 000000000..e6b449d58 --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/operations-importer-rdbms/templates/rolebinding.yaml @@ -0,0 +1,15 @@ +{{- if .Values.managedServiceAccount }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: ph-ee-importer-rdbms-role-binding + namespace: {{ .Release.Namespace }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: ph-ee-importer-rdbms-role +subjects: +- kind: ServiceAccount + name: ph-ee-importer-rdbms + namespace: {{ .Release.Namespace }} +{{- end -}} \ No newline at end of file diff --git a/ph-ee-env-template/helm/ph-ee-engine/operations-importer-rdbms/templates/secret.yaml b/ph-ee-env-template/helm/ph-ee-engine/operations-importer-rdbms/templates/secret.yaml new file mode 100644 index 000000000..e18eb0ae6 --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/operations-importer-rdbms/templates/secret.yaml @@ -0,0 +1,9 @@ +{{- if .Values.enabled -}} +apiVersion: {{ .Values.secret.apiversion }} +kind: Secret +metadata: + name: importer-rdbms-secret +type: Opaque +data: + database-password: {{ .Values.datasource.password | b64enc }} +{{- end }} \ No newline at end of file diff --git a/ph-ee-env-template/helm/ph-ee-engine/operations-importer-rdbms/templates/serviceaccount.yaml b/ph-ee-env-template/helm/ph-ee-engine/operations-importer-rdbms/templates/serviceaccount.yaml new file mode 100644 index 000000000..4ad0af8e5 --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/operations-importer-rdbms/templates/serviceaccount.yaml @@ -0,0 +1,15 @@ +{{- if .Values.managedServiceAccount }} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: ph-ee-importer-rdbms + annotations: + {{- with .Values.serviceAccountAnnotations }} + {{- toYaml . | nindent 4 }} + {{- end }} + labels: + app: ph-ee-importer-rdbms + chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" + heritage: {{ .Release.Service | quote }} + release: {{ .Release.Name | quote }} +{{- end -}} \ No newline at end of file diff --git a/ph-ee-env-template/helm/ph-ee-engine/operations-importer-rdbms/values.yaml b/ph-ee-env-template/helm/ph-ee-engine/operations-importer-rdbms/values.yaml new file mode 100644 index 000000000..9ffce6122 --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/operations-importer-rdbms/values.yaml @@ -0,0 +1,36 @@ +ingress: + apiversion: networking.k8s.io/v1 + +service: + apiversion: "v1" + +secret: + apiversion: "v1" + +configmap: + apiversion: "v1" + +enabled: true +image: "" +imageTag: "" +LOGGING_LEVEL_ROOT: "INFO" +LOGGING_PATTERN_CONSOLE: "%d{dd-MM-yyyy HH:mm:ss.SSS} %magenta([%thread]) %highlight(%-5level) %logger.%M - %msg%n" +javaToolOptions: "-Xmx256M" +SPRING_PROFILES_ACTIVE: "local,tenantsConnection" +bucket_name: "paymenthub-ee-dev" +limits: + cpu: "500m" + memory: "512M" +requests: + cpu: "100m" + memory: "256M" +datasource: + username: "mifos" + password: "password" + host: "operationsmysql" + port: 3306 + schema: "tenants" +deployment: + apiVersion: "apps/v1" + annotations: + deployTime: "{{ .Values.deployTime }}" diff --git a/ph-ee-env-template/helm/ph-ee-engine/operations-web/Chart.yaml b/ph-ee-env-template/helm/ph-ee-engine/operations-web/Chart.yaml new file mode 100644 index 000000000..f8bb2b28d --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/operations-web/Chart.yaml @@ -0,0 +1,5 @@ +apiVersion: v1 +description: ph-ee-operations-web +name: operations_web +version: 1.0.0 +appVersion: "1.0.0" \ No newline at end of file diff --git a/ph-ee-env-template/helm/ph-ee-engine/operations-web/README.md b/ph-ee-env-template/helm/ph-ee-engine/operations-web/README.md new file mode 100644 index 000000000..8d4d9749a --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/operations-web/README.md @@ -0,0 +1,41 @@ +# operations_web + +![Version: 1.0.0](https://img.shields.io/badge/Version-1.0.0-informational?style=flat-square) ![AppVersion: 1.0.0](https://img.shields.io/badge/AppVersion-1.0.0-informational?style=flat-square) + +ph-ee-operations-web + +## Values + +| Key | Type | Default | Description | +|-----|------|---------|-------------| +| SPRING_PROFILES_ACTIVE | string | `"bb"` | | +| configmap.apiversion | string | `"v1"` | | +| configmap.hostname | string | `"ops.sandbox.mifos.io"` | | +| configmap.identity.hostname | string | `"ops-bk.sandbox.mifos.io"` | | +| deployment.apiVersion | string | `"apps/v1"` | | +| deployment.config | object | `{}` | | +| enabled | bool | `true` | | +| hostname | string | `"ops.sandbox.mifos.io"` | | +| image | string | `""` | | +| imageTag | string | `""` | | +| ingress.annotations."konghq.com/plugins" | string | `"request-transformer,oidc,cors"` | | +| ingress.annotations."kubernetes.io/ingress.class" | string | `"nginx"` | | +| ingress.apiversion | string | `"networking.k8s.io/v1"` | | +| ingress.backend.service.name | string | `"ph-ee-operations-web"` | | +| ingress.backend.service.port.number | int | `4200` | | +| ingress.className | string | `"kong"` | | +| ingress.enabled | bool | `true` | | +| ingress.path | string | `"/"` | | +| ingress.tls[0].hosts | string | `"ops.sandbox.mifos.io"` | | +| ingress.tls[1].secretName | string | `"sandbox-secret"` | | +| limits.cpu | string | `"500m"` | | +| limits.memory | string | `"512M"` | | +| requests.cpu | string | `"100m"` | | +| requests.memory | string | `"256M"` | | +| secret.apiversion | string | `"v1"` | | +| service.apiversion | string | `"v1"` | | +| webhost | string | `"ops.sandbox.mifos.io"` | | +| wildcardhostname | string | `"notifications.sandbox.mifos.io"` | | + +---------------------------------------------- +Autogenerated from chart metadata using [helm-docs v1.11.0](https://github.com/norwoodj/helm-docs/releases/v1.11.0) diff --git a/ph-ee-env-template/helm/ph-ee-engine/operations-web/templates/_helpers.tpl b/ph-ee-env-template/helm/ph-ee-engine/operations-web/templates/_helpers.tpl new file mode 100644 index 000000000..16047ac53 --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/operations-web/templates/_helpers.tpl @@ -0,0 +1,32 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +*/}} +{{- define "operations_web.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +*/}} +{{- define "ph-ee-operations-web.fullname" -}} +{{- if .Values.fullnameOverride -}} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- $name := default .Chart.Name .Values.nameOverride -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} + +{{/* +Use the fullname if the serviceAccount value is not set +*/}} +{{- define "ph-ee-operations-web.serviceAccount" -}} +{{- if .Values.serviceAccount }} +{{- .Values.serviceAccount -}} +{{- else }} +{{- $name := default .Chart.Name .Values.nameOverride -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} diff --git a/ph-ee-env-template/helm/ph-ee-engine/operations-web/templates/clusterrole.yaml b/ph-ee-env-template/helm/ph-ee-engine/operations-web/templates/clusterrole.yaml new file mode 100644 index 000000000..f6fc4a85b --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/operations-web/templates/clusterrole.yaml @@ -0,0 +1,11 @@ +{{- if .Values.managedServiceAccount }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + # "namespace" omitted since ClusterRoles are not namespaced + name: ph-ee-operations-web-c-role +rules: +- apiGroups: [""] + resources: ["secrets"] + verbs: ["get", "watch", "list"] +{{- end -}} \ No newline at end of file diff --git a/ph-ee-env-template/helm/ph-ee-engine/operations-web/templates/clusterrolebinding.yaml b/ph-ee-env-template/helm/ph-ee-engine/operations-web/templates/clusterrolebinding.yaml new file mode 100644 index 000000000..27c647920 --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/operations-web/templates/clusterrolebinding.yaml @@ -0,0 +1,15 @@ +{{- if .Values.managedServiceAccount }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: ph-ee-operations-web-c-role-binding +subjects: +- kind: ServiceAccount + name: ph-ee-operations-web # name of your service account + namespace: {{ .Release.Namespace }} # this is the namespace your service account is in +roleRef: # referring to your ClusterRole + kind: ClusterRole + name: ph-ee-operations-web-c-role + apiGroup: rbac.authorization.k8s.io + +{{- end -}} \ No newline at end of file diff --git a/ph-ee-env-template/helm/ph-ee-engine/operations-web/templates/configmap.yaml b/ph-ee-env-template/helm/ph-ee-engine/operations-web/templates/configmap.yaml new file mode 100644 index 000000000..e5ef74dd6 --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/operations-web/templates/configmap.yaml @@ -0,0 +1,13 @@ +apiVersion: {{ .Values.configmap.apiversion }} +kind: ConfigMap +data: + configuration.properties: | + oauth.enabled false + oauth.basicAuth true + oauth.basicAuthToken Y2xpZW50Og== + oauth.serverUrl https://{{ .Values.configmap.identity.hostname }} + serverUrl https://{{ .Values.configmap.hostname }} + auth.enabled false + auth.tenant phdefault +metadata: + name: ph-ee-operations-web-config \ No newline at end of file diff --git a/ph-ee-env-template/helm/ph-ee-engine/operations-web/templates/deployment.yaml b/ph-ee-env-template/helm/ph-ee-engine/operations-web/templates/deployment.yaml new file mode 100644 index 000000000..793ae16cf --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/operations-web/templates/deployment.yaml @@ -0,0 +1,82 @@ +{{- if .Values.enabled -}} + +apiVersion: apps/v1 +kind: Deployment +metadata: + name: ph-ee-operations-web + labels: + app: ph-ee-operations-web +spec: + replicas: {{ .Values.replicas }} + selector: + matchLabels: + app: ph-ee-operations-web + template: + metadata: + labels: + app: ph-ee-operations-web + annotations: +{{- if .Values.deployment.annotations }} +{{ toYaml .Values.deployment.annotations | indent 8 }} +{{- end }} + spec: + containers: + - name: ph-ee-operations-web + image: "{{ .Values.image }}" + imagePullPolicy: "{{ .Values.global.imagePullPolicy }}" + ports: + - containerPort: 80 + resources: + limits: + memory: "{{ .Values.limits.memory }}" + cpu: "{{ .Values.limits.cpu }}" + requests: + memory: "{{ .Values.requests.memory }}" + cpu: "{{ .Values.requests.cpu }}" + env: + - name: "PH_OPS_BACKEND_SERVER_URL" + value: "{{ .Values.backend.PH_OPS_BACKEND_SERVER_URL }}" + - name: "PH_VOU_BACKEND_SERVER_URL" + value: "{{ .Values.backend.PH_VOU_BACKEND_SERVER_URL }}" + - name: "PH_ACT_BACKEND_SERVER_URL" + value: "{{ .Values.backend.PH_ACT_BACKEND_SERVER_URL }}" + - name: "PH_PLATFORM_TENANT_ID" + value: "{{ .Values.backend.PH_PLATFORM_TENANT_ID }}" + - name: "PH_PLATFORM_TENANT_IDS" + value: "{{ .Values.backend.PH_PLATFORM_TENANT_IDS }}" + - name: "PH_REGISTERING_INSTITUTION_ID" + value: "{{ .Values.backend.PH_REGISTERING_INSTITUTION_ID }}" + - name: "PH_AUTH_ENABLED" + value: "{{ .Values.auth.PH_AUTH_ENABLED }}" + - name: "PH_OAUTH_ENABLED" + value: "{{ .Values.auth.PH_OAUTH_ENABLED }}" + - name: "PH_OAUTH_TYPE" + value: "{{ .Values.auth.PH_OAUTH_TYPE }}" + - name: "PH_OAUTH_SERVER_URL" + value: "{{ .Values.auth.PH_OAUTH_SERVER_URL }}" + - name: "PH_OAUTH_REALM" + value: "{{ .Values.auth.PH_OAUTH_REALM }}" + - name: "PH_OAUTH_CLIENT_ID" + value: "{{ .Values.auth.PH_OAUTH_CLIENT_ID }}" + - name: "PH_OAUTH_CLIENT_SECRET" + value: "{{ .Values.auth.PH_OAUTH_CLIENT_SECRET }}" + - name: "PH_OAUTH_BASIC_AUTH" + value: "{{ .Values.auth.PH_OAUTH_BASIC_AUTH }}" + - name: "PH_OAUTH_BASIC_AUTH_TOKEN" + value: "{{ .Values.auth.PH_OAUTH_BASIC_AUTH_TOKEN }}" + - name: "PH_DEFAULT_LANGUAGE" + value: "{{ .Values.PH_DEFAULT_LANGUAGE }}" + - name: "PH_SUPPORTED_LANGUAGES" + value: "{{ .Values.PH_SUPPORTED_LANGUAGES }}" +{{- if .Values.extraEnvs | default .Values.deployment.extraEnvs }} +{{ toYaml ( .Values.extraEnvs | default .Values.deployment.extraEnvs ) | indent 12 }} +{{- end }} + volumeMounts: +{{- if .Values.deployment.config }} +{{ toYaml .Values.deployment.config | indent 12 }} +{{- end }} + volumes: + - name: ph-ee-operations-web-config + configMap: + name: ph-ee-operations-web-config +{{- end }} \ No newline at end of file diff --git a/ph-ee-env-template/helm/ph-ee-engine/operations-web/templates/ingress.yaml b/ph-ee-env-template/helm/ph-ee-engine/operations-web/templates/ingress.yaml new file mode 100644 index 000000000..6458c218f --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/operations-web/templates/ingress.yaml @@ -0,0 +1,49 @@ +{{- if .Values.ingress.enabled -}} +{{- $pathtype := .Values.ingress.pathtype -}} +{{- $ingressPath := .Values.ingress.path -}} +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: ph-ee-operations-web + labels: + app: {{ .Chart.Name }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +{{- with .Values.ingress.annotations }} + annotations: +{{ toYaml . | indent 4 }} +{{- end }} +spec: + {{- if .Values.ingress.className }} + ingressClassName: {{ .Values.ingress.className | quote }} + {{- end }} +{{- if .Values.ingress.tls }} + tls: + {{- if .ingressPath }} + {{- range .Values.ingress.tls }} + - hosts: + {{- range .hosts }} + - {{ . }} + {{- end }} + secretName: {{ .secretName }} + {{- end }} +{{- else }} +{{ toYaml .Values.ingress.tls | indent 4 }} + {{- end }} +{{- end}} + rules: + {{- range .Values.ingress.hosts }} + - host: {{ .host }} + http: + paths: + {{- range .paths }} + - path: {{ .path }} + pathType: {{ $pathtype }} + backend: + service: + name: {{ .backend.service.name}} + port: + number: {{ .backend.service.port.number}} + {{- end }} + {{- end }} + {{- end }} diff --git a/ph-ee-env-template/helm/ph-ee-engine/operations-web/templates/role.yaml b/ph-ee-env-template/helm/ph-ee-engine/operations-web/templates/role.yaml new file mode 100644 index 000000000..0b3e9eb76 --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/operations-web/templates/role.yaml @@ -0,0 +1,14 @@ +{{- if .Values.managedServiceAccount }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: ph-ee-operations-web-role + namespace: {{ .Release.Namespace }} +rules: +- apiGroups: + - "" + resources: + - pods + - configmaps + verbs: ["get", "create", "update"] +{{- end -}} \ No newline at end of file diff --git a/ph-ee-env-template/helm/ph-ee-engine/operations-web/templates/rolebinding.yaml b/ph-ee-env-template/helm/ph-ee-engine/operations-web/templates/rolebinding.yaml new file mode 100644 index 000000000..c56ad64e9 --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/operations-web/templates/rolebinding.yaml @@ -0,0 +1,15 @@ +{{- if .Values.managedServiceAccount }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: ph-ee-operations-web-role-binding + namespace: {{ .Release.Namespace }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: ph-ee-operations-web-role +subjects: +- kind: ServiceAccount + name: ph-ee-operations-web + namespace: {{ .Release.Namespace }} +{{- end -}} \ No newline at end of file diff --git a/ph-ee-env-template/helm/ph-ee-engine/operations-web/templates/service.yaml b/ph-ee-env-template/helm/ph-ee-engine/operations-web/templates/service.yaml new file mode 100644 index 000000000..cd012df14 --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/operations-web/templates/service.yaml @@ -0,0 +1,13 @@ +{{- if .Values.enabled -}} +apiVersion: {{ .Values.service.apiversion }} +kind: Service +metadata: + name: ph-ee-operations-web +spec: + selector: + app: ph-ee-operations-web + ports: + - protocol: TCP + port: 4200 + targetPort: 80 +{{- end }} \ No newline at end of file diff --git a/ph-ee-env-template/helm/ph-ee-engine/operations-web/templates/serviceaccount.yaml b/ph-ee-env-template/helm/ph-ee-engine/operations-web/templates/serviceaccount.yaml new file mode 100644 index 000000000..764a1d7fb --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/operations-web/templates/serviceaccount.yaml @@ -0,0 +1,15 @@ +{{- if .Values.managedServiceAccount }} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: ph-ee-operations-web + annotations: + {{- with .Values.serviceAccountAnnotations }} + {{- toYaml . | nindent 4 }} + {{- end }} + labels: + app: ph-ee-operations-web + chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" + heritage: {{ .Release.Service | quote }} + release: {{ .Release.Name | quote }} +{{- end -}} \ No newline at end of file diff --git a/ph-ee-env-template/helm/ph-ee-engine/operations-web/values.yaml b/ph-ee-env-template/helm/ph-ee-engine/operations-web/values.yaml new file mode 100644 index 000000000..d97a485d8 --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/operations-web/values.yaml @@ -0,0 +1,64 @@ +service: + apiversion: "v1" + +secret: + apiversion: "v1" + +enabled: true +image: "" +imageTag: "" +SPRING_PROFILES_ACTIVE: "bb" +hostname: "ops.sandbox.mifos.io" +webhost: "ops.sandbox.mifos.io" +limits: + cpu: "500m" + memory: "512M" +requests: + cpu: "100m" + memory: "256M" +# Enabling this will publicly expose your Elasticsearch instance. +# Only enable this if you have security enabled on your cluster +ingress: + enabled: false + annotations: {} + # kubernetes.io/ingress.class: "nginx" + pathtype: ImplementationSpecific + hosts: + - host: "" + paths: + - path: / + tls: [] + # - secretName: sandbox-secret + # hosts: + # - chart-example.local +deployment: + apiVersion: "apps/v1" + config: {} + +configmap: + apiversion: "v1" + hostname: "ops.sandbox.mifos.io" + identity: + hostname: "ops-bk.sandbox.mifos.io" +backend: + PH_OPS_BACKEND_SERVER_URL: https://ops-bk.sandbox.mifos.io/api/v1 + PH_VOU_BACKEND_SERVER_URL: https://ops-bk.sandbox.mifos.io/api/v1 + PH_ACT_BACKEND_SERVER_URL: https://ops-bk.sandbox.mifos.io/api/v1 + PH_VOU_CALLBACK_URL: https://vouchers.sandbox.mifos.io + PH_OPS_BATCH_KEY: "" + PH_OPS_BULK_CONNECTOR_URL: https://bulk-connector.sandbox.mifos.io + PH_PLATFORM_TENANT_ID: phdefault + PH_PLATFORM_TENANT_IDS: phdefault + PH_REGISTERING_INSTITUTION_ID: SocialInstitution +auth: + PH_AUTH_ENABLED: false + PH_OAUTH_ENABLED: false + PH_OAUTH_TYPE: keycloak + PH_OAUTH_SERVER_URL: http://keycloak.sandbox.mifos.io/auth + PH_OAUTH_REALM: paymenthub + PH_OAUTH_CLIENT_ID: opsapp + PH_OAUTH_CLIENT_SECRET: Y2xpZW50Og== + PH_OAUTH_BASIC_AUTH: true + PH_OAUTH_BASIC_AUTH_TOKEN: Y2xpZW50Og== +PH_DEFAULT_LANGUAGE: en +PH_SUPPORTED_LANGUAGES: en,fr,es \ No newline at end of file diff --git a/ph-ee-env-template/helm/ph-ee-engine/requirements.yaml b/ph-ee-env-template/helm/ph-ee-engine/requirements.yaml new file mode 100644 index 000000000..a9cdd6c91 --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/requirements.yaml @@ -0,0 +1,127 @@ +dependencies: + - name: camunda-platform + repository: https://helm.camunda.io + version: 8.2.12 + condition: "camunda-platform-helm.enabled" + - name: elasticsearch + repository: http://helm.elastic.co + version: 7.17.3 + condition: "elasticsearch.enabled" + - name: kibana + repository: http://helm.elastic.co + version: 7.16.3 + condition: "kibana.enabled" + - name: mysql + version: 9.4.5 + repository: "https://charts.bitnami.com/bitnami" + alias: operationsmysql + condition: "operations.mysql.enabled" + - name: kong + version: 2.13.1 + repository: https://charts.konghq.com + condition: "kong.enabled" + - name: keycloak + version: 18.1.1 + repository: https://codecentric.github.io/helm-charts + condition: "keycloak.enabled" + - name: redis + version: 17.9.3 + repository: "https://charts.bitnami.com/bitnami" + condition: "redis.enabled" + - name: kafka + version: 25.0.0 + repository: "https://charts.bitnami.com/bitnami" + condition: "kafka.enabled" + - name: operations_app + version: 1.0.0 + repository: "file://./operations-app" + condition: "operations_app.enabled" + - name: ph_ee_connector_gsma + version: 1.0.0 + repository: "file://./connector-gsma" + condition: "ph_ee_connector_gsma.enabled" + - name: notifications + version: 1.0.0 + repository: "file://./connector-notifications" + condition: "notifications.enabled" + - name: paygops_connector + version: 1.0.0 + repository: "file://./ams-paygops" + condition: "paygops_connector.enabled" + - name: roster_connector + version: 1.0.0 + repository: "file://./ams-roster" + condition: "roster_connector.enabled" + - name: mpesa + version: 1.0.0 + repository: "file://./connector-mpesa" + condition: "mpesa.enabled" + - name: operations_web + version: 1.0.0 + repository: "file://./operations-web" + condition: "operations_web.enabled" + - name: ph_ee_connector_mojaloop + version: 1.0.0 + repository: "file://./connector-mojaloop" + condition: "ph_ee_connector_mojaloop.enabled" + - name: ph_ee_connector_slcb + version: 1.0.0 + repository: "file://./connector-slcb" + condition: "ph_ee_connector_slcb.enabled" + - name: importer_es + version: 1.0.0 + repository: "file://./operations-importer-es" + condition: "importer_es.enabled" + - name: messagegateway + version: 1.0.0 + repository: "file://./message-gateway" + condition: "messagegateway.enabled" + - name: ph_ee_connector_ams_mifos + version: 1.0.0 + repository: "file://./connector-ams-mifos" + condition: "ph_ee_connector_ams_mifos.enabled" + - name: connector_bulk + version: 1.0.0 + repository: "file://./connector-bulk" + condition: "connector_bulk.enabled" + - name: channel + version: 1.0.0 + repository: "file://./connector-channel" + condition: "channel.enabled" + - name: importer_rdbms + version: 1.0.0 + repository: "file://./operations-importer-rdbms" + condition: "importer_rdbms.enabled" + - name: zeebe_ops + version: 1.0.0 + repository: "file://./zeebe-ops" + condition: "zeebe_ops.enabled" + - name: mockpayment + version: 1.0.0 + repository: "file://./connector-mock-payment-schema" + condition: "mockpayment.enabled" + + - name: vouchers + version: 1.0.0 + repository: "file://./vouchers" + condition: "vouchers.enabled" + + - name: billPay + version: 1.0.0 + repository: "file://./connector-bill-pay" + condition: "billPay.enabled" + + - name: minio + repository: "https://charts.min.io/" + version: 5.0.14 + condition: "minio.enabled" + + - name: crm + version: 1.0.0 + repository: "file://./connector-crm" + condition: "crm.enabled" + + - name: ph-ee-connector + version: 1.0.0 + repository: "file://./connector-ph-ee-bulk" + condition: "ph-ee-connector.enabled" \ No newline at end of file diff --git a/ph-ee-env-template/helm/ph-ee-engine/setup-files/kong-keycloak-realm.json b/ph-ee-env-template/helm/ph-ee-engine/setup-files/kong-keycloak-realm.json new file mode 100644 index 000000000..315a577d3 --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/setup-files/kong-keycloak-realm.json @@ -0,0 +1,2172 @@ +{ + "id": "Kong", + "realm": "Kong", + "notBefore": 0, + "defaultSignatureAlgorithm": "RS256", + "revokeRefreshToken": false, + "refreshTokenMaxReuse": 0, + "accessTokenLifespan": 300, + "accessTokenLifespanForImplicitFlow": 900, + "ssoSessionIdleTimeout": 1800, + "ssoSessionMaxLifespan": 36000, + "ssoSessionIdleTimeoutRememberMe": 0, + "ssoSessionMaxLifespanRememberMe": 0, + "offlineSessionIdleTimeout": 2592000, + "offlineSessionMaxLifespanEnabled": false, + "offlineSessionMaxLifespan": 5184000, + "clientSessionIdleTimeout": 0, + "clientSessionMaxLifespan": 0, + "clientOfflineSessionIdleTimeout": 0, + "clientOfflineSessionMaxLifespan": 0, + "accessCodeLifespan": 60, + "accessCodeLifespanUserAction": 300, + "accessCodeLifespanLogin": 1800, + "actionTokenGeneratedByAdminLifespan": 43200, + "actionTokenGeneratedByUserLifespan": 300, + "oauth2DeviceCodeLifespan": 600, + "oauth2DevicePollingInterval": 5, + "enabled": true, + "sslRequired": "external", + "registrationAllowed": false, + "registrationEmailAsUsername": false, + "rememberMe": false, + "verifyEmail": false, + "loginWithEmailAllowed": true, + "duplicateEmailsAllowed": false, + "resetPasswordAllowed": false, + "editUsernameAllowed": false, + "bruteForceProtected": false, + "permanentLockout": false, + "maxFailureWaitSeconds": 900, + "minimumQuickLoginWaitSeconds": 60, + "waitIncrementSeconds": 60, + "quickLoginCheckMilliSeconds": 1000, + "maxDeltaTimeSeconds": 43200, + "failureFactor": 30, + "roles": { + "realm": [ + { + "id": "e56ce8e6-314f-4bf1-98f6-51d9f3bee0bd", + "name": "uma_authorization", + "description": "${role_uma_authorization}", + "composite": false, + "clientRole": false, + "containerId": "Kong", + "attributes": {} + }, + { + "id": "75cecb6c-eeee-4ac5-ae3f-16fb17d670a5", + "name": "offline_access", + "description": "${role_offline-access}", + "composite": false, + "clientRole": false, + "containerId": "Kong", + "attributes": {} + }, + { + "id": "f306be38-5b0a-4f72-b32c-acc9843c3948", + "name": "default-roles-kong", + "description": "${role_default-roles}", + "composite": true, + "composites": { + "realm": [ + "offline_access", + "uma_authorization" + ], + "client": { + "account": [ + "view-profile", + "manage-account" + ] + } + }, + "clientRole": false, + "containerId": "Kong", + "attributes": {} + } + ], + "client": { + "kong-oidc": [], + "realm-management": [ + { + "id": "2cf527ea-dfbd-4061-9ff2-9016f3be572f", + "name": "manage-events", + "description": "${role_manage-events}", + "composite": false, + "clientRole": true, + "containerId": "a696932a-e9fc-4598-b656-bc4995a9532e", + "attributes": {} + }, + { + "id": "49b1f4e4-e2e5-4809-b8a1-3a1309648a79", + "name": "realm-admin", + "description": "${role_realm-admin}", + "composite": true, + "composites": { + "client": { + "realm-management": [ + "manage-events", + "create-client", + "view-realm", + "manage-realm", + "view-authorization", + "manage-clients", + "manage-identity-providers", + "query-clients", + "query-realms", + "view-users", + "view-clients", + "view-identity-providers", + "manage-users", + "query-users", + "manage-authorization", + "view-events", + "impersonation", + "query-groups" + ] + } + }, + "clientRole": true, + "containerId": "a696932a-e9fc-4598-b656-bc4995a9532e", + "attributes": {} + }, + { + "id": "784f03f8-c24f-4d53-854f-de53e7224eaf", + "name": "create-client", + "description": "${role_create-client}", + "composite": false, + "clientRole": true, + "containerId": "a696932a-e9fc-4598-b656-bc4995a9532e", + "attributes": {} + }, + { + "id": "859464b4-174e-4370-8c20-51c42552f89a", + "name": "view-realm", + "description": "${role_view-realm}", + "composite": false, + "clientRole": true, + "containerId": "a696932a-e9fc-4598-b656-bc4995a9532e", + "attributes": {} + }, + { + "id": "994cdfea-9f7d-4fb9-84d8-9a64d6fd7458", + "name": "manage-realm", + "description": "${role_manage-realm}", + "composite": false, + "clientRole": true, + "containerId": "a696932a-e9fc-4598-b656-bc4995a9532e", + "attributes": {} + }, + { + "id": "b7b27085-bd72-4f3e-b0e3-23a590927127", + "name": "view-authorization", + "description": "${role_view-authorization}", + "composite": false, + "clientRole": true, + "containerId": "a696932a-e9fc-4598-b656-bc4995a9532e", + "attributes": {} + }, + { + "id": "e79a28ab-05ca-44d9-978e-dc98d4b14dbb", + "name": "manage-clients", + "description": "${role_manage-clients}", + "composite": false, + "clientRole": true, + "containerId": "a696932a-e9fc-4598-b656-bc4995a9532e", + "attributes": {} + }, + { + "id": "7358345e-cc0a-40e5-818c-1777e7aaff3b", + "name": "manage-identity-providers", + "description": "${role_manage-identity-providers}", + "composite": false, + "clientRole": true, + "containerId": "a696932a-e9fc-4598-b656-bc4995a9532e", + "attributes": {} + }, + { + "id": "08ba0de2-a85c-406a-8707-8b27a7104a5a", + "name": "query-clients", + "description": "${role_query-clients}", + "composite": false, + "clientRole": true, + "containerId": "a696932a-e9fc-4598-b656-bc4995a9532e", + "attributes": {} + }, + { + "id": "2aca0e4c-a736-4341-af8c-78c836dd01fa", + "name": "query-realms", + "description": "${role_query-realms}", + "composite": false, + "clientRole": true, + "containerId": "a696932a-e9fc-4598-b656-bc4995a9532e", + "attributes": {} + }, + { + "id": "7dc50f4e-7854-460f-9f43-e67971f38704", + "name": "view-clients", + "description": "${role_view-clients}", + "composite": true, + "composites": { + "client": { + "realm-management": [ + "query-clients" + ] + } + }, + "clientRole": true, + "containerId": "a696932a-e9fc-4598-b656-bc4995a9532e", + "attributes": {} + }, + { + "id": "5332e3a6-9283-4256-8ced-edf552d42a23", + "name": "view-users", + "description": "${role_view-users}", + "composite": true, + "composites": { + "client": { + "realm-management": [ + "query-users", + "query-groups" + ] + } + }, + "clientRole": true, + "containerId": "a696932a-e9fc-4598-b656-bc4995a9532e", + "attributes": {} + }, + { + "id": "8cd0251b-6d63-42b5-aa8f-813d6d696dc7", + "name": "manage-users", + "description": "${role_manage-users}", + "composite": false, + "clientRole": true, + "containerId": "a696932a-e9fc-4598-b656-bc4995a9532e", + "attributes": {} + }, + { + "id": "1a80c1f2-8d4e-429e-9983-362d0d1aadfa", + "name": "query-users", + "description": "${role_query-users}", + "composite": false, + "clientRole": true, + "containerId": "a696932a-e9fc-4598-b656-bc4995a9532e", + "attributes": {} + }, + { + "id": "017fba9a-31d5-4c65-8934-931ba58c9d3a", + "name": "view-identity-providers", + "description": "${role_view-identity-providers}", + "composite": false, + "clientRole": true, + "containerId": "a696932a-e9fc-4598-b656-bc4995a9532e", + "attributes": {} + }, + { + "id": "be66f0c8-d654-4f4c-a445-b460fefc548e", + "name": "manage-authorization", + "description": "${role_manage-authorization}", + "composite": false, + "clientRole": true, + "containerId": "a696932a-e9fc-4598-b656-bc4995a9532e", + "attributes": {} + }, + { + "id": "000dad61-9f98-499f-8dd0-f0f7142c29e8", + "name": "view-events", + "description": "${role_view-events}", + "composite": false, + "clientRole": true, + "containerId": "a696932a-e9fc-4598-b656-bc4995a9532e", + "attributes": {} + }, + { + "id": "f99314e6-7877-40e4-b471-705714638dde", + "name": "impersonation", + "description": "${role_impersonation}", + "composite": false, + "clientRole": true, + "containerId": "a696932a-e9fc-4598-b656-bc4995a9532e", + "attributes": {} + }, + { + "id": "4556dea7-a103-41fe-9d78-fff6b1bcb057", + "name": "query-groups", + "description": "${role_query-groups}", + "composite": false, + "clientRole": true, + "containerId": "a696932a-e9fc-4598-b656-bc4995a9532e", + "attributes": {} + } + ], + "security-admin-console": [], + "admin-cli": [], + "account-console": [], + "broker": [ + { + "id": "fb6b3047-933d-4278-b657-191300d65c62", + "name": "read-token", + "description": "${role_read-token}", + "composite": false, + "clientRole": true, + "containerId": "01f4013e-c990-4983-ae7f-7a0d025c0e14", + "attributes": {} + } + ], + "account": [ + { + "id": "05e1d956-aec5-4a59-b4ba-5a765207c405", + "name": "view-applications", + "description": "${role_view-applications}", + "composite": false, + "clientRole": true, + "containerId": "361e8d18-d33a-46ce-b492-a5d19251101a", + "attributes": {} + }, + { + "id": "765b0dea-3f94-42eb-b9d5-f2dc9cf69c1b", + "name": "manage-account-links", + "description": "${role_manage-account-links}", + "composite": false, + "clientRole": true, + "containerId": "361e8d18-d33a-46ce-b492-a5d19251101a", + "attributes": {} + }, + { + "id": "2139eb6e-ef7f-41fb-93d6-752c2dc89a73", + "name": "view-profile", + "description": "${role_view-profile}", + "composite": false, + "clientRole": true, + "containerId": "361e8d18-d33a-46ce-b492-a5d19251101a", + "attributes": {} + }, + { + "id": "16551f6b-109d-4714-903d-f21477d4cbd4", + "name": "manage-account", + "description": "${role_manage-account}", + "composite": true, + "composites": { + "client": { + "account": [ + "manage-account-links" + ] + } + }, + "clientRole": true, + "containerId": "361e8d18-d33a-46ce-b492-a5d19251101a", + "attributes": {} + }, + { + "id": "9f367d45-e730-4462-aac6-8b9fc5cef660", + "name": "view-consent", + "description": "${role_view-consent}", + "composite": false, + "clientRole": true, + "containerId": "361e8d18-d33a-46ce-b492-a5d19251101a", + "attributes": {} + }, + { + "id": "1f06a316-225c-443b-917f-700165ad462a", + "name": "delete-account", + "description": "${role_delete-account}", + "composite": false, + "clientRole": true, + "containerId": "361e8d18-d33a-46ce-b492-a5d19251101a", + "attributes": {} + }, + { + "id": "af167558-8414-4e5c-9e11-61f459e3c914", + "name": "manage-consent", + "description": "${role_manage-consent}", + "composite": true, + "composites": { + "client": { + "account": [ + "view-consent" + ] + } + }, + "clientRole": true, + "containerId": "361e8d18-d33a-46ce-b492-a5d19251101a", + "attributes": {} + } + ] + } + }, + "groups": [ + { + "id": "c5dd34ff-bf1f-43ea-9976-7fb1371f9432", + "name": "test", + "path": "/test", + "attributes": {}, + "realmRoles": [], + "clientRoles": {}, + "subGroups": [] + } + ], + "defaultRole": { + "id": "f306be38-5b0a-4f72-b32c-acc9843c3948", + "name": "default-roles-kong", + "description": "${role_default-roles}", + "composite": true, + "clientRole": false, + "containerId": "Kong" + }, + "requiredCredentials": [ + "password" + ], + "otpPolicyType": "totp", + "otpPolicyAlgorithm": "HmacSHA1", + "otpPolicyInitialCounter": 0, + "otpPolicyDigits": 6, + "otpPolicyLookAheadWindow": 1, + "otpPolicyPeriod": 30, + "otpSupportedApplications": [ + "FreeOTP", + "Google Authenticator" + ], + "webAuthnPolicyRpEntityName": "keycloak", + "webAuthnPolicySignatureAlgorithms": [ + "ES256" + ], + "webAuthnPolicyRpId": "", + "webAuthnPolicyAttestationConveyancePreference": "not specified", + "webAuthnPolicyAuthenticatorAttachment": "not specified", + "webAuthnPolicyRequireResidentKey": "not specified", + "webAuthnPolicyUserVerificationRequirement": "not specified", + "webAuthnPolicyCreateTimeout": 0, + "webAuthnPolicyAvoidSameAuthenticatorRegister": false, + "webAuthnPolicyAcceptableAaguids": [], + "webAuthnPolicyPasswordlessRpEntityName": "keycloak", + "webAuthnPolicyPasswordlessSignatureAlgorithms": [ + "ES256" + ], + "webAuthnPolicyPasswordlessRpId": "", + "webAuthnPolicyPasswordlessAttestationConveyancePreference": "not specified", + "webAuthnPolicyPasswordlessAuthenticatorAttachment": "not specified", + "webAuthnPolicyPasswordlessRequireResidentKey": "not specified", + "webAuthnPolicyPasswordlessUserVerificationRequirement": "not specified", + "webAuthnPolicyPasswordlessCreateTimeout": 0, + "webAuthnPolicyPasswordlessAvoidSameAuthenticatorRegister": false, + "webAuthnPolicyPasswordlessAcceptableAaguids": [], + "scopeMappings": [ + { + "clientScope": "offline_access", + "roles": [ + "offline_access" + ] + } + ], + "clientScopeMappings": { + "account": [ + { + "client": "account-console", + "roles": [ + "manage-account" + ] + } + ] + }, + "clients": [ + { + "id": "361e8d18-d33a-46ce-b492-a5d19251101a", + "clientId": "account", + "name": "${client_account}", + "rootUrl": "${authBaseUrl}", + "baseUrl": "/realms/Kong/account/", + "surrogateAuthRequired": false, + "enabled": true, + "alwaysDisplayInConsole": false, + "clientAuthenticatorType": "client-secret", + "redirectUris": [ + "/realms/Kong/account/*" + ], + "webOrigins": [], + "notBefore": 0, + "bearerOnly": false, + "consentRequired": false, + "standardFlowEnabled": true, + "implicitFlowEnabled": false, + "directAccessGrantsEnabled": false, + "serviceAccountsEnabled": false, + "publicClient": true, + "frontchannelLogout": false, + "protocol": "openid-connect", + "attributes": {}, + "authenticationFlowBindingOverrides": {}, + "fullScopeAllowed": false, + "nodeReRegistrationTimeout": 0, + "defaultClientScopes": [ + "web-origins", + "profile", + "roles", + "email" + ], + "optionalClientScopes": [ + "address", + "phone", + "offline_access", + "microprofile-jwt" + ] + }, + { + "id": "67a7488e-a386-445f-acd1-655e81a641cf", + "clientId": "account-console", + "name": "${client_account-console}", + "rootUrl": "${authBaseUrl}", + "baseUrl": "/realms/Kong/account/", + "surrogateAuthRequired": false, + "enabled": true, + "alwaysDisplayInConsole": false, + "clientAuthenticatorType": "client-secret", + "redirectUris": [ + "/realms/Kong/account/*" + ], + "webOrigins": [], + "notBefore": 0, + "bearerOnly": false, + "consentRequired": false, + "standardFlowEnabled": true, + "implicitFlowEnabled": false, + "directAccessGrantsEnabled": false, + "serviceAccountsEnabled": false, + "publicClient": true, + "frontchannelLogout": false, + "protocol": "openid-connect", + "attributes": { + "pkce.code.challenge.method": "S256" + }, + "authenticationFlowBindingOverrides": {}, + "fullScopeAllowed": false, + "nodeReRegistrationTimeout": 0, + "protocolMappers": [ + { + "id": "6cbfddd1-b385-48ba-86e7-3c6160e5635f", + "name": "audience resolve", + "protocol": "openid-connect", + "protocolMapper": "oidc-audience-resolve-mapper", + "consentRequired": false, + "config": {} + } + ], + "defaultClientScopes": [ + "web-origins", + "profile", + "roles", + "email" + ], + "optionalClientScopes": [ + "address", + "phone", + "offline_access", + "microprofile-jwt" + ] + }, + { + "id": "1fc9f83b-83c2-4769-89af-4ff8a0f09989", + "clientId": "admin-cli", + "name": "${client_admin-cli}", + "surrogateAuthRequired": false, + "enabled": true, + "alwaysDisplayInConsole": false, + "clientAuthenticatorType": "client-secret", + "redirectUris": [], + "webOrigins": [], + "notBefore": 0, + "bearerOnly": false, + "consentRequired": false, + "standardFlowEnabled": false, + "implicitFlowEnabled": false, + "directAccessGrantsEnabled": true, + "serviceAccountsEnabled": false, + "publicClient": true, + "frontchannelLogout": false, + "protocol": "openid-connect", + "attributes": {}, + "authenticationFlowBindingOverrides": {}, + "fullScopeAllowed": false, + "nodeReRegistrationTimeout": 0, + "defaultClientScopes": [ + "web-origins", + "profile", + "roles", + "email" + ], + "optionalClientScopes": [ + "address", + "phone", + "offline_access", + "microprofile-jwt" + ] + }, + { + "id": "01f4013e-c990-4983-ae7f-7a0d025c0e14", + "clientId": "broker", + "name": "${client_broker}", + "surrogateAuthRequired": false, + "enabled": true, + "alwaysDisplayInConsole": false, + "clientAuthenticatorType": "client-secret", + "redirectUris": [], + "webOrigins": [], + "notBefore": 0, + "bearerOnly": true, + "consentRequired": false, + "standardFlowEnabled": true, + "implicitFlowEnabled": false, + "directAccessGrantsEnabled": false, + "serviceAccountsEnabled": false, + "publicClient": false, + "frontchannelLogout": false, + "protocol": "openid-connect", + "attributes": {}, + "authenticationFlowBindingOverrides": {}, + "fullScopeAllowed": false, + "nodeReRegistrationTimeout": 0, + "defaultClientScopes": [ + "web-origins", + "profile", + "roles", + "email" + ], + "optionalClientScopes": [ + "address", + "phone", + "offline_access", + "microprofile-jwt" + ] + }, + { + "id": "578e995e-7de0-4f09-9fa8-c4caab51843f", + "clientId": "kong-oidc", + "surrogateAuthRequired": false, + "enabled": true, + "alwaysDisplayInConsole": false, + "clientAuthenticatorType": "client-secret", + "secret": "**********", + "redirectUris": [ + "*" + ], + "webOrigins": [ + "localhost (Allowed CORS origin)", + "cribbi.io (Allowed CORS origin)" + ], + "notBefore": 0, + "bearerOnly": false, + "consentRequired": false, + "standardFlowEnabled": true, + "implicitFlowEnabled": false, + "directAccessGrantsEnabled": true, + "serviceAccountsEnabled": false, + "publicClient": false, + "frontchannelLogout": false, + "protocol": "openid-connect", + "attributes": { + "saml.force.post.binding": "false", + "saml.multivalued.roles": "false", + "oauth2.device.authorization.grant.enabled": "false", + "backchannel.logout.revoke.offline.tokens": "false", + "saml.server.signature.keyinfo.ext": "false", + "use.refresh.tokens": "true", + "oidc.ciba.grant.enabled": "false", + "backchannel.logout.session.required": "true", + "client_credentials.use_refresh_token": "false", + "require.pushed.authorization.requests": "false", + "saml.client.signature": "false", + "id.token.as.detached.signature": "false", + "saml.assertion.signature": "false", + "saml.encrypt": "false", + "saml.server.signature": "false", + "exclude.session.state.from.auth.response": "false", + "saml.artifact.binding": "false", + "saml_force_name_id_format": "false", + "acr.loa.map": "{}", + "tls.client.certificate.bound.access.tokens": "false", + "saml.authnstatement": "false", + "display.on.consent.screen": "false", + "token.response.type.bearer.lower-case": "false", + "saml.onetimeuse.condition": "false" + }, + "authenticationFlowBindingOverrides": {}, + "fullScopeAllowed": true, + "nodeReRegistrationTimeout": -1, + "defaultClientScopes": [ + "web-origins", + "profile", + "roles", + "email" + ], + "optionalClientScopes": [ + "address", + "phone", + "offline_access", + "microprofile-jwt" + ] + }, + { + "id": "a696932a-e9fc-4598-b656-bc4995a9532e", + "clientId": "realm-management", + "name": "${client_realm-management}", + "surrogateAuthRequired": false, + "enabled": true, + "alwaysDisplayInConsole": false, + "clientAuthenticatorType": "client-secret", + "redirectUris": [], + "webOrigins": [], + "notBefore": 0, + "bearerOnly": true, + "consentRequired": false, + "standardFlowEnabled": true, + "implicitFlowEnabled": false, + "directAccessGrantsEnabled": false, + "serviceAccountsEnabled": false, + "publicClient": false, + "frontchannelLogout": false, + "protocol": "openid-connect", + "attributes": {}, + "authenticationFlowBindingOverrides": {}, + "fullScopeAllowed": false, + "nodeReRegistrationTimeout": 0, + "defaultClientScopes": [ + "web-origins", + "profile", + "roles", + "email" + ], + "optionalClientScopes": [ + "address", + "phone", + "offline_access", + "microprofile-jwt" + ] + }, + { + "id": "50a77f13-4089-4fd1-8648-e13e15259fe0", + "clientId": "security-admin-console", + "name": "${client_security-admin-console}", + "rootUrl": "${authAdminUrl}", + "baseUrl": "/admin/Kong/console/", + "surrogateAuthRequired": false, + "enabled": true, + "alwaysDisplayInConsole": false, + "clientAuthenticatorType": "client-secret", + "redirectUris": [ + "/admin/Kong/console/*" + ], + "webOrigins": [ + "+" + ], + "notBefore": 0, + "bearerOnly": false, + "consentRequired": false, + "standardFlowEnabled": true, + "implicitFlowEnabled": false, + "directAccessGrantsEnabled": false, + "serviceAccountsEnabled": false, + "publicClient": true, + "frontchannelLogout": false, + "protocol": "openid-connect", + "attributes": { + "pkce.code.challenge.method": "S256" + }, + "authenticationFlowBindingOverrides": {}, + "fullScopeAllowed": false, + "nodeReRegistrationTimeout": 0, + "protocolMappers": [ + { + "id": "16d66308-424e-4452-85a2-52cff0320374", + "name": "locale", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "locale", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "locale", + "jsonType.label": "String" + } + } + ], + "defaultClientScopes": [ + "web-origins", + "profile", + "roles", + "email" + ], + "optionalClientScopes": [ + "address", + "phone", + "offline_access", + "microprofile-jwt" + ] + } + ], + "clientScopes": [ + { + "id": "67332a08-3545-43d0-bc9b-96ec04ab7b1d", + "name": "microprofile-jwt", + "description": "Microprofile - JWT built-in scope", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "true", + "display.on.consent.screen": "false" + }, + "protocolMappers": [ + { + "id": "29e8353e-1062-461c-bcbc-24533b66c4f1", + "name": "upn", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-property-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "username", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "upn", + "jsonType.label": "String" + } + }, + { + "id": "3dc57511-4b31-4711-baf2-e7e4a50e2ef6", + "name": "groups", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-realm-role-mapper", + "consentRequired": false, + "config": { + "multivalued": "true", + "user.attribute": "foo", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "groups", + "jsonType.label": "String" + } + } + ] + }, + { + "id": "e5b5ed97-ee0c-4c02-ad2d-c0101b0e0afa", + "name": "profile", + "description": "OpenID Connect built-in scope: profile", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "true", + "display.on.consent.screen": "true", + "consent.screen.text": "${profileScopeConsentText}" + }, + "protocolMappers": [ + { + "id": "f7273dce-bbc2-4c81-a254-85ff4f085aee", + "name": "given name", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-property-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "firstName", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "given_name", + "jsonType.label": "String" + } + }, + { + "id": "071021ea-04dd-4488-818a-fb0f05974405", + "name": "locale", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "locale", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "locale", + "jsonType.label": "String" + } + }, + { + "id": "e7957678-5936-4be8-af5c-f6c0d3fac1c6", + "name": "zoneinfo", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "zoneinfo", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "zoneinfo", + "jsonType.label": "String" + } + }, + { + "id": "904f3690-0e12-4963-8e8d-19cfe8ee2584", + "name": "website", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "website", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "website", + "jsonType.label": "String" + } + }, + { + "id": "924e8b62-a034-4965-9774-31e2194deac1", + "name": "updated at", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "updatedAt", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "updated_at", + "jsonType.label": "String" + } + }, + { + "id": "f824795d-93ed-41aa-9df4-a69aa5ce8e9b", + "name": "username", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-property-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "username", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "preferred_username", + "jsonType.label": "String" + } + }, + { + "id": "c7f4abf7-80ff-4af1-bb8d-fed39588b902", + "name": "middle name", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "middleName", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "middle_name", + "jsonType.label": "String" + } + }, + { + "id": "ea2ecaf4-5bc2-4b1d-9787-44f7336a485d", + "name": "full name", + "protocol": "openid-connect", + "protocolMapper": "oidc-full-name-mapper", + "consentRequired": false, + "config": { + "id.token.claim": "true", + "access.token.claim": "true", + "userinfo.token.claim": "true" + } + }, + { + "id": "b5c860eb-a96f-42de-bc30-d57de18e8167", + "name": "family name", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-property-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "lastName", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "family_name", + "jsonType.label": "String" + } + }, + { + "id": "b31777f1-d8d4-47b6-9cfc-c0a6c6bf9f3c", + "name": "nickname", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "nickname", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "nickname", + "jsonType.label": "String" + } + }, + { + "id": "35a54a53-7ea0-4082-8979-1ad167d6bcee", + "name": "gender", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "gender", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "gender", + "jsonType.label": "String" + } + }, + { + "id": "f98c231e-3d9d-400e-9ff8-3ed607d5c89c", + "name": "profile", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "profile", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "profile", + "jsonType.label": "String" + } + }, + { + "id": "6159c05d-fec9-407e-b433-596460417380", + "name": "picture", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "picture", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "picture", + "jsonType.label": "String" + } + }, + { + "id": "352521b1-7188-4cdd-bcc9-a5e5294f2a00", + "name": "birthdate", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "birthdate", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "birthdate", + "jsonType.label": "String" + } + } + ] + }, + { + "id": "3e886f78-4185-4d08-9d4c-cf4322a3f483", + "name": "email", + "description": "OpenID Connect built-in scope: email", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "true", + "display.on.consent.screen": "true", + "consent.screen.text": "${emailScopeConsentText}" + }, + "protocolMappers": [ + { + "id": "0f38213b-565b-49f3-a1f9-7f3f5c40a93b", + "name": "email", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-property-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "email", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "email", + "jsonType.label": "String" + } + }, + { + "id": "58c8e210-5154-49d3-8515-14826db18ccd", + "name": "email verified", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-property-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "emailVerified", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "email_verified", + "jsonType.label": "boolean" + } + } + ] + }, + { + "id": "3f5aafd7-c703-4aa7-881e-d0a2cd1ff022", + "name": "phone", + "description": "OpenID Connect built-in scope: phone", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "true", + "display.on.consent.screen": "true", + "consent.screen.text": "${phoneScopeConsentText}" + }, + "protocolMappers": [ + { + "id": "42c0ddb2-d2c6-4766-8ac6-b7573e5aa4e0", + "name": "phone number", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "phoneNumber", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "phone_number", + "jsonType.label": "String" + } + }, + { + "id": "6e0ec5d2-6149-4ba8-882f-d2f808750ac0", + "name": "phone number verified", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "phoneNumberVerified", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "phone_number_verified", + "jsonType.label": "boolean" + } + } + ] + }, + { + "id": "1c14fd95-79a4-4142-956a-68369ad383ba", + "name": "roles", + "description": "OpenID Connect scope for add user roles to the access token", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "false", + "display.on.consent.screen": "true", + "consent.screen.text": "${rolesScopeConsentText}" + }, + "protocolMappers": [ + { + "id": "1c0dcbe2-8934-4ff7-bfda-75d7f4499f61", + "name": "client roles", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-client-role-mapper", + "consentRequired": false, + "config": { + "user.attribute": "foo", + "access.token.claim": "true", + "claim.name": "resource_access.${client_id}.roles", + "jsonType.label": "String", + "multivalued": "true" + } + }, + { + "id": "a0228fb1-992d-4981-80a1-282413ffa750", + "name": "realm roles", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-realm-role-mapper", + "consentRequired": false, + "config": { + "user.attribute": "foo", + "access.token.claim": "true", + "claim.name": "realm_access.roles", + "jsonType.label": "String", + "multivalued": "true" + } + }, + { + "id": "aa809dfb-4e86-4b07-a108-982ff5ce05f2", + "name": "audience resolve", + "protocol": "openid-connect", + "protocolMapper": "oidc-audience-resolve-mapper", + "consentRequired": false, + "config": {} + } + ] + }, + { + "id": "984e29a9-934b-48e8-8765-c05b030192db", + "name": "offline_access", + "description": "OpenID Connect built-in scope: offline_access", + "protocol": "openid-connect", + "attributes": { + "consent.screen.text": "${offlineAccessScopeConsentText}", + "display.on.consent.screen": "true" + } + }, + { + "id": "fa54415e-c8de-414e-bfba-2efad0cc096f", + "name": "role_list", + "description": "SAML role list", + "protocol": "saml", + "attributes": { + "consent.screen.text": "${samlRoleListScopeConsentText}", + "display.on.consent.screen": "true" + }, + "protocolMappers": [ + { + "id": "6c111b35-14f0-4080-a729-3dcf54c3f486", + "name": "role list", + "protocol": "saml", + "protocolMapper": "saml-role-list-mapper", + "consentRequired": false, + "config": { + "single": "false", + "attribute.nameformat": "Basic", + "attribute.name": "Role" + } + } + ] + }, + { + "id": "b5ba65c3-f227-4226-a61f-f7903b9dda79", + "name": "web-origins", + "description": "OpenID Connect scope for add allowed web origins to the access token", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "false", + "display.on.consent.screen": "false", + "consent.screen.text": "" + }, + "protocolMappers": [ + { + "id": "aaf653b5-63d0-4653-ba4b-0d6a5adbb503", + "name": "allowed web origins", + "protocol": "openid-connect", + "protocolMapper": "oidc-allowed-origins-mapper", + "consentRequired": false, + "config": {} + } + ] + }, + { + "id": "b6ddeac5-64c3-409b-8455-6199f81afaa7", + "name": "address", + "description": "OpenID Connect built-in scope: address", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "true", + "display.on.consent.screen": "true", + "consent.screen.text": "${addressScopeConsentText}" + }, + "protocolMappers": [ + { + "id": "2026f3a1-de52-4d85-bf9e-2c42b4125d5d", + "name": "address", + "protocol": "openid-connect", + "protocolMapper": "oidc-address-mapper", + "consentRequired": false, + "config": { + "user.attribute.formatted": "formatted", + "user.attribute.country": "country", + "user.attribute.postal_code": "postal_code", + "userinfo.token.claim": "true", + "user.attribute.street": "street", + "id.token.claim": "true", + "user.attribute.region": "region", + "access.token.claim": "true", + "user.attribute.locality": "locality" + } + } + ] + } + ], + "defaultDefaultClientScopes": [ + "role_list", + "profile", + "email", + "roles", + "web-origins" + ], + "defaultOptionalClientScopes": [ + "offline_access", + "address", + "phone", + "microprofile-jwt" + ], + "browserSecurityHeaders": { + "contentSecurityPolicyReportOnly": "", + "xContentTypeOptions": "nosniff", + "xRobotsTag": "none", + "xFrameOptions": "SAMEORIGIN", + "contentSecurityPolicy": "frame-src 'self'; frame-ancestors 'self'; object-src 'none';", + "xXSSProtection": "1; mode=block", + "strictTransportSecurity": "max-age=31536000; includeSubDomains" + }, + "smtpServer": {}, + "eventsEnabled": false, + "eventsListeners": [ + "jboss-logging" + ], + "enabledEventTypes": [], + "adminEventsEnabled": false, + "adminEventsDetailsEnabled": false, + "identityProviders": [], + "identityProviderMappers": [], + "components": { + "org.keycloak.services.clientregistration.policy.ClientRegistrationPolicy": [ + { + "id": "047ce841-138f-4a63-adc2-41c3314222ba", + "name": "Trusted Hosts", + "providerId": "trusted-hosts", + "subType": "anonymous", + "subComponents": {}, + "config": { + "host-sending-registration-request-must-match": [ + "true" + ], + "client-uris-must-match": [ + "true" + ] + } + }, + { + "id": "1634ff3d-d6e8-4f42-a8a7-38a0ccb6e4f2", + "name": "Consent Required", + "providerId": "consent-required", + "subType": "anonymous", + "subComponents": {}, + "config": {} + }, + { + "id": "6ddd1fd4-598a-4cc3-9890-ed4f0586362c", + "name": "Allowed Client Scopes", + "providerId": "allowed-client-templates", + "subType": "anonymous", + "subComponents": {}, + "config": { + "allow-default-scopes": [ + "true" + ] + } + }, + { + "id": "35e64bb1-cfbe-4343-be5c-fbc2218b8b2a", + "name": "Max Clients Limit", + "providerId": "max-clients", + "subType": "anonymous", + "subComponents": {}, + "config": { + "max-clients": [ + "200" + ] + } + }, + { + "id": "656ba51c-48ee-427d-8896-e1af0e0f4d5b", + "name": "Allowed Client Scopes", + "providerId": "allowed-client-templates", + "subType": "authenticated", + "subComponents": {}, + "config": { + "allow-default-scopes": [ + "true" + ] + } + }, + { + "id": "b9d0fbbf-3f54-4f14-8748-4c00dd43bf7c", + "name": "Allowed Protocol Mapper Types", + "providerId": "allowed-protocol-mappers", + "subType": "authenticated", + "subComponents": {}, + "config": { + "allowed-protocol-mapper-types": [ + "saml-role-list-mapper", + "oidc-sha256-pairwise-sub-mapper", + "oidc-address-mapper", + "oidc-usermodel-property-mapper", + "oidc-full-name-mapper", + "saml-user-attribute-mapper", + "saml-user-property-mapper", + "oidc-usermodel-attribute-mapper" + ] + } + }, + { + "id": "4f0f7c7e-fb7f-4c05-8e91-4715e9e0d163", + "name": "Allowed Protocol Mapper Types", + "providerId": "allowed-protocol-mappers", + "subType": "anonymous", + "subComponents": {}, + "config": { + "allowed-protocol-mapper-types": [ + "oidc-address-mapper", + "oidc-full-name-mapper", + "saml-user-property-mapper", + "oidc-usermodel-attribute-mapper", + "oidc-sha256-pairwise-sub-mapper", + "saml-role-list-mapper", + "saml-user-attribute-mapper", + "oidc-usermodel-property-mapper" + ] + } + }, + { + "id": "73f90916-f316-45b1-a5f4-c01dadfb02e8", + "name": "Full Scope Disabled", + "providerId": "scope", + "subType": "anonymous", + "subComponents": {}, + "config": {} + } + ], + "org.keycloak.keys.KeyProvider": [ + { + "id": "1bb336de-2a5a-4c52-a6d7-7d8de191d5b3", + "name": "rsa-enc-generated", + "providerId": "rsa-enc-generated", + "subComponents": {}, + "config": { + "priority": [ + "100" + ], + "algorithm": [ + "RSA-OAEP" + ] + } + }, + { + "id": "b91a01f0-a022-40ef-9a6f-2525408d65ba", + "name": "rsa-generated", + "providerId": "rsa-generated", + "subComponents": {}, + "config": { + "priority": [ + "100" + ] + } + }, + { + "id": "97787b65-617e-4f76-a448-efd954e90f76", + "name": "hmac-generated", + "providerId": "hmac-generated", + "subComponents": {}, + "config": { + "priority": [ + "100" + ], + "algorithm": [ + "HS256" + ] + } + }, + { + "id": "c8e87279-c3c9-40f8-aadf-0aed34733df9", + "name": "aes-generated", + "providerId": "aes-generated", + "subComponents": {}, + "config": { + "priority": [ + "100" + ] + } + } + ] + }, + "internationalizationEnabled": false, + "supportedLocales": [], + "authenticationFlows": [ + { + "id": "f180127f-0236-4ac9-a512-1faf661ce8f4", + "alias": "Account verification options", + "description": "Method with which to verity the existing account", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "idp-email-verification", + "authenticatorFlow": false, + "requirement": "ALTERNATIVE", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "ALTERNATIVE", + "priority": 20, + "autheticatorFlow": true, + "flowAlias": "Verify Existing Account by Re-authentication", + "userSetupAllowed": false + } + ] + }, + { + "id": "deec2692-a27c-4aaf-b12d-096dd94e80bb", + "alias": "Authentication Options", + "description": "Authentication options.", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "basic-auth", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "basic-auth-otp", + "authenticatorFlow": false, + "requirement": "DISABLED", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "auth-spnego", + "authenticatorFlow": false, + "requirement": "DISABLED", + "priority": 30, + "autheticatorFlow": false, + "userSetupAllowed": false + } + ] + }, + { + "id": "46e967c9-e9f3-4902-bed7-b7fcd7ac552d", + "alias": "Browser - Conditional OTP", + "description": "Flow to determine if the OTP is required for the authentication", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "conditional-user-configured", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "auth-otp-form", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + } + ] + }, + { + "id": "90dcf889-ae92-407f-b80c-3d895a0944b4", + "alias": "Direct Grant - Conditional OTP", + "description": "Flow to determine if the OTP is required for the authentication", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "conditional-user-configured", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "direct-grant-validate-otp", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + } + ] + }, + { + "id": "f7d55ec4-fff1-4c0c-bf0a-1bd9e6738bff", + "alias": "First broker login - Conditional OTP", + "description": "Flow to determine if the OTP is required for the authentication", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "conditional-user-configured", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "auth-otp-form", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + } + ] + }, + { + "id": "0a8e1e82-33e8-48c0-b0db-38a20ffe9a2d", + "alias": "Handle Existing Account", + "description": "Handle what to do if there is existing account with same email/username like authenticated identity provider", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "idp-confirm-link", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "REQUIRED", + "priority": 20, + "autheticatorFlow": true, + "flowAlias": "Account verification options", + "userSetupAllowed": false + } + ] + }, + { + "id": "1db84d52-1c92-4ce4-95c0-033cfe94f0f3", + "alias": "Reset - Conditional OTP", + "description": "Flow to determine if the OTP should be reset or not. Set to REQUIRED to force.", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "conditional-user-configured", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "reset-otp", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + } + ] + }, + { + "id": "02deb437-dc9c-4e36-b73f-34fa609bf5c0", + "alias": "User creation or linking", + "description": "Flow for the existing/non-existing user alternatives", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticatorConfig": "create unique user config", + "authenticator": "idp-create-user-if-unique", + "authenticatorFlow": false, + "requirement": "ALTERNATIVE", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "ALTERNATIVE", + "priority": 20, + "autheticatorFlow": true, + "flowAlias": "Handle Existing Account", + "userSetupAllowed": false + } + ] + }, + { + "id": "6820ed9f-e18d-4ad1-9e08-79a369f1d501", + "alias": "Verify Existing Account by Re-authentication", + "description": "Reauthentication of existing account", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "idp-username-password-form", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "CONDITIONAL", + "priority": 20, + "autheticatorFlow": true, + "flowAlias": "First broker login - Conditional OTP", + "userSetupAllowed": false + } + ] + }, + { + "id": "0de7d34e-cdea-49eb-93b2-241c83b6aeae", + "alias": "browser", + "description": "browser based authentication", + "providerId": "basic-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "auth-cookie", + "authenticatorFlow": false, + "requirement": "ALTERNATIVE", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "auth-spnego", + "authenticatorFlow": false, + "requirement": "DISABLED", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "identity-provider-redirector", + "authenticatorFlow": false, + "requirement": "ALTERNATIVE", + "priority": 25, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "ALTERNATIVE", + "priority": 30, + "autheticatorFlow": true, + "flowAlias": "forms", + "userSetupAllowed": false + } + ] + }, + { + "id": "8ee4765d-e660-448d-8fd8-a356dc08d88e", + "alias": "clients", + "description": "Base authentication for clients", + "providerId": "client-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "client-secret", + "authenticatorFlow": false, + "requirement": "ALTERNATIVE", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "client-jwt", + "authenticatorFlow": false, + "requirement": "ALTERNATIVE", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "client-secret-jwt", + "authenticatorFlow": false, + "requirement": "ALTERNATIVE", + "priority": 30, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "client-x509", + "authenticatorFlow": false, + "requirement": "ALTERNATIVE", + "priority": 40, + "autheticatorFlow": false, + "userSetupAllowed": false + } + ] + }, + { + "id": "bd9c9450-1a92-4ffc-ac3c-b1b8c3a038d2", + "alias": "direct grant", + "description": "OpenID Connect Resource Owner Grant", + "providerId": "basic-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "direct-grant-validate-username", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "direct-grant-validate-password", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "CONDITIONAL", + "priority": 30, + "autheticatorFlow": true, + "flowAlias": "Direct Grant - Conditional OTP", + "userSetupAllowed": false + } + ] + }, + { + "id": "2727dd7b-89d9-4063-b813-4489cc7310fb", + "alias": "docker auth", + "description": "Used by Docker clients to authenticate against the IDP", + "providerId": "basic-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "docker-http-basic-authenticator", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + } + ] + }, + { + "id": "9e332813-ea2e-46e1-bd74-323b49fe7a40", + "alias": "first broker login", + "description": "Actions taken after first broker login with identity provider account, which is not yet linked to any Keycloak account", + "providerId": "basic-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticatorConfig": "review profile config", + "authenticator": "idp-review-profile", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "REQUIRED", + "priority": 20, + "autheticatorFlow": true, + "flowAlias": "User creation or linking", + "userSetupAllowed": false + } + ] + }, + { + "id": "710dfe13-0fd3-48d3-959d-a541620544e3", + "alias": "forms", + "description": "Username, password, otp and other auth forms.", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "auth-username-password-form", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "CONDITIONAL", + "priority": 20, + "autheticatorFlow": true, + "flowAlias": "Browser - Conditional OTP", + "userSetupAllowed": false + } + ] + }, + { + "id": "3c9456b1-8c60-4409-af25-af6f567cf7c0", + "alias": "http challenge", + "description": "An authentication flow based on challenge-response HTTP Authentication Schemes", + "providerId": "basic-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "no-cookie-redirect", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "REQUIRED", + "priority": 20, + "autheticatorFlow": true, + "flowAlias": "Authentication Options", + "userSetupAllowed": false + } + ] + }, + { + "id": "214d41fe-ba80-478b-bcd9-a15221f79801", + "alias": "registration", + "description": "registration flow", + "providerId": "basic-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "registration-page-form", + "authenticatorFlow": true, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": true, + "flowAlias": "registration form", + "userSetupAllowed": false + } + ] + }, + { + "id": "bd3b9631-d962-43cb-9042-580f30e5544e", + "alias": "registration form", + "description": "registration form", + "providerId": "form-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "registration-user-creation", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "registration-profile-action", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 40, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "registration-password-action", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 50, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "registration-recaptcha-action", + "authenticatorFlow": false, + "requirement": "DISABLED", + "priority": 60, + "autheticatorFlow": false, + "userSetupAllowed": false + } + ] + }, + { + "id": "f9ef35b4-e352-4637-8988-0b06810485a0", + "alias": "reset credentials", + "description": "Reset credentials for a user if they forgot their password or something", + "providerId": "basic-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "reset-credentials-choose-user", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "reset-credential-email", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "reset-password", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 30, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "CONDITIONAL", + "priority": 40, + "autheticatorFlow": true, + "flowAlias": "Reset - Conditional OTP", + "userSetupAllowed": false + } + ] + }, + { + "id": "5ffd4f1f-30a0-4c96-adde-407a08d036cf", + "alias": "saml ecp", + "description": "SAML ECP Profile Authentication Flow", + "providerId": "basic-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "http-basic-authenticator", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + } + ] + } + ], + "authenticatorConfig": [ + { + "id": "335da768-988c-46a4-9928-e97285cf23b2", + "alias": "create unique user config", + "config": { + "require.password.update.after.registration": "false" + } + }, + { + "id": "b671f49e-3824-4c80-b933-540a55f1dd37", + "alias": "review profile config", + "config": { + "update.profile.on.first.login": "missing" + } + } + ], + "requiredActions": [ + { + "alias": "CONFIGURE_TOTP", + "name": "Configure OTP", + "providerId": "CONFIGURE_TOTP", + "enabled": true, + "defaultAction": false, + "priority": 10, + "config": {} + }, + { + "alias": "terms_and_conditions", + "name": "Terms and Conditions", + "providerId": "terms_and_conditions", + "enabled": false, + "defaultAction": false, + "priority": 20, + "config": {} + }, + { + "alias": "UPDATE_PASSWORD", + "name": "Update Password", + "providerId": "UPDATE_PASSWORD", + "enabled": true, + "defaultAction": false, + "priority": 30, + "config": {} + }, + { + "alias": "UPDATE_PROFILE", + "name": "Update Profile", + "providerId": "UPDATE_PROFILE", + "enabled": true, + "defaultAction": false, + "priority": 40, + "config": {} + }, + { + "alias": "VERIFY_EMAIL", + "name": "Verify Email", + "providerId": "VERIFY_EMAIL", + "enabled": true, + "defaultAction": false, + "priority": 50, + "config": {} + }, + { + "alias": "delete_account", + "name": "Delete Account", + "providerId": "delete_account", + "enabled": false, + "defaultAction": false, + "priority": 60, + "config": {} + }, + { + "alias": "update_user_locale", + "name": "Update User Locale", + "providerId": "update_user_locale", + "enabled": true, + "defaultAction": false, + "priority": 1000, + "config": {} + } + ], + "browserFlow": "browser", + "registrationFlow": "registration", + "directGrantFlow": "direct grant", + "resetCredentialsFlow": "reset credentials", + "clientAuthenticationFlow": "clients", + "dockerAuthenticationFlow": "docker auth", + "attributes": { + "cibaBackchannelTokenDeliveryMode": "poll", + "cibaExpiresIn": "120", + "cibaAuthRequestedUserHint": "login_hint", + "oauth2DeviceCodeLifespan": "600", + "oauth2DevicePollingInterval": "5", + "parRequestUriLifespan": "60", + "cibaInterval": "5" + }, + "keycloakVersion": "17.0.1", + "userManagedAccessAllowed": false, + "clientProfiles": { + "profiles": [] + }, + "clientPolicies": { + "policies": [] + } +} \ No newline at end of file diff --git a/ph-ee-env-template/helm/ph-ee-engine/templates/post-installation-job/job.yaml b/ph-ee-env-template/helm/ph-ee-engine/templates/post-installation-job/job.yaml new file mode 100644 index 000000000..0e57c680b --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/templates/post-installation-job/job.yaml @@ -0,0 +1,101 @@ +{{- if .Values.post_installation_job.enabled }} +apiVersion: batch/v1 +kind: Job +metadata: + name: post-installation-job + annotations: + "helm.sh/hook": post-install,post-upgrade + "helm.sh/hook-delete-policy": hook-succeeded,before-hook-creation +spec: + template: + spec: + serviceAccountName: job-creator + containers: + - name: post-installation-job + image: ubuntu:latest + securityContext: + privileged: true + env: + - name: NAMESPACE + value: {{ .Release.Namespace }} + workingDir: /app + command: + - "/bin/sh" + - "-c" + args: + - | + #!/bin/bash + + # Install required dependencies + apt-get update + # sudo apt-get update + apt-get --assume-yes install apt-transport-https ca-certificates curl gnupg lsb-release + + #install kubectl + apt-get install -y apt-transport-https ca-certificates curl gpg + + curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.28/deb/Release.key | gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg + + # This overwrites any existing configuration in /etc/apt/sources.list.d/kubernetes.list + echo 'deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.28/deb/ /' | tee /etc/apt/sources.list.d/kubernetes.list + + apt-get install -y kubelet kubeadm kubectl + apt-mark hold kubelet kubeadm kubectl + apt-get install -y kubectl + curl -LO "https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/linux/amd64/kubectl" + chmod +x ./kubectl + mv ./kubectl /usr/local/bin/kubectl + kubectl version + + # Install Docker + apt-get install sysvinit-utils + apt-get --assume-yes install docker-ce docker-ce-cli containerd.io + #---------docker start steps------- + # service docker start + # Verify Docker is running + + apt-get --assume-yes install git + apt-get --assume-yes install make + + git clone https://github.com/openMF/ph-ee-env-labs.git + cd ph-ee-env-labs/helm/es-secret/ + make secrets || echo "elastic-secrets" already exists + + cd ../../helm/kibana-secret + make secrets || echo "kibana-secrets" already exists + kubectl get secrets -n $NAMESPACE + echo ---------------secrets created--------------- + sleep 20 + + #insatll netcat + apt-get update && apt-get install -y netcat-openbsd + echo "------------ netcat installed ---------------" + sleep 10 + SERVICE_HOST=${SERVICE_HOST:-"ph-ee-zeebe-ops"} + SERVICE_PORT=${SERVICE_PORT:-"80"} + until nc -z $SERVICE_HOST $SERVICE_PORT; do + echo "Service $SERVICE_HOST:$SERVICE_PORT is not running. Checking again in 5 seconds..." + sleep 5 + done + + + echo ------zeebe-ops service available----------- + sleep 10 + #Deploy BPMN + kubectl port-forward service/ph-ee-zeebe-ops 5000:80 -n $NAMESPACE & + echo "sleeping to get portforwading ready" + sleep 15 + cd ../../orchestration + sleep 10 + sed -i "/HOST=/c\HOST=http://localhost:5000/zeebe/upload" deployBpmn.sh + cat deployBpmn.sh + cd .. + timeout 180s sh orchestration/deployBpmn.sh && sleep 5 || echo 'deploy Bpmn done' + echo "Removing ph-ee-env-labs directory" + cd .. + rm -rf ph-ee-env-labs + echo ---------------------------successful-------------------------- + + restartPolicy: Never + backoffLimit: 0 +{{- end }} diff --git a/ph-ee-env-template/helm/ph-ee-engine/templates/post-installation-job/role.yaml b/ph-ee-env-template/helm/ph-ee-engine/templates/post-installation-job/role.yaml new file mode 100644 index 000000000..5ec624401 --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/templates/post-installation-job/role.yaml @@ -0,0 +1,16 @@ +{{- if .Values.post_installation_job.enabled }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: job-creator-role +rules: +- apiGroups: ['*'] + resources: ["secrets"] + verbs: ["create", "get", "watch", "list"] +- apiGroups: ['*'] + resources: ["services", "pods"] + verbs: [ "get", "watch", "list"] +- apiGroups: ['*'] + resources: ["pods/portforward"] + verbs: [ "create"] +{{- end }} \ No newline at end of file diff --git a/ph-ee-env-template/helm/ph-ee-engine/templates/post-installation-job/rolebinding.yaml b/ph-ee-env-template/helm/ph-ee-engine/templates/post-installation-job/rolebinding.yaml new file mode 100644 index 000000000..145dd28b4 --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/templates/post-installation-job/rolebinding.yaml @@ -0,0 +1,13 @@ +{{- if .Values.post_installation_job.enabled }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: job-creator-role-binding +subjects: +- kind: ServiceAccount + name: job-creator +roleRef: + kind: Role + name: job-creator-role + apiGroup: rbac.authorization.k8s.io +{{- end }} diff --git a/ph-ee-env-template/helm/ph-ee-engine/templates/post-installation-job/service-account.yaml b/ph-ee-env-template/helm/ph-ee-engine/templates/post-installation-job/service-account.yaml new file mode 100644 index 000000000..24bef7cb6 --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/templates/post-installation-job/service-account.yaml @@ -0,0 +1,6 @@ +{{- if .Values.post_installation_job.enabled }} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: job-creator +{{- end }} \ No newline at end of file diff --git a/ph-ee-env-template/helm/ph-ee-engine/templates/realm-secret.yaml b/ph-ee-env-template/helm/ph-ee-engine/templates/realm-secret.yaml new file mode 100644 index 000000000..bd8204e93 --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/templates/realm-secret.yaml @@ -0,0 +1,13 @@ +{{ if and (.Files.Glob "setup-files/kong-keycloak-realm.json") (.Values.keycloak.enabled) }} + +apiVersion: v1 +kind: Secret +metadata: + name: realm-secret +# labels: +# app: keycloak +type: Opaque +data: +{{ (.Files.Glob "setup-files/kong-keycloak-realm.json").AsSecrets | indent 2 }} + +{{ end }} \ No newline at end of file diff --git a/ph-ee-env-template/helm/ph-ee-engine/templates/tests/_helpers.tpl b/ph-ee-env-template/helm/ph-ee-engine/templates/tests/_helpers.tpl new file mode 100644 index 000000000..fc3f9a252 --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/templates/tests/_helpers.tpl @@ -0,0 +1,58 @@ +{{/* +This template defines a reusable environment section. +It directly provides values. +*/}} + +{{- define "inttest.env" -}} + env: + - name: "OPERATIONS_APP_CONTACTPOINT" + value: "http://ph-ee-operations-app:80" + - name: "BULK_PROCESSOR_CONTACTPOINT" + value: "https://ph-ee-connector-bulk:8443" + - name: "CHANNEL_CONNECTOR_CONTACTPOINT" + value: "https://ph-ee-connector-channel:8443" + - name: "LOGGING_LEVEL_ROOT" + value: "INFO" + - name: "MAX_RETRY_COUNT" + value: "5" + - name: "RETRY_INTERVAL" + value: "15000" + - name: "DEFAULTS_TENANT" + value: "gorilla" + - name: "DEFAULTS_AUTHORIZATION" + value: "Basic bWlmb3M6cGFzc3dvcmQ=" + - name: "CHANNEL_BASE-URL" + value: "https://ph-ee-connector-channel:8443" + - name: "CHANNEL_CONTACTPOINT" + value: "https://ph-ee-connector-channel:8443" + - name: "SAVINGS_CONTACTPOINT" + value: "https://fineract-server:8443" + - name: "LOAN_CONTACTPOINT" + value: "https://fineract-server:8443" + - name: "MOCK_SERVER_PORT" + value: "53013" + - name: "IDENTITY_ACCOUNT_MAPPER_CONTACTPOINT" + value: "http://ph-ee-identity-account-mapper:80" + - name: "MIFOS_CONNECTOR_CONTACTPOINT" + value: "http://ph-ee-connector-ams-mifos:80" + - name: "AMSMIFOS_MOCK_BASE_URL" + value: "http://ph-ee-connector-ams-mifos:70" + - name: "MOCK_PAYMENT_SCHEMA_CONTACTPOINT" + value: "http://ph-ee-connector-mock-payment-schema:8080" + - name: "MY_POD_IP" + valueFrom: + fieldRef: + fieldPath: status.podIP + - name: "CALLBACK_URL" + value: "http://$(MY_POD_IP):53013" + - name: "PAYBILL_MPESA_CONNECTOR_CONTACTPOINT" + value: "" + - name: "VOUCHER_MANAGEMENT_CONTACTPOINT" + value: "http://ph-ee-vouchers:80" + - name: "BILLPAY_CONTACTPOINT" + value: "http://ph-ee-connector-bill-pay:8080" + - name: "awaitly_maxWaitTime" + value: "60" + - name: "GLOBAL_WAIT_TIME_MS" + value: "5000" +{{- end }} diff --git a/ph-ee-env-template/helm/ph-ee-engine/templates/tests/integration-test-ams.yaml b/ph-ee-env-template/helm/ph-ee-engine/templates/tests/integration-test-ams.yaml new file mode 100644 index 000000000..e5f7a98b2 --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/templates/tests/integration-test-ams.yaml @@ -0,0 +1,25 @@ +apiVersion: v1 +kind: Pod +metadata: + name: g2p-sandbox-test-ams + labels: + app: "integration-test-ams" + annotations: + "helm.sh/hook": test-success +spec: + containers: + - name: g2p-sandbox-test-ams + image: "{{ .Values.integration_test.image}}" + imagePullPolicy: "Always" + command: [ "/bin/bash" , "-c" ] + args: + - ./gradlew test -Dcucumber.filter.tags="@amsIntegration" ; echo 'Test complete' ; sleep 1500 ; echo 'pod terminate' + {{- include "inttest.env" . | nindent 4 }} + resources: + limits: + cpu: "{{.Values.integration_test.limits.cpu}}" + memory: "{{.Values.integration_test.limits.memory}}" + requests: + cpu: "{{.Values.integration_test.requests.cpu}}" + memory: "{{.Values.integration_test.requests.memory}}" + restartPolicy: Never diff --git a/ph-ee-env-template/helm/ph-ee-engine/templates/tests/integration-test-gov.yaml b/ph-ee-env-template/helm/ph-ee-engine/templates/tests/integration-test-gov.yaml new file mode 100644 index 000000000..1721d0c8b --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/templates/tests/integration-test-gov.yaml @@ -0,0 +1,26 @@ +apiVersion: v1 +kind: Pod +metadata: + name: g2p-sandbox-test-gov + labels: + app: "integration-test-gov" + annotations: + "helm.sh/hook": test-success +spec: + containers: + - name: g2p-sandbox-test-gov + image: "{{ .Values.integration_test.image}}" + imagePullPolicy: "Always" + command: [ "/bin/bash" , "-c" ] + args: + # - ./gradlew test -Dcucumber.filter.tags="@bd012" ; echo 'Test complete' ; sleep 300 ; echo 'pod terminate' + - ./gradlew test -Dcucumber.filter.tags="@gov and not @ext" ; echo 'Test complete' ; sleep 300 ; echo 'pod terminate' + {{- include "inttest.env" . | nindent 4 }} + resources: + limits: + cpu: "{{.Values.integration_test.limits.cpu}}" + memory: "{{.Values.integration_test.limits.memory}}" + requests: + cpu: "{{.Values.integration_test.requests.cpu}}" + memory: "{{.Values.integration_test.requests.memory}}" + restartPolicy: Never diff --git a/ph-ee-env-template/helm/ph-ee-engine/values.yaml b/ph-ee-env-template/helm/ph-ee-engine/values.yaml new file mode 100644 index 000000000..5853c831b --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/values.yaml @@ -0,0 +1,2235 @@ +ingress: + apiversion: "networking.k8s.io/v1" + +deployment: + apiversion: "apps/v1" + +service: + apiversion: "v1" + +secret: + apiversion: "v1" + +configmap: + apiversion: "v1" + +global: + bucket_name: paymenthub-ee + region: "ap-south-1" + s3BaseUrl: "http://minio:9000" + SPRING_PROFILES_ACTIVE: "bb" + imagePullPolicy: "Always" + LOGGING_LEVEL_ROOT: "INFO" + LOGGING_PATTERN_CONSOLE: "%d{dd-MM-yyyy HH:mm:ss.SSS} %magenta([%thread]) %highlight(%-5level) %logger.%M - %msg%n" + tenants: "" + DFSPIDS: "" + max_execution_threads: 50 + poll_interval: 10 +camunda-platform: + connectors: + enabled: false + global: + zeebe: "{{ .Release.Name }}-zeebe" + elasticsearch: + disableExporter: true + host: "ph-ee-elasticsearch" + identity: + auth: + enabled: false + + zeebe: + enabled: true + env: + # - name: ZEEBE_BROKER_BACKPRESSURE_ENABLED + # value: "false" + - name: ZEEBE_BROKER_EXECUTION_METRICS_EXPORTER_ENABLED + value: "true" + - name: ZEEBE_BROKER_EXPORTERS_ELASTICSEARCH_CLASSNAME + value: "hu.dpc.rt.kafkastreamer.exporter.NoOpExporter" + - name: ZEEBE_BROKER_EXPORTERS_ELASTICSEARCH_JARPATH + value: "/exporters/ph-ee-kafka-exporter.jar" + - name: ZEEBE_BROKER_EXPORTERS_KAFKA_JARPATH + value: "/exporters/ph-ee-kafka-exporter.jar" + - name: ZEEBE_BROKER_EXPORTERS_KAFKA_CLASSNAME + value: "hu.dpc.rt.kafkastreamer.exporter.KafkaExporter" + - name: ZEEBE_BROKER_BACKPRESSURE_VEGAS_INITIALLIMIT + value: "1000" + - name: ZEEBE_BROKER_BACKPRESSURE_VEGAS_ALPHA + value: "2" + - name: ZEEBE_BROKER_BACKPRESSURE_VEGAS_BETA + value: "8" + - name: ZEEBE_BROKER_EXPORTERS_KAFKA_ARGS_INDEX_EVENT + value: 'true' + - name: ZEEBE_BROKER_EXPORTERS_KAFKA_ARGS_INDEX_VARIABLE + value: 'true' + - name: ZEEBE_BROKER_EXPORTERS_KAFKA_ARGS_INDEX_PROCESSINSTANCE + value: 'true' + - name: ZEEBE_BROKER_EXPORTERS_KAFKA_ARGS_INDEX_PROCESS + value: 'true' + - name: ZEEBE_BROKER_EXPORTERS_KAFKA_ARGS_INDEX_INCIDENT + value: 'true' + - name: ZEEBE_BROKER_EXPORTERS_KAFKA_ARGS_INDEX_DEPLOYMENT + value: 'false' + - name: ZEEBE_BROKER_EXPORTERS_KAFKA_ARGS_INDEX_ERROR + value: 'false' + - name: ZEEBE_BROKER_EXPORTERS_KAFKA_ARGS_INDEX_JOB + value: 'false' + - name: ZEEBE_BROKER_EXPORTERS_KAFKA_ARGS_INDEX_VARIABLEDOCUMENT + value: 'false' + - name: ZEEBE_BROKER_EXPORTERS_KAFKA_ARGS_INDEX_WORKFLOWINSTANCE + value: 'false' + - name: ZEEBE_BROKER_EXPORTERS_KAFKA_ARGS_INDEX_CREATETEMPLATE + value: 'false' + + extraInitContainers: + - name: init-ph-ee-kafka-exporter + image: busybox:1.28 + command: ['/bin/sh', '-c'] + args: ['wget -O /exporters/ph-ee-kafka-exporter.jar "https://fynarfin.io/images/exporter-1.3.0-SNAPSHOT.jar"; ls -al /exporters/'] + volumeMounts: + - name: exporters + mountPath: /exporters/ + volumeClaimTemplate: + storageClassName: "gp2" + + image: + repository: camunda/zeebe + tag: 8.2.8 + clusterSize: "1" + partitionCount: "1" + replicationFactor: "1" + cpuThreadCount: "2" + ioThreadCount: "2" + pvcSize: "10Gi" + + resources: + requests: + cpu: 100m + + zeebe-gateway: + replicas: 1 + logLevel: warn + env: + - name: ZEEBE_GATEWAY_THREADS_MANAGEMENTTHREADS + value: "4" + - name: ZEEBE_GATEWAY_MONITORING_ENABLED + value: "true" + + elasticsearch: + enabled: false + fullnameOverride: "zeebe-elasticsearch" + clusterName: "zeebe-elasticsearch" + + operate: + enabled: false + + tasklist: + enabled: false + optimize: + enabled: false + prometheusServiceMonitor: + enabled: true + identity: + enabled: false + +elasticsearch: + enabled: true + # imageTag: 7.17.1 + replicas: 1 + protocol: http + fullnameOverride: "ph-ee-elasticsearch" + clusterName: "ph-ee-elasticsearch" + minimumMasterNodes: 1 + esConfig: + elasticsearch.yml: | + xpack.security.enabled: false + xpack.security.transport.ssl.enabled: false + xpack.security.transport.ssl.verification_mode: certificate + xpack.security.transport.ssl.keystore.path: /usr/share/elasticsearch/config/certs/elastic-certificates.p12 + xpack.security.transport.ssl.truststore.path: /usr/share/elasticsearch/config/certs/elastic-certificates.p12 + xpack.security.http.ssl.enabled: false + xpack.security.http.ssl.truststore.path: /usr/share/elasticsearch/config/certs/elastic-certificates.p12 + xpack.security.http.ssl.keystore.path: /usr/share/elasticsearch/config/certs/elastic-certificates.p12 + secretMounts: + - name: elastic-certificates + secretName: elastic-certificates + path: /usr/share/elasticsearch/config/certs + extraEnvs: + - name: ELASTIC_PASSWORD + valueFrom: + secretKeyRef: + name: elastic-credentials + key: password + + +kibana: + enabled: true + imageTag: 7.16.3 + fullnameOverride: "ph-ee-kibana" + elasticsearchHosts: "http://ph-ee-elasticsearch:9200/" + protocol: http + kibanaConfig: + kibana.yml: | + monitoring.enabled: false + xpack.encryptedSavedObjects.encryptionKey: 5f4dcc3b5aa765d61d8327deb882cf99 + server.ssl: + enabled: false + key: /usr/share/kibana/config/certs/elastic-certificate.pem + certificate: /usr/share/kibana/config/certs/elastic-certificate.pem + xpack.security.encryptionKey: ${KIBANA_ENCRYPTION_KEY} + elasticsearch.ssl: + certificateAuthorities: /usr/share/kibana/config/certs/elastic-certificate.pem + verificationMode: certificate + secretMounts: + - name: elastic-certificate-pem + secretName: elastic-certificate-pem + path: /usr/share/kibana/config/certs + extraEnvs: + - name: 'ELASTICSEARCH_USERNAME' + valueFrom: + secretKeyRef: + name: elastic-credentials + key: username + - name: 'ELASTICSEARCH_PASSWORD' + valueFrom: + secretKeyRef: + name: elastic-credentials + key: password + - name: 'KIBANA_ENCRYPTION_KEY' + valueFrom: + secretKeyRef: + name: kibana + key: encryptionkey + + +channel: + enabled: false + replicas: 1 + image: docker.io/openmf/ph-ee-connector-channel:v1.9.0 + imagePullPolicy: "Always" + TRANSACTION_ID_LENGTH: 20 + gsma_payee_tenant: "" + redis: + host: "127.0.0.1" + port: 6379 + password: "" + idempotency: + enabled: true + keyFormat: "clientCorrelationId_tenant_api" + apiList: "/channel/transfer,/channel/collection,/channel/gsma/transaction,/channel/transactionRequest" + operations: + url: "http://ph-ee-operations-app:80/api/v1" + authEnabled: false + tenantPrimary: + clientId: "" + clientSecret: "" + tenant: "" + tenantSecondary: + clientId: "" + clientSecret: "" + tenant: "" + livenessProbe: + httpGet: + path: /actuator/health/liveness + port: 8443 + scheme: HTTPS + initialDelaySeconds: 120 + periodSeconds: 30 + failureThreshold: 3 + timeoutSeconds: 5 + readinessProbe: + httpGet: + path: /actuator/health/readiness + port: 8443 + scheme: HTTPS + initialDelaySeconds: 120 + periodSeconds: 30 + failureThreshold: 3 + timeoutSeconds: 5 +# Whether this chart should self-manage its service account, role, and associated role binding. + managedServiceAccount: true +# Custom service account override that the pod will use + serviceAccount: "channel" +# Annotations to add to the ServiceAccount that is created if the serviceAccount value isn't set. + serviceAccountAnnotations: {} +# How long to wait for channel pods to stop gracefully + terminationGracePeriod: 30 +# Extra environment variables for channel container. + envFrom: [] + # - configMapRef: + # name: config-secret + extraEnvs: [] +# This is the PriorityClass settings as defined in +# https://kubernetes.io/docs/concepts/configuration/pod-priority-preemption/#priorityclass + priorityClassName: "" + # ph-ee-connector-channelConfig: "" + # ph-ee-connector-channel: | + # - User that the container will execute as. + # Not necessary to run as root (0) as the channel Deployment use cases do not need access to Kubernetes Node internals + # - Typically not necessarily unless running within environments such as OpenShift. + securityContext: + runAsUser: 0 + privileged: false + resources: + limits: + memory: "512M" + cpu: "500m" + requests: + memory: "512M" + cpu: "100m" + service: + annotations: {} +# Enabling this will publicly expose your channel instance. +# Only enable this if you have security enabled on your cluster + ingress: + enabled: true + path: "/channel" + annotations: {} + backend: {} + stub_backend: {} + deployment: + annotations: {} + affinity: {} + nodeSelector: {} + tolerations: [] + envFrom: [] + # - configMapRef: + # name: config-secret + extraEnvs: [] + # - User that the container will execute as. + # Not necessary to run as root (0) as the channel Deployment use cases do not need access to Kubernetes Node internals + # - Typically not necessarily unless running within environments such as OpenShift. + securityContext: + runAsUser: 0 + privileged: false + resources: + limits: + memory: "512M" + cpu: "500m" + requests: + memory: "512M" + cpu: "100m" +# Allows you to add any config files in /usr/share/ + # such as ph-ee-connector-channel.yml for deployment + # ph-ee-connector-channelConfig: {} + # ph-ee-connector-channel.yml: | + +operations: + enabled: true + mysql: + enabled: true + +operationsmysql: + fullnameOverride: "operationsmysql" + image: + tag: "5.7" + debug: false + auth: + database: "tenants" + username: "mifos" + password: "password" + rootPassword: "4ET6ywqlGt" + initdbScripts: + setup.sql: |- + CREATE DATABASE IF NOT EXISTS phdefault; + CREATE DATABASE IF NOT EXISTS messagegateway; + CREATE DATABASE `voucher_management` + GRANT ALL ON *.* TO 'root'@'%'; + GRANT ALL PRIVILEGES ON messagegateway.* TO 'mifos'; + GRANT ALL PRIVILEGES ON phdefault.* TO 'mifos'; + GRANT ALL PRIVILEGES ON `voucher_management`.* TO 'mifos'; + volumeClaimTemplate: + storageClassName: "gp2" + +ph_ee_connector_ams_mifos: + enabled: false + replicas: 1 + image: docker.io/openmf/ph-ee-connector-ams-mifos:v1.3.0 + imagePullPolicy: "Always" + ams_local_enabled: true + ams_local_interop_host: "fineract-server" + ams_local_account_host: "fineract-server" + ams_local_customer_host: "fineract-server" + ams_local_auth_host: "fineract-server" + ams_local_tenants: "" + ams_local_loan_host: "" +# Whether this chart should self-manage its service account, role, and associated role binding. + managedServiceAccount: true +# Custom service account override that the pod will use + serviceAccount: "" +# Annotations to add to the ServiceAccount that is created if the serviceAccount value isn't set. + serviceAccountAnnotations: {} +# How long to wait for ams-mifos pods to stop gracefully + terminationGracePeriod: 180 +# Extra environment variables for ams-mifos container. + envFrom: [] + # - configMapRef: + # name: config-secret + extraEnvs: [] +# This is the PriorityClass settings as defined in +# https://kubernetes.io/docs/concepts/configuration/pod-priority-preemption/#priorityclass + priorityClassName: "" + # ph-ee-connector-ams-mifosConfig: "" + # ph-ee-connector-ams-mifos.yml: | + # - User that the container will execute as. + # Not necessary to run as root (0) as the ams-mifos Deployment use cases do not need access to Kubernetes Node internals + # - Typically not necessarily unless running within environments such as OpenShift. + securityContext: + runAsUser: 0 + privileged: false + resources: + limits: + memory: "384M" + cpu: "500m" + requests: + memory: "256M" + cpu: "300m" +# Enabling this will publicly expose your ams-mifos instance. +# Only enable this if you have security enabled on your cluster + ingress: + enabled: false + annotations: {} + + deployment: + annotations: {} + affinity: {} + nodeSelector: {} + tolerations: [] + envFrom: [] + # - configMapRef: + # name: config-secret + extraEnvs: [] + # - User that the container will execute as. + # Not necessary to run as root (0) as the zeebeops Deployment use cases do not need access to Kubernetes Node internals + # - Typically not necessarily unless running within environments such as OpenShift. + securityContext: + runAsUser: 0 + privileged: false + resources: + limits: + memory: "512M" + cpu: "500m" + requests: + memory: "512M" + cpu: "100m" +# Allows you to add any config files in /usr/share/ + # such as ph-ee-connector-ams-mifos.yml for deployment + # ph-ee-connector-ams-mifosConfig: {} + # ph-ee-connector-ams-mifos.yml: | + +ph_ee_connector_mojaloop: + enabled: false + replicas: 1 + image: docker.io/openmf/ph-ee-connector-mojaloop:v1.3.0 + imagePullPolicy: "Always" + hostname: "" + switch: + quotes: + host: "" + service: "" + als: + host: "" + service: "" + transfers: + host: "" + service: "" + transactions: + host: "" + service: "" + oracle: + host: "" + livenessProbe: + httpGet: + path: /actuator/health/liveness + port: 9191 + initialDelaySeconds: 120 + periodSeconds: 30 + failureThreshold: 3 + timeoutSeconds: 5 + readinessProbe: + httpGet: + path: /actuator/health/readiness + port: 9191 + initialDelaySeconds: 120 + periodSeconds: 30 + failureThreshold: 3 + timeoutSeconds: 5 +# Whether this chart should self-manage its service account, role, and associated role binding. + managedServiceAccount: true +# Custom service account override that the pod will use + serviceAccount: "" +# Annotations to add to the ServiceAccount that is created if the serviceAccount value isn't set. + serviceAccountAnnotations: {} +# How long to wait for mojaloop pods to stop gracefully + terminationGracePeriod: 30 +# Extra environment variables for mojaloop container. + envFrom: [] + # - configMapRef: + # name: config-secret + extraEnvs: [] +# This is the PriorityClass settings as defined in +# https://kubernetes.io/docs/concepts/configuration/pod-priority-preemption/#priorityclass + priorityClassName: "" + # ph-ee-connector-mojaloop-javaConfig: "" + # ph-ee-connector-mojaloop-java.yml: | + # - User that the container will execute as. + # Not necessary to run as root (0) as the mojaloop Deployment use cases do not need access to Kubernetes Node internals + # - Typically not necessarily unless running within environments such as OpenShift. + securityContext: + runAsUser: 0 + privileged: false + resources: + limits: + memory: "512M" + cpu: "500m" + requests: + memory: "512M" + cpu: "100m" +# Enabling this will publicly expose your mojaloop instance. +# Only enable this if you have security enabled on your cluster + ingress: + enabled: true + path: "/" + annotations: {} + backend: {} + deployment: + annotations: {} + affinity: {} + nodeSelector: {} + tolerations: [] + envFrom: [] + # - configMapRef: + # name: config-secret + extraEnvs: [] + # - User that the container will execute as. + # Not necessary to run as root (0) as the mojaloop Deployment use cases do not need access to Kubernetes Node internals + # - Typically not necessarily unless running within environments such as OpenShift. + securityContext: + runAsUser: 0 + privileged: false + resources: + limits: + memory: "512M" + cpu: "500m" + requests: + memory: "512M" + cpu: "100m" +# Allows you to add any config files in /usr/share/ + # such as ph-ee-connector-mojaloop-java.yml for deployment + # ph-ee-connector-mojaloop-javaConfig: {} + # ph-ee-connector-mojaloop-java.yml: | + +operations_app: + enabled: true + replicas: 1 + image: docker.io/openmf/ph-ee-operations-app:v1.10.0 + imagePullPolicy: "Always" + token_client_channel_secret: "" + minio_public_host: "http://minio:9000" + datasource: + username: "mifos" + password: "password" + host: "operationsmysql" + port: 3306 + schema: "tenants" + livenessProbe: + httpGet: + path: /actuator/health/liveness + port: 9191 + initialDelaySeconds: 120 + periodSeconds: 30 + failureThreshold: 3 + timeoutSeconds: 5 + readinessProbe: + httpGet: + path: /actuator/health/readiness + port: 9191 + initialDelaySeconds: 120 + periodSeconds: 30 + failureThreshold: 3 + timeoutSeconds: 5 +# Whether this chart should self-manage its service account, role, and associated role binding. + managedServiceAccount: true +# Custom service account override that the pod will use + serviceAccount: "" +# Annotations to add to the ServiceAccount that is created if the serviceAccount value isn't set. + serviceAccountAnnotations: {} +# How long to wait for operations_app pods to stop gracefully + terminationGracePeriod: 30 +# Extra environment variables for operations_app container. + envFrom: [] + # - configMapRef: + # name: config-secret + extraEnvs: [] +# This is the PriorityClass settings as defined in +# https://kubernetes.io/docs/concepts/configuration/pod-priority-preemption/#priorityclass + priorityClassName: "" +# operations_appConfig: "" +# operations_app.yml: | +# - User that the container will execute as. +# Not necessary to run as root (0) as the operations_app Deployment use cases do not need access to Kubernetes Node internals +# - Typically not necessarily unless running within environments such as OpenShift. + securityContext: + runAsUser: 0 + privileged: false + resources: + limits: + memory: "512M" + cpu: "500m" + requests: + memory: "512M" + cpu: "100m" +# Enabling this will publicly expose your operations_app instance. +# Only enable this if you have security enabled on your cluster + ingress: + enabled: false + path: "/opsapp" + annotations: {} + backend: {} + deployment: + annotations: {} + affinity: {} + nodeSelector: {} + tolerations: [] + envFrom: [] + # - configMapRef: + # name: config-secret + extraEnvs: [] +# - User that the container will execute as. +# Not necessary to run as root (0) as the operations_app Deployment use cases do not need access to Kubernetes Node internals +# - Typically not necessarily unless running within environments such as OpenShift. + securityContext: + runAsUser: 0 + privileged: false + resources: + limits: + memory: "512M" + cpu: "500m" + requests: + memory: "512M" + cpu: "100m" +# Allows you to add any config files in /usr/share/ + # such as operations_app.yml for deployment + +operations_web: + enabled: true + replicas: 1 + image: docker.io/openmf/ph-ee-operations-web:v1.10.0 + imagePullPolicy: "Always" + imagePullSecrets: [] + webhost: "" + livenessProbe: + httpGet: + path: /actuator/health/liveness + port: 9191 + initialDelaySeconds: 120 + periodSeconds: 30 + failureThreshold: 3 + timeoutSeconds: 5 + readinessProbe: + httpGet: + path: /actuator/health/readiness + port: 9191 + initialDelaySeconds: 120 + periodSeconds: 30 + failureThreshold: 3 + timeoutSeconds: 5 +# Whether this chart should self-manage its service account, role, and associated role binding. + managedServiceAccount: true +# Custom service account override that the pod will use + serviceAccount: "" +# Annotations to add to the ServiceAccount that is created if the serviceAccount value isn't set. + serviceAccountAnnotations: {} +# How long to wait for operations_web pods to stop gracefully + terminationGracePeriod: 30 +# Extra environment variables for operations_web container. + envFrom: [] + # - configMapRef: + # name: config-secret + extraEnvs: [] +# This is the PriorityClass settings as defined in +# https://kubernetes.io/docs/concepts/configuration/pod-priority-preemption/#priorityclass + priorityClassName: "" +# ph-ee-operations-web-configConfig: "" +# ph-ee-operations-web-config.yml: | +# - User that the container will execute as. +# Not necessary to run as root (0) as the operations_web Deployment use cases do not need access to Kubernetes Node internals +# - Typically not necessarily unless running within environments such as OpenShift. + securityContext: + runAsUser: 0 + privileged: false + resources: + limits: + memory: "512M" + cpu: "500m" + requests: + memory: "512M" + cpu: "100m" +# Enabling this will publicly expose your operations_web instance. +# Only enable this if you have security enabled on your cluster + ingress: + enabled: false + path: "/" + annotations: {} + backend: {} + deployment: + config: + - name: ph-ee-operations-web-config + mountPath: "/usr/share/nginx/html/assets/configuration.properties" + subPath: "configuration.properties" + annotations: {} + affinity: {} + nodeSelector: {} + tolerations: [] + envFrom: [] + # - configMapRef: + # name: config-secret + extraEnvs: [] +# - User that the container will execute as. +# Not necessary to run as root (0) as the operation-web Deployment use cases do not need access to Kubernetes Node internals +# - Typically not necessarily unless running within environments such as OpenShift. + securityContext: + runAsUser: 0 + privileged: false + resources: + limits: + memory: "512M" + cpu: "500m" + requests: + memory: "512M" + cpu: "100m" +# Allows you to add any config files in /usr/share/ + # such as ph-ee-operations-web.yml for deployment + # ph-ee-operations-webConfig: {} + # ph-ee-operations-web.yml: | + +identity: + +mpesa: + enabled: false + replicas: 1 + image: "docker.io/openmf/ph-ee-connector-mpesa" + imageTag: "v1.6.0" + zeebe_init_transfer_wait_timer: 10 + tenant: "" + serviceAccountName: "" + callback_host: "" + channel: + host: "" + paygops: + host: "" + roster: + host: "" + accounts: + default: + name: "default" + business_short_code: "7385028" + till: "1234567" + auth_host: "https://sandbox.safaricom.co.ke/oauth/v1/generate" + api_host: "https://sandbox.safaricom.co.ke" + client_key: "0pLxbN83FrOl5Nd0Fh9Zi5BQlMxSL2n5" + client_secret: "YzuGNoJxeub8ZC6d" + pass_key: "bfb279f9aa9bdbcf158e97dd71a467cd2e0c893059b10f78e6b72ada1ed2c919" + roster: + name: "roster" + business_short_code: "7385028" + till: "1234567" + auth_host: "https://sandbox.safaricom.co.ke/oauth/v1/generate" + api_host: "https://sandbox.safaricom.co.ke" + client_key: "0pLxbN83FrOl5Nd0Fh9Zi5BQlMxSL2n5" + client_secret: "YzuGNoJxeub8ZC6d" + pass_key: "bfb279f9aa9bdbcf158e97dd71a467cd2e0c893059b10f78e6b72ada1ed2c919" + paygops: + name: "paygops" + business_short_code: "174379" + till: "9347335" + auth_host: "https://sandbox.safaricom.co.ke/oauth/v1/generate" + api_host: "https://sandbox.safaricom.co.ke" + client_key: "0pLxbN83FrOl5Nd0Fh9Zi5BQlMxSL2n5" + client_secret: "YzuGNoJxeub8ZC6d" + pass_key: "bfb279f9aa9bdbcf158e97dd71a467cd2e0c893059b10f78e6b72ada1ed2c919" + + paybill: + accountHoldingInstitutionId: "default" + paygops: + business_short_code: "24322607" + currency: "KES" + roster: + business_short_code: "12345678" + currency: "KES" + livenessProbe: + httpGet: + path: /actuator/health/liveness + port: 9191 + initialDelaySeconds: 120 + periodSeconds: 30 + failureThreshold: 3 + timeoutSeconds: 5 + readinessProbe: + httpGet: + path: /actuator/health/readiness + port: 9191 + initialDelaySeconds: 120 + periodSeconds: 30 + failureThreshold: 3 + timeoutSeconds: 5 +# Whether this chart should self-manage its service account, role, and associated role binding. + managedServiceAccount: true +# Custom service account override that the pod will use + serviceAccount: "" +# Annotations to add to the ServiceAccount that is created if the serviceAccount value isn't set. + serviceAccountAnnotations: {} +# How long to wait for mpesa pods to stop gracefully + terminationGracePeriod: 30 +# Extra environment variables for mpesa container. + envFrom: [] + # - configMapRef: + # name: config-secret + extraEnvs: [] +# This is the PriorityClass settings as defined in +# https://kubernetes.io/docs/concepts/configuration/pod-priority-preemption/#priorityclass + priorityClassName: "" + # ph-ee-connector-mpesaConfig: "" + # ph-ee-connector-mpesa.yml: | + # - User that the container will execute as. + # Not necessary to run as root (0) as the mpesa Deployment use cases do not need access to Kubernetes Node internals + # - Typically not necessarily unless running within environments such as OpenShift. + securityContext: + runAsUser: 0 + privileged: false + resources: + limits: + memory: "512M" + cpu: "500m" + requests: + memory: "512M" + cpu: "100m" +# Enabling this will publicly expose your mpesa instance. +# Only enable this if you have security enabled on your cluster + ingress: + enabled: false + path: "/mpesa" + annotations: {} + backend: {} + deployment: + annotations: {} + affinity: {} + nodeSelector: {} + tolerations: [] + envFrom: [] + # - configMapRef: + # name: config-secret + extraEnvs: [] + # - User that the container will execute as. + # Not necessary to run as root (0) as the mpesa Deployment use cases do not need access to Kubernetes Node internals + # - Typically not necessarily unless running within environments such as OpenShift. + securityContext: + runAsUser: 0 + privileged: false + resources: + limits: + memory: "512M" + cpu: "500m" + requests: + memory: "512M" + cpu: "100m" +# Allows you to add any config files in /usr/share/ + # such as ph-ee-connector-mpesa.yml for deployment + # ph-ee-connector-mpesaConfig: {} + # ph-ee-connector-mpesa.yml: | + +roster_connector: + enabled: false + replicas: 1 + image: "419830066942.dkr.ecr.ap-south-1.amazonaws.com/phee-roster" + imageTag: "v1.3.1" + containerPort: 5000 + ams: + local: + enabled: "" + pesacore: + auth_header: "" + livenessProbe: + httpGet: + path: /actuator/health/liveness + port: 9191 + initialDelaySeconds: 120 + periodSeconds: 30 + failureThreshold: 3 + timeoutSeconds: 5 + readinessProbe: + httpGet: + path: /actuator/health/readiness + port: 9191 + initialDelaySeconds: 120 + periodSeconds: 30 + failureThreshold: 3 + timeoutSeconds: 5 +# Whether this chart should self-manage its service account, role, and associated role binding. + managedServiceAccount: true +# Custom service account override that the pod will use + serviceAccount: "" +# Annotations to add to the ServiceAccount that is created if the serviceAccount value isn't set. + serviceAccountAnnotations: {} +# How long to wait for roster_connector pods to stop gracefully + terminationGracePeriod: 30 +# Extra environment variables for roster_connector container. + envFrom: [] + # - configMapRef: + # name: config-secret + extraEnvs: [] +# This is the PriorityClass settings as defined in +# https://kubernetes.io/docs/concepts/configuration/pod-priority-preemption/#priorityclass + priorityClassName: "" + # ph-ee-connector-ams-rosterConfig: "" + # ph-ee-connector-ams-roster.yml: | + # - User that the container will execute as. + # Not necessary to run as root (0) as the roster_connector Deployment use cases do not need access to Kubernetes Node internals + # - Typically not necessarily unless running within environments such as OpenShift. + securityContext: + runAsUser: 0 + privileged: false + resources: + limits: + memory: "512M" + cpu: "500m" + requests: + memory: "512M" + cpu: "100m" + deployment: + annotations: {} + affinity: {} + nodeSelector: {} + tolerations: [] + envFrom: [] + # - configMapRef: + # name: config-secret + extraEnvs: [] + # - User that the container will execute as. + # Not necessary to run as root (0) as the roster_connector Deployment use cases do not need access to Kubernetes Node internals + # - Typically not necessarily unless running within environments such as OpenShift. + securityContext: + runAsUser: 0 + privileged: false + resources: + limits: + memory: "512M" + cpu: "500m" + requests: + memory: "512M" + cpu: "100m" +# Allows you to add any config files in /usr/share/ + # such as ph-ee-connector-ams-roster.yml for deployment + # ph-ee-connector-ams-rosterConfig: {} + # ph-ee-connector-ams-roster.yml: | + +paygops_connector: + enabled: false + replicas: 1 + image: "419830066942.dkr.ecr.ap-south-1.amazonaws.com/phee-connector-ams-paygops" + imageTag: "v1.6.1" + containerPort: 5000 + ams: + local: + enabled: "" + paygops: + authheader: "" + livenessProbe: + httpGet: + path: /actuator/health/liveness + port: 9191 + initialDelaySeconds: 120 + periodSeconds: 30 + failureThreshold: 3 + timeoutSeconds: 5 + readinessProbe: + httpGet: + path: /actuator/health/readiness + port: 9191 + initialDelaySeconds: 120 + periodSeconds: 30 + failureThreshold: 3 + timeoutSeconds: 5 +# Whether this chart should self-manage its service account, role, and associated role binding. + managedServiceAccount: true +# Custom service account override that the pod will use + serviceAccount: "" +# Annotations to add to the ServiceAccount that is created if the serviceAccount value isn't set. + serviceAccountAnnotations: {} +# How long to wait for paygops pods to stop gracefully + terminationGracePeriod: 30 +# Extra environment variables for paygops container. + envFrom: [] + # - configMapRef: + # name: config-secret + extraEnvs: [] +# This is the PriorityClass settings as defined in +# https://kubernetes.io/docs/concepts/configuration/pod-priority-preemption/#priorityclass + priorityClassName: "" + # ph-ee-connector-ams-paygopsConfig: "" + # ph-ee-connector-ams-paygops.yml: | + # - User that the container will execute as. + # Not necessary to run as root (0) as the paygops Deployment use cases do not need access to Kubernetes Node internals + # - Typically not necessarily unless running within environments such as OpenShift. + securityContext: + runAsUser: 0 + privileged: false + resources: + limits: + memory: "512M" + cpu: "500m" + requests: + memory: "512M" + cpu: "100m" + deployment: + annotations: {} + affinity: {} + nodeSelector: {} + tolerations: [] + envFrom: [] + # - configMapRef: + # name: config-secret + extraEnvs: [] + # - User that the container will execute as. + # Not necessary to run as root (0) as the paygops Deployment use cases do not need access to Kubernetes Node internals + # - Typically not necessarily unless running within environments such as OpenShift. + securityContext: + runAsUser: 0 + privileged: false + resources: + limits: + memory: "512M" + cpu: "500m" + requests: + memory: "512M" + cpu: "100m" +# Allows you to add any config files in /usr/share/ + # such as ph-ee-connector-ams-paygops.yml for deployment + # ph-ee-connector-ams-paygopsConfig: {} + # ph-ee-connector-ams-paygops.yml: | + +messagegateway: + enabled: false + replicas: 1 + image: docker.io/openmf/message-gateway:v1.1.0 + imagePullPolicy: "Always" + CALLBACKCONFIG_HOST: "ph-ee-connector-notifications" + HOSTCONFIG_HOST: "message-gateway" + MYSQL_USERNAME: "mifos" + MYSQL_PASSWORD: "password" + DATASOURCE_URL: jdbc:mysql:thin://operationsmysql:3306/messagegateway + PROVIDERSOURCE_FROMDATABASE: "disabled" + PROVIDERSOURCE_FROMYML: "enabled" + livenessProbe: + httpGet: + path: /actuator/health/liveness + port: 9191 + initialDelaySeconds: 120 + periodSeconds: 30 + failureThreshold: 3 + timeoutSeconds: 5 + readinessProbe: + httpGet: + path: /actuator/health/readiness + port: 9191 + initialDelaySeconds: 120 + periodSeconds: 30 + failureThreshold: 3 + timeoutSeconds: 5 +# Whether this chart should self-manage its service account, role, and associated role binding. + managedServiceAccount: true +# Custom service account override that the pod will use + serviceAccount: "" +# Annotations to add to the ServiceAccount that is created if the serviceAccount value isn't set. + serviceAccountAnnotations: {} +# How long to wait for message-gateway pods to stop gracefully + terminationGracePeriod: 30 +# Extra environment variables for message-gateway container. + envFrom: [] + # - configMapRef: + # name: config-secret + extraEnvs: [] +# This is the PriorityClass settings as defined in +# https://kubernetes.io/docs/concepts/configuration/pod-priority-preemption/#priorityclass + priorityClassName: "" + # ph-ee-message-gatewayConfig: "" + # ph-ee-message-gateway.yml: | + # - User that the container will execute as. + # Not necessary to run as root (0) as the message-gateway Deployment use cases do not need access to Kubernetes Node internals + # - Typically not necessarily unless running within environments such as OpenShift. + securityContext: + runAsUser: 0 + privileged: false + resources: + limits: + memory: "512M" + cpu: "500m" + requests: + memory: "512M" + cpu: "100m" +# Enabling this will publicly expose your message-gateway instance. +# Only enable this if you have security enabled on your cluster + ingress: + enabled: true + path: "/messages" + annotations: {} + backend: {} + secret: + name: "" + key: + telerivet_api_key: "" + value: + api_key: "" + project_id: "" + deployment: + annotations: {} + affinity: {} + nodeSelector: {} + tolerations: [] + envFrom: [] + # - configMapRef: + # name: config-secret + extraEnvs: [] + # - User that the container will execute as. + # Not necessary to run as root (0) as the message-gateway Deployment use cases do not need access to Kubernetes Node internals + # - Typically not necessarily unless running within environments such as OpenShift. + securityContext: + runAsUser: 0 + privileged: false + resources: + limits: + memory: "512M" + cpu: "500m" + requests: + memory: "512M" + cpu: "100m" +# Allows you to add any config files in /usr/share/ + # such as message-gateway.yml for deployment + # message-gatewayConfig: {} + # message-gateway.yml: | + +notifications: + enabled: true + replicas: 1 + image: docker.io/openmf/ph-ee-notifications:v1.3.0 + imagePullPolicy: "Always" + MESSAGEGATEWAYCONFIG_HOST: "message-gateway" + NOTIFICATION_LOCAL_HOST: "ph-ee-connector-notifications" + NOTIFICATION_SUCCESS_ENABLED: "false" + NOTIFICATION_FAILURE_ENABLED: "true" + hostconfig: + host: "message-gateway" + port: 80 + livenessProbe: + httpGet: + path: /actuator/health/liveness + port: 9191 + initialDelaySeconds: 120 + periodSeconds: 30 + failureThreshold: 3 + timeoutSeconds: 5 + readinessProbe: + httpGet: + path: /actuator/health/readiness + port: 9191 + initialDelaySeconds: 120 + periodSeconds: 30 + failureThreshold: 3 + timeoutSeconds: 5 +# Whether this chart should self-manage its service account, role, and associated role binding. + managedServiceAccount: true +# Custom service account override that the pod will use + serviceAccount: "" +# Annotations to add to the ServiceAccount that is created if the serviceAccount value isn't set. + serviceAccountAnnotations: {} +# How long to wait for notifications pods to stop gracefully + terminationGracePeriod: 30 +# Extra environment variables for notifications container. + envFrom: [] + # - configMapRef: + # name: config-secret + extraEnvs: [] +# This is the PriorityClass settings as defined in +# https://kubernetes.io/docs/concepts/configuration/pod-priority-preemption/#priorityclass + priorityClassName: "" + # ph-ee-connector-notificationsConfig: "" + # ph-ee-connector-notifications.yml: | + # - User that the container will execute as. + # Not necessary to run as root (0) as the notifications Deployment use cases do not need access to Kubernetes Node internals + # - Typically not necessarily unless running within environments such as OpenShift. + securityContext: + runAsUser: 0 + privileged: false + resources: + limits: + memory: "512M" + cpu: "500m" + requests: + memory: "512M" + cpu: "100m" +# Enabling this will publicly expose your notifications instance. +# Only enable this if you have security enabled on your cluster + ingress: + enabled: false + path: "/notifications" + annotations: {} + backend: {} + deployment: + annotations: {} + affinity: {} + nodeSelector: {} + tolerations: [] + envFrom: [] + # - configMapRef: + # name: config-secret + extraEnvs: [] + # - User that the container will execute as. + # Not necessary to run as root (0) as the notifications Deployment use cases do not need access to Kubernetes Node internals + # - Typically not necessarily unless running within environments such as OpenShift. + securityContext: + runAsUser: 0 + privileged: false + resources: + limits: + memory: "512M" + cpu: "500m" + requests: + memory: "512" + cpu: "100m" +# Allows you to add any config files in /usr/share/ + # such as ph-ee-connector-notifications.yml for deployment + # ph-ee-connector-notificationsConfig: {} + # ph-ee-connector-notifications.yml: | + +zeebe_ops: + enabled: false + replicas: 1 + image: docker.io/openmf/ph-ee-zeebe-ops:v1.2.0 + imagePullPolicy: "Always" + imagePullSecrets: [] + elasticsearch_contactpoint: "ph-ee-elasticsearch:9200" + elasticsearch_url: "http://ph-ee-elasticsearch:9200/" + elasticsearch_sslverification: false + elasticsearch_security_enabled: false + livenessProbe: + httpGet: + path: /actuator/health/liveness + port: 9191 + initialDelaySeconds: 120 + periodSeconds: 30 + failureThreshold: 3 + timeoutSeconds: 5 + readinessProbe: + httpGet: + path: /actuator/health/readiness + port: 9191 + initialDelaySeconds: 120 + periodSeconds: 30 + failureThreshold: 3 + timeoutSeconds: 5 +# Whether this chart should self-manage its service account, role, and associated role binding. + managedServiceAccount: true +# Custom service account override that the pod will use + serviceAccount: "" +# Annotations to add to the ServiceAccount that is created if the serviceAccount value isn't set. + serviceAccountAnnotations: {} +# How long to wait for Zeebe-ops pods to stop gracefully + terminationGracePeriod: 30 +# Extra environment variables for Zeebe-ops container. + envFrom: [] + # - configMapRef: + # name: config-secret + extraEnvs: [] +# This is the PriorityClass settings as defined in +# https://kubernetes.io/docs/concepts/configuration/pod-priority-preemption/#priorityclass + priorityClassName: "" + # ph-ee-zeebe-opsConfig: "" + # ph-ee-zeebe-ops.yml: | + # - User that the container will execute as. + # Not necessary to run as root (0) as the Zeebe-ops Deployment use cases do not need access to Kubernetes Node internals + # - Typically not necessarily unless running within environments such as OpenShift. + securityContext: + runAsUser: 0 + privileged: false + resources: + limits: + memory: "512M" + cpu: "500m" + requests: + memory: "512M" + cpu: "100m" +# Enabling this will publicly expose your zeebe_ops instance. +# Only enable this if you have security enabled on your cluster + ingress: + enabled: false + path: "/zeebeops" + annotations: {} + backend: {} + deployment: + annotations: {} + affinity: {} + nodeSelector: {} + tolerations: [] + envFrom: [] + # - configMapRef: + # name: config-secret + extraEnvs: [] + # - User that the container will execute as. + # Not necessary to run as root (0) as the zeebeops Deployment use cases do not need access to Kubernetes Node internals + # - Typically not necessarily unless running within environments such as OpenShift. + securityContext: + runAsUser: 0 + privileged: false + resources: + limits: + memory: "512M" + cpu: "500m" + requests: + memory: "512M" + cpu: "100m" +# Allows you to add any config files in /usr/share/ + # such as zeebeops.yml for deployment + # ph-ee-zeebe-opsConfig: {} + # ph-ee-zeebe-ops.yml: | + + +importer_es: + enabled: true + replicas: 1 + image: docker.io/openmf/ph-ee-importer-es:v1.6.0 + imagePullPolicy: "Always" + importer_elasticsearch_url: "http://ph-ee-elasticsearch:9200/" + reporting: + enabled: true + fields: + amount: false + accountId: false + ams: false + clientCorrelationId: false + currency: false + customData: false + confirmationReceived: false + errorCode: false + errorDescription: false + errorInformation: false + externalId: false + initiator: false + initiatorType: false + isNotificationsFailureEnabled: false + isNotificationsSuccessEnabled: false + mpesaTransactionId: false + mpesaTransactionStatusRetryCount: false + originDate: false + partyLookupFailed: false + phoneNumber: false + processDefinitionKey: false + processInstanceKey: false + scenario: false + tenantId: false + timer: false + timestamp: false + transactionFailed: false + transactionId: false + transferCreateFailed: false + transferSettlementFailed: false + transferResponseCREATE: false + elasticsearch_sslverification: false + elasticsearch_security_enabled: false + logging: + level: + root: "INFO" + pattern: + console: "%d{dd-MM-yyyy HH:mm:ss.SSS} %magenta([%thread]) %highlight(%-5level) %logger.%M - %msg%n" + livenessProbe: + httpGet: + path: /actuator/health/liveness + port: 9191 + initialDelaySeconds: 120 + periodSeconds: 30 + failureThreshold: 3 + timeoutSeconds: 5 + readinessProbe: + httpGet: + path: /actuator/health/readiness + port: 9191 + initialDelaySeconds: 120 + periodSeconds: 30 + failureThreshold: 3 + timeoutSeconds: 5 +# Whether this chart should self-manage its service account, role, and associated role binding. + managedServiceAccount: true +# Custom service account override that the pod will use + serviceAccount: "" +# Annotations to add to the ServiceAccount that is created if the serviceAccount value isn't set. + serviceAccountAnnotations: {} +# How long to wait for Zeebe-ops pods to stop gracefully + terminationGracePeriod: 30 +# Extra environment variables for Zeebe-ops container. + envFrom: [] + # - configMapRef: + # name: config-secret + extraEnvs: [] +# This is the PriorityClass settings as defined in +# https://kubernetes.io/docs/concepts/configuration/pod-priority-preemption/#priorityclass + priorityClassName: "" + # ph-ee-zeebe-opsConfig: "" + # ph-ee-zeebe-ops.yml: | + # - User that the container will execute as. + # Not necessary to run as root (0) as the Zeebe-ops Deployment use cases do not need access to Kubernetes Node internals + # - Typically not necessarily unless running within environments such as OpenShift. + securityContext: + runAsUser: 0 + privileged: false + resources: + limits: + memory: "512M" + cpu: "500m" + requests: + memory: "512M" + cpu: "100m" + javaToolOptions: "-Xmx256M" + deployment: + annotations: {} + + + +mockpayment: + enabled: false + image: docker.io/openmf/ph-ee-connector-mock-payment-schema:v1.4.0 + replicas: 1 + mockFailure: + percentage: "0" + limits: + memory: "512M" + cpu: "500m" + requests: + memory: "256M" + cpu: "100m" + deployment: + annotations: {} + + +kafka: + enabled: true + fullnameOverride: kafka + + provisioning: + enabled: true + topics: + - name: zeebe-export + partitions: 1 + replicationFactor: 1 + + controller: + replicaCount: 1 + + listeners: + client: + protocol: PLAINTEXT + + controller: + protocol: PLAINTEXT + + interbroker: + protocol: PLAINTEXT + + external: + protocol: PLAINTEXT + + kraft: + clusterId: spDnn4oSr6DLKPx3cEheLp + + # externalAccess: + # enabled: true + # autoDiscovery: + # enabled: true + + # rbac: + # create: true + + extraConfig: | + offsets.topic.replication.factor=1 + transaction.state.log.replication.factor=1 + +importer_rdbms: + enabled: true + replicas: 1 + image: docker.io/openmf/ph-ee-importer-rdbms:v1.7.1 + imagePullPolicy: "Always" + SPRING_PROFILES_ACTIVE: "local,tenantsConnection" + datasource: + username: "mifos" + password: "password" + host: "operationsmysql" + port: 3306 + schema: "tenants" + livenessProbe: + httpGet: + path: /actuator/health/liveness + port: 9191 + initialDelaySeconds: 120 + periodSeconds: 30 + failureThreshold: 3 + timeoutSeconds: 5 + readinessProbe: + httpGet: + path: /actuator/health/readiness + port: 9191 + initialDelaySeconds: 120 + periodSeconds: 30 + failureThreshold: 3 + timeoutSeconds: 5 +# Whether this chart should self-manage its service account, role, and associated role binding. + managedServiceAccount: true +# Custom service account override that the pod will use + serviceAccount: "" +# Annotations to add to the ServiceAccount that is created if the serviceAccount value isn't set. + serviceAccountAnnotations: {} +# How long to wait for importer_rdbms pods to stop gracefully + terminationGracePeriod: 30 +# Extra environment variables for importer_rdbms container. + envFrom: [] + # - configMapRef: + # name: config-secret + extraEnvs: [] +# This is the PriorityClass settings as defined in +# https://kubernetes.io/docs/concepts/configuration/pod-priority-preemption/#priorityclass + priorityClassName: "" + # ph-ee-importer_rdbmsConfig: "" + # ph-ee-importer_rdbms.yml: | + # - User that the container will execute as. + # Not necessary to run as root (0) as the importer_rdbms Deployment use cases do not need access to Kubernetes Node internals + # - Typically not necessarily unless running within environments such as OpenShift. + securityContext: + runAsUser: 0 + privileged: false + resources: + limits: + memory: "512M" + cpu: "500m" + requests: + memory: "512M" + cpu: "100m" + deployment: + annotations: {} + affinity: {} + nodeSelector: {} + tolerations: [] + envFrom: [] + # - configMapRef: + # name: config-secret + extraEnvs: [] + # - User that the container will execute as. + # Not necessary to run as root (0) as the importer_rdbms Deployment use cases do not need access to Kubernetes Node internals + # - Typically not necessarily unless running within environments such as OpenShift. + securityContext: + runAsUser: 0 + privileged: false + resources: + limits: + memory: "512M" + cpu: "500m" + requests: + memory: "512M" + cpu: "100m" +# Allows you to add any config files in /usr/share/ + # such as ph-ee-importer_rdbms.yml for deployment + # ph-ee-importer_rdbmsConfig: {} + # ph-ee-importer_rdbms.yml: | + javaToolOptions: "-Xmx256M" + +connector_bulk: + enabled: false + replicas: 1 + image: docker.io/openmf/ph-ee-bulk-processor:v1.9.0 + imagePullPolicy: "Always" + camel_disable_ssl: true + channel: + hostname: "" + pollingApi: + timer: "180" + tenants: "" + operations_app: + contactpoint: "http://ph-ee-operations-app:5000" + endpoints: + batch_transaction: "/api/v1/batch/transactions" + identity_account_mapper: + hostname: "http://ph-ee-identity-account-mapper:80" + config: + partylookup: + enable: false + approval: + enable: false + ordering: + enable: false + field: "" + splitting: + enable: true + sub_batch_size: 5 + formatting: + enable: false + standard: "DEFAULT" + mergeback: + enable: true + backpressure: + enable: false + completion_threshold_check: + enable: true + completion_rate: 95 + deduplication: + enabled: true + aws: + access_key: "root" + secret_key: "password" + livenessProbe: + httpGet: + path: /actuator/health/liveness + port: 9191 + initialDelaySeconds: 120 + periodSeconds: 30 + failureThreshold: 3 + timeoutSeconds: 5 + readinessProbe: + httpGet: + path: /actuator/health/readiness + port: 9191 + initialDelaySeconds: 120 + periodSeconds: 30 + failureThreshold: 3 + timeoutSeconds: 5 +# Whether this chart should self-manage its service account, role, and associated role binding. + managedServiceAccount: true +# Custom service account override that the pod will use + serviceAccount: "" +# Annotations to add to the ServiceAccount that is created if the serviceAccount value isn't set. + serviceAccountAnnotations: {} +# How long to wait for connector_bulk pods to stop gracefully + terminationGracePeriod: 30 +# Extra environment variables for connector_bulk container. + envFrom: [] + # - configMapRef: + # name: config-secret + extraEnvs: [] +# This is the PriorityClass settings as defined in +# https://kubernetes.io/docs/concepts/configuration/pod-priority-preemption/#priorityclass + priorityClassName: "" + # ph-ee-connector-bulkConfig: "" + # ph-ee-connector-bulk.yml: | + # - User that the container will execute as. + # Not necessary to run as root (0) as the connector_bulk Deployment use cases do not need access to Kubernetes Node internals + # - Typically not necessarily unless running within environments such as OpenShift. + securityContext: + runAsUser: 0 + privileged: false + resources: + limits: + memory: "512M" + cpu: "500m" + requests: + memory: "512M" + cpu: "100m" + service: + annotations: {} +# Enabling this will publicly expose your connector_bulk instance. +# Only enable this if you have security enabled on your cluster + ingress: + enabled: false + annotations: {} + deployment: + annotations: {} + affinity: {} + nodeSelector: {} + tolerations: [] + envFrom: [] + # - configMapRef: + # name: config-secret + extraEnvs: [] + # - User that the container will execute as. + # Not necessary to run as root (0) as the connector_bulk Deployment use cases do not need access to Kubernetes Node internals + # - Typically not necessarily unless running within environments such as OpenShift. + securityContext: + runAsUser: 0 + privileged: false + resources: + limits: + memory: "512M" + cpu: "500m" + requests: + memory: "512M" + cpu: "100m" +# Allows you to add any config files in /usr/share/ + # such as ph-ee-connector-bulk.yml for deployment + # ph-ee-connector-bulkConfig: {} + # ph-ee-connector-bulk.yml: | + +ph_ee_connector_gsma: + enabled: false + replicas: 1 + image: docker.io/openmf/ph-ee-connector-gsma:v1.2.0 + imagePullPolicy: "Always" +# Whether this chart should self-manage its service account, role, and associated role binding. + managedServiceAccount: true +# Custom service account override that the pod will use + serviceAccount: "" +# Annotations to add to the ServiceAccount that is created if the serviceAccount value isn't set. + serviceAccountAnnotations: {} +# How long to wait for gsma pods to stop gracefully + terminationGracePeriod: 30 +# Extra environment variables for gsma container. + envFrom: [] + # - configMapRef: + # name: config-secret + extraEnvs: [] +# This is the PriorityClass settings as defined in +# https://kubernetes.io/docs/concepts/configuration/pod-priority-preemption/#priorityclass + priorityClassName: "" + # ph_ee_connector_gsmaConfig: "" + # ph_ee_connector_gsma.yml: | + # - User that the container will execute as. + # Not necessary to run as root (0) as the gsma Deployment use cases do not need access to Kubernetes Node internals + # - Typically not necessarily unless running within environments such as OpenShift. + securityContext: + runAsUser: 0 + privileged: false + resources: + limits: + memory: "512M" + cpu: "500m" + requests: + memory: "512M" + cpu: "100m" + deployment: + annotations: {} + affinity: {} + nodeSelector: {} + tolerations: [] + envFrom: [] + # - configMapRef: + # name: config-secret + extraEnvs: [] + # - User that the container will execute as. + # Not necessary to run as root (0) as the gsma Deployment use cases do not need access to Kubernetes Node internals + # - Typically not necessarily unless running within environments such as OpenShift. + securityContext: + runAsUser: 0 + privileged: false + resources: + limits: + memory: "512M" + cpu: "500m" + requests: + memory: "512M" + cpu: "100m" +# Allows you to add any config files in /usr/share/ + # such as ph_ee_connector_gsma.yml for deployment + # ph_ee_connector_gsmaConfig: {} + # ph_ee_connector_gsma.yml: | + +ph-ee-connector_slcb: + enabled: false + replicas: 1 + image: "419830066942.dkr.ecr.ap-south-1.amazonaws.com/ph-ee-slcb" + imageTag: "v1.4.0" + username: "username" + password: "password" + signature_key: "long_segnature_key" + auth_host: "https://g2p-test.slcb.com:8443" + api_host: "https://g2p-test.slcb.com:8443" + account_number: "003001003879112168" + account_type: 0 + institutioncode: "SLCB" + endpoint: + auth: "/api/auth" + transaction_request: "/api/transactionRequest" + reconciliation: "/reconciliation" + account_balance: "/accountBalance" + config: + date_format: "yyyy-MM-dd'T'hh:mm:ssXXX" + reconciliation: + enable: false + livenessProbe: + httpGet: + path: /actuator/health/liveness + port: 9191 + initialDelaySeconds: 120 + periodSeconds: 30 + failureThreshold: 3 + timeoutSeconds: 5 + readinessProbe: + httpGet: + path: /actuator/health/readiness + port: 9191 + initialDelaySeconds: 120 + periodSeconds: 30 + failureThreshold: 3 + timeoutSeconds: 5 +# Whether this chart should self-manage its service account, role, and associated role binding. + managedServiceAccount: true +# Custom service account override that the pod will use + serviceAccount: "" +# Annotations to add to the ServiceAccount that is created if the serviceAccount value isn't set. + serviceAccountAnnotations: {} +# How long to wait for ph_ee_connector_slcb pods to stop gracefully + terminationGracePeriod: 30 +# Extra environment variables for ph_ee_connector_slcb container. + envFrom: [] + # - configMapRef: + # name: config-secret + extraEnvs: [] +# This is the PriorityClass settings as defined in +# https://kubernetes.io/docs/concepts/configuration/pod-priority-preemption/#priorityclass + priorityClassName: "" + # ph_ee_connector_slcbConfig: "" + # ph_ee_connector_slcb.yml: | + # - User that the container will execute as. + # Not necessary to run as root (0) as the ph_ee_connector_slcb Deployment use cases do not need access to Kubernetes Node internals + # - Typically not necessarily unless running within environments such as OpenShift. + securityContext: + runAsUser: 0 + privileged: false + resources: + limits: + memory: "512M" + cpu: "500m" + requests: + memory: "512M" + cpu: "100m" + deployment: + annotations: {} + affinity: {} + nodeSelector: {} + tolerations: [] + envFrom: [] + # - configMapRef: + # name: config-secret + extraEnvs: [] + # - User that the container will execute as. + # Not necessary to run as root (0) as the ph_ee_connector_slcb Deployment use cases do not need access to Kubernetes Node internals + # - Typically not necessarily unless running within environments such as OpenShift. + securityContext: + runAsUser: 0 + privileged: false + resources: + limits: + memory: "512M" + cpu: "500m" + requests: + memory: "512M" + cpu: "100m" +# Allows you to add any config files in /usr/share/ + # such as ph_ee_connector_slcb.yml for deployment + # ph_ee_connector_slcbConfig: {} + # ph_ee_connector_slcb.yml: | + +ph-ee-connector: + enabled: false + replicas: 1 + image: docker.io/openmf/ph-ee-connector-bulk:v1.1.0 + operations_app: + contactpoint: "http://ph-ee-operations-app:5000" + ingress: + enabled: true + annotations: + kubernetes.io/ingress.class: nginx + tls: + - secretName: sandbox-secret + hosts: + - host: connector.sandbox.mifos.io + paths: + - path: "/" + backend: + service: + name: ph-ee-connector + port: + number: 80 + deployment: + annotations: + deployTime: "{{ .Values.deployTime }}" + +mock_oracle: + enabled: false + replicas: 1 + image: "419830066942.dkr.ecr.ap-south-1.amazonaws.com/mock-asl-oracle" + service: + targetport: 4100 + limits: + memory: "512M" + cpu: "500m" + requests: + memory: "512M" + cpu: "100m" +# Enabling this will publicly expose your mock_oracle instance. +# Only enable this if you have security enabled on your cluster + ingress: + enabled: true + path: "/" + annotations: {} + backend: {} + deployment: + annotations: {} + +keycloak: + enabled: false + fullnameOverride: "keycloak" +# Enabling this will publicly expose your keycloak instance. +# Only enable this if you have security enabled on your cluster + ingress: + enabled: false + ingressClassName: "kong" + rules: + - host: 'keycloak.mifos.io' + tls: [] + postgresql: + initdbUser: "keycloak" + initdbPassword: "keycloak" + initdbScripts: + my_init_script.sql: |- + CREATE DATABASE kong; + extraVolumes: | + - name: realm-secret + secret: + secretName: realm-secret + extraVolumeMounts: | + - name: realm-secret + mountPath: "/realm/" + readOnly: true + extraEnv: | + - name: KEYCLOAK_IMPORT + value: /realm/kong-keycloak-realm.json + +integration_test: + enabled: false + replicas: 1 + image: "docker.io/openmf/ph-ee-integration-test:latest" + imageTag: v1.4.0-rc.1 + imagePullPolicy: "Never" + limits: + cpu: "500m" + memory: "3Gi" + requests: + cpu: "100m" + memory: "2Gi" + operations_app: + contactpoint: "http://ph-ee-operations-app:80" + bulk_processor: + contactpoint: "https://ph-ee-connector-bulk:8443" + channel_connector: + contactpoint: "https://ph-ee-connector-channel:8443" + kafka: + brokers: "" + topics: "" + consumerTimeoutMs: "" + zeebe_operations: + contactpoint: "" + no_of_workflows: "" + thread-count: "" + max_retry_count: "" + retry_intervals: "" + defaults: + tenant: "" + authorization: "" + channel: + base_url: "" + loan: + base_url: "" + savings: + base_url: "" + gradle: + command: "" + +redis: + enabled: true + replica: + replicaCount: 1 +volumeClaimTemplate: + storageClassName: "gp2" + +kong: + enabled: false + image: + repository: revomatico/docker-kong-oidc + tag: "latest" + migrations: + init: true + preUpgrade: false + postUpgrade: false + env: + plugins: "bundled,oidc" + database: "postgres" + pg_host: "g2p-sandbox-security-postgresql" + pg_user: "keycloak" + pg_password: "keycloak" + pg_database: "kong" + admin: + enabled: true + http: + enabled: true + tls: + enabled: false +# Enabling this will publicly expose your kong instance. +# Only enable this if you have security enabled on your cluster + ingress: + enabled: true + ingressClassName: "kong" + hostname: kong-admin.mifos.io + extraObjects: + - apiVersion: configuration.konghq.com/v1 + kind: KongClusterPlugin + metadata: + name: request-transformer + annotations: + kubernetes.io/ingress.class: "kong" + labels: + global: "false" + disabled: false # optionally disable the plugin in Kong + plugin: request-transformer + config: + remove: + headers: + - cookie + - x-id-token + - apiVersion: configuration.konghq.com/v1 + kind: KongClusterPlugin + metadata: + name: cors + annotations: + kubernetes.io/ingress.class: "kong" + labels: + global: "true" + disabled: false # optionally disable the plugin in Kong + plugin: cors + config: + origins: + - "*" + credentials: true + max_age: 3600 + exposed_headers : + - "*" + preflight_continue: false + - apiVersion: configuration.konghq.com/v1 + kind: KongClusterPlugin + metadata: + name: oidc + annotations: + kubernetes.io/ingress.class: "kong" + labels: + global: "false" + disabled: false # optionally disable the plugin in Kong + plugin: oidc + config: # configuration for the plugin + realm: Kong + discovery: https://keycloak.localhost/auth/realms/kong-oidc/.well-known/openid-configuration + scope: openid + introspection_endpoint: http://keycloak.localhost/auth/realms/Kong/protocol/openid-connect/token/introspect + redirect_after_logout_uri: http://keycloak.localhost/auth/realms/kong-oidc/protocol/openid-connect/logout?redirect_uri=http://keycloak.localhost + + + +vouchers: + enabled: false + paymentadvice: false + replicas: 1 + image: docker.io/openmf/ph-ee-vouchers:v1.1.0 + ingress: + enabled: true + annotations: + kubernetes.io/ingress.class: nginx + tls: + - secretName: sandbox-secret + hosts: + - host: vouchers.sandbox.mifos.io + paths: + - path: "/" + backend: + service: + name: ph-ee-vouchers + port: + number: 80 + deployment: + annotations: + deployTime: "{{ .Values.deployTime }}" + spring: + datasource: + url: jdbc:mysql://operationsmysql:3306/voucher_management + username: mifos + password: password + async: + core_pool_size: 10 + max_pool_size: 10 + queue_capacity: 100 + expiry_time: 60 + payer: + tenant: rhino + identifier: 12345678 + identifierType: MSISDN + salting: + enabled: true + identity-account-mapper: + hostname: "https://ph-ee-identity-mapper:80" + operations: + hostname: "http://ph-ee-operations-app:80" + endpoints: + transfers: "/api/v1/transfers?size=1&page=0" + +billPay: + enabled: false + replicas: 1 + image: docker.io/openmf/ph-ee-bill-pay:v1.0.0 + imagePullPolicy: "Always" + connector: + contactpoint: "http://ph-ee-connector:80" + billpay: + contactpoint: "http://ph-ee-connector-bill-pay:8080" + livenessProbe: + httpGet: + path: /actuator/health/liveness + port: 8080 + scheme: HTTPS + initialDelaySeconds: 120 + periodSeconds: 30 + failureThreshold: 3 + timeoutSeconds: 5 + readinessProbe: + httpGet: + path: /actuator/health/readiness + port: 8080 + scheme: HTTPS + initialDelaySeconds: 120 + periodSeconds: 30 + failureThreshold: 3 + timeoutSeconds: 5 + # Whether this chart should self-manage its service account, role, and associated role binding. + managedServiceAccount: true + # Custom service account override that the pod will use + serviceAccount: "billPay" + # Annotations to add to the ServiceAccount that is created if the serviceAccount value isn't set. + serviceAccountAnnotations: {} + # How long to wait for pods to stop gracefully + terminationGracePeriod: 30 + # Extra environment variables for container. + envFrom: [] + # - configMapRef: + # name: config-secret + extraEnvs: [] + # This is the PriorityClass settings as defined in + # https://kubernetes.io/docs/concepts/configuration/pod-priority-preemption/#priorityclass + priorityClassName: "" + securityContext: + runAsUser: 0 + privileged: false + resources: + limits: + memory: "512M" + cpu: "500m" + requests: + memory: "512M" + cpu: "100m" + service: + annotations: {} + # Only enable this if you have security enabled on your cluster + ingress: + enabled: true + path: "/billPay" + annotations: {} + backend: {} + stub_backend: {} + deployment: + annotations: {} + affinity: {} + nodeSelector: {} + tolerations: [] + envFrom: [] + # - configMapRef: + # name: config-secret + extraEnvs: [] + # - User that the container will execute as. + # - Typically not necessarily unless running within environments such as OpenShift. + +crm: + enabled: false + replicas: 1 + image: docker.io/openmf/ph-ee-connector-crm:v1.0.0 + imagePullPolicy: "Always" + livenessProbe: + httpGet: + path: /actuator/health/liveness + port: 8080 + scheme: HTTPS + initialDelaySeconds: 120 + periodSeconds: 30 + failureThreshold: 3 + timeoutSeconds: 5 + readinessProbe: + httpGet: + path: /actuator/health/readiness + port: 8080 + scheme: HTTPS + initialDelaySeconds: 120 + periodSeconds: 30 + failureThreshold: 3 + timeoutSeconds: 5 + # Whether this chart should self-manage its service account, role, and associated role binding. + managedServiceAccount: true + # Custom service account override that the pod will use + serviceAccount: "crm" + # Annotations to add to the ServiceAccount that is created if the serviceAccount value isn't set. + serviceAccountAnnotations: {} + # How long to wait for pods to stop gracefully + terminationGracePeriod: 30 + # Extra environment variables for container. + envFrom: [] + # - configMapRef: + # name: config-secret + extraEnvs: [] + # This is the PriorityClass settings as defined in + # https://kubernetes.io/docs/concepts/configuration/pod-priority-preemption/#priorityclass + priorityClassName: "" + securityContext: + runAsUser: 0 + privileged: false + resources: + limits: + memory: "512M" + cpu: "500m" + requests: + memory: "512M" + cpu: "100m" + service: + annotations: {} + # Only enable this if you have security enabled on your cluster + ingress: + enabled: true + path: "/crm" + annotations: {} + backend: {} + stub_backend: {} + deployment: + annotations: {} + affinity: {} + nodeSelector: {} + tolerations: [] + envFrom: [] + # - configMapRef: + # name: config-secret + extraEnvs: [] + # - User that the container will execute as. + # - Typically not necessarily unless running within environments such as OpenShift. +minio: + enabled: true + fullnameOverride: "minio" + resources: + requests: + memory: 256Mi + replicas: 1 + persistence: + enabled: true + size: 10Gi + mode: standalone + rootUser: root + rootPassword: password + buckets: + - name: paymenthub-ee + policy: public + +post_installation_job: + enabled: false diff --git a/ph-ee-env-template/helm/ph-ee-engine/vouchers/Chart.yaml b/ph-ee-env-template/helm/ph-ee-engine/vouchers/Chart.yaml new file mode 100644 index 000000000..5568e54a1 --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/vouchers/Chart.yaml @@ -0,0 +1,5 @@ +apiVersion: v1 +description: ph-ee-vouchers +name: vouchers +version: 1.0.0 +appVersion: "1.0.0" \ No newline at end of file diff --git a/ph-ee-env-template/helm/ph-ee-engine/vouchers/README.md b/ph-ee-env-template/helm/ph-ee-engine/vouchers/README.md new file mode 100644 index 000000000..32a06d6cb --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/vouchers/README.md @@ -0,0 +1,15 @@ +# vouchers + +![Version: 1.0.0](https://img.shields.io/badge/Version-1.0.0-informational?style=flat-square) ![AppVersion: 1.0.0](https://img.shields.io/badge/AppVersion-1.0.0-informational?style=flat-square) + +ph-ee-vouchers + +## Values + +| Key | Type | Default | Description | +|-----|------|---------|-------------| +| SPRING_PROFILES_ACTIVE | string | `""` | | +| zeebe_broker_contactpoint | string | `"zeebe-zeebe-gateway:26500"` | | + +---------------------------------------------- +Autogenerated from chart metadata using [helm-docs v1.11.0](https://github.com/norwoodj/helm-docs/releases/v1.11.0) diff --git a/ph-ee-env-template/helm/ph-ee-engine/vouchers/templates/clusterrole.yaml b/ph-ee-env-template/helm/ph-ee-engine/vouchers/templates/clusterrole.yaml new file mode 100644 index 000000000..5d5931beb --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/vouchers/templates/clusterrole.yaml @@ -0,0 +1,11 @@ +{{- if .Values.managedServiceAccount }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + # "namespace" omitted since ClusterRoles are not namespaced + name: ph-ee-vouchers-c-role +rules: +- apiGroups: [""] + resources: ["secrets"] + verbs: ["get", "watch", "list"] +{{- end -}} \ No newline at end of file diff --git a/ph-ee-env-template/helm/ph-ee-engine/vouchers/templates/clusterrolebinding.yaml b/ph-ee-env-template/helm/ph-ee-engine/vouchers/templates/clusterrolebinding.yaml new file mode 100644 index 000000000..bf1284958 --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/vouchers/templates/clusterrolebinding.yaml @@ -0,0 +1,15 @@ +{{- if .Values.managedServiceAccount }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: ph-ee-vouchers-c-role-binding +subjects: +- kind: ServiceAccount + name: ph-ee-vouchers # name of your service account + namespace: {{ .Release.Namespace }} # this is the namespace your service account is in +roleRef: # referring to your ClusterRole + kind: ClusterRole + name: ph-ee-vouchers-c-role + apiGroup: rbac.authorization.k8s.io + +{{- end -}} \ No newline at end of file diff --git a/ph-ee-env-template/helm/ph-ee-engine/vouchers/templates/deployment.yaml b/ph-ee-env-template/helm/ph-ee-engine/vouchers/templates/deployment.yaml new file mode 100644 index 000000000..94a7ffbe0 --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/vouchers/templates/deployment.yaml @@ -0,0 +1,112 @@ +{{- if .Values.enabled -}} + +apiVersion: apps/v1 +kind: Deployment +metadata: + name: ph-ee-vouchers + labels: + app: ph-ee-vouchers +spec: + replicas: {{ .Values.replicas }} + selector: + matchLabels: + app: ph-ee-vouchers + template: + metadata: + labels: + app: ph-ee-vouchers + annotations: +{{- if .Values.deployment.annotations }} +{{ toYaml .Values.deployment.annotations | indent 8 }} +{{- end }} + spec: + initContainers: + #During this Pod's initialization, check that zeebe-gateway service is up and running before starting this pod + - name: check-zeebe-gateway-ready + image: busybox:latest + command: [ 'sh', '-c','until nc -vz {{ .Release.Name }}-zeebe-gateway 26500; do echo "Waiting for zeebe-gateway service"; sleep 2; done;' ] + containers: + - name: ph-ee-vouchers + image: "{{ .Values.image }}" + ports: + - containerPort: 8080 + imagePullPolicy: "{{ .Values.global.imagePullPolicy }}" + resources: + limits: + memory: "{{ .Values.limits.memory }}" + cpu: "{{ .Values.limits.cpu }}" + requests: + memory: "{{ .Values.requests.memory }}" + cpu: "{{ .Values.requests.cpu }}" + livenessProbe: + httpGet: + path: /actuator/health/liveness + port: 8080 + initialDelaySeconds: {{.Values.livenessProbe.initialDelaySeconds}} + periodSeconds: {{.Values.livenessProbe.periodSeconds}} + readinessProbe: + httpGet: + path: /actuator/health/readiness + port: 8080 + initialDelaySeconds: {{.Values.readinessProbe.initialDelaySeconds}} + periodSeconds: {{.Values.readinessProbe.periodSeconds}} + + env: + - name: "SPRING_PROFILES_ACTIVE" + value: "{{ .Values.global.SPRING_PROFILES_ACTIVE }}" + - name: "ZEEBE_BROKER_CONTACTPOINT" + value: "{{ .Release.Name }}-zeebe-gateway:26500" + - name: "ZEEBE_CLIENT_MAX-EXECUTION-THREADS" + value: "{{ .Values.global.max_execution_threads}}" + - name: "ZEEBE_CLIENT_POLL-INTERVAL" + value: "{{ .Values.global.poll_interval}}" + - name: "PAYER_TENANT" + value: "{{ .Values.payer.tenant }}" + - name: "PAYER_IDENTIFIER" + value: "{{ .Values.payer.identifier }}" + - name: "PAYER_IDENTIFIER_TYPE" + value: "{{ .Values.payer.identifierType }}" + - name: "VOUCHER_HOSTNAME" + value: "{{ .Values.voucher.hostname }}" + - name: "IDENTITY_ACCOUNT_MAPPER_HOSTNAME" + value: "{{ .Values.identity_account_mapper.hostname }}" + - name: "OPERATIONS_HOSTNAME" + value: "{{ .Values.operations.hostname }}" + - name: "OPERATIONS_TRANSFERS_ENDPOINT" + value: "{{ .Values.operations.endpoints.transfers }}" + - name: "SPRING_DATASOURCE_URL" + value: "{{ .Values.spring.datasource.url }}" + - name: "SPRING_DATASOURCE_USERNAME" + value: "{{ .Values.spring.datasource.username }}" + - name: "SPRING_DATASOURCE_PASSWORD" + value: "{{ .Values.spring.datasource.password }}" + - name: "ASYNC_CORE_POOL_SIZE" + value: "{{ .Values.async.core_pool_size }}" + - name: "ASYNC_MAX_POOL_SIZE" + value: "{{ .Values.async.max_pool_size }}" + - name: "ASYNC_QUEUE_CAPACITY" + value: "{{ .Values.async.queue_capacity }}" + - name: "EXPIRY_TIME" + value: "{{ .Values.expiry_time }}" + - name: "SALTING_ENABLED" + value: "{{ .Values.salting.enabled }}" + - name: "LOGGING_LEVEL_ROOT" + value: "{{ .Values.global.LOGGING_LEVEL_ROOT }}" + - name: MOCK_SCHEMA_HOSTNAME + value: "{{ .Values.mock_schema.hostname }}" + - name: PAYMENTADVICE + value: "{{.Values.paymentadvice}}" + +{{- if .Values.extraEnvs | default .Values.deployment.extraEnvs }} +{{ toYaml ( .Values.extraEnvs | default .Values.deployment.extraEnvs ) | indent 10 }} +{{- end }} + envFrom: {{ toYaml ( .Values.envFrom | default .Values.deployment.envFrom ) | nindent 12 }} + securityContext: {{ toYaml ( .Values.podSecurityContext | default .Values.deployment.securityContext ) | nindent 12 }} + volumeMounts: + - name: ph-ee-config + mountPath: "/config" + volumes: + - name: ph-ee-config + configMap: + name: ph-ee-config +{{- end }} diff --git a/ph-ee-env-template/helm/ph-ee-engine/vouchers/templates/ingress.yaml b/ph-ee-env-template/helm/ph-ee-engine/vouchers/templates/ingress.yaml new file mode 100644 index 000000000..5b7d9f670 --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/vouchers/templates/ingress.yaml @@ -0,0 +1,50 @@ +{{- if .Values.ingress.enabled -}} +{{- $pathtype := .Values.ingress.pathtype -}} +{{- $ingressPath := .Values.ingress.path -}} +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: ph-ee-vouchers + labels: + app: {{ .Chart.Name }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +{{- with .Values.ingress.annotations }} + annotations: +{{ toYaml . | indent 4 }} +{{- end }} +spec: + {{- if .Values.ingress.className }} + ingressClassName: {{ .Values.ingress.className | quote }} + {{- end }} +{{- if .Values.ingress.tls }} + tls: + {{- if .ingressPath }} + {{- range .Values.ingress.tls }} + - hosts: + {{- range .hosts }} + - {{ . }} + {{- end }} + secretName: {{ .secretName }} + {{- end }} +{{- else }} +{{ toYaml .Values.ingress.tls | indent 4 }} + {{- end }} +{{- end}} + rules: + {{- range .Values.ingress.hosts }} + - host: {{ .host }} + http: + paths: + {{- range .paths }} + - path: {{ .path }} + pathType: {{ $pathtype }} + backend: + service: + name: {{ .backend.service.name}} + port: + number: {{ .backend.service.port.number}} + {{- end }} + {{- end }} + {{- end }} + \ No newline at end of file diff --git a/ph-ee-env-template/helm/ph-ee-engine/vouchers/templates/rolebinding.yaml b/ph-ee-env-template/helm/ph-ee-engine/vouchers/templates/rolebinding.yaml new file mode 100644 index 000000000..68eea9b8b --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/vouchers/templates/rolebinding.yaml @@ -0,0 +1,15 @@ +{{- if .Values.managedServiceAccount }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: ph-ee-operator-role-binding + namespace: {{ .Release.Namespace }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: ph-ee-operator-role +subjects: + - kind: ServiceAccount + name: payment-hub + namespace: {{ .Release.Namespace }} + {{- end -}} \ No newline at end of file diff --git a/ph-ee-env-template/helm/ph-ee-engine/vouchers/templates/service.yaml b/ph-ee-env-template/helm/ph-ee-engine/vouchers/templates/service.yaml new file mode 100644 index 000000000..47ac4b6b6 --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/vouchers/templates/service.yaml @@ -0,0 +1,19 @@ +{{- if .Values.enabled -}} +apiVersion: {{ .Values.service.apiversion }} +kind: Service +metadata: + labels: + app: ph-ee-vouchers + name: ph-ee-vouchers +spec: + ports: + - name: port + port: 80 + protocol: TCP + targetPort: 8080 + + selector: + app: ph-ee-vouchers + sessionAffinity: None + type: ClusterIP +{{- end }} \ No newline at end of file diff --git a/ph-ee-env-template/helm/ph-ee-engine/vouchers/templates/serviceaccount.yaml b/ph-ee-env-template/helm/ph-ee-engine/vouchers/templates/serviceaccount.yaml new file mode 100644 index 000000000..8d8f775db --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/vouchers/templates/serviceaccount.yaml @@ -0,0 +1,15 @@ +{{- if .Values.managedServiceAccount }} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: ph-ee-vouchers + annotations: + {{- with .Values.serviceAccountAnnotations }} + {{- toYaml . | nindent 4 }} + {{- end }} + labels: + app: ph-ee-vouchers + chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" + heritage: {{ .Release.Service | quote }} + release: {{ .Release.Name | quote }} +{{- end -}} \ No newline at end of file diff --git a/ph-ee-env-template/helm/ph-ee-engine/vouchers/values.yaml b/ph-ee-env-template/helm/ph-ee-engine/vouchers/values.yaml new file mode 100644 index 000000000..5073ac7aa --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/vouchers/values.yaml @@ -0,0 +1,81 @@ +service: + apiversion: "v1" + +secret: + apiversion: "v1" + +configmap: + apiversion: "v1" + +enabled: true +image: docker.io/openmf/ph-ee-vouchers:latest +imagePullPolicy: "" +SPRING_PROFILES_ACTIVE: "" +LOGGING_LEVEL_ROOT: "" +spring: + datasource: + url: + username: + password: + + +async: + core_pool_size: + max_pool_size: + queue_capacity: + +expiry_time: + +salting: + enabled: + +payer: + tenant: + identifier: + identifierType: + +identity_account_mapper: + hostname: "http://ph-ee-identity-account-mapper:80" +voucher: + hostname: "http://ph-ee-vouchers:80" +operations: + hostname: "http://ph-ee-operations-app:5000" + endpoints: + transfers: "" +mock_schema: + hostname: "http://ph-ee-connector-mock-payment-schema:8080" + +limits: + cpu: "500m" + memory: "512M" +requests: + cpu: "100m" + memory: "256M" + +# Enabling this will publicly expose your Elasticsearch instance. +# Only enable this if you have security enabled on your cluster +ingress: + enabled: false + annotations: {} + # kubernetes.io/ingress.class: "nginx" + pathtype: ImplementationSpecific + hosts: + - host: "" + paths: + - path: / + tls: [] + # - secretName: sandbox-secret + # hosts: + # - chart-example.local +paymentadvice: false +deployment: + apiVersion: "apps/v1" + annotations: + deployTime: "{{ .Values.deployTime }}" + +livenessProbe: + initialDelaySeconds: 20 + periodSeconds: 30 +readinessProbe: + initialDelaySeconds: 20 + periodSeconds: 30 diff --git a/ph-ee-env-template/helm/ph-ee-engine/zeebe-ops/Chart.yaml b/ph-ee-env-template/helm/ph-ee-engine/zeebe-ops/Chart.yaml new file mode 100644 index 000000000..754ac06fb --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/zeebe-ops/Chart.yaml @@ -0,0 +1,5 @@ +apiVersion: v1 +description: zeebe-ops +name: zeebe_ops +version: 1.0.0 +appVersion: "1.0.0" \ No newline at end of file diff --git a/ph-ee-env-template/helm/ph-ee-engine/zeebe-ops/README.md b/ph-ee-env-template/helm/ph-ee-engine/zeebe-ops/README.md new file mode 100644 index 000000000..98cd1635b --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/zeebe-ops/README.md @@ -0,0 +1,42 @@ +# zeebe_ops + +![Version: 1.0.0](https://img.shields.io/badge/Version-1.0.0-informational?style=flat-square) ![AppVersion: 1.0.0](https://img.shields.io/badge/AppVersion-1.0.0-informational?style=flat-square) + +zeebe-ops + +## Values + +| Key | Type | Default | Description | +|-----|------|---------|-------------| +| configmap.apiversion | string | `"v1"` | | +| deployment.annotations.deployTime | string | `"{{ .Values.deployTime }}"` | | +| deployment.apiVersion | string | `"apps/v1"` | | +| elasticsearch_contactpoint | string | `"ph-ee-elasticsearch:9200"` | | +| elasticsearch_security_enabled | bool | `false` | | +| elasticsearch_sslverification | bool | `false` | | +| elasticsearch_url | string | `"http://ph-ee-elasticsearch:9200/"` | | +| enabled | bool | `true` | | +| hostname | string | `"zeebeops.sandbox.mifos.io"` | | +| image | string | `""` | | +| imageTag | string | `"latest"` | | +| ingress.annotations."kubernetes.io/ingress.class" | string | `"nginx"` | | +| ingress.apiversion | string | `"networking.k8s.io/v1"` | | +| ingress.backend.service.name | string | `"ph-ee-zeebe-ops"` | | +| ingress.backend.service.port.number | int | `80` | | +| ingress.className | string | `"nginx"` | | +| ingress.enabled | bool | `true` | | +| ingress.path | string | `"/"` | | +| ingress.tls[0].hosts | string | `"zeebeops.sandbox.mifos.io"` | | +| ingress.tls[1].secretName | string | `"sandbox-secret"` | | +| limits.cpu | string | `"500m"` | | +| limits.memory | string | `"512M"` | | +| requests.cpu | string | `"100m"` | | +| requests.memory | string | `"256M"` | | +| secret.apiversion | string | `"v1"` | | +| service.apiversion | string | `"v1"` | | +| tenants | string | `"gorilla,lion"` | | +| wildcardhostname | string | `"zeebeops.sandbox.mifos.io"` | | +| zeebe_broker_contactpoint | string | `"zeebe-zeebe-gateway:26500"` | | + +---------------------------------------------- +Autogenerated from chart metadata using [helm-docs v1.11.0](https://github.com/norwoodj/helm-docs/releases/v1.11.0) diff --git a/ph-ee-env-template/helm/ph-ee-engine/zeebe-ops/templates/_helpers.tpl b/ph-ee-env-template/helm/ph-ee-engine/zeebe-ops/templates/_helpers.tpl new file mode 100644 index 000000000..2fc2278d9 --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/zeebe-ops/templates/_helpers.tpl @@ -0,0 +1,36 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +*/}} +{{- define "zeebe_ops.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +*/}} +{{- define "ph-ee-zeebe-ops.fullname" -}} +{{- if .Values.fullnameOverride -}} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- $name := default .Chart.Name .Values.nameOverride -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} + +{{- define "release.name" -}} +{{- list .Values.a .Values.b .Values.c | join "-" }} +{{- end }} + +{{/* +Use the fullname if the serviceAccount value is not set +*/}} +{{- define "ph-ee-zeebe-ops.serviceAccount" -}} +{{- if .Values.serviceAccount }} +{{- .Values.serviceAccount -}} +{{- else }} +{{- $name := default .Chart.Name .Values.nameOverride -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} diff --git a/ph-ee-env-template/helm/ph-ee-engine/zeebe-ops/templates/clusterrole.yaml b/ph-ee-env-template/helm/ph-ee-engine/zeebe-ops/templates/clusterrole.yaml new file mode 100644 index 000000000..3092d932d --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/zeebe-ops/templates/clusterrole.yaml @@ -0,0 +1,11 @@ +{{- if .Values.managedServiceAccount }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + # "namespace" omitted since ClusterRoles are not namespaced + name: ph-ee-zeebe-ops-c-role +rules: +- apiGroups: [""] + resources: ["secrets"] + verbs: ["get", "watch", "list"] +{{- end -}} \ No newline at end of file diff --git a/ph-ee-env-template/helm/ph-ee-engine/zeebe-ops/templates/clusterrolebinding.yaml b/ph-ee-env-template/helm/ph-ee-engine/zeebe-ops/templates/clusterrolebinding.yaml new file mode 100644 index 000000000..e269e4f60 --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/zeebe-ops/templates/clusterrolebinding.yaml @@ -0,0 +1,15 @@ +{{- if .Values.managedServiceAccount }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: ph-ee-zeebe-ops-c-role-binding +subjects: +- kind: ServiceAccount + name: ph-ee-zeebe-ops # name of your service account + namespace: {{ .Release.Namespace }} # this is the namespace your service account is in +roleRef: # referring to your ClusterRole + kind: ClusterRole + name: ph-ee-zeebe-ops-c-role + apiGroup: rbac.authorization.k8s.io + +{{- end -}} \ No newline at end of file diff --git a/ph-ee-env-template/helm/ph-ee-engine/zeebe-ops/templates/deployment.yaml b/ph-ee-env-template/helm/ph-ee-engine/zeebe-ops/templates/deployment.yaml new file mode 100644 index 000000000..7e808030f --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/zeebe-ops/templates/deployment.yaml @@ -0,0 +1,75 @@ +{{- if .Values.enabled -}} + +apiVersion: apps/v1 +kind: Deployment +metadata: + name: ph-ee-zeebe-ops + labels: + app: ph-ee-zeebe-ops +spec: + replicas: {{ .Values.replicas }} + selector: + matchLabels: + app: ph-ee-zeebe-ops + template: + metadata: + labels: + app: ph-ee-zeebe-ops + annotations: +{{- if .Values.deployment.annotations }} +{{ toYaml .Values.deployment.annotations | indent 8 }} +{{- end }} + spec: + initContainers: + #During this Pod's initialization, check that zeebe-gateway service is up and running before starting this pod + - name: check-zeebe-gateway-ready + image: busybox:latest + command: [ 'sh', '-c','until nc -vz {{ .Release.Name }}-zeebe-gateway 26500; do echo "Waiting for zeebe-gateway service"; sleep 2; done;' ] + containers: + - name: ph-ee-zeebe-ops + image: "{{ .Values.image }}" + imagePullPolicy: "{{ .Values.global.imagePullPolicy }}" + resources: + limits: + memory: "{{ .Values.limits.memory }}" + cpu: "{{ .Values.limits.cpu }}" + requests: + memory: "{{ .Values.requests.memory }}" + cpu: "{{ .Values.requests.cpu }}" + ports: + - containerPort: 5000 + env: + - name: "ZEEBE_BROKER_CONTACTPOINT" + value: "{{ .Release.Name }}-zeebe-gateway:26500" + - name: "TENANTS" + value: "{{ .Values.global.tenants }}" + - name: "DFSPIDS" + value: "{{ .Values.global.DFSPIDS }}" + - name: "elasticsearch_url" + value: "{{ .Values.elasticsearch_url }}" + - name: "LOGGING_LEVEL_ROOT" + value: "{{ .Values.global.LOGGING_LEVEL_ROOT }}" + - name: "SPRING_DATA_ELASTICSEARCH_CLIENT_REACTIVE_ENDPOINTS" + value: "{{ .Values.elasticsearch_contactpoint }}" + - name: "ELASTICSEARCH_SECURITY_ENABLED" + value: "{{ .Values.elasticsearch_security_enabled }}" + - name: "ELASTICSEARCH_SSLVERIFICATION" + value: "{{ .Values.elasticsearch_sslverification }}" + - name: "ELASTICSEARCH_USERNAME" + valueFrom: + secretKeyRef: + name: elastic-credentials + key: username + - name: "ELASTICSEARCH_PASSWORD" + valueFrom: + secretKeyRef: + name: elastic-credentials + key: password +{{- if .Values.extraEnvs | default .Values.deployment.extraEnvs }} +{{ toYaml ( .Values.extraEnvs | default .Values.deployment.extraEnvs ) | indent 10 }} +{{- end }} + envFrom: {{ toYaml ( .Values.envFrom | default .Values.deployment.envFrom ) | nindent 12 }} + securityContext: {{ toYaml ( .Values.podSecurityContext | default .Values.deployment.securityContext ) | nindent 12 }} + + +{{- end }} diff --git a/ph-ee-env-template/helm/ph-ee-engine/zeebe-ops/templates/ingress.yaml b/ph-ee-env-template/helm/ph-ee-engine/zeebe-ops/templates/ingress.yaml new file mode 100644 index 000000000..07adc2ee9 --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/zeebe-ops/templates/ingress.yaml @@ -0,0 +1,56 @@ +{{- if .Values.ingress.enabled -}} +{{- $pathtype := .Values.ingress.pathtype -}} +{{- $ingressPath := .Values.ingress.path -}} +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: ph-ee-zeebe-ops + labels: + app: {{ .Chart.Name }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +{{- with .Values.ingress.annotations }} + annotations: +{{ toYaml . | indent 4 }} +{{- end }} +spec: + {{- if .Values.ingress.className }} + ingressClassName: {{ .Values.ingress.className | quote }} + {{- end }} +{{- if .Values.ingress.tls }} + tls: + {{- if .ingressPath }} + {{- range .Values.ingress.tls }} + - hosts: + {{- range .hosts }} + - {{ . }} + {{- end }} + secretName: {{ .secretName }} + {{- end }} +{{- else }} +{{ toYaml .Values.ingress.tls | indent 4 }} + {{- end }} +{{- end}} + rules: + {{- range .Values.ingress.hosts }} + - host: {{ .host }} + http: + paths: + {{- range .paths }} + - path: {{ .path }} + pathType: {{ $pathtype }} + backend: + service: + name: {{ .backend.service.name}} + port: + number: {{ .backend.service.port.number}} + {{- end }} + - path: /actuator + pathType: Prefix + backend: + service: + name: ph-ee-zeebe-ops + port: + number: 8080 + {{- end }} + {{- end }} diff --git a/ph-ee-env-template/helm/ph-ee-engine/zeebe-ops/templates/role.yaml b/ph-ee-env-template/helm/ph-ee-engine/zeebe-ops/templates/role.yaml new file mode 100644 index 000000000..3c945ae45 --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/zeebe-ops/templates/role.yaml @@ -0,0 +1,14 @@ +{{- if .Values.managedServiceAccount }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: ph-ee-zeebe-ops-role + namespace: {{ .Release.Namespace }} +rules: +- apiGroups: + - "" + resources: + - pods + - configmaps + verbs: ["get", "create", "update"] +{{- end -}} \ No newline at end of file diff --git a/ph-ee-env-template/helm/ph-ee-engine/zeebe-ops/templates/rolebinding.yaml b/ph-ee-env-template/helm/ph-ee-engine/zeebe-ops/templates/rolebinding.yaml new file mode 100644 index 000000000..0f5a6dffb --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/zeebe-ops/templates/rolebinding.yaml @@ -0,0 +1,15 @@ +{{- if .Values.managedServiceAccount }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: ph-ee-zeebe-ops-role-binding + namespace: {{ .Release.Namespace }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: ph-ee-zeebe-ops-role +subjects: +- kind: ServiceAccount + name: ph-ee-zeebe-ops + namespace: {{ .Release.Namespace }} +{{- end -}} \ No newline at end of file diff --git a/ph-ee-env-template/helm/ph-ee-engine/zeebe-ops/templates/service.yaml b/ph-ee-env-template/helm/ph-ee-engine/zeebe-ops/templates/service.yaml new file mode 100644 index 000000000..3c9633e0e --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/zeebe-ops/templates/service.yaml @@ -0,0 +1,22 @@ +{{- if .Values.enabled -}} +apiVersion: {{ .Values.service.apiversion }} +kind: Service +metadata: + labels: + app: ph-ee-zeebe-ops + name: ph-ee-zeebe-ops +spec: + ports: + - name: port + port: 80 + protocol: TCP + targetPort: 5000 + - name: actuator + protocol: TCP + port: 8080 # Port where Actuator endpoints are exposed + targetPort: 8080 + selector: + app: ph-ee-zeebe-ops + sessionAffinity: None + type: ClusterIP +{{- end }} diff --git a/ph-ee-env-template/helm/ph-ee-engine/zeebe-ops/templates/serviceaccount.yaml b/ph-ee-env-template/helm/ph-ee-engine/zeebe-ops/templates/serviceaccount.yaml new file mode 100644 index 000000000..677154ac8 --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/zeebe-ops/templates/serviceaccount.yaml @@ -0,0 +1,15 @@ +{{- if .Values.managedServiceAccount }} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: "ph-ee-zeebe-ops" + annotations: + {{- with .Values.serviceAccountAnnotations }} + {{- toYaml . | nindent 4 }} + {{- end }} + labels: + app: "ph-ee-zeebe-ops" + chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" + heritage: {{ .Release.Service | quote }} + release: {{ .Release.Name | quote }} +{{- end -}} \ No newline at end of file diff --git a/ph-ee-env-template/helm/ph-ee-engine/zeebe-ops/values.yaml b/ph-ee-env-template/helm/ph-ee-engine/zeebe-ops/values.yaml new file mode 100644 index 000000000..5c161f43a --- /dev/null +++ b/ph-ee-env-template/helm/ph-ee-engine/zeebe-ops/values.yaml @@ -0,0 +1,42 @@ +service: + apiversion: "v1" + +secret: + apiversion: "v1" + +configmap: + apiversion: "v1" + +enabled: true +image: "" +imageTag: latest +elasticsearch_url: "http://ph-ee-elasticsearch:9200/" +elasticsearch_contactpoint: "ph-ee-elasticsearch:9200" +tenants: "gorilla,lion" +elasticsearch_sslverification: false +elasticsearch_security_enabled: false +limits: + cpu: "500m" + memory: "512M" +requests: + cpu: "100m" + memory: "256M" +# Enabling this will publicly expose your Elasticsearch instance. +# Only enable this if you have security enabled on your cluster +ingress: + enabled: false + annotations: {} + # kubernetes.io/ingress.class: "nginx" + pathtype: ImplementationSpecific + hosts: + - host: "" + paths: + - path: / + tls: [] + # - secretName: sandbox-secret + # hosts: + # - chart-example.local +deployment: + apiVersion: "apps/v1" + annotations: + deployTime: "{{ .Values.deployTime }}" \ No newline at end of file diff --git a/ph-ee-env-template/orchestration/feel/acknowledgement-individual-workflow.bpmn b/ph-ee-env-template/orchestration/feel/acknowledgement-individual-workflow.bpmn new file mode 100644 index 000000000..e219ec31c --- /dev/null +++ b/ph-ee-env-template/orchestration/feel/acknowledgement-individual-workflow.bpmn @@ -0,0 +1,184 @@ + + + + + Flow_0hik7am + + + Flow_1w7vmx6 + Flow_1th9p1k + + + + + Flow_1muu2qv + + PT90S + + + + + + + + Flow_0rrma2a + Flow_1izyfow + Flow_0v4yazg + Flow_075g5y3 + + + + + + + + Flow_0gxs18c + Flow_0m8wbue + Flow_075g5y3 + Flow_0rrma2a + + + Flow_1l7ujpu + + PT90S + + + + + + Flow_0cse45n + Flow_1wpqedg + Flow_0m8wbue + + + Flow_0hik7am + Flow_0cse45n + + + Flow_1izyfow + Flow_1w7vmx6 + + + Flow_0v4yazg + Flow_1th9p1k + + + Flow_1muu2qv + Flow_1wpqedg + + + Flow_1l7ujpu + Flow_0gxs18c + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ph-ee-env-template/orchestration/feel/acknowledgement-pre-workflow.bpmn b/ph-ee-env-template/orchestration/feel/acknowledgement-pre-workflow.bpmn new file mode 100644 index 000000000..28337a9bd --- /dev/null +++ b/ph-ee-env-template/orchestration/feel/acknowledgement-pre-workflow.bpmn @@ -0,0 +1,115 @@ + + + + + Flow_1sq9wn7 + + + + + + + Flow_1sq9wn7 + Flow_0biu2rr + + + Flow_0biu2rr + Flow_06z7r22 + + + + + + Flow_0mhw4ub + + + Flow_1lyw7r1 + + PT10M + + + + Flow_12ejntn + Flow_1ef22lf + + + Flow_1ef22lf + Flow_0mhw4ub + + + Flow_1lyw7r1 + Flow_12ejntn + Flow_06z7r22 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ph-ee-exporter/.github/pull_request_template.md b/ph-ee-exporter/.github/pull_request_template.md new file mode 100644 index 000000000..98c407dab --- /dev/null +++ b/ph-ee-exporter/.github/pull_request_template.md @@ -0,0 +1,20 @@ +## Description + +* Describe the changes made and why they were made. +* Add a link to teh design document or include the design bullet points related to this PR here. + + _(Ignore if these details are present on the associated JIRA ticket)_ + +## Checklist + +Please make sure these boxes are checked before submitting your pull request - thanks! + +- [ ] Design related bullet points or design document link related to this PR added in the description above. + +- [ ] Updated corresponding Postman Collection or Api documentation for the changes in this PR. + +- [ ] Create/update unit or integration tests for verifying the changes made. + +- [ ] Add required Swagger annotation and update API documentation with details of any API changes if applicable + +- [ ] Followed the naming conventions as given in https://docs.google.com/document/d/1Q4vaMSzrTxxh9TS0RILuNkSkYCxotuYk1Xe0CMIkkCU/edit?usp=sharing diff --git a/ph-ee-exporter/.gitignore b/ph-ee-exporter/.gitignore new file mode 100644 index 000000000..7c648d973 --- /dev/null +++ b/ph-ee-exporter/.gitignore @@ -0,0 +1,7 @@ +.idea +*.iml +target +dependency-reduced-pom.xml + +build +.gradle diff --git a/ph-ee-exporter/Jenkinsfile b/ph-ee-exporter/Jenkinsfile new file mode 100644 index 000000000..ca637ee4c --- /dev/null +++ b/ph-ee-exporter/Jenkinsfile @@ -0,0 +1,11 @@ +pipeline { + agent any + stages { + stage('build') { + steps { + sh 'mvn --version' + sh 'mvn -U clean package deploy' + } + } + } +} diff --git a/ph-ee-exporter/LICENSE b/ph-ee-exporter/LICENSE new file mode 100644 index 000000000..a612ad981 --- /dev/null +++ b/ph-ee-exporter/LICENSE @@ -0,0 +1,373 @@ +Mozilla Public License Version 2.0 +================================== + +1. Definitions +-------------- + +1.1. "Contributor" + means each individual or legal entity that creates, contributes to + the creation of, or owns Covered Software. + +1.2. "Contributor Version" + means the combination of the Contributions of others (if any) used + by a Contributor and that particular Contributor's Contribution. + +1.3. "Contribution" + means Covered Software of a particular Contributor. + +1.4. "Covered Software" + means Source Code Form to which the initial Contributor has attached + the notice in Exhibit A, the Executable Form of such Source Code + Form, and Modifications of such Source Code Form, in each case + including portions thereof. + +1.5. "Incompatible With Secondary Licenses" + means + + (a) that the initial Contributor has attached the notice described + in Exhibit B to the Covered Software; or + + (b) that the Covered Software was made available under the terms of + version 1.1 or earlier of the License, but not also under the + terms of a Secondary License. + +1.6. "Executable Form" + means any form of the work other than Source Code Form. + +1.7. "Larger Work" + means a work that combines Covered Software with other material, in + a separate file or files, that is not Covered Software. + +1.8. "License" + means this document. + +1.9. "Licensable" + means having the right to grant, to the maximum extent possible, + whether at the time of the initial grant or subsequently, any and + all of the rights conveyed by this License. + +1.10. "Modifications" + means any of the following: + + (a) any file in Source Code Form that results from an addition to, + deletion from, or modification of the contents of Covered + Software; or + + (b) any new file in Source Code Form that contains any Covered + Software. + +1.11. "Patent Claims" of a Contributor + means any patent claim(s), including without limitation, method, + process, and apparatus claims, in any patent Licensable by such + Contributor that would be infringed, but for the grant of the + License, by the making, using, selling, offering for sale, having + made, import, or transfer of either its Contributions or its + Contributor Version. + +1.12. "Secondary License" + means either the GNU General Public License, Version 2.0, the GNU + Lesser General Public License, Version 2.1, the GNU Affero General + Public License, Version 3.0, or any later versions of those + licenses. + +1.13. "Source Code Form" + means the form of the work preferred for making modifications. + +1.14. "You" (or "Your") + means an individual or a legal entity exercising rights under this + License. For legal entities, "You" includes any entity that + controls, is controlled by, or is under common control with You. For + purposes of this definition, "control" means (a) the power, direct + or indirect, to cause the direction or management of such entity, + whether by contract or otherwise, or (b) ownership of more than + fifty percent (50%) of the outstanding shares or beneficial + ownership of such entity. + +2. License Grants and Conditions +-------------------------------- + +2.1. Grants + +Each Contributor hereby grants You a world-wide, royalty-free, +non-exclusive license: + +(a) under intellectual property rights (other than patent or trademark) + Licensable by such Contributor to use, reproduce, make available, + modify, display, perform, distribute, and otherwise exploit its + Contributions, either on an unmodified basis, with Modifications, or + as part of a Larger Work; and + +(b) under Patent Claims of such Contributor to make, use, sell, offer + for sale, have made, import, and otherwise transfer either its + Contributions or its Contributor Version. + +2.2. Effective Date + +The licenses granted in Section 2.1 with respect to any Contribution +become effective for each Contribution on the date the Contributor first +distributes such Contribution. + +2.3. Limitations on Grant Scope + +The licenses granted in this Section 2 are the only rights granted under +this License. No additional rights or licenses will be implied from the +distribution or licensing of Covered Software under this License. +Notwithstanding Section 2.1(b) above, no patent license is granted by a +Contributor: + +(a) for any code that a Contributor has removed from Covered Software; + or + +(b) for infringements caused by: (i) Your and any other third party's + modifications of Covered Software, or (ii) the combination of its + Contributions with other software (except as part of its Contributor + Version); or + +(c) under Patent Claims infringed by Covered Software in the absence of + its Contributions. + +This License does not grant any rights in the trademarks, service marks, +or logos of any Contributor (except as may be necessary to comply with +the notice requirements in Section 3.4). + +2.4. Subsequent Licenses + +No Contributor makes additional grants as a result of Your choice to +distribute the Covered Software under a subsequent version of this +License (see Section 10.2) or under the terms of a Secondary License (if +permitted under the terms of Section 3.3). + +2.5. Representation + +Each Contributor represents that the Contributor believes its +Contributions are its original creation(s) or it has sufficient rights +to grant the rights to its Contributions conveyed by this License. + +2.6. Fair Use + +This License is not intended to limit any rights You have under +applicable copyright doctrines of fair use, fair dealing, or other +equivalents. + +2.7. Conditions + +Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted +in Section 2.1. + +3. Responsibilities +------------------- + +3.1. Distribution of Source Form + +All distribution of Covered Software in Source Code Form, including any +Modifications that You create or to which You contribute, must be under +the terms of this License. You must inform recipients that the Source +Code Form of the Covered Software is governed by the terms of this +License, and how they can obtain a copy of this License. You may not +attempt to alter or restrict the recipients' rights in the Source Code +Form. + +3.2. Distribution of Executable Form + +If You distribute Covered Software in Executable Form then: + +(a) such Covered Software must also be made available in Source Code + Form, as described in Section 3.1, and You must inform recipients of + the Executable Form how they can obtain a copy of such Source Code + Form by reasonable means in a timely manner, at a charge no more + than the cost of distribution to the recipient; and + +(b) You may distribute such Executable Form under the terms of this + License, or sublicense it under different terms, provided that the + license for the Executable Form does not attempt to limit or alter + the recipients' rights in the Source Code Form under this License. + +3.3. Distribution of a Larger Work + +You may create and distribute a Larger Work under terms of Your choice, +provided that You also comply with the requirements of this License for +the Covered Software. If the Larger Work is a combination of Covered +Software with a work governed by one or more Secondary Licenses, and the +Covered Software is not Incompatible With Secondary Licenses, this +License permits You to additionally distribute such Covered Software +under the terms of such Secondary License(s), so that the recipient of +the Larger Work may, at their option, further distribute the Covered +Software under the terms of either this License or such Secondary +License(s). + +3.4. Notices + +You may not remove or alter the substance of any license notices +(including copyright notices, patent notices, disclaimers of warranty, +or limitations of liability) contained within the Source Code Form of +the Covered Software, except that You may alter any license notices to +the extent required to remedy known factual inaccuracies. + +3.5. Application of Additional Terms + +You may choose to offer, and to charge a fee for, warranty, support, +indemnity or liability obligations to one or more recipients of Covered +Software. However, You may do so only on Your own behalf, and not on +behalf of any Contributor. You must make it absolutely clear that any +such warranty, support, indemnity, or liability obligation is offered by +You alone, and You hereby agree to indemnify every Contributor for any +liability incurred by such Contributor as a result of warranty, support, +indemnity or liability terms You offer. You may include additional +disclaimers of warranty and limitations of liability specific to any +jurisdiction. + +4. Inability to Comply Due to Statute or Regulation +--------------------------------------------------- + +If it is impossible for You to comply with any of the terms of this +License with respect to some or all of the Covered Software due to +statute, judicial order, or regulation then You must: (a) comply with +the terms of this License to the maximum extent possible; and (b) +describe the limitations and the code they affect. Such description must +be placed in a text file included with all distributions of the Covered +Software under this License. Except to the extent prohibited by statute +or regulation, such description must be sufficiently detailed for a +recipient of ordinary skill to be able to understand it. + +5. Termination +-------------- + +5.1. The rights granted under this License will terminate automatically +if You fail to comply with any of its terms. However, if You become +compliant, then the rights granted under this License from a particular +Contributor are reinstated (a) provisionally, unless and until such +Contributor explicitly and finally terminates Your grants, and (b) on an +ongoing basis, if such Contributor fails to notify You of the +non-compliance by some reasonable means prior to 60 days after You have +come back into compliance. Moreover, Your grants from a particular +Contributor are reinstated on an ongoing basis if such Contributor +notifies You of the non-compliance by some reasonable means, this is the +first time You have received notice of non-compliance with this License +from such Contributor, and You become compliant prior to 30 days after +Your receipt of the notice. + +5.2. If You initiate litigation against any entity by asserting a patent +infringement claim (excluding declaratory judgment actions, +counter-claims, and cross-claims) alleging that a Contributor Version +directly or indirectly infringes any patent, then the rights granted to +You by any and all Contributors for the Covered Software under Section +2.1 of this License shall terminate. + +5.3. In the event of termination under Sections 5.1 or 5.2 above, all +end user license agreements (excluding distributors and resellers) which +have been validly granted by You or Your distributors under this License +prior to termination shall survive termination. + +************************************************************************ +* * +* 6. Disclaimer of Warranty * +* ------------------------- * +* * +* Covered Software is provided under this License on an "as is" * +* basis, without warranty of any kind, either expressed, implied, or * +* statutory, including, without limitation, warranties that the * +* Covered Software is free of defects, merchantable, fit for a * +* particular purpose or non-infringing. The entire risk as to the * +* quality and performance of the Covered Software is with You. * +* Should any Covered Software prove defective in any respect, You * +* (not any Contributor) assume the cost of any necessary servicing, * +* repair, or correction. This disclaimer of warranty constitutes an * +* essential part of this License. No use of any Covered Software is * +* authorized under this License except under this disclaimer. * +* * +************************************************************************ + +************************************************************************ +* * +* 7. Limitation of Liability * +* -------------------------- * +* * +* Under no circumstances and under no legal theory, whether tort * +* (including negligence), contract, or otherwise, shall any * +* Contributor, or anyone who distributes Covered Software as * +* permitted above, be liable to You for any direct, indirect, * +* special, incidental, or consequential damages of any character * +* including, without limitation, damages for lost profits, loss of * +* goodwill, work stoppage, computer failure or malfunction, or any * +* and all other commercial damages or losses, even if such party * +* shall have been informed of the possibility of such damages. This * +* limitation of liability shall not apply to liability for death or * +* personal injury resulting from such party's negligence to the * +* extent applicable law prohibits such limitation. Some * +* jurisdictions do not allow the exclusion or limitation of * +* incidental or consequential damages, so this exclusion and * +* limitation may not apply to You. * +* * +************************************************************************ + +8. Litigation +------------- + +Any litigation relating to this License may be brought only in the +courts of a jurisdiction where the defendant maintains its principal +place of business and such litigation shall be governed by laws of that +jurisdiction, without reference to its conflict-of-law provisions. +Nothing in this Section shall prevent a party's ability to bring +cross-claims or counter-claims. + +9. Miscellaneous +---------------- + +This License represents the complete agreement concerning the subject +matter hereof. If any provision of this License is held to be +unenforceable, such provision shall be reformed only to the extent +necessary to make it enforceable. Any law or regulation which provides +that the language of a contract shall be construed against the drafter +shall not be used to construe this License against a Contributor. + +10. Versions of the License +--------------------------- + +10.1. New Versions + +Mozilla Foundation is the license steward. Except as provided in Section +10.3, no one other than the license steward has the right to modify or +publish new versions of this License. Each version will be given a +distinguishing version number. + +10.2. Effect of New Versions + +You may distribute the Covered Software under the terms of the version +of the License under which You originally received the Covered Software, +or under the terms of any subsequent version published by the license +steward. + +10.3. Modified Versions + +If you create software not governed by this License, and you want to +create a new license for such software, you may create and use a +modified version of this License if you rename the license and remove +any references to the name of the license steward (except to note that +such modified license differs from this License). + +10.4. Distributing Source Code Form that is Incompatible With Secondary +Licenses + +If You choose to distribute Source Code Form that is Incompatible With +Secondary Licenses under the terms of this version of the License, the +notice described in Exhibit B of this License must be attached. + +Exhibit A - Source Code Form License Notice +------------------------------------------- + + This Source Code Form is subject to the terms of the Mozilla Public + License, v. 2.0. If a copy of the MPL was not distributed with this + file, You can obtain one at http://mozilla.org/MPL/2.0/. + +If it is not possible or desirable to put the notice in a particular +file, then You may include the notice in a location (such as a LICENSE +file in a relevant directory) where a recipient would be likely to look +for such a notice. + +You may add additional accurate notices of copyright ownership. + +Exhibit B - "Incompatible With Secondary Licenses" Notice +--------------------------------------------------------- + + This Source Code Form is "Incompatible With Secondary Licenses", as + defined by the Mozilla Public License, v. 2.0. diff --git a/ph-ee-exporter/README.md b/ph-ee-exporter/README.md new file mode 100644 index 000000000..ff2bf61e1 --- /dev/null +++ b/ph-ee-exporter/README.md @@ -0,0 +1,2 @@ +# payment-hub-ee +Payment Hub Enterprise Edition middleware for integration to real-time payment systems. diff --git a/ph-ee-exporter/build.gradle b/ph-ee-exporter/build.gradle new file mode 100644 index 000000000..d1cc34959 --- /dev/null +++ b/ph-ee-exporter/build.gradle @@ -0,0 +1,49 @@ +/* + * This file was generated by the Gradle 'init' task. + * + * This project uses @Incubating APIs which are subject to change. + */ + +plugins { + id 'java' + id 'maven-publish' +} + +jar { + from { + configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) } + } +} + +repositories { + mavenLocal() + maven { + url = uri('https://repo.maven.apache.org/maven2/') + } +} + +dependencies { + implementation ('org.apache.kafka:kafka-clients:2.4.0'){ + exclude group: 'org.slf4j' + } + compileOnly 'io.camunda:zeebe-exporter-api:8.1.1' + compileOnly 'io.camunda:zeebe-elasticsearch-exporter:8.1.1' + compileOnly 'org.json:json:20190722' +} + +group = 'org.mifos.phee' +version = '1.3.0-SNAPSHOT' +description = 'exporter' +java.sourceCompatibility = JavaVersion.VERSION_17 + +publishing { + publications { + maven(MavenPublication) { + from(components.java) + } + } +} + +tasks.withType(JavaCompile) { + options.encoding = 'UTF-8' +} diff --git a/ph-ee-exporter/gradle/wrapper/gradle-wrapper.jar b/ph-ee-exporter/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 000000000..249e5832f Binary files /dev/null and b/ph-ee-exporter/gradle/wrapper/gradle-wrapper.jar differ diff --git a/ph-ee-exporter/gradle/wrapper/gradle-wrapper.properties b/ph-ee-exporter/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 000000000..8049c684f --- /dev/null +++ b/ph-ee-exporter/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-bin.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/ph-ee-exporter/gradlew b/ph-ee-exporter/gradlew new file mode 100755 index 000000000..a69d9cb6c --- /dev/null +++ b/ph-ee-exporter/gradlew @@ -0,0 +1,240 @@ +#!/bin/sh + +# +# Copyright © 2015-2021 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit + +APP_NAME="Gradle" +APP_BASE_NAME=${0##*/} + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/ph-ee-exporter/gradlew.bat b/ph-ee-exporter/gradlew.bat new file mode 100644 index 000000000..53a6b238d --- /dev/null +++ b/ph-ee-exporter/gradlew.bat @@ -0,0 +1,91 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 0 goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/ph-ee-exporter/pom.xml b/ph-ee-exporter/pom.xml new file mode 100644 index 000000000..c83ef250e --- /dev/null +++ b/ph-ee-exporter/pom.xml @@ -0,0 +1,85 @@ + + + 4.0.0 + + hu.dpc.phee + exporter + 1.0.0-SNAPSHOT + + + 11 + 11 + 11 + + UTF-8 + UTF-8 + 3.2.2 + + 8.1.1 + 2.4.0 + 7.6.0 + 20190722 + + + + + org.apache.kafka + kafka-clients + ${kafka.version} + + + org.slf4j + slf4j-api + + + + + io.camunda + zeebe-exporter-api + ${zeebe.version} + provided + + + io.camunda + zeebe-elasticsearch-exporter + ${zeebe.version} + provided + + + org.json + json + ${json.version} + provided + + + + + + + org.apache.maven.plugins + maven-shade-plugin + ${maven-shade-plugin.version} + + + package + + shade + + + + + + + + + + ph-ee-release + http://jenkins.mifos.io:8081/repository/ph-ee-release/ + + + ph-ee-snapshot + http://jenkins.mifos.io:8081/repository/ph-ee-snapshot/ + + + diff --git a/ph-ee-exporter/samples/book-funds.json b/ph-ee-exporter/samples/book-funds.json new file mode 100644 index 000000000..ef56dd94d --- /dev/null +++ b/ph-ee-exporter/samples/book-funds.json @@ -0,0 +1,43 @@ +{ + "partitionId": 1, + "value": { + "type": "book-funds", + "errorMessage": "", + "deadline": 1585044112709, + "errorCode": "", + "bpmnProcessId": "PaymentTest3", + "workflowKey": 2251799813939136, + "customHeaders": {}, + "worker": "default", + "retries": 3, + "elementId": "Task_0qxl8kt", + "elementInstanceKey": 2251799814338378, + "workflowDefinitionVersion": 3, + "variables": { + "transferResponse-PREPARE": "{\"transferCode\":\"0bb1310b-e522-4c3c-a714-5c4c95a44495\",\"completedTimestamp\":\"2020-03-24T11:56:48\",\"transactionCode\":\"a7523176-13b5-449f-bdb1-54b152cde78c\",\"state\":\"ACCEPTED\"}", + "payerConfirmation": "OK", + "transactionStatus": "200", + "localQuoteResponse": "{\"quoteCode\":\"b6ef57ac-9c56-4a93-93c8-e0cb28de9beb\",\"fspFee\":{\"amount\":1.000000,\"currency\":\"TZS\"},\"transactionCode\":\"a7523176-13b5-449f-bdb1-54b152cde78c\",\"state\":\"ACCEPTED\"}", + "payeeFspId": "in03tn05", + "transactionRequest": "{\n \"clientRefId\": \"ref\",\n \"payer\": {\n \"partyIdInfo\": {\n \"partyIdType\": \"MSISDN\",\n \"partyIdentifier\": \"27710203999\",\n\t\t\t\t\"fspId\" : \"in02tn03\",\n\t\t\t\t\"tenantId\" : \"tn03\"\n }\n },\n \"payee\": {\n \"partyIdInfo\": {\n \"partyIdType\": \"MSISDN\",\n \"partyIdentifier\": \"27710305999\"\n },\n \"merchantClassificationCode\": \"\"\n },\n \"amountType\": \"SEND\",\n \"amount\": {\n \"amount\": 13,\n \"currency\": \"TZS\"\n },\n \"transactionType\": {\n \"scenario\": \"TRANSFER\",\n \"initiator\": \"PAYER\",\n \"initiatorType\": \"CONSUMER\"\n },\n \"note\": \"Demo interoperation merchant payment\",\n \"expiration\": \"2019-12-31T00:00:00.000-01:00\"\n }\n", + "transactionId": "a7523176-13b5-449f-bdb1-54b152cde78c", + "externalAccountId": "9062b90de19b43989005d9", + "quoteResponse": "{\"transferAmount\":{\"amount\":\"13\",\"currency\":\"TZS\"},\"payeeReceiveAmount\":{\"amount\":\"13\",\"currency\":\"TZS\"},\"payeeFspFee\":{\"amount\":\"0\",\"currency\":\"TZS\"},\"payeeFspCommission\":{\"amount\":\"0\",\"currency\":\"TZS\"},\"expiration\":\"2020-03-24T10:56:45.431Z\",\"ilpPacket\":\"AQIxMyBnLnR6LmluMDN0bjA1Lk1TSVNETi4yNzcxMDMwNTk5OYIB0GV5SjBjbUZ1YzJGamRHbHZia2xrSWpvaVlUYzFNak14TnpZdE1UTmlOUzAwTkRsbUxXSmtZakV0TlRSaU1UVXlZMlJsTnpoaklpd2ljWFZ2ZEdWSlpDSTZJbVJtTXpFMU5ETmpMV1UxTm1FdE5ERmhOQzFpWTJaakxUSTRNVGczTlROa01qUmlOQ0lzSW5CaGVXVmxJanA3SW5CaGNuUjVTV1JKYm1adklqcDdJbkJoY25SNVNXUlVlWEJsSWpvaVRWTkpVMFJPSWl3aWNHRnlkSGxKWkdWdWRHbG1hV1Z5SWpvaU1qYzNNVEF6TURVNU9Ua2lMQ0ptYzNCSlpDSTZJbWx1TUROMGJqQTFJbjE5TENKd1lYbGxjaUk2ZXlKd1lYSjBlVWxrU1c1bWJ5STZleUp3WVhKMGVVbGtWSGx3WlNJNklrMVRTVk5FVGlJc0luQmhjblI1U1dSbGJuUnBabWxsY2lJNklqSTNOekV3TWpBek9UazVJaXdpWm5Od1NXUWlPaUpwYmpBeWRHNHdNeUo5ZlN3aVlXMXZkVzUwSWpwN0ltTjFjbkpsYm1ONUlqb2lWRnBUSWl3aVlXMXZkVzUwSWpvaU1UTWlmWDA9\",\"condition\":\"JZWzSiP-LkAA7RGhLQXEiu7h_gsnlhuTqhhM1xMrZiM\"}", + "tenantId": "tn03", + "timeoutQuoteRetryCount": 0, + "originDate": 1585043797178, + "isValidUserLookup": true, + "timeoutTransferRetryCount": 0 + }, + "workflowInstanceKey": 2251799814338288 + }, + "sourceRecordPosition": 167504082200, + "position": 167504082392, + "recordType": "EVENT", + "valueType": "JOB", + "timestamp": 1585043812740, + "intent": "ACTIVATED", + "rejectionType": "NULL_VAL", + "rejectionReason": "", + "key": 2251799814338379 +} \ No newline at end of file diff --git a/ph-ee-exporter/samples/payer-request-confirm-completed.json b/ph-ee-exporter/samples/payer-request-confirm-completed.json new file mode 100644 index 000000000..a6e6c5524 --- /dev/null +++ b/ph-ee-exporter/samples/payer-request-confirm-completed.json @@ -0,0 +1,28 @@ +{ + "partitionId": 1, + "value": { + "type": "payer-request-confirm", + "errorMessage": "", + "deadline": 1585044108258, + "errorCode": "", + "bpmnProcessId": "PaymentTest3", + "workflowKey": 2251799813939136, + "customHeaders": {}, + "worker": "default", + "retries": 3, + "elementId": "Task_11ralt4", + "elementInstanceKey": 2251799814338346, + "workflowDefinitionVersion": 3, + "variables": {}, + "workflowInstanceKey": 2251799814338288 + }, + "sourceRecordPosition": 167504041888, + "position": 167504042384, + "recordType": "EVENT", + "valueType": "JOB", + "timestamp": 1585043808313, + "intent": "COMPLETED", + "rejectionType": "NULL_VAL", + "rejectionReason": "", + "key": 2251799814338347 +} diff --git a/ph-ee-exporter/samples/payer-request-confirm.json b/ph-ee-exporter/samples/payer-request-confirm.json new file mode 100644 index 000000000..a02c9951e --- /dev/null +++ b/ph-ee-exporter/samples/payer-request-confirm.json @@ -0,0 +1,39 @@ +{ + "partitionId": 1, + "value": { + "type": "payer-request-confirm", + "errorMessage": "", + "deadline": 1585044108258, + "errorCode": "", + "bpmnProcessId": "PaymentTest3", + "workflowKey": 2251799813939136, + "customHeaders": {}, + "worker": "default", + "retries": 3, + "elementId": "Task_11ralt4", + "elementInstanceKey": 2251799814338346, + "workflowDefinitionVersion": 3, + "variables": { + "externalAccountId": "9062b90de19b43989005d9", + "quoteResponse": "{\"transferAmount\":{\"amount\":\"13\",\"currency\":\"TZS\"},\"payeeReceiveAmount\":{\"amount\":\"13\",\"currency\":\"TZS\"},\"payeeFspFee\":{\"amount\":\"0\",\"currency\":\"TZS\"},\"payeeFspCommission\":{\"amount\":\"0\",\"currency\":\"TZS\"},\"expiration\":\"2020-03-24T10:56:45.431Z\",\"ilpPacket\":\"AQIxMyBnLnR6LmluMDN0bjA1Lk1TSVNETi4yNzcxMDMwNTk5OYIB0GV5SjBjbUZ1YzJGamRHbHZia2xrSWpvaVlUYzFNak14TnpZdE1UTmlOUzAwTkRsbUxXSmtZakV0TlRSaU1UVXlZMlJsTnpoaklpd2ljWFZ2ZEdWSlpDSTZJbVJtTXpFMU5ETmpMV1UxTm1FdE5ERmhOQzFpWTJaakxUSTRNVGczTlROa01qUmlOQ0lzSW5CaGVXVmxJanA3SW5CaGNuUjVTV1JKYm1adklqcDdJbkJoY25SNVNXUlVlWEJsSWpvaVRWTkpVMFJPSWl3aWNHRnlkSGxKWkdWdWRHbG1hV1Z5SWpvaU1qYzNNVEF6TURVNU9Ua2lMQ0ptYzNCSlpDSTZJbWx1TUROMGJqQTFJbjE5TENKd1lYbGxjaUk2ZXlKd1lYSjBlVWxrU1c1bWJ5STZleUp3WVhKMGVVbGtWSGx3WlNJNklrMVRTVk5FVGlJc0luQmhjblI1U1dSbGJuUnBabWxsY2lJNklqSTNOekV3TWpBek9UazVJaXdpWm5Od1NXUWlPaUpwYmpBeWRHNHdNeUo5ZlN3aVlXMXZkVzUwSWpwN0ltTjFjbkpsYm1ONUlqb2lWRnBUSWl3aVlXMXZkVzUwSWpvaU1UTWlmWDA9\",\"condition\":\"JZWzSiP-LkAA7RGhLQXEiu7h_gsnlhuTqhhM1xMrZiM\"}", + "localQuoteResponse": "{\"quoteCode\":\"b6ef57ac-9c56-4a93-93c8-e0cb28de9beb\",\"fspFee\":{\"amount\":1.000000,\"currency\":\"TZS\"},\"transactionCode\":\"a7523176-13b5-449f-bdb1-54b152cde78c\",\"state\":\"ACCEPTED\"}", + "tenantId": "tn03", + "payeeFspId": "in03tn05", + "transactionRequest": "{\n \"clientRefId\": \"ref\",\n \"payer\": {\n \"partyIdInfo\": {\n \"partyIdType\": \"MSISDN\",\n \"partyIdentifier\": \"27710203999\",\n\t\t\t\t\"fspId\" : \"in02tn03\",\n\t\t\t\t\"tenantId\" : \"tn03\"\n }\n },\n \"payee\": {\n \"partyIdInfo\": {\n \"partyIdType\": \"MSISDN\",\n \"partyIdentifier\": \"27710305999\"\n },\n \"merchantClassificationCode\": \"\"\n },\n \"amountType\": \"SEND\",\n \"amount\": {\n \"amount\": 13,\n \"currency\": \"TZS\"\n },\n \"transactionType\": {\n \"scenario\": \"TRANSFER\",\n \"initiator\": \"PAYER\",\n \"initiatorType\": \"CONSUMER\"\n },\n \"note\": \"Demo interoperation merchant payment\",\n \"expiration\": \"2019-12-31T00:00:00.000-01:00\"\n }\n", + "timeoutQuoteRetryCount": 0, + "originDate": 1585043797178, + "transactionId": "a7523176-13b5-449f-bdb1-54b152cde78c", + "isValidUserLookup": true + }, + "workflowInstanceKey": 2251799814338288 + }, + "sourceRecordPosition": 167504036592, + "position": 167504036792, + "recordType": "EVENT", + "valueType": "JOB", + "timestamp": 1585043808289, + "intent": "ACTIVATED", + "rejectionType": "NULL_VAL", + "rejectionReason": "", + "key": 2251799814338347 +} diff --git a/ph-ee-exporter/samples/send-success-to-channel.json b/ph-ee-exporter/samples/send-success-to-channel.json new file mode 100644 index 000000000..8af0087a3 --- /dev/null +++ b/ph-ee-exporter/samples/send-success-to-channel.json @@ -0,0 +1,44 @@ +{ + "partitionId": 1, + "value": { + "type": "send-success-to-channel", + "errorMessage": "", + "deadline": 1585044113241, + "errorCode": "", + "bpmnProcessId": "PaymentTest3", + "workflowKey": 2251799813939136, + "customHeaders": {}, + "worker": "default", + "retries": 3, + "elementId": "Task_0fnxxxc", + "elementInstanceKey": 2251799814338384, + "workflowDefinitionVersion": 3, + "variables": { + "transferResponse-PREPARE": "{\"transferCode\":\"0bb1310b-e522-4c3c-a714-5c4c95a44495\",\"completedTimestamp\":\"2020-03-24T11:56:48\",\"transactionCode\":\"a7523176-13b5-449f-bdb1-54b152cde78c\",\"state\":\"ACCEPTED\"}", + "payerConfirmation": "OK", + "transactionStatus": "200", + "localQuoteResponse": "{\"quoteCode\":\"b6ef57ac-9c56-4a93-93c8-e0cb28de9beb\",\"fspFee\":{\"amount\":1.000000,\"currency\":\"TZS\"},\"transactionCode\":\"a7523176-13b5-449f-bdb1-54b152cde78c\",\"state\":\"ACCEPTED\"}", + "payeeFspId": "in03tn05", + "transactionRequest": "{\n \"clientRefId\": \"ref\",\n \"payer\": {\n \"partyIdInfo\": {\n \"partyIdType\": \"MSISDN\",\n \"partyIdentifier\": \"27710203999\",\n\t\t\t\t\"fspId\" : \"in02tn03\",\n\t\t\t\t\"tenantId\" : \"tn03\"\n }\n },\n \"payee\": {\n \"partyIdInfo\": {\n \"partyIdType\": \"MSISDN\",\n \"partyIdentifier\": \"27710305999\"\n },\n \"merchantClassificationCode\": \"\"\n },\n \"amountType\": \"SEND\",\n \"amount\": {\n \"amount\": 13,\n \"currency\": \"TZS\"\n },\n \"transactionType\": {\n \"scenario\": \"TRANSFER\",\n \"initiator\": \"PAYER\",\n \"initiatorType\": \"CONSUMER\"\n },\n \"note\": \"Demo interoperation merchant payment\",\n \"expiration\": \"2019-12-31T00:00:00.000-01:00\"\n }\n", + "transactionId": "a7523176-13b5-449f-bdb1-54b152cde78c", + "externalAccountId": "9062b90de19b43989005d9", + "quoteResponse": "{\"transferAmount\":{\"amount\":\"13\",\"currency\":\"TZS\"},\"payeeReceiveAmount\":{\"amount\":\"13\",\"currency\":\"TZS\"},\"payeeFspFee\":{\"amount\":\"0\",\"currency\":\"TZS\"},\"payeeFspCommission\":{\"amount\":\"0\",\"currency\":\"TZS\"},\"expiration\":\"2020-03-24T10:56:45.431Z\",\"ilpPacket\":\"AQIxMyBnLnR6LmluMDN0bjA1Lk1TSVNETi4yNzcxMDMwNTk5OYIB0GV5SjBjbUZ1YzJGamRHbHZia2xrSWpvaVlUYzFNak14TnpZdE1UTmlOUzAwTkRsbUxXSmtZakV0TlRSaU1UVXlZMlJsTnpoaklpd2ljWFZ2ZEdWSlpDSTZJbVJtTXpFMU5ETmpMV1UxTm1FdE5ERmhOQzFpWTJaakxUSTRNVGczTlROa01qUmlOQ0lzSW5CaGVXVmxJanA3SW5CaGNuUjVTV1JKYm1adklqcDdJbkJoY25SNVNXUlVlWEJsSWpvaVRWTkpVMFJPSWl3aWNHRnlkSGxKWkdWdWRHbG1hV1Z5SWpvaU1qYzNNVEF6TURVNU9Ua2lMQ0ptYzNCSlpDSTZJbWx1TUROMGJqQTFJbjE5TENKd1lYbGxjaUk2ZXlKd1lYSjBlVWxrU1c1bWJ5STZleUp3WVhKMGVVbGtWSGx3WlNJNklrMVRTVk5FVGlJc0luQmhjblI1U1dSbGJuUnBabWxsY2lJNklqSTNOekV3TWpBek9UazVJaXdpWm5Od1NXUWlPaUpwYmpBeWRHNHdNeUo5ZlN3aVlXMXZkVzUwSWpwN0ltTjFjbkpsYm1ONUlqb2lWRnBUSWl3aVlXMXZkVzUwSWpvaU1UTWlmWDA9\",\"condition\":\"JZWzSiP-LkAA7RGhLQXEiu7h_gsnlhuTqhhM1xMrZiM\"}", + "tenantId": "tn03", + "timeoutQuoteRetryCount": 0, + "originDate": 1585043797178, + "isValidUserLookup": true, + "transferResponse-CREATE": "{\"transferCode\":\"d38b3b71-4126-447b-ba7c-0c5f4ff4419c\",\"completedTimestamp\":\"2020-03-24T11:56:52\",\"transactionCode\":\"a7523176-13b5-449f-bdb1-54b152cde78c\",\"state\":\"ACCEPTED\"}", + "timeoutTransferRetryCount": 0 + }, + "workflowInstanceKey": 2251799814338288 + }, + "sourceRecordPosition": 167504092136, + "position": 167504092336, + "recordType": "EVENT", + "valueType": "JOB", + "timestamp": 1585043813272, + "intent": "ACTIVATED", + "rejectionType": "NULL_VAL", + "rejectionReason": "", + "key": 2251799814338385 +} diff --git a/ph-ee-exporter/samples/transfer-prepare-completed.json b/ph-ee-exporter/samples/transfer-prepare-completed.json new file mode 100644 index 000000000..74e6ead56 --- /dev/null +++ b/ph-ee-exporter/samples/transfer-prepare-completed.json @@ -0,0 +1,42 @@ +{ + "partitionId": 1, + "value": { + "type": "transfer-prepare", + "errorMessage": "", + "deadline": 1585044109428, + "errorCode": "", + "bpmnProcessId": "PaymentTest3", + "workflowKey": 2251799813939136, + "customHeaders": {}, + "worker": "default", + "retries": 3, + "elementId": "Task_0vca3nk", + "elementInstanceKey": 2251799814338364, + "workflowDefinitionVersion": 3, + "variables": { + "transferResponse-PREPARE": "{\"transferCode\":\"0bb1310b-e522-4c3c-a714-5c4c95a44495\",\"completedTimestamp\":\"2020-03-24T11:56:48\",\"transactionCode\":\"a7523176-13b5-449f-bdb1-54b152cde78c\",\"state\":\"ACCEPTED\"}", + "payerConfirmation": "OK", + "localQuoteResponse": "{\"quoteCode\":\"b6ef57ac-9c56-4a93-93c8-e0cb28de9beb\",\"fspFee\":{\"amount\":1.000000,\"currency\":\"TZS\"},\"transactionCode\":\"a7523176-13b5-449f-bdb1-54b152cde78c\",\"state\":\"ACCEPTED\"}", + "payeeFspId": "in03tn05", + "transactionRequest": "{\n \"clientRefId\": \"ref\",\n \"payer\": {\n \"partyIdInfo\": {\n \"partyIdType\": \"MSISDN\",\n \"partyIdentifier\": \"27710203999\",\n\t\t\t\t\"fspId\" : \"in02tn03\",\n\t\t\t\t\"tenantId\" : \"tn03\"\n }\n },\n \"payee\": {\n \"partyIdInfo\": {\n \"partyIdType\": \"MSISDN\",\n \"partyIdentifier\": \"27710305999\"\n },\n \"merchantClassificationCode\": \"\"\n },\n \"amountType\": \"SEND\",\n \"amount\": {\n \"amount\": 13,\n \"currency\": \"TZS\"\n },\n \"transactionType\": {\n \"scenario\": \"TRANSFER\",\n \"initiator\": \"PAYER\",\n \"initiatorType\": \"CONSUMER\"\n },\n \"note\": \"Demo interoperation merchant payment\",\n \"expiration\": \"2019-12-31T00:00:00.000-01:00\"\n }\n", + "transactionId": "a7523176-13b5-449f-bdb1-54b152cde78c", + "externalAccountId": "9062b90de19b43989005d9", + "quoteResponse": "{\"transferAmount\":{\"amount\":\"13\",\"currency\":\"TZS\"},\"payeeReceiveAmount\":{\"amount\":\"13\",\"currency\":\"TZS\"},\"payeeFspFee\":{\"amount\":\"0\",\"currency\":\"TZS\"},\"payeeFspCommission\":{\"amount\":\"0\",\"currency\":\"TZS\"},\"expiration\":\"2020-03-24T10:56:45.431Z\",\"ilpPacket\":\"AQIxMyBnLnR6LmluMDN0bjA1Lk1TSVNETi4yNzcxMDMwNTk5OYIB0GV5SjBjbUZ1YzJGamRHbHZia2xrSWpvaVlUYzFNak14TnpZdE1UTmlOUzAwTkRsbUxXSmtZakV0TlRSaU1UVXlZMlJsTnpoaklpd2ljWFZ2ZEdWSlpDSTZJbVJtTXpFMU5ETmpMV1UxTm1FdE5ERmhOQzFpWTJaakxUSTRNVGczTlROa01qUmlOQ0lzSW5CaGVXVmxJanA3SW5CaGNuUjVTV1JKYm1adklqcDdJbkJoY25SNVNXUlVlWEJsSWpvaVRWTkpVMFJPSWl3aWNHRnlkSGxKWkdWdWRHbG1hV1Z5SWpvaU1qYzNNVEF6TURVNU9Ua2lMQ0ptYzNCSlpDSTZJbWx1TUROMGJqQTFJbjE5TENKd1lYbGxjaUk2ZXlKd1lYSjBlVWxrU1c1bWJ5STZleUp3WVhKMGVVbGtWSGx3WlNJNklrMVRTVk5FVGlJc0luQmhjblI1U1dSbGJuUnBabWxsY2lJNklqSTNOekV3TWpBek9UazVJaXdpWm5Od1NXUWlPaUpwYmpBeWRHNHdNeUo5ZlN3aVlXMXZkVzUwSWpwN0ltTjFjbkpsYm1ONUlqb2lWRnBUSWl3aVlXMXZkVzUwSWpvaU1UTWlmWDA9\",\"condition\":\"JZWzSiP-LkAA7RGhLQXEiu7h_gsnlhuTqhhM1xMrZiM\"}", + "tenantId": "tn03", + "timeoutQuoteRetryCount": 0, + "originDate": 1585043797178, + "isValidUserLookup": true, + "timeoutTransferRetryCount": 0 + }, + "workflowInstanceKey": 2251799814338288 + }, + "sourceRecordPosition": 167504066360, + "position": 167504069192, + "recordType": "EVENT", + "valueType": "JOB", + "timestamp": 1585043809528, + "intent": "COMPLETED", + "rejectionType": "NULL_VAL", + "rejectionReason": "", + "key": 2251799814338365 +} diff --git a/ph-ee-exporter/settings.gradle b/ph-ee-exporter/settings.gradle new file mode 100644 index 000000000..6116af7c7 --- /dev/null +++ b/ph-ee-exporter/settings.gradle @@ -0,0 +1,7 @@ +/* + * This file was generated by the Gradle 'init' task. + * + * This project uses @Incubating APIs which are subject to change. + */ + +rootProject.name = 'exporter' diff --git a/ph-ee-exporter/src/main/java/hu/dpc/rt/kafkastreamer/exporter/KafkaExporter.java b/ph-ee-exporter/src/main/java/hu/dpc/rt/kafkastreamer/exporter/KafkaExporter.java new file mode 100644 index 000000000..a2c0040be --- /dev/null +++ b/ph-ee-exporter/src/main/java/hu/dpc/rt/kafkastreamer/exporter/KafkaExporter.java @@ -0,0 +1,134 @@ +/* + * Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH under + * one or more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Licensed under the Zeebe Community License 1.0. You may not use this file + * except in compliance with the Zeebe Community License 1.0. + */ +package hu.dpc.rt.kafkastreamer.exporter; + +import io.camunda.zeebe.exporter.api.Exporter; +import io.camunda.zeebe.exporter.api.context.Context; +import io.camunda.zeebe.exporter.api.context.Controller; +import io.camunda.zeebe.protocol.record.Record; + +import org.slf4j.Logger; + +import java.time.Duration; +import java.util.Map; + +public class KafkaExporter implements Exporter { + private Logger logger; + private Controller controller; + + private KafkaExporterConfiguration configuration; + + private KafkaExporterClient client; + + private long lastPosition = -1; + + @Override + public void configure(final Context context) { + try { + logger = context.getLogger(); + //logger.info("This is context: " + context.toString()); + configuration = context.getConfiguration().instantiate(KafkaExporterConfiguration.class); + /*Map configs = context.getConfiguration().getArguments(); + for (String key: configs.keySet()) { + logger.info("Config arg: " + key + ":" + configs.get(key)); + }*/ + logger.info("Calling configure"); + logger.info("With context configuration :" + context.getConfiguration()); + logger.info("With context configuration :" + context.getConfiguration().getArguments()); + logger.info("DPC Kafka exporter configured with {}", configuration); + +// context.setFilter(new KafkaRecordFilter(configuration)); + } catch (Exception e) { + logger.error("Failed to configure KafkaExporter", e); + } + } + + @Override + public void open(final Controller controller) { + logger.info("DPC Kafka exporter opening"); + this.controller = controller; + client = createClient(); + scheduleDelayedFlush(); + logger.info("DPC Kafka exporter opened"); + } + + @Override + public void close() { + logger.info("Calling close function"); + try { + flush(); + } catch (final Exception e) { + logger.warn("Failed to flush records before closing exporter.", e); + } + + try { + client.close(); + } catch (final Exception e) { + logger.warn("Failed to close elasticsearch client", e); + } + + logger.info("DPC Kafka exporter closed"); + } + + @Override + public void export(Record record) { + logger.trace("Exporting record " + record); + client.index(record); + lastPosition = record.getPosition(); + + if (client.shouldFlush()) { + flush(); + } + logger.trace("Finish exporting record " + record); + } + + protected KafkaExporterClient createClient() { + return new KafkaExporterClient(configuration, logger); + } + + private void flushAndReschedule() { + logger.info("Calling flushAndReschedule function"); + try { + flush(); + } catch (final Exception e) { + logger.error("Unexpected exception occurred on periodically flushing bulk, will retry later.", e); + } + scheduleDelayedFlush(); + } + + private void scheduleDelayedFlush() { + controller.scheduleCancellableTask(Duration.ofSeconds(configuration.bulk.delay), this::flushAndReschedule); + } + + private void flush() { + logger.info("Calling flush function"); + if (client.flush()) { + controller.updateLastExportedRecordPosition(lastPosition); + } else { + logger.warn("Failed to flush bulk completely"); + } + } + +// public static class KafkaRecordFilter implements Context.RecordFilter { +// private final KafkaExporterConfiguration configuration; +// +// KafkaRecordFilter(final KafkaExporterConfiguration configuration) { +// this.configuration = configuration; +// } +// +// @Override +// public boolean acceptType(final RecordType recordType) { +// return configuration.shouldIndexRecordType(recordType); +// } +// +// @Override +// public boolean acceptValue(final ValueType valueType) { +// return configuration.shouldIndexValueType(valueType); +// } +// } +} diff --git a/ph-ee-exporter/src/main/java/hu/dpc/rt/kafkastreamer/exporter/KafkaExporterClient.java b/ph-ee-exporter/src/main/java/hu/dpc/rt/kafkastreamer/exporter/KafkaExporterClient.java new file mode 100644 index 000000000..fa3c603a0 --- /dev/null +++ b/ph-ee-exporter/src/main/java/hu/dpc/rt/kafkastreamer/exporter/KafkaExporterClient.java @@ -0,0 +1,109 @@ +/* + * Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH under + * one or more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Licensed under the Zeebe Community License 1.0. You may not use this file + * except in compliance with the Zeebe Community License 1.0. + */ +package hu.dpc.rt.kafkastreamer.exporter; + +import io.camunda.zeebe.protocol.record.Record; +import org.apache.kafka.clients.admin.AdminClient; +import org.apache.kafka.clients.admin.NewTopic; +import org.apache.kafka.clients.producer.KafkaProducer; +import org.apache.kafka.clients.producer.ProducerConfig; +import org.apache.kafka.clients.producer.ProducerRecord; +import org.apache.kafka.common.serialization.StringSerializer; +import org.slf4j.Logger; + +import java.text.SimpleDateFormat; +import java.util.*; +import java.util.concurrent.atomic.AtomicLong; + +public class KafkaExporterClient { + private final Logger logger; + private final KafkaExporterConfiguration configuration; + private KafkaExporterMetrics metrics; + private AtomicLong sentToKafka = new AtomicLong(0); + private boolean initialized; + + // json content for now + private KafkaProducer producer; + public static final String kafkaTopic = "zeebe-export"; + + public KafkaExporterClient(final KafkaExporterConfiguration configuration, final Logger logger) { + this.configuration = configuration; + this.logger = logger; + + Map kafkaProperties = new HashMap<>(); + String clientId = buildKafkaClientId(logger); + kafkaProperties.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, "kafka:9092"); + kafkaProperties.put(ProducerConfig.CLIENT_ID_CONFIG, clientId); + kafkaProperties.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class.getName()); + kafkaProperties.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, StringSerializer.class.getName()); + producer = new KafkaProducer<>(kafkaProperties); + + try { + AdminClient adminClient = AdminClient.create(kafkaProperties); + adminClient.createTopics(Arrays.asList(new NewTopic(kafkaTopic, 1, (short) 1))); + adminClient.close(); + logger.info("created kafka topic {} successfully", kafkaTopic); + } catch (Exception e) { + logger.warn("Failed to create Kafka topic (it exists already?)", e); + } + + logger.info("configured Kafka producer with client id {}", clientId); + } + + public static String buildKafkaClientId(Logger logger) { + return UUID.randomUUID().toString(); + } + + public void close() { + producer.close(); + } + + public void index(final Record record) { + if (metrics == null && !initialized) { + try { + metrics = new KafkaExporterMetrics(record.getPartitionId()); + } catch (Exception e) { + logger.warn("## failed to initialize metrics, continuing without it"); + } + initialized = true; + } + + if (configuration.shouldIndexRecord(record)) { + logger.trace("sending record to kafka: {}", record.toJson()); + String jsonString = record.toJson(); + String exportedTime = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZZ").format(new Date()); + jsonString = jsonString.substring(0, jsonString.length() - 1) + + ", \"exportedTime\": \"" + exportedTime + "\"}"; + sentToKafka.incrementAndGet(); + metrics.recordBulkSize(1); + producer.send(new ProducerRecord<>(kafkaTopic, idFor(record), jsonString)); + } else { + logger.trace("skipping record: {}", record.toString()); + } + } + + /** + * @return true if all bulk records where flushed successfully + */ + public boolean flush() { + if (sentToKafka.get() > 0) { + producer.flush(); + logger.info("flushed {} exported records to Kafka", sentToKafka.get()); + sentToKafka.set(0); + } + return true; + } + + public boolean shouldFlush() { + return sentToKafka.get() >= configuration.bulk.size; + } + + protected String idFor(final Record record) { + return record.getPartitionId() + "-" + record.getPosition(); + } +} diff --git a/ph-ee-exporter/src/main/java/hu/dpc/rt/kafkastreamer/exporter/KafkaExporterConfiguration.java b/ph-ee-exporter/src/main/java/hu/dpc/rt/kafkastreamer/exporter/KafkaExporterConfiguration.java new file mode 100644 index 000000000..fe9400471 --- /dev/null +++ b/ph-ee-exporter/src/main/java/hu/dpc/rt/kafkastreamer/exporter/KafkaExporterConfiguration.java @@ -0,0 +1,181 @@ +/* + * Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH under + * one or more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Licensed under the Zeebe Community License 1.0. You may not use this file + * except in compliance with the Zeebe Community License 1.0. + */ +package hu.dpc.rt.kafkastreamer.exporter; + +import io.camunda.zeebe.protocol.record.Record; +import io.camunda.zeebe.protocol.record.RecordType; + +public class KafkaExporterConfiguration { + // elasticsearch http url - not used + public String url = "not used"; + + public final IndexConfiguration index = new IndexConfiguration(); + public final BulkConfiguration bulk = new BulkConfiguration(); + public final AuthenticationConfiguration authentication = new AuthenticationConfiguration(); + + @Override + public String toString() { + return "KafkaExporterConfiguration{" + + "url='" + + url + + '\'' + + ", index=" + + index + + ", bulk=" + + bulk + + ", authentication=" + + authentication + + '}'; + } + + public boolean shouldIndexRecord(final Record record) { + return shouldIndexRecordType(record.getRecordType()) + && shouldIndexValueType(record); + } + + public boolean shouldIndexValueType(final Record record) { + switch (record.getValueType()) { + case DEPLOYMENT: + return index.deployment; + case ERROR: + return index.error; + case INCIDENT: + return index.incident; + case JOB: + return index.job; + case JOB_BATCH: + return index.jobBatch; + case MESSAGE: + return index.message; + case MESSAGE_SUBSCRIPTION: + return index.messageSubscription; + case VARIABLE: + return index.variable; + case VARIABLE_DOCUMENT: + return index.variableDocument; + case PROCESS_INSTANCE: + return index.shouldIndexEventTypeProcessInstance(record); + default: + return false; + } + } + + public boolean shouldIndexRecordType(final RecordType recordType) { + switch (recordType) { + case EVENT: + return index.event; + case COMMAND: + return index.command; + case COMMAND_REJECTION: + return index.rejection; + default: + return false; + } + } + + public static class IndexConfiguration { + // prefix for index and templates + public String prefix = "zeebe-record"; + + // update index template on startup + public boolean createTemplate = true; + + // record types to export + public boolean command = false; + public boolean event = true; + public boolean rejection = false; + + // value types to export + public boolean deployment = true; + public boolean error = true; + public boolean incident = true; + public boolean job = true; + public boolean jobBatch = false; + public boolean message = false; + public boolean messageSubscription = false; + public boolean variable = true; + public boolean variableDocument = true; + public boolean workflowInstance = true; + public boolean workflowInstanceCreation = false; + public boolean workflowInstanceSubscription = false; +// public boolean processInstance = true; + + public boolean shouldIndexEventTypeProcessInstance(final Record record) { + String intent = record.getIntent().toString(); + if(intent.equals("ELEMENT_ACTIVATED") || intent.equals("ELEMENT_COMPLETING") || intent.equals("SEQUENCE_FLOW_TAKEN")) { + return false; + } + return true; + } + + @Override + public String toString() { + return "IndexConfiguration{" + + "indexPrefix='" + + prefix + + '\'' + + ", createTemplate=" + + createTemplate + + ", command=" + + command + + ", event=" + + event + + ", rejection=" + + rejection + + ", error=" + + error + + ", deployment=" + + deployment + + ", incident=" + + incident + + ", job=" + + job + + ", message=" + + message + + ", messageSubscription=" + + messageSubscription + + ", variable=" + + variable + + ", variableDocument=" + + variableDocument + + ", workflowInstance=" + + workflowInstance + + ", workflowInstanceCreation=" + + workflowInstanceCreation + + ", workflowInstanceSubscription=" + + workflowInstanceSubscription + + '}'; + } + } + + public static class BulkConfiguration { + // delay before forced flush + public int delay = 5; + // bulk size before flush + public int size = 1_000; + + @Override + public String toString() { + return "BulkConfiguration{" + "delay=" + delay + ", size=" + size + '}'; + } + } + + public static class AuthenticationConfiguration { + public String username; + public String password; + + public boolean isPresent() { + return (username != null && !username.isEmpty()) && (password != null && !password.isEmpty()); + } + + @Override + public String toString() { + return "AuthenticationConfiguration{" + "username='" + username + '\'' + '}'; + } + } +} diff --git a/ph-ee-exporter/src/main/java/hu/dpc/rt/kafkastreamer/exporter/KafkaExporterException.java b/ph-ee-exporter/src/main/java/hu/dpc/rt/kafkastreamer/exporter/KafkaExporterException.java new file mode 100644 index 000000000..3cced09de --- /dev/null +++ b/ph-ee-exporter/src/main/java/hu/dpc/rt/kafkastreamer/exporter/KafkaExporterException.java @@ -0,0 +1,19 @@ +/* + * Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH under + * one or more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Licensed under the Zeebe Community License 1.0. You may not use this file + * except in compliance with the Zeebe Community License 1.0. + */ +package hu.dpc.rt.kafkastreamer.exporter; + +public class KafkaExporterException extends RuntimeException { + + public KafkaExporterException(final String message) { + super(message); + } + + public KafkaExporterException(final String message, final Throwable cause) { + super(message, cause); + } +} diff --git a/ph-ee-exporter/src/main/java/hu/dpc/rt/kafkastreamer/exporter/KafkaExporterMetrics.java b/ph-ee-exporter/src/main/java/hu/dpc/rt/kafkastreamer/exporter/KafkaExporterMetrics.java new file mode 100644 index 000000000..5179c3189 --- /dev/null +++ b/ph-ee-exporter/src/main/java/hu/dpc/rt/kafkastreamer/exporter/KafkaExporterMetrics.java @@ -0,0 +1,47 @@ +/* + * Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH under + * one or more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Licensed under the Zeebe Community License 1.0. You may not use this file + * except in compliance with the Zeebe Community License 1.0. + */ +package hu.dpc.rt.kafkastreamer.exporter; + +import io.prometheus.client.Histogram; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class KafkaExporterMetrics { + private static Logger logger = LoggerFactory.getLogger(KafkaExporterMetrics.class); + + private static final Histogram FLUSH_DURATION = + Histogram.build() + .namespace("phee_exporter_" + KafkaExporterClient.buildKafkaClientId(logger).replaceAll("-", "_")) + .name("flush_duration_seconds") + .help("Flush duration of bulk exporters in seconds") + .labelNames("partition") + .register(); + + private static final Histogram BULK_SIZE = + Histogram.build() + .namespace("phee_exporter_" + KafkaExporterClient.buildKafkaClientId(logger).replaceAll("-", "_")) + .name("bulk_size") + .help("Exporter bulk size") + .buckets(10, 100, 1_000, 10_000, 100_000) + .labelNames("partition") + .register(); + + private final String partitionIdLabel; + + public KafkaExporterMetrics(final int partitionId) { + this.partitionIdLabel = String.valueOf(partitionId); + } + + public Histogram.Timer measureFlushDuration() { + return FLUSH_DURATION.labels(partitionIdLabel).startTimer(); + } + + public void recordBulkSize(final int bulkSize) { + BULK_SIZE.labels(partitionIdLabel).observe(bulkSize); + } +} diff --git a/ph-ee-exporter/src/main/java/hu/dpc/rt/kafkastreamer/exporter/NoOpExporter.java b/ph-ee-exporter/src/main/java/hu/dpc/rt/kafkastreamer/exporter/NoOpExporter.java new file mode 100644 index 000000000..bb46c9450 --- /dev/null +++ b/ph-ee-exporter/src/main/java/hu/dpc/rt/kafkastreamer/exporter/NoOpExporter.java @@ -0,0 +1,32 @@ +package hu.dpc.rt.kafkastreamer.exporter; + +import io.camunda.zeebe.exporter.api.Exporter; +import io.camunda.zeebe.exporter.api.context.Context; +import io.camunda.zeebe.exporter.api.context.Controller; +import io.camunda.zeebe.protocol.record.Record; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class NoOpExporter implements Exporter { + private Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Override + public void configure(Context context) throws Exception { + logger.info("## no-op exporter configured"); + } + + @Override + public void open(Controller controller) { + logger.info("## no-op exporter opened"); + } + + @Override + public void close() { + logger.info("## no-op exporter closed"); + } + + @Override + public void export(Record record) { + // empty + } +} diff --git a/ph-ee-exporter/src/main/resources/application.yaml b/ph-ee-exporter/src/main/resources/application.yaml new file mode 100644 index 000000000..e69de29bb diff --git a/ph-ee-id-account-validator-impl/.gitignore b/ph-ee-id-account-validator-impl/.gitignore new file mode 100644 index 000000000..c2065bc26 --- /dev/null +++ b/ph-ee-id-account-validator-impl/.gitignore @@ -0,0 +1,37 @@ +HELP.md +.gradle +build/ +!gradle/wrapper/gradle-wrapper.jar +!**/src/main/**/build/ +!**/src/test/**/build/ + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache +bin/ +!**/src/main/**/bin/ +!**/src/test/**/bin/ + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr +out/ +!**/src/main/**/out/ +!**/src/test/**/out/ + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ + +### VS Code ### +.vscode/ diff --git a/ph-ee-id-account-validator-impl/README.md b/ph-ee-id-account-validator-impl/README.md new file mode 100644 index 000000000..c8cd8b6f7 --- /dev/null +++ b/ph-ee-id-account-validator-impl/README.md @@ -0,0 +1,5 @@ +# ph-ee-id-account-validator-impl +account validator implementations for PHEE Id mapper. This repo contains the implemntation for gsma and mojaloop account validation which will be used as a dependency in Identity Account Mapper. + +To upload the jar file for this project to Artifactory, use the artifactoryPublish Gradle task. +The jar file can be built with either the GSMA or Mojaloop implementation by using the ./gradlew jar -Dimplementation= command. The implementation parameter must be set to either gsma or mojaloop. \ No newline at end of file diff --git a/ph-ee-id-account-validator-impl/build.gradle b/ph-ee-id-account-validator-impl/build.gradle new file mode 100644 index 000000000..3f01c99d0 --- /dev/null +++ b/ph-ee-id-account-validator-impl/build.gradle @@ -0,0 +1,94 @@ +plugins { + id 'java' + id 'org.springframework.boot' version '2.7.10' + id 'io.spring.dependency-management' version '1.0.15.RELEASE' + id 'eclipse' + id 'maven-publish' + id "com.jfrog.artifactory" version "4.24.23" +} + +group = 'org.mifos' +version = '0.0.1-SNAPSHOT' +sourceCompatibility = '17' +def artifactId = 'account-conncetor-validation-impl' +def versionNumber = version + +repositories { + mavenCentral() + maven { + url = uri('https://jfrog.sandbox.fynarfin.io/artifactory/fyn-libs-snapshot') + } +} + +dependencies { + implementation 'org.springframework.boot:spring-boot-starter' + testImplementation 'org.springframework.boot:spring-boot-starter-test' + implementation 'io.rest-assured:rest-assured:4.4.0' + implementation 'com.fasterxml.jackson.core:jackson-databind:2.12.5' + implementation 'io.camunda:zeebe-client-java:1.3.1' + implementation 'org.mifos:ph-ee-connector-common:1.4.0-SNAPSHOT' +} + +tasks.named('test') { + useJUnitPlatform() +} + +sourceSets { + main { + java { + // Include all source files by default + srcDirs = ['src/main/java'] + + // Exclude the package if a system property is set + if (System.getProperty('gsma')) { + exclude 'org/mifos/pheeidmaapperaccountvalidatorimp/mojaloopconnector/**' + } + else if(System.getProperty('mojaloop')){ + exclude 'org/mifos/accountvalidatorconnector/gsmaconnector/**' + + } + } + } +} + +jar { + // Set the archive name based on the condition + if (System.getProperty('gsma')) { + archiveFileName = "account-validator-connector-gsma-${project.version}.jar" + } + else if (System.getProperty('mojaloop')) { + archiveFileName = "account-validator-connector-mojaloop-${project.version}.jar" + } +} +publishing { + publications { + mavenJava(MavenPublication) { + from(components.java) + } + } +} +tasks.withType(JavaCompile) { + options.encoding = 'UTF-8' +} + +artifactory { + contextUrl = 'https://jfrog.sandbox.fynarfin.io/artifactory' // base artifactory url + publish { + repository { + repoKey = 'fyn-libs-snapshot' //Artifactory repository key to publish to + //username = 'avik@fynarfin.io' //publisher user name + //password = '****' //publisher password + username = gradle.app_username + password = gradle.app_password + maven = true + } + defaults { + publications('mavenJava') + } + } + +} + +artifactoryPublish { + dependsOn jar +} diff --git a/ph-ee-id-account-validator-impl/gradle/wrapper/gradle-wrapper.jar b/ph-ee-id-account-validator-impl/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 000000000..249e5832f Binary files /dev/null and b/ph-ee-id-account-validator-impl/gradle/wrapper/gradle-wrapper.jar differ diff --git a/ph-ee-id-account-validator-impl/gradle/wrapper/gradle-wrapper.properties b/ph-ee-id-account-validator-impl/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 000000000..774fae876 --- /dev/null +++ b/ph-ee-id-account-validator-impl/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.1-bin.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/ph-ee-id-account-validator-impl/gradlew b/ph-ee-id-account-validator-impl/gradlew new file mode 100755 index 000000000..a69d9cb6c --- /dev/null +++ b/ph-ee-id-account-validator-impl/gradlew @@ -0,0 +1,240 @@ +#!/bin/sh + +# +# Copyright © 2015-2021 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit + +APP_NAME="Gradle" +APP_BASE_NAME=${0##*/} + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/ph-ee-id-account-validator-impl/gradlew.bat b/ph-ee-id-account-validator-impl/gradlew.bat new file mode 100644 index 000000000..53a6b238d --- /dev/null +++ b/ph-ee-id-account-validator-impl/gradlew.bat @@ -0,0 +1,91 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 0 goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/ph-ee-id-account-validator-impl/settings.gradle b/ph-ee-id-account-validator-impl/settings.gradle new file mode 100644 index 000000000..e683dee35 --- /dev/null +++ b/ph-ee-id-account-validator-impl/settings.gradle @@ -0,0 +1,5 @@ +rootProject.name = 'ph-ee-id-account-validator-impl' +gradle.ext{ + app_username = '' + app_password = '' +} diff --git a/ph-ee-id-account-validator-impl/src/main/java/org/mifos/pheeidaccountvalidatorimpl/PhEeIdMaapperAccountValidatorImplApplication.java b/ph-ee-id-account-validator-impl/src/main/java/org/mifos/pheeidaccountvalidatorimpl/PhEeIdMaapperAccountValidatorImplApplication.java new file mode 100644 index 000000000..19a4d9216 --- /dev/null +++ b/ph-ee-id-account-validator-impl/src/main/java/org/mifos/pheeidaccountvalidatorimpl/PhEeIdMaapperAccountValidatorImplApplication.java @@ -0,0 +1,13 @@ +package org.mifos.pheeidaccountvalidatorimpl; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class PhEeIdMaapperAccountValidatorImplApplication { + + public static void main(String[] args) { + SpringApplication.run(PhEeIdMaapperAccountValidatorImplApplication.class, args); + } + +} diff --git a/ph-ee-id-account-validator-impl/src/main/java/org/mifos/pheeidaccountvalidatorimpl/gsmaconnector/GSMAAccountValidation.java b/ph-ee-id-account-validator-impl/src/main/java/org/mifos/pheeidaccountvalidatorimpl/gsmaconnector/GSMAAccountValidation.java new file mode 100644 index 000000000..6548a858d --- /dev/null +++ b/ph-ee-id-account-validator-impl/src/main/java/org/mifos/pheeidaccountvalidatorimpl/gsmaconnector/GSMAAccountValidation.java @@ -0,0 +1,56 @@ +package org.mifos.pheeidaccountvalidatorimpl.gsmaconnector; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import io.restassured.RestAssured; +import io.restassured.builder.RequestSpecBuilder; +import io.restassured.response.Response; +import io.restassured.specification.RequestSpecification; +import org.mifos.pheeidaccountvalidatorimpl.service.AccountValidationService; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; + +import java.util.Map; + +@Service(value = "gsma") +public class GSMAAccountValidation extends AccountValidationService { + @Value("${gsma-connector.contactpoint}") + public String gsmaConnectorContactPoint; + @Value("${gsma-connector.endpoint.account-status}") + public String accountStatusEndpoint; + @Override + public Boolean validateAccount(String financialAddress, String tenant, String paymentModality, String payeeIdentity, String callbackURL){ + accountStatusEndpoint = accountStatusEndpoint.replaceAll("identifierType", paymentModality); + accountStatusEndpoint = accountStatusEndpoint.replaceAll("identifierId", financialAddress); + RequestSpecification requestSpec = new RequestSpecBuilder().build(); + requestSpec.relaxedHTTPSValidation(); + + Response response = RestAssured.given(requestSpec) + .baseUri(gsmaConnectorContactPoint) + .header("Platform-TenantId", tenant) + .when() + .get(accountStatusEndpoint) + .andReturn(); + Integer statusCode = response.then().extract().statusCode(); + String responseBody = response.then().extract().body().asString(); + ObjectMapper objectMapper = new ObjectMapper(); + Map responseMap = null; + try { + responseMap = objectMapper.readValue(responseBody, Map.class); + } catch (JsonProcessingException e) { + throw new RuntimeException(e); + } + +// Extract the value of the "fieldName" field + String fieldValue = responseMap.get("fieldName").toString(); + if(!statusCode.equals(200)) { + return false; + } else if(statusCode.equals(200) && responseMap.get("accountStatus").equals("savingsAccountStatusType.active")){ + return true; + } + else { + return false; + } + } +} + diff --git a/ph-ee-id-account-validator-impl/src/main/java/org/mifos/pheeidaccountvalidatorimpl/mojaloopconnector/MojaloopAccountValidation.java b/ph-ee-id-account-validator-impl/src/main/java/org/mifos/pheeidaccountvalidatorimpl/mojaloopconnector/MojaloopAccountValidation.java new file mode 100644 index 000000000..68fe46930 --- /dev/null +++ b/ph-ee-id-account-validator-impl/src/main/java/org/mifos/pheeidaccountvalidatorimpl/mojaloopconnector/MojaloopAccountValidation.java @@ -0,0 +1,60 @@ +package org.mifos.pheeidaccountvalidatorimpl.mojaloopconnector; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.mifos.connector.common.channel.dto.TransactionChannelRequestDTO; +import org.mifos.connector.common.mojaloop.dto.Party; +import org.mifos.connector.common.mojaloop.dto.PartyIdInfo; +import org.mifos.connector.common.mojaloop.dto.TransactionType; +import org.mifos.connector.common.mojaloop.type.IdentifierType; +import org.mifos.pheeidaccountvalidatorimpl.service.AccountValidationService; +import org.mifos.pheeidaccountvalidatorimpl.zeebe.ZeebeProcessStarter; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.HashMap; +import java.util.Map; + +import static org.mifos.connector.common.mojaloop.type.InitiatorType.CONSUMER; +import static org.mifos.connector.common.mojaloop.type.Scenario.TRANSFER; +import static org.mifos.connector.common.mojaloop.type.TransactionRole.PAYEE; +import static org.mifos.pheeidaccountvalidatorimpl.zeebe.ZeebeVariables.*; + +@Service(value = "mojaloop") +public class MojaloopAccountValidation extends AccountValidationService { + @Autowired + private ZeebeProcessStarter zeebeProcessStarter; + private ObjectMapper objectMapper; + @Override + public Boolean validateAccount(String financialAddress, String fsp, String paymentModality, String payeeIdentity, String callbackURL) { + Map extraVariables = new HashMap<>(); + extraVariables.put("payeeIdentity", payeeIdentity); + TransactionType transactionType = new TransactionType(); + transactionType.setInitiator(PAYEE); + transactionType.setInitiatorType(CONSUMER); + transactionType.setScenario(TRANSFER); + extraVariables.put("initiator", transactionType.getInitiator().name()); + extraVariables.put("initiatorType", transactionType.getInitiatorType().name()); + extraVariables.put("scenario", transactionType.getScenario().name()); + + extraVariables.put(IS_RTP_REQUEST, true); + extraVariables.put(IS_AUTHORISATION_REQUIRED, false); + extraVariables.put(AUTH_TYPE, "NONE"); + extraVariables.put("payeeIdentity", payeeIdentity); + extraVariables.put("callbackURL",callbackURL); + TransactionChannelRequestDTO transactionChannelRequestDTO = new TransactionChannelRequestDTO(); + Party party = new Party(); + PartyIdInfo partyIdInfo = new PartyIdInfo(IdentifierType.MSISDN, financialAddress); + party.setPartyIdInfo(partyIdInfo); + transactionChannelRequestDTO.setPayer(party); + try { + String transactionId = zeebeProcessStarter.startZeebeWorkflow("mojaloop-account-validation", + objectMapper.writeValueAsString(transactionChannelRequestDTO), + extraVariables); + } catch (JsonProcessingException e) { + throw new RuntimeException(e); + } + return null; + } + +} diff --git a/ph-ee-id-account-validator-impl/src/main/java/org/mifos/pheeidaccountvalidatorimpl/service/AccountValidationService.java b/ph-ee-id-account-validator-impl/src/main/java/org/mifos/pheeidaccountvalidatorimpl/service/AccountValidationService.java new file mode 100644 index 000000000..59376dedd --- /dev/null +++ b/ph-ee-id-account-validator-impl/src/main/java/org/mifos/pheeidaccountvalidatorimpl/service/AccountValidationService.java @@ -0,0 +1,6 @@ +package org.mifos.pheeidaccountvalidatorimpl.service; + +public abstract class AccountValidationService { + public abstract Boolean validateAccount(String financialAddress, String dspId, String paymentModality, String payeeIdentity, String callbackURL); + +} diff --git a/ph-ee-id-account-validator-impl/src/main/java/org/mifos/pheeidaccountvalidatorimpl/zeebe/ZeebeProcessStarter.java b/ph-ee-id-account-validator-impl/src/main/java/org/mifos/pheeidaccountvalidatorimpl/zeebe/ZeebeProcessStarter.java new file mode 100644 index 000000000..e39785884 --- /dev/null +++ b/ph-ee-id-account-validator-impl/src/main/java/org/mifos/pheeidaccountvalidatorimpl/zeebe/ZeebeProcessStarter.java @@ -0,0 +1,45 @@ +package org.mifos.pheeidaccountvalidatorimpl.zeebe; + +import io.camunda.zeebe.client.ZeebeClient; +import io.camunda.zeebe.client.api.response.ProcessInstanceEvent; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; + +import java.time.Instant; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + + +@Component +public class ZeebeProcessStarter { + private static Logger logger = LoggerFactory.getLogger(ZeebeProcessStarter.class); + + private ZeebeClient zeebeClient; + public String startZeebeWorkflow(String workflowId, String request, Map extraVariables) { + String transactionId = generateTransactionId(); + + Map variables = new HashMap<>(); + variables.put(ZeebeVariables.TRANSACTION_ID, transactionId); + variables.put(ZeebeVariables.ORIGIN_DATE, Instant.now().toEpochMilli()); + if (extraVariables != null) { + variables.putAll(extraVariables); + } + + logger.info("starting workflow HERE:"); + // TODO if successful transfer response arrives in X timeout return it otherwise do callback + ProcessInstanceEvent instance = zeebeClient.newCreateInstanceCommand() + .bpmnProcessId(workflowId) + .latestVersion() + .variables(variables) + .send() + .join(); + + logger.info("zeebee workflow instance from process {} started with transactionId {}, instance key: {}", workflowId, transactionId, instance.getProcessInstanceKey()); + return transactionId; + } + private String generateTransactionId() { + return UUID.randomUUID().toString(); + } +} diff --git a/ph-ee-id-account-validator-impl/src/main/java/org/mifos/pheeidaccountvalidatorimpl/zeebe/ZeebeVariables.java b/ph-ee-id-account-validator-impl/src/main/java/org/mifos/pheeidaccountvalidatorimpl/zeebe/ZeebeVariables.java new file mode 100644 index 000000000..6b3536143 --- /dev/null +++ b/ph-ee-id-account-validator-impl/src/main/java/org/mifos/pheeidaccountvalidatorimpl/zeebe/ZeebeVariables.java @@ -0,0 +1,13 @@ +package org.mifos.pheeidaccountvalidatorimpl.zeebe; + +public class ZeebeVariables { + private ZeebeVariables() { + } + public static final String ORIGIN_DATE = "originDate"; + public static final String CHANNEL_REQUEST = "channelRequest"; + public static final String TRANSACTION_ID = "transactionId"; + public static final String IS_RTP_REQUEST = "isRtpRequest"; + public static final String IS_AUTHORISATION_REQUIRED = "isAuthorisationRequired"; + public static final String AUTH_TYPE = "authType"; + +} diff --git a/ph-ee-id-account-validator-impl/src/main/resources/application.yml b/ph-ee-id-account-validator-impl/src/main/resources/application.yml new file mode 100644 index 000000000..35ff85651 --- /dev/null +++ b/ph-ee-id-account-validator-impl/src/main/resources/application.yml @@ -0,0 +1,4 @@ +gsma-connector: + contactpoint: "amsmifos.sandbox.fynarfin.io" + endpoint: + account-status: "/ams/accounts/identifierType/identifierId/status" diff --git a/ph-ee-id-account-validator-impl/src/test/java/org/mifos/pheeidmaapperaccountvalidatorimpl/PhEeIdMaapperAccountValidatorImplApplicationTests.java b/ph-ee-id-account-validator-impl/src/test/java/org/mifos/pheeidmaapperaccountvalidatorimpl/PhEeIdMaapperAccountValidatorImplApplicationTests.java new file mode 100644 index 000000000..54c227465 --- /dev/null +++ b/ph-ee-id-account-validator-impl/src/test/java/org/mifos/pheeidmaapperaccountvalidatorimpl/PhEeIdMaapperAccountValidatorImplApplicationTests.java @@ -0,0 +1,9 @@ +package org.mifos.pheeidmaapperaccountvalidatorimpl; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +class PhEeIdMaapperAccountValidatorImplApplicationTests { + +} diff --git a/ph-ee-identity-account-mapper/.circleci/config.yml b/ph-ee-identity-account-mapper/.circleci/config.yml new file mode 100644 index 000000000..a403162cc --- /dev/null +++ b/ph-ee-identity-account-mapper/.circleci/config.yml @@ -0,0 +1,139 @@ +version: 2.1 +orbs: + slack: circleci/slack@4.12.5 + aws-ecr: circleci/aws-ecr@8.2.1 +executors: + docker-executor: + docker: + - image: circleci/openjdk:17-buster-node-browsers-legacy +jobs: + build: + docker: + - image: cimg/openjdk:17.0.0 + - image: docker:17.05.0-ce-git + working_directory: ~/repo + environment: + # Customize the JVM maximum heap limit + JVM_OPTS: -Xmx512m + TERM: dumb + steps: + - checkout + - setup_remote_docker +# - slack/notify: +# event: fail +# mentions: '@here' +# template: basic_fail_1 +# - slack/notify: +# event: pass +# template: basic_success_1 + - run: ./gradlew clean bootJar + - aws-ecr/build-and-push-image: + aws-access-key-id: AWS_ACCESS_KEY_ID + aws-secret-access-key: AWS_SECRET_ACCESS_KEY + extra-build-args: '--compress' + push-image: true + region: ap-south-1 + registry-id: AWS_REGISTRY_ID + repo: ph-ee-identity-account-mapper + repo-scan-on-push: true + role-arn: arn:aws:iam::419830066942:role/CustomAdmin + tag: latest + # - run: ./gradlew cucumberCli + # run tests! Slack Success/Fail Notification Step + #- run: ./gradlew test + + build_and_push_tag_image: + executor: docker-executor + environment: + JVM_OPTS: -Xmx512m + TERM: dumb + GITHUB_TOKEN: ${GITHUB_TOKEN} # Add the GitHub token as an environment variable + + steps: + - checkout + - setup_remote_docker: + version: 20.10.24 + - run: + name: Build and Push Docker tag Image + command: | + # Set environment variables + IMAGE_TAG=$CIRCLE_TAG + + # Check if the Docker image with the same tag already exists in Docker Hub + if curl -s -f -u "$DOCKERHUB_USERNAME":"$DOCKERHUB_PASSWORD" "https://hub.docker.com/v2/repositories/fynarfin/ph-ee-identity-account-mapper/tags/$IMAGE_TAG" > /dev/null; then + echo "Skipping the build and push as the tag $IMAGE_TAG already exists in Docker Hub." + exit 0 + fi + + # Build and tag the Docker image + ./gradlew bootJar + docker build -t "fynarfin/ph-ee-identity-account-mapper:$IMAGE_TAG" . + + # Push the Docker image to Docker Hub + docker login -u "$DOCKERHUB_USERNAME" -p "$DOCKERHUB_PASSWORD" + docker push "fynarfin/ph-ee-identity-account-mapper:$IMAGE_TAG" + + # when: always # The job will be executed even if there's no match for the tag filter + + build_and_push_latest_image: + executor: docker-executor + environment: + JVM_OPTS: -Xmx512m + TERM: dumb + + steps: + - checkout + # Install Docker to build and push the image + - setup_remote_docker: + version: 20.10.24 + + # Build the Docker image + - run: + name: Build Docker image + command: | + ./gradlew checkstyleMain + ./gradlew bootJar + docker build -t fynarfin/ph-ee-identity-account-mapper:latest . + if [ "$CIRCLE_BRANCH" != "develop" ]; then + PR_NUMBER=$(basename $CIRCLE_PULL_REQUEST) + PR_TITLE=$(curl -sSL "https://api.github.com/repos/fynarfin/$CIRCLE_PR_REPONAME/pulls/$PR_NUMBER" | jq -r '.title') + JIRA_STORY=$(echo $PR_TITLE | cut -d "[" -f2 | cut -d "]" -f1 | tr '[A-Z]' '[a-z]') + if [ -z "$JIRA_STORY" ]; then echo "Invalid PR title" && exit 1; else echo "Ticket NO: $JIRA_STORY"; fi + docker image tag fynarfin/$CIRCLE_PR_REPONAME:latest fynarfin/$CIRCLE_PR_REPONAME:$JIRA_STORY + fi + + # Log in to DockerHub using environment variables + - run: + name: Login to DockerHub + command: echo "${DOCKERHUB_PASSWORD}" | docker login -u "${DOCKERHUB_USERNAME}" --password-stdin + + # Push the Docker image to DockerHub + - run: + name: Push Docker image to DockerHub + command: | + if [ "$CIRCLE_BRANCH" = "develop" ]; then + docker push fynarfin/ph-ee-identity-account-mapper:latest + fi + if [ "$CIRCLE_BRANCH" != "develop" ]; then + PR_NUMBER=$(basename $CIRCLE_PULL_REQUEST) + PR_TITLE=$(curl -sSL "https://api.github.com/repos/fynarfin/$CIRCLE_PR_REPONAME/pulls/$PR_NUMBER" | jq -r '.title') + JIRA_STORY=$(echo $PR_TITLE | cut -d "[" -f2 | cut -d "]" -f1 | tr '[A-Z]' '[a-z]') + docker push fynarfin/$CIRCLE_PR_REPONAME:${JIRA_STORY} + fi + +workflows: + build_and_push_image: + jobs: + - build: + context: + - AWS + - slack + - build_and_push_tag_image: + filters: + tags: + only: /^v\d+\.\d+\.\d+$/ # Match tags in the format v1.2.3 + context: + - DOCKER + - build_and_push_latest_image: + context: + - DOCKER diff --git a/ph-ee-identity-account-mapper/.github/pull_request_template.md b/ph-ee-identity-account-mapper/.github/pull_request_template.md new file mode 100644 index 000000000..1d44d4817 --- /dev/null +++ b/ph-ee-identity-account-mapper/.github/pull_request_template.md @@ -0,0 +1,22 @@ +## Description + +* PR title should have jira ticket enclosed in `[]`.
+ Format: ``` [jira_ticket] description```
+ ex: [phee-123] PR title. +* Add a link to the Jira ticket. +* Describe the changes made and why they were made. + +## Checklist + +Please make sure these boxes are checked before submitting your pull request - thanks! +- [ ] Followed the PR title naming convention mentioned above. + +- [ ] Design related bullet points or design document link related to this PR added in the description above. + +- [ ] Updated corresponding Postman Collection or Api documentation for the changes in this PR. + +- [ ] Create/update unit or integration tests for verifying the changes made. + +- [ ] Add required Swagger annotation and update API documentation with details of any API changes if applicable + +- [ ] Followed the naming conventions as given in https://docs.google.com/document/d/1Q4vaMSzrTxxh9TS0RILuNkSkYCxotuYk1Xe0CMIkkCU/edit?usp=sharing diff --git a/ph-ee-identity-account-mapper/.gitignore b/ph-ee-identity-account-mapper/.gitignore new file mode 100644 index 000000000..c2065bc26 --- /dev/null +++ b/ph-ee-identity-account-mapper/.gitignore @@ -0,0 +1,37 @@ +HELP.md +.gradle +build/ +!gradle/wrapper/gradle-wrapper.jar +!**/src/main/**/build/ +!**/src/test/**/build/ + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache +bin/ +!**/src/main/**/bin/ +!**/src/test/**/bin/ + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr +out/ +!**/src/main/**/out/ +!**/src/test/**/out/ + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ + +### VS Code ### +.vscode/ diff --git a/ph-ee-identity-account-mapper/Dockerfile b/ph-ee-identity-account-mapper/Dockerfile new file mode 100644 index 000000000..6b3cbf734 --- /dev/null +++ b/ph-ee-identity-account-mapper/Dockerfile @@ -0,0 +1,5 @@ +FROM openjdk:17-bullseye +EXPOSE 8080 + +COPY build/libs/*.jar . +CMD java -jar *.jar \ No newline at end of file diff --git a/ph-ee-identity-account-mapper/README.md b/ph-ee-identity-account-mapper/README.md new file mode 100644 index 000000000..3b58397ae --- /dev/null +++ b/ph-ee-identity-account-mapper/README.md @@ -0,0 +1,13 @@ +# ph-ee-identity-account-mapper + +## Spotless +Use below command to execute the spotless apply. +```shell +./gradlew spotlessApply +``` + +## Checkstyle +Use below command to execute the checkstyle test. +```shell +./gradlew checkstyleMain +``` diff --git a/ph-ee-identity-account-mapper/build.gradle b/ph-ee-identity-account-mapper/build.gradle new file mode 100644 index 000000000..54c4e30f5 --- /dev/null +++ b/ph-ee-identity-account-mapper/build.gradle @@ -0,0 +1,287 @@ +plugins { + id 'java' + id 'org.springframework.boot' version '2.5.5' + id 'io.spring.dependency-management' version '1.1.0' + id 'idea' + id "org.springdoc.openapi-gradle-plugin" version "1.6.0" + id 'eclipse' + id 'checkstyle' + id 'com.diffplug.spotless' version '6.19.0' + id 'net.ltgt.errorprone' version '3.1.0' +} + +group = 'org.mifos' +version = '0.0.1-SNAPSHOT' +sourceCompatibility = '17' + +repositories { + mavenCentral() + maven { url "https://repo.spring.io/libs-release" } + maven { url "https://repository.jboss.org/nexus/content/repositories/releases" } + maven { url "https://jfrog.sandbox.fynarfin.io/artifactory/fyn-libs-snapshot"} + maven { + url = uri('https://jfrog.sandbox.fynarfin.io/artifactory/fyn-libs-snapshot') + } +} +ext { + zeebClientVersion = '8.1.23' +} + +ext { + springBootVersion = '2.6.2' +} +dependencies { + implementation 'org.springframework.boot:spring-boot-starter' + testImplementation 'org.springframework.boot:spring-boot-starter-test' + implementation("org.springframework.boot:spring-boot-starter-web:2.5.5") + implementation "org.springframework.boot:spring-boot-starter-actuator:$springBootVersion" + implementation("org.springframework.boot:spring-boot-starter-data-jpa:2.5.2") + implementation("org.flywaydb:flyway-core:7.0.4") + implementation 'org.mifos:ph-ee-connector-common:1.8.1-SNAPSHOT' + implementation 'org.eclipse.persistence:org.eclipse.persistence.jpa:2.7.6' + implementation 'javax.annotation:javax.annotation-api:1.3.2' + implementation 'mysql:mysql-connector-java' + implementation 'com.zaxxer:HikariCP' + implementation('io.rest-assured:rest-assured:4.4.0') + implementation "org.springdoc:springdoc-openapi-ui:1.6.11" + implementation 'org.projectlombok:lombok:1.18.20' + annotationProcessor 'org.projectlombok:lombok:1.18.20' + implementation 'com.fasterxml.jackson.core:jackson-databind:2.12.5' + implementation 'org.springframework.boot:spring-boot-starter-cache:2.7.2' + implementation 'javax.cache:cache-api:1.1.1' + implementation 'org.mifos:ph-ee-id-account-validator-impl:0.0.6-SNAPSHOT' + implementation("io.camunda:zeebe-client-java:$zeebClientVersion") + implementation 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.7.9' + implementation("io.camunda:zeebe-client-java:$zeebClientVersion") + implementation 'net.sf.ehcache:ehcache:2.10.6' +} + +tasks.named('test') { + useJUnitPlatform() +} +openApi { + apiDocsUrl.set("http://localhost:8080/v3/api-docs") + outputDir.set(file("src/main/java/docs")) + outputFileName.set("swagger.yaml") +} + +apply plugin:'com.diffplug.spotless' +spotless { + format 'misc', { + target '**/*.md', '**/*.properties', '**/.gitignore', '**/.openapi-generator-ignore', '**/*.yml', '**/*.xml', '**/**.json', '**/*.sql' + targetExclude '**/build/**', '**/bin/**', '**/.settings/**', '**/.idea/**', '**/.gradle/**', '**/gradlew.bat', '**/licenses/**', '**/banner.txt', '.vscode/**' + indentWithSpaces(4) + endWithNewline() + trimTrailingWhitespace() + } + + groovyGradle { + target '*.gradle', '**/*.gradle' + targetExclude '**/build/**' + greclipse() + indentWithSpaces(4) + endWithNewline() + trimTrailingWhitespace() + } + + lineEndings 'UNIX' +} + +configure(this) { + // NOTE: order matters! + apply plugin: 'java' + apply plugin: 'idea' + apply plugin: 'eclipse' + apply plugin: 'checkstyle' + apply plugin: 'net.ltgt.errorprone' + configurations { + implementation.setCanBeResolved(true) + api.setCanBeResolved(true) + } + tasks.withType(JavaCompile) { + options.compilerArgs += [ + "-Xlint:unchecked", + "-Xlint:cast", + "-Xlint:auxiliaryclass", + "-Xlint:deprecation", + "-Xlint:dep-ann", + "-Xlint:divzero", + "-Xlint:empty", + "-Xlint:exports", + "-Xlint:fallthrough", + "-Xlint:finally", + "-Xlint:module", + "-Xlint:opens", + "-Xlint:options", + "-Xlint:overloads", + "-Xlint:overrides", + "-Xlint:path", + "-Xlint:processing", + "-Xlint:removal", + "-Xlint:requires-automatic", + "-Xlint:requires-transitive-automatic", + "-Xlint:try", + "-Xlint:varargs", + "-Xlint:preview", + "-Xlint:static", + // -Werror needs to be disabled because EclipseLink's static weaving doesn't generate warning-free code + // and during an IntelliJ recompilation, it fails + //"-Werror", + "-Xmaxwarns", + 1500, + "-Xmaxerrs", + 1500 + ] + options.deprecation = true + } + // Configuration for the spotless plugin + // https://github.com/diffplug/spotless/tree/main/plugin-gradle + spotless { + java { + targetExclude '**/build/**', '**/bin/**', '**/out/**' + importOrder() //sort imports alphabetically + removeUnusedImports() + eclipse().configFile "$rootDir/ph-ee-identity-account-mapper/config/iam-formatter.xml" + endWithNewline() + trimTrailingWhitespace() + // Enforce style modifier order + custom 'Modifier ordering', { + def modifierRanking = [ + public : 1, + protected : 2, + private : 3, + abstract : 4, + default : 5, + static : 6, + final : 7, + transient : 8, + volatile : 9, + synchronized: 10, + native : 11, + strictfp : 12] + // Find any instance of multiple modifiers. Lead with a non-word character to avoid + // accidental matching against for instance, "an alternative default value" + it.replaceAll(/\W(?:public |protected |private |abstract |default |static |final |transient |volatile |synchronized |native |strictfp ){2,}/, { + // Do not replace the leading non-word character. Identify the modifiers + it.replaceAll(/(?:public |protected |private |abstract |default |static |final |transient |volatile |synchronized |native |strictfp ){2,}/, { + // Sort the modifiers according to the ranking above + it.split().sort({ modifierRanking[it] }).join(' ') + ' ' + } + ) + } + ) + } + } + lineEndings 'UNIX' + } + // If we are running Gradle within Eclipse to enhance classes, + // set the classes directory to point to Eclipse's default build directory + if (project.hasProperty('env') && project.getProperty('env') == 'eclipse') { + sourceSets.main.java.outputDir = file("$projectDir/bin/main") + } + // Configuration for the Checkstyle plugin + // https://docs.gradle.org/current/userguide/checkstyle_plugin.html + dependencies { + checkstyle 'com.puppycrawl.tools:checkstyle:10.3.1' + checkstyle 'com.github.sevntu-checkstyle:sevntu-checks:1.42.0' + } + // Configuration for the errorprone plugin + // https://github.com/tbroyer/gradle-errorprone-plugin + dependencies { + errorprone "com.google.errorprone:error_prone_core:2.20.0" + } + + tasks.withType(JavaCompile) { + options.errorprone { + enabled = project.gradle.startParameter.taskNames.contains('build') || project.gradle.startParameter.taskNames.contains('check') + disableWarningsInGeneratedCode = true + excludedPaths = ".*/build/.*" + disable( + // TODO Remove disabled checks from this list, by fixing remaining usages + "UnusedVariable", + "TypeParameterUnusedInFormals", + "EmptyBlockTag", + "MissingSummary", + "InvalidParam", + "ReturnFromVoid", + "AlmostJavadoc", + "InvalidBlockTag", + "JavaUtilDate", // TODO FINERACT-1298 + "ReturnValueIgnored", + "DirectInvocationOnMock", + "CanIgnoreReturnValueSuggester", + "SameNameButDifferent", // Until errorprone recognizes Lombok + "MultiVariableDeclaration", // Until errorprone recognizes Lombok + "UnnecessaryDefaultInEnumSwitch" // FINERACT-1911 + ) + error( + "DefaultCharset", + "RemoveUnusedImports", + "WaitNotInLoop", + "ThreeLetterTimeZoneID", + "VariableNameSameAsType", + "UnnecessaryParentheses", + "MultipleTopLevelClasses", + "MixedMutabilityReturnType", + "AssertEqualsArgumentOrderChecker", + "EmptySetMultibindingContributions", + "BigDecimalEquals", + "MixedArrayDimensions", + "PackageLocation", + "UseBinds", + "BadImport", + "IntLongMath", + "FloatCast", + "ReachabilityFenceUsage", + "StreamResourceLeak", + "TruthIncompatibleType", + "ByteBufferBackingArray", + "OrphanedFormatString", + "CatchAndPrintStackTrace", + "ObjectToString", + "StringSplitter", + "AssertThrowsMultipleStatements", + "BoxedPrimitiveConstructor", + "EmptyCatch", + "BoxedPrimitiveEquality", + "SynchronizeOnNonFinalField", + "WildcardImport", + "PrivateConstructorForNoninstantiableModule", + "ClassCanBeStatic", + "ClassNewInstance", + "UnnecessaryStaticImport", + "UnsafeFinalization", + "JavaTimeDefaultTimeZone", + "JodaPlusMinusLong", + "SwitchDefault", + "VarTypeName", + "ArgumentSelectionDefectChecker", + "CompareToZero", + "InjectOnConstructorOfAbstractClass", + "ImmutableEnumChecker", + "NarrowingCompoundAssignment", + "MissingCasesInEnumSwitch", + "ReferenceEquality", + "UndefinedEquals", + "UnescapedEntity", + "ModifyCollectionInEnhancedForLoop", + "NonCanonicalType", + "InvalidInlineTag", + "MutablePublicArray", + "StaticAssignmentInConstructor", + "ProtectedMembersInFinalClass", + "OperatorPrecedence", + "EqualsGetClass", + "EqualsUnsafeCast", + "DoubleBraceInitialization", + "UnusedNestedClass", + "UnusedMethod", + "ModifiedButNotUsed", + "InconsistentCapitalization", + "MissingOverride", + ) + } + } +} +task bootRun() { +} diff --git a/ph-ee-identity-account-mapper/config/checkstyle/checkstyle.xml b/ph-ee-identity-account-mapper/config/checkstyle/checkstyle.xml new file mode 100644 index 000000000..20ea24e55 --- /dev/null +++ b/ph-ee-identity-account-mapper/config/checkstyle/checkstyle.xml @@ -0,0 +1,196 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ph-ee-identity-account-mapper/config/checkstyle/suppressions.xml b/ph-ee-identity-account-mapper/config/checkstyle/suppressions.xml new file mode 100644 index 000000000..f4e5b54c3 --- /dev/null +++ b/ph-ee-identity-account-mapper/config/checkstyle/suppressions.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + diff --git a/ph-ee-identity-account-mapper/config/iam-cleanup.xml b/ph-ee-identity-account-mapper/config/iam-cleanup.xml new file mode 100644 index 000000000..5a6471abd --- /dev/null +++ b/ph-ee-identity-account-mapper/config/iam-cleanup.xml @@ -0,0 +1,71 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ph-ee-identity-account-mapper/config/iam-formatter.xml b/ph-ee-identity-account-mapper/config/iam-formatter.xml new file mode 100644 index 000000000..da8833bf7 --- /dev/null +++ b/ph-ee-identity-account-mapper/config/iam-formatter.xml @@ -0,0 +1,366 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ph-ee-identity-account-mapper/gradle/wrapper/gradle-wrapper.jar b/ph-ee-identity-account-mapper/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 000000000..249e5832f Binary files /dev/null and b/ph-ee-identity-account-mapper/gradle/wrapper/gradle-wrapper.jar differ diff --git a/ph-ee-identity-account-mapper/gradle/wrapper/gradle-wrapper.properties b/ph-ee-identity-account-mapper/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 000000000..774fae876 --- /dev/null +++ b/ph-ee-identity-account-mapper/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.1-bin.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/ph-ee-identity-account-mapper/gradlew b/ph-ee-identity-account-mapper/gradlew new file mode 100755 index 000000000..a69d9cb6c --- /dev/null +++ b/ph-ee-identity-account-mapper/gradlew @@ -0,0 +1,240 @@ +#!/bin/sh + +# +# Copyright © 2015-2021 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit + +APP_NAME="Gradle" +APP_BASE_NAME=${0##*/} + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/ph-ee-identity-account-mapper/gradlew.bat b/ph-ee-identity-account-mapper/gradlew.bat new file mode 100644 index 000000000..53a6b238d --- /dev/null +++ b/ph-ee-identity-account-mapper/gradlew.bat @@ -0,0 +1,91 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 0 goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/ph-ee-identity-account-mapper/settings.gradle b/ph-ee-identity-account-mapper/settings.gradle new file mode 100644 index 000000000..35e96e0e2 --- /dev/null +++ b/ph-ee-identity-account-mapper/settings.gradle @@ -0,0 +1 @@ +rootProject.name = 'ph-ee-identity-account-mapper' diff --git a/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/IdentityAccountMapperApplication.java b/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/IdentityAccountMapperApplication.java new file mode 100644 index 000000000..3062d9512 --- /dev/null +++ b/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/IdentityAccountMapperApplication.java @@ -0,0 +1,17 @@ +package org.mifos.identityaccountmapper; + +import org.mifos.identityaccountmapper.util.AbstractApplicationConfiguration; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cache.annotation.EnableCaching; +import org.springframework.context.annotation.ComponentScan; + +@EnableCaching +@SpringBootApplication +@ComponentScan("org.mifos.pheeidaccountvalidatorimpl") +public class IdentityAccountMapperApplication extends AbstractApplicationConfiguration { + + public static void main(String[] args) { + SpringApplication.run(IdentityAccountMapperApplication.class, args); + } +} diff --git a/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/api/definition/AccountLookupApi.java b/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/api/definition/AccountLookupApi.java new file mode 100644 index 000000000..85c999811 --- /dev/null +++ b/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/api/definition/AccountLookupApi.java @@ -0,0 +1,23 @@ +package org.mifos.identityaccountmapper.api.definition; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import java.util.concurrent.ExecutionException; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestHeader; +import org.springframework.web.bind.annotation.RequestParam; + +@Tag(name = "GOV") +public interface AccountLookupApi { + + @Operation(summary = "Account Lookup API") + @GetMapping("/beneficiary") + + ResponseEntity accountLookup(@RequestHeader(value = "X-CallbackURL") String callbackURL, + @RequestParam(value = "payeeIdentity") String payeeIdentity, @RequestParam(value = "paymentModality") String paymentModality, + @RequestParam(value = "requestId") String requestId, + @RequestHeader(value = "X-Registering-Institution-ID") String registeringInstitutionId) + throws ExecutionException, InterruptedException; + +} diff --git a/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/api/definition/AccountLookupCallback.java b/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/api/definition/AccountLookupCallback.java new file mode 100644 index 000000000..0d6d027e5 --- /dev/null +++ b/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/api/definition/AccountLookupCallback.java @@ -0,0 +1,18 @@ +package org.mifos.identityaccountmapper.api.definition; + +import com.fasterxml.jackson.core.JsonProcessingException; +import java.util.concurrent.ExecutionException; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; + +public interface AccountLookupCallback { + + @PutMapping("/accountLookupCallback") + ResponseEntity accountLookupCallback(@RequestBody String requestBody) + throws ExecutionException, InterruptedException, JsonProcessingException; + + @PutMapping("/batchAccountLookupCallback") + ResponseEntity batchAccountLookupCallback(@RequestBody String requestBody) + throws ExecutionException, InterruptedException, JsonProcessingException; +} diff --git a/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/api/definition/AddPaymentModalityApi.java b/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/api/definition/AddPaymentModalityApi.java new file mode 100644 index 000000000..d961bca2b --- /dev/null +++ b/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/api/definition/AddPaymentModalityApi.java @@ -0,0 +1,22 @@ +package org.mifos.identityaccountmapper.api.definition; + +import com.fasterxml.jackson.core.JsonProcessingException; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import java.util.concurrent.ExecutionException; +import org.mifos.identityaccountmapper.data.RequestDTO; +import org.mifos.identityaccountmapper.data.ResponseDTO; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestHeader; + +@Tag(name = "GOV") +public interface AddPaymentModalityApi { + + @Operation(summary = "Adding new payment modality") + @PostMapping("/paymentModality") + ResponseEntity addPaymentModality(@RequestHeader(value = "X-CallbackURL") String callbackURL, + @RequestHeader(value = "X-Registering-Institution-ID") String registeringInstitutionId, @RequestBody RequestDTO requestBody) + throws ExecutionException, InterruptedException, JsonProcessingException; +} diff --git a/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/api/definition/BatchAccountLookupApi.java b/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/api/definition/BatchAccountLookupApi.java new file mode 100644 index 000000000..3a34fb9cc --- /dev/null +++ b/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/api/definition/BatchAccountLookupApi.java @@ -0,0 +1,17 @@ +package org.mifos.identityaccountmapper.api.definition; + +import java.util.concurrent.ExecutionException; +import org.mifos.identityaccountmapper.data.RequestDTO; +import org.mifos.identityaccountmapper.data.ResponseDTO; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestHeader; + +public interface BatchAccountLookupApi { + + @PostMapping("/accountLookup") + ResponseEntity batchAccountLookup(@RequestHeader(value = "X-CallbackURL") String callbackURL, + @RequestBody RequestDTO requestBody, @RequestHeader(value = "X-Registering-Institution-ID") String registeringInstitutionId) + throws ExecutionException, InterruptedException; +} diff --git a/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/api/definition/FetchBeneficiariesApi.java b/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/api/definition/FetchBeneficiariesApi.java new file mode 100644 index 000000000..311c14d15 --- /dev/null +++ b/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/api/definition/FetchBeneficiariesApi.java @@ -0,0 +1,25 @@ +package org.mifos.identityaccountmapper.api.definition; + +import java.util.concurrent.ExecutionException; +import org.mifos.identityaccountmapper.data.FetchBeneficiariesResponseDTO; +import org.springframework.data.domain.Page; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestHeader; +import org.springframework.web.bind.annotation.RequestParam; + +public interface FetchBeneficiariesApi { + + @GetMapping("/beneficiaries/{payeeIdentity}") + ResponseEntity fetchBeneficiary(@PathVariable String payeeIdentity, + @RequestHeader(value = "X-Registering-Institution-ID") String registeringInstitutionId) + throws ExecutionException, InterruptedException; + + @GetMapping("/beneficiaries") + ResponseEntity> fetchAllBeneficiary( + @RequestHeader(value = "X-Registering-Institution-ID") String registeringInstitutionId, + @RequestParam(value = "page", required = false, defaultValue = "0") Integer page, + @RequestParam(value = "pageSize", required = false, defaultValue = "20") Integer pageSize) + throws ExecutionException, InterruptedException; +} diff --git a/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/api/definition/RegisterBeneficiaryApi.java b/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/api/definition/RegisterBeneficiaryApi.java new file mode 100644 index 000000000..161325d45 --- /dev/null +++ b/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/api/definition/RegisterBeneficiaryApi.java @@ -0,0 +1,23 @@ +package org.mifos.identityaccountmapper.api.definition; + +import com.fasterxml.jackson.core.JsonProcessingException; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import java.util.concurrent.ExecutionException; +import org.mifos.identityaccountmapper.data.RequestDTO; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestHeader; + +@Tag(name = "GOV") +public interface RegisterBeneficiaryApi { + + @Operation(summary = "Registering new beneficiary") + @PostMapping("/beneficiary") + + ResponseEntity registerBeneficiary(@RequestHeader(value = "X-CallbackURL") String callbackURL, + @RequestHeader(value = "X-Registering-Institution-ID") String registeringInstitutionId, @RequestBody RequestDTO requestBody) + throws ExecutionException, InterruptedException, JsonProcessingException; + +} diff --git a/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/api/definition/UpdateBeneficiaryApi.java b/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/api/definition/UpdateBeneficiaryApi.java new file mode 100644 index 000000000..45663db27 --- /dev/null +++ b/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/api/definition/UpdateBeneficiaryApi.java @@ -0,0 +1,17 @@ +package org.mifos.identityaccountmapper.api.definition; + +import com.fasterxml.jackson.core.JsonProcessingException; +import java.util.concurrent.ExecutionException; +import org.mifos.identityaccountmapper.data.RequestDTO; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestHeader; + +public interface UpdateBeneficiaryApi { + + @PutMapping("/beneficiary") + ResponseEntity registerBeneficiary(@RequestHeader(value = "X-CallbackURL") String callbackURL, + @RequestHeader(value = "X-Registering-Institution-ID") String registeringInstitutionId, @RequestBody RequestDTO requestBody) + throws ExecutionException, InterruptedException, JsonProcessingException; +} diff --git a/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/api/definition/UpdatePaymentModalityApi.java b/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/api/definition/UpdatePaymentModalityApi.java new file mode 100644 index 000000000..f11a398b4 --- /dev/null +++ b/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/api/definition/UpdatePaymentModalityApi.java @@ -0,0 +1,24 @@ +package org.mifos.identityaccountmapper.api.definition; + +import com.fasterxml.jackson.core.JsonProcessingException; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import java.util.concurrent.ExecutionException; +import org.mifos.identityaccountmapper.data.RequestDTO; +import org.mifos.identityaccountmapper.data.ResponseDTO; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestHeader; + +@Tag(name = "GOV") +public interface UpdatePaymentModalityApi { + + @Operation(summary = "Updating payment modality") + @PutMapping("/paymentModality") + + ResponseEntity updatePaymentModality(@RequestHeader(value = "X-CallbackURL") String callbackURL, + @RequestHeader(value = "X-Registering-Institution-ID") String registeringInstitutionId, @RequestBody RequestDTO requestBody) + throws ExecutionException, InterruptedException, JsonProcessingException; + +} diff --git a/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/api/implementation/AccountLookupApiController.java b/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/api/implementation/AccountLookupApiController.java new file mode 100644 index 000000000..bd6bcbebd --- /dev/null +++ b/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/api/implementation/AccountLookupApiController.java @@ -0,0 +1,59 @@ +package org.mifos.identityaccountmapper.api.implementation; + +import static org.mifos.identityaccountmapper.util.AccountMapperEnum.FAILED_RESPONSE_CODE; +import static org.mifos.identityaccountmapper.util.AccountMapperEnum.FAILED_RESPONSE_MESSAGE; +import static org.mifos.identityaccountmapper.util.AccountMapperEnum.SUCCESS_RESPONSE_CODE; +import static org.mifos.identityaccountmapper.util.AccountMapperEnum.SUCCESS_RESPONSE_MESSAGE; + +import org.mifos.identityaccountmapper.api.definition.AccountLookupApi; +import org.mifos.identityaccountmapper.data.AccountLookupResponseDTO; +import org.mifos.identityaccountmapper.data.ResponseDTO; +import org.mifos.identityaccountmapper.service.AccountLookupService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.data.util.Pair; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.RestController; + +@RestController +public class AccountLookupApiController implements AccountLookupApi { + + @Autowired + AccountLookupService accountLookupService; + + @Value("${isExternalLookup}") + Boolean isExternalLookup; + + @Override + public ResponseEntity accountLookup(String callbackURL, String payeeIdentity, String paymentModality, String requestId, + String registeringInstitutionId) { + + if (!isExternalLookup) { + Pair response; + try { + response = accountLookupService.syncAccountLookup(callbackURL, payeeIdentity, paymentModality, requestId, + registeringInstitutionId); + } catch (Exception e) { + ResponseDTO responseDTO = new ResponseDTO(FAILED_RESPONSE_CODE.getValue(), FAILED_RESPONSE_MESSAGE.getValue(), requestId); + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body((T) responseDTO); + } + + if (!response.getFirst()) { + ResponseDTO responseDTO = new ResponseDTO(FAILED_RESPONSE_CODE.getValue(), FAILED_RESPONSE_MESSAGE.getValue(), requestId); + return ResponseEntity.status(HttpStatus.BAD_REQUEST).body((T) responseDTO); + } else { + return ResponseEntity.status(HttpStatus.OK).body((T) response.getSecond()); + } + } + + try { + accountLookupService.accountLookup(callbackURL, payeeIdentity, paymentModality, requestId, registeringInstitutionId); + } catch (Exception e) { + ResponseDTO responseDTO = new ResponseDTO(FAILED_RESPONSE_CODE.getValue(), FAILED_RESPONSE_MESSAGE.getValue(), requestId); + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body((T) responseDTO); + } + ResponseDTO responseDTO = new ResponseDTO(SUCCESS_RESPONSE_CODE.getValue(), SUCCESS_RESPONSE_MESSAGE.getValue(), requestId); + return ResponseEntity.status(HttpStatus.ACCEPTED).body((T) responseDTO); + } +} diff --git a/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/api/implementation/AccountLookupCallbackController.java b/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/api/implementation/AccountLookupCallbackController.java new file mode 100644 index 000000000..6cbdb6b2d --- /dev/null +++ b/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/api/implementation/AccountLookupCallbackController.java @@ -0,0 +1,98 @@ +package org.mifos.identityaccountmapper.api.implementation; + +import static org.mifos.identityaccountmapper.zeebe.ZeebeVariables.ACCOUNT_LOOKUP; +import static org.mifos.identityaccountmapper.zeebe.ZeebeVariables.ACCOUNT_LOOKUP_FAILED; +import static org.mifos.identityaccountmapper.zeebe.ZeebeVariables.BATCH_ACCOUNT_LOOKUP_RESPONSE; +import static org.mifos.identityaccountmapper.zeebe.ZeebeVariables.PARTY_LOOKUP_FAILED; +import static org.mifos.identityaccountmapper.zeebe.ZeebeVariables.PARTY_LOOKUP_FSP_ID; +import static org.mifos.identityaccountmapper.zeebe.ZeebeVariables.PAYEE_PARTY_ID; +import static org.mifos.identityaccountmapper.zeebe.ZeebeVariables.PAYEE_PARTY_ID_TYPE; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import io.camunda.zeebe.client.ZeebeClient; +import java.io.IOException; +import java.time.Duration; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.ExecutionException; +import org.mifos.identityaccountmapper.api.definition.AccountLookupCallback; +import org.mifos.identityaccountmapper.data.AccountLookupResponseDTO; +import org.mifos.identityaccountmapper.data.BatchAccountLookupResponseDTO; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.RestController; + +@RestController +public class AccountLookupCallbackController implements AccountLookupCallback { + + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Autowired(required = false) + private ZeebeClient zeebeClient; + @Autowired + private ObjectMapper objectMapper; + + @Override + public ResponseEntity accountLookupCallback(String requestBody) + throws ExecutionException, InterruptedException, JsonProcessingException { + Map variables = new HashMap<>(); + + String error = null; + String transactionId = null; + AccountLookupResponseDTO accountLookupResponseDTO = null; + try { + logger.info(requestBody); + accountLookupResponseDTO = objectMapper.readValue(requestBody, AccountLookupResponseDTO.class); + variables.put(ACCOUNT_LOOKUP_FAILED, false); + variables.put(PAYEE_PARTY_ID, accountLookupResponseDTO.getPaymentModalityList().get(0).getFinancialAddress()); + variables.put(PAYEE_PARTY_ID_TYPE, accountLookupResponseDTO.getPaymentModalityList().get(0).getPaymentModality()); + variables.put(PARTY_LOOKUP_FSP_ID, accountLookupResponseDTO.getPaymentModalityList().get(0).getBankingInstitutionCode()); + transactionId = accountLookupResponseDTO.getRequestId(); + Boolean isValidated = accountLookupResponseDTO.getIsValidated(); + if (!isValidated) { + variables.put(ACCOUNT_LOOKUP_FAILED, true); + } + } catch (IOException e) { + variables.put(ACCOUNT_LOOKUP_FAILED, true); + error = objectMapper.readValue(requestBody, String.class); + } + + if (zeebeClient != null) { + + zeebeClient.newPublishMessageCommand().messageName(ACCOUNT_LOOKUP).correlationKey(transactionId) + .timeToLive(Duration.ofMillis(50000)).variables(variables).send(); + } + return ResponseEntity.status(HttpStatus.OK).body("Accepted"); + } + + @Override + public ResponseEntity batchAccountLookupCallback(String requestBody) + throws ExecutionException, InterruptedException, JsonProcessingException { + Map variables = new HashMap<>(); + String error = null; + String transactionId = null; + // String response = exchange.getIn().getBody(String.class); + BatchAccountLookupResponseDTO batchAccountLookupResponseDTO = null; + try { + batchAccountLookupResponseDTO = objectMapper.readValue(requestBody, BatchAccountLookupResponseDTO.class); + variables.put("batchAccountLookupCallback", requestBody); + transactionId = batchAccountLookupResponseDTO.getRequestID(); + variables.put("cachedTransactionId", transactionId); + } catch (Exception e) { + logger.error(e.getMessage()); + variables.put(PARTY_LOOKUP_FAILED, true); + error = objectMapper.readValue(requestBody, String.class); + } + + if (zeebeClient != null) { + + zeebeClient.newPublishMessageCommand().messageName(BATCH_ACCOUNT_LOOKUP_RESPONSE).correlationKey(transactionId) + .timeToLive(Duration.ofMillis(50000)).variables(variables).send(); + } + return ResponseEntity.status(HttpStatus.OK).body("Accepted"); + } +} diff --git a/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/api/implementation/AddPaymentModalityApiController.java b/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/api/implementation/AddPaymentModalityApiController.java new file mode 100644 index 000000000..fe9e9f212 --- /dev/null +++ b/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/api/implementation/AddPaymentModalityApiController.java @@ -0,0 +1,39 @@ +package org.mifos.identityaccountmapper.api.implementation; + +import static org.mifos.identityaccountmapper.util.AccountMapperEnum.FAILED_RESPONSE_CODE; +import static org.mifos.identityaccountmapper.util.AccountMapperEnum.FAILED_RESPONSE_MESSAGE; +import static org.mifos.identityaccountmapper.util.AccountMapperEnum.SUCCESS_RESPONSE_CODE; +import static org.mifos.identityaccountmapper.util.AccountMapperEnum.SUCCESS_RESPONSE_MESSAGE; + +import com.fasterxml.jackson.core.JsonProcessingException; +import java.util.concurrent.ExecutionException; +import org.mifos.identityaccountmapper.api.definition.AddPaymentModalityApi; +import org.mifos.identityaccountmapper.data.RequestDTO; +import org.mifos.identityaccountmapper.data.ResponseDTO; +import org.mifos.identityaccountmapper.service.AddUpdatePaymentModalityService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.RestController; + +@RestController +public class AddPaymentModalityApiController implements AddPaymentModalityApi { + + @Autowired + AddUpdatePaymentModalityService addUpdatePaymentModalityService; + + @Override + public ResponseEntity addPaymentModality(String callbackURL, String registeringInstitutionId, RequestDTO requestBody) + throws ExecutionException, InterruptedException, JsonProcessingException { + try { + addUpdatePaymentModalityService.addPaymentModality(callbackURL, requestBody, registeringInstitutionId); + } catch (Exception e) { + ResponseDTO responseDTO = new ResponseDTO(FAILED_RESPONSE_CODE.getValue(), FAILED_RESPONSE_MESSAGE.getValue(), + requestBody.getRequestID()); + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(responseDTO); + } + ResponseDTO responseDTO = new ResponseDTO(SUCCESS_RESPONSE_CODE.getValue(), SUCCESS_RESPONSE_MESSAGE.getValue(), + requestBody.getRequestID()); + return ResponseEntity.status(HttpStatus.ACCEPTED).body(responseDTO); + } +} diff --git a/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/api/implementation/BatchAccountLookupApiController.java b/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/api/implementation/BatchAccountLookupApiController.java new file mode 100644 index 000000000..b39a83265 --- /dev/null +++ b/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/api/implementation/BatchAccountLookupApiController.java @@ -0,0 +1,40 @@ +package org.mifos.identityaccountmapper.api.implementation; + +import static org.mifos.identityaccountmapper.util.AccountMapperEnum.FAILED_RESPONSE_CODE; +import static org.mifos.identityaccountmapper.util.AccountMapperEnum.FAILED_RESPONSE_MESSAGE; +import static org.mifos.identityaccountmapper.util.AccountMapperEnum.SUCCESS_RESPONSE_CODE; +import static org.mifos.identityaccountmapper.util.AccountMapperEnum.SUCCESS_RESPONSE_MESSAGE; + +import java.util.concurrent.ExecutionException; +import org.mifos.identityaccountmapper.api.definition.BatchAccountLookupApi; +import org.mifos.identityaccountmapper.data.RequestDTO; +import org.mifos.identityaccountmapper.data.ResponseDTO; +import org.mifos.identityaccountmapper.service.AccountLookupService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.RestController; + +@RestController +public class BatchAccountLookupApiController implements BatchAccountLookupApi { + + @Autowired + AccountLookupService accountLookupService; + + @Override + public ResponseEntity batchAccountLookup(String callbackURL, RequestDTO requestDTO, String registeringInstitutionId) + throws ExecutionException, InterruptedException { + try { + accountLookupService.batchAccountLookup(callbackURL, requestDTO.getRequestID(), requestDTO.getBeneficiaries(), + registeringInstitutionId); + + } catch (Exception e) { + ResponseDTO responseDTO = new ResponseDTO(FAILED_RESPONSE_CODE.getValue(), FAILED_RESPONSE_MESSAGE.getValue(), + requestDTO.getRequestID()); + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(responseDTO); + } + ResponseDTO responseDTO = new ResponseDTO(SUCCESS_RESPONSE_CODE.getValue(), SUCCESS_RESPONSE_MESSAGE.getValue(), + requestDTO.getRequestID()); + return ResponseEntity.status(HttpStatus.ACCEPTED).body(responseDTO); + } +} diff --git a/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/api/implementation/FetchBeneficiariesApiController.java b/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/api/implementation/FetchBeneficiariesApiController.java new file mode 100644 index 000000000..e13d8f5b7 --- /dev/null +++ b/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/api/implementation/FetchBeneficiariesApiController.java @@ -0,0 +1,41 @@ +package org.mifos.identityaccountmapper.api.implementation; + +import java.util.concurrent.ExecutionException; +import org.apache.commons.lang3.StringUtils; +import org.mifos.identityaccountmapper.api.definition.FetchBeneficiariesApi; +import org.mifos.identityaccountmapper.data.FetchBeneficiariesResponseDTO; +import org.mifos.identityaccountmapper.service.FetchBeneficiariesService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Page; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.RestController; + +@RestController +public class FetchBeneficiariesApiController implements FetchBeneficiariesApi { + + @Autowired + FetchBeneficiariesService fetchBeneficiariesService; + + @Override + public ResponseEntity fetchBeneficiary(String payeeIdentity, String registeringInstitutionId) + throws ExecutionException, InterruptedException { + if (StringUtils.isBlank(registeringInstitutionId)) { + return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(null); + } + FetchBeneficiariesResponseDTO fetchBeneficiariesResponseDTO = fetchBeneficiariesService.fetchBeneficiary(payeeIdentity, + registeringInstitutionId); + return ResponseEntity.status(HttpStatus.OK).body(fetchBeneficiariesResponseDTO); + } + + @Override + public ResponseEntity> fetchAllBeneficiary(String registeringInstitutionId, Integer page, + Integer pageSize) throws ExecutionException, InterruptedException { + if (StringUtils.isBlank(registeringInstitutionId)) { + return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(null); + } + Page fetchBeneficiariesResponseDTO = fetchBeneficiariesService.fetchAllBeneficiaries(page, pageSize, + registeringInstitutionId); + return ResponseEntity.status(HttpStatus.OK).body(fetchBeneficiariesResponseDTO); + } +} diff --git a/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/api/implementation/RegisterBeneficiaryApiController.java b/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/api/implementation/RegisterBeneficiaryApiController.java new file mode 100644 index 000000000..47c8c800a --- /dev/null +++ b/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/api/implementation/RegisterBeneficiaryApiController.java @@ -0,0 +1,43 @@ +package org.mifos.identityaccountmapper.api.implementation; + +import static org.mifos.identityaccountmapper.util.AccountMapperEnum.FAILED_RESPONSE_CODE; +import static org.mifos.identityaccountmapper.util.AccountMapperEnum.FAILED_RESPONSE_MESSAGE; +import static org.mifos.identityaccountmapper.util.AccountMapperEnum.SUCCESS_RESPONSE_CODE; +import static org.mifos.identityaccountmapper.util.AccountMapperEnum.SUCCESS_RESPONSE_MESSAGE; + +import com.fasterxml.jackson.core.JsonProcessingException; +import java.util.concurrent.ExecutionException; +import org.mifos.connector.common.channel.dto.PhErrorDTO; +import org.mifos.identityaccountmapper.api.definition.RegisterBeneficiaryApi; +import org.mifos.identityaccountmapper.data.RequestDTO; +import org.mifos.identityaccountmapper.data.ResponseDTO; +import org.mifos.identityaccountmapper.service.RegisterBeneficiaryService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.RestController; + +@RestController +public class RegisterBeneficiaryApiController implements RegisterBeneficiaryApi { + + @Autowired + RegisterBeneficiaryService registerBeneficiaryService; + + @Override + public ResponseEntity registerBeneficiary(String callbackURL, String registeringInstitutionId, RequestDTO requestBody) + throws ExecutionException, InterruptedException, JsonProcessingException { + try { + PhErrorDTO phErrorDTO = registerBeneficiaryService.registerBeneficiary(callbackURL, requestBody, registeringInstitutionId); + if (phErrorDTO != null) { + return ResponseEntity.status(HttpStatus.BAD_REQUEST).body((T) phErrorDTO); + } + } catch (Exception e) { + ResponseDTO responseDTO = new ResponseDTO(FAILED_RESPONSE_CODE.getValue(), FAILED_RESPONSE_MESSAGE.getValue(), + requestBody.getRequestID()); + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body((T) responseDTO); + } + ResponseDTO responseDTO = new ResponseDTO(SUCCESS_RESPONSE_CODE.getValue(), SUCCESS_RESPONSE_MESSAGE.getValue(), + requestBody.getRequestID()); + return ResponseEntity.status(HttpStatus.ACCEPTED).body((T) responseDTO); + } +} diff --git a/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/api/implementation/UpdateBeneficiaryApiController.java b/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/api/implementation/UpdateBeneficiaryApiController.java new file mode 100644 index 000000000..413873ec9 --- /dev/null +++ b/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/api/implementation/UpdateBeneficiaryApiController.java @@ -0,0 +1,44 @@ +package org.mifos.identityaccountmapper.api.implementation; + +import static org.mifos.identityaccountmapper.util.AccountMapperEnum.FAILED_RESPONSE_CODE; +import static org.mifos.identityaccountmapper.util.AccountMapperEnum.FAILED_RESPONSE_MESSAGE; +import static org.mifos.identityaccountmapper.util.AccountMapperEnum.SUCCESS_RESPONSE_CODE; +import static org.mifos.identityaccountmapper.util.AccountMapperEnum.SUCCESS_RESPONSE_MESSAGE; + +import com.fasterxml.jackson.core.JsonProcessingException; +import java.util.concurrent.ExecutionException; +import org.mifos.connector.common.channel.dto.PhErrorDTO; +import org.mifos.identityaccountmapper.api.definition.UpdateBeneficiaryApi; +import org.mifos.identityaccountmapper.data.RequestDTO; +import org.mifos.identityaccountmapper.data.ResponseDTO; +import org.mifos.identityaccountmapper.service.AddUpdatePaymentModalityService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.RestController; + +@RestController +public class UpdateBeneficiaryApiController implements UpdateBeneficiaryApi { + + @Autowired + AddUpdatePaymentModalityService addUpdatePaymentModalityService; + + @Override + public ResponseEntity registerBeneficiary(String callbackURL, String registeringInstitutionId, RequestDTO requestBody) + throws ExecutionException, InterruptedException, JsonProcessingException { + try { + PhErrorDTO phErrorDTO = addUpdatePaymentModalityService.updatePaymentModality(callbackURL, requestBody, + registeringInstitutionId); + if (phErrorDTO != null) { + return ResponseEntity.status(HttpStatus.BAD_REQUEST).body((T) phErrorDTO); + } + } catch (Exception e) { + ResponseDTO responseDTO = new ResponseDTO(FAILED_RESPONSE_CODE.getValue(), FAILED_RESPONSE_MESSAGE.getValue(), + requestBody.getRequestID()); + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body((T) responseDTO); + } + ResponseDTO responseDTO = new ResponseDTO(SUCCESS_RESPONSE_CODE.getValue(), SUCCESS_RESPONSE_MESSAGE.getValue(), + requestBody.getRequestID()); + return ResponseEntity.status(HttpStatus.ACCEPTED).body((T) responseDTO); + } +} diff --git a/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/api/implementation/UpdatePaymentModalityApiController.java b/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/api/implementation/UpdatePaymentModalityApiController.java new file mode 100644 index 000000000..dbff8c8c7 --- /dev/null +++ b/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/api/implementation/UpdatePaymentModalityApiController.java @@ -0,0 +1,39 @@ +package org.mifos.identityaccountmapper.api.implementation; + +import static org.mifos.identityaccountmapper.util.AccountMapperEnum.FAILED_RESPONSE_CODE; +import static org.mifos.identityaccountmapper.util.AccountMapperEnum.FAILED_RESPONSE_MESSAGE; +import static org.mifos.identityaccountmapper.util.AccountMapperEnum.SUCCESS_RESPONSE_CODE; +import static org.mifos.identityaccountmapper.util.AccountMapperEnum.SUCCESS_RESPONSE_MESSAGE; + +import com.fasterxml.jackson.core.JsonProcessingException; +import java.util.concurrent.ExecutionException; +import org.mifos.identityaccountmapper.api.definition.UpdatePaymentModalityApi; +import org.mifos.identityaccountmapper.data.RequestDTO; +import org.mifos.identityaccountmapper.data.ResponseDTO; +import org.mifos.identityaccountmapper.service.AddUpdatePaymentModalityService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.RestController; + +@RestController +public class UpdatePaymentModalityApiController implements UpdatePaymentModalityApi { + + @Autowired + AddUpdatePaymentModalityService addUpdatePaymentModalityService; + + @Override + public ResponseEntity updatePaymentModality(String callbackURL, String registeringInstitutionId, RequestDTO requestBody) + throws ExecutionException, InterruptedException, JsonProcessingException { + try { + addUpdatePaymentModalityService.updatePaymentModality(callbackURL, requestBody, registeringInstitutionId); + } catch (Exception e) { + ResponseDTO responseDTO = new ResponseDTO(FAILED_RESPONSE_CODE.getValue(), FAILED_RESPONSE_MESSAGE.getValue(), + requestBody.getRequestID()); + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(responseDTO); + } + ResponseDTO responseDTO = new ResponseDTO(SUCCESS_RESPONSE_CODE.getValue(), SUCCESS_RESPONSE_MESSAGE.getValue(), + requestBody.getRequestID()); + return ResponseEntity.status(HttpStatus.ACCEPTED).body(responseDTO); + } +} diff --git a/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/data/AccountLookupResponseDTO.java b/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/data/AccountLookupResponseDTO.java new file mode 100644 index 000000000..cb6397cb8 --- /dev/null +++ b/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/data/AccountLookupResponseDTO.java @@ -0,0 +1,20 @@ +package org.mifos.identityaccountmapper.data; + +import java.io.Serializable; +import java.util.List; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +public class AccountLookupResponseDTO implements Serializable { + + private String requestId; + private String payeeIdentity; + private List paymentModalityList; + private Boolean isValidated; +} diff --git a/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/data/BatchAccountLookupResponseDTO.java b/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/data/BatchAccountLookupResponseDTO.java new file mode 100644 index 000000000..0b7bcb3a9 --- /dev/null +++ b/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/data/BatchAccountLookupResponseDTO.java @@ -0,0 +1,18 @@ +package org.mifos.identityaccountmapper.data; + +import java.util.List; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +public class BatchAccountLookupResponseDTO { + + private String requestID; + private String registeringInstitutionId; + private List beneficiaryDTOList; +} diff --git a/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/data/BeneficiaryDTO.java b/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/data/BeneficiaryDTO.java new file mode 100644 index 000000000..3daff54f0 --- /dev/null +++ b/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/data/BeneficiaryDTO.java @@ -0,0 +1,19 @@ +package org.mifos.identityaccountmapper.data; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +public class BeneficiaryDTO { + + private String payeeIdentity; + private String paymentModality; + private String financialAddress; + private String bankingInstitutionCode; + +} diff --git a/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/data/CallbackRequestDTO.java b/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/data/CallbackRequestDTO.java new file mode 100644 index 000000000..1085b5387 --- /dev/null +++ b/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/data/CallbackRequestDTO.java @@ -0,0 +1,20 @@ +package org.mifos.identityaccountmapper.data; + +import java.util.List; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +public class CallbackRequestDTO { + + private String requestID; + private String registerRequestID; + private int numberFailedCases; + private List failedCases; + +} diff --git a/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/data/FailedCaseDTO.java b/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/data/FailedCaseDTO.java new file mode 100644 index 000000000..e8a8ce40c --- /dev/null +++ b/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/data/FailedCaseDTO.java @@ -0,0 +1,18 @@ +package org.mifos.identityaccountmapper.data; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +public class FailedCaseDTO { + + private String payeeIdentity; + private String paymentModality; + private String failureReason; + +} diff --git a/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/data/FetchBeneficiariesResponseDTO.java b/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/data/FetchBeneficiariesResponseDTO.java new file mode 100644 index 000000000..d28d1f345 --- /dev/null +++ b/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/data/FetchBeneficiariesResponseDTO.java @@ -0,0 +1,19 @@ +package org.mifos.identityaccountmapper.data; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +public class FetchBeneficiariesResponseDTO { + + private String registeringInstitutionId; + private String payeeIdentity; + private String paymentModality; + private String financialAddress; + private String bankingInstitutionCode; +} diff --git a/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/data/PaymentModalityDTO.java b/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/data/PaymentModalityDTO.java new file mode 100644 index 000000000..f6fccd877 --- /dev/null +++ b/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/data/PaymentModalityDTO.java @@ -0,0 +1,18 @@ +package org.mifos.identityaccountmapper.data; + +import java.io.Serializable; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +public class PaymentModalityDTO implements Serializable { + + private String paymentModality; + private String financialAddress; + private String bankingInstitutionCode; +} diff --git a/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/data/RequestDTO.java b/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/data/RequestDTO.java new file mode 100644 index 000000000..8090a9485 --- /dev/null +++ b/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/data/RequestDTO.java @@ -0,0 +1,19 @@ +package org.mifos.identityaccountmapper.data; + +import java.util.List; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +public class RequestDTO { + + private String requestID; + private String sourceBBID; + private List beneficiaries; + +} diff --git a/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/data/ResponseDTO.java b/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/data/ResponseDTO.java new file mode 100644 index 000000000..9fd2e9fd2 --- /dev/null +++ b/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/data/ResponseDTO.java @@ -0,0 +1,18 @@ +package org.mifos.identityaccountmapper.data; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +public class ResponseDTO { + + private String responseCode; + private String responseDescription; + private String requestID; + +} diff --git a/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/domain/ErrorTracking.java b/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/domain/ErrorTracking.java new file mode 100644 index 000000000..5ca648dce --- /dev/null +++ b/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/domain/ErrorTracking.java @@ -0,0 +1,66 @@ +package org.mifos.identityaccountmapper.domain; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.Table; + +@Entity +@Table(name = "error_tracking") +public class ErrorTracking { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + @Column(name = "request_id", nullable = false) + private String requestId; + @Column(name = "payee_identity", nullable = false) + private String payeeIdentity; + @Column(name = "modality") + private String modality; + @Column(name = "error_description", nullable = false) + private String errorDescription; + + public ErrorTracking() {} + + public ErrorTracking(String requestId, String payeeIdentity, String modality, String errorDescription) { + this.requestId = requestId; + this.payeeIdentity = payeeIdentity; + this.modality = modality; + this.errorDescription = errorDescription; + } + + public String getRequestId() { + return requestId; + } + + public void setRequestId(String requestId) { + this.requestId = requestId; + } + + public String getPayeeIdentity() { + return payeeIdentity; + } + + public void setPayeeIdentity(String payeeIdentity) { + this.payeeIdentity = payeeIdentity; + } + + public String getModality() { + return modality; + } + + public void setModality(String modality) { + this.modality = modality; + } + + public String getErrorDescription() { + return errorDescription; + } + + public void setErrorDescription(String errorDescription) { + this.errorDescription = errorDescription; + } +} diff --git a/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/domain/IdentityDetails.java b/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/domain/IdentityDetails.java new file mode 100644 index 000000000..af7cd2556 --- /dev/null +++ b/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/domain/IdentityDetails.java @@ -0,0 +1,67 @@ +package org.mifos.identityaccountmapper.domain; + +import java.time.LocalDateTime; +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.Table; + +@Entity +@Table(name = "identity_details") +public class IdentityDetails { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + @Column(name = "master_id") + private String masterId; + @Column(name = "registering_institution_id", nullable = false) + private String registeringInstitutionId; + @Column(name = "created_on", nullable = false) + private LocalDateTime createdOn; + @Column(name = "payee_identity", nullable = false) + private String payeeIdentity; + + public IdentityDetails() {} + + public IdentityDetails(String masterId, String registeringInstitutionId, LocalDateTime createdOn, String payeeIdentity) { + this.masterId = masterId; + this.registeringInstitutionId = registeringInstitutionId; + this.createdOn = createdOn; + this.payeeIdentity = payeeIdentity; + } + + public String getMasterId() { + return masterId; + } + + public void setMasterId(String masterId) { + this.masterId = masterId; + } + + public String getRegisteringInstitutionId() { + return registeringInstitutionId; + } + + public void setRegisteringInstitutionId(String registeringInstitutionId) { + this.registeringInstitutionId = registeringInstitutionId; + } + + public LocalDateTime getCreatedOn() { + return createdOn; + } + + public void setCreatedOn(LocalDateTime createdOn) { + this.createdOn = createdOn; + } + + public String getPayeeIdentity() { + return payeeIdentity; + } + + public void setPayeeIdentity(String payeeIdentity) { + this.payeeIdentity = payeeIdentity; + } +} diff --git a/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/domain/PaymentModalityDetails.java b/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/domain/PaymentModalityDetails.java new file mode 100644 index 000000000..809f62cfb --- /dev/null +++ b/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/domain/PaymentModalityDetails.java @@ -0,0 +1,66 @@ +package org.mifos.identityaccountmapper.domain; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.Table; + +@Entity +@Table(name = "payment_modality_details") +public class PaymentModalityDetails { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + @Column(name = "master_id", nullable = false) + private String masterId; + @Column(name = "destination_account", nullable = true) + private String destinationAccount; + @Column(name = "modality") + private String modality; + @Column(name = "institution_code", nullable = true) + private String institutionCode; + + public PaymentModalityDetails() {} + + public PaymentModalityDetails(String masterId, String destinationAccount, String modality, String institutionCode) { + this.masterId = masterId; + this.destinationAccount = destinationAccount; + this.modality = modality; + this.institutionCode = institutionCode; + } + + public String getMasterId() { + return masterId; + } + + public void setMasterId(String masterId) { + this.masterId = masterId; + } + + public String getDestinationAccount() { + return destinationAccount; + } + + public void setDestinationAccount(String destinationAccount) { + this.destinationAccount = destinationAccount; + } + + public String getModality() { + return modality; + } + + public void setModality(String modality) { + this.modality = modality; + } + + public String getInstitutionCode() { + return institutionCode; + } + + public void setInstitutionCode(String institutionCode) { + this.institutionCode = institutionCode; + } +} diff --git a/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/exception/AccountValidationException.java b/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/exception/AccountValidationException.java new file mode 100644 index 000000000..334946656 --- /dev/null +++ b/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/exception/AccountValidationException.java @@ -0,0 +1,15 @@ +package org.mifos.identityaccountmapper.exception; + +import java.text.MessageFormat; + +public class AccountValidationException extends RuntimeException { + + public AccountValidationException(String message) { + super(message); + } + + public static AccountValidationException accountvalidationFailed(final String payeeIdentity) { + String stringWithPlaceHolder = "Payee Identity {0} account validation failed!"; + return new AccountValidationException(MessageFormat.format(stringWithPlaceHolder, payeeIdentity)); + } +} diff --git a/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/exception/PayeeIdentityException.java b/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/exception/PayeeIdentityException.java new file mode 100644 index 000000000..dbbcfca20 --- /dev/null +++ b/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/exception/PayeeIdentityException.java @@ -0,0 +1,15 @@ +package org.mifos.identityaccountmapper.exception; + +import java.text.MessageFormat; + +public class PayeeIdentityException extends RuntimeException { + + public PayeeIdentityException(String message) { + super(message); + } + + public static PayeeIdentityException payeeIdentityNotFound(final String payeeIdentity) { + String stringWithPlaceHolder = "Payee Identity with {0} does not exist!"; + return new PayeeIdentityException(MessageFormat.format(stringWithPlaceHolder, payeeIdentity)); + } +} diff --git a/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/interceptor/ValidatorInterceptor.java b/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/interceptor/ValidatorInterceptor.java new file mode 100644 index 000000000..ec2c998a1 --- /dev/null +++ b/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/interceptor/ValidatorInterceptor.java @@ -0,0 +1,105 @@ +package org.mifos.identityaccountmapper.interceptor; + +import static org.mifos.connector.common.exception.PaymentHubError.ExtValidationError; + +import com.fasterxml.jackson.databind.ObjectMapper; +import java.io.IOException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import lombok.extern.slf4j.Slf4j; +import org.mifos.connector.common.channel.dto.PhErrorDTO; +import org.mifos.connector.common.exception.PaymentHubErrorCategory; +import org.mifos.connector.common.validation.ValidatorBuilder; +import org.mifos.identityaccountmapper.api.implementation.RegisterBeneficiaryApiController; +import org.mifos.identityaccountmapper.api.implementation.UpdateBeneficiaryApiController; +import org.mifos.identityaccountmapper.util.IdentityMapperValidatorsEnum; +import org.springframework.http.HttpStatus; +import org.springframework.stereotype.Component; +import org.springframework.web.method.HandlerMethod; +import org.springframework.web.servlet.HandlerInterceptor; + +@Slf4j +@Component +public class ValidatorInterceptor implements HandlerInterceptor { + + private static final String resource = "ValidatorInterceptor"; + private static final String callbackURL = "X-CallbackURL"; + private static final String registeringInstitutionId = "X-Registering-Institution-ID"; + + @Override + public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws IOException { + log.debug("request at interceptor"); + + if (handler instanceof HandlerMethod) { + HandlerMethod handlerMethod = (HandlerMethod) handler; + + if (handlerMethod.getBeanType().equals(RegisterBeneficiaryApiController.class)) { + + // Using ValidatorBuilder for header validation + final ValidatorBuilder validatorBuilder = new ValidatorBuilder(); + validatorBuilder.reset().resource(resource).parameter(callbackURL).value(request.getHeader(callbackURL)) + .isNullWithFailureCode(IdentityMapperValidatorsEnum.INVALID_CALLBACK_URL); + + validatorBuilder.reset().resource(resource).parameter(registeringInstitutionId) + .value(request.getHeader(registeringInstitutionId)) + .isNullWithFailureCode(IdentityMapperValidatorsEnum.INVALID_REGISTERING_INSTITUTION_ID); + + // If errors exist, set the response and return false + if (validatorBuilder.hasError()) { + validatorBuilder.errorCategory(PaymentHubErrorCategory.Validation.toString()) + .errorCode(IdentityMapperValidatorsEnum.IDENTITY_MAPPER_HEADER_VALIDATION_ERROR.getCode()) + .errorDescription(IdentityMapperValidatorsEnum.IDENTITY_MAPPER_HEADER_VALIDATION_ERROR.getMessage()) + .developerMessage(IdentityMapperValidatorsEnum.IDENTITY_MAPPER_HEADER_VALIDATION_ERROR.getMessage()) + .defaultUserMessage(IdentityMapperValidatorsEnum.IDENTITY_MAPPER_HEADER_VALIDATION_ERROR.getMessage()); + + PhErrorDTO.PhErrorDTOBuilder phErrorDTOBuilder = new PhErrorDTO.PhErrorDTOBuilder(ExtValidationError.getErrorCode()); + phErrorDTOBuilder.fromValidatorBuilder(validatorBuilder); + + // Converting PHErrorDTO in JSON Format + ObjectMapper objectMapper = new ObjectMapper(); + String jsonResponse = objectMapper.writeValueAsString(phErrorDTOBuilder.build()); + + // Setting response status and writing the error message + response.setHeader("Content-Type", "application/json"); + response.setStatus(HttpStatus.BAD_REQUEST.value()); + response.getWriter().write(jsonResponse); + + return false; + } + } else if (handlerMethod.getBeanType().equals(UpdateBeneficiaryApiController.class)) { + // Using ValidatorBuilder for header validation + final ValidatorBuilder validatorBuilder = new ValidatorBuilder(); + validatorBuilder.reset().resource(resource).parameter(callbackURL).value(request.getHeader(callbackURL)) + .isNullWithFailureCode(IdentityMapperValidatorsEnum.INVALID_CALLBACK_URL); + + validatorBuilder.reset().resource(resource).parameter(registeringInstitutionId) + .value(request.getHeader(registeringInstitutionId)) + .isNullWithFailureCode(IdentityMapperValidatorsEnum.INVALID_REGISTERING_INSTITUTION_ID); + + // If errors exist, set the response and return false + if (validatorBuilder.hasError()) { + validatorBuilder.errorCategory(PaymentHubErrorCategory.Validation.toString()) + .errorCode(IdentityMapperValidatorsEnum.IDENTITY_MAPPER_HEADER_VALIDATION_ERROR.getCode()) + .errorDescription(IdentityMapperValidatorsEnum.IDENTITY_MAPPER_HEADER_VALIDATION_ERROR.getMessage()) + .developerMessage(IdentityMapperValidatorsEnum.IDENTITY_MAPPER_HEADER_VALIDATION_ERROR.getMessage()) + .defaultUserMessage(IdentityMapperValidatorsEnum.IDENTITY_MAPPER_HEADER_VALIDATION_ERROR.getMessage()); + + PhErrorDTO.PhErrorDTOBuilder phErrorDTOBuilder = new PhErrorDTO.PhErrorDTOBuilder(ExtValidationError.getErrorCode()); + phErrorDTOBuilder.fromValidatorBuilder(validatorBuilder); + + // Converting PHErrorDTO in JSON Format + ObjectMapper objectMapper = new ObjectMapper(); + String jsonResponse = objectMapper.writeValueAsString(phErrorDTOBuilder.build()); + + // Setting response status and writing the error message + response.setHeader("Content-Type", "application/json"); + response.setStatus(HttpStatus.BAD_REQUEST.value()); + response.getWriter().write(jsonResponse); + + return false; + } + } + } + return true; + } +} diff --git a/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/interceptor/config/WebMvcConfig.java b/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/interceptor/config/WebMvcConfig.java new file mode 100644 index 000000000..d9c015e12 --- /dev/null +++ b/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/interceptor/config/WebMvcConfig.java @@ -0,0 +1,22 @@ +package org.mifos.identityaccountmapper.interceptor.config; + +import org.mifos.identityaccountmapper.interceptor.ValidatorInterceptor; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Primary; +import org.springframework.stereotype.Component; +import org.springframework.web.servlet.config.annotation.InterceptorRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +@Component +@Primary +public class WebMvcConfig implements WebMvcConfigurer { + + @Autowired + ValidatorInterceptor validatorInterceptor; + + @Override + public void addInterceptors(InterceptorRegistry registry) { + registry.addInterceptor(validatorInterceptor).addPathPatterns("/beneficiary"); + registry.addInterceptor(validatorInterceptor).addPathPatterns("/accountLookup"); + } +} diff --git a/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/repository/ErrorTrackingRepository.java b/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/repository/ErrorTrackingRepository.java new file mode 100644 index 000000000..4870103f9 --- /dev/null +++ b/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/repository/ErrorTrackingRepository.java @@ -0,0 +1,9 @@ +package org.mifos.identityaccountmapper.repository; + +import org.mifos.identityaccountmapper.domain.ErrorTracking; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; +import org.springframework.stereotype.Repository; + +@Repository +public interface ErrorTrackingRepository extends JpaRepository, JpaSpecificationExecutor {} diff --git a/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/repository/MasterRepository.java b/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/repository/MasterRepository.java new file mode 100644 index 000000000..6c78bd85e --- /dev/null +++ b/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/repository/MasterRepository.java @@ -0,0 +1,21 @@ +package org.mifos.identityaccountmapper.repository; + +import java.util.Optional; +import org.mifos.identityaccountmapper.domain.IdentityDetails; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; +import org.springframework.stereotype.Repository; + +@Repository +public interface MasterRepository extends JpaRepository, JpaSpecificationExecutor { + + Optional findByMasterIdAndRegisteringInstitutionId(String masterId, String registeringInstitutionId); + + Optional findByPayeeIdentityAndRegisteringInstitutionId(String functionalId, String registeringInstitutionId); + + Boolean existsByPayeeIdentityAndRegisteringInstitutionId(String functionalId, String registeringInstitutionId); + + Page findByRegisteringInstitutionId(String registeringInstitutionId, Pageable pageable); +} diff --git a/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/repository/PaymentModalityRepository.java b/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/repository/PaymentModalityRepository.java new file mode 100644 index 000000000..52c3017a2 --- /dev/null +++ b/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/repository/PaymentModalityRepository.java @@ -0,0 +1,15 @@ +package org.mifos.identityaccountmapper.repository; + +import java.util.List; +import org.mifos.identityaccountmapper.domain.PaymentModalityDetails; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; +import org.springframework.stereotype.Repository; + +@Repository +public interface PaymentModalityRepository + extends JpaRepository, JpaSpecificationExecutor { + // IdentityDetails findByMasterId(Long masterId); + + List findByMasterId(String masterID); +} diff --git a/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/service/AccountLookupReadService.java b/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/service/AccountLookupReadService.java new file mode 100644 index 000000000..002ccc510 --- /dev/null +++ b/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/service/AccountLookupReadService.java @@ -0,0 +1,69 @@ +package org.mifos.identityaccountmapper.service; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import java.util.ArrayList; +import java.util.List; +import org.mifos.identityaccountmapper.data.AccountLookupResponseDTO; +import org.mifos.identityaccountmapper.data.PaymentModalityDTO; +import org.mifos.identityaccountmapper.domain.IdentityDetails; +import org.mifos.identityaccountmapper.domain.PaymentModalityDetails; +import org.mifos.identityaccountmapper.repository.ErrorTrackingRepository; +import org.mifos.identityaccountmapper.repository.MasterRepository; +import org.mifos.identityaccountmapper.repository.PaymentModalityRepository; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.stereotype.Service; + +@Service +public class AccountLookupReadService { + + private final MasterRepository masterRepository; + private final ErrorTrackingRepository errorTrackingRepository; + private final PaymentModalityRepository paymentModalityRepository; + private final SendCallbackService sendCallbackService; + private final ObjectMapper objectMapper; + private static final Logger logger = LoggerFactory.getLogger(AccountLookupReadService.class); + + @Autowired + public AccountLookupReadService(MasterRepository masterRepository, ErrorTrackingRepository errorTrackingRepository, + PaymentModalityRepository paymentModalityRepository, SendCallbackService sendCallbackService, ObjectMapper objectMapper) { + this.masterRepository = masterRepository; + this.errorTrackingRepository = errorTrackingRepository; + this.paymentModalityRepository = paymentModalityRepository; + this.sendCallbackService = sendCallbackService; + this.objectMapper = objectMapper; + } + + @Cacheable(value = "accountLookupCache", key = "#payeeIdentity") + public AccountLookupResponseDTO lookup(String payeeIdentity, String callbackURL, String requestId, String registeringInstitutionId, + Boolean isValidated) { + IdentityDetails identityDetails = null; + List paymentModalityDetails = new ArrayList<>(); + try { + identityDetails = masterRepository.findByPayeeIdentityAndRegisteringInstitutionId(payeeIdentity, registeringInstitutionId) + .orElseThrow(() -> new RuntimeException("Payee Identity does not exist.")); + paymentModalityDetails = paymentModalityRepository.findByMasterId(identityDetails.getMasterId()); + } catch (Exception e) { + logger.error(e.getMessage()); + try { + sendCallbackService.sendCallback(objectMapper.writeValueAsString(e.getMessage()), callbackURL); + } catch (JsonProcessingException ex) { + throw new RuntimeException(ex); + } + } + return createResponseDTO(paymentModalityDetails, identityDetails, requestId, isValidated); + } + + private AccountLookupResponseDTO createResponseDTO(List paymentModalityDetailsList, + IdentityDetails identityDetails, String requestId, Boolean isValidated) { + List paymentModalityList = new ArrayList<>(); + for (PaymentModalityDetails paymentModalityDetails : paymentModalityDetailsList) { + paymentModalityList.add(new PaymentModalityDTO(paymentModalityDetails.getModality(), + paymentModalityDetails.getDestinationAccount(), paymentModalityDetails.getInstitutionCode())); + } + return new AccountLookupResponseDTO(requestId, identityDetails.getPayeeIdentity(), paymentModalityList, isValidated); + } +} diff --git a/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/service/AccountLookupService.java b/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/service/AccountLookupService.java new file mode 100644 index 000000000..41171033f --- /dev/null +++ b/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/service/AccountLookupService.java @@ -0,0 +1,186 @@ +package org.mifos.identityaccountmapper.service; + +import static org.mifos.identityaccountmapper.util.PaymentModalityEnum.getKeyByValue; +import static org.mifos.identityaccountmapper.util.PaymentModalityEnum.getValueByKey; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import org.mifos.identityaccountmapper.data.AccountLookupResponseDTO; +import org.mifos.identityaccountmapper.data.BatchAccountLookupResponseDTO; +import org.mifos.identityaccountmapper.data.BeneficiaryDTO; +import org.mifos.identityaccountmapper.domain.IdentityDetails; +import org.mifos.identityaccountmapper.domain.PaymentModalityDetails; +import org.mifos.identityaccountmapper.exception.PayeeIdentityException; +import org.mifos.identityaccountmapper.repository.ErrorTrackingRepository; +import org.mifos.identityaccountmapper.repository.MasterRepository; +import org.mifos.identityaccountmapper.repository.PaymentModalityRepository; +import org.mifos.pheeidaccountvalidatorimpl.service.AccountValidationService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.NoSuchBeanDefinitionException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.ApplicationContext; +import org.springframework.data.util.Pair; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Service; + +@Service +public class AccountLookupService { + + private final MasterRepository masterRepository; + private final ErrorTrackingRepository errorTrackingRepository; + private final PaymentModalityRepository paymentModalityRepository; + private final SendCallbackService sendCallbackService; + private final ObjectMapper objectMapper; + private final AccountLookupReadService accountLookupReadService; + @Value("${account_validation_enabled}") + private Boolean accountValidationEnabled; + @Value("${account_validator_connector}") + private String accountValidatorConnector; + @Value("${callback_enabled}") + private Boolean callbackEnabled; + @Autowired + private ApplicationContext applicationContext; + + private static final Logger logger = LoggerFactory.getLogger(AccountLookupService.class); + private final Set paymentModalityCodes = new HashSet<>(Set.of("00", "01", "02")); + + @Autowired + public AccountLookupService(MasterRepository masterRepository, ErrorTrackingRepository errorTrackingRepository, + PaymentModalityRepository paymentModalityRepository, SendCallbackService sendCallbackService, ObjectMapper objectMapper, + AccountLookupReadService accountLookupReadService) { + this.masterRepository = masterRepository; + this.errorTrackingRepository = errorTrackingRepository; + this.paymentModalityRepository = paymentModalityRepository; + this.sendCallbackService = sendCallbackService; + this.objectMapper = objectMapper; + this.accountLookupReadService = accountLookupReadService; + } + + @Async("asyncExecutor") + public void batchAccountLookup(String callbackURL, String requestId, List beneficiariesList, + String registeringInstitutionId) { + List accountLookupList = new ArrayList<>(); + beneficiariesList.stream().forEach(beneficiary -> { + if (masterRepository.existsByPayeeIdentityAndRegisteringInstitutionId(beneficiary.getPayeeIdentity(), + registeringInstitutionId)) { + IdentityDetails identityDetails = masterRepository + .findByPayeeIdentityAndRegisteringInstitutionId(beneficiary.getPayeeIdentity(), registeringInstitutionId) + .orElseThrow(() -> PayeeIdentityException.payeeIdentityNotFound(beneficiary.getPayeeIdentity())); + PaymentModalityDetails paymentModalityDetails = paymentModalityRepository.findByMasterId(identityDetails.getMasterId()) + .get(0); + + if (accountValidationEnabled) { + AccountValidationService accountValidationService = null; + try { + accountValidationService = (AccountValidationService) this.applicationContext.getBean(accountValidatorConnector); + } catch (NoSuchBeanDefinitionException ex) { + // Handle the case when the bean is not found in the application context + } + assert accountValidationService != null; + Boolean accountValidate = accountValidationService.validateAccount(paymentModalityDetails.getDestinationAccount(), + paymentModalityDetails.getInstitutionCode(), fetchPaymentModality(paymentModalityDetails.getModality()), + beneficiary.getPayeeIdentity(), callbackURL); + if (!accountValidate) { + return; + } + } + accountLookupList.add(new BeneficiaryDTO(beneficiary.getPayeeIdentity(), paymentModalityDetails.getModality(), + paymentModalityDetails.getDestinationAccount(), paymentModalityDetails.getInstitutionCode())); + + } + }); + BatchAccountLookupResponseDTO batchAccountLookupResponse = new BatchAccountLookupResponseDTO(requestId, registeringInstitutionId, + accountLookupList); + try { + sendCallbackService.sendCallback(objectMapper.writeValueAsString(batchAccountLookupResponse), callbackURL); + } catch (JsonProcessingException e) { + throw new RuntimeException(e); + } + } + + @Async("asyncExecutor") + public void accountLookup(String callbackURL, String payeeIdentity, String paymentModality, String requestId, + String registeringInstitutionId) { + logger.info("Inside Async function"); + IdentityDetails identityDetails = masterRepository + .findByPayeeIdentityAndRegisteringInstitutionId(payeeIdentity, registeringInstitutionId) + .orElseThrow(() -> PayeeIdentityException.payeeIdentityNotFound(payeeIdentity)); + if (!identityDetails.getRegisteringInstitutionId().matches(registeringInstitutionId)) { + sendCallbackService.sendCallback("Registering Institution Id is not mapped to the Payee Identity provided in the request.", + callbackURL); + return; + } + logger.info("Before helper function"); + Boolean accountValidate = accountlookupHelper(callbackURL, payeeIdentity, paymentModality, identityDetails); + sendAccountLookupCallback(callbackURL, accountValidate, payeeIdentity, requestId, registeringInstitutionId); + } + + public Pair syncAccountLookup(String callbackURL, String payeeIdentity, String paymentModality, + String requestId, String registeringInstitutionId) throws JsonProcessingException { + logger.info("Inside sync account lookup"); + IdentityDetails identityDetails = masterRepository + .findByPayeeIdentityAndRegisteringInstitutionId(payeeIdentity, registeringInstitutionId) + .orElseThrow(() -> PayeeIdentityException.payeeIdentityNotFound(payeeIdentity)); + if (!identityDetails.getRegisteringInstitutionId().matches(registeringInstitutionId)) { + sendCallbackService.sendCallback("Registering Institution Id is not mapped to the Payee Identity provided in the request.", + callbackURL); + return Pair.of(false, null); + } + logger.info("Before helper function"); + boolean accountValidate = accountlookupHelper(callbackURL, payeeIdentity, paymentModality, identityDetails); + AccountLookupResponseDTO responseDTO = accountLookupReadService.lookup(payeeIdentity, callbackURL, requestId, + registeringInstitutionId, accountValidate); + logger.info(objectMapper.writeValueAsString(responseDTO)); + return Pair.of(accountValidate, responseDTO); + } + + public boolean accountlookupHelper(String callbackURL, String payeeIdentity, String paymentModality, IdentityDetails identityDetails) { + + PaymentModalityDetails paymentModalityDetails = paymentModalityRepository.findByMasterId(identityDetails.getMasterId()).get(0); + + if (!paymentModalityCodes.contains(paymentModality)) { + paymentModality = getValueByKey(paymentModality); + } + + AccountValidationService accountValidationService; + try { + accountValidationService = (AccountValidationService) this.applicationContext.getBean(accountValidatorConnector); + } catch (NoSuchBeanDefinitionException ex) { + logger.error("AccountValidationService bean not found: {}", accountValidatorConnector, ex); + return false; + } + + Boolean accountValidate; + try { + accountValidate = accountValidationService.validateAccount(paymentModalityDetails.getDestinationAccount(), + paymentModalityDetails.getInstitutionCode(), fetchPaymentModality(paymentModality), payeeIdentity, callbackURL); + } catch (Exception ex) { + logger.error("Error during account validation", ex); + return false; + } + + logger.info("Account validate result: {}", accountValidate); + return Boolean.TRUE.equals(accountValidate); + } + + public void sendAccountLookupCallback(String callbackURL, Boolean accountValidate, String payeeIdentity, String requestId, + String registeringInstitutionId) { + try { + sendCallbackService.sendCallback(objectMapper.writeValueAsString( + accountLookupReadService.lookup(payeeIdentity, callbackURL, requestId, registeringInstitutionId, accountValidate)), + callbackURL); + } catch (JsonProcessingException | RuntimeException e) { + logger.error(e.getMessage()); + } + } + + public String fetchPaymentModality(String paymentModality) { + return getKeyByValue(paymentModality); + } +} diff --git a/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/service/AccountLookupWorkers.java b/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/service/AccountLookupWorkers.java new file mode 100644 index 000000000..4d0c79ba0 --- /dev/null +++ b/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/service/AccountLookupWorkers.java @@ -0,0 +1,38 @@ +package org.mifos.identityaccountmapper.service; + +import static org.mifos.identityaccountmapper.util.AccountMapperEnum.WORKER_ACCOUNT_LOOKUP_CALLBACK; + +import io.camunda.zeebe.client.ZeebeClient; +import java.util.Map; +import javax.annotation.PostConstruct; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +@Component +public class AccountLookupWorkers { + + private Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Autowired + private ZeebeClient zeebeClient; + + @Value("${zeebe.client.evenly-allocated-max-jobs}") + private int workerMaxJobs; + + @PostConstruct + public void setupWorkers() { + logger.info("## generating " + WORKER_ACCOUNT_LOOKUP_CALLBACK + "zeebe worker"); + zeebeClient.newWorker().jobType(WORKER_ACCOUNT_LOOKUP_CALLBACK.getValue()).handler((client, job) -> { + logger.info("Job '{}' started from process '{}' with key {}", job.getType(), job.getBpmnProcessId(), job.getKey()); + Map existingVariables = job.getVariablesAsMap(); + + logger.debug("Zeebe variables: {}", existingVariables); + + client.newCompleteCommand(job.getKey()).send(); + }).name(WORKER_ACCOUNT_LOOKUP_CALLBACK.getValue()).maxJobsActive(workerMaxJobs).open(); + + } +} diff --git a/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/service/AddUpdatePaymentModalityService.java b/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/service/AddUpdatePaymentModalityService.java new file mode 100644 index 000000000..e32291cb6 --- /dev/null +++ b/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/service/AddUpdatePaymentModalityService.java @@ -0,0 +1,223 @@ +package org.mifos.identityaccountmapper.service; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import java.util.ArrayList; +import java.util.List; +import javax.transaction.Transactional; +import org.mifos.connector.common.channel.dto.PhErrorDTO; +import org.mifos.identityaccountmapper.data.BeneficiaryDTO; +import org.mifos.identityaccountmapper.data.CallbackRequestDTO; +import org.mifos.identityaccountmapper.data.RequestDTO; +import org.mifos.identityaccountmapper.domain.ErrorTracking; +import org.mifos.identityaccountmapper.domain.IdentityDetails; +import org.mifos.identityaccountmapper.domain.PaymentModalityDetails; +import org.mifos.identityaccountmapper.exception.PayeeIdentityException; +import org.mifos.identityaccountmapper.repository.ErrorTrackingRepository; +import org.mifos.identityaccountmapper.repository.MasterRepository; +import org.mifos.identityaccountmapper.repository.PaymentModalityRepository; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.cache.annotation.CacheEvict; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Service; + +@Service +public class AddUpdatePaymentModalityService { + + private final MasterRepository masterRepository; + private final ErrorTrackingRepository errorTrackingRepository; + private final PaymentModalityRepository paymentModalityRepository; + private final SendCallbackService sendCallbackService; + private final ObjectMapper objectMapper; + private static final Logger logger = LoggerFactory.getLogger(AddUpdatePaymentModalityService.class); + @Autowired + private BeneficiaryValidator beneficiaryValidator; + + @Autowired + public AddUpdatePaymentModalityService(MasterRepository masterRepository, ErrorTrackingRepository errorTrackingRepository, + PaymentModalityRepository paymentModalityRepository, SendCallbackService sendCallbackService, ObjectMapper objectMapper) { + this.masterRepository = masterRepository; + this.errorTrackingRepository = errorTrackingRepository; + this.paymentModalityRepository = paymentModalityRepository; + this.sendCallbackService = sendCallbackService; + this.objectMapper = objectMapper; + } + + @Async("asyncExecutor") + public void addPaymentModality(String callbackURL, RequestDTO requestBody, String registeringInstitutionId) { + List beneficiaryList = requestBody.getBeneficiaries(); + List errorTrackingsList = new ArrayList<>(); + + validateAndAddPaymentModality(beneficiaryList, requestBody, errorTrackingsList, registeringInstitutionId); + sendCallback(errorTrackingsList, requestBody.getRequestID(), callbackURL); + } + + public PhErrorDTO updatePaymentModality(String callbackURL, RequestDTO requestBody, String registeringInstitutionId) { + PhErrorDTO phErrorDTO = beneficiaryValidator.validateCreateBeneficiary(requestBody); + if (phErrorDTO == null) { + List beneficiaryList = requestBody.getBeneficiaries(); + List errorTrackingsList = new ArrayList<>(); + + validateAndUpdatePaymentModality(beneficiaryList, requestBody, errorTrackingsList, registeringInstitutionId); + CallbackRequestDTO callbackRequest = sendCallbackService.createRequestBody(errorTrackingsList, requestBody.getRequestID()); + + try { + sendCallbackService.sendCallback(objectMapper.writeValueAsString(callbackRequest), callbackURL); + } catch (JsonProcessingException e) { + logger.error(e.getMessage()); + } + + } + return phErrorDTO; + } + + private void sendCallback(List errorTrackingList, String requestId, String callbackURL) { + CallbackRequestDTO callbackRequest = sendCallbackService.createRequestBody(errorTrackingList, requestId); + + try { + sendCallbackService.sendCallback(objectMapper.writeValueAsString(callbackRequest), callbackURL); + } catch (JsonProcessingException e) { + throw new RuntimeException(e); + } + } + + private void validateAndUpdatePaymentModality(List beneficiaryList, RequestDTO request, + List errorTrackingList, String registeringInstitutionId) { + beneficiaryList.stream().forEach(beneficiary -> { + String requestID = request.getRequestID(); + Boolean beneficiaryExists = validateBeneficiary(beneficiary, requestID, errorTrackingList, registeringInstitutionId); + updateModalityDetails(beneficiary, beneficiaryExists, errorTrackingList, requestID, beneficiary.getPayeeIdentity(), + registeringInstitutionId); + }); + } + + @Transactional + @CacheEvict(value = "accountLookupCache", key = "#payeeIdentity") + public void updateModalityDetails(BeneficiaryDTO beneficiary, Boolean beneficiaryExists, List errorTrackingList, + String requestID, String payeeIdentity, String registeringInstitutionId) { + try { + if (beneficiaryExists) { + PaymentModalityDetails paymentModality = fetchPaymentModalityDetails(beneficiary, registeringInstitutionId); + + paymentModality.setModality(beneficiary.getPaymentModality()); + if (beneficiary.getFinancialAddress() != null) { + paymentModality.setDestinationAccount(beneficiary.getFinancialAddress()); + } + if (beneficiary.getBankingInstitutionCode() != null) { + paymentModality.setInstitutionCode(beneficiary.getBankingInstitutionCode()); + } + paymentModalityRepository.save(paymentModality); + } + } catch (Exception e) { + saveError(requestID, beneficiary, e.getMessage(), errorTrackingList); + logger.error(e.getMessage()); + } + } + + private void validateAndAddPaymentModality(List beneficiaryList, RequestDTO request, + List errorTrackingList, String registeringInstitutionId) { + beneficiaryList.stream().forEach(beneficiary -> { + String requestID = request.getRequestID(); + Boolean beneficiaryExists = validateBeneficiary(beneficiary, requestID, errorTrackingList, registeringInstitutionId); + addModalityDetails(beneficiary, beneficiaryExists, errorTrackingList, requestID, beneficiary.getPayeeIdentity(), + registeringInstitutionId); + }); + } + + @Transactional + @CacheEvict(value = "accountLookupCache", key = "#payeeIdentity") + public void addModalityDetails(BeneficiaryDTO beneficiary, Boolean beneficiaryExists, List errorTrackingList, + String requestID, String payeeIdentity, String registeringInstitutionId) { + try { + if (beneficiaryExists) { + PaymentModalityDetails paymentModality = fetchPaymentModalityDetails(beneficiary, registeringInstitutionId); + + if (!paymentModalityExist(paymentModality, requestID, beneficiary, errorTrackingList)) { + paymentModality.setModality(beneficiary.getPaymentModality()); + if (beneficiary.getFinancialAddress() != null) { + paymentModality.setDestinationAccount(beneficiary.getFinancialAddress()); + } + if (beneficiary.getBankingInstitutionCode() != null) { + paymentModality.setInstitutionCode(beneficiary.getBankingInstitutionCode()); + } + paymentModalityRepository.save(paymentModality); + } + } + } catch (Exception e) { + saveError(requestID, beneficiary, e.getMessage(), errorTrackingList); + logger.error(e.getMessage()); + } + } + + private PaymentModalityDetails fetchPaymentModalityDetails(BeneficiaryDTO beneficiary, String registeringInstitutionId) { + IdentityDetails identityDetails = null; + try { + identityDetails = masterRepository + .findByPayeeIdentityAndRegisteringInstitutionId(beneficiary.getPayeeIdentity(), registeringInstitutionId) + .orElseThrow(() -> PayeeIdentityException.payeeIdentityNotFound(beneficiary.getPayeeIdentity())); + } catch (PayeeIdentityException e) { + logger.error(e.getMessage()); + } + return paymentModalityRepository.findByMasterId(identityDetails.getMasterId()).get(0); + } + + @Transactional + private Boolean validateBeneficiary(BeneficiaryDTO beneficiary, String requestID, List errorTrackingList, + String registeringInstitutionId) { + Boolean beneficiaryExists = masterRepository.existsByPayeeIdentityAndRegisteringInstitutionId(beneficiary.getPayeeIdentity(), + registeringInstitutionId); + if (!beneficiaryExists) { + saveError(requestID, beneficiary, "Beneficiary is not registered", errorTrackingList); + } else if (!beneficiaryValidator.validateBankingInstitutionCode(beneficiary.getPaymentModality(), + beneficiary.getBankingInstitutionCode())) { + ErrorTracking errorTracking = new ErrorTracking(requestID, beneficiary.getPayeeIdentity(), beneficiary.getPaymentModality(), + "Banking Institution Code Invalid"); + errorTrackingList.add(errorTracking); + beneficiaryExists = false; + + } else if (!beneficiaryValidator.validatePaymentModality(beneficiary.getPaymentModality())) { + ErrorTracking errorTracking = new ErrorTracking(requestID, beneficiary.getPayeeIdentity(), beneficiary.getPaymentModality(), + "Payment Modality Invalid"); + errorTrackingList.add(errorTracking); + beneficiaryExists = false; + } else if (!beneficiaryValidator.validateFinancialAddress(beneficiary.getFinancialAddress())) { + ErrorTracking errorTracking = new ErrorTracking(requestID, beneficiary.getPayeeIdentity(), beneficiary.getPaymentModality(), + "Financial Address Invalid"); + errorTrackingList.add(errorTracking); + beneficiaryExists = false; + } else { + IdentityDetails identityDetails = masterRepository + .findByPayeeIdentityAndRegisteringInstitutionId(beneficiary.getPayeeIdentity(), registeringInstitutionId) + .orElseThrow(() -> PayeeIdentityException.payeeIdentityNotFound(beneficiary.getPayeeIdentity())); + if (!identityDetails.getRegisteringInstitutionId().equals(registeringInstitutionId)) { + saveError(requestID, beneficiary, "Registering Institution Id Mismatch", errorTrackingList); + return false; + } + } + return beneficiaryExists; + } + + @Transactional + private Boolean paymentModalityExist(PaymentModalityDetails paymentModality, String requestID, BeneficiaryDTO beneficiary, + List errorTrackingList) { + if (paymentModality.getModality() != null) { + saveError(requestID, beneficiary, "Beneficiary already registered with other Modality", errorTrackingList); + return true; + } + return false; + } + + @Transactional + private void saveError(String requestID, BeneficiaryDTO beneficiary, String errorDescription, List errorTrackingList) { + try { + ErrorTracking errorTracking = new ErrorTracking(requestID, beneficiary.getPayeeIdentity(), beneficiary.getPaymentModality(), + errorDescription); + errorTrackingList.add(errorTracking); + this.errorTrackingRepository.save(errorTracking); + } catch (Exception e) { + logger.error(e.getMessage()); + } + } +} diff --git a/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/service/BeneficiaryValidator.java b/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/service/BeneficiaryValidator.java new file mode 100644 index 000000000..176d7940f --- /dev/null +++ b/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/service/BeneficiaryValidator.java @@ -0,0 +1,88 @@ +package org.mifos.identityaccountmapper.service; + +import static org.mifos.connector.common.exception.PaymentHubError.ExtValidationError; +import static org.mifos.identityaccountmapper.util.PaymentModalityEnum.ACCOUNT_ID; +import static org.mifos.identityaccountmapper.util.PaymentModalityEnum.MSISDN; +import static org.mifos.identityaccountmapper.util.PaymentModalityEnum.VIRTUAL_ADDRESS; +import static org.mifos.identityaccountmapper.util.PaymentModalityEnum.VOUCHER; +import static org.mifos.identityaccountmapper.util.PaymentModalityEnum.WALLET_ID; + +import org.mifos.connector.common.channel.dto.PhErrorDTO; +import org.mifos.connector.common.exception.PaymentHubErrorCategory; +import org.mifos.connector.common.validation.ValidatorBuilder; +import org.mifos.identityaccountmapper.data.RequestDTO; +import org.mifos.identityaccountmapper.util.IdentityMapperValidatorsEnum; +import org.springframework.stereotype.Service; + +@Service +public class BeneficiaryValidator { + + private static final String resource = "beneficiaryValidator"; + private static final String requestId = "requestID"; + private static final int expectedRequestIdLength = 12; + private static final String payeeIdentity = "payeeIdentity"; + private static final int expectedPayeeIdentityLength = 20; + private static final String financialAddress = "financialAddress"; + private static final int expectedFinancialAddressLength = 12; + private static final String bankingInstitutionCode = "bankingInstitutionCode"; + private static final int expectedBankingInstitutionCodeLength = 11; + private static final String paymentModality = "paymentModality"; + private static final int expectedPaymentModalityLength = 2; + + public PhErrorDTO validateCreateBeneficiary(RequestDTO request) { + final ValidatorBuilder validatorBuilder = new ValidatorBuilder(); + validatorBuilder.reset().resource(resource).parameter(requestId).value(request.getRequestID()) + .isNullWithFailureCode(IdentityMapperValidatorsEnum.INVALID_REQUEST_ID).validateFieldMaxLengthWithFailureCodeAndErrorParams( + expectedRequestIdLength, IdentityMapperValidatorsEnum.INVALID_REQUEST_ID_LENGTH); + + if (validatorBuilder.hasError()) { + validatorBuilder.errorCategory(PaymentHubErrorCategory.Validation.toString()) + .errorCode(IdentityMapperValidatorsEnum.IDENTITY_MAPPER_SCHEMA_VALIDATION_ERROR.getCode()) + .errorDescription(IdentityMapperValidatorsEnum.IDENTITY_MAPPER_SCHEMA_VALIDATION_ERROR.getMessage()) + .developerMessage(IdentityMapperValidatorsEnum.IDENTITY_MAPPER_SCHEMA_VALIDATION_ERROR.getMessage()) + .defaultUserMessage(IdentityMapperValidatorsEnum.IDENTITY_MAPPER_SCHEMA_VALIDATION_ERROR.getMessage()); + + PhErrorDTO.PhErrorDTOBuilder phErrorDTOBuilder = new PhErrorDTO.PhErrorDTOBuilder(ExtValidationError.getErrorCode()); + phErrorDTOBuilder.fromValidatorBuilder(validatorBuilder); + return phErrorDTOBuilder.build(); + } + + return null; + } + + public Boolean validatePaymentModality(String paymentModality) { + if (paymentModality != null && !(paymentModality.equals(ACCOUNT_ID.getValue()) || paymentModality.equals(MSISDN.getValue()) + || paymentModality.equals(VIRTUAL_ADDRESS.getValue()) || paymentModality.equals(WALLET_ID.getValue()) + || paymentModality.equals(VOUCHER.getValue()))) { + return false; + } + return true; + + } + + public Boolean validateBankingInstitutionCode(String paymentModality, String bankingInstitutionCode) { + if ((paymentModality != null + && (paymentModality.equals(ACCOUNT_ID.getValue()) || paymentModality.equals(MSISDN.getValue()) + || paymentModality.equals(WALLET_ID.getValue())) + && ((bankingInstitutionCode == null || bankingInstitutionCode.isEmpty()) + || ((bankingInstitutionCode != null && bankingInstitutionCode.length() > 11))))) { + return false; + } + return true; + + } + + public Boolean validatePayeeIdentity(String payeeIdentity) { + if (payeeIdentity == null || payeeIdentity.isEmpty() || (!payeeIdentity.isEmpty() && payeeIdentity.length() > 20)) { + return false; + } + return true; + } + + public Boolean validateFinancialAddress(String financialAddress) { + if (financialAddress != null && financialAddress.length() > 30) { + return false; + } + return true; + } +} diff --git a/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/service/FetchBeneficiariesService.java b/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/service/FetchBeneficiariesService.java new file mode 100644 index 000000000..5b651b399 --- /dev/null +++ b/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/service/FetchBeneficiariesService.java @@ -0,0 +1,62 @@ +package org.mifos.identityaccountmapper.service; + +import java.util.List; +import org.mifos.identityaccountmapper.data.FetchBeneficiariesResponseDTO; +import org.mifos.identityaccountmapper.domain.IdentityDetails; +import org.mifos.identityaccountmapper.domain.PaymentModalityDetails; +import org.mifos.identityaccountmapper.exception.PayeeIdentityException; +import org.mifos.identityaccountmapper.repository.MasterRepository; +import org.mifos.identityaccountmapper.repository.PaymentModalityRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; +import org.springframework.stereotype.Service; + +@Service +public class FetchBeneficiariesService { + + private final MasterRepository masterRepository; + private final PaymentModalityRepository paymentModalityRepository; + + @Autowired + public FetchBeneficiariesService(MasterRepository masterRepository, PaymentModalityRepository paymentModalityRepository) { + this.masterRepository = masterRepository; + this.paymentModalityRepository = paymentModalityRepository; + } + + public FetchBeneficiariesResponseDTO fetchBeneficiary(String payeeIdentity, String registeringInstitutionId) { + IdentityDetails identityDetails = new IdentityDetails(); + PaymentModalityDetails paymentModalityDetails = new PaymentModalityDetails(); + if (masterRepository.existsByPayeeIdentityAndRegisteringInstitutionId(payeeIdentity, registeringInstitutionId)) { + identityDetails = masterRepository.findByPayeeIdentityAndRegisteringInstitutionId(payeeIdentity, registeringInstitutionId) + .orElseThrow(() -> PayeeIdentityException.payeeIdentityNotFound(payeeIdentity)); + paymentModalityDetails = paymentModalityRepository.findByMasterId(identityDetails.getMasterId()).get(0); + } + return new FetchBeneficiariesResponseDTO(registeringInstitutionId, payeeIdentity, paymentModalityDetails.getModality(), + paymentModalityDetails.getDestinationAccount(), paymentModalityDetails.getInstitutionCode()); + } + + public Page fetchAllBeneficiaries(int page, int pageSize, String registeringInstitutionId) { + Pageable pageRequest = PageRequest.of(page, pageSize); + + Page identityPage = masterRepository.findByRegisteringInstitutionId(registeringInstitutionId, pageRequest); + + return identityPage.map(identityDetails -> { + PaymentModalityDetails paymentModalityDetails = null; + if (identityDetails != null) { + List paymentModalities = paymentModalityRepository.findByMasterId(identityDetails.getMasterId()); + if (!paymentModalities.isEmpty()) { + paymentModalityDetails = paymentModalities.get(0); + } + } + + return new FetchBeneficiariesResponseDTO(registeringInstitutionId, + identityDetails != null ? identityDetails.getPayeeIdentity() : null, + paymentModalityDetails != null ? paymentModalityDetails.getModality() : null, + paymentModalityDetails != null ? paymentModalityDetails.getDestinationAccount() : null, + paymentModalityDetails != null ? paymentModalityDetails.getInstitutionCode() : null); + }); + } + +} diff --git a/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/service/RegisterBeneficiaryService.java b/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/service/RegisterBeneficiaryService.java new file mode 100644 index 000000000..5db7b568f --- /dev/null +++ b/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/service/RegisterBeneficiaryService.java @@ -0,0 +1,140 @@ +package org.mifos.identityaccountmapper.service; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.util.ArrayList; +import java.util.List; +import javax.transaction.Transactional; +import org.mifos.connector.common.channel.dto.PhErrorDTO; +import org.mifos.identityaccountmapper.data.BeneficiaryDTO; +import org.mifos.identityaccountmapper.data.CallbackRequestDTO; +import org.mifos.identityaccountmapper.data.RequestDTO; +import org.mifos.identityaccountmapper.domain.ErrorTracking; +import org.mifos.identityaccountmapper.domain.IdentityDetails; +import org.mifos.identityaccountmapper.domain.PaymentModalityDetails; +import org.mifos.identityaccountmapper.repository.ErrorTrackingRepository; +import org.mifos.identityaccountmapper.repository.MasterRepository; +import org.mifos.identityaccountmapper.repository.PaymentModalityRepository; +import org.mifos.identityaccountmapper.util.UniqueIDGenerator; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +@Service +public class RegisterBeneficiaryService { + + private final MasterRepository masterRepository; + private final ErrorTrackingRepository errorTrackingRepository; + private final PaymentModalityRepository paymentModalityRepository; + private final SendCallbackService sendCallbackService; + private final ObjectMapper objectMapper; + private static final Logger logger = LoggerFactory.getLogger(RegisterBeneficiaryService.class); + @Autowired + private BeneficiaryValidator beneficiaryValidator; + + @Autowired + public RegisterBeneficiaryService(MasterRepository masterRepository, ErrorTrackingRepository errorTrackingRepository, + PaymentModalityRepository paymentModalityRepository, SendCallbackService sendCallbackService, ObjectMapper objectMapper) { + this.masterRepository = masterRepository; + this.errorTrackingRepository = errorTrackingRepository; + this.paymentModalityRepository = paymentModalityRepository; + this.sendCallbackService = sendCallbackService; + this.objectMapper = objectMapper; + } + + public PhErrorDTO registerBeneficiary(String callbackURL, RequestDTO requestBody, String registeringInstitutionId) { + PhErrorDTO phErrorDTO = beneficiaryValidator.validateCreateBeneficiary(requestBody); + if (phErrorDTO == null) { + List beneficiaryList = requestBody.getBeneficiaries(); + List errorTrackingsList = new ArrayList<>(); + + validateAndSaveBeneficiaries(beneficiaryList, requestBody, errorTrackingsList, registeringInstitutionId); + CallbackRequestDTO callbackRequest = sendCallbackService.createRequestBody(errorTrackingsList, requestBody.getRequestID()); + + try { + sendCallbackService.sendCallback(objectMapper.writeValueAsString(callbackRequest), callbackURL); + } catch (JsonProcessingException e) { + logger.error(e.getMessage()); + } + } + return phErrorDTO; + } + + @Transactional + private void validateAndSaveBeneficiaries(List beneficiariesList, RequestDTO request, + List errorTrackingList, String registeringInstitutionId) { + beneficiariesList.stream().forEach(beneficiary -> { + String requestID = request.getRequestID(); + Boolean beneficiaryExists = validateBeneficiary(beneficiary, requestID, errorTrackingList, registeringInstitutionId); + try { + if (!beneficiaryExists) { + String masterId = UniqueIDGenerator.generateUniqueNumber(20); + IdentityDetails identityDetails = new IdentityDetails(masterId, registeringInstitutionId, + LocalDateTime.now(ZoneId.systemDefault()), beneficiary.getPayeeIdentity()); + this.masterRepository.save(identityDetails); + PaymentModalityDetails paymentModalityDetails = new PaymentModalityDetails(masterId, beneficiary.getFinancialAddress(), + beneficiary.getPaymentModality(), beneficiary.getBankingInstitutionCode()); + this.paymentModalityRepository.save(paymentModalityDetails); + } + } catch (RuntimeException e) { + try { + ErrorTracking errorTracking = new ErrorTracking(requestID, beneficiary.getPayeeIdentity(), + beneficiary.getPaymentModality(), e.getMessage()); + this.errorTrackingRepository.save(errorTracking); + } catch (RuntimeException ex) { + logger.error(e.getMessage()); + } catch (Exception e2) { + logger.error(e2.getMessage()); + } + } catch (Exception e) { + logger.error(e.getMessage()); + } + }); + } + + @Transactional + private Boolean validateBeneficiary(BeneficiaryDTO beneficiary, String requestID, List errorTrackingList, + String registeringInstitutionId) { + Boolean beneficiaryExists = masterRepository.existsByPayeeIdentityAndRegisteringInstitutionId(beneficiary.getPayeeIdentity(), + registeringInstitutionId); + try { + if (beneficiaryExists) { + ErrorTracking errorTracking = new ErrorTracking(requestID, beneficiary.getPayeeIdentity(), beneficiary.getPaymentModality(), + "Beneficiary already registered"); + errorTrackingList.add(errorTracking); + this.errorTrackingRepository.save(errorTracking); + } else { + logger.info("payee Identity {} {}", beneficiary.getPayeeIdentity(), beneficiary.getPayeeIdentity().length()); + if (!beneficiaryValidator.validatePayeeIdentity(beneficiary.getPayeeIdentity())) { + ErrorTracking errorTracking = new ErrorTracking(requestID, beneficiary.getPayeeIdentity(), + beneficiary.getPaymentModality(), "Payee Identity Invalid"); + errorTrackingList.add(errorTracking); + beneficiaryExists = true; + } else if (!beneficiaryValidator.validatePayeeIdentity(beneficiary.getPayeeIdentity())) { + ErrorTracking errorTracking = new ErrorTracking(requestID, beneficiary.getPayeeIdentity(), + beneficiary.getPaymentModality(), "Payee Modality Invalid"); + errorTrackingList.add(errorTracking); + beneficiaryExists = true; + } else if (!beneficiaryValidator.validateBankingInstitutionCode(beneficiary.getPaymentModality(), + beneficiary.getBankingInstitutionCode())) { + ErrorTracking errorTracking = new ErrorTracking(requestID, beneficiary.getPayeeIdentity(), + beneficiary.getPaymentModality(), "Banking Institution Code Invalid"); + errorTrackingList.add(errorTracking); + beneficiaryExists = true; + + } else if (!beneficiaryValidator.validateFinancialAddress(beneficiary.getFinancialAddress())) { + ErrorTracking errorTracking = new ErrorTracking(requestID, beneficiary.getPayeeIdentity(), + beneficiary.getPaymentModality(), "Financial Address Invalid"); + errorTrackingList.add(errorTracking); + beneficiaryExists = true; + } + } + } catch (Exception e) { + logger.error(e.getMessage()); + } + return beneficiaryExists; + } +} diff --git a/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/service/SendCallbackService.java b/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/service/SendCallbackService.java new file mode 100644 index 000000000..fc30a0560 --- /dev/null +++ b/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/service/SendCallbackService.java @@ -0,0 +1,47 @@ +package org.mifos.identityaccountmapper.service; + +import io.restassured.RestAssured; +import io.restassured.builder.RequestSpecBuilder; +import io.restassured.http.ContentType; +import io.restassured.response.Response; +import io.restassured.specification.RequestSpecification; +import java.util.ArrayList; +import java.util.List; +import org.mifos.identityaccountmapper.data.CallbackRequestDTO; +import org.mifos.identityaccountmapper.data.FailedCaseDTO; +import org.mifos.identityaccountmapper.domain.ErrorTracking; +import org.mifos.identityaccountmapper.util.UniqueIDGenerator; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Service; + +@Service +public class SendCallbackService { + + private static final Logger logger = LoggerFactory.getLogger(SendCallbackService.class); + + public void sendCallback(String body, String callbackURL) { + logger.debug(body); + logger.debug(callbackURL); + RequestSpecification requestSpec = new RequestSpecBuilder().build(); + requestSpec.relaxedHTTPSValidation(); + Response response = RestAssured.given(requestSpec).baseUri(callbackURL).header("Content-Type", ContentType.JSON).body(body).when() + .put(); + + String responseBody = response.getBody().asString(); + logger.debug(responseBody); + int responseCode = response.getStatusCode(); + logger.debug(String.valueOf(responseCode)); + } + + public CallbackRequestDTO createRequestBody(List errorTrackingList, String requestId) { + List failedCaseList = new ArrayList<>(); + int numberFailedCases = 0; + for (ErrorTracking error : errorTrackingList) { + failedCaseList.add(new FailedCaseDTO(error.getPayeeIdentity(), error.getModality(), error.getErrorDescription())); + numberFailedCases++; + } + + return new CallbackRequestDTO(UniqueIDGenerator.generateUniqueNumber(12), requestId, numberFailedCases, failedCaseList); + } +} diff --git a/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/util/AbstractApplicationConfiguration.java b/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/util/AbstractApplicationConfiguration.java new file mode 100644 index 000000000..93aaf31b2 --- /dev/null +++ b/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/util/AbstractApplicationConfiguration.java @@ -0,0 +1,33 @@ +package org.mifos.identityaccountmapper.util; + +import java.util.concurrent.Executor; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.scheduling.annotation.EnableAsync; +import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; + +@Configuration +@EnableAsync +@ComponentScan(basePackages = "org.mifos.identityaccountmapper") +public abstract class AbstractApplicationConfiguration { + + @Value("${async.core-pool-size}") + public Integer corePoolSize; + @Value("${async.max-pool-size}") + public Integer maxPoolSize; + @Value("${async.queue-capacity}") + public Integer queueCapacity; + + @Bean(name = "asyncExecutor") + public Executor asyncExecutor() { + ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); + executor.setCorePoolSize(corePoolSize); + executor.setMaxPoolSize(maxPoolSize); + executor.setQueueCapacity(queueCapacity); + executor.setThreadNamePrefix("AsyncThread-"); + executor.initialize(); + return executor; + } +} diff --git a/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/util/AccountMapperEnum.java b/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/util/AccountMapperEnum.java new file mode 100644 index 000000000..02bdd9a63 --- /dev/null +++ b/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/util/AccountMapperEnum.java @@ -0,0 +1,18 @@ +package org.mifos.identityaccountmapper.util; + +public enum AccountMapperEnum { + + SUCCESS_RESPONSE_CODE("00"), FAILED_RESPONSE_CODE("01"), SUCCESS_RESPONSE_MESSAGE( + "Request successfully received by Pay-BB"), FAILED_RESPONSE_MESSAGE( + "Request not acknowledged by Pay-BB"), WORKER_ACCOUNT_LOOKUP_CALLBACK("mojaloop-party-lookup-callback"); + + private final String value; + + AccountMapperEnum(String value) { + this.value = value; + } + + public String getValue() { + return this.value; + } +} diff --git a/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/util/CacheConfig.java b/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/util/CacheConfig.java new file mode 100644 index 000000000..72ff2e42d --- /dev/null +++ b/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/util/CacheConfig.java @@ -0,0 +1,52 @@ +package org.mifos.identityaccountmapper.util; + +import net.sf.ehcache.Cache; +import net.sf.ehcache.CacheManager; +import net.sf.ehcache.config.CacheConfiguration; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.cache.annotation.CachingConfigurerSupport; +import org.springframework.cache.annotation.EnableCaching; +import org.springframework.cache.ehcache.EhCacheCacheManager; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +@EnableCaching +public class CacheConfig extends CachingConfigurerSupport { + + @Value("${spring.cache.time_to_live}") + private Integer ttl; + @Value("${spring.cache.time_to_idle}") + private Integer tti; + @Value("${spring.cache.max_entries_heap}") + private Integer maxEntriesHeap; + @Value("${spring.cache.max_byte_off_heap}") + private Long maxByteOffHeap; + @Value("${spring.cache.max_byte_disk}") + private Long maxByteDisk; + + @Bean + public CacheManager ehCacheManager() { + CacheConfiguration cacheConfig = new CacheConfiguration(); + cacheConfig.setName("accountLookupCache"); + cacheConfig.setEternal(false); + cacheConfig.setTimeToIdleSeconds(tti); + cacheConfig.setTimeToLiveSeconds(ttl); + cacheConfig.setMaxEntriesLocalHeap(maxEntriesHeap); + cacheConfig.setMaxBytesLocalOffHeap(maxByteOffHeap); + cacheConfig.setMaxBytesLocalDisk(maxByteDisk); + cacheConfig.overflowToOffHeap(false); + + Cache cache = new Cache(cacheConfig); + + CacheManager cacheManager = new CacheManager(); + cacheManager.addCache(cache); + + return cacheManager; + } + + @Bean + public EhCacheCacheManager cacheCacheManager() { + return new EhCacheCacheManager(ehCacheManager()); + } +} diff --git a/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/util/Config.java b/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/util/Config.java new file mode 100644 index 000000000..0a5f9c937 --- /dev/null +++ b/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/util/Config.java @@ -0,0 +1,8 @@ +package org.mifos.identityaccountmapper.util; + +import org.springframework.cache.annotation.EnableCaching; +import org.springframework.context.annotation.Configuration; + +@Configuration +@EnableCaching +public class Config {} diff --git a/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/util/IdentityMapperValidatorsEnum.java b/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/util/IdentityMapperValidatorsEnum.java new file mode 100644 index 000000000..d49a8f585 --- /dev/null +++ b/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/util/IdentityMapperValidatorsEnum.java @@ -0,0 +1,62 @@ +package org.mifos.identityaccountmapper.util; + +import org.mifos.connector.common.exception.PaymentHubErrorCategory; +import org.mifos.connector.common.validation.ValidationCodeType; + +public enum IdentityMapperValidatorsEnum implements ValidationCodeType { + + IDENTITY_MAPPER_VALIDATION_ERROR("error.msg.header.validation.errors", + "The headers are invalid"), IDENTITY_MAPPER_SCHEMA_VALIDATION_ERROR("error.msg.schema.validation.errors", + "The request is invalid"), INVALID_CALLBACK_URL("error.msg.schema.callback.url.cannot.be.null.or.empty", + "Callback URL cannot be null or empty"), INVALID_CALLBACK_URL_LENGTH( + "error.msg.schema.callback.url.length.is.invalid", + "Callback URL length is invalid"), INVALID_REGISTERING_INSTITUTION_ID( + "error.msg.schema.registering.institution.id.cannot.be.null.or.empty", + "Registering Institution Id cannot be null or empty"), INVALID_REGISTERING_INSTITUTION_ID_LENGTH( + "error.msg.schema.registering.institution.id.length.is.invalid", + "Registering Institution Id cannot length is invalid"), INVALID_REQUEST_ID( + "error.msg.schema.request.id.cannot.be.null.or.empty", + "Request Id cannot be null or empty"), INVALID_REQUEST_ID_LENGTH( + "error.msg.schema.request.id.length.is.invalid", + "Request Id length is invalid"), INVALID_PAYEE_IDENTITY( + "error.msg.schema.payee.identity.cannot.be.null.or.empty", + "Payee Identity cannot be null or empty"), INVALID_PAYEE_IDENTITY_LENGTH( + "error.msg.schema.payee.identity.length.is.invalid", + "Payee Identity length is invalid"), + + INVALID_BANKING_INSTITUTION_CODE("error.msg.schema.banking.institution.code.cannot.be.null.or.empty", + "Banking Institution Code cannot be null or empty"), INVALID_BANKING_INSTITUTION_CODE_LENGTH( + "error.msg.schema.banking.institution.code.length.is.invalid", + "Banking Institution Code length is invalid"), INVALID_FINANCIAL_ADDRESS( + "error.msg.schema.financial.address.cannot.be.null.or.empty", + "Financial Address cannot be null or empty"), INVALID_FINANCIAL_ADDRESS_LENGTH( + "error.msg.schema.financial.address.length.is.invalid", + "Financial Address length is invalid"), INVALID_PAYMENT_MODALITY( + "error.msg.schema.payment.modality.cannot.be.null.or.empty", + "Payment Modality cannot be null or empty"), INVALID_PAYMENT_MODALITY_VALUE( + "error.msg.schema.payment.modality.is.invalid", + "Payment Modality is invalid"), IDENTITY_MAPPER_HEADER_VALIDATION_ERROR( + "error.msg.header.validation.errors", "The headers are invalid"); + + private final String code; + private final String category; + private final String message; + + IdentityMapperValidatorsEnum(String code, String message) { + this.code = code; + this.category = PaymentHubErrorCategory.Validation.toString(); + this.message = message; + } + + public String getCode() { + return this.code; + } + + public String getCategory() { + return this.category; + } + + public String getMessage() { + return message; + } +} diff --git a/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/util/PaymentModalityEnum.java b/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/util/PaymentModalityEnum.java new file mode 100644 index 000000000..ee6fe3b00 --- /dev/null +++ b/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/util/PaymentModalityEnum.java @@ -0,0 +1,34 @@ +package org.mifos.identityaccountmapper.util; + +public enum PaymentModalityEnum { + + ACCOUNT_ID("00"), MSISDN("01"), VIRTUAL_ADDRESS("02"), WALLET_ID("03"), VOUCHER("04"); + + private final String value; + + PaymentModalityEnum(String value) { + this.value = value; + } + + public static String getValueByKey(String key) { + for (PaymentModalityEnum pair : values()) { + if (pair.name().equalsIgnoreCase(key)) { + return pair.getValue(); + } + } + return null; + } + + public static String getKeyByValue(String value) { + for (PaymentModalityEnum pair : values()) { + if (pair.getValue().equalsIgnoreCase(value)) { + return pair.name(); + } + } + return null; + } + + public String getValue() { + return this.value; + } +} diff --git a/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/util/UniqueIDGenerator.java b/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/util/UniqueIDGenerator.java new file mode 100644 index 000000000..706a9391c --- /dev/null +++ b/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/util/UniqueIDGenerator.java @@ -0,0 +1,42 @@ +package org.mifos.identityaccountmapper.util; + +import java.nio.charset.Charset; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.Random; + +public final class UniqueIDGenerator { + + private UniqueIDGenerator() {} + + public static String generateUniqueNumber(int length) { + Random rand = new Random(); + long timestamp = System.currentTimeMillis(); + long randomLong = rand.nextLong(100000000); + String uniqueNumber = timestamp + "" + randomLong; + return uniqueNumber.substring(0, length); + } + + public static String generateUniqueID(int length) { + try { + MessageDigest md = MessageDigest.getInstance("SHA-256"); + Random rand = new Random(); + long timestamp = System.currentTimeMillis(); + int randomInt = rand.nextInt(100000); + String input = timestamp + "" + randomInt; + byte[] hash = md.digest(input.getBytes(Charset.defaultCharset())); + String hashString = bytesToHex(hash); + return hashString.substring(0, length); + } catch (NoSuchAlgorithmException e) { + throw new RuntimeException(e); + } + } + + private static String bytesToHex(byte[] bytes) { + StringBuilder sb = new StringBuilder(); + for (byte b : bytes) { + sb.append(String.format("%02x", b)); + } + return sb.toString(); + } +} diff --git a/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/zeebe/ZeebeClientConfiguration.java b/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/zeebe/ZeebeClientConfiguration.java new file mode 100644 index 000000000..e74cb1ebf --- /dev/null +++ b/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/zeebe/ZeebeClientConfiguration.java @@ -0,0 +1,27 @@ +package org.mifos.identityaccountmapper.zeebe; + +import io.camunda.zeebe.client.ZeebeClient; +import java.time.Duration; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class ZeebeClientConfiguration { + + @Value("${zeebe.broker.contactpoint}") + private String zeebeBrokerContactpoint; + + @Value("${zeebe.client.max-execution-threads}") + private int zeebeClientMaxThreads; + + @Value("${zeebe.client.poll-interval}") + private int zeebeClientPollInterval; + + @Bean + public ZeebeClient setup() { + return ZeebeClient.newClientBuilder().gatewayAddress(zeebeBrokerContactpoint).usePlaintext() + .defaultJobPollInterval(Duration.ofMillis(zeebeClientPollInterval)).defaultJobWorkerMaxJobsActive(2000) + .numJobWorkerExecutionThreads(zeebeClientMaxThreads).build(); + } +} diff --git a/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/zeebe/ZeebeVariables.java b/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/zeebe/ZeebeVariables.java new file mode 100644 index 000000000..5f53a1e8c --- /dev/null +++ b/ph-ee-identity-account-mapper/src/main/java/org/mifos/identityaccountmapper/zeebe/ZeebeVariables.java @@ -0,0 +1,16 @@ +package org.mifos.identityaccountmapper.zeebe; + +public final class ZeebeVariables { + + private ZeebeVariables() {} + + public static final String ACCOUNT_LOOKUP_FAILED = "accountLookupFailed"; + public static final String PAYEE_PARTY_ID = "payeePartyId"; + public static final String PAYEE_PARTY_ID_TYPE = "payeePartyIdType"; + public static final String PARTY_LOOKUP_FSP_ID = "partyLookupFspId"; + public static final String ACCOUNT_LOOKUP = "account-lookup"; + public static final String BATCH_ACCOUNT_LOOKUP = "batchAccountLookup"; + public static final String BATCH_ACCOUNT_LOOKUP_RESPONSE = "batch-account-lookup-response"; + public static final String PARTY_LOOKUP_FAILED = "partyLookupFailed"; + +} diff --git a/ph-ee-identity-account-mapper/src/main/resources/application.yml b/ph-ee-identity-account-mapper/src/main/resources/application.yml new file mode 100644 index 000000000..bb1a4f822 --- /dev/null +++ b/ph-ee-identity-account-mapper/src/main/resources/application.yml @@ -0,0 +1,79 @@ +server: + port: 8080 + +spring: + main: + cloud-platform: + JAVA_TOOL_OPTIONS: "-Xmx4G" + + jpa: + show-sql: false + generate-ddl: false + + cache: + time_to_live: 3 + time_to_idle: 3 + max_entries_heap: 10 + max_byte_off_heap: 10 + max_byte_disk: 10 + + datasource: + url: jdbc:mysql://operationsmysql:3306/identity_account_mapper + username: root + password: mysql + driver-class-name: com.mysql.cj.jdbc.Driver + hikari: + minimum-idle: 5 + maximum-pool-size: 20 + pool-name: MyHikariCP + connection-test-query: SELECT 1 + connection-timeout: 30000 + idle-timeout: 600000 + max-lifetime: 1800000 + leak-detection-threshold: 2000 + validation-timeout: 5000 + +logging: + level: + ROOT: DEBUG + +async: + core-pool-size: 5 + max-pool-size: 5 + queue-capacity: 50 + +gsma_connector: + contactpoint: "https://ams-mifos.sandbox.fynarfin.io" + endpoint: + account-status: "/ams/accounts/identifierType/identifierId/status" + +mojaloop-connector: + contactpoint: "http://account-lookup-service.sandbox.fynarfin.io" + endpoint: + get-parties: "/parties/" + callback-register: "/participants/fsp/endpoints" + +account_validation_enabled : false +account_validator_connector: "gsma" +callback_enabled: false +zeebe: + client: + max-execution-threads: 50 + evenly-allocated-max-jobs: 100 + poll-interval: 10 + # number-of-workers: 15 + # evenly-allocated-max-jobs: "#{${zeebe.client.max-execution-threads} / ${zeebe.client.number-of-workers}}" + broker: + contactpoint: "zeebe-zeebe-gateway:26500" + +management: + endpoint: + health: + probes: + enabled: true + liveness: + enabled: true + readiness: + enabled: true + +isExternalLookup: true diff --git a/ph-ee-identity-account-mapper/src/main/resources/db/migration/V1__Initial_Setup.sql b/ph-ee-identity-account-mapper/src/main/resources/db/migration/V1__Initial_Setup.sql new file mode 100644 index 000000000..68db7abf6 --- /dev/null +++ b/ph-ee-identity-account-mapper/src/main/resources/db/migration/V1__Initial_Setup.sql @@ -0,0 +1,28 @@ +CREATE TABLE identity_details ( + id BIGINT(20) PRIMARY KEY NOT NULL AUTO_INCREMENT, + master_id VARCHAR(200) NOT NULL, + created_on TIMESTAMP NOT NULL, + source_bb_id VARCHAR(200) NOT NULL, + payee_identity VARCHAR(200) NOT NULL +); + +CREATE TABLE payment_modality_details ( +id BIGINT(20) PRIMARY KEY NOT NULL AUTO_INCREMENT, + master_id VARCHAR(200) NOT NULL, + modality BIGINT(20) NULL DEFAULT NULL, + destination_account VARCHAR(200) NULL DEFAULT NULL, + institution_code VARCHAR(200) NULL DEFAULT NULL +); + +CREATE TABLE error_tracking ( + id BIGINT(20) PRIMARY KEY NOT NULL AUTO_INCREMENT, + request_id VARCHAR(200) NOT NULL, + payee_identity VARCHAR(200) NOT NULL, + modality BIGINT(20) NULL DEFAULT NULL, + error_description VARCHAR(200) NOT NULL +); +CREATE INDEX idx_payee_identity ON identity_details (payee_identity, master_id); + +CREATE INDEX idx_master_id ON identity_details (payee_identity, master_id); + +CREATE INDEX idx_master_id ON payment_modality_details (master_id); diff --git a/ph-ee-identity-account-mapper/src/main/resources/db/migration/V2__add_registering_institution_id.sql b/ph-ee-identity-account-mapper/src/main/resources/db/migration/V2__add_registering_institution_id.sql new file mode 100644 index 000000000..3e0292f02 --- /dev/null +++ b/ph-ee-identity-account-mapper/src/main/resources/db/migration/V2__add_registering_institution_id.sql @@ -0,0 +1,2 @@ +ALTER TABLE identity_details +CHANGE COLUMN source_bb_id registering_institution_id VARCHAR(200) NOT NULL; diff --git a/ph-ee-identity-account-mapper/src/test/java/org/mifos/pheeidentityaccountmapper/PhEeIdentityAccountMapperApplicationTests.java b/ph-ee-identity-account-mapper/src/test/java/org/mifos/pheeidentityaccountmapper/PhEeIdentityAccountMapperApplicationTests.java new file mode 100644 index 000000000..4b7865e10 --- /dev/null +++ b/ph-ee-identity-account-mapper/src/test/java/org/mifos/pheeidentityaccountmapper/PhEeIdentityAccountMapperApplicationTests.java @@ -0,0 +1,8 @@ +package org.mifos.pheeidentityaccountmapper; + +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +class PhEeIdentityAccountMapperApplicationTests { + +} diff --git a/ph-ee-importer-es/.circleci/config.yml b/ph-ee-importer-es/.circleci/config.yml new file mode 100644 index 000000000..b5e61c97d --- /dev/null +++ b/ph-ee-importer-es/.circleci/config.yml @@ -0,0 +1,102 @@ +version: 2.1 +executors: + docker-executor: + docker: + - image: circleci/openjdk:17-buster-node-browsers-legacy + auth: + username: $DOCKERHUB_USERNAME + password: $DOCKERHUB_PASSWORD + +jobs: + build_and_push_tag_image: + executor: docker-executor + environment: + JVM_OPTS: -Xmx512m + TERM: dumb + GITHUB_TOKEN: ${GITHUB_TOKEN} # Add the GitHub token as an environment variable + + steps: + - checkout + - setup_remote_docker: + version: 20.10.14 + - run: + name: Build and Push Docker tag Image + command: | + # Set environment variables + IMAGE_TAG=$CIRCLE_TAG + + # Check if the Docker image with the same tag already exists in Docker Hub + if curl -s -f -u "$DOCKERHUB_USERNAME":"$DOCKERHUB_PASSWORD" "https://hub.docker.com/v2/repositories/fynarfin/ph-ee-importer-es/tags/$IMAGE_TAG" > /dev/null; then + echo "Skipping the build and push as the tag $IMAGE_TAG already exists in Docker Hub." + exit 0 + fi + + # Build and tag the Docker image + ./gradlew bootJar + docker build -t "fynarfin/ph-ee-importer-es:$IMAGE_TAG" . + + # Push the Docker image to Docker Hub + docker login -u "$DOCKERHUB_USERNAME" -p "$DOCKERHUB_PASSWORD" + docker push "fynarfin/ph-ee-importer-es:$IMAGE_TAG" + + # when: always # The job will be executed even if there's no match for the tag filter + + build_and_push_latest_image: + executor: docker-executor + environment: + JVM_OPTS: -Xmx512m + TERM: dumb + + steps: + - checkout + # Install Docker to build and push the image + - setup_remote_docker: + version: 20.10.14 + + # Build the Docker image + - run: + name: Build Docker image + command: | + IMAGE_TAG=$CIRCLE_TAG + ./gradlew bootJar + docker build -t fynarfin/ph-ee-importer-es:latest . + if [ "$CIRCLE_BRANCH" != "develop" ]; then + PR_NUMBER=$(basename $CIRCLE_PULL_REQUEST) + PR_TITLE=$(curl -sSL "https://api.github.com/repos/fynarfin/$CIRCLE_PROJECT_REPONAME/pulls/$PR_NUMBER" | jq -r '.title') + JIRA_STORY=$(echo $PR_TITLE | cut -d "[" -f2 | cut -d "]" -f1 | tr '[A-Z]' '[a-z]') + if [ -z "$JIRA_STORY" ]; then echo "Invalid PR title" && exit 1; else echo "Ticket NO: $JIRA_STORY"; fi + docker image tag fynarfin/$CIRCLE_PROJECT_REPONAME:latest fynarfin/$CIRCLE_PROJECT_REPONAME:$JIRA_STORY + fi + + # Log in to DockerHub using environment variables + - run: + name: Login to DockerHub + command: echo "${DOCKERHUB_PASSWORD}" | docker login -u "${DOCKERHUB_USERNAME}" --password-stdin + + # Push the Docker image to DockerHub + - run: + name: Push Docker image to DockerHub + command: | + if [ "$CIRCLE_BRANCH" = "develop" ]; then + docker push fynarfin/ph-ee-importer-es:latest + fi + if [ "$CIRCLE_BRANCH" != "develop" ]; then + PR_NUMBER=$(basename $CIRCLE_PULL_REQUEST) + PR_TITLE=$(curl -sSL "https://api.github.com/repos/fynarfin/$CIRCLE_PROJECT_REPONAME/pulls/$PR_NUMBER" | jq -r '.title') + JIRA_STORY=$(echo $PR_TITLE | cut -d "[" -f2 | cut -d "]" -f1 | tr '[A-Z]' '[a-z]') + docker push fynarfin/$CIRCLE_PROJECT_REPONAME:${JIRA_STORY} + fi + +workflows: + version: 2 + build-and-push: + jobs: + - build_and_push_tag_image: + filters: + tags: + only: /^v\d+\.\d+\.\d+$/ # Match tags in the format v1.2.3 + context: + - DOCKER + - build_and_push_latest_image: + context: + - DOCKER diff --git a/ph-ee-importer-es/.github/pull_request_template.md b/ph-ee-importer-es/.github/pull_request_template.md new file mode 100644 index 000000000..1d44d4817 --- /dev/null +++ b/ph-ee-importer-es/.github/pull_request_template.md @@ -0,0 +1,22 @@ +## Description + +* PR title should have jira ticket enclosed in `[]`.
+ Format: ``` [jira_ticket] description```
+ ex: [phee-123] PR title. +* Add a link to the Jira ticket. +* Describe the changes made and why they were made. + +## Checklist + +Please make sure these boxes are checked before submitting your pull request - thanks! +- [ ] Followed the PR title naming convention mentioned above. + +- [ ] Design related bullet points or design document link related to this PR added in the description above. + +- [ ] Updated corresponding Postman Collection or Api documentation for the changes in this PR. + +- [ ] Create/update unit or integration tests for verifying the changes made. + +- [ ] Add required Swagger annotation and update API documentation with details of any API changes if applicable + +- [ ] Followed the naming conventions as given in https://docs.google.com/document/d/1Q4vaMSzrTxxh9TS0RILuNkSkYCxotuYk1Xe0CMIkkCU/edit?usp=sharing diff --git a/ph-ee-importer-es/.github/workflows/test.yml b/ph-ee-importer-es/.github/workflows/test.yml new file mode 100644 index 000000000..0779a0ee6 --- /dev/null +++ b/ph-ee-importer-es/.github/workflows/test.yml @@ -0,0 +1,12 @@ +name: Test +on: [push, pull_request] +jobs: + Assemble: + runs-on: ubuntu-latest + steps: + - name: Check out repository code + uses: actions/checkout@v2 + - name: Build project + run: ./gradlew clean build + - name: Build Docker image + run: docker build . -t paymenthubee.mifos.io/phee/importer-es diff --git a/ph-ee-importer-es/.gitignore b/ph-ee-importer-es/.gitignore new file mode 100644 index 000000000..684d72cd2 --- /dev/null +++ b/ph-ee-importer-es/.gitignore @@ -0,0 +1,36 @@ +.idea +*.iml +target +dependency-reduced-pom.xml + +target/ +.gradle +build +build/ +!gradle/wrapper/gradle-wrapper.jar + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ + +### VS Code ### +.vscode/ + +.DS_Store +src/.DS_Store +src/main/.DS_Store + diff --git a/ph-ee-importer-es/Dockerfile b/ph-ee-importer-es/Dockerfile new file mode 100644 index 000000000..4d9466061 --- /dev/null +++ b/ph-ee-importer-es/Dockerfile @@ -0,0 +1,5 @@ +FROM openjdk:17 +WORKDIR /app +COPY build/libs/*.jar . +CMD java -jar *.jar + diff --git a/ph-ee-importer-es/Jenkinsfile b/ph-ee-importer-es/Jenkinsfile new file mode 100644 index 000000000..6ae5690dc --- /dev/null +++ b/ph-ee-importer-es/Jenkinsfile @@ -0,0 +1,18 @@ +pipeline { + agent any + stages { + stage('build') { + steps { + sh 'mvn --version' + sh 'mvn -U clean package' + } + } + stage('docker') { + steps { + sh 'docker build . -t paymenthubee.azurecr.io/phee/importer-es' + sh 'docker push paymenthubee.azurecr.io/phee/importer-es' + } + } + + } +} diff --git a/ph-ee-importer-es/LICENSE b/ph-ee-importer-es/LICENSE new file mode 100644 index 000000000..a612ad981 --- /dev/null +++ b/ph-ee-importer-es/LICENSE @@ -0,0 +1,373 @@ +Mozilla Public License Version 2.0 +================================== + +1. Definitions +-------------- + +1.1. "Contributor" + means each individual or legal entity that creates, contributes to + the creation of, or owns Covered Software. + +1.2. "Contributor Version" + means the combination of the Contributions of others (if any) used + by a Contributor and that particular Contributor's Contribution. + +1.3. "Contribution" + means Covered Software of a particular Contributor. + +1.4. "Covered Software" + means Source Code Form to which the initial Contributor has attached + the notice in Exhibit A, the Executable Form of such Source Code + Form, and Modifications of such Source Code Form, in each case + including portions thereof. + +1.5. "Incompatible With Secondary Licenses" + means + + (a) that the initial Contributor has attached the notice described + in Exhibit B to the Covered Software; or + + (b) that the Covered Software was made available under the terms of + version 1.1 or earlier of the License, but not also under the + terms of a Secondary License. + +1.6. "Executable Form" + means any form of the work other than Source Code Form. + +1.7. "Larger Work" + means a work that combines Covered Software with other material, in + a separate file or files, that is not Covered Software. + +1.8. "License" + means this document. + +1.9. "Licensable" + means having the right to grant, to the maximum extent possible, + whether at the time of the initial grant or subsequently, any and + all of the rights conveyed by this License. + +1.10. "Modifications" + means any of the following: + + (a) any file in Source Code Form that results from an addition to, + deletion from, or modification of the contents of Covered + Software; or + + (b) any new file in Source Code Form that contains any Covered + Software. + +1.11. "Patent Claims" of a Contributor + means any patent claim(s), including without limitation, method, + process, and apparatus claims, in any patent Licensable by such + Contributor that would be infringed, but for the grant of the + License, by the making, using, selling, offering for sale, having + made, import, or transfer of either its Contributions or its + Contributor Version. + +1.12. "Secondary License" + means either the GNU General Public License, Version 2.0, the GNU + Lesser General Public License, Version 2.1, the GNU Affero General + Public License, Version 3.0, or any later versions of those + licenses. + +1.13. "Source Code Form" + means the form of the work preferred for making modifications. + +1.14. "You" (or "Your") + means an individual or a legal entity exercising rights under this + License. For legal entities, "You" includes any entity that + controls, is controlled by, or is under common control with You. For + purposes of this definition, "control" means (a) the power, direct + or indirect, to cause the direction or management of such entity, + whether by contract or otherwise, or (b) ownership of more than + fifty percent (50%) of the outstanding shares or beneficial + ownership of such entity. + +2. License Grants and Conditions +-------------------------------- + +2.1. Grants + +Each Contributor hereby grants You a world-wide, royalty-free, +non-exclusive license: + +(a) under intellectual property rights (other than patent or trademark) + Licensable by such Contributor to use, reproduce, make available, + modify, display, perform, distribute, and otherwise exploit its + Contributions, either on an unmodified basis, with Modifications, or + as part of a Larger Work; and + +(b) under Patent Claims of such Contributor to make, use, sell, offer + for sale, have made, import, and otherwise transfer either its + Contributions or its Contributor Version. + +2.2. Effective Date + +The licenses granted in Section 2.1 with respect to any Contribution +become effective for each Contribution on the date the Contributor first +distributes such Contribution. + +2.3. Limitations on Grant Scope + +The licenses granted in this Section 2 are the only rights granted under +this License. No additional rights or licenses will be implied from the +distribution or licensing of Covered Software under this License. +Notwithstanding Section 2.1(b) above, no patent license is granted by a +Contributor: + +(a) for any code that a Contributor has removed from Covered Software; + or + +(b) for infringements caused by: (i) Your and any other third party's + modifications of Covered Software, or (ii) the combination of its + Contributions with other software (except as part of its Contributor + Version); or + +(c) under Patent Claims infringed by Covered Software in the absence of + its Contributions. + +This License does not grant any rights in the trademarks, service marks, +or logos of any Contributor (except as may be necessary to comply with +the notice requirements in Section 3.4). + +2.4. Subsequent Licenses + +No Contributor makes additional grants as a result of Your choice to +distribute the Covered Software under a subsequent version of this +License (see Section 10.2) or under the terms of a Secondary License (if +permitted under the terms of Section 3.3). + +2.5. Representation + +Each Contributor represents that the Contributor believes its +Contributions are its original creation(s) or it has sufficient rights +to grant the rights to its Contributions conveyed by this License. + +2.6. Fair Use + +This License is not intended to limit any rights You have under +applicable copyright doctrines of fair use, fair dealing, or other +equivalents. + +2.7. Conditions + +Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted +in Section 2.1. + +3. Responsibilities +------------------- + +3.1. Distribution of Source Form + +All distribution of Covered Software in Source Code Form, including any +Modifications that You create or to which You contribute, must be under +the terms of this License. You must inform recipients that the Source +Code Form of the Covered Software is governed by the terms of this +License, and how they can obtain a copy of this License. You may not +attempt to alter or restrict the recipients' rights in the Source Code +Form. + +3.2. Distribution of Executable Form + +If You distribute Covered Software in Executable Form then: + +(a) such Covered Software must also be made available in Source Code + Form, as described in Section 3.1, and You must inform recipients of + the Executable Form how they can obtain a copy of such Source Code + Form by reasonable means in a timely manner, at a charge no more + than the cost of distribution to the recipient; and + +(b) You may distribute such Executable Form under the terms of this + License, or sublicense it under different terms, provided that the + license for the Executable Form does not attempt to limit or alter + the recipients' rights in the Source Code Form under this License. + +3.3. Distribution of a Larger Work + +You may create and distribute a Larger Work under terms of Your choice, +provided that You also comply with the requirements of this License for +the Covered Software. If the Larger Work is a combination of Covered +Software with a work governed by one or more Secondary Licenses, and the +Covered Software is not Incompatible With Secondary Licenses, this +License permits You to additionally distribute such Covered Software +under the terms of such Secondary License(s), so that the recipient of +the Larger Work may, at their option, further distribute the Covered +Software under the terms of either this License or such Secondary +License(s). + +3.4. Notices + +You may not remove or alter the substance of any license notices +(including copyright notices, patent notices, disclaimers of warranty, +or limitations of liability) contained within the Source Code Form of +the Covered Software, except that You may alter any license notices to +the extent required to remedy known factual inaccuracies. + +3.5. Application of Additional Terms + +You may choose to offer, and to charge a fee for, warranty, support, +indemnity or liability obligations to one or more recipients of Covered +Software. However, You may do so only on Your own behalf, and not on +behalf of any Contributor. You must make it absolutely clear that any +such warranty, support, indemnity, or liability obligation is offered by +You alone, and You hereby agree to indemnify every Contributor for any +liability incurred by such Contributor as a result of warranty, support, +indemnity or liability terms You offer. You may include additional +disclaimers of warranty and limitations of liability specific to any +jurisdiction. + +4. Inability to Comply Due to Statute or Regulation +--------------------------------------------------- + +If it is impossible for You to comply with any of the terms of this +License with respect to some or all of the Covered Software due to +statute, judicial order, or regulation then You must: (a) comply with +the terms of this License to the maximum extent possible; and (b) +describe the limitations and the code they affect. Such description must +be placed in a text file included with all distributions of the Covered +Software under this License. Except to the extent prohibited by statute +or regulation, such description must be sufficiently detailed for a +recipient of ordinary skill to be able to understand it. + +5. Termination +-------------- + +5.1. The rights granted under this License will terminate automatically +if You fail to comply with any of its terms. However, if You become +compliant, then the rights granted under this License from a particular +Contributor are reinstated (a) provisionally, unless and until such +Contributor explicitly and finally terminates Your grants, and (b) on an +ongoing basis, if such Contributor fails to notify You of the +non-compliance by some reasonable means prior to 60 days after You have +come back into compliance. Moreover, Your grants from a particular +Contributor are reinstated on an ongoing basis if such Contributor +notifies You of the non-compliance by some reasonable means, this is the +first time You have received notice of non-compliance with this License +from such Contributor, and You become compliant prior to 30 days after +Your receipt of the notice. + +5.2. If You initiate litigation against any entity by asserting a patent +infringement claim (excluding declaratory judgment actions, +counter-claims, and cross-claims) alleging that a Contributor Version +directly or indirectly infringes any patent, then the rights granted to +You by any and all Contributors for the Covered Software under Section +2.1 of this License shall terminate. + +5.3. In the event of termination under Sections 5.1 or 5.2 above, all +end user license agreements (excluding distributors and resellers) which +have been validly granted by You or Your distributors under this License +prior to termination shall survive termination. + +************************************************************************ +* * +* 6. Disclaimer of Warranty * +* ------------------------- * +* * +* Covered Software is provided under this License on an "as is" * +* basis, without warranty of any kind, either expressed, implied, or * +* statutory, including, without limitation, warranties that the * +* Covered Software is free of defects, merchantable, fit for a * +* particular purpose or non-infringing. The entire risk as to the * +* quality and performance of the Covered Software is with You. * +* Should any Covered Software prove defective in any respect, You * +* (not any Contributor) assume the cost of any necessary servicing, * +* repair, or correction. This disclaimer of warranty constitutes an * +* essential part of this License. No use of any Covered Software is * +* authorized under this License except under this disclaimer. * +* * +************************************************************************ + +************************************************************************ +* * +* 7. Limitation of Liability * +* -------------------------- * +* * +* Under no circumstances and under no legal theory, whether tort * +* (including negligence), contract, or otherwise, shall any * +* Contributor, or anyone who distributes Covered Software as * +* permitted above, be liable to You for any direct, indirect, * +* special, incidental, or consequential damages of any character * +* including, without limitation, damages for lost profits, loss of * +* goodwill, work stoppage, computer failure or malfunction, or any * +* and all other commercial damages or losses, even if such party * +* shall have been informed of the possibility of such damages. This * +* limitation of liability shall not apply to liability for death or * +* personal injury resulting from such party's negligence to the * +* extent applicable law prohibits such limitation. Some * +* jurisdictions do not allow the exclusion or limitation of * +* incidental or consequential damages, so this exclusion and * +* limitation may not apply to You. * +* * +************************************************************************ + +8. Litigation +------------- + +Any litigation relating to this License may be brought only in the +courts of a jurisdiction where the defendant maintains its principal +place of business and such litigation shall be governed by laws of that +jurisdiction, without reference to its conflict-of-law provisions. +Nothing in this Section shall prevent a party's ability to bring +cross-claims or counter-claims. + +9. Miscellaneous +---------------- + +This License represents the complete agreement concerning the subject +matter hereof. If any provision of this License is held to be +unenforceable, such provision shall be reformed only to the extent +necessary to make it enforceable. Any law or regulation which provides +that the language of a contract shall be construed against the drafter +shall not be used to construe this License against a Contributor. + +10. Versions of the License +--------------------------- + +10.1. New Versions + +Mozilla Foundation is the license steward. Except as provided in Section +10.3, no one other than the license steward has the right to modify or +publish new versions of this License. Each version will be given a +distinguishing version number. + +10.2. Effect of New Versions + +You may distribute the Covered Software under the terms of the version +of the License under which You originally received the Covered Software, +or under the terms of any subsequent version published by the license +steward. + +10.3. Modified Versions + +If you create software not governed by this License, and you want to +create a new license for such software, you may create and use a +modified version of this License if you rename the license and remove +any references to the name of the license steward (except to note that +such modified license differs from this License). + +10.4. Distributing Source Code Form that is Incompatible With Secondary +Licenses + +If You choose to distribute Source Code Form that is Incompatible With +Secondary Licenses under the terms of this version of the License, the +notice described in Exhibit B of this License must be attached. + +Exhibit A - Source Code Form License Notice +------------------------------------------- + + This Source Code Form is subject to the terms of the Mozilla Public + License, v. 2.0. If a copy of the MPL was not distributed with this + file, You can obtain one at http://mozilla.org/MPL/2.0/. + +If it is not possible or desirable to put the notice in a particular +file, then You may include the notice in a location (such as a LICENSE +file in a relevant directory) where a recipient would be likely to look +for such a notice. + +You may add additional accurate notices of copyright ownership. + +Exhibit B - "Incompatible With Secondary Licenses" Notice +--------------------------------------------------------- + + This Source Code Form is "Incompatible With Secondary Licenses", as + defined by the Mozilla Public License, v. 2.0. diff --git a/ph-ee-importer-es/README.md b/ph-ee-importer-es/README.md new file mode 100644 index 000000000..a938c7811 --- /dev/null +++ b/ph-ee-importer-es/README.md @@ -0,0 +1,4 @@ +# payment-hub-ee +Payment Hub Enterprise Edition middleware for integration to real-time payment systems. + +#Auto-trigger diff --git a/ph-ee-importer-es/build.gradle b/ph-ee-importer-es/build.gradle new file mode 100644 index 000000000..97bdc48f6 --- /dev/null +++ b/ph-ee-importer-es/build.gradle @@ -0,0 +1,179 @@ +/* + * This file was generated by the Gradle 'init' task. + */ + +plugins { + id 'java' + id 'maven-publish' + id 'org.springframework.boot' version '3.1.3' + id 'io.spring.dependency-management' version '1.1.3' + id 'eclipse' + id 'checkstyle' + id 'com.diffplug.spotless' version '6.19.0' +} + +repositories { + mavenLocal() + maven { + url = uri('https://repo.maven.apache.org/maven2') + } + + maven { + url = uri('https://jfrog.sandbox.fynarfin.io/artifactory/fyn-libs-snapshot') + } +} + +apply plugin: 'com.diffplug.spotless' +spotless { + format 'misc', { + target '**/*.md', '**/*.properties', '**/.gitignore', '**/.openapi-generator-ignore', '**/*.yml', '**/*.xml', '**/**.json', '**/*.sql' + targetExclude '**/build/**', '**/bin/**', '**/.settings/**', '**/.idea/**', '**/.gradle/**', '**/gradlew.bat', '**/licenses/**', '**/banner.txt', '.vscode/**' + indentWithSpaces(4) + endWithNewline() + trimTrailingWhitespace() + } + + groovyGradle { + target '*.gradle', '**/*.gradle' + targetExclude '**/build/**' + greclipse() + indentWithSpaces(4) + endWithNewline() + trimTrailingWhitespace() + } + + lineEndings 'UNIX' +} + +dependencies { + implementation 'org.springframework.boot:spring-boot-starter' + testImplementation 'org.springframework.boot:spring-boot-starter-test' + implementation 'javax.annotation:javax.annotation-api:1.3.2' + implementation 'io.zeebe:zeebe-elasticsearch-exporter:0.24.6' + implementation 'org.elasticsearch.client:elasticsearch-rest-high-level-client:7.17.0' + implementation 'org.apache.camel.springboot:camel-spring-boot-starter:3.4.0' + implementation 'org.apache.kafka:kafka-streams:3.3.2' + implementation 'org.springframework.kafka:spring-kafka:3.0.9' + implementation 'org.json:json:20190722' + testImplementation 'junit:junit:4.13' + implementation 'org.apache.commons:commons-text:1.10.0' + checkstyle 'com.puppycrawl.tools:checkstyle:10.9.3' + checkstyle 'com.github.sevntu-checkstyle:sevntu-checks:1.44.1' + implementation 'com.diffplug.gradle.spotless:spotless:2.4.1' + implementation 'com.diffplug.spotless:spotless-plugin-gradle:6.17.0' +} + +configure(this) { + // NOTE: order matters! + apply plugin: 'java' + apply plugin: 'idea' + apply plugin: 'eclipse' + apply plugin: 'checkstyle' + configurations { + implementation.setCanBeResolved(true) + api.setCanBeResolved(true) + } + tasks.withType(JavaCompile) { + options.compilerArgs += [ + "-Xlint:unchecked", + "-Xlint:cast", + "-Xlint:auxiliaryclass", + "-Xlint:deprecation", + "-Xlint:dep-ann", + "-Xlint:divzero", + "-Xlint:empty", + "-Xlint:exports", + "-Xlint:fallthrough", + "-Xlint:finally", + "-Xlint:module", + "-Xlint:opens", + "-Xlint:options", + "-Xlint:overloads", + "-Xlint:overrides", + "-Xlint:path", + "-Xlint:processing", + "-Xlint:removal", + "-Xlint:requires-automatic", + "-Xlint:requires-transitive-automatic", + "-Xlint:try", + "-Xlint:varargs", + "-Xlint:preview", + "-Xlint:static", + // -Werror needs to be disabled because EclipseLink's static weaving doesn't generate warning-free code + // and during an IntelliJ recompilation, it fails + //"-Werror", + "-Xmaxwarns", + 1500, + "-Xmaxerrs", + 1500 + ] + options.deprecation = true + } + // Configuration for the spotless plugin + // https://github.com/diffplug/spotless/tree/main/plugin-gradle + spotless { + java { + targetExclude '**/build/**', '**/bin/**', '**/out/**' + importOrder() //sort imports alphabetically + removeUnusedImports() + eclipse().configFile "$rootDir/ph-ee-importer-es/config/es-formatter.xml" + endWithNewline() + trimTrailingWhitespace() + // Enforce style modifier order + custom 'Modifier ordering', { + def modifierRanking = [ + public : 1, + protected : 2, + private : 3, + abstract : 4, + default : 5, + static : 6, + final : 7, + transient : 8, + volatile : 9, + synchronized: 10, + native : 11, + strictfp : 12] + // Find any instance of multiple modifiers. Lead with a non-word character to avoid + // accidental matching against for instance, "an alternative default value" + it.replaceAll(/\W(?:public |protected |private |abstract |default |static |final |transient |volatile |synchronized |native |strictfp ){2,}/, { + // Do not replace the leading non-word character. Identify the modifiers + it.replaceAll(/(?:public |protected |private |abstract |default |static |final |transient |volatile |synchronized |native |strictfp ){2,}/, { + // Sort the modifiers according to the ranking above + it.split().sort({ modifierRanking[it] }).join(' ') + ' ' + } + ) + } + ) + } + } + lineEndings 'UNIX' + } + // If we are running Gradle within Eclipse to enhance classes, + // set the classes directory to point to Eclipse's default build directory + if (project.hasProperty('env') && project.getProperty('env') == 'eclipse') { + sourceSets.main.java.outputDir = file("$projectDir/bin/main") + } + // Configuration for the Checkstyle plugin + // https://docs.gradle.org/current/userguide/checkstyle_plugin.html + dependencies { + checkstyle 'com.puppycrawl.tools:checkstyle:10.3.1' + checkstyle 'com.github.sevntu-checkstyle:sevntu-checks:1.42.0' + } +} + +group = 'org.mifos' +version = '1.0.0-SNAPSHOT' +sourceCompatibility = '17' + +publishing { + publications { + maven(MavenPublication) { + from(components.java) + } + } +} + +tasks.withType(JavaCompile) { + options.encoding = 'UTF-8' +} diff --git a/ph-ee-importer-es/config/checkstyle/checkstyle.xml b/ph-ee-importer-es/config/checkstyle/checkstyle.xml new file mode 100644 index 000000000..5183efef5 --- /dev/null +++ b/ph-ee-importer-es/config/checkstyle/checkstyle.xml @@ -0,0 +1,266 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ph-ee-importer-es/config/checkstyle/suppressions.xml b/ph-ee-importer-es/config/checkstyle/suppressions.xml new file mode 100644 index 000000000..f4e5b54c3 --- /dev/null +++ b/ph-ee-importer-es/config/checkstyle/suppressions.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + diff --git a/ph-ee-importer-es/config/es-cleanup.xml b/ph-ee-importer-es/config/es-cleanup.xml new file mode 100644 index 000000000..773e7806a --- /dev/null +++ b/ph-ee-importer-es/config/es-cleanup.xml @@ -0,0 +1,71 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ph-ee-importer-es/config/es-formatter.xml b/ph-ee-importer-es/config/es-formatter.xml new file mode 100644 index 000000000..cf7972207 --- /dev/null +++ b/ph-ee-importer-es/config/es-formatter.xml @@ -0,0 +1,366 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ph-ee-importer-es/gradle/wrapper/gradle-wrapper.jar b/ph-ee-importer-es/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 000000000..41d9927a4 Binary files /dev/null and b/ph-ee-importer-es/gradle/wrapper/gradle-wrapper.jar differ diff --git a/ph-ee-importer-es/gradle/wrapper/gradle-wrapper.properties b/ph-ee-importer-es/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 000000000..9f4197d5f --- /dev/null +++ b/ph-ee-importer-es/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,7 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.2.1-bin.zip +networkTimeout=10000 +validateDistributionUrl=true +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/ph-ee-importer-es/gradlew b/ph-ee-importer-es/gradlew new file mode 100755 index 000000000..1b6c78733 --- /dev/null +++ b/ph-ee-importer-es/gradlew @@ -0,0 +1,234 @@ +#!/bin/sh + +# +# Copyright © 2015-2021 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit + +APP_NAME="Gradle" +APP_BASE_NAME=${0##*/} + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/ph-ee-importer-es/gradlew.bat b/ph-ee-importer-es/gradlew.bat new file mode 100644 index 000000000..ac1b06f93 --- /dev/null +++ b/ph-ee-importer-es/gradlew.bat @@ -0,0 +1,89 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/ph-ee-importer-es/settings.gradle b/ph-ee-importer-es/settings.gradle new file mode 100644 index 000000000..b1c891b3e --- /dev/null +++ b/ph-ee-importer-es/settings.gradle @@ -0,0 +1,5 @@ +/* + * This file was generated by the Gradle 'init' task. + */ + +rootProject.name = 'importer-es' diff --git a/ph-ee-importer-es/src/main/java/org/mifos/phee/kafkastreamer/importer/ElasticsearchClient.java b/ph-ee-importer-es/src/main/java/org/mifos/phee/kafkastreamer/importer/ElasticsearchClient.java new file mode 100644 index 000000000..f73df418f --- /dev/null +++ b/ph-ee-importer-es/src/main/java/org/mifos/phee/kafkastreamer/importer/ElasticsearchClient.java @@ -0,0 +1,361 @@ +package org.mifos.phee.kafkastreamer.importer; + +import io.prometheus.client.Histogram; +import io.zeebe.exporter.ElasticsearchExporterException; +import io.zeebe.exporter.ElasticsearchMetrics; +import io.zeebe.util.VersionUtil; +import java.io.IOException; +import java.io.InputStream; +import java.net.URI; +import java.net.URISyntaxException; +import java.security.KeyManagementException; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.time.Instant; +import java.time.ZoneOffset; +import java.time.format.DateTimeFormatter; +import java.util.Collections; +import java.util.Map; +import javax.annotation.PostConstruct; +import javax.net.ssl.SSLContext; +import org.apache.http.HttpHost; +import org.apache.http.auth.AuthScope; +import org.apache.http.auth.UsernamePasswordCredentials; +import org.apache.http.client.CredentialsProvider; +import org.apache.http.conn.ssl.NoopHostnameVerifier; +import org.apache.http.impl.client.BasicCredentialsProvider; +import org.apache.http.impl.nio.client.HttpAsyncClientBuilder; +import org.apache.http.impl.nio.reactor.IOReactorConfig; +import org.apache.http.ssl.SSLContextBuilder; +import org.apache.http.ssl.SSLContexts; +import org.elasticsearch.ElasticsearchException; +import org.elasticsearch.action.admin.indices.template.put.PutIndexTemplateRequest; +import org.elasticsearch.action.bulk.BulkItemResponse; +import org.elasticsearch.action.bulk.BulkRequest; +import org.elasticsearch.action.bulk.BulkResponse; +import org.elasticsearch.action.index.IndexRequest; +import org.elasticsearch.action.update.UpdateRequest; +import org.elasticsearch.client.RequestOptions; +import org.elasticsearch.client.RestClient; +import org.elasticsearch.client.RestClientBuilder; +import org.elasticsearch.client.RestHighLevelClient; +import org.elasticsearch.common.xcontent.XContentHelper; +import org.elasticsearch.xcontent.XContentType; +import org.json.JSONObject; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.scheduling.TaskScheduler; +import org.springframework.scheduling.support.PeriodicTrigger; +import org.springframework.stereotype.Component; + +@Component +public class ElasticsearchClient { + + public static String INDEX_TEMPLATE_FILENAME_PATTERN = "/zeebe-record-%s-template.json"; + public static String INDEX_DELIMITER = "_"; + public static String ALIAS_DELIMITER = "-"; + + private Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Value("${importer.elasticsearch.bulk-size}") + private Integer bulkSize; + + @Value("${importer.elasticsearch.url}") + private String elasticUrl; + + @Value("${importer.elasticsearch.index-prefix}") + private String indexPrefix; + + @Value("${reporting.enabled}") + private Boolean reportingEnabled; + + @Value("${elasticsearch.security.enabled}") + private Boolean securityEnabled; + + @Value("${elasticsearch.sslVerification}") + private Boolean sslVerify; + + @Value("${elasticsearch.username}") + private String username; + + @Value("${elasticsearch.password}") + private String password; + + @Autowired + private TaskScheduler taskScheduler; + + @Autowired + private PaymentsIndexConfiguration paymentsIndexConfiguration; + + private RestHighLevelClient client; + private ElasticsearchMetrics metrics; + + private DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd").withZone(ZoneOffset.UTC); + private BulkRequest bulkRequest = new BulkRequest(); + + @PostConstruct + public void setup() { + this.client = createClient(); + taskScheduler.schedule(this::flush, new PeriodicTrigger(2000)); + } + + public void close() throws IOException { + client.close(); + } + + public void bulk(IndexRequest indexRequest) { + logger.info("Calling bulk request for insert"); + bulkRequest.add(indexRequest); + } + + public void bulk(UpdateRequest updateRequest) { + logger.info("Calling bulk request for upsert"); + bulkRequest.add(updateRequest); + } + + public void index(JSONObject record) { + if (metrics == null) { + metrics = new ElasticsearchMetrics(record.getInt("partitionId")); + } + logger.info("Getting index method called with record value type " + record.getString("valueType")); + if (reportingEnabled) { + upsertToReportingIndex(record); + } + logger.info("Pushing index for " + indexFor(record)); + IndexRequest request = new IndexRequest(indexFor(record), typeFor(record), idFor(record)) + .source(record.toString(), XContentType.JSON).routing(Integer.toString(record.getInt("partitionId"))); + bulk(request); + } + + public void upsertToReportingIndex(JSONObject record) { + JSONObject newRecord = new JSONObject(); + if (record.getString("valueType").equalsIgnoreCase("variable")) { + JSONObject valueObj = record.getJSONObject("value"); + if (valueObj.has("name")) { // Checking for variable events + if (paymentsIndexConfiguration.getVariables().contains(valueObj.getString("name"))) { + if (valueObj.getString("name").equalsIgnoreCase("amount")) { + newRecord.put((String) valueObj.get("name"), Double.parseDouble(valueObj.getString("value").replaceAll("\"", ""))); + } else if (valueObj.getString("name").equalsIgnoreCase("originDate")) { + Instant timestamp = Instant.ofEpochMilli(valueObj.getLong("value")); + newRecord.put((String) valueObj.get("name"), timestamp); + } else { + newRecord.put((String) valueObj.get("name"), valueObj.get("value").toString().replaceAll("\"", "")); + } + } + if (!newRecord.has("processInstanceKey")) { + newRecord.put("processInstanceKey", String.valueOf(valueObj.getLong("processInstanceKey"))); + Instant timestamp = Instant.ofEpochMilli(record.getLong("timestamp")); + newRecord.put("timestamp", timestamp); + } + } + logger.info("New Record before insert is: " + newRecord); + String version = VersionUtil.getVersionLowerCase(); + Instant timestamp = Instant.ofEpochMilli(record.getLong("timestamp")); + String name = "zeebe-payments" + INDEX_DELIMITER + version + INDEX_DELIMITER + formatter.format(timestamp); + UpdateRequest request1 = new UpdateRequest(name, valueObj.get("processInstanceKey").toString()).doc(newRecord.toMap()) + .upsert(newRecord.toString(), XContentType.JSON); + bulk(request1); + } + } + + public synchronized int flush() { + boolean success; + int bulkSize = bulkRequest.numberOfActions(); + if (bulkSize > 0) { + try { + metrics.recordBulkSize(bulkSize); + BulkResponse responses = exportBulk(); + success = checkBulkResponses(responses); + } catch (IOException e) { + throw new ElasticsearchExporterException("Failed to flush bulk", e); + } + + if (success) { // all records where flushed, create new bulk request, otherwise retry next time + bulkRequest = new BulkRequest(); + } + } + + return bulkSize; + } + + private BulkResponse exportBulk() throws IOException { + try (Histogram.Timer timer = metrics.measureFlushDuration()) { + return client.bulk(bulkRequest, RequestOptions.DEFAULT); + } + } + + private boolean checkBulkResponses(BulkResponse responses) { + for (BulkItemResponse response : responses) { + if (response.isFailed()) { + logger.warn("Failed to flush at least one bulk request {}", response.getFailureMessage()); + return false; + } + } + + return true; + } + + public boolean shouldFlush() { + return bulkRequest.numberOfActions() >= bulkSize; + } + + /** + * @return true if request was acknowledged + */ + public boolean putIndexTemplate(ExtendedValueType extendedValueType) { + String templateName = indexPrefixForValueType(extendedValueType); + String aliasName = aliasNameForValueType(extendedValueType); + String filename = indexTemplateForValueType(extendedValueType); + return putIndexTemplate(templateName, aliasName, filename); + } + + /** + * @return true if request was acknowledged + */ + public boolean putIndexTemplate(String templateName, String aliasName, String filename) { + Map template; + try (InputStream inputStream = KafkaElasticImportApplication.class.getResourceAsStream(filename)) { + if (inputStream != null) { + template = XContentHelper.convertToMap(XContentType.JSON.xContent(), inputStream, true); + } else { + throw new ElasticsearchExporterException("Failed to find index template in classpath " + filename); + } + } catch (IOException e) { + throw new ElasticsearchExporterException("Failed to load index template from classpath " + filename, e); + } + + // update prefix in template in case it was changed in configuration + template.put("index_patterns", Collections.singletonList(templateName + INDEX_DELIMITER + "*")); + + // update alias in template in case it was changed in configuration + template.put("aliases", Collections.singletonMap(aliasName, Collections.EMPTY_MAP)); + + if (reportingEnabled) { + if (templateName.equals("zeebe-record")) { + Map template1; + try (InputStream inputStream1 = KafkaElasticImportApplication.class.getResourceAsStream("/zeebe-payments.json")) { + if (inputStream1 != null) { + template1 = XContentHelper.convertToMap(XContentType.JSON.xContent(), inputStream1, true); + } else { + throw new ElasticsearchExporterException("Failed to find index template in classpath " + filename); + } + } catch (IOException e) { + throw new ElasticsearchExporterException("Failed to load index template from classpath " + filename, e); + } + template1.put("index_patterns", Collections.singletonList("zeebe-payments" + INDEX_DELIMITER + "*")); + template1.put("aliases", Collections.singletonMap("zeebe-payments", Collections.EMPTY_MAP)); + PutIndexTemplateRequest request = new PutIndexTemplateRequest("zeebe-payments").source(template1); + putIndexTemplate(request); + } + } + PutIndexTemplateRequest request = new PutIndexTemplateRequest(templateName).source(template); + + return putIndexTemplate(request); + } + + /** + * @return true if request was acknowledged + */ + private boolean putIndexTemplate(PutIndexTemplateRequest putIndexTemplateRequest) { + try { + return client.indices().putTemplate(putIndexTemplateRequest, RequestOptions.DEFAULT).isAcknowledged(); + } catch (ElasticsearchException exception) { + throw new ElasticsearchExporterException("Failed to Connect ES", exception); + } catch (IOException e) { + throw new ElasticsearchExporterException("Failed to put index template", e); + } + } + + private RestHighLevelClient createClient() { + RestClientBuilder builder; + SSLContext sslContext = null; + if (securityEnabled) { + final CredentialsProvider credentialsProvider = new BasicCredentialsProvider(); + credentialsProvider.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials(username, password)); + if (sslVerify) { + SSLContextBuilder sslBuilder = null; + try { + sslBuilder = SSLContexts.custom().loadTrustMaterial(null, (x509Certificates, s) -> true); + sslContext = sslBuilder.build(); + } catch (NoSuchAlgorithmException | KeyStoreException | KeyManagementException e) { + e.printStackTrace(); + } + HttpHost httpHost = urlToHttpHost(elasticUrl); + SSLContext finalSslContext = sslContext; + builder = RestClient.builder(httpHost) + .setHttpClientConfigCallback(httpClientBuilder -> httpClientBuilder.setSSLContext(finalSslContext) + .setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE).setDefaultCredentialsProvider(credentialsProvider)); + } else { + HttpHost httpHost = urlToHttpHost(elasticUrl); + builder = RestClient.builder(httpHost).setHttpClientConfigCallback(new RestClientBuilder.HttpClientConfigCallback() { + + @Override + public HttpAsyncClientBuilder customizeHttpClient(HttpAsyncClientBuilder httpClientBuilder) { + return httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider); + } + }); + } + } else { + HttpHost httpHost = urlToHttpHost(elasticUrl); + builder = RestClient.builder(httpHost).setHttpClientConfigCallback(this::setHttpClientConfigCallback); + } + return new RestHighLevelClient(builder); + } + + private HttpAsyncClientBuilder setHttpClientConfigCallback(HttpAsyncClientBuilder builder) { + builder.setDefaultIOReactorConfig(IOReactorConfig.custom().setIoThreadCount(1).build()); + + return builder; + } + + private static HttpHost urlToHttpHost(String url) { + URI uri; + try { + uri = new URI(url); + } catch (URISyntaxException e) { + throw new ElasticsearchExporterException("Failed to parse url " + url, e); + } + + return new HttpHost(uri.getHost(), uri.getPort(), uri.getScheme()); + } + + protected String indexFor(JSONObject record) { + Instant timestamp = Instant.ofEpochMilli(record.getLong("timestamp")); + return indexPrefixForValueTypeWithDelimiter(ExtendedValueType.valueOf(record.getString("valueType"))) + formatter.format(timestamp); + } + + protected String idFor(JSONObject record) { + return record.getInt("partitionId") + "-" + record.getLong("position"); + } + + protected String typeFor(JSONObject record) { + return "_doc"; + } + + protected String indexPrefixForValueTypeWithDelimiter(ExtendedValueType extendedValueType) { + return indexPrefixForValueType(extendedValueType) + INDEX_DELIMITER; + } + + private String aliasNameForValueType(ExtendedValueType extendedValueType) { + return indexPrefix + ALIAS_DELIMITER + valueTypeToString(extendedValueType); + } + + private String indexPrefixForValueType(ExtendedValueType valueType) { + String version = VersionUtil.getVersionLowerCase(); + + return indexPrefix + INDEX_DELIMITER + valueTypeToString(valueType) + INDEX_DELIMITER + version; + } + + private static String valueTypeToString(ExtendedValueType extendedValueType) { + if (extendedValueType.name().equalsIgnoreCase("process_instance")) { + extendedValueType = ExtendedValueType.WORKFLOW_INSTANCE; + } + return extendedValueType.name().toLowerCase().replaceAll("_", "-"); + } + + private static String indexTemplateForValueType(ExtendedValueType valueType) { + return String.format(INDEX_TEMPLATE_FILENAME_PATTERN, valueTypeToString(valueType)); + } +} diff --git a/ph-ee-importer-es/src/main/java/org/mifos/phee/kafkastreamer/importer/ElasticsearchExporterConfiguration.java b/ph-ee-importer-es/src/main/java/org/mifos/phee/kafkastreamer/importer/ElasticsearchExporterConfiguration.java new file mode 100644 index 000000000..a479ecb78 --- /dev/null +++ b/ph-ee-importer-es/src/main/java/org/mifos/phee/kafkastreamer/importer/ElasticsearchExporterConfiguration.java @@ -0,0 +1,173 @@ +/* + * Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH under + * one or more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Licensed under the Zeebe Community License 1.0. You may not use this file + * except in compliance with the Zeebe Community License 1.0. + */ +package org.mifos.phee.kafkastreamer.importer; + +import io.zeebe.protocol.record.Record; +import io.zeebe.protocol.record.RecordType; +import io.zeebe.protocol.record.ValueType; +import org.springframework.stereotype.Component; + +@Component +public class ElasticsearchExporterConfiguration { + + // elasticsearch http url + public String url = "http://localhost:9200"; + + public final IndexConfiguration index = new IndexConfiguration(); + public final BulkConfiguration bulk = new BulkConfiguration(); + private final AuthenticationConfiguration authentication = new AuthenticationConfiguration(); + + public boolean hasAuthenticationPresent() { + return getAuthentication().isPresent(); + } + + public AuthenticationConfiguration getAuthentication() { + return authentication; + } + + @Override + public String toString() { + return "ElasticsearchExporterConfiguration{" + "url='" + url + '\'' + ", index=" + index + ", bulk=" + bulk + '}'; + } + + public boolean shouldIndexRecord(final Record record) { + return shouldIndexRecordType(record.getRecordType()) && shouldIndexValueType(record.getValueType()); + } + + public boolean shouldIndexValueType(final ValueType valueType) { + switch (valueType) { + case DEPLOYMENT: + return index.deployment; + case ERROR: + return index.error; + case INCIDENT: + return index.incident; + case JOB: + return index.job; + case JOB_BATCH: + return index.jobBatch; + case MESSAGE: + return index.message; + case MESSAGE_SUBSCRIPTION: + return index.messageSubscription; + case VARIABLE: + return index.variable; + case VARIABLE_DOCUMENT: + return index.variableDocument; + case WORKFLOW_INSTANCE: + return index.workflowInstance; + case WORKFLOW_INSTANCE_CREATION: + return index.workflowInstanceCreation; + case WORKFLOW_INSTANCE_SUBSCRIPTION: + return index.workflowInstanceSubscription; + default: + return false; + } + } + + public boolean shouldIndexRecordType(final RecordType recordType) { + switch (recordType) { + case EVENT: + return index.event; + case COMMAND: + return index.command; + case COMMAND_REJECTION: + return index.rejection; + default: + return false; + } + } + + public static class IndexConfiguration { + + // prefix for index and templates + public String prefix = "zeebe-record"; + + // update index template on startup + public boolean createTemplate = true; + + // record types to export + public boolean command = false; + public boolean event = true; + public boolean rejection = false; + + // value types to export + public boolean deployment = true; + public boolean error = false; + public boolean incident = true; + public boolean job = false; + public boolean jobBatch = false; + public boolean message = false; + public boolean messageSubscription = false; + public boolean variable = true; + public boolean variableDocument = false; + public boolean workflowInstance = true; + public boolean workflowInstanceCreation = false; + public boolean workflowInstanceSubscription = false; + + // size limits + public int ignoreVariablesAbove = 8191; + + @Override + public String toString() { + return "IndexConfiguration{" + "indexPrefix='" + prefix + '\'' + ", createTemplate=" + createTemplate + ", command=" + command + + ", event=" + event + ", rejection=" + rejection + ", error=" + error + ", deployment=" + deployment + ", incident=" + + incident + ", job=" + job + ", message=" + message + ", messageSubscription=" + messageSubscription + ", variable=" + + variable + ", variableDocument=" + variableDocument + ", workflowInstance=" + workflowInstance + + ", workflowInstanceCreation=" + workflowInstanceCreation + ", workflowInstanceSubscription=" + + workflowInstanceSubscription + ", ignoreVariablesAbove=" + ignoreVariablesAbove + '}'; + } + } + + public static class BulkConfiguration { + + // delay before forced flush + public int delay = 5; + // bulk size before flush + public int size = 1_000; + // memory limit of the bulk in bytes before flush + public int memoryLimit = 10 * 1024 * 1024; + + @Override + public String toString() { + return "BulkConfiguration{" + "delay=" + delay + ", size=" + size + ", memoryLimit=" + memoryLimit + '}'; + } + } + + public static class AuthenticationConfiguration { + + private String username; + private String password; + + public boolean isPresent() { + return (username != null && !username.isEmpty()) && (password != null && !password.isEmpty()); + } + + public String getUsername() { + return username; + } + + public void setUsername(final String username) { + this.username = username; + } + + public String getPassword() { + return password; + } + + public void setPassword(final String password) { + this.password = password; + } + + @Override + public String toString() { + // we don't want to expose this information + return "AuthenticationConfiguration{Confidential information}"; + } + } +} diff --git a/ph-ee-importer-es/src/main/java/org/mifos/phee/kafkastreamer/importer/ElasticsearchTemplateSetup.java b/ph-ee-importer-es/src/main/java/org/mifos/phee/kafkastreamer/importer/ElasticsearchTemplateSetup.java new file mode 100644 index 000000000..d568051f6 --- /dev/null +++ b/ph-ee-importer-es/src/main/java/org/mifos/phee/kafkastreamer/importer/ElasticsearchTemplateSetup.java @@ -0,0 +1,67 @@ +/* + * Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH under + * one or more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Licensed under the Zeebe Community License 1.0. You may not use this file + * except in compliance with the Zeebe Community License 1.0. + */ +package org.mifos.phee.kafkastreamer.importer; + +import io.zeebe.exporter.ElasticsearchExporterConfiguration.IndexConfiguration; +import javax.annotation.PostConstruct; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +@Component +public class ElasticsearchTemplateSetup { + + public static final String ZEEBE_RECORD_TEMPLATE_JSON = "/zeebe-record-template.json"; + private Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Value("${importer.elasticsearch.index-prefix}") + private String indexPrefix; + + @Autowired + private ElasticsearchClient client; + + @PostConstruct + public void setup() { + createIndexTemplates(); + } + + private void createIndexTemplates() { + IndexConfiguration indexConfiguration = new IndexConfiguration(); + + if (indexConfiguration.createTemplate) { + createRootIndexTemplate(); + + if (indexConfiguration.incident) { + createValueIndexTemplate(ExtendedValueType.INCIDENT); + } + if (indexConfiguration.variable) { + createValueIndexTemplate(ExtendedValueType.VARIABLE); + } + if (indexConfiguration.workflowInstance) { + createValueIndexTemplate(ExtendedValueType.WORKFLOW_INSTANCE); + } + } + } + + private void createRootIndexTemplate() { + final String templateName = indexPrefix; + final String aliasName = indexPrefix; + final String filename = ZEEBE_RECORD_TEMPLATE_JSON; + if (!client.putIndexTemplate(templateName, aliasName, filename)) { + logger.warn("Put index template {} from file {} was not acknowledged", templateName, filename); + } + } + + private void createValueIndexTemplate(final ExtendedValueType extendedValueType) { + if (!client.putIndexTemplate(extendedValueType)) { + logger.warn("Put index template for value type {} was not acknowledged", extendedValueType); + } + } +} diff --git a/ph-ee-importer-es/src/main/java/org/mifos/phee/kafkastreamer/importer/ExtendedValueType.java b/ph-ee-importer-es/src/main/java/org/mifos/phee/kafkastreamer/importer/ExtendedValueType.java new file mode 100644 index 000000000..d90d79b32 --- /dev/null +++ b/ph-ee-importer-es/src/main/java/org/mifos/phee/kafkastreamer/importer/ExtendedValueType.java @@ -0,0 +1,101 @@ +package org.mifos.phee.kafkastreamer.importer; + +public enum ExtendedValueType { + + JOB((short) 0), + + DEPLOYMENT((short) 4), + + WORKFLOW_INSTANCE((short) 5), + + INCIDENT((short) 6), + + PROCESS((short) 7), + + PROCESS_INSTANCE((short) 8), + + MESSAGE((short) 10), + + MESSAGE_SUBSCRIPTION((short) 11), + + WORKFLOW_INSTANCE_SUBSCRIPTION((short) 12), + + JOB_BATCH((short) 14), + + TIMER((short) 15), + + MESSAGE_START_EVENT_SUBSCRIPTION((short) 16), + + VARIABLE((short) 17), + + VARIABLE_DOCUMENT((short) 18), + + WORKFLOW_INSTANCE_CREATION((short) 19), + + ERROR((short) 20), + + WORKFLOW_INSTANCE_RESULT((short) 21), + + /** + * To be used to represent a not known value from a later version. + */ + SBE_UNKNOWN((short) 255), + + /** + * To be used to represent not present or null. + */ + NULL_VAL((short) 255); + + private final short value; + + ExtendedValueType(final short value) { + this.value = value; + } + + public short value() { + return value; + } + + public static ExtendedValueType get(final short value) { + switch (value) { + case 0: + return JOB; + case 4: + return DEPLOYMENT; + case 5: + return WORKFLOW_INSTANCE; + case 6: + return INCIDENT; + case 7: + return PROCESS; + case 8: + return PROCESS_INSTANCE; + case 10: + return MESSAGE; + case 11: + return MESSAGE_SUBSCRIPTION; + case 12: + return WORKFLOW_INSTANCE_SUBSCRIPTION; + case 14: + return JOB_BATCH; + case 15: + return TIMER; + case 16: + return MESSAGE_START_EVENT_SUBSCRIPTION; + case 17: + return VARIABLE; + case 18: + return VARIABLE_DOCUMENT; + case 19: + return WORKFLOW_INSTANCE_CREATION; + case 20: + return ERROR; + case 21: + return WORKFLOW_INSTANCE_RESULT; + case 255: + return NULL_VAL; + } + + return SBE_UNKNOWN; + } +} diff --git a/ph-ee-importer-es/src/main/java/org/mifos/phee/kafkastreamer/importer/KafkaConfiguration.java b/ph-ee-importer-es/src/main/java/org/mifos/phee/kafkastreamer/importer/KafkaConfiguration.java new file mode 100644 index 000000000..17d530b54 --- /dev/null +++ b/ph-ee-importer-es/src/main/java/org/mifos/phee/kafkastreamer/importer/KafkaConfiguration.java @@ -0,0 +1,70 @@ +package org.mifos.phee.kafkastreamer.importer; + +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; +import org.apache.kafka.clients.consumer.ConsumerConfig; +import org.apache.kafka.common.serialization.StringDeserializer; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.kafka.annotation.EnableKafka; +import org.springframework.kafka.config.ConcurrentKafkaListenerContainerFactory; +import org.springframework.kafka.config.KafkaListenerContainerFactory; +import org.springframework.kafka.core.ConsumerFactory; +import org.springframework.kafka.core.DefaultKafkaConsumerFactory; +import org.springframework.kafka.listener.ConcurrentMessageListenerContainer; + +@EnableKafka +@Configuration +public class KafkaConfiguration { + + private Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Value("${kafka.brokers}") + private String kafkaBrokers; + + @Bean + KafkaListenerContainerFactory> kafkaListenerContainerFactory() { + ConcurrentKafkaListenerContainerFactory factory = new ConcurrentKafkaListenerContainerFactory<>(); + factory.setConsumerFactory(consumerFactory()); + factory.setConcurrency(3); // TODO externalize + factory.getContainerProperties().setPollTimeout(3000); // TODO externalize + + return factory; + } + + @Bean + public ConsumerFactory consumerFactory() { + return new DefaultKafkaConsumerFactory<>(consumerConfigs()); + } + + @Bean + public Map consumerConfigs() { + String hostname = buildKafkaClientId(logger); + + Map properties = new HashMap<>(); + properties.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, kafkaBrokers); + properties.put(ConsumerConfig.CLIENT_ID_CONFIG, hostname); + properties.put(ConsumerConfig.GROUP_ID_CONFIG, hostname); + properties.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class.getName()); + properties.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class.getName()); + return properties; + } + + public static String buildKafkaClientId(Logger logger) { + String clientId; + try { + clientId = InetAddress.getLocalHost().getHostName(); + } catch (UnknownHostException e) { + logger.error("failed to resolve local hostname, picking random clientId"); + clientId = UUID.randomUUID().toString(); + } + return clientId; + } + +} diff --git a/ph-ee-importer-es/src/main/java/org/mifos/phee/kafkastreamer/importer/KafkaElasticImportApplication.java b/ph-ee-importer-es/src/main/java/org/mifos/phee/kafkastreamer/importer/KafkaElasticImportApplication.java new file mode 100644 index 000000000..995aee29c --- /dev/null +++ b/ph-ee-importer-es/src/main/java/org/mifos/phee/kafkastreamer/importer/KafkaElasticImportApplication.java @@ -0,0 +1,15 @@ +package org.mifos.phee.kafkastreamer.importer; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.scheduling.annotation.EnableScheduling; + +@EnableScheduling +@SpringBootApplication +public class KafkaElasticImportApplication { + + public static void main(String[] args) { + SpringApplication.run(KafkaElasticImportApplication.class, args); + } + +} diff --git a/ph-ee-importer-es/src/main/java/org/mifos/phee/kafkastreamer/importer/KafkaImporter.java b/ph-ee-importer-es/src/main/java/org/mifos/phee/kafkastreamer/importer/KafkaImporter.java new file mode 100644 index 000000000..93a8e18f3 --- /dev/null +++ b/ph-ee-importer-es/src/main/java/org/mifos/phee/kafkastreamer/importer/KafkaImporter.java @@ -0,0 +1,44 @@ +package org.mifos.phee.kafkastreamer.importer; + +import org.json.JSONObject; +import org.mifos.phee.kafkastreamer.importer.service.MaskingService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.kafka.annotation.KafkaListener; +import org.springframework.stereotype.Component; + +@Component +public class KafkaImporter { + + private Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Autowired + private ElasticsearchClient elasticsearchClient; + + @Value("${importer.masking.enable}") + private boolean maskingEnable; + + @Autowired + private MaskingService maskingService; + + @KafkaListener(topics = "${importer.kafka.topic}") + public void listen(String rawData) throws Exception { + if (maskingEnable) { + logger.debug("Before: {}", rawData); + rawData = maskingService.mask(rawData); + logger.debug("After: {}", rawData); + } + + JSONObject data = new JSONObject(rawData); + logger.trace("from kafka: {}", data.toString(2)); + + elasticsearchClient.index(data); + + if (elasticsearchClient.shouldFlush()) { + int flushed = elasticsearchClient.flush(); + logger.info("flushed {} records to ES", flushed); + } + } +} diff --git a/ph-ee-importer-es/src/main/java/org/mifos/phee/kafkastreamer/importer/KafkaVariables.java b/ph-ee-importer-es/src/main/java/org/mifos/phee/kafkastreamer/importer/KafkaVariables.java new file mode 100644 index 000000000..55155593e --- /dev/null +++ b/ph-ee-importer-es/src/main/java/org/mifos/phee/kafkastreamer/importer/KafkaVariables.java @@ -0,0 +1,18 @@ +package org.mifos.phee.kafkastreamer.importer; + +public class KafkaVariables { + + public static final String VALUE_TYPE = "valueType"; + public static final String VALUE = "value"; + public static final String NAME = "name"; + public static final String VALUE_TYPE_VARIABLE = "VARIABLE"; + public static final String CHANNEL_REQUEST = "channelRequest"; + public static final String CHANNEL_GSMA_REQUEST = "gsmaChannelRequest"; + public static final String PAYER = "payer"; + public static final String PAYEE = "payee"; + public static final String PARTY_ID_INFO = "partyIdInfo"; + public static final String PARTY_IDENTIFIER = "partyIdentifier"; + public static final String DEBIT_PARTY = "debitParty"; + public static final String CREDIT_PARTY = "creditParty"; + public static final String PARTY_ID_IDENTIFIER = "partyIdIdentifier"; +} diff --git a/ph-ee-importer-es/src/main/java/org/mifos/phee/kafkastreamer/importer/PaymentsIndexConfiguration.java b/ph-ee-importer-es/src/main/java/org/mifos/phee/kafkastreamer/importer/PaymentsIndexConfiguration.java new file mode 100644 index 000000000..e7d4d919f --- /dev/null +++ b/ph-ee-importer-es/src/main/java/org/mifos/phee/kafkastreamer/importer/PaymentsIndexConfiguration.java @@ -0,0 +1,237 @@ +package org.mifos.phee.kafkastreamer.importer; + +import java.util.ArrayList; +import java.util.List; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +@Component +public class PaymentsIndexConfiguration { + + public List variables = new ArrayList(); + + @Value("${reporting.fields.amount}") + private Boolean amountVal; + + @Value("${reporting.fields.accountId}") + private Boolean accountIdVal; + + @Value("${reporting.fields.errorCode}") + private Boolean errorCodeVal; + + @Value("${reporting.fields.errorDescription}") + private Boolean errorDescriptionVal; + + @Value("${reporting.fields.externalId}") + private Boolean externalIdVal; + + @Value("${reporting.fields.initiator}") + private Boolean initiatorVal; + + @Value("${reporting.fields.initiatorType}") + private Boolean initiatorTypeVal; + + @Value("${reporting.fields.isNotificationsFailureEnabled}") + private Boolean isNotificationsFailureEnabledVal; + + @Value("${reporting.fields.isNotificationsSuccessEnabled}") + private Boolean isNotificationsSuccessEnabledVal; + + @Value("${reporting.fields.mpesaTransactionId}") + private Boolean mpesaTransactionIdVal; + + @Value("${reporting.fields.mpesaTransactionStatusRetryCount}") + private Boolean mpesaTransactionStatusRetryCountVal; + + @Value("${reporting.fields.originDate}") + private Boolean originDateVal; + + @Value("${reporting.fields.partyLookupFailed}") + private Boolean partyLookupFailedVal; + + @Value("${reporting.fields.phoneNumber}") + private Boolean phoneNumberVal; + + @Value("${reporting.fields.processDefinitionKey}") + private Boolean processDefinitionKeyVal; + + @Value("${reporting.fields.processInstanceKey}") + private Boolean processInstanceKeyVal; + + @Value("${reporting.fields.scenario}") + private Boolean scenarioVal; + + @Value("${reporting.fields.tenantId}") + private Boolean tenantIdVal; + + @Value("${reporting.fields.timer}") + private Boolean timerVal; + + @Value("${reporting.fields.timestamp}") + private Boolean timestampVal; + + @Value("${reporting.fields.transactionFailed}") + private Boolean transactionFailedVal; + + @Value("${reporting.fields.transactionId}") + private Boolean transactionIdVal; + + @Value("${reporting.fields.transferCreateFailed}") + private Boolean transferCreateFailedVal; + + @Value("${reporting.fields.transferSettlementFailed}") + private Boolean transferSettlementFailedVal; + + @Value("${reporting.fields.transferResponseCREATE}") + private Boolean transferResponseCREATEVal; + + @Value("${reporting.fields.currency}") + private Boolean currencyVal; + + @Value("${reporting.fields.errorInformation}") + private Boolean errorInformationVal; + + @Value("${reporting.fields.customData}") + private Boolean customDataVal; + + @Value("${reporting.fields.confirmationReceived}") + private Boolean confirmationReceivedVal; + + @Value("${reporting.fields.clientCorrelationId}") + private Boolean clientCorrelationIdVal; + + @Value("${reporting.fields.ams}") + private Boolean amsVal; + + public PaymentsIndexConfiguration() {} + + public List getVariables() { + Boolean amount = amountVal; + Boolean accountId = accountIdVal; + Boolean errorCode = errorCodeVal; + Boolean errorDescription = errorDescriptionVal; + Boolean externalId = externalIdVal; + Boolean initiator = initiatorVal; + Boolean initiatorType = initiatorTypeVal; + Boolean isNotificationsFailureEnabled = isNotificationsFailureEnabledVal; + Boolean isNotificationsSuccessEnabled = isNotificationsFailureEnabledVal; + Boolean mpesaTransactionId = mpesaTransactionIdVal; + Boolean mpesaTransactionStatusRetryCount = mpesaTransactionStatusRetryCountVal; + Boolean originDate = originDateVal; + Boolean partyLookupFailed = partyLookupFailedVal; + Boolean phoneNumber = phoneNumberVal; + Boolean processDefinitionKey = processDefinitionKeyVal; + Boolean processInstanceKey = processInstanceKeyVal; + Boolean scenario = scenarioVal; + Boolean tenantId = tenantIdVal; + Boolean timer = timerVal; + Boolean timestamp = timestampVal; + Boolean transactionFailed = transactionFailedVal; + Boolean transactionId = transactionIdVal; + Boolean transferCreateFailed = transferCreateFailedVal; + Boolean transferSettlementFailed = transferSettlementFailedVal; + Boolean transferResponseCREATE = transferResponseCREATEVal; + Boolean currency = currencyVal; + Boolean errorInformation = errorInformationVal; + Boolean customData = customDataVal; + Boolean confirmationReceived = confirmationReceivedVal; + Boolean clientCorrelationId = clientCorrelationIdVal; + Boolean ams = amsVal; + + if (amount) { + variables.add("amount"); + } + if (accountId) { + variables.add("accountId"); + } + if (errorCode) { + variables.add("errorCode"); + } + if (errorDescription) { + variables.add("errorDescription"); + } + if (externalId) { + variables.add("externalId"); + } + if (initiator) { + variables.add("initiator"); + } + if (initiatorType) { + variables.add("initiatorType"); + } + if (isNotificationsFailureEnabled) { + variables.add("isNotificationsFailureEnabled"); + } + if (isNotificationsSuccessEnabled) { + variables.add("isNotificationsSuccessEnabled"); + } + if (mpesaTransactionId) { + variables.add("mpesaTransactionId"); + } + if (mpesaTransactionStatusRetryCount) { + variables.add("mpesaTransactionStatusRetryCount"); + } + if (originDate) { + variables.add("originDate"); + } + if (partyLookupFailed) { + variables.add("partyLookupFailed"); + } + if (phoneNumber) { + variables.add("phoneNumber"); + } + if (processDefinitionKey) { + variables.add("processDefinitionKey"); + } + if (processInstanceKey) { + variables.add("processInstanceKey"); + } + if (scenario) { + variables.add("scenario"); + } + if (tenantId) { + variables.add("tenantId"); + } + if (timer) { + variables.add("timer"); + } + if (timestamp) { + variables.add("timestamp"); + } + if (transactionFailed) { + variables.add("transactionFailed"); + } + if (transactionId) { + variables.add("transactionId"); + } + if (transferCreateFailed) { + variables.add("transferCreateFailed"); + } + if (transferSettlementFailed) { + variables.add("transferSettlementFailed"); + } + if (transferResponseCREATE) { + variables.add("transferResponse-CREATE"); + } + if (currency) { + variables.add("currency"); + } + if (errorInformation) { + variables.add("errorInformation"); + } + if (customData) { + variables.add("customData"); + } + if (confirmationReceived) { + variables.add("confirmationReceived"); + } + if (clientCorrelationId) { + variables.add("clientCorrelationId"); + } + if (ams) { + variables.add("ams"); + } + return variables; + } + +} diff --git a/ph-ee-importer-es/src/main/java/org/mifos/phee/kafkastreamer/importer/service/MaskingService.java b/ph-ee-importer-es/src/main/java/org/mifos/phee/kafkastreamer/importer/service/MaskingService.java new file mode 100644 index 000000000..20057dff8 --- /dev/null +++ b/ph-ee-importer-es/src/main/java/org/mifos/phee/kafkastreamer/importer/service/MaskingService.java @@ -0,0 +1,14 @@ +package org.mifos.phee.kafkastreamer.importer.service; + +public interface MaskingService { + + /** + * Takes raw data from kafka stream and mask the relevant information. + * + * @param rawData + * data from kafka stream + * @return the masked data + */ + String mask(String rawData) throws Exception; + +} diff --git a/ph-ee-importer-es/src/main/java/org/mifos/phee/kafkastreamer/importer/service/MaskingServiceImpl.java b/ph-ee-importer-es/src/main/java/org/mifos/phee/kafkastreamer/importer/service/MaskingServiceImpl.java new file mode 100644 index 000000000..ebf33110d --- /dev/null +++ b/ph-ee-importer-es/src/main/java/org/mifos/phee/kafkastreamer/importer/service/MaskingServiceImpl.java @@ -0,0 +1,161 @@ +package org.mifos.phee.kafkastreamer.importer.service; + +import static org.apache.commons.text.StringEscapeUtils.unescapeJava; + +import java.util.ArrayList; +import java.util.List; + +import org.json.JSONArray; +import org.json.JSONObject; +import org.mifos.phee.kafkastreamer.importer.KafkaVariables; +import org.mifos.phee.kafkastreamer.importer.utils.AesUtil; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; + +@Service +public class MaskingServiceImpl implements MaskingService { + + private Logger log = LoggerFactory.getLogger(this.getClass()); + + @Value("#{'${importer.masking.fields}'.split(',')}") + private List fieldsToBeMasked; + + @Value("${importer.masking.key}") + private String encryptionKey; + + @Override + public String mask(String rawData) throws Exception { + log.debug("Inside mask"); + JSONObject data = new JSONObject(rawData); + String valueType = data.getString(KafkaVariables.VALUE_TYPE); + if (!valueType.equalsIgnoreCase(KafkaVariables.VALUE_TYPE_VARIABLE)) { + // do nothing when record value type is [KafkaVariables.VALUE_TYPE_VARIABLE] + log.debug("Do nothing"); + return rawData; + } + + JSONObject value = data.getJSONObject(KafkaVariables.VALUE); + String name = value.getString(KafkaVariables.NAME); + log.debug("NAME: {}, VALUE: {}", name, value); + if (name.equalsIgnoreCase(KafkaVariables.CHANNEL_REQUEST)) { + log.debug("Inside CHANNEL_REQUEST condition"); + String valueStringifiedJsonString = value.getString(KafkaVariables.VALUE); + JSONObject channelRequest = getJsonObjectFromStringifiedJson(valueStringifiedJsonString); + + ListfieldsRequiredMasking=new ArrayList<>(); + fieldsRequiredMasking.add(KafkaVariables.PAYER); + fieldsRequiredMasking.add(KafkaVariables.PAYEE); + if(AesUtil.checkForMaskingFields(channelRequest,fieldsRequiredMasking)){ + return rawData; + } + String payerPartyIdentifier = "", payeePartyIdentifier = ""; + + if (channelRequest.has("payer")) { + Object payerValue = channelRequest.get("payer"); + Object payeeValue = channelRequest.get("payee"); + + if (payerValue instanceof JSONArray) { + JSONArray payerArray = (JSONArray) payerValue; + JSONArray payeeArray = (JSONArray) payeeValue; + + JSONObject payerObject = payerArray.getJSONObject(0); + payerPartyIdentifier = payerObject.getString(KafkaVariables.PARTY_ID_IDENTIFIER); + JSONObject payeeObject = payeeArray.getJSONObject(0); + payeePartyIdentifier = payeeObject.getString(KafkaVariables.PARTY_ID_IDENTIFIER); + + payerPartyIdentifier = encryptData(payerPartyIdentifier); + payeePartyIdentifier = encryptData(payeePartyIdentifier); + + payerObject.put(KafkaVariables.PARTY_ID_IDENTIFIER, payerPartyIdentifier); + payeeObject.put(KafkaVariables.PARTY_ID_IDENTIFIER, payeePartyIdentifier); + } else if (payerValue instanceof JSONObject) { + JSONObject payerObject = (JSONObject) payerValue; + JSONObject payeeObject = (JSONObject) payeeValue; + payerPartyIdentifier = payerObject.getJSONObject(KafkaVariables.PARTY_ID_INFO) + .getString(KafkaVariables.PARTY_IDENTIFIER); + payeePartyIdentifier = payeeObject.getJSONObject(KafkaVariables.PARTY_ID_INFO) + .getString(KafkaVariables.PARTY_IDENTIFIER); + payerPartyIdentifier = encryptData(payerPartyIdentifier); + payeePartyIdentifier = encryptData(payeePartyIdentifier); + + channelRequest.getJSONObject(KafkaVariables.PAYER).getJSONObject(KafkaVariables.PARTY_ID_INFO) + .put(KafkaVariables.PARTY_IDENTIFIER, payerPartyIdentifier); + channelRequest.getJSONObject(KafkaVariables.PAYEE).getJSONObject(KafkaVariables.PARTY_ID_INFO) + .put(KafkaVariables.PARTY_IDENTIFIER, payeePartyIdentifier); + } + + } + value.put(KafkaVariables.VALUE, channelRequest.toString()); + } else if (name.equalsIgnoreCase(KafkaVariables.CHANNEL_GSMA_REQUEST)) { + log.debug("Inside CHANNEL_GSMA_REQUEST condition"); + String valueStringifiedJsonString = value.getString(KafkaVariables.VALUE); + JSONObject channelGsmaRequest = getJsonObjectFromStringifiedJson(valueStringifiedJsonString); + + ListfieldsRequiredMasking=new ArrayList<>(); + fieldsRequiredMasking.add(KafkaVariables.DEBIT_PARTY); + fieldsRequiredMasking.add(KafkaVariables.CREDIT_PARTY); + + if(AesUtil.checkForMaskingFields(channelGsmaRequest,fieldsRequiredMasking)){ + return rawData; + } + + String debitIdentifier = channelGsmaRequest.getJSONArray(KafkaVariables.DEBIT_PARTY).getJSONObject(0) + .getString(KafkaVariables.VALUE); + String creditIdentifier = channelGsmaRequest.getJSONArray(KafkaVariables.CREDIT_PARTY).getJSONObject(0) + .getString(KafkaVariables.VALUE); + + debitIdentifier = encryptData(debitIdentifier); + creditIdentifier = encryptData(creditIdentifier); + + channelGsmaRequest.getJSONArray(KafkaVariables.DEBIT_PARTY).getJSONObject(0).put(KafkaVariables.VALUE, debitIdentifier); + channelGsmaRequest.getJSONArray(KafkaVariables.CREDIT_PARTY).getJSONObject(0).put(KafkaVariables.VALUE, creditIdentifier); + + value.put(KafkaVariables.VALUE, channelGsmaRequest.toString()); + } else { + log.debug("Inside ELSE condition"); + for (String field : fieldsToBeMasked) { + log.debug("Field: {}", field); + if (name.equalsIgnoreCase(field)) { + log.debug("Field matched: {}", name); + String fieldValue = value.getString(KafkaVariables.VALUE); + fieldValue = encryptData(fieldValue); + value.put(KafkaVariables.VALUE, fieldValue); + } + } + } + + data.put(KafkaVariables.VALUE, value); + return data.toString(); + } + + // un-stringifies and returns the [JSONObject] instance from string + private JSONObject getJsonObjectFromStringifiedJson(String stringifiedJson) { + String s = unescapeJava(stringifiedJson); + s = s.substring(1, s.length() - 1); + return new JSONObject(s); + } + + // encrypts the data based on the length of the data passed + private String encryptData(String data) throws Exception { + String masked = ""; + String unmasked = ""; + if (data.isEmpty()) { + // nothing to mask + return data; + } else if (data.length() == 1) { + // mask everything + masked = AesUtil.encrypt(data, encryptionKey); + } else if (data.length() == 2) { + // leave last digit and mask first + unmasked = data.substring(data.length() - 1); + masked = AesUtil.encrypt(data.substring(0, data.length() - 1), encryptionKey); + } else { + // leave last 2 digit and mask rest of it + unmasked = data.substring(data.length() - 2); + masked = AesUtil.encrypt(data.substring(0, data.length() - 2), encryptionKey); + } + return new StringBuilder().append("{").append(masked).append("}").append(unmasked).toString(); + } +} diff --git a/ph-ee-importer-es/src/main/java/org/mifos/phee/kafkastreamer/importer/utils/AesUtil.java b/ph-ee-importer-es/src/main/java/org/mifos/phee/kafkastreamer/importer/utils/AesUtil.java new file mode 100644 index 000000000..d4261ef0a --- /dev/null +++ b/ph-ee-importer-es/src/main/java/org/mifos/phee/kafkastreamer/importer/utils/AesUtil.java @@ -0,0 +1,97 @@ +package org.mifos.phee.kafkastreamer.importer.utils; + +import java.security.NoSuchAlgorithmException; +import java.security.SecureRandom; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.KeySpec; +import java.util.List; +import javax.crypto.Cipher; +import javax.crypto.KeyGenerator; +import javax.crypto.SecretKey; +import javax.crypto.SecretKeyFactory; +import javax.crypto.spec.PBEKeySpec; +import javax.crypto.spec.SecretKeySpec; +import org.apache.commons.codec.binary.Base64; +import org.json.JSONObject; + +public class AesUtil { + + /** + * Encrypts the string data using AES algorithm + * + * @param plaintext + * the string data to be encrypted + * @param stringKey + * key in the Base64 string encoded format + * @return ecnypted data + * @throws Exception + */ + public static String encrypt(String plaintext, String stringKey) throws Exception { + SecretKey key = getSecretKey(stringKey); + Cipher cipher = Cipher.getInstance("AES"); + cipher.init(Cipher.ENCRYPT_MODE, key); + return base64Encode(cipher.doFinal(plaintext.getBytes())); + } + + /** + * Decrypts the data using AES algorithm + * + * @param encryptedString + * Base64 encoded encrypted string + * @param stringKey + * key in the Base64 string encoded format + * @return decrypted data in string format + * @throws Exception + */ + public static String decrypt(String encryptedString, String stringKey) throws Exception { + SecretKey key = getSecretKey(stringKey); + byte[] cipherText = base64Decode(encryptedString); + Cipher cipher = Cipher.getInstance("AES"); + cipher.init(Cipher.DECRYPT_MODE, key); + return new String(cipher.doFinal(cipherText)); + } + + // encodes the given byte array to Base64 + public static String base64Encode(byte[] data) { + return Base64.encodeBase64String(data); + } + + // decodes the base64 encoded String to byte array + public static byte[] base64Decode(String base64EncodedString) { + return Base64.decodeBase64(base64EncodedString); + } + + public static SecretKey deriveKey(String key, byte[] salt, int iterationCount, int keyLength) throws NoSuchAlgorithmException, InvalidKeySpecException { + SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256"); + KeySpec spec = new PBEKeySpec(key.toCharArray(), salt, iterationCount, keyLength); + SecretKey tmp = factory.generateSecret(spec); + return new SecretKeySpec(tmp.getEncoded(), "AES"); + } + + // get instance of class [SecretKey] using the string format of the key + public static SecretKey getSecretKey(String key) throws NoSuchAlgorithmException, InvalidKeySpecException { + byte[] aesByte = base64Decode(key); + int iterationCount = 10000; + int keyLength = 256; // adding key length + + SecretKey newKey = deriveKey(key, aesByte, iterationCount, keyLength); + return newKey; + } + + // generates and returns the string encoded AES key + public static String generateSecretKey() throws NoSuchAlgorithmException { + KeyGenerator keyGenerator = KeyGenerator.getInstance("AES"); + keyGenerator.init(256, new SecureRandom()); + SecretKey key = keyGenerator.generateKey(); + return base64Encode(key.getEncoded()); + } + public static boolean checkForMaskingFields(JSONObject jsonObject, List fieldsRequiredMasking) { + for (String field : fieldsRequiredMasking) { + if (!jsonObject.has(field)) { + return true; + } + } + return false; + } + +} diff --git a/ph-ee-importer-es/src/main/resources/application.yml b/ph-ee-importer-es/src/main/resources/application.yml new file mode 100644 index 000000000..f05f2347f --- /dev/null +++ b/ph-ee-importer-es/src/main/resources/application.yml @@ -0,0 +1,62 @@ +kafka: + brokers: "kafka:9092" + +importer: + masking: + enable: true + key: "" + fields: "partyIdentifier,partyId" + kafka: + topic: "zeebe-export" + elasticsearch: + url: "https://ph-ee-elasticsearch:9200/" + bulk-size: 20 + index-prefix: "zeebe-record" + +elasticsearch: + security: + enabled: false + sslVerification: false + username: "elastic" + password: "somepassword" + +logging: + level: + ROOT: INFO + pattern: + console: "%clr(%d{dd-MM-yyyy HH:mm:ss.SSS}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr([%35.35t]){faint} %clr(%-28.28logger{28}){cyan} %clr(:){faint}%X{BUSINESS-LOG} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}" + +reporting: + enabled: true + fields: + amount: true + accountId: true + ams: true + clientCorrelationId: true + currency: true + customData: false + confirmationReceived: false + errorCode: false + errorDescription: true + errorInformation: true + externalId: true + initiator: false + initiatorType: false + isNotificationsFailureEnabled: false + isNotificationsSuccessEnabled: false + mpesaTransactionId: false + mpesaTransactionStatusRetryCount: false + originDate: false + partyLookupFailed: false + phoneNumber: true + processDefinitionKey: false + processInstanceKey: true + scenario: false + tenantId: false + timer: false + timestamp: true + transactionFailed: false + transactionId: false + transferCreateFailed: false + transferSettlementFailed: false + transferResponseCREATE: false diff --git a/ph-ee-importer-es/src/main/resources/kibana/Dashboard b/ph-ee-importer-es/src/main/resources/kibana/Dashboard new file mode 100644 index 000000000..3d040113e --- /dev/null +++ b/ph-ee-importer-es/src/main/resources/kibana/Dashboard @@ -0,0 +1,9 @@ +{"attributes":{"fieldAttrs":"{\"value.bpmnProcessId\":{\"count\":4},\"value.processDefinitionKey\":{\"count\":4},\"value.processDefinitionVersion\":{\"count\":3},\"value.processInstanceKey\":{\"count\":3},\"value.elementId\":{\"count\":2},\"value.retries\":{\"count\":2},\"value.type\":{\"count\":2},\"intent\":{\"count\":1},\"timestamp\":{\"count\":1}}","fields":"[]","runtimeFieldMap":"{}","timeFieldName":"timestamp","title":"zeebe-*"},"coreMigrationVersion":"7.13.2","id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","migrationVersion":{"index-pattern":"7.11.0"},"references":[],"type":"index-pattern","updated_at":"2022-01-17T09:27:43.036Z","version":"WzEwODIxLDEzXQ=="} +{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[],\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\"}"},"title":"ProcessInstanceCount","uiStateJSON":"{}","version":1,"visState":"{\"title\":\"ProcessInstanceCount\",\"type\":\"table\",\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"cardinality\",\"params\":{\"field\":\"value.processInstanceKey\",\"customLabel\":\"processInstanceCount\"},\"schema\":\"metric\"},{\"id\":\"2\",\"enabled\":true,\"type\":\"terms\",\"params\":{\"field\":\"value.bpmnProcessId\",\"orderBy\":\"1\",\"order\":\"desc\",\"size\":10,\"otherBucket\":false,\"otherBucketLabel\":\"Other\",\"missingBucket\":false,\"missingBucketLabel\":\"Missing\",\"customLabel\":\"processDefinition\"},\"schema\":\"bucket\"}],\"params\":{\"perPage\":10,\"showPartialRows\":false,\"showMetricsAtAllLevels\":false,\"showTotal\":false,\"showToolbar\":false,\"totalFunc\":\"sum\",\"percentageCol\":\"\"}}"},"coreMigrationVersion":"7.13.2","id":"f21cb760-26bf-11ec-95b3-cb627b5ccd4b","migrationVersion":{"visualization":"7.13.1"},"references":[{"id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","name":"kibanaSavedObjectMeta.searchSourceJSON.index","type":"index-pattern"}],"type":"visualization","updated_at":"2022-01-17T09:27:43.036Z","version":"WzEwODIyLDEzXQ=="} +{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[],\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\"}"},"title":"ProcessInstanceKeys","uiStateJSON":"{}","version":1,"visState":"{\"title\":\"ProcessInstanceKeys\",\"type\":\"table\",\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"count\",\"params\":{},\"schema\":\"metric\"},{\"id\":\"2\",\"enabled\":true,\"type\":\"terms\",\"params\":{\"field\":\"value.bpmnProcessId\",\"orderBy\":\"1\",\"order\":\"desc\",\"size\":1005,\"otherBucket\":false,\"otherBucketLabel\":\"Other\",\"missingBucket\":false,\"missingBucketLabel\":\"Missing\",\"customLabel\":\"ProcessDef\"},\"schema\":\"bucket\"},{\"id\":\"3\",\"enabled\":true,\"type\":\"terms\",\"params\":{\"field\":\"value.processInstanceKey\",\"orderBy\":\"1\",\"order\":\"desc\",\"size\":5,\"otherBucket\":true,\"otherBucketLabel\":\"Other\",\"missingBucket\":false,\"missingBucketLabel\":\"Missing\",\"customLabel\":\"ProcessInstanceKey\"},\"schema\":\"bucket\"}],\"params\":{\"perPage\":10,\"showPartialRows\":false,\"showMetricsAtAllLevels\":false,\"showTotal\":false,\"showToolbar\":false,\"totalFunc\":\"sum\",\"percentageCol\":\"\"}}"},"coreMigrationVersion":"7.13.2","id":"df1144f0-26c0-11ec-95b3-cb627b5ccd4b","migrationVersion":{"visualization":"7.13.1"},"references":[{"id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","name":"kibanaSavedObjectMeta.searchSourceJSON.index","type":"index-pattern"}],"type":"visualization","updated_at":"2022-01-17T09:27:43.036Z","version":"WzEwODIzLDEzXQ=="} +{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[],\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\"}"},"title":"Process Variables","uiStateJSON":"{}","version":1,"visState":"{\"title\":\"Process Variables\",\"type\":\"table\",\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"count\",\"params\":{},\"schema\":\"metric\"},{\"id\":\"2\",\"enabled\":true,\"type\":\"terms\",\"params\":{\"field\":\"value.name\",\"orderBy\":\"1\",\"order\":\"desc\",\"size\":100,\"otherBucket\":false,\"otherBucketLabel\":\"Other\",\"missingBucket\":false,\"missingBucketLabel\":\"Missing\",\"customLabel\":\"variableName\"},\"schema\":\"bucket\"},{\"id\":\"3\",\"enabled\":true,\"type\":\"terms\",\"params\":{\"field\":\"value.value\",\"orderBy\":\"1\",\"order\":\"desc\",\"size\":100,\"otherBucket\":false,\"otherBucketLabel\":\"Other\",\"missingBucket\":false,\"missingBucketLabel\":\"Missing\",\"customLabel\":\"variableValue\"},\"schema\":\"bucket\"}],\"params\":{\"perPage\":20,\"showPartialRows\":false,\"showMetricsAtAllLevels\":false,\"showTotal\":false,\"showToolbar\":false,\"totalFunc\":\"sum\",\"percentageCol\":\"\"}}"},"coreMigrationVersion":"7.13.2","id":"8cf5f410-26c3-11ec-95b3-cb627b5ccd4b","migrationVersion":{"visualization":"7.13.1"},"references":[{"id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","name":"kibanaSavedObjectMeta.searchSourceJSON.index","type":"index-pattern"}],"type":"visualization","updated_at":"2022-01-17T09:27:43.036Z","version":"WzEwODI0LDEzXQ=="} +{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[]}"},"title":"Variable Input","uiStateJSON":"{}","version":1,"visState":"{\"title\":\"Variable Input\",\"type\":\"input_control_vis\",\"aggs\":[],\"params\":{\"controls\":[{\"id\":\"1633538407315\",\"fieldName\":\"value.name\",\"parent\":\"\",\"label\":\"VariableName\",\"type\":\"list\",\"options\":{\"type\":\"terms\",\"multiselect\":true,\"dynamicOptions\":true,\"size\":5,\"order\":\"desc\"},\"indexPatternRefName\":\"control_0_index_pattern\"}],\"updateFiltersOnChange\":false,\"useTimeFilter\":false,\"pinFilters\":false}}"},"coreMigrationVersion":"7.13.2","id":"2b5132f0-26c4-11ec-95b3-cb627b5ccd4b","migrationVersion":{"visualization":"7.13.1"},"references":[{"id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","name":"control_0_index_pattern","type":"index-pattern"}],"type":"visualization","updated_at":"2022-01-17T09:27:43.036Z","version":"WzEwODI1LDEzXQ=="} +{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[],\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\"}"},"title":"Task/State ","uiStateJSON":"{}","version":1,"visState":"{\"title\":\"Task/State \",\"type\":\"table\",\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"count\",\"params\":{},\"schema\":\"metric\"},{\"id\":\"2\",\"enabled\":true,\"type\":\"terms\",\"params\":{\"field\":\"value.type\",\"orderBy\":\"1\",\"order\":\"desc\",\"size\":20,\"otherBucket\":false,\"otherBucketLabel\":\"Other\",\"missingBucket\":false,\"missingBucketLabel\":\"Missing\",\"customLabel\":\"Task/State Name\"},\"schema\":\"bucket\"}],\"params\":{\"perPage\":10,\"showPartialRows\":false,\"showMetricsAtAllLevels\":false,\"showTotal\":false,\"showToolbar\":false,\"totalFunc\":\"sum\",\"percentageCol\":\"\"}}"},"coreMigrationVersion":"7.13.2","id":"cc282ac0-26c5-11ec-95b3-cb627b5ccd4b","migrationVersion":{"visualization":"7.13.1"},"references":[{"id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","name":"kibanaSavedObjectMeta.searchSourceJSON.index","type":"index-pattern"}],"type":"visualization","updated_at":"2022-01-17T09:27:43.036Z","version":"WzEwODI2LDEzXQ=="} +{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"language\":\"lucene\",\"query\":\"\"},\"filter\":[]}"},"title":"Vega Visualisation 3: Pie chart for transactions above filter","uiStateJSON":"{}","version":1,"visState":"{\"title\":\"Vega Visualisation 3: Pie chart for transactions above filter\",\"type\":\"vega\",\"aggs\":[],\"params\":{\"spec\":\"{\\n $schema: https://vega.github.io/schema/vega-lite/v5.json\\n title: Event counts from all indexes\\n data: {\\n url: {\\n index: _all\\n body: {\\n aggs: {\\n categories: {\\n terms: {\\n field: value.processInstanceKey\\n }\\n aggs: {\\n duration: {\\n scripted_metric: {\\n init_script: state.responses = ['start':0,'stop':0]\\n map_script: def intent = doc['intent'].value; def time = doc['timestamp'].value.getMillis(); state.responses.start = time; if (intent.contains('COMPLETED') && time > state.responses['stop']) { state.responses.stop = time;} else if(intent.contains('CREATED') && time < state.responses['start'] ) {state.responses.start = time;}\\n combine_script: state.responses\\n reduce_script: def diff = null;for (responses in states) {diff = responses['stop'] - responses['start'];}return diff;\\n }\\n }\\n }\\n }\\n }\\n size: 0\\n query: {\\n bool: {\\n must: [\\n ]\\n filter: [\\n {\\n match_all: {\\n }\\n }\\n {\\n match_phrase: {\\n value.bpmnProcessId: mpesa-flow-v3\\n }\\n }\\n ]\\n should: [\\n ]\\n must_not: [\\n ]\\n }\\n }\\n }\\n }\\n format: {\\n property: aggregations.categories.buckets\\n }\\n }\\n transform: [\\n {\\n calculate: \\\"datum['duration.value'] > 120000 ? 'above 2 min' : 'below 2 min' \\\"\\n as: diff\\n }\\n ]\\n mark: arc\\n encoding: {\\n theta: {\\n field: duration.value\\n aggregate: count\\n type: quantitative\\n }\\n color: {\\n field: diff\\n type: nominal\\n axis: {\\n title: Process Instance\\n }\\n }\\n }\\n}\"}}"},"coreMigrationVersion":"7.13.2","id":"04748e40-7771-11ec-80b6-cdd557ff9b70","migrationVersion":{"visualization":"7.13.1"},"references":[],"type":"visualization","updated_at":"2022-01-17T09:27:43.036Z","version":"WzEwODI3LDEzXQ=="} +{"attributes":{"description":"","hits":0,"kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"language\":\"kuery\",\"query\":\"\"},\"filter\":[]}"},"optionsJSON":"{\"hidePanelTitles\":false,\"useMargins\":true}","panelsJSON":"[{\"version\":\"7.13.2\",\"type\":\"visualization\",\"gridData\":{\"x\":0,\"y\":0,\"w\":18,\"h\":7,\"i\":\"6fc4224e-00ad-4a0b-bc30-cdd7c8c26e68\"},\"panelIndex\":\"6fc4224e-00ad-4a0b-bc30-cdd7c8c26e68\",\"embeddableConfig\":{\"savedVis\":{\"title\":\"ProcessDefControl\",\"description\":\"\",\"type\":\"input_control_vis\",\"params\":{\"controls\":[{\"id\":\"1633536719626\",\"fieldName\":\"value.bpmnProcessId\",\"parent\":\"\",\"label\":\"ProcessDef\",\"type\":\"list\",\"options\":{\"type\":\"terms\",\"multiselect\":true,\"dynamicOptions\":true,\"size\":5,\"order\":\"desc\"},\"indexPatternRefName\":\"control_6fc4224e-00ad-4a0b-bc30-cdd7c8c26e68_0_index_pattern\"}],\"updateFiltersOnChange\":false,\"useTimeFilter\":false,\"pinFilters\":false},\"uiState\":{},\"data\":{\"aggs\":[],\"searchSource\":{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[]}}},\"enhancements\":{}}},{\"version\":\"7.13.2\",\"type\":\"visualization\",\"gridData\":{\"x\":18,\"y\":0,\"w\":29,\"h\":7,\"i\":\"2adee62e-ff39-4b27-899d-6acc933194f7\"},\"panelIndex\":\"2adee62e-ff39-4b27-899d-6acc933194f7\",\"embeddableConfig\":{\"vis\":{\"params\":{\"colWidth\":[{\"colIndex\":0,\"width\":364}]}},\"enhancements\":{}},\"panelRefName\":\"panel_2adee62e-ff39-4b27-899d-6acc933194f7\"},{\"version\":\"7.13.2\",\"type\":\"visualization\",\"gridData\":{\"x\":0,\"y\":7,\"w\":34,\"h\":12,\"i\":\"17035d4c-4ab4-4311-b7e9-6d60b8f532c3\"},\"panelIndex\":\"17035d4c-4ab4-4311-b7e9-6d60b8f532c3\",\"embeddableConfig\":{\"savedVis\":{\"title\":\"ProcessInstanceKeys\",\"description\":\"\",\"type\":\"table\",\"params\":{\"perPage\":10,\"showPartialRows\":false,\"showMetricsAtAllLevels\":false,\"showTotal\":false,\"showToolbar\":false,\"totalFunc\":\"sum\",\"percentageCol\":\"\"},\"uiState\":{},\"data\":{\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"count\",\"params\":{},\"schema\":\"metric\"},{\"id\":\"2\",\"enabled\":true,\"type\":\"terms\",\"params\":{\"field\":\"value.bpmnProcessId\",\"orderBy\":\"1\",\"order\":\"desc\",\"size\":1005,\"otherBucket\":false,\"otherBucketLabel\":\"Other\",\"missingBucket\":false,\"missingBucketLabel\":\"Missing\",\"customLabel\":\"ProcessDef\"},\"schema\":\"bucket\"},{\"id\":\"3\",\"enabled\":true,\"type\":\"terms\",\"params\":{\"field\":\"value.processInstanceKey\",\"orderBy\":\"1\",\"order\":\"desc\",\"size\":5,\"otherBucket\":true,\"otherBucketLabel\":\"Other\",\"missingBucket\":false,\"missingBucketLabel\":\"Missing\",\"customLabel\":\"ProcessInstanceKey\"},\"schema\":\"bucket\"}],\"searchSource\":{\"index\":\"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b\",\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[]}}},\"enhancements\":{}},\"panelRefName\":\"panel_17035d4c-4ab4-4311-b7e9-6d60b8f532c3\"},{\"version\":\"7.13.2\",\"type\":\"visualization\",\"gridData\":{\"x\":0,\"y\":19,\"w\":46,\"h\":12,\"i\":\"1a06ddb5-0b36-40e8-96be-7640d6d954b3\"},\"panelIndex\":\"1a06ddb5-0b36-40e8-96be-7640d6d954b3\",\"embeddableConfig\":{\"savedVis\":{\"title\":\"Process Variables\",\"description\":\"\",\"type\":\"table\",\"params\":{\"perPage\":20,\"showPartialRows\":false,\"showMetricsAtAllLevels\":false,\"showTotal\":false,\"showToolbar\":false,\"totalFunc\":\"sum\",\"percentageCol\":\"\"},\"uiState\":{},\"data\":{\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"count\",\"params\":{},\"schema\":\"metric\"},{\"id\":\"2\",\"enabled\":true,\"type\":\"terms\",\"params\":{\"field\":\"value.name\",\"orderBy\":\"1\",\"order\":\"desc\",\"size\":100,\"otherBucket\":false,\"otherBucketLabel\":\"Other\",\"missingBucket\":false,\"missingBucketLabel\":\"Missing\",\"customLabel\":\"variableName\"},\"schema\":\"bucket\"},{\"id\":\"3\",\"enabled\":true,\"type\":\"terms\",\"params\":{\"field\":\"value.value\",\"orderBy\":\"1\",\"order\":\"desc\",\"size\":100,\"otherBucket\":false,\"otherBucketLabel\":\"Other\",\"missingBucket\":false,\"missingBucketLabel\":\"Missing\",\"customLabel\":\"variableValue\"},\"schema\":\"bucket\"}],\"searchSource\":{\"index\":\"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b\",\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[]}}},\"vis\":{\"params\":{\"colWidth\":[{\"colIndex\":1,\"width\":1046.3333333333333},{\"colIndex\":0,\"width\":182}]}},\"table\":null,\"enhancements\":{}},\"panelRefName\":\"panel_1a06ddb5-0b36-40e8-96be-7640d6d954b3\"},{\"version\":\"7.13.2\",\"type\":\"visualization\",\"gridData\":{\"x\":0,\"y\":31,\"w\":19,\"h\":7,\"i\":\"162e25cc-3f99-48cd-ac26-c16f4c18bf6f\"},\"panelIndex\":\"162e25cc-3f99-48cd-ac26-c16f4c18bf6f\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_162e25cc-3f99-48cd-ac26-c16f4c18bf6f\"},{\"version\":\"7.13.2\",\"type\":\"visualization\",\"gridData\":{\"x\":19,\"y\":31,\"w\":28,\"h\":15,\"i\":\"38bca8ec-0692-433d-996b-1366b50ce5b2\"},\"panelIndex\":\"38bca8ec-0692-433d-996b-1366b50ce5b2\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_38bca8ec-0692-433d-996b-1366b50ce5b2\"},{\"version\":\"7.13.2\",\"type\":\"visualization\",\"gridData\":{\"x\":0,\"y\":46,\"w\":24,\"h\":15,\"i\":\"8fc4fc44-91d6-496a-af8f-444214d80872\"},\"panelIndex\":\"8fc4fc44-91d6-496a-af8f-444214d80872\",\"embeddableConfig\":{\"savedVis\":{\"title\":\"Vega Visualisation 1: Time taken for each task\",\"description\":\"\",\"type\":\"vega\",\"params\":{\"spec\":\"{\\n \\\"$schema\\\": \\\"https://vega.github.io/schema/vega-lite/v5.json\\\",\\n \\\"title\\\": \\\"Event counts from all indexes\\\",\\n \\\"data\\\": {\\n \\\"url\\\": {\\n \\\"index\\\": \\\"_all\\\",\\n \\\"body\\\": {\\n \\\"aggs\\\": {\\n categories: {\\n terms: { field: \\\"value.elementId\\\" }\\n \\\"aggs\\\": {\\n \\\"duration\\\": {\\n \\\"scripted_metric\\\": {\\n \\\"init_script\\\": \\\"state.responses = ['start':0,'stop':0]\\\", \\n \\\"map_script\\\": \\\"def intent = doc['intent'].value; if (intent.contains('COMPLETED')) {state.responses.stop += doc['timestamp'].value.getMillis();} else if(intent.contains('CREATED')) {state.responses.start += doc['timestamp'].value.getMillis();} else {state.responses.start += 0;state.responses.stop += 0;}\\\",\\n \\\"combine_script\\\": \\\"state.responses\\\",\\n \\\"reduce_script\\\": \\\"def diff = null;for (responses in states) {diff = responses['stop'] - responses['start'];}return diff;\\\"\\n }\\n }\\n }\\n \\n }\\n }\\n \\\"size\\\": 0,\\n \\\"query\\\": {\\n \\\"bool\\\": {\\n \\\"must\\\": [],\\n \\\"filter\\\": [\\n {\\n \\\"match_all\\\": {}\\n },\\n {\\n \\\"match_phrase\\\": {\\n \\\"value.bpmnProcessId\\\": \\\"mpesa-flow-v3\\\"\\n }\\n },\\n {\\n \\\"match_phrase\\\": {\\n \\\"value.processInstanceKey\\\": 2251799831883666\\n }\\n },\\n ],\\n \\\"should\\\": [],\\n \\\"must_not\\\": [\\n {\\n \\\"match_phrase\\\": {\\n \\\"value.elementId\\\": \\\"Gateway_0y10qkw\\\"\\n }\\n }{\\n \\\"match_phrase\\\": {\\n \\\"value.elementId\\\": \\\"Gateway_071nepp\\\"\\n }\\n }{\\n \\\"match_phrase\\\": {\\n \\\"value.elementId\\\": \\\"Gateway_1hsu2ep\\\"\\n }\\n }\\n {\\n \\\"match_phrase\\\": {\\n \\\"value.elementId\\\": \\\"Event_1b36xu9\\\"\\n }\\n }\\n {\\n \\\"match_phrase\\\": {\\n \\\"value.elementId\\\": \\\"StartEvent_1\\\"\\n }\\n }\\n {\\n \\\"match_phrase\\\": {\\n \\\"value.elementId\\\": \\\"StartEvent_1\\\"\\n }\\n }\\n {\\n \\\"match_phrase\\\": {\\n \\\"value.elementId\\\": \\\"Flow_03ncatg\\\"\\n }\\n }\\n ]\\n }\\n }\\n }\\n },\\n format: {property: \\\"aggregations.categories.buckets\\\" }\\n },\\n mark: bar\\n\\n encoding: {\\n x: {\\\"field\\\": \\\"duration.value\\\", \\n \\\"type\\\": \\\"temporal\\\", \\n \\\"timeUnit\\\": \\\"seconds\\\",\\n \\\"axis\\\": {title: \\\"Time taken in miliseconds \\\" }\\n \\n }\\n y: {\\n field: key\\n type: nominal\\n axis: { title: \\\"Tasks\\\" }\\n }\\n color: {\\n field: key\\n type: nominal\\n }\\n }\\n \\\"layer\\\": [\\n {\\n \\\"mark\\\": \\\"rect\\\",\\n \\\"encoding\\\": {\\n \\\"color\\\": {\\n \\\"field\\\": \\\"duration.value\\\",\\n \\\"type\\\": \\\"temporal\\\",\\n \\\"timeUnit\\\": \\\"milliseconds\\\",\\n \\\"title\\\": \\\"Time elapsed\\\",\\n \\\"legend\\\": {\\\"direction\\\": \\\"horizontal\\\", \\\"gradientLength\\\": 120}\\n }\\n }\\n }]\\n}\"},\"uiState\":{},\"data\":{\"aggs\":[],\"searchSource\":{\"query\":{\"language\":\"kuery\",\"query\":\"\"},\"filter\":[]}}},\"enhancements\":{}}},{\"version\":\"7.13.2\",\"type\":\"visualization\",\"gridData\":{\"x\":24,\"y\":46,\"w\":24,\"h\":15,\"i\":\"039d9f15-1fef-4e21-ab1d-cee335f2b337\"},\"panelIndex\":\"039d9f15-1fef-4e21-ab1d-cee335f2b337\",\"embeddableConfig\":{\"savedVis\":{\"title\":\"Vega Visualisation 2: All process with elapsed time per task\",\"description\":\"\",\"type\":\"vega\",\"params\":{\"spec\":\"{\\n \\\"$schema\\\": \\\"https://vega.github.io/schema/vega-lite/v5.json\\\",\\n \\\"title\\\": \\\"Event counts from all indexes\\\",\\n \\\"data\\\": {\\n \\\"url\\\": {\\n \\\"index\\\": \\\"_all\\\",\\n \\\"body\\\": {\\n \\\"aggs\\\": {\\n \\\"categories\\\": {\\n \\\"terms\\\": {\\\"field\\\": \\\"value.processInstanceKey\\\"},\\n \\\"aggs\\\": {\\n \\\"duration\\\": {\\n scripted_metric: {\\n init_script: state.responses = ['start':0,'stop':0]\\n map_script: def intent = doc['intent'].value; def time = doc['timestamp'].value.getMillis(); state.responses.start = time; if (intent.contains('COMPLETED') && time > state.responses['stop']) { state.responses.stop = time;} else if(intent.contains('CREATED') && time < state.responses['start'] ) {state.responses.start = time;}\\n combine_script: state.responses\\n reduce_script: def diff = null;for (responses in states) {diff = responses['stop'] - responses['start'];}return diff;\\n }\\n }\\n }\\n }\\n },\\n \\\"size\\\": 0,\\n \\\"query\\\": {\\n \\\"bool\\\": {\\n \\\"must\\\": [],\\n \\\"filter\\\": [\\n {\\\"match_all\\\": {}},\\n {\\\"match_phrase\\\": {\\\"value.bpmnProcessId\\\": \\\"mpesa-flow-v3\\\"}}\\n ],\\n \\\"should\\\": [],\\n \\\"must_not\\\": []\\n }\\n }\\n }\\n },\\n \\\"format\\\": {\\\"property\\\": \\\"aggregations.categories.buckets\\\"}\\n },\\n \\\"encoding\\\": {\\n \\\"x\\\": {\\n \\\"field\\\": \\\"duration.value\\\",\\n \\\"type\\\": \\\"temporal\\\",\\n \\\"timeUnit\\\": \\\"seconds\\\",\\n \\\"axis\\\": {\\\"title\\\": \\\"Time taken in miliseconds \\\"}\\n },\\n \\\"y\\\": {\\n \\\"field\\\": \\\"key\\\",\\n \\\"type\\\": \\\"nominal\\\",\\n \\\"axis\\\": {\\\"title\\\": \\\"Process Instance\\\"}\\n },\\n \\\"color\\\": {\\\"field\\\": \\\"key\\\", \\\"type\\\": \\\"nominal\\\"}\\n },\\n \\\"layer\\\": [\\n {\\n \\\"mark\\\": \\\"rect\\\",\\n \\\"encoding\\\": {\\n \\\"color\\\": {\\n \\\"field\\\": \\\"duration.value\\\",\\n \\\"type\\\": \\\"temporal\\\",\\n \\\"timeUnit\\\": \\\"milliseconds\\\",\\n \\\"title\\\": \\\"Time elapsed\\\",\\n \\\"legend\\\": {\\\"direction\\\": \\\"horizontal\\\", \\\"gradientLength\\\": 120}\\n }\\n }\\n },\\n {\\n \\\"mark\\\": \\\"text\\\",\\n \\\"encoding\\\": {\\n \\\"text\\\": {\\\"field\\\": \\\"duration.value\\\", \\\"type\\\": \\\"temporal\\\",\\n \\\"timeUnit\\\": \\\"seconds\\\"},\\n \\\"color\\\": {\\n \\\"condition\\\": {\\n \\\"test\\\": \\\"datum['duration.value'] > 120000\\\",\\n \\\"value\\\": \\\"red\\\"\\n },\\n \\\"value\\\": \\\"black\\\"\\n }\\n }\\n }\\n ],\\n \\\"config\\\": {\\\"axis\\\": {\\\"grid\\\": true, \\\"tickBand\\\": \\\"extent\\\"}}\\n}\"},\"uiState\":{},\"data\":{\"aggs\":[],\"searchSource\":{\"query\":{\"language\":\"kuery\",\"query\":\"\"},\"filter\":[]}}},\"enhancements\":{}}},{\"version\":\"7.13.2\",\"type\":\"visualization\",\"gridData\":{\"x\":0,\"y\":61,\"w\":24,\"h\":15,\"i\":\"5eed1959-b4a0-4cb9-80d8-16fb83199078\"},\"panelIndex\":\"5eed1959-b4a0-4cb9-80d8-16fb83199078\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_5eed1959-b4a0-4cb9-80d8-16fb83199078\"}]","refreshInterval":{"pause":true,"value":0},"timeFrom":"now-1w","timeRestore":true,"timeTo":"now","title":"PHEE","version":1},"coreMigrationVersion":"7.13.2","id":"8bcc01c0-26bd-11ec-95b3-cb627b5ccd4b","migrationVersion":{"dashboard":"7.13.1"},"references":[{"id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","name":"6fc4224e-00ad-4a0b-bc30-cdd7c8c26e68:control_6fc4224e-00ad-4a0b-bc30-cdd7c8c26e68_0_index_pattern","type":"index-pattern"},{"id":"f21cb760-26bf-11ec-95b3-cb627b5ccd4b","name":"2adee62e-ff39-4b27-899d-6acc933194f7:panel_2adee62e-ff39-4b27-899d-6acc933194f7","type":"visualization"},{"id":"df1144f0-26c0-11ec-95b3-cb627b5ccd4b","name":"17035d4c-4ab4-4311-b7e9-6d60b8f532c3:panel_17035d4c-4ab4-4311-b7e9-6d60b8f532c3","type":"visualization"},{"id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","name":"17035d4c-4ab4-4311-b7e9-6d60b8f532c3:kibanaSavedObjectMeta.searchSourceJSON.index","type":"index-pattern"},{"id":"8cf5f410-26c3-11ec-95b3-cb627b5ccd4b","name":"1a06ddb5-0b36-40e8-96be-7640d6d954b3:panel_1a06ddb5-0b36-40e8-96be-7640d6d954b3","type":"visualization"},{"id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","name":"1a06ddb5-0b36-40e8-96be-7640d6d954b3:kibanaSavedObjectMeta.searchSourceJSON.index","type":"index-pattern"},{"id":"2b5132f0-26c4-11ec-95b3-cb627b5ccd4b","name":"162e25cc-3f99-48cd-ac26-c16f4c18bf6f:panel_162e25cc-3f99-48cd-ac26-c16f4c18bf6f","type":"visualization"},{"id":"cc282ac0-26c5-11ec-95b3-cb627b5ccd4b","name":"38bca8ec-0692-433d-996b-1366b50ce5b2:panel_38bca8ec-0692-433d-996b-1366b50ce5b2","type":"visualization"},{"id":"04748e40-7771-11ec-80b6-cdd557ff9b70","name":"5eed1959-b4a0-4cb9-80d8-16fb83199078:panel_5eed1959-b4a0-4cb9-80d8-16fb83199078","type":"visualization"}],"type":"dashboard","updated_at":"2022-01-17T09:27:43.036Z","version":"WzEwODI4LDEzXQ=="} +{"exportedCount":8,"missingRefCount":0,"missingReferences":[]} \ No newline at end of file diff --git a/ph-ee-importer-es/src/main/resources/kibana/Dashboard 2 b/ph-ee-importer-es/src/main/resources/kibana/Dashboard 2 new file mode 100644 index 000000000..3d040113e --- /dev/null +++ b/ph-ee-importer-es/src/main/resources/kibana/Dashboard 2 @@ -0,0 +1,9 @@ +{"attributes":{"fieldAttrs":"{\"value.bpmnProcessId\":{\"count\":4},\"value.processDefinitionKey\":{\"count\":4},\"value.processDefinitionVersion\":{\"count\":3},\"value.processInstanceKey\":{\"count\":3},\"value.elementId\":{\"count\":2},\"value.retries\":{\"count\":2},\"value.type\":{\"count\":2},\"intent\":{\"count\":1},\"timestamp\":{\"count\":1}}","fields":"[]","runtimeFieldMap":"{}","timeFieldName":"timestamp","title":"zeebe-*"},"coreMigrationVersion":"7.13.2","id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","migrationVersion":{"index-pattern":"7.11.0"},"references":[],"type":"index-pattern","updated_at":"2022-01-17T09:27:43.036Z","version":"WzEwODIxLDEzXQ=="} +{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[],\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\"}"},"title":"ProcessInstanceCount","uiStateJSON":"{}","version":1,"visState":"{\"title\":\"ProcessInstanceCount\",\"type\":\"table\",\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"cardinality\",\"params\":{\"field\":\"value.processInstanceKey\",\"customLabel\":\"processInstanceCount\"},\"schema\":\"metric\"},{\"id\":\"2\",\"enabled\":true,\"type\":\"terms\",\"params\":{\"field\":\"value.bpmnProcessId\",\"orderBy\":\"1\",\"order\":\"desc\",\"size\":10,\"otherBucket\":false,\"otherBucketLabel\":\"Other\",\"missingBucket\":false,\"missingBucketLabel\":\"Missing\",\"customLabel\":\"processDefinition\"},\"schema\":\"bucket\"}],\"params\":{\"perPage\":10,\"showPartialRows\":false,\"showMetricsAtAllLevels\":false,\"showTotal\":false,\"showToolbar\":false,\"totalFunc\":\"sum\",\"percentageCol\":\"\"}}"},"coreMigrationVersion":"7.13.2","id":"f21cb760-26bf-11ec-95b3-cb627b5ccd4b","migrationVersion":{"visualization":"7.13.1"},"references":[{"id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","name":"kibanaSavedObjectMeta.searchSourceJSON.index","type":"index-pattern"}],"type":"visualization","updated_at":"2022-01-17T09:27:43.036Z","version":"WzEwODIyLDEzXQ=="} +{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[],\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\"}"},"title":"ProcessInstanceKeys","uiStateJSON":"{}","version":1,"visState":"{\"title\":\"ProcessInstanceKeys\",\"type\":\"table\",\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"count\",\"params\":{},\"schema\":\"metric\"},{\"id\":\"2\",\"enabled\":true,\"type\":\"terms\",\"params\":{\"field\":\"value.bpmnProcessId\",\"orderBy\":\"1\",\"order\":\"desc\",\"size\":1005,\"otherBucket\":false,\"otherBucketLabel\":\"Other\",\"missingBucket\":false,\"missingBucketLabel\":\"Missing\",\"customLabel\":\"ProcessDef\"},\"schema\":\"bucket\"},{\"id\":\"3\",\"enabled\":true,\"type\":\"terms\",\"params\":{\"field\":\"value.processInstanceKey\",\"orderBy\":\"1\",\"order\":\"desc\",\"size\":5,\"otherBucket\":true,\"otherBucketLabel\":\"Other\",\"missingBucket\":false,\"missingBucketLabel\":\"Missing\",\"customLabel\":\"ProcessInstanceKey\"},\"schema\":\"bucket\"}],\"params\":{\"perPage\":10,\"showPartialRows\":false,\"showMetricsAtAllLevels\":false,\"showTotal\":false,\"showToolbar\":false,\"totalFunc\":\"sum\",\"percentageCol\":\"\"}}"},"coreMigrationVersion":"7.13.2","id":"df1144f0-26c0-11ec-95b3-cb627b5ccd4b","migrationVersion":{"visualization":"7.13.1"},"references":[{"id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","name":"kibanaSavedObjectMeta.searchSourceJSON.index","type":"index-pattern"}],"type":"visualization","updated_at":"2022-01-17T09:27:43.036Z","version":"WzEwODIzLDEzXQ=="} +{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[],\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\"}"},"title":"Process Variables","uiStateJSON":"{}","version":1,"visState":"{\"title\":\"Process Variables\",\"type\":\"table\",\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"count\",\"params\":{},\"schema\":\"metric\"},{\"id\":\"2\",\"enabled\":true,\"type\":\"terms\",\"params\":{\"field\":\"value.name\",\"orderBy\":\"1\",\"order\":\"desc\",\"size\":100,\"otherBucket\":false,\"otherBucketLabel\":\"Other\",\"missingBucket\":false,\"missingBucketLabel\":\"Missing\",\"customLabel\":\"variableName\"},\"schema\":\"bucket\"},{\"id\":\"3\",\"enabled\":true,\"type\":\"terms\",\"params\":{\"field\":\"value.value\",\"orderBy\":\"1\",\"order\":\"desc\",\"size\":100,\"otherBucket\":false,\"otherBucketLabel\":\"Other\",\"missingBucket\":false,\"missingBucketLabel\":\"Missing\",\"customLabel\":\"variableValue\"},\"schema\":\"bucket\"}],\"params\":{\"perPage\":20,\"showPartialRows\":false,\"showMetricsAtAllLevels\":false,\"showTotal\":false,\"showToolbar\":false,\"totalFunc\":\"sum\",\"percentageCol\":\"\"}}"},"coreMigrationVersion":"7.13.2","id":"8cf5f410-26c3-11ec-95b3-cb627b5ccd4b","migrationVersion":{"visualization":"7.13.1"},"references":[{"id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","name":"kibanaSavedObjectMeta.searchSourceJSON.index","type":"index-pattern"}],"type":"visualization","updated_at":"2022-01-17T09:27:43.036Z","version":"WzEwODI0LDEzXQ=="} +{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[]}"},"title":"Variable Input","uiStateJSON":"{}","version":1,"visState":"{\"title\":\"Variable Input\",\"type\":\"input_control_vis\",\"aggs\":[],\"params\":{\"controls\":[{\"id\":\"1633538407315\",\"fieldName\":\"value.name\",\"parent\":\"\",\"label\":\"VariableName\",\"type\":\"list\",\"options\":{\"type\":\"terms\",\"multiselect\":true,\"dynamicOptions\":true,\"size\":5,\"order\":\"desc\"},\"indexPatternRefName\":\"control_0_index_pattern\"}],\"updateFiltersOnChange\":false,\"useTimeFilter\":false,\"pinFilters\":false}}"},"coreMigrationVersion":"7.13.2","id":"2b5132f0-26c4-11ec-95b3-cb627b5ccd4b","migrationVersion":{"visualization":"7.13.1"},"references":[{"id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","name":"control_0_index_pattern","type":"index-pattern"}],"type":"visualization","updated_at":"2022-01-17T09:27:43.036Z","version":"WzEwODI1LDEzXQ=="} +{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[],\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\"}"},"title":"Task/State ","uiStateJSON":"{}","version":1,"visState":"{\"title\":\"Task/State \",\"type\":\"table\",\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"count\",\"params\":{},\"schema\":\"metric\"},{\"id\":\"2\",\"enabled\":true,\"type\":\"terms\",\"params\":{\"field\":\"value.type\",\"orderBy\":\"1\",\"order\":\"desc\",\"size\":20,\"otherBucket\":false,\"otherBucketLabel\":\"Other\",\"missingBucket\":false,\"missingBucketLabel\":\"Missing\",\"customLabel\":\"Task/State Name\"},\"schema\":\"bucket\"}],\"params\":{\"perPage\":10,\"showPartialRows\":false,\"showMetricsAtAllLevels\":false,\"showTotal\":false,\"showToolbar\":false,\"totalFunc\":\"sum\",\"percentageCol\":\"\"}}"},"coreMigrationVersion":"7.13.2","id":"cc282ac0-26c5-11ec-95b3-cb627b5ccd4b","migrationVersion":{"visualization":"7.13.1"},"references":[{"id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","name":"kibanaSavedObjectMeta.searchSourceJSON.index","type":"index-pattern"}],"type":"visualization","updated_at":"2022-01-17T09:27:43.036Z","version":"WzEwODI2LDEzXQ=="} +{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"language\":\"lucene\",\"query\":\"\"},\"filter\":[]}"},"title":"Vega Visualisation 3: Pie chart for transactions above filter","uiStateJSON":"{}","version":1,"visState":"{\"title\":\"Vega Visualisation 3: Pie chart for transactions above filter\",\"type\":\"vega\",\"aggs\":[],\"params\":{\"spec\":\"{\\n $schema: https://vega.github.io/schema/vega-lite/v5.json\\n title: Event counts from all indexes\\n data: {\\n url: {\\n index: _all\\n body: {\\n aggs: {\\n categories: {\\n terms: {\\n field: value.processInstanceKey\\n }\\n aggs: {\\n duration: {\\n scripted_metric: {\\n init_script: state.responses = ['start':0,'stop':0]\\n map_script: def intent = doc['intent'].value; def time = doc['timestamp'].value.getMillis(); state.responses.start = time; if (intent.contains('COMPLETED') && time > state.responses['stop']) { state.responses.stop = time;} else if(intent.contains('CREATED') && time < state.responses['start'] ) {state.responses.start = time;}\\n combine_script: state.responses\\n reduce_script: def diff = null;for (responses in states) {diff = responses['stop'] - responses['start'];}return diff;\\n }\\n }\\n }\\n }\\n }\\n size: 0\\n query: {\\n bool: {\\n must: [\\n ]\\n filter: [\\n {\\n match_all: {\\n }\\n }\\n {\\n match_phrase: {\\n value.bpmnProcessId: mpesa-flow-v3\\n }\\n }\\n ]\\n should: [\\n ]\\n must_not: [\\n ]\\n }\\n }\\n }\\n }\\n format: {\\n property: aggregations.categories.buckets\\n }\\n }\\n transform: [\\n {\\n calculate: \\\"datum['duration.value'] > 120000 ? 'above 2 min' : 'below 2 min' \\\"\\n as: diff\\n }\\n ]\\n mark: arc\\n encoding: {\\n theta: {\\n field: duration.value\\n aggregate: count\\n type: quantitative\\n }\\n color: {\\n field: diff\\n type: nominal\\n axis: {\\n title: Process Instance\\n }\\n }\\n }\\n}\"}}"},"coreMigrationVersion":"7.13.2","id":"04748e40-7771-11ec-80b6-cdd557ff9b70","migrationVersion":{"visualization":"7.13.1"},"references":[],"type":"visualization","updated_at":"2022-01-17T09:27:43.036Z","version":"WzEwODI3LDEzXQ=="} +{"attributes":{"description":"","hits":0,"kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"language\":\"kuery\",\"query\":\"\"},\"filter\":[]}"},"optionsJSON":"{\"hidePanelTitles\":false,\"useMargins\":true}","panelsJSON":"[{\"version\":\"7.13.2\",\"type\":\"visualization\",\"gridData\":{\"x\":0,\"y\":0,\"w\":18,\"h\":7,\"i\":\"6fc4224e-00ad-4a0b-bc30-cdd7c8c26e68\"},\"panelIndex\":\"6fc4224e-00ad-4a0b-bc30-cdd7c8c26e68\",\"embeddableConfig\":{\"savedVis\":{\"title\":\"ProcessDefControl\",\"description\":\"\",\"type\":\"input_control_vis\",\"params\":{\"controls\":[{\"id\":\"1633536719626\",\"fieldName\":\"value.bpmnProcessId\",\"parent\":\"\",\"label\":\"ProcessDef\",\"type\":\"list\",\"options\":{\"type\":\"terms\",\"multiselect\":true,\"dynamicOptions\":true,\"size\":5,\"order\":\"desc\"},\"indexPatternRefName\":\"control_6fc4224e-00ad-4a0b-bc30-cdd7c8c26e68_0_index_pattern\"}],\"updateFiltersOnChange\":false,\"useTimeFilter\":false,\"pinFilters\":false},\"uiState\":{},\"data\":{\"aggs\":[],\"searchSource\":{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[]}}},\"enhancements\":{}}},{\"version\":\"7.13.2\",\"type\":\"visualization\",\"gridData\":{\"x\":18,\"y\":0,\"w\":29,\"h\":7,\"i\":\"2adee62e-ff39-4b27-899d-6acc933194f7\"},\"panelIndex\":\"2adee62e-ff39-4b27-899d-6acc933194f7\",\"embeddableConfig\":{\"vis\":{\"params\":{\"colWidth\":[{\"colIndex\":0,\"width\":364}]}},\"enhancements\":{}},\"panelRefName\":\"panel_2adee62e-ff39-4b27-899d-6acc933194f7\"},{\"version\":\"7.13.2\",\"type\":\"visualization\",\"gridData\":{\"x\":0,\"y\":7,\"w\":34,\"h\":12,\"i\":\"17035d4c-4ab4-4311-b7e9-6d60b8f532c3\"},\"panelIndex\":\"17035d4c-4ab4-4311-b7e9-6d60b8f532c3\",\"embeddableConfig\":{\"savedVis\":{\"title\":\"ProcessInstanceKeys\",\"description\":\"\",\"type\":\"table\",\"params\":{\"perPage\":10,\"showPartialRows\":false,\"showMetricsAtAllLevels\":false,\"showTotal\":false,\"showToolbar\":false,\"totalFunc\":\"sum\",\"percentageCol\":\"\"},\"uiState\":{},\"data\":{\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"count\",\"params\":{},\"schema\":\"metric\"},{\"id\":\"2\",\"enabled\":true,\"type\":\"terms\",\"params\":{\"field\":\"value.bpmnProcessId\",\"orderBy\":\"1\",\"order\":\"desc\",\"size\":1005,\"otherBucket\":false,\"otherBucketLabel\":\"Other\",\"missingBucket\":false,\"missingBucketLabel\":\"Missing\",\"customLabel\":\"ProcessDef\"},\"schema\":\"bucket\"},{\"id\":\"3\",\"enabled\":true,\"type\":\"terms\",\"params\":{\"field\":\"value.processInstanceKey\",\"orderBy\":\"1\",\"order\":\"desc\",\"size\":5,\"otherBucket\":true,\"otherBucketLabel\":\"Other\",\"missingBucket\":false,\"missingBucketLabel\":\"Missing\",\"customLabel\":\"ProcessInstanceKey\"},\"schema\":\"bucket\"}],\"searchSource\":{\"index\":\"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b\",\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[]}}},\"enhancements\":{}},\"panelRefName\":\"panel_17035d4c-4ab4-4311-b7e9-6d60b8f532c3\"},{\"version\":\"7.13.2\",\"type\":\"visualization\",\"gridData\":{\"x\":0,\"y\":19,\"w\":46,\"h\":12,\"i\":\"1a06ddb5-0b36-40e8-96be-7640d6d954b3\"},\"panelIndex\":\"1a06ddb5-0b36-40e8-96be-7640d6d954b3\",\"embeddableConfig\":{\"savedVis\":{\"title\":\"Process Variables\",\"description\":\"\",\"type\":\"table\",\"params\":{\"perPage\":20,\"showPartialRows\":false,\"showMetricsAtAllLevels\":false,\"showTotal\":false,\"showToolbar\":false,\"totalFunc\":\"sum\",\"percentageCol\":\"\"},\"uiState\":{},\"data\":{\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"count\",\"params\":{},\"schema\":\"metric\"},{\"id\":\"2\",\"enabled\":true,\"type\":\"terms\",\"params\":{\"field\":\"value.name\",\"orderBy\":\"1\",\"order\":\"desc\",\"size\":100,\"otherBucket\":false,\"otherBucketLabel\":\"Other\",\"missingBucket\":false,\"missingBucketLabel\":\"Missing\",\"customLabel\":\"variableName\"},\"schema\":\"bucket\"},{\"id\":\"3\",\"enabled\":true,\"type\":\"terms\",\"params\":{\"field\":\"value.value\",\"orderBy\":\"1\",\"order\":\"desc\",\"size\":100,\"otherBucket\":false,\"otherBucketLabel\":\"Other\",\"missingBucket\":false,\"missingBucketLabel\":\"Missing\",\"customLabel\":\"variableValue\"},\"schema\":\"bucket\"}],\"searchSource\":{\"index\":\"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b\",\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[]}}},\"vis\":{\"params\":{\"colWidth\":[{\"colIndex\":1,\"width\":1046.3333333333333},{\"colIndex\":0,\"width\":182}]}},\"table\":null,\"enhancements\":{}},\"panelRefName\":\"panel_1a06ddb5-0b36-40e8-96be-7640d6d954b3\"},{\"version\":\"7.13.2\",\"type\":\"visualization\",\"gridData\":{\"x\":0,\"y\":31,\"w\":19,\"h\":7,\"i\":\"162e25cc-3f99-48cd-ac26-c16f4c18bf6f\"},\"panelIndex\":\"162e25cc-3f99-48cd-ac26-c16f4c18bf6f\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_162e25cc-3f99-48cd-ac26-c16f4c18bf6f\"},{\"version\":\"7.13.2\",\"type\":\"visualization\",\"gridData\":{\"x\":19,\"y\":31,\"w\":28,\"h\":15,\"i\":\"38bca8ec-0692-433d-996b-1366b50ce5b2\"},\"panelIndex\":\"38bca8ec-0692-433d-996b-1366b50ce5b2\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_38bca8ec-0692-433d-996b-1366b50ce5b2\"},{\"version\":\"7.13.2\",\"type\":\"visualization\",\"gridData\":{\"x\":0,\"y\":46,\"w\":24,\"h\":15,\"i\":\"8fc4fc44-91d6-496a-af8f-444214d80872\"},\"panelIndex\":\"8fc4fc44-91d6-496a-af8f-444214d80872\",\"embeddableConfig\":{\"savedVis\":{\"title\":\"Vega Visualisation 1: Time taken for each task\",\"description\":\"\",\"type\":\"vega\",\"params\":{\"spec\":\"{\\n \\\"$schema\\\": \\\"https://vega.github.io/schema/vega-lite/v5.json\\\",\\n \\\"title\\\": \\\"Event counts from all indexes\\\",\\n \\\"data\\\": {\\n \\\"url\\\": {\\n \\\"index\\\": \\\"_all\\\",\\n \\\"body\\\": {\\n \\\"aggs\\\": {\\n categories: {\\n terms: { field: \\\"value.elementId\\\" }\\n \\\"aggs\\\": {\\n \\\"duration\\\": {\\n \\\"scripted_metric\\\": {\\n \\\"init_script\\\": \\\"state.responses = ['start':0,'stop':0]\\\", \\n \\\"map_script\\\": \\\"def intent = doc['intent'].value; if (intent.contains('COMPLETED')) {state.responses.stop += doc['timestamp'].value.getMillis();} else if(intent.contains('CREATED')) {state.responses.start += doc['timestamp'].value.getMillis();} else {state.responses.start += 0;state.responses.stop += 0;}\\\",\\n \\\"combine_script\\\": \\\"state.responses\\\",\\n \\\"reduce_script\\\": \\\"def diff = null;for (responses in states) {diff = responses['stop'] - responses['start'];}return diff;\\\"\\n }\\n }\\n }\\n \\n }\\n }\\n \\\"size\\\": 0,\\n \\\"query\\\": {\\n \\\"bool\\\": {\\n \\\"must\\\": [],\\n \\\"filter\\\": [\\n {\\n \\\"match_all\\\": {}\\n },\\n {\\n \\\"match_phrase\\\": {\\n \\\"value.bpmnProcessId\\\": \\\"mpesa-flow-v3\\\"\\n }\\n },\\n {\\n \\\"match_phrase\\\": {\\n \\\"value.processInstanceKey\\\": 2251799831883666\\n }\\n },\\n ],\\n \\\"should\\\": [],\\n \\\"must_not\\\": [\\n {\\n \\\"match_phrase\\\": {\\n \\\"value.elementId\\\": \\\"Gateway_0y10qkw\\\"\\n }\\n }{\\n \\\"match_phrase\\\": {\\n \\\"value.elementId\\\": \\\"Gateway_071nepp\\\"\\n }\\n }{\\n \\\"match_phrase\\\": {\\n \\\"value.elementId\\\": \\\"Gateway_1hsu2ep\\\"\\n }\\n }\\n {\\n \\\"match_phrase\\\": {\\n \\\"value.elementId\\\": \\\"Event_1b36xu9\\\"\\n }\\n }\\n {\\n \\\"match_phrase\\\": {\\n \\\"value.elementId\\\": \\\"StartEvent_1\\\"\\n }\\n }\\n {\\n \\\"match_phrase\\\": {\\n \\\"value.elementId\\\": \\\"StartEvent_1\\\"\\n }\\n }\\n {\\n \\\"match_phrase\\\": {\\n \\\"value.elementId\\\": \\\"Flow_03ncatg\\\"\\n }\\n }\\n ]\\n }\\n }\\n }\\n },\\n format: {property: \\\"aggregations.categories.buckets\\\" }\\n },\\n mark: bar\\n\\n encoding: {\\n x: {\\\"field\\\": \\\"duration.value\\\", \\n \\\"type\\\": \\\"temporal\\\", \\n \\\"timeUnit\\\": \\\"seconds\\\",\\n \\\"axis\\\": {title: \\\"Time taken in miliseconds \\\" }\\n \\n }\\n y: {\\n field: key\\n type: nominal\\n axis: { title: \\\"Tasks\\\" }\\n }\\n color: {\\n field: key\\n type: nominal\\n }\\n }\\n \\\"layer\\\": [\\n {\\n \\\"mark\\\": \\\"rect\\\",\\n \\\"encoding\\\": {\\n \\\"color\\\": {\\n \\\"field\\\": \\\"duration.value\\\",\\n \\\"type\\\": \\\"temporal\\\",\\n \\\"timeUnit\\\": \\\"milliseconds\\\",\\n \\\"title\\\": \\\"Time elapsed\\\",\\n \\\"legend\\\": {\\\"direction\\\": \\\"horizontal\\\", \\\"gradientLength\\\": 120}\\n }\\n }\\n }]\\n}\"},\"uiState\":{},\"data\":{\"aggs\":[],\"searchSource\":{\"query\":{\"language\":\"kuery\",\"query\":\"\"},\"filter\":[]}}},\"enhancements\":{}}},{\"version\":\"7.13.2\",\"type\":\"visualization\",\"gridData\":{\"x\":24,\"y\":46,\"w\":24,\"h\":15,\"i\":\"039d9f15-1fef-4e21-ab1d-cee335f2b337\"},\"panelIndex\":\"039d9f15-1fef-4e21-ab1d-cee335f2b337\",\"embeddableConfig\":{\"savedVis\":{\"title\":\"Vega Visualisation 2: All process with elapsed time per task\",\"description\":\"\",\"type\":\"vega\",\"params\":{\"spec\":\"{\\n \\\"$schema\\\": \\\"https://vega.github.io/schema/vega-lite/v5.json\\\",\\n \\\"title\\\": \\\"Event counts from all indexes\\\",\\n \\\"data\\\": {\\n \\\"url\\\": {\\n \\\"index\\\": \\\"_all\\\",\\n \\\"body\\\": {\\n \\\"aggs\\\": {\\n \\\"categories\\\": {\\n \\\"terms\\\": {\\\"field\\\": \\\"value.processInstanceKey\\\"},\\n \\\"aggs\\\": {\\n \\\"duration\\\": {\\n scripted_metric: {\\n init_script: state.responses = ['start':0,'stop':0]\\n map_script: def intent = doc['intent'].value; def time = doc['timestamp'].value.getMillis(); state.responses.start = time; if (intent.contains('COMPLETED') && time > state.responses['stop']) { state.responses.stop = time;} else if(intent.contains('CREATED') && time < state.responses['start'] ) {state.responses.start = time;}\\n combine_script: state.responses\\n reduce_script: def diff = null;for (responses in states) {diff = responses['stop'] - responses['start'];}return diff;\\n }\\n }\\n }\\n }\\n },\\n \\\"size\\\": 0,\\n \\\"query\\\": {\\n \\\"bool\\\": {\\n \\\"must\\\": [],\\n \\\"filter\\\": [\\n {\\\"match_all\\\": {}},\\n {\\\"match_phrase\\\": {\\\"value.bpmnProcessId\\\": \\\"mpesa-flow-v3\\\"}}\\n ],\\n \\\"should\\\": [],\\n \\\"must_not\\\": []\\n }\\n }\\n }\\n },\\n \\\"format\\\": {\\\"property\\\": \\\"aggregations.categories.buckets\\\"}\\n },\\n \\\"encoding\\\": {\\n \\\"x\\\": {\\n \\\"field\\\": \\\"duration.value\\\",\\n \\\"type\\\": \\\"temporal\\\",\\n \\\"timeUnit\\\": \\\"seconds\\\",\\n \\\"axis\\\": {\\\"title\\\": \\\"Time taken in miliseconds \\\"}\\n },\\n \\\"y\\\": {\\n \\\"field\\\": \\\"key\\\",\\n \\\"type\\\": \\\"nominal\\\",\\n \\\"axis\\\": {\\\"title\\\": \\\"Process Instance\\\"}\\n },\\n \\\"color\\\": {\\\"field\\\": \\\"key\\\", \\\"type\\\": \\\"nominal\\\"}\\n },\\n \\\"layer\\\": [\\n {\\n \\\"mark\\\": \\\"rect\\\",\\n \\\"encoding\\\": {\\n \\\"color\\\": {\\n \\\"field\\\": \\\"duration.value\\\",\\n \\\"type\\\": \\\"temporal\\\",\\n \\\"timeUnit\\\": \\\"milliseconds\\\",\\n \\\"title\\\": \\\"Time elapsed\\\",\\n \\\"legend\\\": {\\\"direction\\\": \\\"horizontal\\\", \\\"gradientLength\\\": 120}\\n }\\n }\\n },\\n {\\n \\\"mark\\\": \\\"text\\\",\\n \\\"encoding\\\": {\\n \\\"text\\\": {\\\"field\\\": \\\"duration.value\\\", \\\"type\\\": \\\"temporal\\\",\\n \\\"timeUnit\\\": \\\"seconds\\\"},\\n \\\"color\\\": {\\n \\\"condition\\\": {\\n \\\"test\\\": \\\"datum['duration.value'] > 120000\\\",\\n \\\"value\\\": \\\"red\\\"\\n },\\n \\\"value\\\": \\\"black\\\"\\n }\\n }\\n }\\n ],\\n \\\"config\\\": {\\\"axis\\\": {\\\"grid\\\": true, \\\"tickBand\\\": \\\"extent\\\"}}\\n}\"},\"uiState\":{},\"data\":{\"aggs\":[],\"searchSource\":{\"query\":{\"language\":\"kuery\",\"query\":\"\"},\"filter\":[]}}},\"enhancements\":{}}},{\"version\":\"7.13.2\",\"type\":\"visualization\",\"gridData\":{\"x\":0,\"y\":61,\"w\":24,\"h\":15,\"i\":\"5eed1959-b4a0-4cb9-80d8-16fb83199078\"},\"panelIndex\":\"5eed1959-b4a0-4cb9-80d8-16fb83199078\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_5eed1959-b4a0-4cb9-80d8-16fb83199078\"}]","refreshInterval":{"pause":true,"value":0},"timeFrom":"now-1w","timeRestore":true,"timeTo":"now","title":"PHEE","version":1},"coreMigrationVersion":"7.13.2","id":"8bcc01c0-26bd-11ec-95b3-cb627b5ccd4b","migrationVersion":{"dashboard":"7.13.1"},"references":[{"id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","name":"6fc4224e-00ad-4a0b-bc30-cdd7c8c26e68:control_6fc4224e-00ad-4a0b-bc30-cdd7c8c26e68_0_index_pattern","type":"index-pattern"},{"id":"f21cb760-26bf-11ec-95b3-cb627b5ccd4b","name":"2adee62e-ff39-4b27-899d-6acc933194f7:panel_2adee62e-ff39-4b27-899d-6acc933194f7","type":"visualization"},{"id":"df1144f0-26c0-11ec-95b3-cb627b5ccd4b","name":"17035d4c-4ab4-4311-b7e9-6d60b8f532c3:panel_17035d4c-4ab4-4311-b7e9-6d60b8f532c3","type":"visualization"},{"id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","name":"17035d4c-4ab4-4311-b7e9-6d60b8f532c3:kibanaSavedObjectMeta.searchSourceJSON.index","type":"index-pattern"},{"id":"8cf5f410-26c3-11ec-95b3-cb627b5ccd4b","name":"1a06ddb5-0b36-40e8-96be-7640d6d954b3:panel_1a06ddb5-0b36-40e8-96be-7640d6d954b3","type":"visualization"},{"id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","name":"1a06ddb5-0b36-40e8-96be-7640d6d954b3:kibanaSavedObjectMeta.searchSourceJSON.index","type":"index-pattern"},{"id":"2b5132f0-26c4-11ec-95b3-cb627b5ccd4b","name":"162e25cc-3f99-48cd-ac26-c16f4c18bf6f:panel_162e25cc-3f99-48cd-ac26-c16f4c18bf6f","type":"visualization"},{"id":"cc282ac0-26c5-11ec-95b3-cb627b5ccd4b","name":"38bca8ec-0692-433d-996b-1366b50ce5b2:panel_38bca8ec-0692-433d-996b-1366b50ce5b2","type":"visualization"},{"id":"04748e40-7771-11ec-80b6-cdd557ff9b70","name":"5eed1959-b4a0-4cb9-80d8-16fb83199078:panel_5eed1959-b4a0-4cb9-80d8-16fb83199078","type":"visualization"}],"type":"dashboard","updated_at":"2022-01-17T09:27:43.036Z","version":"WzEwODI4LDEzXQ=="} +{"exportedCount":8,"missingRefCount":0,"missingReferences":[]} \ No newline at end of file diff --git a/ph-ee-importer-es/src/main/resources/kibana/Process Definitions Key n Name.txt b/ph-ee-importer-es/src/main/resources/kibana/Process Definitions Key n Name.txt new file mode 100644 index 000000000..2af756265 --- /dev/null +++ b/ph-ee-importer-es/src/main/resources/kibana/Process Definitions Key n Name.txt @@ -0,0 +1,3 @@ +{"attributes":{"fieldAttrs":"{"value.bpmnProcessId":{"count":4},"value.processDefinitionKey":{"count":4},"value.processDefinitionVersion":{"count":3},"value.processInstanceKey":{"count":3},"value.elementId":{"count":2},"value.retries":{"count":2},"value.type":{"count":2},"intent":{"count":1},"timestamp":{"count":1}}","fields":"[]","runtimeFieldMap":"{}","timeFieldName":"timestamp","title":"zeebe-*"},"coreMigrationVersion":"7.13.2","id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","migrationVersion":{"index-pattern":"7.11.0"},"references":[],"type":"index-pattern","updated_at":"2022-01-17T09:27:43.036Z","version":"WzEwODIxLDEzXQ=="} +{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{"query":{"language":"kuery","query":""},"filter":[],"indexRefName":"kibanaSavedObjectMeta.searchSourceJSON.index"}"},"title":"Process Definitions Key n Name","uiStateJSON":"{}","version":1,"visState":"{"title":"Process Definitions Key n Name","type":"table","aggs":[{"id":"1","enabled":true,"type":"count","params":{},"schema":"metric"},{"id":"4","enabled":true,"type":"terms","params":{"field":"value.bpmnProcessId","orderBy":"1","order":"desc","size":5,"otherBucket":false,"otherBucketLabel":"Other","missingBucket":false,"missingBucketLabel":"Missing"},"schema":"bucket"},{"id":"3","enabled":true,"type":"terms","params":{"field":"value.processDefinitionKey","orderBy":"1","order":"desc","size":10,"otherBucket":false,"otherBucketLabel":"Other","missingBucket":false,"missingBucketLabel":"Missing"},"schema":"bucket"}],"params":{"perPage":10,"showPartialRows":false,"showMetricsAtAllLevels":false,"showTotal":false,"showToolbar":false,"totalFunc":"sum","percentageCol":""}}"},"coreMigrationVersion":"7.13.2","id":"75cbd5d0-26bd-11ec-95b3-cb627b5ccd4b","migrationVersion":{"visualization":"7.13.1"},"references":[{"id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","name":"kibanaSavedObjectMeta.searchSourceJSON.index","type":"index-pattern"}],"type":"visualization","updated_at":"2021-10-09T11:23:47.619Z","version":"Wzk5MzYsMTNd"} +{"exportedCount":2,"missingRefCount":0,"missingReferences":[]} \ No newline at end of file diff --git a/ph-ee-importer-es/src/main/resources/kibana/Process Variables.txt b/ph-ee-importer-es/src/main/resources/kibana/Process Variables.txt new file mode 100644 index 000000000..bf4c0f097 --- /dev/null +++ b/ph-ee-importer-es/src/main/resources/kibana/Process Variables.txt @@ -0,0 +1,3 @@ +{"attributes":{"fieldAttrs":"{"value.bpmnProcessId":{"count":4},"value.processDefinitionKey":{"count":4},"value.processDefinitionVersion":{"count":3},"value.processInstanceKey":{"count":3},"value.elementId":{"count":2},"value.retries":{"count":2},"value.type":{"count":2},"intent":{"count":1},"timestamp":{"count":1}}","fields":"[]","runtimeFieldMap":"{}","timeFieldName":"timestamp","title":"zeebe-*"},"coreMigrationVersion":"7.13.2","id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","migrationVersion":{"index-pattern":"7.11.0"},"references":[],"type":"index-pattern","updated_at":"2022-01-17T09:27:43.036Z","version":"WzExOTI4LDE3XQ=="} +{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{"query":{"query":"","language":"kuery"},"filter":[],"indexRefName":"kibanaSavedObjectMeta.searchSourceJSON.index"}"},"title":"Process Variables","uiStateJSON":"{}","version":1,"visState":"{"title":"Process Variables","type":"table","aggs":[{"id":"1","enabled":true,"type":"count","params":{},"schema":"metric"},{"id":"2","enabled":true,"type":"terms","params":{"field":"value.name","orderBy":"1","order":"desc","size":100,"otherBucket":false,"otherBucketLabel":"Other","missingBucket":false,"missingBucketLabel":"Missing","customLabel":"variableName"},"schema":"bucket"},{"id":"3","enabled":true,"type":"terms","params":{"field":"value.value","orderBy":"1","order":"desc","size":100,"otherBucket":false,"otherBucketLabel":"Other","missingBucket":false,"missingBucketLabel":"Missing","customLabel":"variableValue"},"schema":"bucket"}],"params":{"perPage":20,"showPartialRows":false,"showMetricsAtAllLevels":false,"showTotal":false,"showToolbar":false,"totalFunc":"sum","percentageCol":""}}"},"coreMigrationVersion":"7.13.2","id":"8cf5f410-26c3-11ec-95b3-cb627b5ccd4b","migrationVersion":{"visualization":"7.13.1"},"references":[{"id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","name":"kibanaSavedObjectMeta.searchSourceJSON.index","type":"index-pattern"}],"type":"visualization","updated_at":"2022-01-17T09:27:43.036Z","version":"WzExOTMxLDE3XQ=="} +{"exportedCount":2,"missingRefCount":0,"missingReferences":[]} \ No newline at end of file diff --git a/ph-ee-importer-es/src/main/resources/kibana/ProcessInstanceCount.txt b/ph-ee-importer-es/src/main/resources/kibana/ProcessInstanceCount.txt new file mode 100644 index 000000000..ef75f4beb --- /dev/null +++ b/ph-ee-importer-es/src/main/resources/kibana/ProcessInstanceCount.txt @@ -0,0 +1,3 @@ +{"attributes":{"fieldAttrs":"{"value.bpmnProcessId":{"count":4},"value.processDefinitionKey":{"count":4},"value.processDefinitionVersion":{"count":3},"value.processInstanceKey":{"count":3},"value.elementId":{"count":2},"value.retries":{"count":2},"value.type":{"count":2},"intent":{"count":1},"timestamp":{"count":1}}","fields":"[]","runtimeFieldMap":"{}","timeFieldName":"timestamp","title":"zeebe-*"},"coreMigrationVersion":"7.13.2","id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","migrationVersion":{"index-pattern":"7.11.0"},"references":[],"type":"index-pattern","updated_at":"2022-01-17T09:27:43.036Z","version":"WzExOTI4LDE3XQ=="} +{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{"query":{"query":"","language":"kuery"},"filter":[],"indexRefName":"kibanaSavedObjectMeta.searchSourceJSON.index"}"},"title":"ProcessInstanceCount","uiStateJSON":"{}","version":1,"visState":"{"title":"ProcessInstanceCount","type":"table","aggs":[{"id":"1","enabled":true,"type":"cardinality","params":{"field":"value.processInstanceKey","customLabel":"processInstanceCount"},"schema":"metric"},{"id":"2","enabled":true,"type":"terms","params":{"field":"value.bpmnProcessId","orderBy":"1","order":"desc","size":10,"otherBucket":false,"otherBucketLabel":"Other","missingBucket":false,"missingBucketLabel":"Missing","customLabel":"processDefinition"},"schema":"bucket"}],"params":{"perPage":10,"showPartialRows":false,"showMetricsAtAllLevels":false,"showTotal":false,"showToolbar":false,"totalFunc":"sum","percentageCol":""}}"},"coreMigrationVersion":"7.13.2","id":"f21cb760-26bf-11ec-95b3-cb627b5ccd4b","migrationVersion":{"visualization":"7.13.1"},"references":[{"id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","name":"kibanaSavedObjectMeta.searchSourceJSON.index","type":"index-pattern"}],"type":"visualization","updated_at":"2022-01-17T09:27:43.036Z","version":"WzExOTI5LDE3XQ=="} +{"exportedCount":2,"missingRefCount":0,"missingReferences":[]} \ No newline at end of file diff --git a/ph-ee-importer-es/src/main/resources/kibana/ProcessInstanceKeys.txt b/ph-ee-importer-es/src/main/resources/kibana/ProcessInstanceKeys.txt new file mode 100644 index 000000000..d1946eb01 --- /dev/null +++ b/ph-ee-importer-es/src/main/resources/kibana/ProcessInstanceKeys.txt @@ -0,0 +1,3 @@ +{"attributes":{"fieldAttrs":"{"value.bpmnProcessId":{"count":4},"value.processDefinitionKey":{"count":4},"value.processDefinitionVersion":{"count":3},"value.processInstanceKey":{"count":3},"value.elementId":{"count":2},"value.retries":{"count":2},"value.type":{"count":2},"intent":{"count":1},"timestamp":{"count":1}}","fields":"[]","runtimeFieldMap":"{}","timeFieldName":"timestamp","title":"zeebe-*"},"coreMigrationVersion":"7.13.2","id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","migrationVersion":{"index-pattern":"7.11.0"},"references":[],"type":"index-pattern","updated_at":"2022-01-17T09:27:43.036Z","version":"WzExOTI4LDE3XQ=="} +{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{"query":{"query":"","language":"kuery"},"filter":[],"indexRefName":"kibanaSavedObjectMeta.searchSourceJSON.index"}"},"title":"ProcessInstanceKeys","uiStateJSON":"{}","version":1,"visState":"{"title":"ProcessInstanceKeys","type":"table","aggs":[{"id":"1","enabled":true,"type":"count","params":{},"schema":"metric"},{"id":"2","enabled":true,"type":"terms","params":{"field":"value.bpmnProcessId","orderBy":"1","order":"desc","size":1005,"otherBucket":false,"otherBucketLabel":"Other","missingBucket":false,"missingBucketLabel":"Missing","customLabel":"ProcessDef"},"schema":"bucket"},{"id":"3","enabled":true,"type":"terms","params":{"field":"value.processInstanceKey","orderBy":"1","order":"desc","size":5,"otherBucket":true,"otherBucketLabel":"Other","missingBucket":false,"missingBucketLabel":"Missing","customLabel":"ProcessInstanceKey"},"schema":"bucket"}],"params":{"perPage":10,"showPartialRows":false,"showMetricsAtAllLevels":false,"showTotal":false,"showToolbar":false,"totalFunc":"sum","percentageCol":""}}"},"coreMigrationVersion":"7.13.2","id":"df1144f0-26c0-11ec-95b3-cb627b5ccd4b","migrationVersion":{"visualization":"7.13.1"},"references":[{"id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","name":"kibanaSavedObjectMeta.searchSourceJSON.index","type":"index-pattern"}],"type":"visualization","updated_at":"2022-01-17T09:27:43.036Z","version":"WzExOTMwLDE3XQ=="} +{"exportedCount":2,"missingRefCount":0,"missingReferences":[]} \ No newline at end of file diff --git a/ph-ee-importer-es/src/main/resources/kibana/Task:State.txt b/ph-ee-importer-es/src/main/resources/kibana/Task:State.txt new file mode 100644 index 000000000..e4ccd7813 --- /dev/null +++ b/ph-ee-importer-es/src/main/resources/kibana/Task:State.txt @@ -0,0 +1,3 @@ +{"attributes":{"fieldAttrs":"{"value.bpmnProcessId":{"count":4},"value.processDefinitionKey":{"count":4},"value.processDefinitionVersion":{"count":3},"value.processInstanceKey":{"count":3},"value.elementId":{"count":2},"value.retries":{"count":2},"value.type":{"count":2},"intent":{"count":1},"timestamp":{"count":1}}","fields":"[]","runtimeFieldMap":"{}","timeFieldName":"timestamp","title":"zeebe-*"},"coreMigrationVersion":"7.13.2","id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","migrationVersion":{"index-pattern":"7.11.0"},"references":[],"type":"index-pattern","updated_at":"2022-01-17T09:27:43.036Z","version":"WzExOTI4LDE3XQ=="} +{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{"query":{"query":"","language":"kuery"},"filter":[],"indexRefName":"kibanaSavedObjectMeta.searchSourceJSON.index"}"},"title":"Task/State ","uiStateJSON":"{}","version":1,"visState":"{"title":"Task/State ","type":"table","aggs":[{"id":"1","enabled":true,"type":"count","params":{},"schema":"metric"},{"id":"2","enabled":true,"type":"terms","params":{"field":"value.type","orderBy":"1","order":"desc","size":20,"otherBucket":false,"otherBucketLabel":"Other","missingBucket":false,"missingBucketLabel":"Missing","customLabel":"Task/State Name"},"schema":"bucket"}],"params":{"perPage":10,"showPartialRows":false,"showMetricsAtAllLevels":false,"showTotal":false,"showToolbar":false,"totalFunc":"sum","percentageCol":""}}"},"coreMigrationVersion":"7.13.2","id":"cc282ac0-26c5-11ec-95b3-cb627b5ccd4b","migrationVersion":{"visualization":"7.13.1"},"references":[{"id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","name":"kibanaSavedObjectMeta.searchSourceJSON.index","type":"index-pattern"}],"type":"visualization","updated_at":"2022-01-17T09:27:43.036Z","version":"WzExOTMzLDE3XQ=="} +{"exportedCount":2,"missingRefCount":0,"missingReferences":[]} \ No newline at end of file diff --git a/ph-ee-importer-es/src/main/resources/kibana/Variable Input.txt b/ph-ee-importer-es/src/main/resources/kibana/Variable Input.txt new file mode 100644 index 000000000..7e59bc11b --- /dev/null +++ b/ph-ee-importer-es/src/main/resources/kibana/Variable Input.txt @@ -0,0 +1,3 @@ +{"attributes":{"fieldAttrs":"{"value.bpmnProcessId":{"count":4},"value.processDefinitionKey":{"count":4},"value.processDefinitionVersion":{"count":3},"value.processInstanceKey":{"count":3},"value.elementId":{"count":2},"value.retries":{"count":2},"value.type":{"count":2},"intent":{"count":1},"timestamp":{"count":1}}","fields":"[]","runtimeFieldMap":"{}","timeFieldName":"timestamp","title":"zeebe-*"},"coreMigrationVersion":"7.13.2","id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","migrationVersion":{"index-pattern":"7.11.0"},"references":[],"type":"index-pattern","updated_at":"2022-01-17T09:27:43.036Z","version":"WzExOTI4LDE3XQ=="} +{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{"query":{"query":"","language":"kuery"},"filter":[]}"},"title":"Variable Input","uiStateJSON":"{}","version":1,"visState":"{"title":"Variable Input","type":"input_control_vis","aggs":[],"params":{"controls":[{"id":"1633538407315","fieldName":"value.name","parent":"","label":"VariableName","type":"list","options":{"type":"terms","multiselect":true,"dynamicOptions":true,"size":5,"order":"desc"},"indexPatternRefName":"control_0_index_pattern"}],"updateFiltersOnChange":false,"useTimeFilter":false,"pinFilters":false}}"},"coreMigrationVersion":"7.13.2","id":"2b5132f0-26c4-11ec-95b3-cb627b5ccd4b","migrationVersion":{"visualization":"7.13.1"},"references":[{"id":"4e01ca10-26bc-11ec-95b3-cb627b5ccd4b","name":"control_0_index_pattern","type":"index-pattern"}],"type":"visualization","updated_at":"2022-01-17T09:27:43.036Z","version":"WzExOTMyLDE3XQ=="} +{"exportedCount":2,"missingRefCount":0,"missingReferences":[]} \ No newline at end of file diff --git a/ph-ee-importer-es/src/main/resources/kibana/Vega Visualisation 1.txt b/ph-ee-importer-es/src/main/resources/kibana/Vega Visualisation 1.txt new file mode 100644 index 000000000..390313176 --- /dev/null +++ b/ph-ee-importer-es/src/main/resources/kibana/Vega Visualisation 1.txt @@ -0,0 +1,2 @@ +{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{"query":{"language":"kuery","query":""},"filter":[]}"},"title":"Vega Visualisation 1: Time taken for each task","uiStateJSON":"{}","version":1,"visState":"{"title":"Vega Visualisation 1: Time taken for each task","type":"vega","aggs":[],"params":{"spec":"{\n \"$schema\": \"https://vega.github.io/schema/vega-lite/v5.json\",\n \"title\": \"Event counts from all indexes\",\n \"data\": {\n \"url\": {\n \"index\": \"_all\",\n \"body\": {\n \"aggs\": {\n categories: {\n terms: { field: \"value.elementId\" }\n \"aggs\": {\n \"duration\": {\n \"scripted_metric\": {\n \"init_script\": \"state.responses = ['start':0,'stop':0]\", \n \"map_script\": \"def intent = doc['intent'].value; if (intent.contains('COMPLETED')) {state.responses.stop += doc['timestamp'].value.getMillis();} else if(intent.contains('CREATED')) {state.responses.start += doc['timestamp'].value.getMillis();} else {state.responses.start += 0;state.responses.stop += 0;}\",\n \"combine_script\": \"state.responses\",\n \"reduce_script\": \"def diff = null;for (responses in states) {diff = responses['stop'] - responses['start'];}return diff;\"\n }\n }\n }\n \n }\n }\n \"size\": 0,\n \"query\": {\n \"bool\": {\n \"must\": [],\n \"filter\": [\n {\n \"match_all\": {}\n },\n {\n \"match_phrase\": {\n \"value.bpmnProcessId\": \"mpesa-flow-v3\"\n }\n },\n {\n \"match_phrase\": {\n \"value.processInstanceKey\": 2251799831883666\n }\n },\n ],\n \"should\": [],\n \"must_not\": [\n {\n \"match_phrase\": {\n \"value.elementId\": \"Gateway_0y10qkw\"\n }\n }{\n \"match_phrase\": {\n \"value.elementId\": \"Gateway_071nepp\"\n }\n }{\n \"match_phrase\": {\n \"value.elementId\": \"Gateway_1hsu2ep\"\n }\n }\n {\n \"match_phrase\": {\n \"value.elementId\": \"Event_1b36xu9\"\n }\n }\n {\n \"match_phrase\": {\n \"value.elementId\": \"StartEvent_1\"\n }\n }\n {\n \"match_phrase\": {\n \"value.elementId\": \"StartEvent_1\"\n }\n }\n {\n \"match_phrase\": {\n \"value.elementId\": \"Flow_03ncatg\"\n }\n }\n ]\n }\n }\n }\n },\n format: {property: \"aggregations.categories.buckets\" }\n },\n mark: bar\n\n encoding: {\n x: {\"field\": \"duration.value\", \n \"type\": \"temporal\", \n \"timeUnit\": \"seconds\",\n \"axis\": {title: \"Time taken in miliseconds \" }\n \n }\n y: {\n field: key\n type: nominal\n axis: { title: \"Tasks\" }\n }\n color: {\n field: key\n type: nominal\n }\n }\n \"layer\": [\n {\n \"mark\": \"rect\",\n \"encoding\": {\n \"color\": {\n \"field\": \"duration.value\",\n \"type\": \"temporal\",\n \"timeUnit\": \"milliseconds\",\n \"title\": \"Time elapsed\",\n \"legend\": {\"direction\": \"horizontal\", \"gradientLength\": 120}\n }\n }\n }]\n}"}}"},"coreMigrationVersion":"7.13.2","id":"2e472360-5e88-11ec-a438-afa3cbc0f058","migrationVersion":{"visualization":"7.13.1"},"references":[],"type":"visualization","updated_at":"2022-01-17T08:38:32.243Z","version":"WzEwNTAxLDEzXQ=="} +{"exportedCount":1,"missingRefCount":0,"missingReferences":[]} \ No newline at end of file diff --git a/ph-ee-importer-es/src/main/resources/kibana/Vega Visualisation 2.txt b/ph-ee-importer-es/src/main/resources/kibana/Vega Visualisation 2.txt new file mode 100644 index 000000000..a76143013 --- /dev/null +++ b/ph-ee-importer-es/src/main/resources/kibana/Vega Visualisation 2.txt @@ -0,0 +1,2 @@ +{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{"query":{"language":"kuery","query":""},"filter":[]}"},"title":"Vega Visualisation 2: All process with elapsed time per task","uiStateJSON":"{}","version":1,"visState":"{"title":"Vega Visualisation 2: All process with elapsed time per task","type":"vega","aggs":[],"params":{"spec":"{\n \"$schema\": \"https://vega.github.io/schema/vega-lite/v5.json\",\n \"title\": \"Event counts from all indexes\",\n \"data\": {\n \"url\": {\n \"index\": \"_all\",\n \"body\": {\n \"aggs\": {\n \"categories\": {\n \"terms\": {\"field\": \"value.processInstanceKey\"},\n \"aggs\": {\n \"duration\": {\n scripted_metric: {\n init_script: state.responses = ['start':0,'stop':0]\n map_script: def intent = doc['intent'].value; def time = doc['timestamp'].value.getMillis(); state.responses.start = time; if (intent.contains('COMPLETED') && time > state.responses['stop']) { state.responses.stop = time;} else if(intent.contains('CREATED') && time < state.responses['start'] ) {state.responses.start = time;}\n combine_script: state.responses\n reduce_script: def diff = null;for (responses in states) {diff = responses['stop'] - responses['start'];}return diff;\n }\n }\n }\n }\n },\n \"size\": 0,\n \"query\": {\n \"bool\": {\n \"must\": [],\n \"filter\": [\n {\"match_all\": {}},\n {\"match_phrase\": {\"value.bpmnProcessId\": \"mpesa-flow-v3\"}}\n ],\n \"should\": [],\n \"must_not\": []\n }\n }\n }\n },\n \"format\": {\"property\": \"aggregations.categories.buckets\"}\n },\n \"encoding\": {\n \"x\": {\n \"field\": \"duration.value\",\n \"type\": \"temporal\",\n \"timeUnit\": \"seconds\",\n \"axis\": {\"title\": \"Time taken in miliseconds \"}\n },\n \"y\": {\n \"field\": \"key\",\n \"type\": \"nominal\",\n \"axis\": {\"title\": \"Process Instance\"}\n },\n \"color\": {\"field\": \"key\", \"type\": \"nominal\"}\n },\n \"layer\": [\n {\n \"mark\": \"rect\",\n \"encoding\": {\n \"color\": {\n \"field\": \"duration.value\",\n \"type\": \"temporal\",\n \"timeUnit\": \"milliseconds\",\n \"title\": \"Time elapsed\",\n \"legend\": {\"direction\": \"horizontal\", \"gradientLength\": 120}\n }\n }\n },\n {\n \"mark\": \"text\",\n \"encoding\": {\n \"text\": {\"field\": \"duration.value\", \"type\": \"temporal\",\n \"timeUnit\": \"seconds\"},\n \"color\": {\n \"condition\": {\n \"test\": \"datum['duration.value'] > 120000\",\n \"value\": \"red\"\n },\n \"value\": \"black\"\n }\n }\n }\n ],\n \"config\": {\"axis\": {\"grid\": true, \"tickBand\": \"extent\"}}\n}"}}"},"coreMigrationVersion":"7.13.2","id":"d8a2f570-61a1-11ec-a438-afa3cbc0f058","migrationVersion":{"visualization":"7.13.1"},"references":[],"type":"visualization","updated_at":"2022-01-17T08:38:18.374Z","version":"WzEwNDkyLDEzXQ=="} +{"exportedCount":1,"missingRefCount":0,"missingReferences":[]} \ No newline at end of file diff --git a/ph-ee-importer-es/src/main/resources/kibana/Vega Visualisation 3.txt b/ph-ee-importer-es/src/main/resources/kibana/Vega Visualisation 3.txt new file mode 100644 index 000000000..423b97c39 --- /dev/null +++ b/ph-ee-importer-es/src/main/resources/kibana/Vega Visualisation 3.txt @@ -0,0 +1,2 @@ +{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{"query":{"language":"lucene","query":""},"filter":[]}"},"title":"Vega Visualisation 3: Pie chart for transactions above filter","uiStateJSON":"{}","version":1,"visState":"{"title":"Vega Visualisation 3: Pie chart for transactions above filter","type":"vega","aggs":[],"params":{"spec":"{\n $schema: https://vega.github.io/schema/vega-lite/v5.json\n title: Event counts from all indexes\n data: {\n url: {\n index: _all\n body: {\n aggs: {\n categories: {\n terms: {\n field: value.processInstanceKey\n }\n aggs: {\n duration: {\n scripted_metric: {\n init_script: state.responses = ['start':0,'stop':0]\n map_script: def intent = doc['intent'].value; def time = doc['timestamp'].value.getMillis(); state.responses.start = time; if (intent.contains('COMPLETED') && time > state.responses['stop']) { state.responses.stop = time;} else if(intent.contains('CREATED') && time < state.responses['start'] ) {state.responses.start = time;}\n combine_script: state.responses\n reduce_script: def diff = null;for (responses in states) {diff = responses['stop'] - responses['start'];}return diff;\n }\n }\n }\n }\n }\n size: 0\n query: {\n bool: {\n must: [\n ]\n filter: [\n {\n match_all: {\n }\n }\n {\n match_phrase: {\n value.bpmnProcessId: mpesa-flow-v3\n }\n }\n ]\n should: [\n ]\n must_not: [\n ]\n }\n }\n }\n }\n format: {\n property: aggregations.categories.buckets\n }\n }\n transform: [\n {\n calculate: \"datum['duration.value'] > 120000 ? 'above 2 min' : 'below 2 min' \"\n as: diff\n }\n ]\n mark: arc\n encoding: {\n theta: {\n field: duration.value\n aggregate: count\n type: quantitative\n }\n color: {\n field: diff\n type: nominal\n axis: {\n title: Process Instance\n }\n }\n }\n}"}}"},"coreMigrationVersion":"7.13.2","id":"04748e40-7771-11ec-80b6-cdd557ff9b70","migrationVersion":{"visualization":"7.13.1"},"references":[],"type":"visualization","updated_at":"2022-01-17T08:40:40.620Z","version":"WzEwNTI1LDEzXQ=="} +{"exportedCount":1,"missingRefCount":0,"missingReferences":[]} \ No newline at end of file diff --git a/ph-ee-importer-es/src/main/resources/logback.xml b/ph-ee-importer-es/src/main/resources/logback.xml new file mode 100644 index 000000000..5f81424f3 --- /dev/null +++ b/ph-ee-importer-es/src/main/resources/logback.xml @@ -0,0 +1,18 @@ + + + + + + + + + + ${CONSOLE_LOG_PATTERN} + utf8 + + + + + + + diff --git a/ph-ee-importer-es/src/main/resources/zeebe-payments.json b/ph-ee-importer-es/src/main/resources/zeebe-payments.json new file mode 100644 index 000000000..214e649dc --- /dev/null +++ b/ph-ee-importer-es/src/main/resources/zeebe-payments.json @@ -0,0 +1,167 @@ +{ + "index_patterns": [ + "zeebe-payments_*" + ], + "order": 20, + "settings": { + "number_of_shards": "3", + "number_of_replicas": "0", + "queries": { + "cache": { + "enabled": "false" + } + } + }, + "aliases": { + "zeebe-payments": {} + }, + "mappings": { + "_doc": { + "dynamic_templates": [ + { + "strings": { + "match_mapping_type": "string", + "path_unmatch": "request.*", + "match": "*", + "mapping": { + "type": "text" + } + } + }, + { + "strings": { + "match_mapping_type": "object", + "path_unmatch": "request.*", + "match": "*", + "mapping": { + "type": "object" + } + } + } + ], + "properties": { + "accountId": { + "type": "text" + }, + "amount": { + "type": "float" + }, + "ams": { + "type": "text" + + }, + "clientCorrelationId": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "currency": { + "type": "text" + }, + "customData": { + "type": "text" + }, + "errorCode": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "errorDescription": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "errorInformation": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "initiator": { + "type": "text" + }, + "initiatorType": { + "type": "text" + }, + "isNotificationsFailureEnabled": { + "type": "text" + }, + "isNotificationsSuccessEnabled": { + "type": "text" + }, + "mpesaTransactionId": { + "type": "text" + }, + "mpesaTransactionStatusRetryCount": { + "type": "text" + }, + "originDate": { + "type": "date" + }, + "partyLookupFailed": { + "type": "text" + }, + "phoneNumber": { + "type": "text" + }, + "processDefinitionKey": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "processInstanceKey": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "scenario": { + "type": "text" + }, + "tenantId": { + "type": "text" + }, + "timer": { + "type": "text" + }, + "timestamp": { + "type": "date" + }, + "transactionFailed": { + "type": "text" + }, + "transactionId": { + "type": "text" + }, + "transferCreateFailed": { + "type": "text" + }, + "transferSettlementFailed": { + "type": "text" + } + } + } + } +} diff --git a/ph-ee-importer-es/src/main/resources/zeebe-record-deployment-template.json b/ph-ee-importer-es/src/main/resources/zeebe-record-deployment-template.json new file mode 100644 index 000000000..ab3b50cac --- /dev/null +++ b/ph-ee-importer-es/src/main/resources/zeebe-record-deployment-template.json @@ -0,0 +1,50 @@ +{ + "index_patterns": [ + "zeebe-record_deployment_*" + ], + "order": 20, + "aliases": { + "zeebe-record-deployment": {} + }, + "mappings": { + "_doc": { + "dynamic": "true", + "properties": { + "value": { + "dynamic": "true", + "properties": { + "deployedWorkflows": { + "properties": { + "bpmnProcessId": { + "type": "keyword" + }, + "version": { + "type": "long" + }, + "workflowKey": { + "type": "long" + }, + "resourceName": { + "type": "text" + } + } + }, + "resources": { + "properties": { + "resource": { + "enabled": false + }, + "resourceName": { + "type": "text" + }, + "resourceType": { + "type": "keyword" + } + } + } + } + } + } + } + } +} diff --git a/ph-ee-importer-es/src/main/resources/zeebe-record-error-template.json b/ph-ee-importer-es/src/main/resources/zeebe-record-error-template.json new file mode 100644 index 000000000..b27d0d84d --- /dev/null +++ b/ph-ee-importer-es/src/main/resources/zeebe-record-error-template.json @@ -0,0 +1,33 @@ +{ + "index_patterns": [ + "zeebe-record_error_*" + ], + "order": 20, + "aliases": { + "zeebe-record-error": {} + }, + "mappings": { + "_doc": { + "dynamic": "true", + "properties": { + "value": { + "dynamic": "true", + "properties": { + "exceptionMessage": { + "type": "text" + }, + "stacktrace": { + "type": "text" + }, + "errorEventPosition": { + "type": "long" + }, + "workflowInstanceKey": { + "type": "long" + } + } + } + } + } + } +} diff --git a/ph-ee-importer-es/src/main/resources/zeebe-record-incident-template.json b/ph-ee-importer-es/src/main/resources/zeebe-record-incident-template.json new file mode 100644 index 000000000..bd95e8e16 --- /dev/null +++ b/ph-ee-importer-es/src/main/resources/zeebe-record-incident-template.json @@ -0,0 +1,48 @@ +{ + "index_patterns": [ + "zeebe-record_incident_*" + ], + "order": 20, + "aliases": { + "zeebe-record-incident": {} + }, + "mappings": { + "_doc": { + "dynamic": "true", + "properties": { + "value": { + "dynamic": "true", + "properties": { + "errorType": { + "type": "keyword" + }, + "errorMessage": { + "type": "text" + }, + "bpmnProcessId": { + "type": "keyword" + }, + "workflowKey": { + "type": "long" + }, + "workflowInstanceKey": { + "type": "long" + }, + "elementId": { + "type": "keyword" + }, + "elementInstanceKey": { + "type": "long" + }, + "jobKey": { + "type": "long" + }, + "variableScopeKey": { + "type": "long" + } + } + } + } + } + } +} diff --git a/ph-ee-importer-es/src/main/resources/zeebe-record-job-batch-template.json b/ph-ee-importer-es/src/main/resources/zeebe-record-job-batch-template.json new file mode 100644 index 000000000..9956e2e07 --- /dev/null +++ b/ph-ee-importer-es/src/main/resources/zeebe-record-job-batch-template.json @@ -0,0 +1,87 @@ +{ + "index_patterns": [ + "zeebe-record_job-batch_*" + ], + "order": 20, + "aliases": { + "zeebe-record-job-batch": {} + }, + "mappings": { + "_doc": { + "dynamic": "true", + "properties": { + "value": { + "dynamic": "true", + "properties": { + "type": { + "type": "keyword" + }, + "worker": { + "type": "keyword" + }, + "timeout": { + "type": "long" + }, + "maxJobsToActivate": { + "type": "integer" + }, + "jobKeys": { + "type": "long" + }, + "jobs": { + "type": "nested", + "dynamic": "true", + "properties": { + "type": { + "type": "keyword" + }, + "elementId": { + "type": "text" + }, + "elementInstanceKey": { + "type": "long" + }, + "bpmnProcessId": { + "type": "keyword" + }, + "workflowDefinitionVersion": { + "type": "integer" + }, + "workflowInstanceKey": { + "type": "long" + }, + "workflowKey": { + "type": "long" + }, + "customHeaders": { + "enabled": false + }, + "worker": { + "type": "keyword" + }, + "retries": { + "type": "long" + }, + "deadline": { + "type": "date" + }, + "variables": { + "enabled": false + }, + "errorMessage": { + "type": "text" + }, + "errorCode": { + "type": "text" + } + } + }, + "truncated": { + "type": "boolean" + } + } + } + } + } + } +} diff --git a/ph-ee-importer-es/src/main/resources/zeebe-record-job-template.json b/ph-ee-importer-es/src/main/resources/zeebe-record-job-template.json new file mode 100644 index 000000000..81d473dfd --- /dev/null +++ b/ph-ee-importer-es/src/main/resources/zeebe-record-job-template.json @@ -0,0 +1,66 @@ +{ + "index_patterns": [ + "zeebe-record_job_*" + ], + "order": 20, + "settings": { + "number_of_shards": 3 + }, + "aliases": { + "zeebe-record-job": {} + }, + "mappings": { + "_doc": { + "dynamic": "true", + "properties": { + "value": { + "dynamic": "true", + "properties": { + "type": { + "type": "keyword" + }, + "elementId": { + "type": "text" + }, + "elementInstanceKey": { + "type": "long" + }, + "bpmnProcessId": { + "type": "keyword" + }, + "workflowDefinitionVersion": { + "type": "integer" + }, + "workflowInstanceKey": { + "type": "long" + }, + "workflowKey": { + "type": "long" + }, + "customHeaders": { + "enabled": false + }, + "worker": { + "type": "keyword" + }, + "retries": { + "type": "long" + }, + "deadline": { + "type": "long" + }, + "variables": { + "enabled": false + }, + "errorMessage": { + "type": "text" + }, + "errorCode": { + "type": "text" + } + } + } + } + } + } +} diff --git a/ph-ee-importer-es/src/main/resources/zeebe-record-message-subscription-template.json b/ph-ee-importer-es/src/main/resources/zeebe-record-message-subscription-template.json new file mode 100644 index 000000000..629aa9462 --- /dev/null +++ b/ph-ee-importer-es/src/main/resources/zeebe-record-message-subscription-template.json @@ -0,0 +1,42 @@ +{ + "index_patterns": [ + "zeebe-record_message-subscription_*" + ], + "order": 20, + "aliases": { + "zeebe-record-message-subscription": {} + }, + "mappings": { + "_doc": { + "dynamic": "true", + "properties": { + "value": { + "dynamic": "true", + "properties": { + "workflowInstancePartitionId": { + "type": "integer" + }, + "workflowInstanceKey": { + "type": "long" + }, + "elementInstanceKey": { + "type": "long" + }, + "messageName": { + "type": "keyword" + }, + "correlationKey": { + "type": "text" + }, + "bpmnProcessId": { + "type": "keyword" + }, + "messageKey": { + "type": "long" + } + } + } + } + } + } +} diff --git a/ph-ee-importer-es/src/main/resources/zeebe-record-message-template.json b/ph-ee-importer-es/src/main/resources/zeebe-record-message-template.json new file mode 100644 index 000000000..f03574cc2 --- /dev/null +++ b/ph-ee-importer-es/src/main/resources/zeebe-record-message-template.json @@ -0,0 +1,36 @@ +{ + "index_patterns": [ + "zeebe-record_message_*" + ], + "order": 20, + "aliases": { + "zeebe-record-message": {} + }, + "mappings": { + "_doc": { + "dynamic": "true", + "properties": { + "value": { + "dynamic": "true", + "properties": { + "name": { + "type": "keyword" + }, + "correlationKey": { + "type": "text" + }, + "messageId": { + "type": "keyword" + }, + "timeToLive": { + "type": "long" + }, + "variables": { + "enabled": false + } + } + } + } + } + } +} diff --git a/ph-ee-importer-es/src/main/resources/zeebe-record-template.json b/ph-ee-importer-es/src/main/resources/zeebe-record-template.json new file mode 100644 index 000000000..02168c25b --- /dev/null +++ b/ph-ee-importer-es/src/main/resources/zeebe-record-template.json @@ -0,0 +1,52 @@ +{ + "index_patterns": [ + "zeebe-record_*" + ], + "order": 10, + "settings": { + "number_of_shards": 1, + "number_of_replicas": 0, + "index.queries.cache.enabled": false + }, + "aliases": { + "zeebe-record": {} + }, + "mappings": { + "_doc": { + + "dynamic": "true", + "properties": { + "position": { + "type": "long" + }, + "sourceRecordPosition": { + "type": "long" + }, + "key": { + "type": "long" + }, + "timestamp": { + "type": "date" + }, + "intent": { + "type": "keyword" + }, + "partitionId": { + "type": "integer" + }, + "recordType": { + "type": "keyword" + }, + "rejectionType": { + "type": "keyword" + }, + "rejectionReason": { + "type": "text" + }, + "valueType": { + "type": "keyword" + } + } + } + } +} diff --git a/ph-ee-importer-es/src/main/resources/zeebe-record-variable-document-template.json b/ph-ee-importer-es/src/main/resources/zeebe-record-variable-document-template.json new file mode 100644 index 000000000..924d0687c --- /dev/null +++ b/ph-ee-importer-es/src/main/resources/zeebe-record-variable-document-template.json @@ -0,0 +1,30 @@ +{ + "index_patterns": [ + "zeebe-record_variable-document_*" + ], + "order": 20, + "aliases": { + "zeebe-record-variable-document": {} + }, + "mappings": { + "_doc": { + "dynamic": "true", + "properties": { + "value": { + "dynamic": "true", + "properties": { + "scopeKey": { + "type": "long" + }, + "updateSemantics": { + "type": "keyword" + }, + "variables": { + "enabled": false + } + } + } + } + } + } +} diff --git a/ph-ee-importer-es/src/main/resources/zeebe-record-variable-template.json b/ph-ee-importer-es/src/main/resources/zeebe-record-variable-template.json new file mode 100644 index 000000000..733e43f4d --- /dev/null +++ b/ph-ee-importer-es/src/main/resources/zeebe-record-variable-template.json @@ -0,0 +1,37 @@ +{ + "index_patterns": [ + "zeebe-record_variable_*" + ], + "order": 20, + "aliases": { + "zeebe-record-variable": {} + }, + "mappings": { + "_doc": { + "dynamic": "true", + "properties": { + "value": { + "dynamic": "true", + "properties": { + "name": { + "type": "keyword" + }, + "value": { + "type": "keyword", + "ignore_above": 8191 + }, + "scopeKey": { + "type": "long" + }, + "workflowInstanceKey": { + "type": "long" + }, + "workflowKey": { + "type": "long" + } + } + } + } + } + } +} diff --git a/ph-ee-importer-es/src/main/resources/zeebe-record-workflow-instance-creation-template.json b/ph-ee-importer-es/src/main/resources/zeebe-record-workflow-instance-creation-template.json new file mode 100644 index 000000000..0d0cb70b1 --- /dev/null +++ b/ph-ee-importer-es/src/main/resources/zeebe-record-workflow-instance-creation-template.json @@ -0,0 +1,36 @@ +{ + "index_patterns": [ + "zeebe-record_workflow-instance-creation_*" + ], + "order": 20, + "aliases": { + "zeebe-record-workflow-instance-creation": {} + }, + "mappings": { + "_doc": { + "dynamic": "true", + "properties": { + "value": { + "dynamic": "true", + "properties": { + "bpmnProcessId": { + "type": "keyword" + }, + "version": { + "type": "integer" + }, + "workflowKey": { + "type": "long" + }, + "workflowInstanceKey": { + "type": "long" + }, + "variables": { + "enabled": false + } + } + } + } + } + } +} diff --git a/ph-ee-importer-es/src/main/resources/zeebe-record-workflow-instance-subscription-template.json b/ph-ee-importer-es/src/main/resources/zeebe-record-workflow-instance-subscription-template.json new file mode 100644 index 000000000..e7d7bed5d --- /dev/null +++ b/ph-ee-importer-es/src/main/resources/zeebe-record-workflow-instance-subscription-template.json @@ -0,0 +1,42 @@ +{ + "index_patterns": [ + "zeebe-record_workflow-instance-subscription_*" + ], + "order": 20, + "aliases": { + "zeebe-record-workflow-instance-subscription": {} + }, + "mappings": { + "_doc": { + "dynamic": "true", + "properties": { + "value": { + "dynamic": "true", + "properties": { + "workflowInstanceKey": { + "type": "long" + }, + "elementInstanceKey": { + "type": "long" + }, + "messageName": { + "type": "keyword" + }, + "variables": { + "enabled": false + }, + "bpmnProcessId": { + "type": "keyword" + }, + "messageKey": { + "type": "long" + }, + "correlationKey": { + "type": "keyword" + } + } + } + } + } + } +} diff --git a/ph-ee-importer-es/src/main/resources/zeebe-record-workflow-instance-template.json b/ph-ee-importer-es/src/main/resources/zeebe-record-workflow-instance-template.json new file mode 100644 index 000000000..3fb8ea4c2 --- /dev/null +++ b/ph-ee-importer-es/src/main/resources/zeebe-record-workflow-instance-template.json @@ -0,0 +1,51 @@ +{ + "index_patterns": [ + "zeebe-record_workflow-instance_*" + ], + "order": 20, + "settings": { + "number_of_shards": 3 + }, + "aliases": { + "zeebe-record-workflow-instance": {} + }, + "mappings": { + "_doc": { + "dynamic": "true", + "properties": { + "value": { + "dynamic": "true", + "properties": { + "bpmnProcessId": { + "type": "keyword" + }, + "version": { + "type": "integer" + }, + "processDefinitionKey": { + "type": "long" + }, + "processInstanceKey": { + "type": "long" + }, + "elementId": { + "type": "keyword" + }, + "flowScopeKey": { + "type": "long" + }, + "bpmnElementType": { + "type": "keyword" + }, + "parentProcessInstanceKey": { + "type": "long" + }, + "parentElementInstanceKey": { + "type": "long" + } + } + } + } + } + } +} diff --git a/ph-ee-importer-rdbms/.circleci/config.yml b/ph-ee-importer-rdbms/.circleci/config.yml new file mode 100644 index 000000000..63334ed7d --- /dev/null +++ b/ph-ee-importer-rdbms/.circleci/config.yml @@ -0,0 +1,97 @@ +version: 2.1 +executors: + docker-executor: + docker: + - image: circleci/openjdk:17-buster-node-browsers-legacy + +jobs: + build_and_push_tag_image: + executor: docker-executor + environment: + JVM_OPTS: -Xmx512m + TERM: dumb + GITHUB_TOKEN: ${GITHUB_TOKEN} # Add the GitHub token as an environment variable + + steps: + - checkout + - setup_remote_docker: + version: 20.10.14 + - run: + name: Build and Push Docker tag Image + command: | + # Set environment variables + IMAGE_TAG=$CIRCLE_TAG + + # Check if the Docker image with the same tag already exists in Docker Hub + if curl -s -f -u "$DOCKERHUB_USERNAME":"$DOCKERHUB_PASSWORD" "https://hub.docker.com/v2/repositories/fynarfin/ph-ee-importer-rdbms/tags/$IMAGE_TAG" > /dev/null; then + echo "Skipping the build and push as the tag $IMAGE_TAG already exists in Docker Hub." + exit 0 + fi + # Build and tag the Docker image + ./gradlew bootJar + docker build -t "/ph-ee-importer-rdbms:$IMAGE_TAG" . + # Push the Docker image to Docker Hub + docker login -u "$DOCKERHUB_USERNAME" -p "$DOCKERHUB_PASSWORD" + docker push "/ph-ee-importer-rdbms:$IMAGE_TAG" + # when: always # The job will be executed even if there's no match for the tag filter + + build_and_push_latest_image: + executor: docker-executor + environment: + JVM_OPTS: -Xmx512m + TERM: dumb + + steps: + - checkout + # Install Docker to build and push the image + - setup_remote_docker: + version: 20.10.14 + + # Build the Docker image + - run: + name: Build Docker image + command: | + #Check for PR title Validity + + IMAGE_TAG=$CIRCLE_TAG + ./gradlew clean bootJar + docker build -t fynarfin/ph-ee-importer-rdbms:latest . + + if [ "$CIRCLE_BRANCH" != "develop" ]; then + PR_NUMBER=$(basename $CIRCLE_PULL_REQUEST) + PR_TITLE=$(curl -sSL "https://api.github.com/repos/fynarfin/$CIRCLE_PR_REPONAME/pulls/$PR_NUMBER" | jq -r '.title') + JIRA_STORY=$(echo $PR_TITLE | cut -d "[" -f2 | cut -d "]" -f1 | tr '[A-Z]' '[a-z]') + if [ -z "$JIRA_STORY" ]; then echo "Invalid PR title" && exit 1; else echo "Ticket NO: $JIRA_STORY"; fi + docker image tag fynarfin/$CIRCLE_PR_REPONAME:latest fynarfin/$CIRCLE_PR_REPONAME:$JIRA_STORY + fi + # Log in to DockerHub using environment variables + - run: + name: Login to DockerHub + command: echo "${DOCKERHUB_PASSWORD}" | docker login -u "${DOCKERHUB_USERNAME}" --password-stdin + + # Push the Docker image to DockerHub + - run: + name: Push Docker image to DockerHub + command: | + if [ "$CIRCLE_BRANCH" = "develop" ]; then + docker push fynarfin/ph-ee-importer-rdbms:latest + fi + if [ "$CIRCLE_BRANCH" != "develop" ]; then + PR_NUMBER=$(basename $CIRCLE_PULL_REQUEST) + PR_TITLE=$(curl -sSL "https://api.github.com/repos/fynarfin/$CIRCLE_PR_REPONAME/pulls/$PR_NUMBER" | jq -r '.title') + JIRA_STORY=$(echo $PR_TITLE | cut -d "[" -f2 | cut -d "]" -f1 | tr '[A-Z]' '[a-z]') + docker push fynarfin/$CIRCLE_PR_REPONAME:${JIRA_STORY} + fi +workflows: + version: 2 + build-and-push: + jobs: + - build_and_push_tag_image: + filters: + tags: + only: /^v\d+\.\d+\.\d+$/ # Match tags in the format v1.2.3 + context: + - DOCKER + - build_and_push_latest_image: + context: + - DOCKER diff --git a/ph-ee-importer-rdbms/.github/pull_request_template.md b/ph-ee-importer-rdbms/.github/pull_request_template.md new file mode 100644 index 000000000..98c407dab --- /dev/null +++ b/ph-ee-importer-rdbms/.github/pull_request_template.md @@ -0,0 +1,20 @@ +## Description + +* Describe the changes made and why they were made. +* Add a link to teh design document or include the design bullet points related to this PR here. + + _(Ignore if these details are present on the associated JIRA ticket)_ + +## Checklist + +Please make sure these boxes are checked before submitting your pull request - thanks! + +- [ ] Design related bullet points or design document link related to this PR added in the description above. + +- [ ] Updated corresponding Postman Collection or Api documentation for the changes in this PR. + +- [ ] Create/update unit or integration tests for verifying the changes made. + +- [ ] Add required Swagger annotation and update API documentation with details of any API changes if applicable + +- [ ] Followed the naming conventions as given in https://docs.google.com/document/d/1Q4vaMSzrTxxh9TS0RILuNkSkYCxotuYk1Xe0CMIkkCU/edit?usp=sharing diff --git a/ph-ee-importer-rdbms/.gitignore b/ph-ee-importer-rdbms/.gitignore new file mode 100644 index 000000000..105892017 --- /dev/null +++ b/ph-ee-importer-rdbms/.gitignore @@ -0,0 +1,15 @@ +*.iml +target +.idea +.project +.classpath +.settings +bin +bin/ +.gradle +.gradle/ +build +.DS_Store +createDDL.jdbc +console*.log + diff --git a/ph-ee-importer-rdbms/Dockerfile b/ph-ee-importer-rdbms/Dockerfile new file mode 100644 index 000000000..7477fba78 --- /dev/null +++ b/ph-ee-importer-rdbms/Dockerfile @@ -0,0 +1,5 @@ +FROM openjdk:17 +EXPOSE 8080 + +COPY build/libs/*.jar ./ +CMD java -jar *.jar diff --git a/ph-ee-importer-rdbms/Jenkinsfile b/ph-ee-importer-rdbms/Jenkinsfile new file mode 100644 index 000000000..93d98d26b --- /dev/null +++ b/ph-ee-importer-rdbms/Jenkinsfile @@ -0,0 +1,17 @@ +pipeline { + agent any + stages { + stage('build') { + steps { + sh 'mvn --version' + sh 'mvn -U clean package' + } + } + stage('docker') { + steps { + sh 'docker build . -t paymenthubee.azurecr.io/phee/importer-rdbms' + sh 'docker push paymenthubee.azurecr.io/phee/importer-rdbms' + } + } + } +} diff --git a/ph-ee-importer-rdbms/LICENSE b/ph-ee-importer-rdbms/LICENSE new file mode 100644 index 000000000..a612ad981 --- /dev/null +++ b/ph-ee-importer-rdbms/LICENSE @@ -0,0 +1,373 @@ +Mozilla Public License Version 2.0 +================================== + +1. Definitions +-------------- + +1.1. "Contributor" + means each individual or legal entity that creates, contributes to + the creation of, or owns Covered Software. + +1.2. "Contributor Version" + means the combination of the Contributions of others (if any) used + by a Contributor and that particular Contributor's Contribution. + +1.3. "Contribution" + means Covered Software of a particular Contributor. + +1.4. "Covered Software" + means Source Code Form to which the initial Contributor has attached + the notice in Exhibit A, the Executable Form of such Source Code + Form, and Modifications of such Source Code Form, in each case + including portions thereof. + +1.5. "Incompatible With Secondary Licenses" + means + + (a) that the initial Contributor has attached the notice described + in Exhibit B to the Covered Software; or + + (b) that the Covered Software was made available under the terms of + version 1.1 or earlier of the License, but not also under the + terms of a Secondary License. + +1.6. "Executable Form" + means any form of the work other than Source Code Form. + +1.7. "Larger Work" + means a work that combines Covered Software with other material, in + a separate file or files, that is not Covered Software. + +1.8. "License" + means this document. + +1.9. "Licensable" + means having the right to grant, to the maximum extent possible, + whether at the time of the initial grant or subsequently, any and + all of the rights conveyed by this License. + +1.10. "Modifications" + means any of the following: + + (a) any file in Source Code Form that results from an addition to, + deletion from, or modification of the contents of Covered + Software; or + + (b) any new file in Source Code Form that contains any Covered + Software. + +1.11. "Patent Claims" of a Contributor + means any patent claim(s), including without limitation, method, + process, and apparatus claims, in any patent Licensable by such + Contributor that would be infringed, but for the grant of the + License, by the making, using, selling, offering for sale, having + made, import, or transfer of either its Contributions or its + Contributor Version. + +1.12. "Secondary License" + means either the GNU General Public License, Version 2.0, the GNU + Lesser General Public License, Version 2.1, the GNU Affero General + Public License, Version 3.0, or any later versions of those + licenses. + +1.13. "Source Code Form" + means the form of the work preferred for making modifications. + +1.14. "You" (or "Your") + means an individual or a legal entity exercising rights under this + License. For legal entities, "You" includes any entity that + controls, is controlled by, or is under common control with You. For + purposes of this definition, "control" means (a) the power, direct + or indirect, to cause the direction or management of such entity, + whether by contract or otherwise, or (b) ownership of more than + fifty percent (50%) of the outstanding shares or beneficial + ownership of such entity. + +2. License Grants and Conditions +-------------------------------- + +2.1. Grants + +Each Contributor hereby grants You a world-wide, royalty-free, +non-exclusive license: + +(a) under intellectual property rights (other than patent or trademark) + Licensable by such Contributor to use, reproduce, make available, + modify, display, perform, distribute, and otherwise exploit its + Contributions, either on an unmodified basis, with Modifications, or + as part of a Larger Work; and + +(b) under Patent Claims of such Contributor to make, use, sell, offer + for sale, have made, import, and otherwise transfer either its + Contributions or its Contributor Version. + +2.2. Effective Date + +The licenses granted in Section 2.1 with respect to any Contribution +become effective for each Contribution on the date the Contributor first +distributes such Contribution. + +2.3. Limitations on Grant Scope + +The licenses granted in this Section 2 are the only rights granted under +this License. No additional rights or licenses will be implied from the +distribution or licensing of Covered Software under this License. +Notwithstanding Section 2.1(b) above, no patent license is granted by a +Contributor: + +(a) for any code that a Contributor has removed from Covered Software; + or + +(b) for infringements caused by: (i) Your and any other third party's + modifications of Covered Software, or (ii) the combination of its + Contributions with other software (except as part of its Contributor + Version); or + +(c) under Patent Claims infringed by Covered Software in the absence of + its Contributions. + +This License does not grant any rights in the trademarks, service marks, +or logos of any Contributor (except as may be necessary to comply with +the notice requirements in Section 3.4). + +2.4. Subsequent Licenses + +No Contributor makes additional grants as a result of Your choice to +distribute the Covered Software under a subsequent version of this +License (see Section 10.2) or under the terms of a Secondary License (if +permitted under the terms of Section 3.3). + +2.5. Representation + +Each Contributor represents that the Contributor believes its +Contributions are its original creation(s) or it has sufficient rights +to grant the rights to its Contributions conveyed by this License. + +2.6. Fair Use + +This License is not intended to limit any rights You have under +applicable copyright doctrines of fair use, fair dealing, or other +equivalents. + +2.7. Conditions + +Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted +in Section 2.1. + +3. Responsibilities +------------------- + +3.1. Distribution of Source Form + +All distribution of Covered Software in Source Code Form, including any +Modifications that You create or to which You contribute, must be under +the terms of this License. You must inform recipients that the Source +Code Form of the Covered Software is governed by the terms of this +License, and how they can obtain a copy of this License. You may not +attempt to alter or restrict the recipients' rights in the Source Code +Form. + +3.2. Distribution of Executable Form + +If You distribute Covered Software in Executable Form then: + +(a) such Covered Software must also be made available in Source Code + Form, as described in Section 3.1, and You must inform recipients of + the Executable Form how they can obtain a copy of such Source Code + Form by reasonable means in a timely manner, at a charge no more + than the cost of distribution to the recipient; and + +(b) You may distribute such Executable Form under the terms of this + License, or sublicense it under different terms, provided that the + license for the Executable Form does not attempt to limit or alter + the recipients' rights in the Source Code Form under this License. + +3.3. Distribution of a Larger Work + +You may create and distribute a Larger Work under terms of Your choice, +provided that You also comply with the requirements of this License for +the Covered Software. If the Larger Work is a combination of Covered +Software with a work governed by one or more Secondary Licenses, and the +Covered Software is not Incompatible With Secondary Licenses, this +License permits You to additionally distribute such Covered Software +under the terms of such Secondary License(s), so that the recipient of +the Larger Work may, at their option, further distribute the Covered +Software under the terms of either this License or such Secondary +License(s). + +3.4. Notices + +You may not remove or alter the substance of any license notices +(including copyright notices, patent notices, disclaimers of warranty, +or limitations of liability) contained within the Source Code Form of +the Covered Software, except that You may alter any license notices to +the extent required to remedy known factual inaccuracies. + +3.5. Application of Additional Terms + +You may choose to offer, and to charge a fee for, warranty, support, +indemnity or liability obligations to one or more recipients of Covered +Software. However, You may do so only on Your own behalf, and not on +behalf of any Contributor. You must make it absolutely clear that any +such warranty, support, indemnity, or liability obligation is offered by +You alone, and You hereby agree to indemnify every Contributor for any +liability incurred by such Contributor as a result of warranty, support, +indemnity or liability terms You offer. You may include additional +disclaimers of warranty and limitations of liability specific to any +jurisdiction. + +4. Inability to Comply Due to Statute or Regulation +--------------------------------------------------- + +If it is impossible for You to comply with any of the terms of this +License with respect to some or all of the Covered Software due to +statute, judicial order, or regulation then You must: (a) comply with +the terms of this License to the maximum extent possible; and (b) +describe the limitations and the code they affect. Such description must +be placed in a text file included with all distributions of the Covered +Software under this License. Except to the extent prohibited by statute +or regulation, such description must be sufficiently detailed for a +recipient of ordinary skill to be able to understand it. + +5. Termination +-------------- + +5.1. The rights granted under this License will terminate automatically +if You fail to comply with any of its terms. However, if You become +compliant, then the rights granted under this License from a particular +Contributor are reinstated (a) provisionally, unless and until such +Contributor explicitly and finally terminates Your grants, and (b) on an +ongoing basis, if such Contributor fails to notify You of the +non-compliance by some reasonable means prior to 60 days after You have +come back into compliance. Moreover, Your grants from a particular +Contributor are reinstated on an ongoing basis if such Contributor +notifies You of the non-compliance by some reasonable means, this is the +first time You have received notice of non-compliance with this License +from such Contributor, and You become compliant prior to 30 days after +Your receipt of the notice. + +5.2. If You initiate litigation against any entity by asserting a patent +infringement claim (excluding declaratory judgment actions, +counter-claims, and cross-claims) alleging that a Contributor Version +directly or indirectly infringes any patent, then the rights granted to +You by any and all Contributors for the Covered Software under Section +2.1 of this License shall terminate. + +5.3. In the event of termination under Sections 5.1 or 5.2 above, all +end user license agreements (excluding distributors and resellers) which +have been validly granted by You or Your distributors under this License +prior to termination shall survive termination. + +************************************************************************ +* * +* 6. Disclaimer of Warranty * +* ------------------------- * +* * +* Covered Software is provided under this License on an "as is" * +* basis, without warranty of any kind, either expressed, implied, or * +* statutory, including, without limitation, warranties that the * +* Covered Software is free of defects, merchantable, fit for a * +* particular purpose or non-infringing. The entire risk as to the * +* quality and performance of the Covered Software is with You. * +* Should any Covered Software prove defective in any respect, You * +* (not any Contributor) assume the cost of any necessary servicing, * +* repair, or correction. This disclaimer of warranty constitutes an * +* essential part of this License. No use of any Covered Software is * +* authorized under this License except under this disclaimer. * +* * +************************************************************************ + +************************************************************************ +* * +* 7. Limitation of Liability * +* -------------------------- * +* * +* Under no circumstances and under no legal theory, whether tort * +* (including negligence), contract, or otherwise, shall any * +* Contributor, or anyone who distributes Covered Software as * +* permitted above, be liable to You for any direct, indirect, * +* special, incidental, or consequential damages of any character * +* including, without limitation, damages for lost profits, loss of * +* goodwill, work stoppage, computer failure or malfunction, or any * +* and all other commercial damages or losses, even if such party * +* shall have been informed of the possibility of such damages. This * +* limitation of liability shall not apply to liability for death or * +* personal injury resulting from such party's negligence to the * +* extent applicable law prohibits such limitation. Some * +* jurisdictions do not allow the exclusion or limitation of * +* incidental or consequential damages, so this exclusion and * +* limitation may not apply to You. * +* * +************************************************************************ + +8. Litigation +------------- + +Any litigation relating to this License may be brought only in the +courts of a jurisdiction where the defendant maintains its principal +place of business and such litigation shall be governed by laws of that +jurisdiction, without reference to its conflict-of-law provisions. +Nothing in this Section shall prevent a party's ability to bring +cross-claims or counter-claims. + +9. Miscellaneous +---------------- + +This License represents the complete agreement concerning the subject +matter hereof. If any provision of this License is held to be +unenforceable, such provision shall be reformed only to the extent +necessary to make it enforceable. Any law or regulation which provides +that the language of a contract shall be construed against the drafter +shall not be used to construe this License against a Contributor. + +10. Versions of the License +--------------------------- + +10.1. New Versions + +Mozilla Foundation is the license steward. Except as provided in Section +10.3, no one other than the license steward has the right to modify or +publish new versions of this License. Each version will be given a +distinguishing version number. + +10.2. Effect of New Versions + +You may distribute the Covered Software under the terms of the version +of the License under which You originally received the Covered Software, +or under the terms of any subsequent version published by the license +steward. + +10.3. Modified Versions + +If you create software not governed by this License, and you want to +create a new license for such software, you may create and use a +modified version of this License if you rename the license and remove +any references to the name of the license steward (except to note that +such modified license differs from this License). + +10.4. Distributing Source Code Form that is Incompatible With Secondary +Licenses + +If You choose to distribute Source Code Form that is Incompatible With +Secondary Licenses under the terms of this version of the License, the +notice described in Exhibit B of this License must be attached. + +Exhibit A - Source Code Form License Notice +------------------------------------------- + + This Source Code Form is subject to the terms of the Mozilla Public + License, v. 2.0. If a copy of the MPL was not distributed with this + file, You can obtain one at http://mozilla.org/MPL/2.0/. + +If it is not possible or desirable to put the notice in a particular +file, then You may include the notice in a location (such as a LICENSE +file in a relevant directory) where a recipient would be likely to look +for such a notice. + +You may add additional accurate notices of copyright ownership. + +Exhibit B - "Incompatible With Secondary Licenses" Notice +--------------------------------------------------------- + + This Source Code Form is "Incompatible With Secondary Licenses", as + defined by the Mozilla Public License, v. 2.0. diff --git a/ph-ee-importer-rdbms/README.md b/ph-ee-importer-rdbms/README.md new file mode 100644 index 000000000..fe8068e49 --- /dev/null +++ b/ph-ee-importer-rdbms/README.md @@ -0,0 +1,3 @@ +# payment-hub-ee +Payment Hub Enterprise Edition middleware for integration to real-time payment systems. +#Auto-Trigger diff --git a/ph-ee-importer-rdbms/build.gradle b/ph-ee-importer-rdbms/build.gradle new file mode 100644 index 000000000..e65d1007e --- /dev/null +++ b/ph-ee-importer-rdbms/build.gradle @@ -0,0 +1,71 @@ +/* + * This file was generated by the Gradle 'init' task. + * + * This project uses @Incubating APIs which are subject to change. + */ + +plugins { + id 'java' + id 'java-library' + id 'maven-publish' + id 'org.springframework.boot' version '3.1.3' + id 'io.spring.dependency-management' version '1.1.3' +} + +repositories { + mavenLocal() + maven { + url = uri('https://repo.spring.io/milestone') + } + + maven { + url = uri('https://repo.maven.apache.org/maven2/') + } + maven { + url = uri('https://jfrog.sandbox.fynarfin.io/artifactory/fyn-libs-snapshot') + } +} + +dependencies { + api 'org.springframework.boot:spring-boot-starter:3.0.9' + api 'org.yaml:snakeyaml:2.0' + api 'org.springframework.boot:spring-boot-actuator:3.0.9' + api 'org.apache.kafka:kafka-streams:3.3.2' + api 'org.springframework.kafka:spring-kafka:3.0.9' + api 'org.json:json:20230227' + api 'io.javalin:javalin:5.6.2' + api 'org.springframework.boot:spring-boot-starter-data-jpa:3.0.9' + api 'org.eclipse.persistence:org.eclipse.persistence.jpa:4.0.1' + api 'com.fasterxml.jackson.dataformat:jackson-dataformat-csv:2.14.0' + api 'com.jayway.jsonpath:json-path:2.7.0' + api 'mysql:mysql-connector-java:8.0.31' + api 'org.postgresql:postgresql:42.5.1' + api 'com.zaxxer:HikariCP:5.0.1' + api 'org.apache.commons:commons-text:1.10.0' + implementation 'com.amazonaws:aws-java-sdk:1.11.486' + testImplementation 'org.junit.jupiter:junit-jupiter:5.9.1' + implementation 'org.projectlombok:lombok:1.18.22' + annotationProcessor 'org.projectlombok:lombok:1.18.24' + testImplementation 'org.junit.jupiter:junit-jupiter:5.9.1' +} + +group = 'hu.dpc.phee' +version = '1.0.0-SNAPSHOT' +description = 'importer-rdbms' +java.sourceCompatibility = JavaVersion.VERSION_17 + +publishing { + publications { + maven(MavenPublication) { + from(components.java) + } + } +} + +tasks.withType(JavaCompile) { + options.encoding = 'UTF-8' +} + +tasks.withType(Javadoc) { + options.encoding = 'UTF-8' +} diff --git a/ph-ee-importer-rdbms/config/checkstyle/checkstyle.xml b/ph-ee-importer-rdbms/config/checkstyle/checkstyle.xml new file mode 100644 index 000000000..b9350ad75 --- /dev/null +++ b/ph-ee-importer-rdbms/config/checkstyle/checkstyle.xml @@ -0,0 +1,240 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ph-ee-importer-rdbms/config/checkstyle/suppressions.xml b/ph-ee-importer-rdbms/config/checkstyle/suppressions.xml new file mode 100644 index 000000000..f4e5b54c3 --- /dev/null +++ b/ph-ee-importer-rdbms/config/checkstyle/suppressions.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + diff --git a/ph-ee-importer-rdbms/config/rdbms-cleanup.xml b/ph-ee-importer-rdbms/config/rdbms-cleanup.xml new file mode 100644 index 000000000..7d3e4b6d8 --- /dev/null +++ b/ph-ee-importer-rdbms/config/rdbms-cleanup.xml @@ -0,0 +1,71 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ph-ee-importer-rdbms/config/rdbms-formatter.xml b/ph-ee-importer-rdbms/config/rdbms-formatter.xml new file mode 100644 index 000000000..82f1d3642 --- /dev/null +++ b/ph-ee-importer-rdbms/config/rdbms-formatter.xml @@ -0,0 +1,366 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ph-ee-importer-rdbms/gradle/wrapper/gradle-wrapper.jar b/ph-ee-importer-rdbms/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 000000000..c1962a79e Binary files /dev/null and b/ph-ee-importer-rdbms/gradle/wrapper/gradle-wrapper.jar differ diff --git a/ph-ee-importer-rdbms/gradle/wrapper/gradle-wrapper.properties b/ph-ee-importer-rdbms/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 000000000..0419a8919 --- /dev/null +++ b/ph-ee-importer-rdbms/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,7 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.2.1-bin.zip +networkTimeout=10000 +validateDistributionUrl=true +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists \ No newline at end of file diff --git a/ph-ee-importer-rdbms/gradlew b/ph-ee-importer-rdbms/gradlew new file mode 100755 index 000000000..aeb74cbb4 --- /dev/null +++ b/ph-ee-importer-rdbms/gradlew @@ -0,0 +1,245 @@ +#!/bin/sh + +# +# Copyright © 2015-2021 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/ph-ee-importer-rdbms/gradlew.bat b/ph-ee-importer-rdbms/gradlew.bat new file mode 100644 index 000000000..6689b85be --- /dev/null +++ b/ph-ee-importer-rdbms/gradlew.bat @@ -0,0 +1,92 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 0 goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/ph-ee-importer-rdbms/settings.gradle b/ph-ee-importer-rdbms/settings.gradle new file mode 100644 index 000000000..a8b31cca5 --- /dev/null +++ b/ph-ee-importer-rdbms/settings.gradle @@ -0,0 +1,7 @@ +/* + * This file was generated by the Gradle 'init' task. + * + * This project uses @Incubating APIs which are subject to change. + */ + +rootProject.name = 'importer-rdbms' diff --git a/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/DatabaseImporterApplication.java b/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/DatabaseImporterApplication.java new file mode 100644 index 000000000..62db06eb4 --- /dev/null +++ b/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/DatabaseImporterApplication.java @@ -0,0 +1,31 @@ +package hu.dpc.phee.operator; + +import com.fasterxml.jackson.dataformat.csv.CsvMapper; +import hu.dpc.phee.operator.config.TransferTransformerConfig; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; +import org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class, DataSourceTransactionManagerAutoConfiguration.class}) +@Configuration +@EnableConfigurationProperties(value = TransferTransformerConfig.class) +public class DatabaseImporterApplication { + + static { + // NOTE zeebe timestamps are also GMT, parsed dates in DB should also use GMT to match this + System.setProperty("user.timezone", "GMT"); + } + + public static void main(String[] args) { + SpringApplication.run(DatabaseImporterApplication.class, args); + } + + @Bean + public CsvMapper csvMapper() { + return new CsvMapper(); + } +} diff --git a/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/Healthcheck.java b/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/Healthcheck.java new file mode 100644 index 000000000..585bdc9aa --- /dev/null +++ b/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/Healthcheck.java @@ -0,0 +1,22 @@ +package hu.dpc.phee.operator; + +import io.javalin.Javalin; +import jakarta.annotation.PostConstruct; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Service; + +@Service +public class Healthcheck { + private Logger logger = LoggerFactory.getLogger(this.getClass()); + + @PostConstruct + public void start() { + int port = 5000; + logger.info("starting healthcheck service on port {}", port); + Javalin.create() + .get("/", ctx -> ctx.result()) + .start(port); + } + +} diff --git a/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/config/AnalyticsConfig.java b/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/config/AnalyticsConfig.java new file mode 100644 index 000000000..8f9b6ec78 --- /dev/null +++ b/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/config/AnalyticsConfig.java @@ -0,0 +1,11 @@ +package hu.dpc.phee.operator.config; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class AnalyticsConfig { + + @Value("${reliability.events-timestamps-dump-enabled}") + public String enableEventsTimestampsDump; +} diff --git a/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/config/AwsStorageConfig.java b/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/config/AwsStorageConfig.java new file mode 100644 index 000000000..9a9f8d4ef --- /dev/null +++ b/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/config/AwsStorageConfig.java @@ -0,0 +1,37 @@ +package hu.dpc.phee.operator.config; + +import com.amazonaws.auth.AWSCredentials; +import com.amazonaws.auth.AWSStaticCredentialsProvider; +import com.amazonaws.auth.BasicAWSCredentials; +import com.amazonaws.client.builder.AwsClientBuilder; +import com.amazonaws.services.s3.AmazonS3; +import com.amazonaws.services.s3.AmazonS3ClientBuilder; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.context.annotation.Bean; +import org.springframework.stereotype.Component; + +@Component +public class AwsStorageConfig { + + @Value("${cloud.aws.credentials.access-key}") + private String accessKey; + + @Value("${cloud.aws.credentials.secret-key}") + private String accessSecret; + + @Value("${cloud.aws.region.static}") + private String region; + @Value("${cloud.aws.s3BaseUrl}") + private String endpoint; + + @Bean + @ConditionalOnProperty(value = "cloud.aws.enabled", havingValue = "true") + public AmazonS3 s3Client() { + AWSCredentials credentials = new BasicAWSCredentials(accessKey, accessSecret); + return AmazonS3ClientBuilder.standard().withCredentials(new AWSStaticCredentialsProvider(credentials)) + .withPathStyleAccessEnabled(true).withEndpointConfiguration(new AwsClientBuilder.EndpointConfiguration(endpoint, region)) + .build(); + } + +} diff --git a/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/config/CacheConfig.java b/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/config/CacheConfig.java new file mode 100644 index 000000000..20336168d --- /dev/null +++ b/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/config/CacheConfig.java @@ -0,0 +1,30 @@ +package hu.dpc.phee.operator.config; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.cache.CacheManager; +import org.springframework.cache.annotation.CacheEvict; +import org.springframework.cache.annotation.EnableCaching; +import org.springframework.cache.concurrent.ConcurrentMapCacheManager; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.scheduling.annotation.EnableScheduling; +import org.springframework.scheduling.annotation.Scheduled; + +@Configuration +@EnableCaching +@EnableScheduling +public class CacheConfig { + private Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Bean + public CacheManager cacheManager() { + return new ConcurrentMapCacheManager("tenantServerConnection"); + } + + @CacheEvict(allEntries = true, value = {"tenantServerConnection"}) + @Scheduled(fixedDelay = 10 * 60 * 1000, initialDelay = 500) + public void reportCacheEvict() { + logger.info("Flushing all cached tenantServerConnection entries"); + } +} diff --git a/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/config/EclipselinkJpaConfiguration.java b/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/config/EclipselinkJpaConfiguration.java new file mode 100644 index 000000000..9cb50122c --- /dev/null +++ b/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/config/EclipselinkJpaConfiguration.java @@ -0,0 +1,64 @@ +package hu.dpc.phee.operator.config; + +import org.eclipse.persistence.config.PersistenceUnitProperties; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.ObjectProvider; +import org.springframework.boot.autoconfigure.domain.EntityScan; +import org.springframework.boot.autoconfigure.orm.jpa.JpaBaseConfiguration; +import org.springframework.boot.autoconfigure.orm.jpa.JpaProperties; +import org.springframework.boot.autoconfigure.transaction.TransactionManagerCustomizers; +import org.springframework.context.annotation.AdviceMode; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.jpa.repository.config.EnableJpaRepositories; +import org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver; +import org.springframework.orm.jpa.vendor.AbstractJpaVendorAdapter; +import org.springframework.orm.jpa.vendor.EclipseLinkJpaVendorAdapter; +import org.springframework.transaction.annotation.EnableTransactionManagement; +import org.springframework.transaction.jta.JtaTransactionManager; + +import javax.sql.DataSource; +import java.util.HashMap; +import java.util.Map; + +@Configuration +@EntityScan(basePackages = "hu.dpc.phee.operator") +@EnableJpaRepositories(basePackages = "hu.dpc.phee.operator") +@EnableTransactionManagement(proxyTargetClass = true, mode = AdviceMode.PROXY) +public class EclipselinkJpaConfiguration extends JpaBaseConfiguration { + + private Logger logger = LoggerFactory.getLogger(this.getClass()); + + public EclipselinkJpaConfiguration(DataSource routingDataSource, JpaProperties properties, ObjectProvider jtaTransactionManager, ObjectProvider transactionManagerCustomizers) { + super(routingDataSource, properties, jtaTransactionManager); + logger.info("## Eclipselink datasource: {}", routingDataSource); + } + + @Override + protected AbstractJpaVendorAdapter createJpaVendorAdapter() { + return new EclipseLinkJpaVendorAdapter(); + } + + @Override + protected Map getVendorProperties() { + HashMap map = new HashMap<>(); + map.put(PersistenceUnitProperties.WEAVING, detectWeavingMode()); + map.put(PersistenceUnitProperties.LOGGING_LEVEL, "FINEST"); + map.put(PersistenceUnitProperties.DDL_GENERATION, "none"); + map.put("eclipselink.jdbc.batch-writing", "JDBC"); + map.put("eclipselink.jdbc.batch-writing.size", "1000"); + map.put("eclipselink.cache.shared.default", "false"); + map.put("eclipselink.logging.level.sql", "FINE"); + map.put("eclipselink.logging.parameters", "true"); + map.put("eclipselink.logging.session", "true"); + map.put("eclipselink.logging.thread", "true"); + map.put("eclipselink.logging.timestamp", "false"); + return map; + } + + private String detectWeavingMode() { + String weavingMode = InstrumentationLoadTimeWeaver.isInstrumentationAvailable() ? "true" : "static"; + logger.debug("weaving mode is set to {}", weavingMode); + return weavingMode; + } +} diff --git a/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/config/EclipselinkLogger.java b/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/config/EclipselinkLogger.java new file mode 100644 index 000000000..d0bec7ae9 --- /dev/null +++ b/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/config/EclipselinkLogger.java @@ -0,0 +1,167 @@ +package hu.dpc.phee.operator.config; + +import org.eclipse.persistence.logging.AbstractSessionLog; +import org.eclipse.persistence.logging.SessionLog; +import org.eclipse.persistence.logging.SessionLogEntry; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.util.StringUtils; + +import java.util.HashMap; +import java.util.Map; + +/** + * This is a wrapper class for SLF4J. It is used when messages need to be logged through SLF4J. + */ +public class EclipselinkLogger extends AbstractSessionLog { + + public static final String ECLIPSELINK_NAMESPACE = "org.eclipse.persistence.logging"; + public static final String DEFAULT_CATEGORY = "default"; + + public static final String DEFAULT_ECLIPSELINK_NAMESPACE = ECLIPSELINK_NAMESPACE + "." + DEFAULT_CATEGORY; + + private Map mapLevels; + private Map categoryLoggers = new HashMap<>(); + + public EclipselinkLogger() { + super(); + createCategoryLoggers(); + initMapLevels(); + } + + @Override + public void log(SessionLogEntry entry) { + if (!shouldLog(entry.getLevel(), entry.getNameSpace())) { + return; + } + + Logger logger = getLogger(entry.getNameSpace()); + LogLevel logLevel = getLogLevel(entry.getLevel()); + + StringBuilder message = new StringBuilder(); + message.append(getSupplementDetailString(entry)); + message.append(formatMessage(entry)); + + String finalMesssage = message.toString(); + switch (logLevel) { + case TRACE: + logger.trace(finalMesssage); + break; + case DEBUG: + logger.debug(finalMesssage); + break; + case INFO: + logger.info(finalMesssage); + break; + case WARN: + logger.warn(finalMesssage); + break; + case ERROR: + logger.error(finalMesssage); + break; + default: + break; + } + } + + @Override + public boolean shouldLog(int level, String category) { + Logger logger = getLogger(category); + boolean resp = false; + LogLevel logLevel = getLogLevel(level); + + switch (logLevel) { + case TRACE: + resp = logger.isTraceEnabled(); + break; + case DEBUG: + resp = logger.isDebugEnabled(); + break; + case INFO: + resp = logger.isInfoEnabled(); + break; + case WARN: + resp = logger.isWarnEnabled(); + break; + case ERROR: + resp = logger.isErrorEnabled(); + break; + default: + break; + } + return resp; + } + + @Override + public boolean shouldLog(int level) { + return shouldLog(level, DEFAULT_CATEGORY); + } + + /** + * Return true if SQL logging should log visible bind parameters. If the shouldDisplayData is not set, return false. + */ + @Override + public boolean shouldDisplayData() { + if (this.shouldDisplayData != null) { + return shouldDisplayData; + } else { + return false; + } + } + + /** + * Initialize loggers eagerly. + */ + private void createCategoryLoggers() { + for (String category : SessionLog.loggerCatagories) { + addLogger(category, ECLIPSELINK_NAMESPACE + "." + category); + } + addLogger(DEFAULT_CATEGORY, DEFAULT_ECLIPSELINK_NAMESPACE); + } + + /** + * INTERNAL: Add Logger to the categoryLoggers. + */ + private void addLogger(String loggerCategory, String loggerNameSpace) { + categoryLoggers.put(loggerCategory, + LoggerFactory.getLogger(loggerNameSpace)); + } + + /** + * INTERNAL: Return the Logger for the given category. + */ + private Logger getLogger(String wantedCategory) { + String category = wantedCategory; + if (!StringUtils.hasText(wantedCategory) || !this.categoryLoggers.containsKey(wantedCategory)) { + category = DEFAULT_CATEGORY; + } + return categoryLoggers.get(category); + } + + /** + * Return the corresponding Slf4j Level for a given EclipseLink level. + */ + private LogLevel getLogLevel(Integer level) { + LogLevel logLevel = mapLevels.get(level); + if (logLevel == null) { + logLevel = LogLevel.OFF; + } + return logLevel; + } + + enum LogLevel { + TRACE, DEBUG, INFO, WARN, ERROR, OFF + } + + private void initMapLevels() { + mapLevels = new HashMap<>(); + mapLevels.put(SessionLog.ALL, LogLevel.TRACE); + mapLevels.put(SessionLog.FINEST, LogLevel.TRACE); + mapLevels.put(SessionLog.FINER, LogLevel.TRACE); + mapLevels.put(SessionLog.FINE, LogLevel.DEBUG); + mapLevels.put(SessionLog.CONFIG, LogLevel.INFO); + mapLevels.put(SessionLog.INFO, LogLevel.INFO); + mapLevels.put(SessionLog.WARNING, LogLevel.WARN); + mapLevels.put(SessionLog.SEVERE, LogLevel.ERROR); + } +} diff --git a/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/config/KafkaConfiguration.java b/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/config/KafkaConfiguration.java new file mode 100644 index 000000000..b1187eda9 --- /dev/null +++ b/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/config/KafkaConfiguration.java @@ -0,0 +1,106 @@ +package hu.dpc.phee.operator.config; + +import org.apache.kafka.clients.consumer.ConsumerConfig; +import org.apache.kafka.common.serialization.Serdes; +import org.apache.kafka.common.serialization.StringDeserializer; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.kafka.annotation.EnableKafka; +import org.springframework.kafka.annotation.EnableKafkaStreams; +import org.springframework.kafka.annotation.KafkaStreamsDefaultConfiguration; +import org.springframework.kafka.config.ConcurrentKafkaListenerContainerFactory; +import org.springframework.kafka.config.KafkaListenerContainerFactory; +import org.springframework.kafka.config.KafkaStreamsConfiguration; +import org.springframework.kafka.core.ConsumerFactory; +import org.springframework.kafka.core.DefaultKafkaConsumerFactory; +import org.springframework.kafka.listener.ConcurrentMessageListenerContainer; + +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +import static org.apache.kafka.streams.StreamsConfig.*; + +@EnableKafka +@EnableKafkaStreams +@Configuration +public class KafkaConfiguration { + + private Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Value("${kafka.brokers}") + private String kafkaBrokers; + + @Value("kafka.consumer-group") + private String consumerGroup; + + @Value("kafka.username") + private String kafkaUserName; + + @Value("kafka.password") + private String kafkaPassword; + + + @Bean + KafkaListenerContainerFactory> kafkaListenerContainerFactory() { + ConcurrentKafkaListenerContainerFactory factory = new ConcurrentKafkaListenerContainerFactory<>(); + factory.setConsumerFactory(consumerFactory()); + factory.setConcurrency(3); // TODO externalize + factory.getContainerProperties().setPollTimeout(3000); // TODO externalize + + return factory; + } + + @Bean + public ConsumerFactory consumerFactory() { + return new DefaultKafkaConsumerFactory<>(consumerConfigs()); + } + + @Bean(name = KafkaStreamsDefaultConfiguration.DEFAULT_STREAMS_CONFIG_BEAN_NAME) + KafkaStreamsConfiguration kStreamsConfig() { + logger.info("kafka Brokers :{}",kafkaBrokers); + logger.info("consumer group :{}",consumerGroup); + Map props = new HashMap<>(); + props.put(APPLICATION_ID_CONFIG, consumerGroup); + props.put(BOOTSTRAP_SERVERS_CONFIG, kafkaBrokers); + props.put(DEFAULT_KEY_SERDE_CLASS_CONFIG, Serdes.String().getClass().getName()); + props.put(COMMIT_INTERVAL_MS_CONFIG, 1000); + return new KafkaStreamsConfiguration(props); + } + + public Map consumerConfigs() { + String hostname = buildKafkaClientId(logger); + logger.info("configuring Kafka consumer {} for bootstrap servers {}", hostname, kafkaBrokers); + + Map properties = new HashMap<>(); + properties.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, kafkaBrokers); + properties.put(ConsumerConfig.CLIENT_ID_CONFIG, hostname); + properties.put(ConsumerConfig.GROUP_ID_CONFIG, hostname); + properties.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class.getName()); + properties.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class.getName()); + + // These should be added when kafka auth is enabled +// properties.put("sasl.jaas.config", "org.apache.kafka.common.security.plain.PlainLoginModule required username=\"admin\" password=\"admin\""); +// properties.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer"); +// properties.put("security.protocol", "SASL_PLAINTEXT"); + + return properties; + } + + public static String buildKafkaClientId(Logger logger) { + String clientId; + try { + clientId = InetAddress.getLocalHost().getHostName(); + } catch (UnknownHostException e) { + logger.error("failed to resolve local hostname, picking random clientId"); + clientId = UUID.randomUUID().toString(); + } + logger.info("using Kafka client id {}", clientId); + return clientId; + } +} diff --git a/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/config/TransferTransformerConfig.java b/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/config/TransferTransformerConfig.java new file mode 100644 index 000000000..3db3144c6 --- /dev/null +++ b/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/config/TransferTransformerConfig.java @@ -0,0 +1,52 @@ +package hu.dpc.phee.operator.config; + +import jakarta.annotation.PostConstruct; +import lombok.Data; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Configuration; + +import java.util.List; +import java.util.Optional; + +@EnableConfigurationProperties +@Configuration +@ConfigurationProperties(prefix = "transfer") +@Data +public class TransferTransformerConfig { + private Logger logger = LoggerFactory.getLogger(this.getClass()); + + @PostConstruct + public void setup() { + if (flows == null) { + throw new RuntimeException("Invalid configuration, no Transfer transformers configured"); + } + logger.info("Loaded Transfer transformers for {} flows from configuration", flows.size()); + } + + private List flows; + + @Data + public static class Flow { + private String name; + private String direction; + private String type; + private List transformers; + + } + + @Data + public static class Transformer { + private String field; + private String variableName; + private String jsonPath; + private String constant; + private String xpath; + } + + public Optional findFlow(String name) { + return flows.stream().filter(flow -> name.equalsIgnoreCase(flow.getName())).findAny(); + } +} diff --git a/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/entity/analytics/EventTimestamps.java b/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/entity/analytics/EventTimestamps.java new file mode 100644 index 000000000..c179b3faf --- /dev/null +++ b/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/entity/analytics/EventTimestamps.java @@ -0,0 +1,38 @@ +package hu.dpc.phee.operator.entity.analytics; + +import lombok.Getter; +import lombok.Setter; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.Table; + +@Entity +@Table(name = "event_timestamps") +@Getter +@Setter +public class EventTimestamps { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "ID") + private Long id; + + @Column(name = "WORKFLOW_INSTANCE_KEY") + private Long workflowInstanceKey; + + @Column(name = "TRANSACTION_ID") + private String transactionId; + + @Column(name = "EXPORTED_TIME") + private String exportedTime; + + @Column(name = "IMPORTED_TIME") + private String importedTime; + + @Column(name = "ZEEBE_TIME") + private String ZeebeTime; + +} diff --git a/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/entity/analytics/EventTimestampsRepository.java b/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/entity/analytics/EventTimestampsRepository.java new file mode 100644 index 000000000..8924db300 --- /dev/null +++ b/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/entity/analytics/EventTimestampsRepository.java @@ -0,0 +1,8 @@ +package hu.dpc.phee.operator.entity.analytics; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; + +public interface EventTimestampsRepository extends JpaRepository, JpaSpecificationExecutor { + +} diff --git a/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/entity/batch/Batch.java b/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/entity/batch/Batch.java new file mode 100644 index 000000000..27cbad7b5 --- /dev/null +++ b/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/entity/batch/Batch.java @@ -0,0 +1,101 @@ +package hu.dpc.phee.operator.entity.batch; + +import hu.dpc.phee.operator.entity.parent.AbstractPersistableCustom; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.Table; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import org.eclipse.persistence.annotations.Index; +import java.util.Date; + +@Entity +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +@Table(name = "batches") +public class Batch extends AbstractPersistableCustom { + + @Column(name = "BATCH_ID") + private String batchId; + + @Column(name = "SUB_BATCH_ID") + private String subBatchId; + + @Column(name = "REQUEST_ID") + private String requestId; + + @Column(name = "REQUEST_FILE") + private String requestFile; + + @Column(name = "TOTAL_TRANSACTIONS") + private Long totalTransactions; + + @Column(name = "ONGOING") + private Long ongoing; + + @Column(name = "FAILED") + private Long failed; + + @Column(name = "COMPLETED") + private Long completed; + + @Column(name = "TOTAL_AMOUNT") + private Long totalAmount; + + @Column(name = "ONGOING_AMOUNT") + private Long ongoingAmount; + + @Column(name = "FAILED_AMOUNT") + private Long failedAmount; + + @Column(name = "COMPLETED_AMOUNT") + private Long completedAmount; + + @Column(name = "RESULT_FILE") + private String resultFile; + + @Column(name = "RESULT_GENERATED_AT") + private Date resultGeneratedAt; + + @Column(name = "NOTE") + private String note; + + @Column(name = "WORKFLOW_KEY") + private Long workflowKey; + + @Column(name = "WORKFLOW_INSTANCE_KEY") + @Index(name = "idx_batches_key") + private Long workflowInstanceKey; + + @Column(name = "STARTED_AT") + private Date startedAt; + + @Column(name = "COMPLETED_AT") + private Date completedAt; + + @Column(name = "PAYMENT_MODE") + private String paymentMode; + + @Column(name = "REGISTERING_INSTITUTION_ID") + private String registeringInstitutionId; + + @Column(name = "PAYER_FSP") + private String payerFsp; + + @Column(name = "CLIENT_CORRELATION_ID") + private String correlationId; + + @Column(name = "APPROVED_AMOUNT") + private Long approvedAmount; + + @Column(name = "APPROVED_COUNT") + private Long approvedCount; + + public Batch(Long workflowInstanceKey) { + this.workflowInstanceKey = workflowInstanceKey; + } +} diff --git a/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/entity/batch/BatchRepository.java b/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/entity/batch/BatchRepository.java new file mode 100644 index 000000000..c824178ff --- /dev/null +++ b/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/entity/batch/BatchRepository.java @@ -0,0 +1,14 @@ +package hu.dpc.phee.operator.entity.batch; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; + +import java.util.Optional; + +public interface BatchRepository extends JpaRepository, JpaSpecificationExecutor { + + Optional findByWorkflowInstanceKey(Long workflowInstanceKey); + Optional findByBatchId(String batchId); + Optional findBySubBatchId(String subBatchId); + Optional findByBatchIdAndSubBatchIdIsNull(String batchId); +} diff --git a/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/entity/batch/CsvSchema.java b/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/entity/batch/CsvSchema.java new file mode 100644 index 000000000..75143e4ce --- /dev/null +++ b/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/entity/batch/CsvSchema.java @@ -0,0 +1,9 @@ +package hu.dpc.phee.operator.entity.batch; + +public interface CsvSchema { + + String getCsvString(); + + String getCsvHeader(); + +} diff --git a/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/entity/batch/Transaction.java b/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/entity/batch/Transaction.java new file mode 100644 index 000000000..d12c11dde --- /dev/null +++ b/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/entity/batch/Transaction.java @@ -0,0 +1,202 @@ +package hu.dpc.phee.operator.entity.batch; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; + +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonPropertyOrder({ "id", "request_id", "payment_mode", "account_number", "payer_identifier_type", "payer_identifier", + "payee_identifier_type", "payee_identifier", "amount", "currency", "note", "program_shortcode", "cycle" , "batch_id"}) +public class Transaction implements CsvSchema { + + @JsonProperty("id") + private int id; + + @JsonProperty("request_id") + private String requestId; + + @JsonProperty("payment_mode") + private String paymentMode; + + @JsonProperty("account_number") + private String accountNumber; + + @JsonProperty("amount") + private String amount; + + @JsonProperty("currency") + private String currency; + + @JsonProperty("note") + private String note; + + @JsonProperty(value = "payer_identifier_type") + private String payerIdentifierType; + + @JsonProperty("payer_identifier") + private String payerIdentifier; + + @JsonProperty("payee_identifier_type") + private String payeeIdentifierType; + + @JsonProperty("payee_identifier") + private String payeeIdentifier; + + @JsonProperty("program_shortcode") + private String programShortCode; + + @JsonProperty("cycle") + private String cycle; + + @JsonProperty("batch_id") + private String batchId; + + @JsonIgnore + private String status; + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getRequestId() { + return requestId; + } + + public void setRequestId(String requestId) { + this.requestId = requestId; + } + + public String getPaymentMode() { + return paymentMode; + } + + public void setPaymentMode(String paymentMode) { + this.paymentMode = paymentMode; + } + + public String getAccountNumber() { + return accountNumber; + } + + public void setAccountNumber(String accountNumber) { + this.accountNumber = accountNumber; + } + + public String getAmount() { + return amount; + } + + public void setAmount(String amount) { + this.amount = amount; + } + + public String getCurrency() { + return currency; + } + + public void setCurrency(String currency) { + this.currency = currency; + } + + public String getNote() { + return note; + } + + public void setNote(String note) { + this.note = note; + } + + public String getBatchId() { + return batchId; + } + + public void setBatchId(String batchId) { + this.batchId = batchId; + } + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } + + public String getPayerIdentifierType() { + return payerIdentifierType; + } + + public void setPayerIdentifierType(String payerIdentifierType) { + this.payerIdentifierType = payerIdentifierType; + } + + public String getPayerIdentifier() { + return payerIdentifier; + } + + public void setPayerIdentifier(String payerIdentifier) { + this.payerIdentifier = payerIdentifier; + } + + public String getPayeeIdentifierType() { + return payeeIdentifierType; + } + + public void setPayeeIdentifierType(String payeeIdentifierType) { + this.payeeIdentifierType = payeeIdentifierType; + } + + public String getPayeeIdentifier() { + return payeeIdentifier; + } + + public void setPayeeIdentifier(String payeeIdentifier) { + this.payeeIdentifier = payeeIdentifier; + } + + public String getProgramShortCode() { + return programShortCode; + } + + public void setProgramShortCode(String programShortCode) { + this.programShortCode = programShortCode; + } + + public String getCycle() { + return cycle; + } + + public void setCycle(String cycle) { + this.cycle = cycle; + } + + @Override + public String toString() { + return "Transaction{" + "id=" + id + ", request_id='" + requestId + '\'' + ", payment_mode='" + paymentMode + '\'' + + ", account_number='" + accountNumber + '\'' + ", amount='" + amount + '\'' + ", currency='" + currency + '\'' + ", note='" + + note + '\'' + ", batchId='" + batchId + '\'' + ", status='" + status + '\'' + '}'; + } + + @JsonIgnore + @Override + public String getCsvString() { + if (status == null || !status.isEmpty()) { + return String.format("%s,%s,%s,%s,%s,%s,%s", id, requestId, paymentMode, accountNumber, amount, currency, note); + } + return String.format("%s,%s,%s,%s,%s,%s,%s,%s", id, requestId, paymentMode, accountNumber, amount, currency, note, status); + } + + @JsonIgnore + @Override + public String getCsvHeader() { + if (status.isEmpty()) { + return "id,request_id,payment_mode,account_number,amount,currency,note"; + } + return "id,request_id,payment_mode,account_number,amount,currency,note,status"; + } +} diff --git a/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/entity/businesskey/BusinessKey.java b/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/entity/businesskey/BusinessKey.java new file mode 100644 index 000000000..ba811cefd --- /dev/null +++ b/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/entity/businesskey/BusinessKey.java @@ -0,0 +1,59 @@ +package hu.dpc.phee.operator.entity.businesskey; + +import hu.dpc.phee.operator.entity.parent.AbstractPersistableCustom; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.Table; +import org.eclipse.persistence.annotations.Index; + +@Entity +@Table(name = "businesskeys") +public class BusinessKey extends AbstractPersistableCustom { + + @Column(name = "BUSINESS_KEY") + @Index(name = "idx_businessKey") + private String businessKey; + + @Column(name = "BUSINESS_KEY_TYPE") + @Index(name = "idx_businessKeyType") + private String businessKeyType; + + @Column(name = "WORKFLOW_INSTANCE_KEY") + @Index(name = "idx_workflowInstanceKey") + private Long workflowInstanceKey; + + @Column(name = "TIMESTAMP") + private Long timestamp; + + public String getBusinessKeyType() { + return businessKeyType; + } + + public void setBusinessKeyType(String businessKeyType) { + this.businessKeyType = businessKeyType; + } + + public Long getWorkflowInstanceKey() { + return workflowInstanceKey; + } + + public void setWorkflowInstanceKey(Long workflowInstanceKey) { + this.workflowInstanceKey = workflowInstanceKey; + } + + public Long getTimestamp() { + return timestamp; + } + + public void setTimestamp(Long timestamp) { + this.timestamp = timestamp; + } + + public String getBusinessKey() { + return businessKey; + } + + public void setBusinessKey(String transactionId) { + this.businessKey = transactionId; + } +} diff --git a/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/entity/businesskey/BusinessKeyRepository.java b/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/entity/businesskey/BusinessKeyRepository.java new file mode 100644 index 000000000..abc1ddd6b --- /dev/null +++ b/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/entity/businesskey/BusinessKeyRepository.java @@ -0,0 +1,11 @@ +package hu.dpc.phee.operator.entity.businesskey; + +import org.springframework.data.repository.CrudRepository; + +import java.util.List; + +public interface BusinessKeyRepository extends CrudRepository { + + List findByBusinessKeyAndBusinessKeyType(String businessKey, String businessKeyType); + +} diff --git a/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/entity/outboundmessages/OutboudMessages.java b/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/entity/outboundmessages/OutboudMessages.java new file mode 100644 index 000000000..c5995e94d --- /dev/null +++ b/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/entity/outboundmessages/OutboudMessages.java @@ -0,0 +1,162 @@ +package hu.dpc.phee.operator.entity.outboundmessages; + +import hu.dpc.phee.operator.entity.parent.AbstractPersistableCustom; + +import hu.dpc.phee.operator.entity.transfer.TransferStatus; +import hu.dpc.phee.operator.util.SmsMessageStatusType; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.Table; +import jakarta.persistence.Temporal; +import jakarta.persistence.TemporalType; +import lombok.Data; + +import java.util.Date; + +@Entity +@Table(name = "m_outbound_messages") +public class OutboudMessages extends AbstractPersistableCustom { + @com.fasterxml.jackson.annotation.JsonIgnore + @Column(name = "tenant_id", nullable = false) + private Long tenantId; + + @Column(name = "external_id", nullable = true) + private String externalId; + + @Column(name = "internal_id", nullable = false) + private Long internalId; + + @Column(name = "submitted_on_date", nullable = true) + @Temporal(TemporalType.DATE) + private Date submittedOnDate; + + @Column(name = "delivered_on_date", nullable = true) + @Temporal(TemporalType.TIMESTAMP) + private Date deliveredOnDate; + + @Column(name = "delivery_status", nullable = false) + private Integer deliveryStatus = SmsMessageStatusType.PENDING.getValue(); + + @Column(name = "delivery_error_message", nullable = true) + private String deliveryErrorMessage; + + @Column(name = "source_address", nullable = true) + private String sourceAddress; + + @Column(name = "mobile_number", nullable = false) + private String mobileNumber; + + @Column(name = "message", nullable = false) + private String message; + + @Column(name = "sms_bridge_id", nullable = false) + private Long bridgeId; + + public OutboudMessages() { + } + + public OutboudMessages(Long workflowInstanceKey) { + this.internalId = workflowInstanceKey; + this.deliveryStatus = SmsMessageStatusType.PENDING.getValue(); + } + + public Long getTenantId() { + return tenantId; + } + + public void setTenantId(Long tenantId) { + this.tenantId = tenantId; + } + + public String getExternalId() { + return externalId; + } + + public void setExternalId(String externalId) { + this.externalId = externalId; + } + + public Long getInternalId() { + return internalId; + } + + public void setInternalId(Long internalId) { + this.internalId = internalId; + } + + public Date getSubmittedOnDate() { + return submittedOnDate; + } + + public void setSubmittedOnDate(Date submittedOnDate) { + this.submittedOnDate = submittedOnDate; + } + + public Date getDeliveredOnDate() { + return deliveredOnDate; + } + + public void setDeliveredOnDate(Date deliveredOnDate) { + this.deliveredOnDate = deliveredOnDate; + } + + public Integer getDeliveryStatus() { + return deliveryStatus; + } + + public void setDeliveryStatus(Integer deliveryStatus) { + this.deliveryStatus = deliveryStatus; + } + + public String getDeliveryErrorMessage() { + return deliveryErrorMessage; + } + + public void setDeliveryErrorMessage(String deliveryErrorMessage) { + this.deliveryErrorMessage = deliveryErrorMessage; + } + + public String getSourceAddress() { + return sourceAddress; + } + + public void setSourceAddress(String sourceAddress) { + this.sourceAddress = sourceAddress; + } + + public String getMobileNumber() { + return mobileNumber; + } + + public void setMobileNumber(String mobileNumber) { + this.mobileNumber = mobileNumber; + } + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } + + public Long getBridgeId() { + return bridgeId; + } + + public void setBridgeId(Long bridgeId) { + this.bridgeId = bridgeId; + } + + public String getResponse() { + return response; + } + + public void setResponse(String response) { + this.response = response; + } + + @Column(name = "response") + private String response; + +} diff --git a/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/entity/outboundmessages/OutboundMessagesRepository.java b/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/entity/outboundmessages/OutboundMessagesRepository.java new file mode 100644 index 000000000..eba2b4f74 --- /dev/null +++ b/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/entity/outboundmessages/OutboundMessagesRepository.java @@ -0,0 +1,7 @@ +package hu.dpc.phee.operator.entity.outboundmessages; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; + +public interface OutboundMessagesRepository extends JpaRepository, JpaSpecificationExecutor { + OutboudMessages findByInternalId(Long internalId); +} diff --git a/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/entity/parent/AbstractPersistableCustom.java b/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/entity/parent/AbstractPersistableCustom.java new file mode 100644 index 000000000..bf9090fa8 --- /dev/null +++ b/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/entity/parent/AbstractPersistableCustom.java @@ -0,0 +1,50 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package hu.dpc.phee.operator.entity.parent; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import jakarta.persistence.*; +import org.springframework.data.domain.Persistable; + +import java.io.Serializable; + + +@MappedSuperclass +public abstract class AbstractPersistableCustom implements Persistable { + + @Id + @Column(name = "ID") + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @Override + public Long getId() { + return id; + } + + public void setId(final Long id) { + this.id = id; + } + + @Override + @JsonIgnore + public boolean isNew() { + return null == this.id; + } +} diff --git a/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/entity/task/Task.java b/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/entity/task/Task.java new file mode 100644 index 000000000..e393fed55 --- /dev/null +++ b/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/entity/task/Task.java @@ -0,0 +1,37 @@ +package hu.dpc.phee.operator.entity.task; + + +import hu.dpc.phee.operator.entity.parent.AbstractPersistableCustom; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.Table; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.With; + +@Entity +@Table(name = "tasks") +@Data +@With +@NoArgsConstructor +@AllArgsConstructor +public class Task extends AbstractPersistableCustom { + + @Column(name = "WORKFLOW_KEY") + private Long workflowKey; + @Id + @Column(name = "WORKFLOW_INSTANCE_KEY") + private Long workflowInstanceKey; + @Column(name = "TIMESTAMP") + private Long timestamp; + @Column(name = "INTENT") + private String intent; + @Column(name = "RECORD_TYPE") + private String recordType; + @Column(name = "TYPE") + private String type; + @Column(name = "ELEMENT_ID") + private String elementId; +} diff --git a/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/entity/task/TaskRepository.java b/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/entity/task/TaskRepository.java new file mode 100644 index 000000000..0bf4ef287 --- /dev/null +++ b/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/entity/task/TaskRepository.java @@ -0,0 +1,11 @@ +package hu.dpc.phee.operator.entity.task; + +import org.springframework.data.repository.CrudRepository; + +import java.util.List; + +public interface TaskRepository extends CrudRepository { + + List findByWorkflowInstanceKey(Long workflowInstanceKey); + +} diff --git a/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/entity/tenant/DataSourcePerTenantService.java b/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/entity/tenant/DataSourcePerTenantService.java new file mode 100644 index 000000000..0038bc62c --- /dev/null +++ b/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/entity/tenant/DataSourcePerTenantService.java @@ -0,0 +1,56 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package hu.dpc.phee.operator.entity.tenant; + +import com.zaxxer.hikari.HikariDataSource; +import hu.dpc.phee.operator.tenants.TenantsService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.DisposableBean; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import javax.sql.DataSource; +import java.util.HashMap; +import java.util.Map; + + +@Service +public class DataSourcePerTenantService implements DisposableBean { + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + private final Map tenantToDataSourceMap = new HashMap<>(); + + @Autowired + TenantsService tenantsService; + + + public DataSource retrieveDataSource() { + DataSource threadLocalDatasource = ThreadLocalContextUtil.getTenant(); + return threadLocalDatasource != null ? threadLocalDatasource : tenantsService.getAnyDataSource(); + } + + @Override + public void destroy() { + for (Map.Entry entry : this.tenantToDataSourceMap.entrySet()) { + HikariDataSource ds = (HikariDataSource) entry.getValue(); + ds.close(); + logger.info("Datasource closed: {}", ds.getPoolName()); + } + } +} diff --git a/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/entity/tenant/RoutingDataSource.java b/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/entity/tenant/RoutingDataSource.java new file mode 100644 index 000000000..b50245426 --- /dev/null +++ b/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/entity/tenant/RoutingDataSource.java @@ -0,0 +1,45 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package hu.dpc.phee.operator.entity.tenant; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.jdbc.datasource.AbstractDataSource; +import org.springframework.stereotype.Component; + +import java.sql.Connection; +import java.sql.SQLException; + + +@Component +public class RoutingDataSource extends AbstractDataSource { + + @Autowired + private DataSourcePerTenantService dataSourcePerTenantService; + + @Override + public Connection getConnection() throws SQLException { + return dataSourcePerTenantService.retrieveDataSource().getConnection(); + } + + @Override + public Connection getConnection(final String username, final String password) throws SQLException { + return dataSourcePerTenantService.retrieveDataSource().getConnection(username, password); + } + +} diff --git a/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/entity/tenant/ThreadLocalContextUtil.java b/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/entity/tenant/ThreadLocalContextUtil.java new file mode 100644 index 000000000..8ab34b1c1 --- /dev/null +++ b/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/entity/tenant/ThreadLocalContextUtil.java @@ -0,0 +1,49 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package hu.dpc.phee.operator.entity.tenant; + +import org.springframework.util.Assert; + +import javax.sql.DataSource; + +public class ThreadLocalContextUtil { + + private static final ThreadLocal tenantcontext = new ThreadLocal<>(); + private static String tenantName; + public static void setTenant(final DataSource dataSource) { + Assert.notNull(dataSource, "tenant dataSource cannot be null"); + tenantcontext.set(dataSource); + } + + public static DataSource getTenant() { + return tenantcontext.get(); + } + + public static void clear() { + tenantcontext.remove(); + } + + public static String getTenantName() { + return tenantName; + } + + public static void setTenantName(String tenantName) { + ThreadLocalContextUtil.tenantName = tenantName; + } +} \ No newline at end of file diff --git a/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/entity/transactionrequest/TransactionRequest.java b/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/entity/transactionrequest/TransactionRequest.java new file mode 100644 index 000000000..a962b865e --- /dev/null +++ b/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/entity/transactionrequest/TransactionRequest.java @@ -0,0 +1,282 @@ +package hu.dpc.phee.operator.entity.transactionrequest; + +import hu.dpc.phee.operator.entity.parent.AbstractPersistableCustom; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.EnumType; +import jakarta.persistence.Enumerated; +import jakarta.persistence.Table; + +import java.math.BigDecimal; +import java.util.Date; + +import static hu.dpc.phee.operator.entity.transactionrequest.TransactionRequestState.IN_PROGRESS; + +@Entity +@Table(name = "transaction_requests") +public class TransactionRequest extends AbstractPersistableCustom { + + @Column(name = "WORKFLOW_INSTANCE_KEY") + private Long workflowInstanceKey; + + @Column(name = "TRANSACTION_ID") + private String transactionId; + + @Column(name = "STARTED_AT") + private Date startedAt; + + @Column(name = "COMPLETED_AT") + private Date completedAt; + + @Enumerated(EnumType.STRING) + @Column(name = "STATE") + private TransactionRequestState state; + + @Column(name = "PAYEE_DFSP_ID") + private String payeeDfspId; + @Column(name = "PAYEE_PARTY_ID") + private String payeePartyId; + @Column(name = "PAYEE_PARTY_ID_TYPE") + private String payeePartyIdType; + @Column(name = "PAYEE_FEE") + private BigDecimal payeeFee; + @Column(name = "PAYEE_QUOTE_CODE") + private String payeeQuoteCode; + + @Column(name = "PAYER_DFSP_ID") + private String payerDfspId; + @Column(name = "PAYER_PARTY_ID") + private String payerPartyId; + @Column(name = "PAYER_PARTY_ID_TYPE") + private String payerPartyIdType; + @Column(name = "PAYER_FEE") + private BigDecimal payerFee; + @Column(name = "PAYER_QUOTE_CODE") + private String payerQuoteCode; + + @Column(name = "AMOUNT") + private BigDecimal amount; + + @Column(name = "CURRENCY") + private String currency; + + @Column(name = "DIRECTION") + private String direction; + + @Column(name = "AUTH_TYPE") + private String authType; + + @Column(name = "INITIATOR_TYPE") + private String initiatorType; + + @Column(name = "SCENARIO") + private String scenario; + + @Column(name = "EXTERNAL_ID") + private String externalId; + + @Column(name = "CLIENTCORRELATIONID") + private String clientCorrelationId; + + @Column(name = "ERROR_INFORMATION") + private String errorInformation; + + public TransactionRequest() {} + + public String getExternalId() { + return externalId; + } + + public void setExternalId(String externalId) { + this.externalId = externalId; + } + + public TransactionRequest(Long workflowInstanceKey) { + this.workflowInstanceKey = workflowInstanceKey; + this.state = IN_PROGRESS; + } + + public Long getWorkflowInstanceKey() { + return workflowInstanceKey; + } + + public void setWorkflowInstanceKey(Long workflowInstanceKey) { + this.workflowInstanceKey = workflowInstanceKey; + } + + public String getTransactionId() { + return transactionId; + } + + public void setTransactionId(String transactionId) { + this.transactionId = transactionId; + } + + public Date getStartedAt() { + return startedAt; + } + + public void setStartedAt(Date startedAt) { + this.startedAt = startedAt; + } + + public Date getCompletedAt() { + return completedAt; + } + + public void setCompletedAt(Date completedAt) { + this.completedAt = completedAt; + } + + public TransactionRequestState getState() { + return state; + } + + public void setState(TransactionRequestState state) { + this.state = state; + } + + public String getPayeeDfspId() { + return payeeDfspId; + } + + public void setPayeeDfspId(String payeeDfspId) { + this.payeeDfspId = payeeDfspId; + } + + public String getPayeePartyId() { + return payeePartyId; + } + + public void setPayeePartyId(String payeePartyId) { + this.payeePartyId = payeePartyId; + } + + public String getPayeePartyIdType() { + return payeePartyIdType; + } + + public void setPayeePartyIdType(String payeePartyIdType) { + this.payeePartyIdType = payeePartyIdType; + } + + public BigDecimal getPayeeFee() { + return payeeFee; + } + + public void setPayeeFee(BigDecimal payeeFee) { + this.payeeFee = payeeFee; + } + + public String getPayeeQuoteCode() { + return payeeQuoteCode; + } + + public void setPayeeQuoteCode(String payeeQuoteCode) { + this.payeeQuoteCode = payeeQuoteCode; + } + + public String getPayerDfspId() { + return payerDfspId; + } + + public void setPayerDfspId(String payerDfspId) { + this.payerDfspId = payerDfspId; + } + + public String getPayerPartyId() { + return payerPartyId; + } + + public void setPayerPartyId(String payerPartyId) { + this.payerPartyId = payerPartyId; + } + + public String getPayerPartyIdType() { + return payerPartyIdType; + } + + public void setPayerPartyIdType(String payerPartyIdType) { + this.payerPartyIdType = payerPartyIdType; + } + + public BigDecimal getPayerFee() { + return payerFee; + } + + public void setPayerFee(BigDecimal payerFee) { + this.payerFee = payerFee; + } + + public String getPayerQuoteCode() { + return payerQuoteCode; + } + + public void setPayerQuoteCode(String payerQuoteCode) { + this.payerQuoteCode = payerQuoteCode; + } + + public BigDecimal getAmount() { + return amount; + } + + public void setAmount(BigDecimal amount) { + this.amount = amount; + } + + public String getCurrency() { + return currency; + } + + public void setCurrency(String currency) { + this.currency = currency; + } + + public String getDirection() { + return direction; + } + + public void setDirection(String direction) { + this.direction = direction; + } + + public String getAuthType() { + return authType; + } + + public void setAuthType(String authType) { + this.authType = authType; + } + + public String getInitiatorType() { + return initiatorType; + } + + public void setInitiatorType(String initiatorType) { + this.initiatorType = initiatorType; + } + + public String getScenario() { + return scenario; + } + + public void setScenario(String scenario) { + this.scenario = scenario; + } + + public void setClientCorrelationId(String clientCorrelationId) { + this.clientCorrelationId = clientCorrelationId; + } + + public String getClientCorrelationId() { + return clientCorrelationId; + } + + public String getErrorInformation() { + return errorInformation; + } + + public void setErrorInformation(String errorInformation) { + this.errorInformation = errorInformation; + } +} diff --git a/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/entity/transactionrequest/TransactionRequestRepository.java b/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/entity/transactionrequest/TransactionRequestRepository.java new file mode 100644 index 000000000..7d6fe4669 --- /dev/null +++ b/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/entity/transactionrequest/TransactionRequestRepository.java @@ -0,0 +1,9 @@ +package hu.dpc.phee.operator.entity.transactionrequest; + +import org.springframework.data.repository.CrudRepository; + +public interface TransactionRequestRepository extends CrudRepository { + + TransactionRequest findByWorkflowInstanceKey(Long workflowInstanceKey); + +} diff --git a/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/entity/transactionrequest/TransactionRequestState.java b/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/entity/transactionrequest/TransactionRequestState.java new file mode 100644 index 000000000..9364bd15c --- /dev/null +++ b/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/entity/transactionrequest/TransactionRequestState.java @@ -0,0 +1,6 @@ +package hu.dpc.phee.operator.entity.transactionrequest; + +public enum TransactionRequestState { + + INITIATED, IN_PROGRESS, RECEIVED, REQUEST_ACCEPTED, ACCEPTED, REJECTED, FAILED, SUCCESS; +} diff --git a/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/entity/transfer/Transfer.java b/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/entity/transfer/Transfer.java new file mode 100644 index 000000000..dd5c4e3aa --- /dev/null +++ b/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/entity/transfer/Transfer.java @@ -0,0 +1,97 @@ +package hu.dpc.phee.operator.entity.transfer; + + +import jakarta.annotation.Nullable; +import jakarta.persistence.*; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.With; + +import java.math.BigDecimal; +import java.util.Date; + +@Entity +@Table(name = "transfers") +@Cacheable(false) +@Data +@With +@NoArgsConstructor +@AllArgsConstructor +public class Transfer { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "ID") + private Long id; + + @Column(name = "WORKFLOW_INSTANCE_KEY") + private Long workflowInstanceKey; + + @Column(name = "TRANSACTION_ID") + private String transactionId; + + @Column(name = "STARTED_AT") + private Date startedAt; + @Column(name = "COMPLETED_AT") + private Date completedAt; + + @Enumerated(EnumType.STRING) + @Column(name = "status") + private TransferStatus status; + + @Column(name = "STATUS_DETAIL") + private String statusDetail; + + @Column(name = "PAYEE_DFSP_ID") + private String payeeDfspId; + @Column(name = "PAYEE_PARTY_ID") + private String payeePartyId; + @Column(name = "PAYEE_PARTY_ID_TYPE") + private String payeePartyIdType; + @Column(name = "PAYEE_FEE") + private BigDecimal payeeFee; + @Column(name = "PAYEE_FEE_CURRENCY") + private String payeeFeeCurrency; + @Column(name = "PAYEE_QUOTE_CODE") + private String payeeQuoteCode; + + @Column(name = "PAYER_DFSP_ID") + private String payerDfspId; + @Column(name = "PAYER_PARTY_ID") + private String payerPartyId; + @Column(name = "PAYER_PARTY_ID_TYPE") + private String payerPartyIdType; + @Column(name = "PAYER_FEE") + private BigDecimal payerFee; + @Column(name = "PAYER_FEE_CURRENCY") + private String payerFeeCurrency; + @Column(name = "PAYER_QUOTE_CODE") + private String payerQuoteCode; + + @Column(name = "amount") + private BigDecimal amount; + + @Column(name = "currency") + private String currency; + + @Column(name = "direction") + private String direction; + + @Column(name = "error_information") + private String errorInformation; + + @Column(name = "BATCH_ID") + private String batchId; + + @Column(name = "CLIENTCORRELATIONID") + private String clientCorrelationId; + @Transient + private String tenantId; + + + public Transfer(Long workflowInstanceKey) { + this.workflowInstanceKey = workflowInstanceKey; + this.status = TransferStatus.IN_PROGRESS; + } +} diff --git a/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/entity/transfer/TransferDetail.java b/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/entity/transfer/TransferDetail.java new file mode 100644 index 000000000..5c6977645 --- /dev/null +++ b/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/entity/transfer/TransferDetail.java @@ -0,0 +1,43 @@ +package hu.dpc.phee.operator.entity.transfer; + +import hu.dpc.phee.operator.entity.task.Task; +import hu.dpc.phee.operator.entity.variable.Variable; + +import java.util.List; + + +public class TransferDetail { + private Transfer transfer; + private List tasks; + private List variables; + + public TransferDetail(Transfer transfer, List tasks, List variables) { + this.transfer = transfer; + this.tasks = tasks; + this.variables = variables; + } + + public Transfer getTransfer() { + return transfer; + } + + public void setTransfer(Transfer transfer) { + this.transfer = transfer; + } + + public List getTasks() { + return tasks; + } + + public void setTasks(List tasks) { + this.tasks = tasks; + } + + public List getVariables() { + return variables; + } + + public void setVariables(List variables) { + this.variables = variables; + } +} diff --git a/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/entity/transfer/TransferRepository.java b/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/entity/transfer/TransferRepository.java new file mode 100644 index 000000000..004307840 --- /dev/null +++ b/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/entity/transfer/TransferRepository.java @@ -0,0 +1,11 @@ +package hu.dpc.phee.operator.entity.transfer; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; +import java.util.Optional; + +public interface TransferRepository extends JpaRepository, JpaSpecificationExecutor { + + Optional findByWorkflowInstanceKey(Long workflowInstanceKey); + Optional findByTransactionIdAndBatchId(String transactionId, String batchId); +} diff --git a/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/entity/transfer/TransferSpecs.java b/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/entity/transfer/TransferSpecs.java new file mode 100644 index 000000000..287b3ce78 --- /dev/null +++ b/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/entity/transfer/TransferSpecs.java @@ -0,0 +1,30 @@ +package hu.dpc.phee.operator.entity.transfer; + +import jakarta.persistence.metamodel.SingularAttribute; +import org.springframework.data.jpa.domain.Specification; + +import java.util.Date; + +public class TransferSpecs { + + public static Specification between(SingularAttribute attribute, Date from, Date to) { + return (root, query, builder) -> + builder.and( + builder.greaterThanOrEqualTo(root.get(attribute), from), + builder.lessThanOrEqualTo(root.get(attribute), to) + ); + } + + public static Specification later(SingularAttribute attribute, Date from) { + return (root, query, builder) -> builder.greaterThanOrEqualTo(root.get(attribute), from); + } + + public static Specification earlier(SingularAttribute attribute, Date to) { + return (root, query, builder) -> builder.lessThanOrEqualTo(root.get(attribute), to); + } + + + public static Specification match(SingularAttribute attribute, T input) { + return (root, query, builder) -> builder.equal(root.get(attribute), input); + } +} diff --git a/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/entity/transfer/TransferStatus.java b/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/entity/transfer/TransferStatus.java new file mode 100644 index 000000000..5fcfa8825 --- /dev/null +++ b/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/entity/transfer/TransferStatus.java @@ -0,0 +1,10 @@ +package hu.dpc.phee.operator.entity.transfer; + +public enum TransferStatus { + + COMPLETED, + FAILED, + EXCEPTION, + IN_PROGRESS, + UNKNOWN +} diff --git a/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/entity/variable/Variable.java b/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/entity/variable/Variable.java new file mode 100644 index 000000000..d0e79f5ea --- /dev/null +++ b/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/entity/variable/Variable.java @@ -0,0 +1,40 @@ +package hu.dpc.phee.operator.entity.variable; + + +import hu.dpc.phee.operator.entity.parent.AbstractPersistableCustom; +import jakarta.persistence.*; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.With; +import org.eclipse.persistence.annotations.Index; + +@Entity +@IdClass(VariableId.class) +@Table(name = "variables") +@Cacheable(false) +@Data +@With +@NoArgsConstructor +@AllArgsConstructor +public class Variable { + + @Id + @Column(name = "WORKFLOW_INSTANCE_KEY") + private Long workflowInstanceKey; + + @Id + @Column(name = "NAME") + private String name; + + @Column(name = "WORKFLOW_KEY") + private Long workflowKey; + + @Column(name = "TIMESTAMP") + private Long timestamp; + + @Lob + @Column(name = "VALUE") + private String value; + +} diff --git a/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/entity/variable/VariableId.java b/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/entity/variable/VariableId.java new file mode 100644 index 000000000..8dbac8ae9 --- /dev/null +++ b/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/entity/variable/VariableId.java @@ -0,0 +1,19 @@ +package hu.dpc.phee.operator.entity.variable; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.With; + +import java.io.Serializable; + +@Data +@With +@NoArgsConstructor +@AllArgsConstructor +public class VariableId implements Serializable { + + private Long workflowInstanceKey; + private String name; + +} diff --git a/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/entity/variable/VariableRepository.java b/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/entity/variable/VariableRepository.java new file mode 100644 index 000000000..5eaeb9efe --- /dev/null +++ b/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/entity/variable/VariableRepository.java @@ -0,0 +1,11 @@ +package hu.dpc.phee.operator.entity.variable; + +import org.springframework.data.repository.CrudRepository; + +import java.util.List; + +public interface VariableRepository extends CrudRepository { + + List findByWorkflowInstanceKey(Long workflowInstanceKey); + +} diff --git a/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/file/AwsFileTransferImpl.java b/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/file/AwsFileTransferImpl.java new file mode 100644 index 000000000..326916fdb --- /dev/null +++ b/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/file/AwsFileTransferImpl.java @@ -0,0 +1,42 @@ +package hu.dpc.phee.operator.file; + +import com.amazonaws.services.s3.AmazonS3; +import com.amazonaws.services.s3.model.S3Object; +import com.amazonaws.services.s3.model.S3ObjectInputStream; +import com.amazonaws.util.IOUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; + +@Service +public class AwsFileTransferImpl implements FileTransferService { + + private Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Autowired + private AmazonS3 s3Client; + + @Override + public String downloadFile(String fileName, String bucketName) { + S3Object s3Object = s3Client.getObject(bucketName, fileName); + S3ObjectInputStream inputStream = s3Object.getObjectContent(); + try { + byte[] content = IOUtils.toByteArray(inputStream); + File file = new File(fileName); + try (FileOutputStream fos = new FileOutputStream(file)) { + fos.write(content); + } + logger.debug("File {} downloaded at path {}", fileName, file.getAbsolutePath()); + return file.getAbsolutePath(); + } catch (IOException e) { + logger.debug(e.getMessage()); + } + return null; + } + +} diff --git a/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/file/CsvFileService.java b/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/file/CsvFileService.java new file mode 100644 index 000000000..19d28edef --- /dev/null +++ b/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/file/CsvFileService.java @@ -0,0 +1,44 @@ +package hu.dpc.phee.operator.file; + +import com.fasterxml.jackson.databind.MappingIterator; +import com.fasterxml.jackson.dataformat.csv.CsvMapper; +import com.fasterxml.jackson.dataformat.csv.CsvSchema; +import hu.dpc.phee.operator.entity.batch.Transaction; +import java.io.IOException; +import java.io.Reader; +import java.nio.charset.Charset; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.List; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component +@Slf4j +public class CsvFileService { + + @Autowired + private CsvMapper csvMapper; + + public List getTransactionList(String filename) { + List transactionList; + try { + CsvSchema schema = CsvSchema.emptySchema().withHeader(); + Reader reader = Files.newBufferedReader(Paths.get(filename), Charset.defaultCharset()); + MappingIterator readValues = csvMapper.readerWithSchemaFor(Transaction.class).with(schema).readValues(reader); + transactionList = new ArrayList<>(); + while (readValues.hasNext()) { + Transaction current = readValues.next(); + transactionList.add(current); + } + } catch (IOException e) { + log.debug(e.getMessage()); + log.error("Error building TransactionList for file: {}", filename); + return null; + } + return transactionList; + } + +} diff --git a/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/file/FileTransferService.java b/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/file/FileTransferService.java new file mode 100644 index 000000000..a12de6d74 --- /dev/null +++ b/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/file/FileTransferService.java @@ -0,0 +1,7 @@ +package hu.dpc.phee.operator.file; + +public interface FileTransferService { + + String downloadFile(String fileName, String bucketName); + +} diff --git a/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/importer/JsonPathReader.java b/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/importer/JsonPathReader.java new file mode 100644 index 000000000..506f6b710 --- /dev/null +++ b/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/importer/JsonPathReader.java @@ -0,0 +1,29 @@ +package hu.dpc.phee.operator.importer; + +import com.jayway.jsonpath.*; +import org.apache.commons.text.StringEscapeUtils; + +public class JsonPathReader { + private static ParseContext jsonParser; + + static { + Configuration config = Configuration.defaultConfiguration() + .addOptions(Option.DEFAULT_PATH_LEAF_TO_NULL) + .addOptions(Option.SUPPRESS_EXCEPTIONS); + jsonParser = JsonPath.using(config); + } + + public static DocumentContext parse(String json) { + return jsonParser.parse(json); + } + + public static DocumentContext parseEscaped(String escapedJson) { + String rawString = StringEscapeUtils.unescapeJson(strip(escapedJson)); + return jsonParser.parse(rawString); + } + + public static String strip(String str) { + return str.replaceAll("^\"|\"$", ""); + } + +} diff --git a/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/streams/InFlightTransferManager.java b/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/streams/InFlightTransferManager.java new file mode 100644 index 000000000..8fd6040e3 --- /dev/null +++ b/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/streams/InFlightTransferManager.java @@ -0,0 +1,58 @@ +package hu.dpc.phee.operator.streams; + +import com.jayway.jsonpath.DocumentContext; +import hu.dpc.phee.operator.config.TransferTransformerConfig; +import hu.dpc.phee.operator.entity.transfer.Transfer; +import hu.dpc.phee.operator.entity.transfer.TransferRepository; +import hu.dpc.phee.operator.entity.transfer.TransferStatus; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.Optional; + +@Component +public class InFlightTransferManager { + + @Autowired + TransferTransformerConfig transferTransformerConfig; + + @Autowired + TransferRepository transferRepository; + + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + public Transfer retrieveOrCreateTransfer(String bpmn, DocumentContext record, String processType) { + Long processInstanceKey = record.read("$.value.processInstanceKey", Long.class); + Optional config = transferTransformerConfig.findFlow(bpmn); + + Optional optionalTransfer = transferRepository.findByWorkflowInstanceKey(processInstanceKey); + + Transfer transfer = optionalTransfer.orElseGet(() -> { + if (!processType.equals("INCIDENT")) { + logger.debug("Creating new Transfer for processInstanceKey: {}", processInstanceKey); + Transfer newTransfer = new Transfer(processInstanceKey); + newTransfer.setStatus(TransferStatus.IN_PROGRESS); + + config.ifPresent(c -> newTransfer.setDirection(c.getDirection())); + + if (config.isEmpty()) { + logger.error("No config found for bpmn: {}", bpmn); + } + + transferRepository.save(newTransfer); + return newTransfer; + } else { + //Since no transaction found returning dummy transaction + Transfer dummy = new Transfer(0L); + dummy.setErrorInformation("404"); + return dummy; + } + }); + + optionalTransfer.ifPresent(t -> logger.debug("Found existing Transfer for processInstanceKey: {}", processInstanceKey)); + + return transfer; + } +} diff --git a/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/streams/InflightBatchManager.java b/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/streams/InflightBatchManager.java new file mode 100644 index 000000000..558e6c182 --- /dev/null +++ b/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/streams/InflightBatchManager.java @@ -0,0 +1,239 @@ +package hu.dpc.phee.operator.streams; + +import com.jayway.jsonpath.DocumentContext; +import hu.dpc.phee.operator.config.TransferTransformerConfig; +import hu.dpc.phee.operator.entity.batch.Batch; +import hu.dpc.phee.operator.entity.batch.BatchRepository; +import hu.dpc.phee.operator.entity.batch.Transaction; +import hu.dpc.phee.operator.entity.tenant.ThreadLocalContextUtil; +import hu.dpc.phee.operator.entity.transfer.Transfer; +import hu.dpc.phee.operator.entity.transfer.TransferRepository; +import hu.dpc.phee.operator.entity.transfer.TransferStatus; +import hu.dpc.phee.operator.file.CsvFileService; +import hu.dpc.phee.operator.file.FileTransferService; +import hu.dpc.phee.operator.util.BatchFormatToTransferMapper; +import hu.dpc.phee.operator.util.PaymentModeEnum; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +import java.math.BigDecimal; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.UUID; + +import static hu.dpc.phee.operator.util.OperatorUtils.strip; + +@Component +public class InflightBatchManager { + + @Autowired + BatchRepository batchRepository; + + @Autowired + TransferRepository transferRepository; + @Autowired + TransferTransformerConfig transferTransformerConfig; + + @Autowired + private FileTransferService fileTransferService; + + @Autowired + private CsvFileService csvFileService; + + @Value("${application.bucket-name}") + private String bucketName; + + private final Map workflowKeyBatchFileNameAssociations = new HashMap<>(); + + private final Map workflowKeyBatchIdAssociations = new HashMap<>(); + + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + public Batch retrieveOrCreateBatch(String bpmn, DocumentContext record) { + Long processInstanceKey = record.read("$.value.processInstanceKey", Long.class); + Optional config = transferTransformerConfig.findFlow(bpmn); + + Optional batchOptional = batchRepository.findByWorkflowInstanceKey(processInstanceKey); + if (batchOptional.isEmpty()) { + logger.debug("Creating new Batch for processInstanceKey: {}", processInstanceKey); + String batchId = getBatchId(processInstanceKey); + + if (batchId != null && batchRepository.findByBatchIdAndSubBatchIdIsNull(batchId).isEmpty()) { + Batch batch = new Batch(processInstanceKey); + batchRepository.save(batch); + return batch; + } + else if (batchId != null) { + Batch batch = batchRepository.findByBatchIdAndSubBatchIdIsNull(batchId).orElse(null); + assert batch != null; + return batch; + } + else{ + Batch batch = new Batch(processInstanceKey); + batchRepository.save(batch); + return batch; + } + } else { + logger.debug("Found existing Batch for processInstanceKey: {}", processInstanceKey); + } + + return batchOptional.orElse(null); + } + + + public void checkWorkerIdAndUpdateTransferData(Batch batch, Long workflowInstanceKey, Long timestamp) { + updateTransferTableForBatch(batch, workflowInstanceKey, timestamp); + + } + + private void updateTransferTableForBatch(Batch batch, Long workflowInstanceKey, Long completeTimestamp) { + String filename = getBatchFileName(workflowInstanceKey); + logger.debug("Filename {}", filename); + if (filename == null) { + return; + } + filename = strip(filename); + String localFilePath = fileTransferService.downloadFile(filename, bucketName); + if (localFilePath == null) { + logger.error("Null localFilePath, Error updating transfer table for batch with instance key {} and batch filename {}", + workflowInstanceKey, filename); + return; + } + List transactionList = csvFileService.getTransactionList(filename); + for (Transaction transaction : transactionList) { + Transfer transfer = BatchFormatToTransferMapper.mapToTransferEntity(transaction); + transfer.setWorkflowInstanceKey(workflowInstanceKey); + transfer.setCompletedAt(new Date(completeTimestamp)); + transfer.setTransactionId(transaction.getRequestId()); + transfer.setClientCorrelationId(UUID.randomUUID().toString()); + transfer.setPayeeDfspId(batch.getPaymentMode()); + transfer.setPayerDfspId(ThreadLocalContextUtil.getTenantName()); + String batchId = getBatchId(workflowInstanceKey); + if(transaction.getBatchId() == null || transaction.getBatchId().isEmpty()) + { + transfer.setBatchId(batchId); + }else { + transfer.setBatchId(transaction.getBatchId()); + } + transfer.setPayeeFeeCurrency(transaction.getCurrency()); + transfer.setPayeeFee(BigDecimal.ZERO); + transfer.setPayerFeeCurrency(transaction.getCurrency()); + transfer.setPayerFee(BigDecimal.ZERO); + if(transaction.getPaymentMode().equals(PaymentModeEnum.CLOSED_LOOP.getValue())) { + + BatchFormatToTransferMapper.updateTransferUsingBatchDetails(transfer, batch); + transfer = updatedExistingRecord(transfer, batchId); + transferRepository.save(transfer); + } + logger.debug("Saved transfer with batchId: {}", transfer.getBatchId()); + } + + } + + public Transfer updatedExistingRecord(Transfer transfer, String batchId) { + // Attempt to find an existing transfer with the provided batchId + Optional existingTransferOpt = transferRepository.findByTransactionIdAndBatchId(transfer.getTransactionId(), batchId); + + // If not found, attempt to find with the transfer's own batchId + Transfer existingTransfer = existingTransferOpt.orElseGet(() -> + transferRepository.findByTransactionIdAndBatchId(transfer.getTransactionId(), transfer.getBatchId()) + .orElse(null)); + + // If still not found, return the original transfer + if (existingTransfer == null) { + return transfer; + } + + // If found, update the existing transfer with the provided transfer's details and return + return updateTransfer(existingTransfer, transfer); + } + + public Transfer updateTransfer(Transfer transfer1, Transfer transfer2) { + transfer1.setWorkflowInstanceKey(transfer2.getWorkflowInstanceKey()); + transfer1.setTransactionId(transfer2.getTransactionId()); + transfer1.setStartedAt(transfer2.getStartedAt()); + transfer1.setCompletedAt(transfer2.getCompletedAt()); + transfer1.setStatus(transfer2.getStatus()); + transfer1.setStatusDetail(transfer2.getStatusDetail()); + transfer1.setPayeeDfspId(transfer2.getPayeeDfspId()); + transfer1.setPayeePartyId(transfer2.getPayeePartyId()); + transfer1.setPayeePartyIdType(transfer2.getPayeePartyIdType()); + transfer1.setPayeeFee(transfer2.getPayeeFee()); + transfer1.setPayeeFeeCurrency(transfer2.getPayeeFeeCurrency()); + transfer1.setPayeeQuoteCode(transfer2.getPayeeQuoteCode()); + transfer1.setPayerDfspId(transfer2.getPayerDfspId()); + transfer1.setPayerPartyId(transfer2.getPayerPartyId()); + transfer1.setPayerPartyIdType(transfer2.getPayerPartyIdType()); + transfer1.setPayerFee(transfer2.getPayerFee()); + transfer1.setPayerFeeCurrency(transfer2.getPayerFeeCurrency()); + transfer1.setPayerQuoteCode(transfer2.getPayerQuoteCode()); + transfer1.setAmount(transfer2.getAmount()); + transfer1.setCurrency(transfer2.getCurrency()); + transfer1.setDirection(transfer2.getDirection()); + transfer1.setErrorInformation(transfer2.getErrorInformation()); + transfer1.setBatchId(transfer2.getBatchId()); + transfer1.setClientCorrelationId(transfer2.getClientCorrelationId()); + return transfer1; + } + + public void updateTransferTableWithFailedTransaction(Long workflowInstanceKey, String filename) { + logger.debug("Filename {}", filename); + if (filename == null) { + return; + } + filename = strip(filename); + String localFilePath = fileTransferService.downloadFile(filename, bucketName); + List transactionList = csvFileService.getTransactionList(localFilePath); + for (Transaction transaction : transactionList) { + Transfer transfer = BatchFormatToTransferMapper.mapToTransferEntity(transaction); + transfer.setStatus(TransferStatus.FAILED); + transfer.setWorkflowInstanceKey(workflowInstanceKey);; + String batchId = getBatchId(workflowInstanceKey); + if(transaction.getBatchId() == null || transaction.getBatchId().isEmpty()) + { + transfer.setBatchId(batchId); + }else { + transfer.setBatchId(transaction.getBatchId()); + } + transfer.setStartedAt(new Date()); + transfer.setCompletedAt(new Date()); + transfer.setErrorInformation(transaction.getNote()); + transfer.setClientCorrelationId(UUID.randomUUID().toString()); + transfer.setTransactionId(transaction.getRequestId()); + logger.debug("Inserting failed txn: {}", transfer); + logger.debug("Inserting failed txn with note: {}", transaction.getNote()); + transfer = updatedExistingRecord(transfer, batchId); + transferRepository.save(transfer); + } + } + + public String getBatchFileName(Long workflowKey) { + synchronized (workflowKeyBatchFileNameAssociations) { + return workflowKeyBatchFileNameAssociations.get(workflowKey); + } + } + + public void storeBatchId(Long workflowKey, String batchId) { + synchronized (workflowKeyBatchFileNameAssociations) { + workflowKeyBatchIdAssociations.put(workflowKey, batchId); + } + } + + public String getBatchId(Long workflowKey) { + synchronized (workflowKeyBatchFileNameAssociations) { + return workflowKeyBatchIdAssociations.get(workflowKey); + } + } + + public void storeBatchFileName(Long workflowKey, String filename) { + synchronized (workflowKeyBatchFileNameAssociations) { + workflowKeyBatchFileNameAssociations.put(workflowKey, filename); + } + } +} diff --git a/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/streams/InflightOutboundMessageManager.java b/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/streams/InflightOutboundMessageManager.java new file mode 100644 index 000000000..ad7a129e6 --- /dev/null +++ b/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/streams/InflightOutboundMessageManager.java @@ -0,0 +1,40 @@ +package hu.dpc.phee.operator.streams; + +import com.jayway.jsonpath.DocumentContext; +import hu.dpc.phee.operator.config.TransferTransformerConfig; +import hu.dpc.phee.operator.entity.outboundmessages.OutboudMessages; +import hu.dpc.phee.operator.entity.outboundmessages.OutboundMessagesRepository; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.Optional; + +@Component +public class InflightOutboundMessageManager { + + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Autowired + private OutboundMessagesRepository outboundMessagesRepository; + + @Autowired + TransferTransformerConfig transferTransformerConfig; + + public OutboudMessages retrieveOrCreateOutboundMessage(String bpmn, DocumentContext record) { + Long processInstanceKey = record.read("$.value.processInstanceKey", Long.class); + Optional config = transferTransformerConfig.findFlow(bpmn); + OutboudMessages outboudMessages = outboundMessagesRepository.findByInternalId(processInstanceKey); + + if (outboudMessages != null) { + logger.debug("creating new OutboudMessages for processInstanceKey: {}", processInstanceKey); + OutboudMessages newOutboudMessages = new OutboudMessages(processInstanceKey); + outboudMessages = outboundMessagesRepository.save(newOutboudMessages); + } else { + logger.debug("found existing OutboudMessages for processInstanceKey: {}", processInstanceKey); + } + + return outboudMessages; + } +} diff --git a/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/streams/InflightTransactionRequestManager.java b/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/streams/InflightTransactionRequestManager.java new file mode 100644 index 000000000..14daace8f --- /dev/null +++ b/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/streams/InflightTransactionRequestManager.java @@ -0,0 +1,46 @@ +package hu.dpc.phee.operator.streams; + +import com.jayway.jsonpath.DocumentContext; +import hu.dpc.phee.operator.config.TransferTransformerConfig; +import hu.dpc.phee.operator.entity.transactionrequest.TransactionRequest; +import hu.dpc.phee.operator.entity.transactionrequest.TransactionRequestRepository; +import hu.dpc.phee.operator.entity.transactionrequest.TransactionRequestState; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.Optional; + +@Component +public class InflightTransactionRequestManager { + + @Autowired + TransactionRequestRepository transactionRequestRepository; + + @Autowired + TransferTransformerConfig transferTransformerConfig; + + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + public TransactionRequest retrieveOrCreateTransaction(String bpmn, DocumentContext record) { + Long processInstanceKey = record.read("$.value.processInstanceKey", Long.class); + Optional config = transferTransformerConfig.findFlow(bpmn); + TransactionRequest transactionRequest = transactionRequestRepository.findByWorkflowInstanceKey(processInstanceKey); + if (transactionRequest == null) { + logger.debug("creating new Transaction for processInstanceKey: {}", processInstanceKey); + transactionRequest = new TransactionRequest(processInstanceKey); + transactionRequest.setState(TransactionRequestState.IN_PROGRESS); + + if (config.isPresent()) { + transactionRequest.setDirection(config.get().getDirection()); + } else { + logger.error("No config found for bpmn: {}", bpmn); + } + transactionRequestRepository.save(transactionRequest); + } else { + logger.debug("found existing Transaction for processInstanceKey: {}", processInstanceKey); + } + return transactionRequest; + } +} diff --git a/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/streams/RecordParser.java b/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/streams/RecordParser.java new file mode 100644 index 000000000..84922d4bd --- /dev/null +++ b/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/streams/RecordParser.java @@ -0,0 +1,403 @@ +package hu.dpc.phee.operator.streams; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.jayway.jsonpath.DocumentContext; +import com.jayway.jsonpath.JsonPath; +import hu.dpc.phee.operator.config.TransferTransformerConfig; +import hu.dpc.phee.operator.entity.batch.Batch; +import hu.dpc.phee.operator.entity.batch.BatchRepository; +import hu.dpc.phee.operator.entity.outboundmessages.OutboudMessages; +import hu.dpc.phee.operator.entity.outboundmessages.OutboundMessagesRepository; +import hu.dpc.phee.operator.entity.task.Task; +import hu.dpc.phee.operator.entity.transactionrequest.TransactionRequest; +import hu.dpc.phee.operator.entity.transactionrequest.TransactionRequestRepository; +import hu.dpc.phee.operator.entity.transactionrequest.TransactionRequestState; +import hu.dpc.phee.operator.entity.transfer.Transfer; +import hu.dpc.phee.operator.entity.transfer.TransferRepository; +import hu.dpc.phee.operator.entity.transfer.TransferStatus; +import hu.dpc.phee.operator.entity.variable.Variable; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.text.StringEscapeUtils; +import org.apache.logging.log4j.util.Strings; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.PropertyAccessorFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; +import org.w3c.dom.Document; +import org.xml.sax.InputSource; + +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.xpath.XPathFactory; +import java.io.IOException; +import java.io.StringReader; +import java.util.Arrays; +import java.util.Date; +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; + +import static hu.dpc.phee.operator.util.OperatorUtils.strip; + +@Component +public class RecordParser { + + @Autowired + private InFlightTransferManager inFlightTransferManager; + + @Autowired + private InflightTransactionRequestManager inflightTransactionRequestManager; + + @Autowired + private InflightBatchManager inflightBatchManager; + + @Autowired + private InflightOutboundMessageManager inflightOutboundMessageManager; + + @Autowired + TransferRepository transferRepository; + + @Autowired + TransactionRequestRepository transactionRequestRepository; + + @Autowired + BatchRepository batchRepository; + + @Autowired + OutboundMessagesRepository outboundMessagesRepository; + + @Autowired + TransferTransformerConfig transferTransformerConfig; + + private final DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance(); + + private final XPathFactory xPathFactory = XPathFactory.newInstance(); + + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Transactional + public List processWorkflowInstance(DocumentContext recordDocument, String bpmn, Long workflowInstanceKey, Long timestamp, String bpmnElementType, String elementId, String flowType, DocumentContext sample) { + logger.debug("Processing workflow instance"); + String recordType = recordDocument.read("$.recordType", String.class); + String intent = recordDocument.read("$.intent", String.class); + + if (!"START_EVENT".equals(bpmnElementType) && !"END_EVENT".equals(bpmnElementType)) { + return List.of(); + } + + Optional config = transferTransformerConfig.findFlow(bpmn); + logger.debug("Inside processWorkflowInstance recordDocument {}", recordDocument); + List constantTransformers = transferTransformerConfig.getFlows().stream() + .filter(it -> bpmn.equalsIgnoreCase(it.getName())) + .flatMap(it -> it.getTransformers().stream()) + .filter(it -> Strings.isNotBlank(it.getConstant())) + .toList(); + + if ("TRANSFER".equalsIgnoreCase(flowType)) { + logger.debug("Processing flow of type TRANSFER"); + Transfer transfer = inFlightTransferManager.retrieveOrCreateTransfer(bpmn, sample, "PROCESS_INSTANCE"); + if ("EVENT".equals(recordType) && "START_EVENT".equals(bpmnElementType) && "ELEMENT_ACTIVATED".equals(intent)) { + transfer.setStartedAt(new Date(timestamp)); + transfer.setDirection(config.get().getDirection()); + logger.debug("found {} constant transformers for flow start {}", constantTransformers.size(), bpmn); + } else if ("EVENT".equals(recordType) && "END_EVENT".equals(bpmnElementType) && "ELEMENT_COMPLETED".equals(intent)) { + logger.debug("finishing transfer for processInstanceKey: {} at elementId: {}", workflowInstanceKey, elementId); + transfer.setCompletedAt(new Date(timestamp)); + if (StringUtils.isNotEmpty(elementId) && elementId.contains("Failed")) { + transfer.setStatus(TransferStatus.FAILED); + } else { + transfer.setStatus(TransferStatus.COMPLETED); + } + } + constantTransformers.forEach(it -> applyTransformer(transfer, null, null, it)); + transferRepository.save(transfer); + } else if ("TRANSACTION-REQUEST".equalsIgnoreCase(flowType)) { + logger.debug("Processing flow of type TRANSACTION"); + TransactionRequest transactionRequest = inflightTransactionRequestManager.retrieveOrCreateTransaction(bpmn, sample); + if ("ELEMENT_ACTIVATING".equals(intent)) { + transactionRequest.setStartedAt(new Date(timestamp)); + transactionRequest.setDirection(config.get().getDirection()); + logger.debug("found {} constant transformers for flow start {}", constantTransformers.size(), bpmn); + } else if ("ELEMENT_COMPLETED".equals(intent)) { + logger.debug("finishing transaction for processInstanceKey: {} at elementId: {}", workflowInstanceKey, elementId); + transactionRequest.setCompletedAt(new Date(timestamp)); + if(!config.get().getName().contains("bill_request")) { + if (StringUtils.isNotEmpty(elementId) && elementId.contains("Failed")) { + transactionRequest.setState(TransactionRequestState.FAILED); + } else { + transactionRequest.setState(TransactionRequestState.ACCEPTED); + } + } + } + constantTransformers.forEach(it -> applyTransformer(transactionRequest, null, null, it)); + transactionRequestRepository.save(transactionRequest); + } else if ("BATCH".equalsIgnoreCase(flowType)) { + logger.debug("Processing flow of type BATCH"); + Batch batch = inflightBatchManager.retrieveOrCreateBatch(bpmn, sample); + if ("ELEMENT_ACTIVATING".equals(intent)) { + batch.setStartedAt(new Date(timestamp)); + logger.debug("found {} constant transformers for flow start {}", constantTransformers.size(), bpmn); + } else if ("ELEMENT_COMPLETED".equals(intent)) { + logger.debug("Inside ELEMENT_COMPLETED"); + // if (!config.get().getName().contains("bulk_processor")) { + logger.debug("Inside if condition PROCESS_INSTANCE, json {}", recordType); + inflightBatchManager.checkWorkerIdAndUpdateTransferData(batch, workflowInstanceKey, timestamp); + // } + batch.setCompletedAt(new Date(timestamp)); + } + constantTransformers.forEach(it -> applyTransformer(batch, null, null, it)); + batchRepository.save(batch); + } else if ("OUTBOUND_MESSAGES".equalsIgnoreCase(flowType)) { + logger.debug("Processing flow of type OUTBOUND MESSAGES"); + OutboudMessages outboudMessages = inflightOutboundMessageManager.retrieveOrCreateOutboundMessage(bpmn, recordDocument); + if ("ELEMENT_ACTIVATING".equals(intent)) { + outboudMessages.setSubmittedOnDate(new Date(timestamp)); + } else if ("ELEMENT_COMPLETED".equals(intent)) { + outboudMessages.setDeliveredOnDate(new Date(timestamp)); + } + outboundMessagesRepository.save(outboudMessages); + constantTransformers.forEach(it -> applyTransformer(outboudMessages, null, null, it)); + } else { + logger.error("No matching flow types for the given request"); + } + return List.of(); + } + + public void updateRtpTransaction(TransactionRequest transactionRequest, String value){ + if(value.equals("INITIATED")){ + transactionRequest.setState(TransactionRequestState.INITIATED); + } else if(value.equals("IN_PROGRESS")){ + transactionRequest.setState(TransactionRequestState.IN_PROGRESS); + } else if(value.equals("REQUEST_ACCEPTED")){ + transactionRequest.setState(TransactionRequestState.REQUEST_ACCEPTED); + } else if (value.equals("ACCEPTED")){ + transactionRequest.setState(TransactionRequestState.ACCEPTED); + } else if(value.equals("SUCCESS")){ + transactionRequest.setState(TransactionRequestState.SUCCESS); + } + } + + public List processVariable(DocumentContext recordDocument, String bpmn, Long workflowInstanceKey, Long workflowKey, Long timestamp, String flowType, DocumentContext sample)throws JsonProcessingException { + logger.debug("Processing variable instance"); + String variableName = recordDocument.read("$.value.name", String.class); + String variableValue = recordDocument.read("$.value.value", String.class); + String value = variableValue.startsWith("\"") && variableValue.endsWith("\"") ? StringEscapeUtils.unescapeJson(variableValue.substring(1, variableValue.length() - 1)) : variableValue; + + List results = List.of( + new Variable() + .withWorkflowInstanceKey(workflowInstanceKey) + .withName(variableName) + .withWorkflowKey(workflowKey) + .withTimestamp(timestamp) + .withValue(value)); + + if(variableName.equals("subBatchDetails")) { + parseSubBatchDetails(variableValue); + } + + if (variableName.equals("failedTransactionFile")) { + // insert the transaction into transfer table + logger.debug("Name {} and value: {}"); + inflightBatchManager.updateTransferTableWithFailedTransaction(workflowInstanceKey, value); + } + + if (variableName.equals("batchId")) { + logger.debug("store batchid {} in tempDocStore for instance {}", strip(value), workflowInstanceKey); + inflightBatchManager.storeBatchId(workflowInstanceKey, value); + } + + logger.debug("finding transformers for bpmn: {} and variable: {}", bpmn, variableName); + List matchingTransformers = transferTransformerConfig.getFlows().stream() + .filter(it -> bpmn.equalsIgnoreCase(it.getName())) + .flatMap(it -> it.getTransformers().stream()) + .filter(it -> variableName.equalsIgnoreCase(it.getVariableName())) + .toList(); + + matchTransformerForFlowType(flowType, bpmn, sample, matchingTransformers, variableName, value, workflowInstanceKey); + + return results; + } + + @Transactional + private void matchTransformerForFlowType(String flowType, String bpmn, DocumentContext sample, List matchingTransformers, String variableName, String value, Long workflowInstanceKey) { + Optional config = transferTransformerConfig.findFlow(bpmn); + if ("TRANSFER".equalsIgnoreCase(flowType)) { + Transfer transfer = inFlightTransferManager.retrieveOrCreateTransfer(bpmn, sample, "VARIABLE"); + matchingTransformers.forEach(transformer -> applyTransformer(transfer, variableName, value, transformer)); + transferRepository.save(transfer); + } else if ("TRANSACTION-REQUEST".equalsIgnoreCase(flowType)) { + TransactionRequest transactionRequest = inflightTransactionRequestManager.retrieveOrCreateTransaction(bpmn, sample); + if(variableName.equals("state")){ + updateRtpTransaction(transactionRequest, value); + } + matchingTransformers.forEach(transformer -> applyTransformer(transactionRequest, variableName, value, transformer)); + transactionRequestRepository.save(transactionRequest); + } else if ("BATCH".equalsIgnoreCase(flowType)) { + Batch batch = inflightBatchManager.retrieveOrCreateBatch(bpmn, sample); + matchingTransformers.forEach(transformer -> applyTransformer(batch, variableName, value, transformer)); + batchRepository.save(batch); + //if (!config.get().getName().equalsIgnoreCase("bulk_processor")) { + logger.debug("Inside if condition {}", variableName); + if (variableName.equals("filename")) { + logger.debug("store filename {} in tempDocStore for instance {}", strip(value), workflowInstanceKey); + inflightBatchManager.storeBatchFileName(workflowInstanceKey, value); + } + if (variableName.equals("batchId")) { + logger.debug("store batchid {} in tempDocStore for instance {}", strip(value), workflowInstanceKey); + inflightBatchManager.storeBatchId(workflowInstanceKey, value); + } + //} + } else if ("OUTBOUND_MESSAGES".equalsIgnoreCase(flowType)) { + OutboudMessages outboudMessages = inflightOutboundMessageManager.retrieveOrCreateOutboundMessage(bpmn, sample); + matchingTransformers.forEach(transformer -> applyTransformer(outboudMessages, variableName, value, transformer)); + outboundMessagesRepository.save(outboudMessages); + } else { + logger.error("No matching flow types for the given request"); + } + } + + public List processTask(DocumentContext recordDocument, Long workflowInstanceKey, String valueType, Long workflowKey, Long timestamp) { + logger.debug("Processing task instance"); + return List.of( + new Task() + .withWorkflowInstanceKey(workflowInstanceKey) + .withWorkflowKey(workflowKey) + .withTimestamp(timestamp) + .withIntent(recordDocument.read("$.intent", String.class)) + .withRecordType(valueType) + .withType(recordDocument.read("$.value.type", String.class)) + .withElementId(recordDocument.read("$.value.elementId", String.class)) + ); + } + + @Transactional + public List processIncident(Long timestamp, String flowType, String bpmn, DocumentContext sample, Long workflowInstanceKey) { + logger.debug("Processing incident instance"); + if ("TRANSFER".equalsIgnoreCase(flowType)) { + Transfer transfer = inFlightTransferManager.retrieveOrCreateTransfer(bpmn, sample, "INCIDENT"); + //Skipping dummy transfer cases + if(transfer.getWorkflowInstanceKey().equals(0L) || transfer.getErrorInformation().equals("404")) { + logger.debug("Inside dummy fail case ------------------------------------------------------ "); + } else { + logger.debug("failing Transfer {} based on incident event", transfer.getTransactionId()); + transfer.setStatus(TransferStatus.EXCEPTION); + transfer.setCompletedAt(new Date(timestamp)); + transferRepository.save(transfer); + } + } else if ("TRANSACTION-REQUEST".equalsIgnoreCase(flowType)) { + TransactionRequest transactionRequest = inflightTransactionRequestManager.retrieveOrCreateTransaction(bpmn, sample); + logger.warn("failing Transaction {} based on incident event", transactionRequest.getTransactionId()); + transactionRequest.setState(TransactionRequestState.FAILED); + transactionRequest.setCompletedAt(new Date(timestamp)); + transactionRequestRepository.save(transactionRequest); + } else if ("BATCH".equalsIgnoreCase(flowType)) { + Batch batch = inflightBatchManager.retrieveOrCreateBatch(bpmn, sample); + logger.warn("failing Batch {} based on incident event", batch.getBatchId()); + batch.setNote("Failed Batch Request"); + batch.setCompletedAt(new Date(timestamp)); + batchRepository.save(batch); + } else if ("OUTBOUND_MESSAGES".equalsIgnoreCase(flowType)) { + OutboudMessages outboudMessages = inflightOutboundMessageManager.retrieveOrCreateOutboundMessage(bpmn, sample); + logger.warn("failing Outbound Message Request {} based on incident event", outboudMessages.getInternalId()); + outboudMessages.setDeliveredOnDate(new Date(timestamp)); + outboudMessages.setDeliveryErrorMessage("Failed Message Request"); + outboundMessagesRepository.save(outboudMessages); + } else { + logger.error("No flow type for the incident event"); + } + return List.of(); + } + + private void applyTransformer(Object object, String variableName, String variableValue, TransferTransformerConfig.Transformer transformer) { + logger.debug("applying transformer for field: {}", transformer.getField()); + try { + String fieldName = transformer.getField(); + if (Strings.isNotBlank(transformer.getConstant())) { + logger.debug("setting constant value: {}", transformer.getConstant()); + PropertyAccessorFactory.forBeanPropertyAccess(object).setPropertyValue(fieldName, transformer.getConstant()); + return; + } + + if (Strings.isNotBlank(transformer.getJsonPath())) { + try { + ObjectMapper objectMapper = new ObjectMapper(); + JsonNode jsonNode = objectMapper.readTree(variableValue); + if (jsonNode.isArray()) { + // It's a JSON array + for (JsonNode jsonObject : jsonNode) { + processJsonObject(jsonObject,transformer,object,fieldName,variableName,variableValue); + } + } else if (jsonNode.isObject()) { + // It's a JSON object + processJsonObject(jsonNode,transformer,object,fieldName,variableName,variableValue); + } else { + System.err.println("Invalid JSON input."); + } + } catch (IOException e) { + e.printStackTrace(); + } + return; + } + + if (Strings.isNotBlank(transformer.getXpath())) { + logger.debug("applying xpath for variable {}", variableName); + Document document = documentBuilderFactory.newDocumentBuilder().parse(new InputSource(new StringReader(variableValue))); + String result = xPathFactory.newXPath().compile(transformer.getXpath()).evaluate(document); + logger.debug("xpath result: {} for variable {}", result, variableName); + if (StringUtils.isNotBlank(result)) { + PropertyAccessorFactory.forBeanPropertyAccess(object).setPropertyValue(fieldName, result); + } else { + logger.error("null result when setting field {} from variable {}. Xpath: {}, variable value: {}", fieldName, variableName, transformer.getXpath(), variableValue); + } + return; + } + + logger.debug("setting simple variable value: {} for variable {}", variableValue, variableName); + PropertyAccessorFactory.forBeanPropertyAccess(object).setPropertyValue(fieldName, variableValue); + + } catch (Exception e) { + logger.error("failed to apply transformer {} to variable {}", transformer, variableName, e); + } + } + + private void processJsonObject(JsonNode jsonNode, TransferTransformerConfig.Transformer transformer, Object object, String fieldName, String variableName, String variableValue) { + DocumentContext document = JsonPath.parse(jsonNode.toString()); + Object result = document.read(transformer.getJsonPath()); + logger.debug("Results:{}",result); + + String value = null; + if (result != null) { + if (result instanceof String) { + value = (String) result; + } + if (result instanceof List) { + value = ((List) result).stream().map(Object::toString).collect(Collectors.joining(" ")); + } else { + value = result.toString(); + } + PropertyAccessorFactory.forBeanPropertyAccess(object).setPropertyValue(fieldName, value); + } + + if (StringUtils.isBlank(value)) { + logger.error("null result when setting field {} from variable {}. Jsonpath: {}, variable value: {}", fieldName, variableName, transformer.getJsonPath(), variableValue); + } + } + + @Transactional + public void parseSubBatchDetails(String jsonString) throws JsonProcessingException { + ObjectMapper objectMapper = new ObjectMapper(); + List batches = Arrays.asList(objectMapper.readValue(jsonString, Batch[].class)); + logger.debug("Inside parseSubBatchDetails batch size - {}", batches.size()); + for (Batch bt : batches) { + Optional existingBatchOpt = batchRepository.findBySubBatchId(bt.getSubBatchId()); + + existingBatchOpt.orElseGet(() -> { + batchRepository.save(bt); + return bt; // Return bt as it's saved now. + }); + } + } +} diff --git a/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/streams/StreamsSetup.java b/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/streams/StreamsSetup.java new file mode 100644 index 000000000..8e6ba7c1c --- /dev/null +++ b/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/streams/StreamsSetup.java @@ -0,0 +1,262 @@ +package hu.dpc.phee.operator.streams; + +import com.jayway.jsonpath.DocumentContext; +import hu.dpc.phee.operator.config.AnalyticsConfig; +import hu.dpc.phee.operator.config.TransferTransformerConfig; +import hu.dpc.phee.operator.entity.analytics.EventTimestampsRepository; +import hu.dpc.phee.operator.entity.analytics.EventTimestamps; +import hu.dpc.phee.operator.entity.batch.BatchRepository; +import hu.dpc.phee.operator.entity.outboundmessages.OutboundMessagesRepository; +import hu.dpc.phee.operator.entity.task.Task; +import hu.dpc.phee.operator.entity.task.TaskRepository; +import hu.dpc.phee.operator.entity.tenant.ThreadLocalContextUtil; +import hu.dpc.phee.operator.entity.transactionrequest.TransactionRequestRepository; +import hu.dpc.phee.operator.entity.transfer.TransferRepository; +import hu.dpc.phee.operator.entity.variable.Variable; +import hu.dpc.phee.operator.entity.variable.VariableRepository; +import hu.dpc.phee.operator.importer.JsonPathReader; +import hu.dpc.phee.operator.tenants.TenantsService; +import jakarta.annotation.PostConstruct; +import org.apache.kafka.common.serialization.Serde; +import org.apache.kafka.common.serialization.Serdes; +import org.apache.kafka.streams.StreamsBuilder; +import org.apache.kafka.streams.kstream.Aggregator; +import org.apache.kafka.streams.kstream.Consumed; +import org.apache.kafka.streams.kstream.Materialized; +import org.apache.kafka.streams.kstream.Merger; +import org.apache.kafka.streams.kstream.SessionWindows; +import org.apache.kafka.streams.kstream.Windowed; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.data.util.Pair; +import org.springframework.stereotype.Service; +import org.springframework.transaction.support.TransactionTemplate; + +import javax.sql.DataSource; +import java.text.SimpleDateFormat; +import java.time.Duration; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Date; +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import static org.apache.kafka.common.serialization.Serdes.ListSerde; + +@Service +public class StreamsSetup { + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + private static final Serde STRING_SERDE = Serdes.String(); + + @Value("${importer.kafka.topic}") + private String kafkaTopic; + + @Value("${importer.kafka.aggreation-window-seconds}") + private int aggregationWindowSeconds; + + @Autowired + private StreamsBuilder streamsBuilder; + + @Autowired + private TransactionTemplate transactionTemplate; + + @Autowired + TransferTransformerConfig transferTransformerConfig; + + @Autowired + TransferRepository transferRepository; + + @Autowired + TransactionRequestRepository transactionRequestRepository; + + @Autowired + BatchRepository batchRepository; + + @Autowired + OutboundMessagesRepository outboundMessagesRepository; + + @Autowired + TenantsService tenantsService; + + @Autowired + RecordParser recordParser; + + @Autowired + VariableRepository variableRepository; + + @Autowired + TaskRepository taskRepository; + + @Autowired + private EventTimestampsRepository eventTimestampsRepository; + + @Autowired AnalyticsConfig analyticsConfig; + + + @PostConstruct + public void setup() { + logger.debug("## setting up kafka streams on topic `{}`, aggregating every {} seconds", kafkaTopic, aggregationWindowSeconds); + Aggregator> aggregator = (key, value, aggregate) -> { + aggregate.add(value); + return aggregate; + }; + Merger> merger = (key, first, second) -> Stream.of(first, second) + .flatMap(Collection::stream) + .collect(Collectors.toList()); + + streamsBuilder.stream(kafkaTopic, Consumed.with(STRING_SERDE, STRING_SERDE)) + .groupByKey() + .windowedBy(SessionWindows.ofInactivityGapAndGrace(Duration.ofSeconds(aggregationWindowSeconds), Duration.ZERO)) + .aggregate(ArrayList::new, aggregator, merger, Materialized.with(STRING_SERDE, ListSerde(ArrayList.class, STRING_SERDE))) + .toStream() + .foreach(this::process); + + // TODO kafka-ba kell leirni a vegen az entitaslistat, nem DB-be, hogy konzisztens es ujrajatszhato legyen !! + } + + public void process(Object _key, Object _value) { + Windowed key = (Windowed) _key; + List records = (List) _value; + + if (records == null || records.size() == 0) { + logger.warn("skipping processing, null records for key: {}", key); + return; + } + + String bpmn; + String tenantName; + String first = records.get(0); + + DocumentContext sample = JsonPathReader.parse(first); + try { + Pair bpmnAndTenant = retrieveTenant(sample); + bpmn = bpmnAndTenant.getFirst(); + tenantName = bpmnAndTenant.getSecond(); + logger.trace("resolving tenant server connection for tenant: {}", tenantName); + DataSource tenant = tenantsService.getTenantDataSource(tenantName); + ThreadLocalContextUtil.setTenant(tenant); + ThreadLocalContextUtil.setTenantName(tenantName); + } catch (Exception e) { + logger.error("failed to process first record: {}, skipping whole batch", first, e); + return; + } + + try { + if (transferTransformerConfig.findFlow(bpmn).isEmpty()) { + logger.warn("skip saving flow information, no configured flow found for bpmn: {}", bpmn); + return; + } + Optional config = transferTransformerConfig.findFlow(bpmn); + String flowType = getTypeForFlow(config); + + logger.debug("processing key: {}, records: {}", key, records); + + transactionTemplate.executeWithoutResult(status -> { + for (String record : records) { + try { + DocumentContext recordDocument = JsonPathReader.parse(record); + if (analyticsConfig.enableEventsTimestampsDump.equals("true")) { + logToTimestampsTable(recordDocument); + } + logger.debug("from kafka: {}", recordDocument.jsonString()); + + String valueType = recordDocument.read("$.valueType", String.class); + logger.debug("processing {} event", valueType); + + Long workflowKey = recordDocument.read("$.value.processDefinitionKey"); + Long workflowInstanceKey = recordDocument.read("$.value.processInstanceKey"); + Long timestamp = recordDocument.read("$.timestamp"); + String bpmnElementType = recordDocument.read("$.value.bpmnElementType"); + String elementId = recordDocument.read("$.value.elementId"); + logger.debug("Processing document of type {}", valueType); + + List entities = switch (valueType) { + case "DEPLOYMENT", "VARIABLE_DOCUMENT", "WORKFLOW_INSTANCE" -> List.of(); + case "PROCESS_INSTANCE" -> { + yield recordParser.processWorkflowInstance(recordDocument, bpmn, workflowInstanceKey, timestamp, bpmnElementType, elementId, flowType, sample); + } + + case "JOB" -> { + yield recordParser.processTask(recordDocument, workflowInstanceKey, valueType, workflowKey, timestamp); + } + + case "VARIABLE" -> { + yield recordParser.processVariable(recordDocument, bpmn, workflowInstanceKey, workflowKey, timestamp, flowType, sample); + } + + case "INCIDENT" -> { + yield recordParser.processIncident(timestamp, flowType, bpmn, sample, workflowInstanceKey); + } + + default -> throw new IllegalStateException("Unexpected event type: " + valueType); + }; + if (entities.size() != 0) { + logger.debug("Saving {} entities", entities.size()); + entities.forEach(entity -> { + if (entity instanceof Variable) { + variableRepository.save((Variable) entity); + } else if (entity instanceof Task) { + taskRepository.save((Task) entity); + } else { + throw new IllegalStateException("Unexpected entity type: " + entity.getClass()); + } + }); + } + } catch (Exception e) { + logger.error("failed to parse record: {}", record, e); + } + } + }); + } catch (Exception e) { + logger.error("failed to process batch", e); + + } finally { + ThreadLocalContextUtil.clear(); + } + } + + private String getTypeForFlow(Optional config) { + return config.map(TransferTransformerConfig.Flow::getType).orElse(null); + } + + public Pair retrieveTenant(DocumentContext record) { + String bpmnProcessIdWithTenant = findBpmnProcessId(record); + + String[] split = bpmnProcessIdWithTenant.split("-"); + if (split.length < 2) { + throw new RuntimeException("Invalid bpmnProcessId, has no tenant information: '" + bpmnProcessIdWithTenant + "'"); + } + return Pair.of(split[0], split[1]); + } + + private String findBpmnProcessId(DocumentContext record) { + String bpmnProcessIdWithTenant = record.read("$.value.bpmnProcessId", String.class); + if (bpmnProcessIdWithTenant == null) { + logger.warn("can't find bpmnProcessId in record: {}, trying alternative ways..", record.jsonString()); + List ids = record.read("$.value..bpmnProcessId", List.class); + if (ids.size() > 1) { + throw new RuntimeException("Invalid bpmnProcessIdWithTenant, has more than one bpmnProcessIds: '" + ids + "'"); + } + bpmnProcessIdWithTenant = ids.get(0); + } + logger.debug("resolved bpmnProcessIdWithTenant: {}", bpmnProcessIdWithTenant); + return bpmnProcessIdWithTenant; + } + + public void logToTimestampsTable(DocumentContext incomingRecord) { + try{ + EventTimestamps eventTimestamps = new EventTimestamps(); + eventTimestamps.setWorkflowInstanceKey(incomingRecord.read("$.value.processInstanceKey")); + eventTimestamps.setExportedTime(incomingRecord.read("$.exportedTime")); + eventTimestamps.setImportedTime(new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZZ").format(new Date())); + eventTimestamps.setZeebeTime(incomingRecord.read("$.timestamp").toString()); + eventTimestampsRepository.save(eventTimestamps); + }catch (Exception e) { + logger.debug(e.getMessage().toString() + " Error parsing record"); + } + } +} diff --git a/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/tenants/TenantConnectionProperties.java b/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/tenants/TenantConnectionProperties.java new file mode 100644 index 000000000..b414207e6 --- /dev/null +++ b/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/tenants/TenantConnectionProperties.java @@ -0,0 +1,33 @@ +package hu.dpc.phee.operator.tenants; + +import lombok.Data; + +@Data +public class TenantConnectionProperties { + String name; + String schemaServer; + String schemaName; + String schemaServerPort; + String schemaUsername; + String schemaPassword; + String driverClass; + String jdbcProtocol; + String jdbcSubProtocol; + String autoUpdate; + String poolInitialSize; + String poolValidationInterval; + String poolRemoveAbandoned; + String poolRemoveAbandonedTimeout; + String poolLogAbandoned; + String poolAbandonWhenPercentageFull; + String poolTestOnBorrow; + String poolMaxActive; + String poolMinIdle; + String poolMaxIdle; + String poolSuspectTimeout; + String poolTimeBetweenEvictionRunsMillis; + String poolMinEvictableIdleTimeMillis; + String deadlockMaxRetries; + String deadlockMaxRetryInterval; + String schemaConnectionParameters; +} diff --git a/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/tenants/TenantConnections.java b/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/tenants/TenantConnections.java new file mode 100644 index 000000000..c8fb8e6fa --- /dev/null +++ b/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/tenants/TenantConnections.java @@ -0,0 +1,16 @@ +package hu.dpc.phee.operator.tenants; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Configuration; + +import java.util.List; + +@Configuration +@ConfigurationProperties("tenants") +@Data +public class TenantConnections { + + List connections; + +} diff --git a/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/tenants/TenantsService.java b/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/tenants/TenantsService.java new file mode 100644 index 000000000..0a6c9f886 --- /dev/null +++ b/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/tenants/TenantsService.java @@ -0,0 +1,117 @@ +package hu.dpc.phee.operator.tenants; + +import com.zaxxer.hikari.HikariConfig; +import com.zaxxer.hikari.HikariDataSource; +import jakarta.annotation.PostConstruct; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.DisposableBean; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.core.env.Environment; +import org.springframework.stereotype.Component; + +import javax.sql.DataSource; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +@Component +public class TenantsService implements DisposableBean { + private Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Value("${datasource.common.protocol}") + private String jdbcProtocol; + + @Value("${datasource.common.subprotocol}") + private String jdbcSubprotocol; + + @Value("${datasource.common.driverclass_name}") + private String driverClass; + + + @Autowired + private Environment environment; + + @Autowired + TenantConnections tenantConnectionList; + + private Map tenantConnectionProperties; + + private Map tenantDataSources = new HashMap<>(); + + + @PostConstruct + public void setup() { + String[] activeProfiles = environment.getActiveProfiles(); + List tenants = Stream.of(activeProfiles) + .map(profile -> profile.startsWith("tenant-") ? profile.substring("tenant-".length()) : null) + .filter(Objects::nonNull) + .toList(); + logger.info("Loaded tenants from configuration: {}", tenants); + + if (tenantConnectionList.getConnections().isEmpty()) { + throw new RuntimeException("No tenant connection properties found in configuration"); + } + + this.tenantConnectionProperties = tenantConnectionList.getConnections().stream() + .collect(Collectors.toMap(TenantConnectionProperties::getName, it -> it)); + logger.info("loaded {} tenant config properties: {}", tenantConnectionProperties.size(), tenantConnectionProperties); + + tenantConnectionProperties.forEach((name, properties) -> { + logger.info("Creating datasource for tenant {}", name); + tenantDataSources.put(name, createNewDataSourceFor(properties)); + }); + } + + + public DataSource getTenantDataSource(String tenantIdentifier) { + return tenantDataSources.get(tenantIdentifier); + } + + // for initializing JPA repositories + public DataSource getAnyDataSource() { + return tenantDataSources.values().iterator().next(); + } + + @Override + public void destroy() { + logger.info("Closing {} datasources", tenantDataSources.size()); + this.tenantDataSources.forEach((name, ds) -> { + try { + ((HikariDataSource) ds).close(); + } catch (Exception e) { + logger.error("Error closing datasource for tenant {}", name, e); + } + }); + } + + + private String createJdbcUrl(String jdbcProtocol, String jdbcSubprotocol, String hostname, int port, String dbName) { + return jdbcProtocol + ':' + jdbcSubprotocol + "://" + hostname + ':' + port + '/' + dbName; + } + + public DataSource createNewDataSourceFor(TenantConnectionProperties tenant) { + HikariConfig config = new HikariConfig(); + int port = Integer.parseInt(tenant.getSchemaServerPort()); + config.setJdbcUrl(createJdbcUrl(jdbcProtocol, jdbcSubprotocol, tenant.getSchemaServer(), port, tenant.getSchemaName())); + config.setUsername(tenant.getSchemaUsername()); + config.setPassword(tenant.getSchemaPassword()); + config.setAutoCommit(false); + config.setConnectionInitSql("SELECT 1"); + config.setValidationTimeout(30000); + config.setConnectionTestQuery("SELECT 1"); + config.setConnectionTimeout(30000); + config.setDriverClassName(driverClass); + config.setIdleTimeout(600000); + config.setMaximumPoolSize(20); + config.setMinimumIdle(5); + config.setPoolName(tenant.getSchemaName() + "Pool"); + logger.info("Hikari pool created for tenant: {}", tenant); + return new HikariDataSource(config); + } + +} diff --git a/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/util/BatchFormatToTransferMapper.java b/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/util/BatchFormatToTransferMapper.java new file mode 100644 index 000000000..ee634875f --- /dev/null +++ b/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/util/BatchFormatToTransferMapper.java @@ -0,0 +1,86 @@ +package hu.dpc.phee.operator.util; + +import hu.dpc.phee.operator.entity.batch.Batch; +import hu.dpc.phee.operator.entity.batch.Transaction; +import hu.dpc.phee.operator.entity.transfer.Transfer; +import hu.dpc.phee.operator.entity.transfer.TransferStatus; + +import java.math.BigDecimal; +import java.util.Objects; + +public final class BatchFormatToTransferMapper { + + private BatchFormatToTransferMapper() {} + + public static Transfer mapToTransferEntity(Transaction transaction) { + Transfer transfer = new Transfer(); + + transfer.setAmount(BigDecimal.valueOf(Long.parseLong(transaction.getAmount()))); + // below condition check will make sure backward compatibility with old batch format + if (transaction.getAccountNumber() != null && !transaction.getAccountNumber().equalsIgnoreCase("")) { + transfer.setPayeePartyId(transaction.getAccountNumber()); + transfer.setPayeePartyIdType("accountnumber"); + } else { + transfer.setPayeePartyId(transaction.getPayeeIdentifier()); + transfer.setPayeePartyIdType(transaction.getPayeeIdentifierType()); + } + // below 2 fields will work only for new CSV specs + transfer.setPayerPartyIdType(transaction.getPayerIdentifierType()); + transfer.setPayerPartyId(transaction.getPayerIdentifier()); + transfer.setDirection("UNKNOWN"); + transfer.setBatchId(transaction.getBatchId()); + transfer.setCurrency(transaction.getCurrency()); + TransferStatus status; + if (transaction.getStatus() != null) { + String st = transaction.getStatus().toUpperCase(); + if (st.contains("SUCCESS") || st.contains("COMPLETED")) { + status = TransferStatus.COMPLETED; + } else if (st.equals("FAILED") || st.equals("ERROR")) { + status = TransferStatus.FAILED; + transfer.setErrorInformation(transaction.getStatus()); + } else { + status = TransferStatus.UNKNOWN; + } + } else { + status = TransferStatus.UNKNOWN; + } + transfer.setStatus(status); + + return transfer; + } + + public static Transfer updateTransferUsingBatchDetails(Transfer transfer, Batch batch) { + if (batch == null) { + return transfer; + } + + if (transfer.getStatus() == TransferStatus.UNKNOWN) { + if (batch.getCompletedAt() != null) { + transfer.setStatus(TransferStatus.COMPLETED); + } else { + if (batch.getTotalTransactions() != null && batch.getCompleted() != null) { + if (Objects.equals(batch.getTotalTransactions(), batch.getCompleted())) { + transfer.setStatus(TransferStatus.COMPLETED); + } + } + if (batch.getCompleted() != null && batch.getTotalTransactions() != null + && batch.getCompleted().longValue() == batch.getTotalTransactions().longValue()) { + transfer.setStatus(TransferStatus.COMPLETED); + } else if (batch.getOngoing() != null && batch.getOngoing() != 0 && batch.getCompletedAt() == null) { + transfer.setStatus(TransferStatus.IN_PROGRESS); + } else if (batch.getFailed() != null) { + transfer.setStatus(TransferStatus.FAILED); + } else { + transfer.setStatus(TransferStatus.IN_PROGRESS); + } + } + } + + if (batch.getStartedAt() != null) { + transfer.setStartedAt(batch.getStartedAt()); + } + + return transfer; + } + +} diff --git a/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/util/OperatorUtils.java b/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/util/OperatorUtils.java new file mode 100644 index 000000000..9607c64ca --- /dev/null +++ b/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/util/OperatorUtils.java @@ -0,0 +1,16 @@ +package hu.dpc.phee.operator.util; + +import java.text.SimpleDateFormat; + +public final class OperatorUtils { + + private OperatorUtils() {} + + public static String strip(String str) { + return str.replaceAll("^\"|\"$", ""); + } + + public static SimpleDateFormat dateFormat() { + return new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss"); + } +} diff --git a/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/util/PaymentModeEnum.java b/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/util/PaymentModeEnum.java new file mode 100644 index 000000000..7d058fb16 --- /dev/null +++ b/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/util/PaymentModeEnum.java @@ -0,0 +1,14 @@ +package hu.dpc.phee.operator.util; + +public enum PaymentModeEnum { + CLOSED_LOOP("closedloop"); + private final String value; + + PaymentModeEnum(String value) { + this.value = value; + } + + public String getValue() { + return this.value; + } +} diff --git a/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/util/SmsMessageStatusType.java b/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/util/SmsMessageStatusType.java new file mode 100644 index 000000000..8a39979d3 --- /dev/null +++ b/ph-ee-importer-rdbms/src/main/java/hu/dpc/phee/operator/util/SmsMessageStatusType.java @@ -0,0 +1,89 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package hu.dpc.phee.operator.util; + +/** + * SMS message delivery status predefined enum constants + **/ +public enum SmsMessageStatusType { + INVALID(0, "smsMessageStatusType.invalid"), // unknown status type + PENDING(100, "smsMessageStatusType.pending"), // message received + WAITING_FOR_REPORT(150, "smsMessageStatusType.pending"), + SENT(200, "smsMessageStatusType.sent"), // message sent to the SMS gateway + DELIVERED(300, "smsMessageStatusType.delivered"), // SMS gateway's attempt to deliver message to recipient's phone was successful + FAILED(400, "smsMessageStatusType.failed"); // SMS gateway's attempt to deliver message to recipient's phone failed + + private final Integer value; + private final String code; + + /** + * get enum constant by value + * + * @param statusValue the value of the enum constant + * @return enum constant + **/ + public static SmsMessageStatusType fromInt(final Integer statusValue) { + + SmsMessageStatusType enumeration = SmsMessageStatusType.INVALID; + + switch (statusValue) { + case 100: + enumeration = SmsMessageStatusType.PENDING; + break; + + case 150: + enumeration = SmsMessageStatusType.WAITING_FOR_REPORT; + break; + + case 200: + enumeration = SmsMessageStatusType.SENT; + break; + case 300: + enumeration = SmsMessageStatusType.DELIVERED; + break; + case 400: + enumeration = SmsMessageStatusType.FAILED; + break; + } + + return enumeration; + } + + /** + * SmsMessageStatusType constructor + **/ + private SmsMessageStatusType(final Integer value, final String code) { + this.value = value; + this.code = code; + } + + /** + * @return enum constant value + **/ + public Integer getValue() { + return this.value; + } + + /** + * @return enum constant + **/ + public String getCode() { + return this.code; + } +} diff --git a/ph-ee-importer-rdbms/src/main/resources/META-INF/persistence.xml b/ph-ee-importer-rdbms/src/main/resources/META-INF/persistence.xml new file mode 100644 index 000000000..fa24a96a7 --- /dev/null +++ b/ph-ee-importer-rdbms/src/main/resources/META-INF/persistence.xml @@ -0,0 +1,6 @@ + + + org.eclipse.persistence.jpa.PersistenceProvider + false + + diff --git a/ph-ee-importer-rdbms/src/main/resources/application-local.yml b/ph-ee-importer-rdbms/src/main/resources/application-local.yml new file mode 100644 index 000000000..641c8e809 --- /dev/null +++ b/ph-ee-importer-rdbms/src/main/resources/application-local.yml @@ -0,0 +1,1316 @@ +datasource: + core: + host: operationsmysql + port: 3306 + schema: tenants + username: mifos + password: password + common: + protocol: "jdbc" + subprotocol: mysql + driverclass_name: com.mysql.cj.jdbc.Driver + +# The transfer flows will be moved to env-labs +transfer: + flows: + - name: notification + direction: OUTGOING + type: OUTBOUND_MESSAGES + transformers: + - field: internalId + variableName: internalId + - field: response + variableName: deliveryMessage + - field: message + variableName: messageType + - field: externalId + variableName: transactionId + - field: mobileNumber + variableName: phoneNumber + - name: bulk_processor + direction: UNKNOWN + type: BATCH + transformers: + - field: batchId + variableName: batchId + - field: payerFsp + variableName: tenantId + - field: requestFile + variableName: filename + - field: registeringInstitutionId + variableName: registeringInstituteId + - field: correlationId + variableName: clientCorrelationId + - field: requestId + variableName: transactionList + jsonPath: $.request_id + - field: note + variableName: transactionList + jsonPath: $.note + - field: paymentMode + variableName: transactionList + jsonPath: $.payment_mode + - name: bulk_processor_account_lookup + direction: UNKNOWN + type: BATCH + transformers: + - field: batchId + variableName: batchId + - field: payerFsp + variableName: tenantId + - field: requestFile + variableName: filename + - field: registeringInstitutionId + variableName: registeringInstituteId + - field: correlationId + variableName: clientCorrelationId + - field: requestId + variableName: transactionList + jsonPath: $.request_id + - field: note + variableName: transactionList + jsonPath: $.note + - field: paymentMode + variableName: transactionList + jsonPath: $.payment_mode + - field: approvedAmount + variableName: totalApprovedAmount + - field: approvedCount + variableName: totalApprovedCount + - name: slcb + direction: UNKNOWN + type: BATCH + transformers: + - field: batchId + variableName: batchId + - field: payerFsp + variableName: tenantId + - field: requestFile + variableName: filename + - field: registeringInstitutionId + variableName: registeringInstituteId + - field: correlationId + variableName: clientCorrelationId + - field: requestId + variableName: transactionList + jsonPath: $.request_id + - field: note + variableName: transactionList + jsonPath: $.note + - field: paymentMode + variableName: transactionList + jsonPath: $.payment_mode +# - name: bulk_connector_closedloop +# direction: UNKNOWN +# type: BATCH +# transformers: +# - field: batchId +# variableName: batchId +# - field: payerFsp +# variableName: tenantId +# - field: requestFile +# variableName: filename +# - field: registeringInstitutionId +# variableName: registeringInstituteId +# - field: correlationId +# variableName: clientCorrelationId +# - field: requestId +# variableName: transactionList +# jsonPath: $.request_id +# - field: note +# variableName: transactionList +# jsonPath: $.note +# - field: paymentMode +# variableName: transactionList +# jsonPath: $.payment_mode + - name: inbound_transfer_mifos + direction: INCOMING + type: TRANSACTION-REQUEST + transformers: + - field: transactionId + variableName: transactionId + - field: clientCorrelationId + variableName: clientCorrelationId + - field: amount + variableName: channelRequest + jsonPath: $.amount + - field: currency + variableName: channelRequest + jsonPath: $.currency + - field: payerPartyIdType + variableName: channelRequest + jsonPath: $.payer[0].partyIdType + - field: payerPartyId + variableName: channelRequest + jsonPath: $.payer[0].partyIdIdentifier + - field: payeePartyIdType + variableName: channelRequest + jsonPath: $.payee[0].partyIdType + - field: payeePartyId + variableName: channelRequest + jsonPath: $.payee[0].partyIdIdentifier + - name: inbound_transfer_paygops + direction: INCOMING + type: TRANSACTION-REQUEST + transformers: + - field: transactionId + variableName: transactionId + - field: clientCorrelationId + variableName: clientCorrelationId + - field: amount + variableName: channelRequest + jsonPath: $.amount + - field: currency + variableName: channelRequest + jsonPath: $.currency + - field: payerPartyIdType + variableName: channelRequest + jsonPath: $.payer[0].partyIdType + - field: payerPartyId + variableName: channelRequest + jsonPath: $.payer[0].partyIdIdentifier + - field: payeePartyIdType + variableName: channelRequest + jsonPath: $.payee[0].partyIdType + - field: payeePartyId + variableName: channelRequest + jsonPath: $.payee[0].partyIdIdentifier + - name: inbound_transfer_roster + direction: INCOMING + type: TRANSACTION-REQUEST + transformers: + - field: transactionId + variableName: transactionId + - field: clientCorrelationId + variableName: clientCorrelationId + - field: amount + variableName: channelRequest + jsonPath: $.amount + - field: currency + variableName: channelRequest + jsonPath: $.currency + - field: payerPartyIdType + variableName: channelRequest + jsonPath: $.payer[0].partyIdType + - field: payerPartyId + variableName: channelRequest + jsonPath: $.payer[0].partyIdIdentifier + - field: payeePartyIdType + variableName: channelRequest + jsonPath: $.payee[0].partyIdType + - field: payeePartyId + variableName: channelRequest + jsonPath: $.payee[0].partyIdIdentifier + - name: inbound_transfer_tupande + direction: INCOMING + type: TRANSACTION-REQUEST + transformers: + - field: transactionId + variableName: transactionId + - field: clientCorrelationId + variableName: clientCorrelationId + - field: amount + variableName: channelRequest + jsonPath: $.amount + - field: currency + variableName: channelRequest + jsonPath: $.currency + - field: payerPartyIdType + variableName: channelRequest + jsonPath: $.payer[0].partyIdType + - field: payerPartyId + variableName: channelRequest + jsonPath: $.payer[0].partyIdIdentifier + - field: payeePartyIdType + variableName: channelRequest + jsonPath: $.payee[0].partyIdType + - field: payeePartyId + variableName: channelRequest + jsonPath: $.payee[0].partyIdIdentifier + - name: inbound_transfer_erply + direction: INCOMING + type: TRANSACTION-REQUEST + transformers: + - field: transactionId + variableName: transactionId + - field: clientCorrelationId + variableName: clientCorrelationId + - field: amount + variableName: channelRequest + jsonPath: $.amount + - field: currency + variableName: channelRequest + jsonPath: $.currency + - field: payerPartyIdType + variableName: channelRequest + jsonPath: $.payer[0].partyIdType + - field: payerPartyId + variableName: channelRequest + jsonPath: $.payer[0].partyIdIdentifier + - field: payeePartyIdType + variableName: channelRequest + jsonPath: $.payee[0].partyIdType + - field: payeePartyId + variableName: channelRequest + jsonPath: $.payee[0].partyIdIdentifier + - name: PayerTransactionRequest + direction: INCOMING + type: TRANSACTION-REQUEST + transformers: + - field: transactionId + variableName: transactionId + - field: clientCorrelationId + variableName: clientCorrelationId + - field: amount + variableName: channelRequest + jsonPath: $.amount + - field: currency + variableName: channelRequest + jsonPath: $.currency + - field: payerPartyIdType + variableName: channelRequest + jsonPath: $.payer[0].partyIdType + - field: payerPartyId + variableName: channelRequest + jsonPath: $.payer[0].partyIdIdentifier + - field: payeePartyIdType + variableName: channelRequest + jsonPath: $.payee[0].partyIdType + - field: payeePartyId + variableName: channelRequest + jsonPath: $.payee[0].partyIdIdentifier + - name: PayeeTransactionRequest + direction: OUTGOING + type: TRANSACTION-REQUEST + transformers: + - field: transactionId + variableName: transactionId + - field: clientCorrelationId + variableName: clientCorrelationId + - field: amount + variableName: channelRequest + jsonPath: $.amount + - field: currency + variableName: channelRequest + jsonPath: $.currency + - field: payerPartyIdType + variableName: channelRequest + jsonPath: $.payer[0].partyIdType + - field: payerPartyId + variableName: channelRequest + jsonPath: $.payer[0].partyIdIdentifier + - field: payeePartyIdType + variableName: channelRequest + jsonPath: $.payee[0].partyIdType + - field: payeePartyId + variableName: channelRequest + jsonPath: $.payee[0].partyIdIdentifier + - name: mpesa_flow + direction: INCOMING + type: TRANSACTION-REQUEST + transformers: + - field: transactionId + variableName: transactionId + - field: clientCorrelationId + variableName: clientCorrelationId + - field: amount + variableName: channelRequest + jsonPath: $.amount + - field: currency + variableName: channelRequest + jsonPath: $.currency + - field: payerPartyIdType + variableName: channelRequest + jsonPath: $.payer[0].partyIdType + - field: payerPartyId + variableName: channelRequest + jsonPath: $.payer[0].partyIdIdentifier + - field: payeePartyIdType + variableName: channelRequest + jsonPath: $.payee[0].partyIdType + - field: payeePartyId + variableName: channelRequest + jsonPath: $.payee[0].partyIdIdentifier + - name: mpesa_flow_roster + direction: INCOMING + type: TRANSACTION-REQUEST + transformers: + - field: transactionId + - field: transactionId + variableName: transactionId + - field: clientCorrelationId + variableName: clientCorrelationId + - field: amount + variableName: channelRequest + jsonPath: $.amount + - field: currency + variableName: channelRequest + jsonPath: $.currency + - field: payerPartyIdType + variableName: channelRequest + jsonPath: $.payer[0].partyIdType + - field: payerPartyId + variableName: channelRequest + jsonPath: $.payer[0].partyIdIdentifier + - field: payeePartyIdType + variableName: channelRequest + jsonPath: $.payee[0].partyIdType + - field: payeePartyId + variableName: channelRequest + jsonPath: $.payee[0].partyIdIdentifier + - name: mpesa_flow_paygops + direction: INCOMING + type: TRANSACTION-REQUEST + transformers: + - field: transactionId + variableName: transactionId + - field: clientCorrelationId + variableName: clientCorrelationId + - field: amount + variableName: channelRequest + jsonPath: $.amount + - field: currency + variableName: channelRequest + jsonPath: $.currency + - field: payerPartyIdType + variableName: channelRequest + jsonPath: $.payer[0].partyIdType + - field: payerPartyId + variableName: channelRequest + jsonPath: $.payer[0].partyIdIdentifier + - field: payeePartyIdType + variableName: channelRequest + jsonPath: $.payee[0].partyIdType + - field: payeePartyId + variableName: channelRequest + jsonPath: $.payee[0].partyIdIdentifier + - name: minimal_mock_transfer_request + direction: OUTGOING + type: TRANSACTION-REQUEST + transformers: + - field: transactionId + variableName: transactionId + - field: clientCorrelationId + variableName: clientCorrelationId + - field: amount + variableName: channelRequest + jsonPath: $.amount + - field: currency + variableName: channelRequest + jsonPath: $.currency + - field: payerPartyIdType + variableName: channelRequest + jsonPath: $.payer[0].partyIdType + - field: payerPartyId + variableName: channelRequest + jsonPath: $.payer[0].partyIdIdentifier + - field: payeePartyIdType + variableName: channelRequest + jsonPath: $.payee[0].partyIdType + - field: payeePartyId + variableName: channelRequest + jsonPath: $.payee[0].partyIdIdentifier + - name: PayerFundTransfer + direction: OUTGOING + type: TRANSFER + transformers: + - field: amount + variableName: channelRequest + jsonPath: $.amount.amount + - field: currency + variableName: channelRequest + jsonPath: $.amount.currency + - field: payeePartyIdType + variableName: channelRequest + jsonPath: $.payee.partyIdInfo.partyIdType + - field: payeePartyId + variableName: channelRequest + jsonPath: $.payee.partyIdInfo.partyIdentifier + - field: payerPartyIdType + variableName: channelRequest + jsonPath: $.payer.partyIdInfo.partyIdType + - field: payerPartyId + variableName: channelRequest + jsonPath: $.payer.partyIdInfo.partyIdentifier + - field: transactionId + variableName: transactionId + - field: currency + variableName: currency + - field: batchId + variableName: batchId + - field: tenantId + variableName: tenantId + - field: errorInformation + variableName: errorInformation + - field: clientCorrelationId + variableName: clientCorrelationId + - name: PayeeQuoteTransfer + direction: INCOMING + type: TRANSFER + transformers: + - field: amount + variableName: channelRequest + jsonPath: $.amount.amount + - field: currency + variableName: channelRequest + jsonPath: $.amount.currency + - field: payeePartyIdType + variableName: channelRequest + jsonPath: $.payee.partyIdInfo.partyIdType + - field: payeePartyId + variableName: channelRequest + jsonPath: $.payee.partyIdInfo.partyIdentifier + - field: payerPartyIdType + variableName: channelRequest + jsonPath: $.payer.partyIdInfo.partyIdType + - field: payerPartyId + variableName: channelRequest + jsonPath: $.payer.partyIdInfo.partyIdentifier + - field: transactionId + variableName: transactionId + - field: currency + variableName: currency + - field: batchId + variableName: batchId + - field: tenantId + variableName: tenantId + - field: errorInformation + variableName: errorInformation + - field: clientCorrelationId + variableName: clientCorrelationId + - name: transferProcess + direction: UNKNOWN + type: TRANSFER + transformers: + - field: amount + variableName: channelRequest + jsonPath: $.amount.amount + - field: currency + variableName: channelRequest + jsonPath: $.amount.currency + - field: payeePartyIdType + variableName: channelRequest + jsonPath: $.payee.partyIdInfo.partyIdType + - field: payeePartyId + variableName: channelRequest + jsonPath: $.payee.partyIdInfo.partyIdentifier + - field: payerPartyIdType + variableName: channelRequest + jsonPath: $.payer.partyIdInfo.partyIdType + - field: payerPartyId + variableName: channelRequest + jsonPath: $.payer.partyIdInfo.partyIdentifier + - field: transactionId + variableName: transactionId + - field: currency + variableName: currency + - field: batchId + variableName: batchId + - field: tenantId + variableName: tenantId + - field: errorInformation + variableName: errorInformation + - field: clientCorrelationId + variableName: clientCorrelationId + - name: international_remittance_payee_process + direction: OUTGOING + type: TRANSFER + transformers: + - field: amount + variableName: channelRequest + jsonPath: $.amount.amount + - field: currency + variableName: channelRequest + jsonPath: $.amount.currency + - field: payeePartyIdType + variableName: channelRequest + jsonPath: $.payee.partyIdInfo.partyIdType + - field: payeePartyId + variableName: channelRequest + jsonPath: $.payee.partyIdInfo.partyIdentifier + - field: payerPartyIdType + variableName: channelRequest + jsonPath: $.payer.partyIdInfo.partyIdType + - field: payerPartyId + variableName: channelRequest + jsonPath: $.payer.partyIdInfo.partyIdentifier + - field: transactionId + variableName: transactionId + - field: currency + variableName: currency + - field: batchId + variableName: batchId + - field: tenantId + variableName: tenantId + - field: errorInformation + variableName: errorInformation + - field: clientCorrelationId + variableName: clientCorrelationId + - name: international_remittance_payer_process + direction: OUTGOING + type: TRANSFER + transformers: + - field: amount + variableName: channelRequest + jsonPath: $.amount.amount + - field: currency + variableName: channelRequest + jsonPath: $.amount.currency + - field: payeePartyIdType + variableName: channelRequest + jsonPath: $.payee.partyIdInfo.partyIdType + - field: payeePartyId + variableName: channelRequest + jsonPath: $.payee.partyIdInfo.partyIdentifier + - field: payerPartyIdType + variableName: channelRequest + jsonPath: $.payer.partyIdInfo.partyIdType + - field: payerPartyId + variableName: channelRequest + jsonPath: $.payer.partyIdInfo.partyIdentifier + - field: transactionId + variableName: transactionId + - field: currency + variableName: currency + - field: batchId + variableName: batchId + - field: tenantId + variableName: tenantId + - field: errorInformation + variableName: errorInformation + - field: clientCorrelationId + variableName: clientCorrelationId + - name: gsma_base_transaction + direction: OUTGOING + type: TRANSFER + transformers: + - field: amount + variableName: channelRequest + jsonPath: $.amount.amount + - field: currency + variableName: channelRequest + jsonPath: $.amount.currency + - field: payeePartyIdType + variableName: channelRequest + jsonPath: $.payee.partyIdInfo.partyIdType + - field: payeePartyId + variableName: channelRequest + jsonPath: $.payee.partyIdInfo.partyIdentifier + - field: payerPartyIdType + variableName: channelRequest + jsonPath: $.payer.partyIdInfo.partyIdType + - field: payerPartyId + variableName: channelRequest + jsonPath: $.payer.partyIdInfo.partyIdentifier + - field: transactionId + variableName: transactionId + - field: currency + variableName: currency + - field: batchId + variableName: batchId + - field: tenantId + variableName: tenantId + - field: errorInformation + variableName: errorInformation + - field: clientCorrelationId + variableName: clientCorrelationId + - name: inbound_transfer_paygops + direction: INCOMING + type: TRANSFER + transformers: + - field: amount + variableName: channelRequest + jsonPath: $.amount.amount + - field: currency + variableName: channelRequest + jsonPath: $.amount.currency + - field: payeePartyIdType + variableName: channelRequest + jsonPath: $.payee.partyIdInfo.partyIdType + - field: payeePartyId + variableName: channelRequest + jsonPath: $.payee.partyIdInfo.partyIdentifier + - field: payerPartyIdType + variableName: channelRequest + jsonPath: $.payer.partyIdInfo.partyIdType + - field: payerPartyId + variableName: channelRequest + jsonPath: $.payer.partyIdInfo.partyIdentifier + - field: transactionId + variableName: transactionId + - field: currency + variableName: currency + - field: batchId + variableName: batchId + - field: tenantId + variableName: tenantId + - field: errorInformation + variableName: errorInformation + - field: clientCorrelationId + variableName: clientCorrelationId + - name: inbound_transfer_roster + direction: INCOMING + type: TRANSFER + transformers: + - field: amount + variableName: channelRequest + jsonPath: $.amount.amount + - field: currency + variableName: channelRequest + jsonPath: $.amount.currency + - field: payeePartyIdType + variableName: channelRequest + jsonPath: $.payee.partyIdInfo.partyIdType + - field: payeePartyId + variableName: channelRequest + jsonPath: $.payee.partyIdInfo.partyIdentifier + - field: payerPartyIdType + variableName: channelRequest + jsonPath: $.payer.partyIdInfo.partyIdType + - field: payerPartyId + variableName: channelRequest + jsonPath: $.payer.partyIdInfo.partyIdentifier + - field: transactionId + variableName: transactionId + - field: currency + variableName: currency + - field: batchId + variableName: batchId + - field: tenantId + variableName: tenantId + - field: errorInformation + variableName: errorInformation + - field: clientCorrelationId + variableName: clientCorrelationId + - name: PayeeQuoteTransfer + direction: INCOMING + type: TRANSFER + transformers: + - field: amount + variableName: channelRequest + jsonPath: $.amount.amount + - field: currency + variableName: channelRequest + jsonPath: $.amount.currency + - field: payeePartyIdType + variableName: channelRequest + jsonPath: $.payee.partyIdInfo.partyIdType + - field: payeePartyId + variableName: channelRequest + jsonPath: $.payee.partyIdInfo.partyIdentifier + - field: payerPartyIdType + variableName: channelRequest + jsonPath: $.payer.partyIdInfo.partyIdType + - field: payerPartyId + variableName: channelRequest + jsonPath: $.payer.partyIdInfo.partyIdentifier + - field: transactionId + variableName: transactionId + - field: currency + variableName: currency + - field: batchId + variableName: batchId + - field: tenantId + variableName: tenantId + - field: errorInformation + variableName: errorInformation + - field: clientCorrelationId + variableName: clientCorrelationId + - name: transferProcess + direction: UNKNOWN + type: TRANSFER + transformers: + - field: amount + variableName: channelRequest + jsonPath: $.amount.amount + - field: currency + variableName: channelRequest + jsonPath: $.amount.currency + - field: payeePartyIdType + variableName: channelRequest + jsonPath: $.payee.partyIdInfo.partyIdType + - field: payeePartyId + variableName: channelRequest + jsonPath: $.payee.partyIdInfo.partyIdentifier + - field: payerPartyIdType + variableName: channelRequest + jsonPath: $.payer.partyIdInfo.partyIdType + - field: payerPartyId + variableName: channelRequest + jsonPath: $.payer.partyIdInfo.partyIdentifier + - field: transactionId + variableName: transactionId + - field: currency + variableName: currency + - field: batchId + variableName: batchId + - field: tenantId + variableName: tenantId + - field: errorInformation + variableName: errorInformation + - field: clientCorrelationId + variableName: clientCorrelationId + - name: international_remittance_payee_process + direction: OUTGOING + type: TRANSFER + transformers: + - field: amount + variableName: channelRequest + jsonPath: $.amount.amount + - field: currency + variableName: channelRequest + jsonPath: $.amount.currency + - field: payeePartyIdType + variableName: channelRequest + jsonPath: $.payee.partyIdInfo.partyIdType + - field: payeePartyId + variableName: channelRequest + jsonPath: $.payee.partyIdInfo.partyIdentifier + - field: payerPartyIdType + variableName: channelRequest + jsonPath: $.payer.partyIdInfo.partyIdType + - field: payerPartyId + variableName: channelRequest + jsonPath: $.payer.partyIdInfo.partyIdentifier + - field: transactionId + variableName: transactionId + - field: currency + variableName: currency + - field: batchId + variableName: batchId + - field: tenantId + variableName: tenantId + - field: errorInformation + variableName: errorInformation + - field: clientCorrelationId + variableName: clientCorrelationId + - name: international_remittance_payer_process + direction: OUTGOING + type: TRANSFER + transformers: + - field: amount + variableName: channelRequest + jsonPath: $.amount.amount + - field: currency + variableName: channelRequest + jsonPath: $.amount.currency + - field: payeePartyIdType + variableName: channelRequest + jsonPath: $.payee.partyIdInfo.partyIdType + - field: payeePartyId + variableName: channelRequest + jsonPath: $.payee.partyIdInfo.partyIdentifier + - field: payerPartyIdType + variableName: channelRequest + jsonPath: $.payer.partyIdInfo.partyIdType + - field: payerPartyId + variableName: channelRequest + jsonPath: $.payer.partyIdInfo.partyIdentifier + - field: transactionId + variableName: transactionId + - field: currency + variableName: currency + - field: batchId + variableName: batchId + - field: tenantId + variableName: tenantId + - field: errorInformation + variableName: errorInformation + - field: clientCorrelationId + variableName: clientCorrelationId + - name: gsma_base_transaction + direction: OUTGOING + type: TRANSFER + transformers: + - field: amount + variableName: channelRequest + jsonPath: $.amount.amount + - field: currency + variableName: channelRequest + jsonPath: $.amount.currency + - field: payeePartyIdType + variableName: channelRequest + jsonPath: $.payee.partyIdInfo.partyIdType + - field: payeePartyId + variableName: channelRequest + jsonPath: $.payee.partyIdInfo.partyIdentifier + - field: payerPartyIdType + variableName: channelRequest + jsonPath: $.payer.partyIdInfo.partyIdType + - field: payerPartyId + variableName: channelRequest + jsonPath: $.payer.partyIdInfo.partyIdentifier + - field: transactionId + variableName: transactionId + - field: currency + variableName: currency + - field: batchId + variableName: batchId + - field: tenantId + variableName: tenantId + - field: errorInformation + variableName: errorInformation + - field: clientCorrelationId + variableName: clientCorrelationId + - name: mock_payment_transfer + direction: OUTGOING + type: TRANSFER + transformers: + - field: amount + variableName: channelRequest + jsonPath: $.amount.amount + - field: currency + variableName: channelRequest + jsonPath: $.amount.currency + - field: payeePartyIdType + variableName: channelRequest + jsonPath: $.payee.partyIdInfo.partyIdType + - field: payeePartyId + variableName: channelRequest + jsonPath: $.payee.partyIdInfo.partyIdentifier + - field: payerPartyIdType + variableName: channelRequest + jsonPath: $.payer.partyIdInfo.partyIdType + - field: payerPartyId + variableName: channelRequest + jsonPath: $.payer.partyIdInfo.partyIdentifier + - field: transactionId + variableName: transactionId + - field: currency + variableName: currency + - field: batchId + variableName: batchId + - field: tenantId + variableName: tenantId + - field: errorInformation + variableName: errorInformation + - field: clientCorrelationId + variableName: clientCorrelationId + - name: mock_payer_fund_transfer + direction: OUTGOING + type: TRANSFER + transformers: + - field: amount + variableName: channelRequest + jsonPath: $.amount.amount + - field: currency + variableName: channelRequest + jsonPath: $.amount.currency + - field: payeePartyIdType + variableName: channelRequest + jsonPath: $.payee.partyIdInfo.partyIdType + - field: payeePartyId + variableName: channelRequest + jsonPath: $.payee.partyIdInfo.partyIdentifier + - field: payerPartyIdType + variableName: channelRequest + jsonPath: $.payer.partyIdInfo.partyIdType + - field: payerPartyId + variableName: channelRequest + jsonPath: $.payer.partyIdInfo.partyIdentifier + - field: transactionId + variableName: transactionId + - field: currency + variableName: currency + - field: batchId + variableName: batchId + - field: tenantId + variableName: tenantId + - field: errorInformation + variableName: errorInformation + - field: clientCorrelationId + variableName: clientCorrelationId + - name: mock_payment_transfer_debit + direction: OUTGOING + type: TRANSFER + transformers: + - field: amount + variableName: channelRequest + jsonPath: $.amount.amount + - field: currency + variableName: channelRequest + jsonPath: $.amount.currency + - field: payeePartyIdType + variableName: channelRequest + jsonPath: $.payee.partyIdInfo.partyIdType + - field: payeePartyId + variableName: channelRequest + jsonPath: $.payee.partyIdInfo.partyIdentifier + - field: payerPartyIdType + variableName: channelRequest + jsonPath: $.payer.partyIdInfo.partyIdType + - field: payerPartyId + variableName: channelRequest + jsonPath: $.payer.partyIdInfo.partyIdentifier + - field: transactionId + variableName: transactionId + - field: currency + variableName: currency + - field: batchId + variableName: batchId + - field: tenantId + variableName: tenantId + - field: errorInformation + variableName: errorInformation + - field: clientCorrelationId + variableName: clientCorrelationId + - name: minimal_mock_fund_transfer + direction: OUTGOING + type: TRANSFER + transformers: + - field: amount + variableName: channelRequest + jsonPath: $.amount.amount + - field: currency + variableName: channelRequest + jsonPath: $.amount.currency + - field: payeePartyIdType + variableName: channelRequest + jsonPath: $.payee.partyIdInfo.partyIdType + - field: payeePartyId + variableName: channelRequest + jsonPath: $.payee.partyIdInfo.partyIdentifier + - field: payerPartyIdType + variableName: channelRequest + jsonPath: $.payer.partyIdInfo.partyIdType + - field: payerPartyId + variableName: channelRequest + jsonPath: $.payer.partyIdInfo.partyIdentifier + - field: transactionId + variableName: transactionId + - field: currency + variableName: currency + - field: batchId + variableName: batchId + - field: tenantId + variableName: tenantId + - field: errorInformation + variableName: errorInformation + - field: clientCorrelationId + variableName: clientCorrelationId + - name: minimal_mock_fund_transfer_account_lookup + direction: OUTGOING + type: TRANSFER + transformers: + - field: amount + variableName: channelRequest + jsonPath: $.amount.amount + - field: currency + variableName: channelRequest + jsonPath: $.amount.currency + - field: payeePartyIdType + variableName: channelRequest + jsonPath: $.payee.partyIdInfo.partyIdType + - field: payeePartyId + variableName: channelRequest + jsonPath: $.payee.partyIdInfo.partyIdentifier + - field: payerPartyIdType + variableName: channelRequest + jsonPath: $.payer.partyIdInfo.partyIdType + - field: payerPartyId + variableName: channelRequest + jsonPath: $.payer.partyIdInfo.partyIdentifier + - field: transactionId + variableName: transactionId + - field: currency + variableName: currency + - field: batchId + variableName: batchId + - field: tenantId + variableName: tenantId + - field: errorInformation + variableName: errorInformation + - field: clientCorrelationId + variableName: clientCorrelationId + - name: inbound_transfer_tupande + direction: INCOMING + type: TRANSFER + transformers: + - field: amount + variableName: channelRequest + jsonPath: $.amount.amount + - field: currency + variableName: channelRequest + jsonPath: $.amount.currency + - field: payeePartyIdType + variableName: channelRequest + jsonPath: $.payee.partyIdInfo.partyIdType + - field: payeePartyId + variableName: channelRequest + jsonPath: $.payee.partyIdInfo.partyIdentifier + - field: payerPartyIdType + variableName: channelRequest + jsonPath: $.payer.partyIdInfo.partyIdType + - field: payerPartyId + variableName: channelRequest + jsonPath: $.payer.partyIdInfo.partyIdentifier + - field: transactionId + variableName: transactionId + - field: currency + variableName: currency + - field: batchId + variableName: batchId + - field: tenantId + variableName: tenantId + - field: errorInformation + variableName: errorInformation + - field: clientCorrelationId + variableName: clientCorrelationId + - name: inbound_transfer_erply + direction: INCOMING + type: TRANSFER + transformers: + - field: amount + variableName: channelRequest + jsonPath: $.amount.amount + - field: currency + variableName: channelRequest + jsonPath: $.amount.currency + - field: payeePartyIdType + variableName: channelRequest + jsonPath: $.payee.partyIdInfo.partyIdType + - field: payeePartyId + variableName: channelRequest + jsonPath: $.payee.partyIdInfo.partyIdentifier + - field: payerPartyIdType + variableName: channelRequest + jsonPath: $.payer.partyIdInfo.partyIdType + - field: payerPartyId + variableName: channelRequest + jsonPath: $.payer.partyIdInfo.partyIdentifier + - field: transactionId + variableName: transactionId + - field: currency + variableName: currency + - field: batchId + variableName: batchId + - field: tenantId + variableName: tenantId + - field: errorInformation + variableName: errorInformation + - field: clientCorrelationId + variableName: clientCorrelationId + - name: mock_payment_transfer + direction: OUTGOING + type: TRANSFER + transformers: + - field: amount + variableName: channelRequest + jsonPath: $.amount.amount + - field: currency + variableName: channelRequest + jsonPath: $.amount.currency + - field: payeePartyIdType + variableName: channelRequest + jsonPath: $.payee.partyIdInfo.partyIdType + - field: payeePartyId + variableName: channelRequest + jsonPath: $.payee.partyIdInfo.partyIdentifier + - field: payerPartyIdType + variableName: channelRequest + jsonPath: $.payer.partyIdInfo.partyIdType + - field: payerPartyId + variableName: channelRequest + jsonPath: $.payer.partyIdInfo.partyIdentifier + - field: transactionId + variableName: transactionId + - field: currency + variableName: currency + - field: batchId + variableName: batchId + - field: tenantId + variableName: tenantId + - field: errorInformation + variableName: errorInformation + - field: clientCorrelationId + variableName: clientCorrelationId + - name: mock_payer_fund_transfer + direction: OUTGOING + type: TRANSFER + transformers: + - field: amount + variableName: channelRequest + jsonPath: $.amount.amount + - field: currency + variableName: channelRequest + jsonPath: $.amount.currency + - field: payeePartyIdType + variableName: channelRequest + jsonPath: $.payee.partyIdInfo.partyIdType + - field: payeePartyId + variableName: channelRequest + jsonPath: $.payee.partyIdInfo.partyIdentifier + - field: payerPartyIdType + variableName: channelRequest + jsonPath: $.payer.partyIdInfo.partyIdType + - field: payerPartyId + variableName: channelRequest + jsonPath: $.payer.partyIdInfo.partyIdentifier + - field: transactionId + variableName: transactionId + - field: currency + variableName: currency + - field: batchId + variableName: batchId + - field: tenantId + variableName: tenantId + - field: errorInformation + variableName: errorInformation + - field: clientCorrelationId + variableName: clientCorrelationId + - name: mock_payment_transfer_debit + direction: OUTGOING + type: TRANSFER + transformers: + - field: amount + variableName: channelRequest + jsonPath: $.amount.amount + - field: currency + variableName: channelRequest + jsonPath: $.amount.currency + - field: payeePartyIdType + variableName: channelRequest + jsonPath: $.payee.partyIdInfo.partyIdType + - field: payeePartyId + variableName: channelRequest + jsonPath: $.payee.partyIdInfo.partyIdentifier + - field: payerPartyIdType + variableName: channelRequest + jsonPath: $.payer.partyIdInfo.partyIdType + - field: payerPartyId + variableName: channelRequest + jsonPath: $.payer.partyIdInfo.partyIdentifier + - field: transactionId + variableName: transactionId + - field: currency + variableName: currency + - field: batchId + variableName: batchId + - field: tenantId + variableName: tenantId + - field: errorInformation + variableName: errorInformation + - field: clientCorrelationId + variableName: clientCorrelationId + - name: minimal_mock_fund_transfer + direction: OUTGOING + type: TRANSFER + transformers: + - field: amount + variableName: channelRequest + jsonPath: $.amount.amount + - field: currency + variableName: channelRequest + jsonPath: $.amount.currency + - field: payeePartyIdType + variableName: channelRequest + jsonPath: $.payee.partyIdInfo.partyIdType + - field: payeePartyId + variableName: channelRequest + jsonPath: $.payee.partyIdInfo.partyIdentifier + - field: payerPartyIdType + variableName: channelRequest + jsonPath: $.payer.partyIdInfo.partyIdType + - field: payerPartyId + variableName: channelRequest + jsonPath: $.payer.partyIdInfo.partyIdentifier + - field: transactionId + variableName: transactionId + - field: currency + variableName: currency + - field: batchId + variableName: batchId + - field: tenantId + variableName: tenantId + - field: errorInformation + variableName: errorInformation + - field: clientCorrelationId + variableName: clientCorrelationId + - name: minimal_mock_fund_transfer_account_lookup + direction: OUTGOING + type: TRANSFER + transformers: + - field: amount + variableName: channelRequest + jsonPath: $.amount.amount + - field: currency + variableName: channelRequest + jsonPath: $.amount.currency + - field: payeePartyIdType + variableName: channelRequest + jsonPath: $.payee.partyIdInfo.partyIdType + - field: payeePartyId + variableName: channelRequest + jsonPath: $.payee.partyIdInfo.partyIdentifier + - field: payerPartyIdType + variableName: channelRequest + jsonPath: $.payer.partyIdInfo.partyIdType + - field: payerPartyId + variableName: channelRequest + jsonPath: $.payer.partyIdInfo.partyIdentifier + - field: transactionId + variableName: transactionId + - field: currency + variableName: currency + - field: batchId + variableName: batchId + - field: tenantId + variableName: tenantId + - field: errorInformation + variableName: errorInformation + - field: clientCorrelationId + variableName: clientCorrelationId + - field: payeeDfspId + variableName: partyLookupFspId + - name: payment_notification + direction: OUTGOING + type: TRANSFER + transformers: + - field: amount + variableName: amount + - field: payeePartyIdType + variableName: payeePartyIdType + - field: payeePartyId + variableName: payeePartyId + - field: payerPartyIdType + variableName: payerPartyIdType + - field: payerPartyId + variableName: payerPartyId + - field: transactionId + variableName: transactionId + - field: currency + variableName: currency + - field: batchId + variableName: batchId + - field: tenantId + variableName: tenantId + - field: errorInformation + variableName: errorInformation + - field: clientCorrelationId + variableName: clientCorrelationId + - name: bill_request + direction: INCOMING + type: TRANSACTION-REQUEST + transformers: + - field: transactionId + variableName: transactionId + - field: amount + variableName: billAmount + - field: payerDfspId + variableName: tenantId + - field: payeeDfspId + variableName: payeeDfspId + - field: clientCorrelationId + variableName: X-CorrelationID + - field: payeePartyIdType + variableName: payeePartyIdType + - field: payeePartyId + variableName: payeePartyId + - field: payerPartyIdType + variableName: payerPartyIdType + - field: payerPartyId + variableName: payerPartyId + - field: errorInformation + variableName: errorInformation + + diff --git a/ph-ee-importer-rdbms/src/main/resources/application-tenants.yml b/ph-ee-importer-rdbms/src/main/resources/application-tenants.yml new file mode 100644 index 000000000..c41b9c50f --- /dev/null +++ b/ph-ee-importer-rdbms/src/main/resources/application-tenants.yml @@ -0,0 +1,80 @@ +tenants: + connections: + - name: gorilla + schema_server: operationsmysql + schema_name: gorilla + schema_server_port: 3306 + schema_username: mifos + schema_password: password + driver_class: "com.mysql.cj.jdbc.Driver" + jdbcProtocol: "jdbc" + jdbcSubProtocol: mysql + auto_update: true + pool_initial_size: 5 + pool_validation_interval: 30000 + pool_remove_abandoned: 1 + pool_remove_abandoned_timeout: 60 + pool_log_abandoned: 1 + pool_abandon_when_percentage_full: 50 + pool_test_on_borrow: 1 + pool_max_active: 40 + pool_min_idle: 20 + pool_max_idle: 10 + pool_suspect_timeout: 60 + pool_time_between_eviction_runs_millis: 34000 + pool_min_evictable_idle_time_millis: 60000 + deadlock_max_retries: 0 + deadlock_max_retry_interval: 1 + schema_connection_parameters: + - name: rhino + schema_server: operationsmysql + schema_name: rhino + schema_server_port: 3306 + schema_username: mifos + schema_password: password + driver_class: "com.mysql.cj.jdbc.Driver" + jdbcProtocol: "jdbc" + jdbcSubProtocol: mysql + auto_update: true + pool_initial_size: 5 + pool_validation_interval: 30000 + pool_remove_abandoned: 1 + pool_remove_abandoned_timeout: 60 + pool_log_abandoned: 1 + pool_abandon_when_percentage_full: 50 + pool_test_on_borrow: 1 + pool_max_active: 40 + pool_min_idle: 20 + pool_max_idle: 10 + pool_suspect_timeout: 60 + pool_time_between_eviction_runs_millis: 34000 + pool_min_evictable_idle_time_millis: 60000 + deadlock_max_retries: 0 + deadlock_max_retry_interval: 1 + schema_connection_parameters: + - name: lion + schema_server: operationsmysql + schema_name: lion + schema_server_port: 3306 + schema_username: mifos + schema_password: password + driver_class: "com.mysql.cj.jdbc.Driver" + jdbcProtocol: "jdbc" + jdbcSubProtocol: mysql + auto_update: true + pool_initial_size: 5 + pool_validation_interval: 30000 + pool_remove_abandoned: 1 + pool_remove_abandoned_timeout: 60 + pool_log_abandoned: 1 + pool_abandon_when_percentage_full: 50 + pool_test_on_borrow: 1 + pool_max_active: 40 + pool_min_idle: 20 + pool_max_idle: 10 + pool_suspect_timeout: 60 + pool_time_between_eviction_runs_millis: 34000 + pool_min_evictable_idle_time_millis: 60000 + deadlock_max_retries: 0 + deadlock_max_retry_interval: 1 + schema_connection_parameters: \ No newline at end of file diff --git a/ph-ee-importer-rdbms/src/main/resources/application.yml b/ph-ee-importer-rdbms/src/main/resources/application.yml new file mode 100644 index 000000000..3d517cc12 --- /dev/null +++ b/ph-ee-importer-rdbms/src/main/resources/application.yml @@ -0,0 +1,65 @@ +kafka: + brokers: "kafka:9092" + consumer-group: ch1 +# To be used when auth is enabled in kafka +# username: "admin" +# password: "admin" + +importer: + kafka: + topic: "zeebe-export" + reset: true + aggreation-window-seconds: 2 + +spring: + profiles: + active: "local,tenants" + jpa: + show-sql: false + properties: + eclipselink: + logging: + level: "INFO" + parameters: true + session: true + thread: true + timestamp: true + logger: "hu.dpc.phee.operator.config.EclipselinkLogger" + open-in-view: false + +datasource: + common: + protocol: "jdbc" + subprotocol: "mysql" + driverclass_name: "com.mysql.cj.jdbc.Driver" + core: + port: 3306 + host: "operationsmysql" + schema: "tenants" + username: "mifos" + password: "password" + +server: + port: 8000 + +application: + bucket-name: paymenthub-ee + +cloud: + aws: + enabled: true + s3BaseUrl: "https://s3.ap-south-1.amazonaws.com" + credentials: + access-key: ${AWS_ACCESS_KEY:access_key_from_aws} + secret-key: ${AWS_SECRET_KEY:secret_key_from_aws} + region: + static: ap-south-1 + +logging: + level: + ROOT: INFO + pattern: + console: "%clr(%d{dd-MM-yyyy HH:mm:ss.SSS}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr([%35.35t]){faint} %clr(%-28.28logger{28}){cyan} %clr(:){faint}%X{BUSINESS-LOG} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}" + +reliability: + events-timestamps-dump-enabled: true \ No newline at end of file diff --git a/ph-ee-importer-rdbms/src/main/resources/kafka/kafka-streams-version.properties b/ph-ee-importer-rdbms/src/main/resources/kafka/kafka-streams-version.properties new file mode 100644 index 000000000..e69de29bb diff --git a/ph-ee-importer-rdbms/src/main/resources/logback.xml b/ph-ee-importer-rdbms/src/main/resources/logback.xml new file mode 100644 index 000000000..ed5361087 --- /dev/null +++ b/ph-ee-importer-rdbms/src/main/resources/logback.xml @@ -0,0 +1,41 @@ + + + + + + + + + ${CONSOLE_LOG_PATTERN} + utf8 + + + + + logs/console.log + + logs/console-%d{yyyy-MM-dd}.%i.log + 300MB + 3 + 950MB + + + ${CONSOLE_LOG_PATTERN} + utf8 + + + + + + + + + + + + + + + + diff --git a/ph-ee-importer-rdbms/src/main/resources/samples/payee-flow.log b/ph-ee-importer-rdbms/src/main/resources/samples/payee-flow.log new file mode 100644 index 000000000..0750bcdec --- /dev/null +++ b/ph-ee-importer-rdbms/src/main/resources/samples/payee-flow.log @@ -0,0 +1,99 @@ +### original process start ### +{"partitionId":1, +"value": +{ +"version":1, +"flowScopeKey":-1, +"bpmnElementType":"PROCESS", +"parentWorkflowInstanceKey":-1, +"parentElementInstanceKey":-1, +"workflowInstanceKey":2251799813686963, +"bpmnProcessId":"PayerFundTransfer-DFSPID", +"workflowKey":2251799813686925, +"elementId":"PayerFundTransfer-DFSPID" +}, +"sourceRecordPosition":4296365776, +"position":4296367480, +"key":2251799813686963, +"timestamp":1590762784476, +"valueType":"WORKFLOW_INSTANCE", +"recordType":"EVENT", +"rejectionType":"NULL_VAL", +"rejectionReason":"", +"intent":"ELEMENT_ACTIVATING" +} + +## variable inside call activity ### +{ +"partitionId":1, +"value": +{ +"name":"partyLookupFailed", +"value":"false", +"scopeKey":2251799813687036, +"workflowInstanceKey":2251799813687036, +"workflowKey":2251799813686943 +}, +"sourceRecordPosition":4296435464, +"position":4296436448, +"key":2251799813687037, +"timestamp":1590762798085, +"valueType":"VARIABLE", +"recordType":"EVENT", +"rejectionType":"NULL_VAL", +"rejectionReason":"", +"intent":"CREATED" +} + +### call activity start ### +{ +"partitionId":1, +"value": +{ +"version":1, +"flowScopeKey":-1, +"bpmnElementType":"PROCESS", +"parentWorkflowInstanceKey":2251799813686963, +"parentElementInstanceKey":2251799813687035, +"workflowInstanceKey":2251799813687036, +"bpmnProcessId":"transfer-process-DFSPID", +"workflowKey":2251799813686943, +"elementId":"transfer-processDFSPID" +}, +"sourceRecordPosition":4296435464, +"position":4296436120, +"key":2251799813687036, +"timestamp":1590762798085, +"valueType":"WORKFLOW_INSTANCE", +"recordType":"EVENT", +"rejectionType":"NULL_VAL", +"rejectionReason":"", +"intent":"ELEMENT_ACTIVATING" +} + +### deployment ### +{ +"partitionId":1, +"value": { +"resources": [{ +"resource":"---------", +"resourceName":"./orchestration/feel/transfer-process-DFSPID.bpmn", +"resourceType":"BPMN_XML" +}], +"deployedWorkflows": [{ +"version":1, +"resourceName":"./orchestration/feel/transfer-process-DFSPID.bpmn", +"bpmnProcessId":"transfer-process-tn02", +"workflowKey":2251799813688244 +}] +}, +"sourceRecordPosition":4299925008, +"position":4299964072, +"key":2251799813688245, +"timestamp":1591957096471, +"valueType":"DEPLOYMENT", +"rejectionType":"NULL_VAL", +"rejectionReason":"", +"intent":"CREATED", +"recordType":"EVENT" +} \ No newline at end of file diff --git a/ph-ee-importer-rdbms/src/test/java/hu/dpc/phee/operator/importer/FindBpmnProcessIdTest.java b/ph-ee-importer-rdbms/src/test/java/hu/dpc/phee/operator/importer/FindBpmnProcessIdTest.java new file mode 100644 index 000000000..7d4d1a776 --- /dev/null +++ b/ph-ee-importer-rdbms/src/test/java/hu/dpc/phee/operator/importer/FindBpmnProcessIdTest.java @@ -0,0 +1,50 @@ +package hu.dpc.phee.operator.importer; + +import com.jayway.jsonpath.DocumentContext; +import com.jayway.jsonpath.JsonPath; +import org.junit.jupiter.api.Test; + +import java.util.List; + +public class FindBpmnProcessIdTest { + String json = "{\n" + + " \"partitionId\": 1,\n" + + " \"value\": {\n" + + " \"resources\": [\n" + + " {\n" + + " \"resource\": \"cz4K\",\n" + + " \"resourceName\": \"ig2-incoming-recall.bpmn\"\n" + + " }\n" + + " ],\n" + + " \"processesMetadata\": [\n" + + " {\n" + + " \"version\": 17,\n" + + " \"checksum\": \"jtjo2yfFuJ94yDTFzFH5RA==\",\n" + + " \"bpmnProcessId\": \"binx_ig2_incoming_recall-binx\",\n" + + " \"duplicate\": false,\n" + + " \"processDefinitionKey\": 2251799837455793,\n" + + " \"resourceName\": \"ig2-incoming-recall.bpmn\"\n" + + " }\n" + + " ],\n" + + " \"decisionsMetadata\": [],\n" + + " \"decisionRequirementsMetadata\": []\n" + + " },\n" + + " \"key\": 2251799837455794,\n" + + " \"timestamp\": 1687446188134,\n" + + " \"position\": 47500976,\n" + + " \"valueType\": \"DEPLOYMENT\",\n" + + " \"brokerVersion\": \"8.2.2\",\n" + + " \"recordType\": \"EVENT\",\n" + + " \"sourceRecordPosition\": 47500974,\n" + + " \"intent\": \"CREATED\",\n" + + " \"rejectionType\": \"NULL_VAL\",\n" + + " \"rejectionReason\": \"\"\n" + + "}"; + + @Test + public void test() { + DocumentContext record = JsonPath.parse(json); + List bpmnProcessId = record.read("$.value..bpmnProcessId", List.class); + System.out.println(bpmnProcessId.get(0)); + } +} diff --git a/ph-ee-importer-rdbms/src/test/java/hu/dpc/phee/operator/importer/JsonParseTest.java b/ph-ee-importer-rdbms/src/test/java/hu/dpc/phee/operator/importer/JsonParseTest.java new file mode 100644 index 000000000..1d01290dd --- /dev/null +++ b/ph-ee-importer-rdbms/src/test/java/hu/dpc/phee/operator/importer/JsonParseTest.java @@ -0,0 +1,149 @@ +package hu.dpc.phee.operator.importer; + +import com.jayway.jsonpath.*; +import hu.dpc.phee.operator.entity.task.Task; +import org.apache.kafka.clients.producer.KafkaProducer; +import org.apache.kafka.clients.producer.ProducerConfig; +import org.apache.kafka.clients.producer.ProducerRecord; +import org.apache.kafka.common.serialization.StringSerializer; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; + +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +public class JsonParseTest { + + String taskCreated = "{\n" + + " \"partitionId\": 3,\n" + + " \"sourceRecordPosition\": 12885411520,\n" + + " \"recordType\": \"EVENT\",\n" + + " \"valueType\": \"WORKFLOW_INSTANCE\",\n" + + " \"position\": 12885411896,\n" + + " \"rejectionType\": \"NULL_VAL\",\n" + + " \"rejectionReason\": \"\",\n" + + " \"value\": {\n" + + " \"elementId\": \"Task_1lfzg19\",\n" + + " \"variables\": {},\n" + + " \"errorMessage\": \"\",\n" + + " \"errorCode\": \"\",\n" + + " \"type\": \"payee-party-lookup-DFSPID\",\n" + + " \"retries\": 3,\n" + + " \"elementInstanceKey\": 6755399441058323,\n" + + " \"workflowKey\": 2251799813687425,\n" + + " \"workflowInstanceKey\": 6755399441058311,\n" + + " \"bpmnProcessId\": \"PayeePartyLookup-tn01\",\n" + + " \"deadline\": -1,\n" + + " \"worker\": \"\",\n" + + " \"customHeaders\": {},\n" + + " \"workflowDefinitionVersion\": 1\n" + + " },\n" + + " \"intent\": \"CREATED\",\n" + + " \"key\": 6755399441058324,\n" + + " \"timestamp\": 1586104064972\n" + + "}"; + + String processActivating = "{\"partitionId\":1,\n" + + "\"value\":\n" + + "{\n" + + "\"version\":1,\n" + + "\"flowScopeKey\":-1,\n" + + "\"bpmnElementType\":\"PROCESS\",\n" + + "\"parentWorkflowInstanceKey\":-1,\n" + + "\"parentElementInstanceKey\":-1,\n" + + "\"workflowInstanceKey\":2251799813686963,\n" + + "\"bpmnProcessId\":\"PayerFundTransfer-tn01\",\n" + + "\"workflowKey\":2251799813686925,\n" + + "\"elementId\":\"PayerFundTransfer-tn01\"\n" + + "},\n" + + "\"sourceRecordPosition\":4296365776,\n" + + "\"position\":4296367480,\n" + + "\"key\":2251799813686963,\n" + + "\"timestamp\":1590762784476,\n" + + "\"valueType\":\"WORKFLOW_INSTANCE\",\n" + + "\"recordType\":\"EVENT\",\n" + + "\"rejectionType\":\"NULL_VAL\",\n" + + "\"rejectionReason\":\"\",\n" + + "\"intent\":\"ELEMENT_ACTIVATING\"\n" + + "}"; + + String deployment = "{\n" + + "\"partitionId\":1,\n" + + "\"value\":\n" + + "{\n" + + "\"resources\":\n" + + "[{\n" + + "\"resource\":\"---------\",\n" + + "\"resourceName\":\"./orchestration/feel/transfer-process-DFSPID.bpmn\",\n" + + "\"resourceType\":\"BPMN_XML\"\n" + + "}],\n" + + "\"deployedWorkflows\":\n" + + "[{\n" + + "\"version\":1,\n" + + "\"resourceName\":\"./orchestration/feel/transfer-process-DFSPID.bpmn\",\n" + + "\"bpmnProcessId\":\"transfer-process-tn02\",\n" + + "\"workflowKey\":2251799813688244\n" + + "}]\n" + + "},\n" + + "\"sourceRecordPosition\":4299925008,\n" + + "\"position\":4299964072,\n" + + "\"key\":2251799813688245,\n" + + "\"timestamp\":1591957096471,\n" + + "\"valueType\":\"DEPLOYMENT\",\n" + + "\"rejectionType\":\"NULL_VAL\",\n" + + "\"rejectionReason\":\"\",\n" + + "\"intent\":\"CREATED\",\n" + + "\"recordType\":\"EVENT\"\n" + + "}"; + + String variableCreated = "{\n" + + " \"partitionId\": 3,\n" + + " \"sourceRecordPosition\": 12885411520,\n" + + " \"recordType\": \"EVENT\",\n" + + " \"valueType\": \"VARIABLE\",\n" + + " \"position\": 12885411896,\n" + + " \"rejectionType\": \"NULL_VAL\",\n" + + " \"rejectionReason\": \"\",\n" + + " \"value\": {\n" + + " \"name\": \"transactionId\",\n" + + " \"value\": \"abc-123-def-456\",\n" + + " \"workflowKey\": 2251799813687425,\n" + + " \"workflowInstanceKey\": 6755399441058311,\n" + + " \"scopeKey\": 6755399441058311,\n" + + " },\n" + + " \"intent\": \"CREATED\",\n" + + " \"key\": 6755399441058324,\n" + + " \"timestamp\": 1586104064972\n" + + "}"; + + @Test + public void test() { + Configuration config = Configuration.defaultConfiguration() + .addOptions(Option.DEFAULT_PATH_LEAF_TO_NULL) + .addOptions(Option.SUPPRESS_EXCEPTIONS); + ParseContext jsonParser = JsonPath.using(config); + + DocumentContext doc = jsonParser.parse(taskCreated); + Object read = doc.read("$.value.bpmnProcessId"); + Task task = new Task(); + task.setWorkflowKey(doc.read("$.value.workflowKey")); + task.setWorkflowInstanceKey(doc.read("$.value.workflowInstanceKey")); + System.out.println(task); + } + + @Test + @Disabled + public void testSendKafkaMessage() { + Map kafkaProperties = new HashMap<>(); + + kafkaProperties.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, "localhost:9092"); + kafkaProperties.put(ProducerConfig.CLIENT_ID_CONFIG, UUID.randomUUID().toString()); + kafkaProperties.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class.getName()); + kafkaProperties.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, StringSerializer.class.getName()); + KafkaProducer producer = new KafkaProducer<>(kafkaProperties); + + producer.send(new ProducerRecord<>("zeebe-export", "0-1", processActivating)); + producer.flush(); + } +} \ No newline at end of file diff --git a/ph-ee-importer-rdbms/src/test/java/hu/dpc/phee/operator/importer/KafkaSender.java b/ph-ee-importer-rdbms/src/test/java/hu/dpc/phee/operator/importer/KafkaSender.java new file mode 100644 index 000000000..c4045ee70 --- /dev/null +++ b/ph-ee-importer-rdbms/src/test/java/hu/dpc/phee/operator/importer/KafkaSender.java @@ -0,0 +1,57 @@ +package hu.dpc.phee.operator.importer; + +import org.apache.kafka.clients.producer.KafkaProducer; +import org.apache.kafka.clients.producer.ProducerRecord; +import org.junit.jupiter.api.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.List; +import java.util.Properties; +import java.util.stream.Stream; + +public class KafkaSender { + private Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Test + public void test() { + Properties config = new Properties(); + config.put("bootstrap.servers", "localhost:9092"); + config.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer"); + config.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer"); + + KafkaProducer producer = new KafkaProducer<>(config); + int oneKey = (int) (Math.random() * 1000000); + int otherKey = (int) (Math.random() * 1000000); + List> records = Stream.of( + new ProducerRecord<>("zeebe-export", "key-" + oneKey, "{\"test\": \"1a\"}"), + null, + new ProducerRecord<>("zeebe-export", "key-" + otherKey, "{\"test\": \"2a\"}"), +// null, + new ProducerRecord<>("zeebe-export", "key-" + oneKey, "{\"test\": \"3a\"}"), + new ProducerRecord<>("zeebe-export", "key-" + oneKey, "{\"test\": \"4a\"}"), +// null, + new ProducerRecord<>("zeebe-export", "key-" + otherKey, "{\"test\": \"5a\"}") + ).toList(); + + for (ProducerRecord record : records) { + if (record == null) { + sleep(); + } else { + logger.debug("sending record: {}", record); + producer.send(record); + } + } + producer.close(); + logger.info("records sent"); + } + + private void sleep() { + try { + logger.debug("sleeping.."); + Thread.sleep(3600); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } +} diff --git a/ph-ee-importer-rdbms/src/test/resources/event-samples/incident/1.json b/ph-ee-importer-rdbms/src/test/resources/event-samples/incident/1.json new file mode 100644 index 000000000..ed97ee813 --- /dev/null +++ b/ph-ee-importer-rdbms/src/test/resources/event-samples/incident/1.json @@ -0,0 +1,24 @@ +{ + "partitionId": 1, + "value": { + "errorMessage": "org.springframework.web.client.HttpClientErrorException$BadRequest: 400 : \"{\"developerMessage\":\"The request was invalid. This typically will happen due to validation errors which are provided.\",\"httpStatusCode\":\"400\",\"defaultUserMessage\":\"Validation errors exist.\",\"userMessageGlobalisationCode\":\"validation.msg.validation.errors.exist\",\"errors\":[{\"developerMessage\":\"The parameter `transactionAmount` must be greater than 0.\",\"defaultUserMessage\":\"The parameter `transactionAmount` must be greater than 0.\",\"userMessageGlobalisationCode\":\"validation.msg.savingsaccount.transaction.transactionAmount.not.greater.than.zero\",\"parameterName\":\"transactionAmount\",\"value\":null,\"args\":[{\"value\":0.0},{\"value\":0}]}]}\"", + "processDefinitionKey": 2251799813685862, + "elementInstanceKey": 2251799817574397, + "elementId": "Activity_TransferTheAmountBetweenDisposalAccounts", + "bpmnProcessId": "binx_onus_credit_transfer", + "jobKey": 2251799817574405, + "variableScopeKey": 2251799817574397, + "errorType": "JOB_NO_RETRIES", + "processInstanceKey": 2251799817574322 + }, + "key": 2251799817574407, + "timestamp": 1680775431139, + "valueType": "INCIDENT", + "brokerVersion": "8.1.8", + "recordType": "EVENT", + "sourceRecordPosition": 8325545, + "intent": "RESOLVED", + "rejectionType": "NULL_VAL", + "rejectionReason": "", + "position": 8325548 +} diff --git a/ph-ee-importer-rdbms/src/test/resources/event-samples/job/1.json b/ph-ee-importer-rdbms/src/test/resources/event-samples/job/1.json new file mode 100644 index 000000000..62d6260fd --- /dev/null +++ b/ph-ee-importer-rdbms/src/test/resources/event-samples/job/1.json @@ -0,0 +1,31 @@ +{ + "partitionId": 3, + "value": { + "type": "transferToConversionAccountInAms", + "errorMessage": "", + "retries": 3, + "retryBackoff": 0, + "recurringTime": -1, + "processDefinitionVersion": 2, + "processDefinitionKey": 2251799816094393, + "elementInstanceKey": 6755399445221901, + "elementId": "Activity_TransferToCenversionAccountInAms", + "customHeaders": {}, + "bpmnProcessId": "binx_ig2_credit_transfer_debtor_process-binx", + "variables": {}, + "deadline": -1, + "processInstanceKey": 6755399445221857, + "worker": "", + "errorCode": "" + }, + "key": 6755399445221909, + "timestamp": 1680776111668, + "valueType": "JOB", + "brokerVersion": "8.1.8", + "recordType": "EVENT", + "sourceRecordPosition": 8329782, + "intent": "CREATED", + "rejectionType": "NULL_VAL", + "rejectionReason": "", + "position": 8329791 +} diff --git a/ph-ee-importer-rdbms/src/test/resources/event-samples/process_instance/1.json b/ph-ee-importer-rdbms/src/test/resources/event-samples/process_instance/1.json new file mode 100644 index 000000000..6e6c6c218 --- /dev/null +++ b/ph-ee-importer-rdbms/src/test/resources/event-samples/process_instance/1.json @@ -0,0 +1,24 @@ +{ + "partitionId": 2, + "value": { + "version": 2, + "processDefinitionKey": 2251799816094393, + "elementId": "Flow_1uam7ja", + "bpmnProcessId": "binx_ig2_credit_transfer_debtor_process-binx", + "flowScopeKey": 4503599631529096, + "bpmnElementType": "SEQUENCE_FLOW", + "parentProcessInstanceKey": -1, + "parentElementInstanceKey": -1, + "processInstanceKey": 4503599631529096 + }, + "key": 4503599631529139, + "timestamp": 1680776111962, + "valueType": "PROCESS_INSTANCE", + "brokerVersion": "8.1.8", + "recordType": "EVENT", + "sourceRecordPosition": 8315094, + "intent": "SEQUENCE_FLOW_TAKEN", + "rejectionType": "NULL_VAL", + "rejectionReason": "", + "position": 8315115 +} diff --git a/ph-ee-importer-rdbms/src/test/resources/event-samples/process_instance/2.json b/ph-ee-importer-rdbms/src/test/resources/event-samples/process_instance/2.json new file mode 100644 index 000000000..3e6a52986 --- /dev/null +++ b/ph-ee-importer-rdbms/src/test/resources/event-samples/process_instance/2.json @@ -0,0 +1,24 @@ +{ + "partitionId": 2, + "value": { + "version": 2, + "processDefinitionKey": 2251799816094393, + "elementId": "Activity_GetAccountIdsFromAms", + "bpmnProcessId": "binx_ig2_credit_transfer_debtor_process-binx", + "flowScopeKey": 4503599631529096, + "bpmnElementType": "SERVICE_TASK", + "parentProcessInstanceKey": -1, + "parentElementInstanceKey": -1, + "processInstanceKey": 4503599631529096 + }, + "key": 4503599631529114, + "timestamp": 1680776111910, + "valueType": "PROCESS_INSTANCE", + "brokerVersion": "8.1.8", + "recordType": "EVENT", + "sourceRecordPosition": 8315079, + "intent": "ELEMENT_ACTIVATING", + "rejectionType": "NULL_VAL", + "rejectionReason": "", + "position": 8315080 +} diff --git a/ph-ee-importer-rdbms/src/test/resources/event-samples/process_instance/3.json b/ph-ee-importer-rdbms/src/test/resources/event-samples/process_instance/3.json new file mode 100644 index 000000000..478503f8a --- /dev/null +++ b/ph-ee-importer-rdbms/src/test/resources/event-samples/process_instance/3.json @@ -0,0 +1,24 @@ +{ + "partitionId": 2, + "value": { + "version": 2, + "processDefinitionKey": 2251799816094393, + "elementId": "Activity_GetAccountIdsFromAms", + "bpmnProcessId": "binx_ig2_credit_transfer_debtor_process-binx", + "flowScopeKey": 4503599631529096, + "bpmnElementType": "SERVICE_TASK", + "parentProcessInstanceKey": -1, + "parentElementInstanceKey": -1, + "processInstanceKey": 4503599631529096 + }, + "key": 4503599631529114, + "timestamp": 1680776111962, + "valueType": "PROCESS_INSTANCE", + "brokerVersion": "8.1.8", + "recordType": "EVENT", + "sourceRecordPosition": 8315094, + "intent": "ELEMENT_COMPLETED", + "rejectionType": "NULL_VAL", + "rejectionReason": "", + "position": 8315114 +} diff --git a/ph-ee-importer-rdbms/src/test/resources/event-samples/process_instance/process_activated.json b/ph-ee-importer-rdbms/src/test/resources/event-samples/process_instance/process_activated.json new file mode 100644 index 000000000..a27ce2e43 --- /dev/null +++ b/ph-ee-importer-rdbms/src/test/resources/event-samples/process_instance/process_activated.json @@ -0,0 +1,24 @@ +{ + "partitionId": 1, + "value": { + "version": 3, + "processDefinitionKey": 2251799815420374, + "elementId": "binx_hct_inst_credit_transfer_debtor_process-binx", + "bpmnProcessId": "binx_hct_inst_credit_transfer_debtor_process-binx", + "flowScopeKey": -1, + "bpmnElementType": "PROCESS", + "parentProcessInstanceKey": -1, + "parentElementInstanceKey": -1, + "processInstanceKey": 2251799819651146 + }, + "key": 2251799819651146, + "timestamp": 1681402193759, + "valueType": "PROCESS_INSTANCE", + "brokerVersion": "8.1.8", + "recordType": "EVENT", + "sourceRecordPosition": 11927641, + "intent": "ELEMENT_ACTIVATED", + "rejectionType": "NULL_VAL", + "rejectionReason": "", + "position": 11927644 +} diff --git a/ph-ee-importer-rdbms/src/test/resources/event-samples/process_instance/process_completed.json b/ph-ee-importer-rdbms/src/test/resources/event-samples/process_instance/process_completed.json new file mode 100644 index 000000000..813839ce7 --- /dev/null +++ b/ph-ee-importer-rdbms/src/test/resources/event-samples/process_instance/process_completed.json @@ -0,0 +1,24 @@ +{ + "partitionId": 1, + "value": { + "version": 3, + "processDefinitionKey": 2251799815420374, + "elementId": "binx_hct_inst_credit_transfer_debtor_process-binx", + "bpmnProcessId": "binx_hct_inst_credit_transfer_debtor_process-binx", + "flowScopeKey": -1, + "bpmnElementType": "PROCESS", + "parentProcessInstanceKey": -1, + "parentElementInstanceKey": -1, + "processInstanceKey": 2251799819651146 + }, + "key": 2251799819651146, + "timestamp": 1681402195934, + "valueType": "PROCESS_INSTANCE", + "brokerVersion": "8.1.8", + "recordType": "EVENT", + "sourceRecordPosition": 11927865, + "intent": "ELEMENT_COMPLETED", + "rejectionType": "NULL_VAL", + "rejectionReason": "", + "position": 11927867 +} diff --git a/ph-ee-importer-rdbms/src/test/resources/event-samples/variable/1.json b/ph-ee-importer-rdbms/src/test/resources/event-samples/variable/1.json new file mode 100644 index 000000000..7f9739947 --- /dev/null +++ b/ph-ee-importer-rdbms/src/test/resources/event-samples/variable/1.json @@ -0,0 +1,21 @@ +{ + "partitionId": 2, + "value": { + "name": "currency", + "value": "\"HUF\"", + "processDefinitionKey": 2251799816094393, + "bpmnProcessId": "binx_ig2_credit_transfer_debtor_process-binx", + "scopeKey": 4503599631529114, + "processInstanceKey": 4503599631529096 + }, + "key": 4503599631529126, + "timestamp": 1680776111962, + "valueType": "VARIABLE", + "brokerVersion": "8.1.8", + "recordType": "EVENT", + "sourceRecordPosition": 8315094, + "intent": "CREATED", + "rejectionType": "NULL_VAL", + "rejectionReason": "", + "position": 8315101 +} \ No newline at end of file diff --git a/ph-ee-importer-rdbms/start-local-mysql.sh b/ph-ee-importer-rdbms/start-local-mysql.sh new file mode 100644 index 000000000..a747b9c18 --- /dev/null +++ b/ph-ee-importer-rdbms/start-local-mysql.sh @@ -0,0 +1 @@ +docker run -it -e MYSQL_ROOT_PASSWORD=a -e MYSQL_USER=mifos -e MYSQL_PASSWORD=password -e MYSQL_DATABASE=operator -p3306:3306 mysql diff --git a/ph-ee-integration-test/.circleci/config.yml b/ph-ee-integration-test/.circleci/config.yml new file mode 100644 index 000000000..44b00abd7 --- /dev/null +++ b/ph-ee-integration-test/.circleci/config.yml @@ -0,0 +1,479 @@ +version: 2.1 +orbs: + slack: circleci/slack@4.12.5 + aws-ecr: circleci/aws-ecr@8.2.1 + helm: circleci/helm@2.0.1 + aws-eks: circleci/aws-eks@2.2.0 + kubernetes: circleci/kubernetes@1.3 + fynarfin-orb: fynarfin/docker-image-availability-check-and-upgrade@1.0.2 +executors: + docker-executor: + docker: + - image: circleci/openjdk:17-buster-node-browsers-legacy +jobs: + build: + docker: + - image: cimg/openjdk:17.0.0-node + - image: docker:17.05.0-ce-git + working_directory: ~/repo + environment: + JVM_OPTS: -Xmx512m + TERM: dumb + steps: + - checkout + - setup_remote_docker + - aws-ecr/build-and-push-image: + aws-access-key-id: AWS_ACCESS_KEY_ID + aws-secret-access-key: AWS_SECRET_ACCESS_KEY + extra-build-args: "--compress" + push-image: true + region: "$REGION" + registry-id: AWS_REGISTRY_ID + repo: phee-integration-test + repo-scan-on-push: true + role-arn: arn:aws:iam::419830066942:role/CustomAdmin + tag: latest + + build_and_push_tag_image: + executor: docker-executor + environment: + JVM_OPTS: -Xmx512m + TERM: dumb + GITHUB_TOKEN: ${GITHUB_TOKEN} # Add the GitHub token as an environment variable + steps: + - checkout + - setup_remote_docker: + version: 20.10.24 + - run: + name: Build and Push Docker tag Image + command: | + # Set environment variables + IMAGE_TAG=$CIRCLE_TAG + + # Check if the Docker image with the same tag already exists in Docker Hub + if curl -s -f -u "$DOCKERHUB_USERNAME":"$DOCKERHUB_PASSWORD" "https://hub.docker.com/v2/repositories/fynarfin/ph-ee-integration-test/tags/$IMAGE_TAG" > /dev/null; then + echo "Skipping the build and push as the tag $IMAGE_TAG already exists in Docker Hub." + exit 0 + fi + + # Build and tag the Docker image + ./gradlew bootJar + docker build -t "fynarfin/ph-ee-integration-test:$IMAGE_TAG" . + + # Push the Docker image to Docker Hub + docker login -u "$DOCKERHUB_USERNAME" -p "$DOCKERHUB_PASSWORD" + docker push "fynarfin/ph-ee-integration-test:$IMAGE_TAG" + + # when: always # The job will be executed even if there's no match for the tag filter + + build_and_push_latest_image: + executor: docker-executor + environment: + JVM_OPTS: -Xmx512m + TERM: dumb + steps: + - checkout + # Install Docker to build and push the image + - setup_remote_docker: + version: 20.10.24 + + # Build the Docker image + - run: + name: Build Docker image + command: | + ./gradlew checkstyleMain + ./gradlew checkstyleTest + ./gradlew bootJar + docker build -t fynarfin/ph-ee-integration-test:latest . + if [ "$CIRCLE_BRANCH" != "develop" ]; then + PR_NUMBER=$(basename $CIRCLE_PULL_REQUEST) + PR_TITLE=$(curl -sSL "https://api.github.com/repos/fynarfin/$CIRCLE_PROJECT_REPONAME/pulls/$PR_NUMBER" | jq -r '.title') + JIRA_STORY=$(echo $PR_TITLE | cut -d "[" -f2 | cut -d "]" -f1 | tr '[A-Z]' '[a-z]') + if [ -z "$JIRA_STORY" ]; then echo "Invalid PR title" && exit 1; else echo "Ticket NO: $JIRA_STORY"; fi + docker image tag fynarfin/ph-ee-integration-test:latest fynarfin/ph-ee-integration-test:$JIRA_STORY + fi + + # Log in to DockerHub using environment variables + - run: + name: Login to DockerHub + command: echo "${DOCKERHUB_PASSWORD}" | docker login -u "${DOCKERHUB_USERNAME}" --password-stdin + + # Push the Docker image to DockerHub + - run: + name: Push Docker image to DockerHub + command: | + if [ "$CIRCLE_BRANCH" = "develop" ]; then + docker push fynarfin/ph-ee-integration-test:latest + fi + if [ "$CIRCLE_BRANCH" != "develop" ]; then + PR_NUMBER=$(basename $CIRCLE_PULL_REQUEST) + PR_TITLE=$(curl -sSL "https://api.github.com/repos/fynarfin/$CIRCLE_PROJECT_REPONAME/pulls/$PR_NUMBER" | jq -r '.title') + JIRA_STORY=$(echo $PR_TITLE | cut -d "[" -f2 | cut -d "]" -f1 | tr '[A-Z]' '[a-z]') + docker push fynarfin/ph-ee-integration-test:${JIRA_STORY} + fi + docker-image-availability-check-and-upgrade: + docker: + - image: 'cimg/python:3.10' + steps: + - fynarfin-orb/docker-image-availability-check-and-upgrade: + namespace: paymenthub + chart-base-url: https://fynarfin.io/images/fynarfin + chart-name: ph-ee-g2psandbox-fynarfin + chart-version: 0.2.0 + release-name: g2p-sandbox + cluster-name: "sit" + aws-region: "$REGION" + service-file-path: https://raw.githubusercontent.com/fynarfin/ph-ee-env-labs/develop/.circleci/services.txt + + create-tls-secret-paymenthub-namespace: + docker: + - image: 'cimg/base:2022.06' + environment: + TERM: dumb + NAMESPACE: paymenthub + steps: + - setup_remote_docker: + version: 20.10.24 + - kubernetes/install-kubectl + - aws-eks/update-kubeconfig-with-authenticator: + cluster-name: "sit" + aws-region: "$REGION" + - run: | + echo "$KEY" | tr '#' '\n' > key.pem + echo "$SSL_BUNDLE" | tr '#' '\n' > ssl-bundle.crt + openssl x509 -in ssl-bundle.crt -text -noout + if kubectl get secret fyn-cert --namespace $NAMESPACE &> /dev/null; then + echo "Secret fyn-cert already exists. Skipping creation." + else + kubectl create secret tls fyn-cert --namespace $NAMESPACE --key=key.pem --cert=ssl-bundle.crt -o yaml + fi + + create-secret-paymenthub-namespace: + docker: + - image: 'cimg/base:2022.06' + environment: + TERM: dumb + NAMESPACE: paymenthub + steps: + - setup_remote_docker: + version: 20.10.14 + - kubernetes/install-kubectl + - run: git clone https://github.com/fynarfin/ph-ee-env-labs + - aws-eks/update-kubeconfig-with-authenticator: + cluster-name: "sit" + aws-region: "$REGION" + - run: | + cd ph-ee-env-labs + export ENV_NAMESPACE=$NAMESPACE + kubectl config use-context arn:aws:eks:$REGION:419830066942:cluster/sit + kubectl config get-contexts + cd helm/kibana-secret/ + make secrets || echo "kibana" already exists + + - run: | + cd ph-ee-env-labs + export ENV_NAMESPACE=$NAMESPACE + kubectl config use-context arn:aws:eks:$REGION:419830066942:cluster/sit + kubectl config get-contexts + cd helm/es-secret/ + make secrets || echo "elastic-certificates" already exists + + - run: "kubectl delete pod -n $NAMESPACE `kubectl get pods -n $NAMESPACE | grep ph-ee-connector-bulk|cut -d ' ' -f1 ` || echo ' ' " + - run: "kubectl delete pod -n $NAMESPACE `kubectl get pods -n $NAMESPACE | grep ph-ee-connector-mock-payment-schema|cut -d ' ' -f1 ` || echo ' ' " + - run: "kubectl delete pod -n $NAMESPACE `kubectl get pods -n $NAMESPACE | grep ph-ee-importer-rdbms|cut -d ' ' -f1 ` || echo ' ' " + - run: "kubectl delete pod -n $NAMESPACE `kubectl get pods -n $NAMESPACE | grep ph-ee-vouchers|cut -d ' ' -f1 ` || echo ' ' " + + deploying-bpmns: + docker: + - image: 'cimg/base:2022.06' + steps: + - run: git clone https://github.com/fynarfin/ph-ee-env-labs + - run: echo $AWS_PROFILE + - run: echo $AWS_DEFAULT_PROFILE + - run: | + #sleep 5 + #sudo apt install -y netcat + #until nc -vz https://zeebeops.sandbox.fynarfin.io 443; do echo "Waiting for zeebe-ops service"; sleep 2; done; + - run: | + cd ph-ee-env-labs + sh orchestration/deployBpmn.sh + test-chart-gov: + docker: + - image: cimg/openjdk:17.0.0-node + steps: + - checkout + #- run: git clone https://github.com/fynarfin/ph-ee-integration-test + - run: + name: Ngrok setup + command: curl -s https://ngrok-agent.s3.amazonaws.com/ngrok.asc | sudo tee /etc/apt/trusted.gpg.d/ngrok.asc >/dev/null && echo "deb https://ngrok-agent.s3.amazonaws.com buster main" | sudo tee /etc/apt/sources.list.d/ngrok.list && sudo apt update && sudo apt install ngrok + - run: + name: Test execution + no_output_timeout: 30m + command: | + ngrok config add-authtoken $AUTH_TOKEN + echo "web_addr: $LOCAL_PORT" >> /home/circleci/.config/ngrok/ngrok.yml + ngrok http 53013 > /dev/null & + echo -n "Extracting ngrok public url ." + NGROK_PUBLIC_URL="" + while [ -z "$NGROK_PUBLIC_URL" ]; do + # Run 'curl' against ngrok API and extract public (using 'sed' command) + export NGROK_PUBLIC_URL=$(curl --silent --max-time 10 --connect-timeout 5 \ + --show-error http://127.0.0.1:$LOCAL_PORT/api/tunnels | \ + sed -nE 's/.*public_url":"https:..([^"]*).*/\1/p') + sleep 1 + echo -n "." + done + + export CALLBACK_URL="https://$NGROK_PUBLIC_URL" + echo -n "Public url ." + echo $CALLBACK_URL + ./gradlew test -Dcucumber.filter.tags="@gov and not @common and not @commonExtended" + echo -n "Test execution is completed, kill ngrok" + pkill ngrok + - store_test_results: + path: build/test-results/test/TEST-org.fynarfin.integrationtest.TestRunner.xml + - store_artifacts: + path: build/test-results + + test-chart-e2e: + docker: + - image: cimg/openjdk:17.0.0-node + steps: + - checkout + #- run: git clone https://github.com/fynarfin/ph-ee-integration-test + - run: + name: Ngrok setup + command: curl -s https://ngrok-agent.s3.amazonaws.com/ngrok.asc | sudo tee /etc/apt/trusted.gpg.d/ngrok.asc >/dev/null && echo "deb https://ngrok-agent.s3.amazonaws.com buster main" | sudo tee /etc/apt/sources.list.d/ngrok.list && sudo apt update && sudo apt install ngrok + - run: + name: Test execution + no_output_timeout: 30m + command: | + ngrok config add-authtoken $AUTH_TOKEN + echo "web_addr: $LOCAL_PORT" >> /home/circleci/.config/ngrok/ngrok.yml + ngrok http 53013 > /dev/null & + echo -n "Extracting ngrok public url ." + NGROK_PUBLIC_URL="" + while [ -z "$NGROK_PUBLIC_URL" ]; do + # Run 'curl' against ngrok API and extract public (using 'sed' command) + export NGROK_PUBLIC_URL=$(curl --silent --max-time 10 --connect-timeout 5 \ + --show-error http://127.0.0.1:$LOCAL_PORT/api/tunnels | \ + sed -nE 's/.*public_url":"https:..([^"]*).*/\1/p') + sleep 1 + echo -n "." + done + + export CALLBACK_URL="https://$NGROK_PUBLIC_URL" + echo -n "Public url ." + echo $CALLBACK_URL + ./gradlew test -Dcucumber.filter.tags="@e2e" + echo -n "Test execution is completed, kill ngrok" + pkill ngrok + - store_test_results: + path: build/test-results/test/TEST-org.fynarfin.integrationtest.TestRunner.xml + - store_artifacts: + path: build/test-results + + test-chart-ams: + docker: + - image: cimg/openjdk:17.0.0 + steps: + - checkout + #- run: git clone https://github.com/fynarfin/ph-ee-integration-test + - run: + name: Ngrok setup + command: curl -s https://ngrok-agent.s3.amazonaws.com/ngrok.asc | sudo tee /etc/apt/trusted.gpg.d/ngrok.asc >/dev/null && echo "deb https://ngrok-agent.s3.amazonaws.com buster main" | sudo tee /etc/apt/sources.list.d/ngrok.list && sudo apt update && sudo apt install ngrok + - run: + name: Test execution + no_output_timeout: 30m + command: | + ngrok config add-authtoken $AUTH_TOKEN + echo "web_addr: $LOCAL_PORT" >> /home/circleci/.config/ngrok/ngrok.yml + ngrok http 53013 > /dev/null & + echo -n "Extracting ngrok public url ." + NGROK_PUBLIC_URL="" + while [ -z "$NGROK_PUBLIC_URL" ]; do + # Run 'curl' against ngrok API and extract public (using 'sed' command) + export NGROK_PUBLIC_URL=$(curl --silent --max-time 10 --connect-timeout 5 \ + --show-error http://127.0.0.1:$LOCAL_PORT/api/tunnels | \ + sed -nE 's/.*public_url":"https:..([^"]*).*/\1/p') + sleep 1 + echo -n "." + done + + export CALLBACK_URL="https://$NGROK_PUBLIC_URL" + echo -n "Public url ." + echo $CALLBACK_URL + ./gradlew test -Dcucumber.filter.tags="@amsIntegration and not @common and not @commonExtended" + echo -n "Test execution is completed, kill ngrok" + pkill ngrok + - store_test_results: + path: build/test-results/test/TEST-org.fynarfin.integrationtest.TestRunner.xml + - store_artifacts: + path: build/test-results + test-chart-common: + docker: + - image: cimg/openjdk:17.0.0 + steps: + - checkout + #- run: git clone https://github.com/openmf/ph-ee-integration-test + - run: + name: Ngrok setup + command: curl -s https://ngrok-agent.s3.amazonaws.com/ngrok.asc | sudo tee /etc/apt/trusted.gpg.d/ngrok.asc >/dev/null && echo "deb https://ngrok-agent.s3.amazonaws.com buster main" | sudo tee /etc/apt/sources.list.d/ngrok.list && sudo apt update && sudo apt install ngrok + - run: + name: Test execution + no_output_timeout: 30m + command: | + ngrok config add-authtoken $AUTH_TOKEN + echo "web_addr: $LOCAL_PORT" >> /home/circleci/.config/ngrok/ngrok.yml + ngrok http 53013 > /dev/null & + echo -n "Extracting ngrok public url ." + NGROK_PUBLIC_URL="" + while [ -z "$NGROK_PUBLIC_URL" ]; do + # Run 'curl' against ngrok API and extract public (using 'sed' command) + export NGROK_PUBLIC_URL=$(curl --silent --max-time 10 --connect-timeout 5 \ + --show-error http://127.0.0.1:$LOCAL_PORT/api/tunnels | \ + sed -nE 's/.*public_url":"https:..([^"]*).*/\1/p') + sleep 1 + echo -n "." + done + + export CALLBACK_URL="https://$NGROK_PUBLIC_URL" + echo -n "Public url ." + echo $CALLBACK_URL + ./gradlew test -Dcucumber.filter.tags="@common" + echo -n "Test execution is completed, kill ngrok" + pkill ngrok + - store_test_results: + path: build/test-results/test/TEST-org.mifos.integrationtest.TestRunner.xml + - store_artifacts: + path: build/test-results + test-chart-common-extended: + docker: + - image: cimg/openjdk:17.0.0 + steps: + - checkout + #- run: git clone https://github.com/openmf/ph-ee-integration-test + - run: + name: Ngrok setup + command: curl -s https://ngrok-agent.s3.amazonaws.com/ngrok.asc | sudo tee /etc/apt/trusted.gpg.d/ngrok.asc >/dev/null && echo "deb https://ngrok-agent.s3.amazonaws.com buster main" | sudo tee /etc/apt/sources.list.d/ngrok.list && sudo apt update && sudo apt install ngrok + - run: + name: Test execution + no_output_timeout: 30m + command: | + ngrok config add-authtoken $AUTH_TOKEN + echo "web_addr: $LOCAL_PORT" >> /home/circleci/.config/ngrok/ngrok.yml + ngrok http 53013 > /dev/null & + echo -n "Extracting ngrok public url ." + NGROK_PUBLIC_URL="" + while [ -z "$NGROK_PUBLIC_URL" ]; do + # Run 'curl' against ngrok API and extract public (using 'sed' command) + export NGROK_PUBLIC_URL=$(curl --silent --max-time 10 --connect-timeout 5 \ + --show-error http://127.0.0.1:$LOCAL_PORT/api/tunnels | \ + sed -nE 's/.*public_url":"https:..([^"]*).*/\1/p') + sleep 1 + echo -n "." + done + + export CALLBACK_URL="https://$NGROK_PUBLIC_URL" + echo -n "Public url ." + echo $CALLBACK_URL + ./gradlew test -Dcucumber.filter.tags="@commonExtended and not @e2e" + echo -n "Test execution is completed, kill ngrok" + pkill ngrok + - store_test_results: + path: build/test-results/test/TEST-org.mifos.integrationtest.TestRunner.xml + - store_artifacts: + path: build/test-results +workflows: + deploy: + jobs: + - build: + context: + - AWS + - slack + - build_and_push_tag_image: + filters: + tags: + only: /^v\d+\.\d+\.\d+([-rc.0-9]+)*?$/ # Match tags in the format v1.2.3 + context: + - DOCKER + - build_and_push_latest_image: + context: + - DOCKER + - docker-image-availability-check-and-upgrade: + context: + - AWS + - Helm + - slack + requires: + - build + - build_and_push_tag_image + - build_and_push_latest_image + - create-secret-paymenthub-namespace: + requires: + - docker-image-availability-check-and-upgrade + context: + - AWS + - Helm + - slack + - Secrets + # - install-helm-chart: + # cluster-name: sit + # - delete-helm-release: + # cluster-name: sit + # requires: + # - install-helm-chart + - deploying-bpmns: + requires: + - create-secret-paymenthub-namespace + context: + - AWS + - Helm + - slack + - test-chart-e2e: + requires: + - deploying-bpmns + context: + - AWS + - Helm + - slack + - Ngrok + - test-chart-ams: + requires: + - test-chart-e2e + context: + - AWS + - Helm + - slack + - Ngrok + - test-chart-gov: + requires: + - test-chart-ams + context: + - AWS + - Helm + - slack + - Ngrok + - test-chart-common: + requires: + - test-chart-gov + context: + - AWS + - Helm + - slack + - Ngrok + - test-chart-common-extended: + requires: + - test-chart-common + context: + - AWS + - Helm + - slack + - Ngrok + - create-tls-secret-paymenthub-namespace: + context: + - AWS + - Helm + - slack + - Secrets + - TLS diff --git a/ph-ee-integration-test/.github/pull_request_template.md b/ph-ee-integration-test/.github/pull_request_template.md new file mode 100644 index 000000000..a84a42980 --- /dev/null +++ b/ph-ee-integration-test/.github/pull_request_template.md @@ -0,0 +1,30 @@ +## Description + +* PR title should have jira ticket enclosed in `[]`.
+ Format: ``` [jira_ticket] description```
+ ex: [phee-123] PR title. +* Add a link to the Jira ticket. +* Describe the changes made and why they were made. + +## Checklist + +Please make sure these boxes are checked before submitting your pull request - thanks! +- [ ] Followed the PR title naming convention mentioned above. + +- [ ] Acknowledge that we will not merge PRs that are not passing the checks ("green") - it is your (author's) responsibility to get a proposed PR to pass all the checks, not primarily the project's maintainers. + +- [ ] The PR title should include a JIRA ticket + +- [ ] Design-related bullet points or design document links related to this PR added in the description above. + +- [ ] Updated corresponding Postman Collection or API documentation for the changes in this PR. + +- [ ] Create/update unit or integration tests for verifying the changes made. + +- [ ] Add required Swagger annotation and update API documentation with details of any API changes if applicable + +- [ ] Followed the naming conventions as given in https://docs.google.com/document/d/1Q4vaMSzrTxxh9TS0RILuNkSkYCxotuYk1Xe0CMIkkCU/edit?usp=sharing + +- [ ] Followed coding conventions at https://cwiki.apache.org/confluence/display/FINERACT/Coding+Conventions. + +FYI our guidelines for code reviews same as https://cwiki.apache.org/confluence/display/FINERACT/Code+Review+Guide. diff --git a/ph-ee-integration-test/.github/workflows/jit-security.yml b/ph-ee-integration-test/.github/workflows/jit-security.yml new file mode 100644 index 000000000..d3babba2a --- /dev/null +++ b/ph-ee-integration-test/.github/workflows/jit-security.yml @@ -0,0 +1,285 @@ +name: Workflows generated by the MVS plan +run-name: ${{fromJSON(github.event.inputs.client_payload).payload.job_title}} +on: + workflow_dispatch: + inputs: + client_payload: + description: The Client payload + required: true + +permissions: + contents: read + id-token: write + +jobs: + docker-scan: + if: fromJSON(github.event.inputs.client_payload).payload.workflow_job_name == 'docker-scan' && fromJSON(github.event.inputs.client_payload).payload.workflow_slug == 'workflow-docker-scan' + runs-on: ubuntu-22.04 + timeout-minutes: 60 + steps: + - name: trivy + uses: jitsecurity-controls/jit-github-action@v4.2.2 + with: + security_control: registry.jit.io/control-trivy-alpine:latest + + enrich: + if: fromJSON(github.event.inputs.client_payload).payload.workflow_job_name == 'enrich' && fromJSON(github.event.inputs.client_payload).payload.workflow_slug == 'workflow-enrichment-code' + runs-on: ubuntu-22.04 + timeout-minutes: 60 + steps: + - name: enrichment + uses: jitsecurity-controls/jit-github-action@v4.2.2 + with: + security_control: registry.jit.io/control-enrichment-slim:latest + + iac-misconfig-detection-kubernetes: + if: fromJSON(github.event.inputs.client_payload).payload.workflow_job_name == 'iac-misconfig-detection-kubernetes' && fromJSON(github.event.inputs.client_payload).payload.workflow_slug == 'workflow-kubernetes-iac-misconfiguration-detection' + runs-on: ubuntu-22.04 + timeout-minutes: 60 + steps: + - name: kubescape + uses: jitsecurity-controls/jit-github-action@v4.2.2 + with: + security_control: registry.jit.io/control-kubescape-slim:latest + + remediation-pr: + if: fromJSON(github.event.inputs.client_payload).payload.workflow_job_name == 'remediation-pr' && fromJSON(github.event.inputs.client_payload).payload.workflow_slug == 'workflow-remediation-pr' + runs-on: ubuntu-22.04 + timeout-minutes: 60 + steps: + - name: remediation-pr + uses: jitsecurity-controls/jit-github-action@v4.2.2 + with: + security_control: registry.jit.io/open-remediation-pr-alpine:latest + + secret-detection: + if: fromJSON(github.event.inputs.client_payload).payload.workflow_job_name == 'secret-detection' && fromJSON(github.event.inputs.client_payload).payload.workflow_slug == 'workflow-secret-detection' + runs-on: ubuntu-22.04 + timeout-minutes: 60 + steps: + - name: gitleaks + uses: jitsecurity-controls/jit-github-action@v4.2.2 + with: + security_control: registry.jit.io/control-gitleaks-alpine:latest + + software-bill-of-materials: + if: fromJSON(github.event.inputs.client_payload).payload.workflow_job_name == 'software-bill-of-materials' && fromJSON(github.event.inputs.client_payload).payload.workflow_slug == 'workflow-sbom' + runs-on: ubuntu-22.04 + timeout-minutes: 60 + steps: + - name: syft + uses: jitsecurity-controls/jit-github-action@v4.2.2 + with: + security_control: registry.jit.io/control-syft-alpine:latest + fail_if_cannot_checkout: false + + software-component-analysis-elixir: + if: fromJSON(github.event.inputs.client_payload).payload.workflow_job_name == 'software-component-analysis-elixir' && fromJSON(github.event.inputs.client_payload).payload.workflow_slug == 'workflow-sca' + runs-on: ubuntu-22.04 + timeout-minutes: 60 + steps: + - name: osv-scanner + uses: jitsecurity-controls/jit-github-action@v4.2.2 + with: + security_control: registry.jit.io/control-osv-scanner-alpine:latest + + software-component-analysis-go: + if: fromJSON(github.event.inputs.client_payload).payload.workflow_job_name == 'software-component-analysis-go' && fromJSON(github.event.inputs.client_payload).payload.workflow_slug == 'workflow-sca' + runs-on: ubuntu-22.04 + timeout-minutes: 60 + steps: + - name: nancy + uses: jitsecurity-controls/jit-github-action@v4.2.2 + with: + security_control: registry.jit.io/control-nancy-alpine:latest + + software-component-analysis-gradle: + if: fromJSON(github.event.inputs.client_payload).payload.workflow_job_name == 'software-component-analysis-gradle' && fromJSON(github.event.inputs.client_payload).payload.workflow_slug == 'workflow-sca' + runs-on: ubuntu-22.04 + timeout-minutes: 60 + steps: + - name: jit-gradle + uses: jitsecurity-controls/jit-github-action@v4.2.2 + with: + security_control: registry.jit.io/control-jit-gradle-scanner:latest + + software-component-analysis-java: + if: fromJSON(github.event.inputs.client_payload).payload.workflow_job_name == 'software-component-analysis-java' && fromJSON(github.event.inputs.client_payload).payload.workflow_slug == 'workflow-sca' + runs-on: ubuntu-22.04 + timeout-minutes: 60 + steps: + - name: osv-scanner + uses: jitsecurity-controls/jit-github-action@v4.2.2 + with: + security_control: registry.jit.io/control-osv-scanner-alpine:latest + + software-component-analysis-js: + if: fromJSON(github.event.inputs.client_payload).payload.workflow_job_name == 'software-component-analysis-js' && fromJSON(github.event.inputs.client_payload).payload.workflow_slug == 'workflow-sca' + runs-on: ubuntu-22.04 + timeout-minutes: 60 + steps: + - name: npm-audit + uses: jitsecurity-controls/jit-github-action@v4.2.2 + with: + security_control: registry.jit.io/control-npm-audit-slim:latest + + software-component-analysis-php: + if: fromJSON(github.event.inputs.client_payload).payload.workflow_job_name == 'software-component-analysis-php' && fromJSON(github.event.inputs.client_payload).payload.workflow_slug == 'workflow-sca' + runs-on: ubuntu-22.04 + timeout-minutes: 60 + steps: + - name: osv-scanner + uses: jitsecurity-controls/jit-github-action@v4.2.2 + with: + security_control: registry.jit.io/control-osv-scanner-alpine:latest + + software-component-analysis-poetry: + if: fromJSON(github.event.inputs.client_payload).payload.workflow_job_name == 'software-component-analysis-poetry' && fromJSON(github.event.inputs.client_payload).payload.workflow_slug == 'workflow-sca' + runs-on: ubuntu-22.04 + timeout-minutes: 60 + steps: + - name: osv-scanner + uses: jitsecurity-controls/jit-github-action@v4.2.2 + with: + security_control: registry.jit.io/control-osv-scanner-alpine:latest + + software-component-analysis-python: + if: fromJSON(github.event.inputs.client_payload).payload.workflow_job_name == 'software-component-analysis-python' && fromJSON(github.event.inputs.client_payload).payload.workflow_slug == 'workflow-sca' + runs-on: ubuntu-22.04 + timeout-minutes: 60 + steps: + - name: osv-scanner + uses: jitsecurity-controls/jit-github-action@v4.2.2 + with: + security_control: registry.jit.io/control-osv-scanner-alpine:latest + + software-component-analysis-trivy-csharp: + if: fromJSON(github.event.inputs.client_payload).payload.workflow_job_name == 'software-component-analysis-trivy-csharp' && fromJSON(github.event.inputs.client_payload).payload.workflow_slug == 'workflow-sca' + runs-on: ubuntu-22.04 + timeout-minutes: 60 + steps: + - name: trivy-dotnet + uses: jitsecurity-controls/jit-github-action@v4.2.2 + with: + security_control: registry.jit.io/control-trivy-dotnet-slim:latest + + static-code-analysis-c-cpp: + if: fromJSON(github.event.inputs.client_payload).payload.workflow_job_name == 'static-code-analysis-c-cpp' && fromJSON(github.event.inputs.client_payload).payload.workflow_slug == 'workflow-sast' + runs-on: ubuntu-22.04 + timeout-minutes: 60 + steps: + - name: semgrep + uses: jitsecurity-controls/jit-github-action@v4.2.2 + with: + security_control: registry.jit.io/control-semgrep-alpine:latest + + static-code-analysis-csharp: + if: fromJSON(github.event.inputs.client_payload).payload.workflow_job_name == 'static-code-analysis-csharp' && fromJSON(github.event.inputs.client_payload).payload.workflow_slug == 'workflow-sast' + runs-on: ubuntu-22.04 + timeout-minutes: 60 + steps: + - name: semgrep + uses: jitsecurity-controls/jit-github-action@v4.2.2 + with: + security_control: registry.jit.io/control-semgrep-alpine:latest + + static-code-analysis-go: + if: fromJSON(github.event.inputs.client_payload).payload.workflow_job_name == 'static-code-analysis-go' && fromJSON(github.event.inputs.client_payload).payload.workflow_slug == 'workflow-sast' + runs-on: ubuntu-22.04 + timeout-minutes: 60 + steps: + - name: gosec + uses: jitsecurity-controls/jit-github-action@v4.2.2 + with: + security_control: registry.jit.io/control-gosec-alpine:latest + + static-code-analysis-java: + if: fromJSON(github.event.inputs.client_payload).payload.workflow_job_name == 'static-code-analysis-java' && fromJSON(github.event.inputs.client_payload).payload.workflow_slug == 'workflow-sast' + runs-on: ubuntu-22.04 + timeout-minutes: 60 + steps: + - name: semgrep + uses: jitsecurity-controls/jit-github-action@v4.2.2 + with: + security_control: registry.jit.io/control-semgrep-alpine:latest + + static-code-analysis-js: + if: fromJSON(github.event.inputs.client_payload).payload.workflow_job_name == 'static-code-analysis-js' && fromJSON(github.event.inputs.client_payload).payload.workflow_slug == 'workflow-sast' + runs-on: ubuntu-22.04 + timeout-minutes: 60 + steps: + - name: semgrep + uses: jitsecurity-controls/jit-github-action@v4.2.2 + with: + security_control: registry.jit.io/control-semgrep-alpine:latest + + static-code-analysis-kotlin: + if: fromJSON(github.event.inputs.client_payload).payload.workflow_job_name == 'static-code-analysis-kotlin' && fromJSON(github.event.inputs.client_payload).payload.workflow_slug == 'workflow-sast' + runs-on: ubuntu-22.04 + timeout-minutes: 60 + steps: + - name: semgrep + uses: jitsecurity-controls/jit-github-action@v4.2.2 + with: + security_control: registry.jit.io/control-semgrep-alpine:latest + + static-code-analysis-php: + if: fromJSON(github.event.inputs.client_payload).payload.workflow_job_name == 'static-code-analysis-php' && fromJSON(github.event.inputs.client_payload).payload.workflow_slug == 'workflow-sast' + runs-on: ubuntu-22.04 + timeout-minutes: 60 + steps: + - name: semgrep + uses: jitsecurity-controls/jit-github-action@v4.2.2 + with: + security_control: registry.jit.io/control-semgrep-alpine:latest + + static-code-analysis-python-semgrep: + if: fromJSON(github.event.inputs.client_payload).payload.workflow_job_name == 'static-code-analysis-python-semgrep' && fromJSON(github.event.inputs.client_payload).payload.workflow_slug == 'workflow-sast' + runs-on: ubuntu-22.04 + timeout-minutes: 60 + steps: + - name: semgrep + uses: jitsecurity-controls/jit-github-action@v4.2.2 + with: + security_control: registry.jit.io/control-semgrep-alpine:latest + + static-code-analysis-ruby: + if: fromJSON(github.event.inputs.client_payload).payload.workflow_job_name == 'static-code-analysis-ruby' && fromJSON(github.event.inputs.client_payload).payload.workflow_slug == 'workflow-sast' + runs-on: ubuntu-22.04 + timeout-minutes: 60 + steps: + - name: semgrep + uses: jitsecurity-controls/jit-github-action@v4.2.2 + with: + security_control: registry.jit.io/control-semgrep-alpine:latest + + static-code-analysis-rust: + if: fromJSON(github.event.inputs.client_payload).payload.workflow_job_name == 'static-code-analysis-rust' && fromJSON(github.event.inputs.client_payload).payload.workflow_slug == 'workflow-sast' + runs-on: ubuntu-22.04 + timeout-minutes: 60 + steps: + - name: semgrep + uses: jitsecurity-controls/jit-github-action@v4.2.2 + with: + security_control: registry.jit.io/control-semgrep-alpine:latest + + static-code-analysis-scala: + if: fromJSON(github.event.inputs.client_payload).payload.workflow_job_name == 'static-code-analysis-scala' && fromJSON(github.event.inputs.client_payload).payload.workflow_slug == 'workflow-sast' + runs-on: ubuntu-22.04 + timeout-minutes: 60 + steps: + - name: semgrep + uses: jitsecurity-controls/jit-github-action@v4.2.2 + with: + security_control: registry.jit.io/control-semgrep-alpine:latest + + static-code-analysis-swift: + if: fromJSON(github.event.inputs.client_payload).payload.workflow_job_name == 'static-code-analysis-swift' && fromJSON(github.event.inputs.client_payload).payload.workflow_slug == 'workflow-sast' + runs-on: ubuntu-22.04 + timeout-minutes: 60 + steps: + - name: semgrep + uses: jitsecurity-controls/jit-github-action@v4.2.2 + with: + security_control: registry.jit.io/control-semgrep-alpine:latest + \ No newline at end of file diff --git a/ph-ee-integration-test/.gitignore b/ph-ee-integration-test/.gitignore new file mode 100644 index 000000000..9c9677e57 --- /dev/null +++ b/ph-ee-integration-test/.gitignore @@ -0,0 +1,39 @@ +HELP.md +.gradle +build/ +!gradle/wrapper/gradle-wrapper.jar +!**/src/main/**/build/ +!**/src/test/**/build/ +.DS_Store +cucumber-report +cucumber.json + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache +bin/ +!**/src/main/**/bin/ +!**/src/test/**/bin/ + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr +out/ +!**/src/main/**/out/ +!**/src/test/**/out/ + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +### Load Test setup ### +/vouchertest diff --git a/ph-ee-integration-test/.jit/BulkSwaggerNew.yaml b/ph-ee-integration-test/.jit/BulkSwaggerNew.yaml new file mode 100644 index 000000000..f48104d02 --- /dev/null +++ b/ph-ee-integration-test/.jit/BulkSwaggerNew.yaml @@ -0,0 +1,242 @@ +{ + "openapi": "3.0.1", + "info": { + "title": "OpenAPI definition", + "version": "v0" + }, + "servers": [ + { + "url": "https://bulk-connector.sandbox.fynarfin.io", + "description": "Generated server url" + } + ], + "paths": { + "/simulate": { + "post": { + "tags": [ + "simulate-api-controller" + ], + "operationId": "simulate", + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/bulk/transfer/{requestId}/{fileName}": { + "post": { + "tags": [ + "bulk-transfer-controller" + ], + "operationId": "bulkTransfer", + "parameters": [ + { + "name": "X-CorrelationID", + "in": "header", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "filename", + "in": "header", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "purpose", + "in": "header", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "Type", + "in": "header", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "Platform-TenantId", + "in": "header", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "required": [ + "data" + ], + "type": "object", + "properties": { + "data": { + "type": "string", + "format": "binary" + } + } + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "string" + } + } + } + } + } + } + }, + "/batchtransactions": { + "post": { + "tags": [ + "batch-transactions-controller" + ], + "operationId": "batchTransactions", + "parameters": [ + { + "name": "X-CorrelationID", + "in": "header", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "filename", + "in": "header", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "purpose", + "in": "header", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "Type", + "in": "header", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "Platform-TenantId", + "in": "header", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "X-Registering-Institution-ID", + "in": "header", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "X-Program-ID", + "in": "header", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "X-CallbackURL", + "in": "header", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "string" + } + } + } + } + } + } + }, + "/authorization/callback": { + "post": { + "tags": [ + "callback-controller" + ], + "operationId": "handleAuthorizationCallback", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthorizationResponse" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "type": "object" + } + } + } + } + } + } + } + }, + "components": { + "schemas": { + "AuthorizationResponse": { + "type": "object", + "properties": { + "clientCorrelationId": { + "type": "string" + }, + "status": { + "type": "string" + }, + "reason": { + "type": "string" + } + } + } + } + } +} \ No newline at end of file diff --git a/ph-ee-integration-test/.jit/IDAM-swagger.yaml b/ph-ee-integration-test/.jit/IDAM-swagger.yaml new file mode 100644 index 000000000..0aeadc56e --- /dev/null +++ b/ph-ee-integration-test/.jit/IDAM-swagger.yaml @@ -0,0 +1,621 @@ +{ + "openapi": "3.0.1", + "info": { + "title": "OpenAPI definition", + "version": "v0" + }, + "servers": [ + { + "url": "https://identity-mapper.sandbox.fynarfin.io", + "description": "Generated server url" + } + ], + "paths": { + "/paymentModality": { + "put": { + "tags": [ + "GOV" + ], + "summary": "Updating payment modality", + "operationId": "updatePaymentModality", + "parameters": [ + { + "name": "X-CallbackURL", + "in": "header", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "X-Registering-Institution-ID", + "in": "header", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RequestDTO" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/ResponseDTO" + } + } + } + } + } + }, + "post": { + "tags": [ + "GOV" + ], + "summary": "Adding new payment modality", + "operationId": "addPaymentModality", + "parameters": [ + { + "name": "X-CallbackURL", + "in": "header", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "X-Registering-Institution-ID", + "in": "header", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RequestDTO" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/ResponseDTO" + } + } + } + } + } + } + }, + "/beneficiary": { + "get": { + "tags": [ + "GOV" + ], + "summary": "Account Lookup API", + "operationId": "accountLookup", + "parameters": [ + { + "name": "X-CallbackURL", + "in": "header", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "payeeIdentity", + "in": "query", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "paymentModality", + "in": "query", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "requestId", + "in": "query", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "X-Registering-Institution-ID", + "in": "header", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/ResponseDTO" + } + } + } + } + } + }, + "put": { + "tags": [ + "update-beneficiary-api-controller" + ], + "operationId": "registerBeneficiary", + "parameters": [ + { + "name": "X-CallbackURL", + "in": "header", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "X-Registering-Institution-ID", + "in": "header", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RequestDTO" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/ResponseDTO" + } + } + } + } + } + }, + "post": { + "tags": [ + "GOV" + ], + "summary": "Registering new beneficiary", + "operationId": "registerBeneficiary_1", + "parameters": [ + { + "name": "X-CallbackURL", + "in": "header", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "X-Registering-Institution-ID", + "in": "header", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RequestDTO" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/ResponseDTO" + } + } + } + } + } + } + }, + "/batchAccountLookupCallback": { + "put": { + "tags": [ + "account-lookup-callback-controller" + ], + "operationId": "batchAccountLookupCallback", + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "string" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "type": "object" + } + } + } + } + } + } + }, + "/accountLookupCallback": { + "put": { + "tags": [ + "account-lookup-callback-controller" + ], + "operationId": "accountLookupCallback", + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "string" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "type": "object" + } + } + } + } + } + } + }, + "/accountLookup": { + "post": { + "tags": [ + "batch-account-lookup-api-controller" + ], + "operationId": "batchAccountLookup", + "parameters": [ + { + "name": "X-CallbackURL", + "in": "header", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "X-Registering-Institution-ID", + "in": "header", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RequestDTO" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/ResponseDTO" + } + } + } + } + } + } + }, + "/beneficiaries": { + "get": { + "tags": [ + "fetch-beneficiaries-api-controller" + ], + "operationId": "fetchAllBeneficiary", + "parameters": [ + { + "name": "X-Registering-Institution-ID", + "in": "header", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "page", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "format": "int32", + "default": 0 + } + }, + { + "name": "pageSize", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "format": "int32", + "default": 20 + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/PageFetchBeneficiariesResponseDTO" + } + } + } + } + } + } + }, + "/beneficiaries/{payeeIdentity}": { + "get": { + "tags": [ + "fetch-beneficiaries-api-controller" + ], + "operationId": "fetchBeneficiary", + "parameters": [ + { + "name": "payeeIdentity", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "X-Registering-Institution-ID", + "in": "header", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/FetchBeneficiariesResponseDTO" + } + } + } + } + } + } + } + }, + "components": { + "schemas": { + "BeneficiaryDTO": { + "type": "object", + "properties": { + "payeeIdentity": { + "type": "string" + }, + "paymentModality": { + "type": "string" + }, + "financialAddress": { + "type": "string" + }, + "bankingInstitutionCode": { + "type": "string" + } + } + }, + "RequestDTO": { + "type": "object", + "properties": { + "requestID": { + "type": "string" + }, + "sourceBBID": { + "type": "string" + }, + "beneficiaries": { + "type": "array", + "items": { + "$ref": "#/components/schemas/BeneficiaryDTO" + } + } + } + }, + "ResponseDTO": { + "type": "object", + "properties": { + "responseCode": { + "type": "string" + }, + "responseDescription": { + "type": "string" + }, + "requestID": { + "type": "string" + } + } + }, + "FetchBeneficiariesResponseDTO": { + "type": "object", + "properties": { + "registeringInstitutionId": { + "type": "string" + }, + "payeeIdentity": { + "type": "string" + }, + "paymentModality": { + "type": "string" + }, + "financialAddress": { + "type": "string" + }, + "bankingInstitutionCode": { + "type": "string" + } + } + }, + "PageFetchBeneficiariesResponseDTO": { + "type": "object", + "properties": { + "totalPages": { + "type": "integer", + "format": "int32" + }, + "totalElements": { + "type": "integer", + "format": "int64" + }, + "first": { + "type": "boolean" + }, + "last": { + "type": "boolean" + }, + "size": { + "type": "integer", + "format": "int32" + }, + "content": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FetchBeneficiariesResponseDTO" + } + }, + "number": { + "type": "integer", + "format": "int32" + }, + "sort": { + "$ref": "#/components/schemas/SortObject" + }, + "pageable": { + "$ref": "#/components/schemas/PageableObject" + }, + "numberOfElements": { + "type": "integer", + "format": "int32" + }, + "empty": { + "type": "boolean" + } + } + }, + "PageableObject": { + "type": "object", + "properties": { + "offset": { + "type": "integer", + "format": "int64" + }, + "sort": { + "$ref": "#/components/schemas/SortObject" + }, + "pageNumber": { + "type": "integer", + "format": "int32" + }, + "pageSize": { + "type": "integer", + "format": "int32" + }, + "paged": { + "type": "boolean" + }, + "unpaged": { + "type": "boolean" + } + } + }, + "SortObject": { + "type": "object", + "properties": { + "empty": { + "type": "boolean" + }, + "unsorted": { + "type": "boolean" + }, + "sorted": { + "type": "boolean" + } + } + } + } + } +} \ No newline at end of file diff --git a/ph-ee-integration-test/.jit/jit-config.yml b/ph-ee-integration-test/.jit/jit-config.yml new file mode 100644 index 000000000..e75c4a619 --- /dev/null +++ b/ph-ee-integration-test/.jit/jit-config.yml @@ -0,0 +1,7 @@ +applications: +- api_domain: identity-mapper.sandbox.fynarfin.io + application_name: IDAM + authentication_mode: non-authenticated + exclude_paths: [] + target_url: .jit/IDAM-swagger.yaml + type: api diff --git a/ph-ee-integration-test/.jit/jit-integration.yml b/ph-ee-integration-test/.jit/jit-integration.yml new file mode 100644 index 000000000..8b1378917 --- /dev/null +++ b/ph-ee-integration-test/.jit/jit-integration.yml @@ -0,0 +1 @@ + diff --git a/ph-ee-integration-test/.jit/jit-plan.yml b/ph-ee-integration-test/.jit/jit-plan.yml new file mode 100644 index 000000000..1862fc308 --- /dev/null +++ b/ph-ee-integration-test/.jit/jit-plan.yml @@ -0,0 +1,27 @@ +name: My plan +level: beginner +update_id: c08be731-f2ac-4754-b68a-7219256e7954 +author: Jit +version: 0.1 +owners: + default: null +references: + - https://www.jit.io +tags: [] +items: + - name: Scan your API for vulnerabilities + uses: jitsecurity-controls/jit-plans/items/runtime/item-api-security.yml@latest + - name: Scan your code for vulnerabilities (SAST) + uses: jitsecurity-controls/jit-plans/items/code/item-code-vulnerability.yml@latest + - name: Scan your Dockerfiles for vulnerabilities + uses: jitsecurity-controls/jit-plans/items/infrastructure/item-container-scan.yml@latest + - name: Scan your code dependencies for vulnerabilities (SCA) + uses: jitsecurity-controls/jit-plans/items/code/item-dependency-check.yml@latest + - name: Scan Kubernetes configuration files + uses: jitsecurity-controls/jit-plans/items/infrastructure/item-iac-kubernetes.yml@latest + - name: Verify that MFA for your GitHub organization is enabled + uses: jitsecurity-controls/jit-plans/items/third_party_app/item-mfa-scm.yml@latest + - name: Scan code for hard-coded secrets + uses: jitsecurity-controls/jit-plans/items/code/item-secret-detection.yml@latest + - name: Generate a Software Bill of Materials (SBOM) + uses: jitsecurity-controls/jit-plans/items/code/item-software-bill-of-materials.yml@latest diff --git a/ph-ee-integration-test/Dockerfile b/ph-ee-integration-test/Dockerfile new file mode 100644 index 000000000..c6402debb --- /dev/null +++ b/ph-ee-integration-test/Dockerfile @@ -0,0 +1,7 @@ +FROM openjdk:17 +COPY . ph-ee-connector-integration-test +RUN microdnf install findutils +RUN cd /ph-ee-connector-integration-test && ./gradlew compileJava --no-daemon +RUN cd /ph-ee-connector-integration-test && ./gradlew assemble --no-daemon || return 0 +RUN cd /ph-ee-connector-integration-test && ./gradlew build -x test +WORKDIR /ph-ee-connector-integration-test diff --git a/ph-ee-integration-test/README.md b/ph-ee-integration-test/README.md new file mode 100644 index 000000000..91ce83b07 --- /dev/null +++ b/ph-ee-integration-test/README.md @@ -0,0 +1,149 @@ +# ph-ee-connector-integration-test + +![CUCUMBER](https://img.shields.io/badge/Cucumber-3DDC84?style=for-the-badge&logo=cucumber&logoColor=white) +
+Cucumber is a test writing framework which is used to achieve the idea of BDD(Behaviour Driven Development). To know more about BDD and why it is considered [read this article](https://www.tutorialspoint.com/behavior_driven_development/behavior_test_driven_development.htm). + +## Run test suite +./gradlew cucumberCli +OR +helm test + +## Three main components of cucumber +1. Ghrekin feature file + Its is a human readable domain specific language, to deffine a behaviour. +2. Step definition + Its the actual definition or implementation of each of the steps/ behaviour deffined in the feature file. +3. Context configuration + Integration test can be spefcific to spring applicaiton, camel specific or any other environment. So cucmber can be configured with different context within which each of the step definition will be executed. + +## Dependency +Below are the required dependency to work in the spring and camel environment. +```gradle +implementation 'io.cucumber:cucumber-java:7.8.1' +implementation 'io.cucumber:cucumber-spring:7.8.1' +testImplementation 'io.cucumber:cucumber-junit:7.8.1' +testImplementation 'org.apache.camel:camel-test:3.4.0' +testImplementation 'org.springframework.boot:spring-boot-starter-test:2.5.4' +``` + +## 1. Writing a feature file +Refer the [official guide](https://cucumber.io/docs/gherkin/reference/) for any help wuth writing feature file. The extention of the feature file is `.feature`. Below is one of the sample feature file. +```gherkin +Feature: SLCB integration test + Scenario: Test the payload of the SLCB + Given I have a batchId: "123-123-123", requestId: "3af-567-dfr", purpose: "integration test" + And I mock transactionList with two transactions each of "1" value + And I can start camel context + When I call the buildPayload route + Then the exchange should have a variable with SLCB payload + And I can parse SLCB payload to DTO + And total transaction amount is 2 + And total transaction count is 2, failed is 0 and completed is 0 +``` + +## 2. Adding step definition +The step definition can be created in a simple plain java class. Inside the java class you can use all the design patterns specific to the context it is run in. So for example you want to use `@Autowire` for any bean then make sure you are using the `SpringBootTest` context and that bean is present in that context. +Each of the step definition need to match with the phrase mentioned in the feature file with proper annotation. A sample step definition for the `Given I have a batchId: "123-123-123", requestId: "3af-567-dfr", purpose: "integration test"` expression is added below. Where {string} is the placeholder for the variable. To find more about variables data type [refer this](https://cucumber.io/docs/cucumber/step-definitions/?lang=java). +```java +@Given("I have a batchId: {string}, requestId: {string}, purpose: {string}") +public void i_have_required_data(String batchId, String requestId, String purpose){ + this.batchId = batchId; + this.requestId = requestId; + this.purpose = purpose; +} +``` + +## 3. Configuring context for cucumber tests +Cucumber can be run in any context. And configuring this part totally depends on the scenario which we are testing. For configuring the context for spring applicaiton use the below annotation on default spring test class or create a new one. +```java +@SpringBootTest +@CucumberContextConfiguration +@ActiveProfiles("test") +@ContextConfiguration(classes =
, loader = SpringBootContextLoader.class) +``` +The `@CucumberContextConfiguration` is responsible for making sure that all the stepDefinitions are executed in this particular environment. + +--- +Yay!! :boom: :boom: +
+Now we can run respective feature file directly form the intellij. +
+Screenshot 2022-10-26 at 6 58 19 PM + +## Adding runner configuration +Below java class will make sure to run cucumber test using JUnit test command. +Where the `glue` property is for defining the package which contains the step definitions, `feature` refers to the path where feature file is located and `plugin` is for providing different plugin configuration supported by cucumber. +```java +@RunWith(Cucumber.class) +@CucumberOptions( + features = {"src/test/java/resources"}, + glue = {"org.mifos.integrationtest.cucumber"}, + plugin = { + "html:cucumber-report", + "json:cucumber.json", + "pretty", + "html:build/cucumber-report.html", + "json:build/cucumber-report.json" +## Adding gradle configuration +Adding gradle configuration will allow us to run all the cucumber feature file at using using a CLI. + +```gradle +configurations { + cucumberRuntime { + extendsFrom testImplementation + } +} + +task cucumberCli() { + dependsOn assemble, testClasses + doLast { + javaexec { + main = "io.cucumber.core.cli.Main" + classpath = configurations.cucumberRuntime + sourceSets.main.output + sourceSets.test.output + args = [ + '--plugin', 'pretty', + '--plugin', 'html:target/cucumber-report.html', + '--glue', 'org.mifos.connector.slcb.cucumber', + 'src/test/java/resources'] + } +) +public class TestRunner { +} +``` +Adding below configuration will allow us to wire the CLI arguments be passed in the actual runner configuration while running the cucumber test using JUnit. +```groovy +test { + systemProperty "cucumber.filter.tags", System.getProperty("cucumber.filter.tags") +} +``` +## Running an integration test +Use below command to execute the integration test. +```shell +./gradlew test -Dcucumber.filter.tags="" +``` +Where `` has to be replaced with valid tag, for example if you are willing to run test cases related to g2p scenario then pass the tag `@gov`. If `-Dcucumber.filter.tags` flag is omitted then all the test cases would be triggered independent of the tag. +```shell +* Try: +> Run with --stacktrace option to get the stack trace. +> Run with --debug option to get more log output. +> Run with --scan to get full insights. +``` + +# Checkstyle +Use below command to execute the checkstyle test. +```shell +./gradlew checkstyleMain +``` + +## Spotless +Use below command to execute the spotless apply. +```shell +./gradlew spotlessApply +``` + +## FAQs +1. How to make step def reusable? +2. Order of execution of feature/steps? +3. Calling a scenario from another feature? +4. How cucumber picks feature file? How to configure the location of feature file? diff --git a/ph-ee-integration-test/build.gradle b/ph-ee-integration-test/build.gradle new file mode 100644 index 000000000..c9aa4029c --- /dev/null +++ b/ph-ee-integration-test/build.gradle @@ -0,0 +1,221 @@ +plugins { + id 'org.springframework.boot' version '2.7.1' + id 'io.spring.dependency-management' version '1.0.11.RELEASE' + id 'java' + id 'eclipse' + id 'checkstyle' + id 'com.diffplug.spotless' version '6.19.0' + id 'com.adarshr.test-logger' version '3.2.0' +} + +apply plugin:'com.diffplug.spotless' +spotless { + format 'misc', { + target '**/*.md', '**/*.properties', '**/.gitignore', '**/.openapi-generator-ignore', '**/*.yml', '**/*.xml', '**/**.json', '**/*.sql' + targetExclude '**/build/**', '**/bin/**', '**/.settings/**', '**/.idea/**', '**/.gradle/**', '**/gradlew.bat', '**/licenses/**', '**/banner.txt', '.vscode/**', '.jit/**', '.github/**' + indentWithSpaces(4) + endWithNewline() + trimTrailingWhitespace() + } + + groovyGradle { + target '*.gradle', '**/*.gradle' + targetExclude '**/build/**' + greclipse() + indentWithSpaces(4) + endWithNewline() + trimTrailingWhitespace() + } + + lineEndings 'UNIX' +} + +configure(this) { + // NOTE: order matters! + apply plugin: 'java' + apply plugin: 'idea' + apply plugin: 'eclipse' + apply plugin: 'checkstyle' + configurations { + implementation.setCanBeResolved(true) + api.setCanBeResolved(true) + } + tasks.withType(JavaCompile) { + options.compilerArgs += [ + "-Xlint:unchecked", + "-Xlint:cast", + "-Xlint:auxiliaryclass", + "-Xlint:deprecation", + "-Xlint:dep-ann", + "-Xlint:divzero", + "-Xlint:empty", + "-Xlint:exports", + "-Xlint:fallthrough", + "-Xlint:finally", + "-Xlint:module", + "-Xlint:opens", + "-Xlint:options", + "-Xlint:overloads", + "-Xlint:overrides", + "-Xlint:path", + "-Xlint:processing", + "-Xlint:removal", + "-Xlint:requires-automatic", + "-Xlint:requires-transitive-automatic", + "-Xlint:try", + "-Xlint:varargs", + "-Xlint:preview", + "-Xlint:static", + // -Werror needs to be disabled because EclipseLink's static weaving doesn't generate warning-free code + // and during an IntelliJ recompilation, it fails + //"-Werror", + "-Xmaxwarns", + 1500, + "-Xmaxerrs", + 1500 + ] + options.deprecation = true + } + // Configuration for the spotless plugin + // https://github.com/diffplug/spotless/tree/main/plugin-gradle + spotless { + java { + targetExclude '**/build/**', '**/bin/**', '**/out/**' + importOrder() //sort imports alphabetically + removeUnusedImports() + eclipse().configFile "$rootDir/ph-ee-integration-test/config/formatter.xml" + endWithNewline() + trimTrailingWhitespace() + // Enforce style modifier order + custom 'Modifier ordering', { + def modifierRanking = [ + public : 1, + protected : 2, + private : 3, + abstract : 4, + default : 5, + static : 6, + final : 7, + transient : 8, + volatile : 9, + synchronized: 10, + native : 11, + strictfp : 12] + // Find any instance of multiple modifiers. Lead with a non-word character to avoid + // accidental matching against for instance, "an alternative default value" + it.replaceAll(/\W(?:public |protected |private |abstract |default |static |final |transient |volatile |synchronized |native |strictfp ){2,}/, { + // Do not replace the leading non-word character. Identify the modifiers + it.replaceAll(/(?:public |protected |private |abstract |default |static |final |transient |volatile |synchronized |native |strictfp ){2,}/, { + // Sort the modifiers according to the ranking above + it.split().sort({ modifierRanking[it] }).join(' ') + ' ' + } + ) + } + ) + } + } + lineEndings 'UNIX' + } + // If we are running Gradle within Eclipse to enhance classes, + // set the classes directory to point to Eclipse's default build directory + if (project.hasProperty('env') && project.getProperty('env') == 'eclipse') { + sourceSets.main.java.outputDir = file("$projectDir/bin/main") + } + // Configuration for the Checkstyle plugin + // https://docs.gradle.org/current/userguide/checkstyle_plugin.html + dependencies { + checkstyle 'com.puppycrawl.tools:checkstyle:10.3.1' + checkstyle 'com.github.sevntu-checkstyle:sevntu-checks:1.42.0' + } +} + +group = 'org.mifos' +version = '0.0.1-SNAPSHOT' +sourceCompatibility = '17' + +repositories { + mavenLocal() + maven { + url = uri('https://repo.maven.apache.org/maven2') + } + + maven { + url = uri('https://jfrog.sandbox.fynarfin.io/artifactory/fyn-libs-snapshot') + } +} + +dependencies { + implementation 'org.springframework.boot:spring-boot-starter' + testImplementation "com.github.tomakehurst:wiremock-jre8:2.35.0" + testImplementation 'org.springframework.boot:spring-boot-starter-test' + implementation 'org.mifos:ph-ee-connector-common:1.8.1-SNAPSHOT' + testImplementation "com.google.truth:truth:1.1.3" + testImplementation 'com.google.code.gson:gson:2.9.0' + testImplementation('io.rest-assured:rest-assured:5.1.1') { + exclude group: 'org.codehaus.groovy' + } + + testCompileOnly 'org.projectlombok:lombok:1.18.24' + testAnnotationProcessor 'org.projectlombok:lombok:1.18.24' + implementation 'io.cucumber:cucumber-java:7.8.1' + implementation 'io.cucumber:cucumber-spring:7.8.1' + testImplementation 'io.cucumber:cucumber-junit:7.8.1' + + testRuntimeOnly("org.junit.vintage:junit-vintage-engine") + checkstyle 'com.puppycrawl.tools:checkstyle:10.9.3' + checkstyle 'com.github.sevntu-checkstyle:sevntu-checks:1.44.1' + implementation 'com.diffplug.gradle.spotless:spotless:2.4.1' + implementation 'com.diffplug.spotless:spotless-plugin-gradle:6.17.0' + implementation 'org.mifos:openapi-java-client:2.0.4-SNAPSHOT' + testImplementation 'org.hamcrest:hamcrest:2.2' + implementation 'com.opencsv:opencsv:5.5.2' + testImplementation 'org.apache.commons:commons-csv:1.5' + testImplementation 'org.awaitility:awaitility:4.2.0' + implementation 'commons-validator:commons-validator:1.7' +} + +tasks.named('test') { + useJUnitPlatform() +} + + +configurations { + cucumberRuntime { + extendsFrom testImplementation + } +} +testlogger { + theme 'mocha' // pick a theme - mocha, standard, plain, mocha-parallel, standard-parallel or plain-parallel + showSkipped false + showStandardStreams true + showStackTraces true +} + +test { + systemProperty "cucumber.filter.tags", System.getProperty("cucumber.filter.tags") + systemProperty "cucumber.filter.name", System.getProperty("cucumber.filter.name") +} +task cucumberCli() { + dependsOn assemble, testClasses + doLast { + javaexec { + main = "io.cucumber.core.cli.Main" + classpath = configurations.cucumberRuntime + sourceSets.main.output + sourceSets.test.output + args = [ + '--plugin', + 'html:cucumber-report', + '--plugin', + 'json:cucumber.json', + '--plugin', + 'pretty', + '--plugin', + 'html:build/cucumber-report.html', + '--plugin', + 'json:build/cucumber-report.json', + '--glue', + 'org.mifos.integrationtest.cucumber', + 'src/test/java/resources' + ] + } + } +} diff --git a/ph-ee-integration-test/config/checkstyle/checkstyle.xml b/ph-ee-integration-test/config/checkstyle/checkstyle.xml new file mode 100644 index 000000000..5183efef5 --- /dev/null +++ b/ph-ee-integration-test/config/checkstyle/checkstyle.xml @@ -0,0 +1,266 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ph-ee-integration-test/config/checkstyle/suppressions.xml b/ph-ee-integration-test/config/checkstyle/suppressions.xml new file mode 100644 index 000000000..f4e5b54c3 --- /dev/null +++ b/ph-ee-integration-test/config/checkstyle/suppressions.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + diff --git a/ph-ee-integration-test/config/cleanup.xml b/ph-ee-integration-test/config/cleanup.xml new file mode 100644 index 000000000..8b4edbb2d --- /dev/null +++ b/ph-ee-integration-test/config/cleanup.xml @@ -0,0 +1,71 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ph-ee-integration-test/config/formatter.xml b/ph-ee-integration-test/config/formatter.xml new file mode 100644 index 000000000..6e5574842 --- /dev/null +++ b/ph-ee-integration-test/config/formatter.xml @@ -0,0 +1,366 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ph-ee-integration-test/config/spotbugs/exclude.xml b/ph-ee-integration-test/config/spotbugs/exclude.xml new file mode 100644 index 000000000..297519c5e --- /dev/null +++ b/ph-ee-integration-test/config/spotbugs/exclude.xml @@ -0,0 +1,29 @@ + + + + + + + diff --git a/ph-ee-integration-test/gradle/wrapper/gradle-wrapper.jar b/ph-ee-integration-test/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 000000000..41d9927a4 Binary files /dev/null and b/ph-ee-integration-test/gradle/wrapper/gradle-wrapper.jar differ diff --git a/ph-ee-integration-test/gradle/wrapper/gradle-wrapper.properties b/ph-ee-integration-test/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 000000000..00e33edef --- /dev/null +++ b/ph-ee-integration-test/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.1-bin.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/ph-ee-integration-test/gradlew b/ph-ee-integration-test/gradlew new file mode 100755 index 000000000..1b6c78733 --- /dev/null +++ b/ph-ee-integration-test/gradlew @@ -0,0 +1,234 @@ +#!/bin/sh + +# +# Copyright © 2015-2021 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit + +APP_NAME="Gradle" +APP_BASE_NAME=${0##*/} + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/ph-ee-integration-test/gradlew.bat b/ph-ee-integration-test/gradlew.bat new file mode 100644 index 000000000..ac1b06f93 --- /dev/null +++ b/ph-ee-integration-test/gradlew.bat @@ -0,0 +1,89 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/ph-ee-integration-test/settings.gradle b/ph-ee-integration-test/settings.gradle new file mode 100644 index 000000000..fd9771468 --- /dev/null +++ b/ph-ee-integration-test/settings.gradle @@ -0,0 +1 @@ +rootProject.name = 'integrationtest' diff --git a/ph-ee-integration-test/src/main/java/org/mifos/integrationtest/IntegrationTestApplication.java b/ph-ee-integration-test/src/main/java/org/mifos/integrationtest/IntegrationTestApplication.java new file mode 100644 index 000000000..50198560d --- /dev/null +++ b/ph-ee-integration-test/src/main/java/org/mifos/integrationtest/IntegrationTestApplication.java @@ -0,0 +1,25 @@ +package org.mifos.integrationtest; + +import io.cucumber.core.internal.com.fasterxml.jackson.annotation.JsonInclude; +import io.cucumber.core.internal.com.fasterxml.jackson.databind.DeserializationFeature; +import io.cucumber.core.internal.com.fasterxml.jackson.databind.ObjectMapper; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.Bean; + +@SpringBootApplication +public class IntegrationTestApplication { + + public static void main(String[] args) { + SpringApplication.run(IntegrationTestApplication.class, args); + } + + @Bean + public ObjectMapper objectMapper() { + ObjectMapper objectMapper = new ObjectMapper(); + return objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL) + .configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true) + .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + } + +} diff --git a/ph-ee-integration-test/src/main/java/org/mifos/integrationtest/config/BillPayConnectorConfig.java b/ph-ee-integration-test/src/main/java/org/mifos/integrationtest/config/BillPayConnectorConfig.java new file mode 100644 index 000000000..daa9446b6 --- /dev/null +++ b/ph-ee-integration-test/src/main/java/org/mifos/integrationtest/config/BillPayConnectorConfig.java @@ -0,0 +1,32 @@ +package org.mifos.integrationtest.config; + +import javax.annotation.PostConstruct; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +@Component +public class BillPayConnectorConfig { + + @Value("${billPay.contactpoint}") + public String billPayContactPoint; + + @Value("${billPay.endpoints.inquiry}") + public String inquiryEndpoint; + + @Value("${billPay.endpoints.payments}") + public String paymentsEndpoint; + + @Value("${callback_url}") + public String callbackURL; + @Value("${billPay.endpoints.billerRtpRequest}") + public String billerRtpEndpoint; + + @Value("${billPay.endpoints.billStatus}") + public String statusEndpoint; + + @PostConstruct + private void setup() { + inquiryEndpoint = billPayContactPoint + inquiryEndpoint; + } + +} diff --git a/ph-ee-integration-test/src/main/java/org/mifos/integrationtest/config/BulkProcessorConfig.java b/ph-ee-integration-test/src/main/java/org/mifos/integrationtest/config/BulkProcessorConfig.java new file mode 100644 index 000000000..c2ac13559 --- /dev/null +++ b/ph-ee-integration-test/src/main/java/org/mifos/integrationtest/config/BulkProcessorConfig.java @@ -0,0 +1,46 @@ +package org.mifos.integrationtest.config; + +import javax.annotation.PostConstruct; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +@Component +public class BulkProcessorConfig { + + @Value("${bulk-processor.contactpoint}") + public String bulkProcessorContactPoint; + + @Value("${bulk-processor.endpoints.bulk-transactions}") + public String bulkTransactionEndpoint; + + @Value("${bulk-processor.endpoints.simulate}") + public String simulateEndpoint; + + public String bulkTransactionUrl; + + public String callbackUrl; + + public int retryCount; + + public int getRetryCount() { + return retryCount; + } + + public void setRetryCount(int retryCount) { + this.retryCount = retryCount; + } + + @PostConstruct + private void setup() { + bulkTransactionUrl = bulkProcessorContactPoint + bulkTransactionEndpoint; + simulateEndpoint = bulkProcessorContactPoint + simulateEndpoint; + } + + public String getCallbackUrl() { + return callbackUrl; + } + + public void setCallbackUrl(String callbackUrl) { + this.callbackUrl = callbackUrl; + } +} diff --git a/ph-ee-integration-test/src/main/java/org/mifos/integrationtest/config/ChannelConnectorConfig.java b/ph-ee-integration-test/src/main/java/org/mifos/integrationtest/config/ChannelConnectorConfig.java new file mode 100644 index 000000000..2ab33b320 --- /dev/null +++ b/ph-ee-integration-test/src/main/java/org/mifos/integrationtest/config/ChannelConnectorConfig.java @@ -0,0 +1,48 @@ +package org.mifos.integrationtest.config; + +import javax.annotation.PostConstruct; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +@Component +public class ChannelConnectorConfig { + + @Value("${channel-connector.contactpoint}") + public String channelConnectorContactPoint; + + @Value("${channel-connector.endpoints.transfer}") + public String transferEndpoint; + + @Value("${channel-connector.endpoints.gsma-p2p}") + public String gsmaP2PEndpoint; + @Value("${channel-connector.endpoints.gsma-deposit}") + public String gsmaP2PDepositEndpoint; + @Value("${channel-connector.endpoints.collection}") + public String collectionEndpoint; + @Value("${channel-connector.endpoints.transferReq}") + public String transferReqEndpoint; + @Value("${channel-connector.endpoints.gsma-transaction}") + private String gsmaTransactionEndpoint; + + public String transferUrl; + + public String requestType; + + public String getRequestType() { + return requestType; + } + + public void setRequestType(String requestType) { + this.requestType = requestType; + } + + public String getGsmaTransactionEndpoint() { + return gsmaTransactionEndpoint; + } + + @PostConstruct + private void setup() { + transferUrl = channelConnectorContactPoint + transferEndpoint; + } + +} diff --git a/ph-ee-integration-test/src/main/java/org/mifos/integrationtest/config/FspConfig.java b/ph-ee-integration-test/src/main/java/org/mifos/integrationtest/config/FspConfig.java new file mode 100644 index 000000000..c2534b613 --- /dev/null +++ b/ph-ee-integration-test/src/main/java/org/mifos/integrationtest/config/FspConfig.java @@ -0,0 +1,37 @@ +package org.mifos.integrationtest.config; + +import java.util.HashMap; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Configuration; + +@Configuration +@ConfigurationProperties(prefix = "fspconfig") +public class FspConfig { + + private HashMap payeefsp; + private HashMap payerfsp; + + public HashMap getPayeefsp() { + return payeefsp; + } + + public void setPayeefsp(HashMap payeefsp) { + this.payeefsp = payeefsp; + } + + public HashMap getPayerfsp() { + return payerfsp; + } + + public void setPayerfsp(HashMap payerfsp) { + this.payerfsp = payerfsp; + } + + public String getPayeeFsp(String key) { + return payeefsp.get(key); + } + + public String getPayerFsp(String key) { + return payerfsp.get(key); + } +} diff --git a/ph-ee-integration-test/src/main/java/org/mifos/integrationtest/config/GsmaConfig.java b/ph-ee-integration-test/src/main/java/org/mifos/integrationtest/config/GsmaConfig.java new file mode 100644 index 000000000..c6ca03a4d --- /dev/null +++ b/ph-ee-integration-test/src/main/java/org/mifos/integrationtest/config/GsmaConfig.java @@ -0,0 +1,53 @@ +package org.mifos.integrationtest.config; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +@Component +public class GsmaConfig { + + @Value("${channel.base-url}") + public String channelConnectorBaseUrl; + @Value("${channel.endpoint}") + public String gsmaEndpoint; + @Value("${loan.base-url}") + public String loanBaseUrl; + @Value("${loan.endpoints.product-endpoint}") + public String loanProductEndpoint; + @Value("${loan.endpoints.account-endpoint}") + public String loanAccountEndpoint; + @Value("${loan.endpoints.approve-endpoint}") + public String loanApproveEndpoint; + @Value("${loan.endpoints.repayment-endpoint}") + public String loanRepaymentEndpoint; + @Value("${loan.endpoints.disburse-endpoint}") + public String loanDisburseEndpoint; + @Value("${loan.endpoints.accountid-endpoint}") + public String loanGetAccountIdEndpoint; + @Value("${savings.base-url}") + public String savingsBaseUrl; + @Value("${savings.endpoints.product-endpoint}") + public String savingsProductEndpoint; + @Value("${savings.endpoints.approve-endpoint}") + public String savingsApproveEndpoint; + @Value("${savings.endpoints.account-endpoint}") + public String savingsAccountEndpoint; + @Value("${savings.endpoints.activate-endpoint}") + public String savingsActivateEndpoint; + @Value("${savings.endpoints.interop-identifier-endpoint}") + public String interopIdentifierEndpoint; + @Value("${savings.endpoints.deposit-endpoint}") + public String savingsDepositAccountEndpoint; + @Value("${savings.base-url}") + public String payerClientBaseUrl; + @Value("${savings.endpoints.client-endpoint}") + public String payerClientEndpoint; + @Value("${amsmifos.mock.base-url}") + public String amsMifosBasseUrl; + @Value("${amsmifos.mock.endpoints.deposit-endpoint}") + public String savingsDepositAccountMockEndpoint; + @Value("${amsmifos.mock.endpoints.repayment-endpoint}") + public String loanRepaymentMockEndpoint; + @Value("${callback_url}") + public String callbackURL; +} diff --git a/ph-ee-integration-test/src/main/java/org/mifos/integrationtest/config/IdentityMapperConfig.java b/ph-ee-integration-test/src/main/java/org/mifos/integrationtest/config/IdentityMapperConfig.java new file mode 100644 index 000000000..2599c00e0 --- /dev/null +++ b/ph-ee-integration-test/src/main/java/org/mifos/integrationtest/config/IdentityMapperConfig.java @@ -0,0 +1,26 @@ +package org.mifos.integrationtest.config; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +@Component +public class IdentityMapperConfig { + + @Value("${identity-account-mapper.contactpoint}") + public String identityMapperContactPoint; + + @Value("${identity-account-mapper.endpoints.register-beneficiary}") + public String registerBeneficiaryEndpoint; + @Value("${identity-account-mapper.endpoints.add-payment-modality}") + public String addPaymentModalityEndpoint; + @Value("${identity-account-mapper.endpoints.update-payment-modality}") + public String updatePaymentModalityEndpoint; + @Value("${identity-account-mapper.endpoints.account-lookup}") + public String accountLookupEndpoint; + @Value("${callback_url}") + public String callbackURL; + @Value("${identity-account-mapper.endpoints.batch-account-lookup}") + public String batchAccountLookupEndpoint; + @Value("${identity-account-mapper.endpoints.fetch-beneficiary}") + public String fetchBeneficiaryEndpoint; +} diff --git a/ph-ee-integration-test/src/main/java/org/mifos/integrationtest/config/JWSKeyConfig.java b/ph-ee-integration-test/src/main/java/org/mifos/integrationtest/config/JWSKeyConfig.java new file mode 100644 index 000000000..c35e1d74f --- /dev/null +++ b/ph-ee-integration-test/src/main/java/org/mifos/integrationtest/config/JWSKeyConfig.java @@ -0,0 +1,15 @@ +package org.mifos.integrationtest.config; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +@Component +public class JWSKeyConfig { + + @Value("${json-web-signature.privateKey}") + public String privateKey; + + @Value("${json-web-signature.x509Certificate}") + public String x509Certificate; + +} diff --git a/ph-ee-integration-test/src/main/java/org/mifos/integrationtest/config/KeycloakConfig.java b/ph-ee-integration-test/src/main/java/org/mifos/integrationtest/config/KeycloakConfig.java new file mode 100644 index 000000000..ed4161de8 --- /dev/null +++ b/ph-ee-integration-test/src/main/java/org/mifos/integrationtest/config/KeycloakConfig.java @@ -0,0 +1,51 @@ +package org.mifos.integrationtest.config; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +@Component +public class KeycloakConfig { + + @Value("${keycloak.contactpoint}") + public String keycloakContactPoint; + + @Value("${keycloak.realm}") + public String realm; + + @Value("${keycloak.discoveryUrl}") + public String discoveryUrl; + + @Value("${keycloak.introspectionEndpoint}") + public String introspectionUrl; + + @Value("${keycloak.endpoint.token}") + public String tokenEndpoint; + + @Value("${keycloak.endpoint.user}") + public String userEndpoint; + + @Value("${keycloak.endpoint.userResetPassword}") + public String userPasswordResetEndpoint; + + @Value("${keycloak.config.client.id}") + public String clientId; + + @Value("${keycloak.config.client.secret}") + public String clientSecret; + + @Value("${keycloak.config.admin.username}") + public String adminUsername; + + @Value("${keycloak.config.admin.password}") + public String adminPassword; + + @Value("${keycloak.config.grant_type}") + public String grantType; + + public static String headerUsernameKey = "username"; + public static String headerPasswordKey = "password"; + public static String headerClientIdKey = "client_id"; + public static String headerClientSecretKey = "client_secret"; + public static String headerGrantTypeKey = "grant_type"; + +} diff --git a/ph-ee-integration-test/src/main/java/org/mifos/integrationtest/config/KongConfig.java b/ph-ee-integration-test/src/main/java/org/mifos/integrationtest/config/KongConfig.java new file mode 100644 index 000000000..fd6883f25 --- /dev/null +++ b/ph-ee-integration-test/src/main/java/org/mifos/integrationtest/config/KongConfig.java @@ -0,0 +1,59 @@ +package org.mifos.integrationtest.config; + +import javax.annotation.PostConstruct; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +@Component +public class KongConfig { + + @Value("${kong.service.host}") + public String serviceHost; + + @Value("${kong.route.host}") + public String routeHost; + + @Value("${kong.service.channel-connector}") + public String channelServiceUrl; + + @Value("${kong.route.channel.host}") + public String channelRouteHost; + + @Value("${kong.route.channel.path}") + public String channelRoutePath; + + @Value("${kong.admin-contactpoint}") + public String adminContactPoint; + + @Value("${kong.endpoint.consumers}") + public String consumerEndpoint; + + @Value("${kong.endpoint.createKey}") + public String createKeyEndpoint; + + @Value("${kong.endpoint.services}") + public String servicesEndpoint; + + @Value("${kong.endpoint.createRoute}") + public String createRouteEndpoint; + + @Value("${kong.endpoint.createPlugin}") + public String createPluginEndpoint; + + @Value("${kong.endpoint.routes}") + public String routesEndpoint; + + @Value("${kong.endpoint.plugins}") + public String pluginsEndpoint; + + @Value("${kong.header.apikey}") + public String apiKeyHeader; + + public String serviceUrl; + + @PostConstruct + private void setup() { + serviceUrl = new StringBuilder().append("https://").append(serviceHost).append("/").toString(); + } + +} diff --git a/ph-ee-integration-test/src/main/java/org/mifos/integrationtest/config/KongOidcPluginConfig.java b/ph-ee-integration-test/src/main/java/org/mifos/integrationtest/config/KongOidcPluginConfig.java new file mode 100644 index 000000000..1e5ad5a47 --- /dev/null +++ b/ph-ee-integration-test/src/main/java/org/mifos/integrationtest/config/KongOidcPluginConfig.java @@ -0,0 +1,15 @@ +package org.mifos.integrationtest.config; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +@Component +public class KongOidcPluginConfig { + + @Value("${kong.plugin.oidc.scope}") + public String scope; + + @Value("${kong.plugin.oidc.bearerTokenOnly}") + public boolean bearerTokenOnly; + +} diff --git a/ph-ee-integration-test/src/main/java/org/mifos/integrationtest/config/MockPaymentSchemaConfig.java b/ph-ee-integration-test/src/main/java/org/mifos/integrationtest/config/MockPaymentSchemaConfig.java new file mode 100644 index 000000000..aa33f951f --- /dev/null +++ b/ph-ee-integration-test/src/main/java/org/mifos/integrationtest/config/MockPaymentSchemaConfig.java @@ -0,0 +1,15 @@ +package org.mifos.integrationtest.config; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +@Component +public class MockPaymentSchemaConfig { + + @Value("${mock-payment-schema.contactpoint}") + public String mockPaymentSchemaContactPoint; + + @Value("${mock-payment-schema.endpoints.mock-batch-authorization}") + public String mockBatchAuthorizationEndpoint; + +} diff --git a/ph-ee-integration-test/src/main/java/org/mifos/integrationtest/config/MojaloopCallbackEndpoints.java b/ph-ee-integration-test/src/main/java/org/mifos/integrationtest/config/MojaloopCallbackEndpoints.java new file mode 100644 index 000000000..b598fb414 --- /dev/null +++ b/ph-ee-integration-test/src/main/java/org/mifos/integrationtest/config/MojaloopCallbackEndpoints.java @@ -0,0 +1,42 @@ +package org.mifos.integrationtest.config; + +import java.util.List; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Configuration; + +@Configuration +@ConfigurationProperties(prefix = "mojaloop") +public class MojaloopCallbackEndpoints { + + private List callbackEndpoints; + + public List getCallbackEndpoints() { + return callbackEndpoints; + } + + public void setCallbackEndpoints(List callbackEndpoints) { + this.callbackEndpoints = callbackEndpoints; + } + + public static class CallbackEndpoint { + + private String type; + private String value; + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } + } +} diff --git a/ph-ee-integration-test/src/main/java/org/mifos/integrationtest/config/MojaloopConfig.java b/ph-ee-integration-test/src/main/java/org/mifos/integrationtest/config/MojaloopConfig.java new file mode 100644 index 000000000..61dd4b77a --- /dev/null +++ b/ph-ee-integration-test/src/main/java/org/mifos/integrationtest/config/MojaloopConfig.java @@ -0,0 +1,65 @@ +package org.mifos.integrationtest.config; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +@Component +public class MojaloopConfig { + + @Value("${mojaloop.contactpoint}") + public String mojaloopBaseurl; + + @Value("${mojaloop.central-ledger-contactpoint}") + public String mojaloopCentralLedgerBaseurl; + + @Value("${mojaloop.account-lookup-admin-contactpoint}") + public String mojaloopAccountLookupAdminBaseurl; + + @Value("${mojaloop.endpoint.als}") + public String addUserToAlsEndpoint; + + @Value("${mojaloop.endpoint.hub-account}") + public String mojaloopHubAccount; + + @Value("${mojaloop.endpoint.settlement-model}") + public String settlementModel; + + @Value("${mojaloop.endpoint.participant}") + public String participant; + + @Value("${mojaloop.endpoint.position-and-limits}") + public String initialPositionAndLimitEndpoint; + + @Value("${mojaloop.endpoint.add-callback}") + public String addCallbackEndpoint; + + @Value("${mojaloop.endpoint.record-fund}") + public String recordFundsEndpoint; + + @Value("${mojaloop.endpoint.oracle}") + public String oracleEndpoint; + + @Value("${mojaloop.fspid.payer}") + public String payerFspId; + + @Value("${mojaloop.fspid.payee1}") + public String payeeFspId; + + @Value("${mojaloop.fspid.payee2}") + public String payeeFspId2; + + @Value("${mojaloop.fspid.payee3}") + public String payeeFspId3; + + @Value("${ml-connector.host}") + public String mlConnectorHost; + + @Value("${ml-connector.endpoint.get-party}") + public String mlConnectorGetPartyEndpoint; + + @Value("${ml-connector.endpoint.get-quote}") + public String mlConnectorGetQuoteEndpoint; + + @Value("${ml-connector.endpoint.transfer}") + public String mlConnectorTransferEndpoint; +} diff --git a/ph-ee-integration-test/src/main/java/org/mifos/integrationtest/config/NetflixConductorConfig.java b/ph-ee-integration-test/src/main/java/org/mifos/integrationtest/config/NetflixConductorConfig.java new file mode 100644 index 000000000..f1e250d43 --- /dev/null +++ b/ph-ee-integration-test/src/main/java/org/mifos/integrationtest/config/NetflixConductorConfig.java @@ -0,0 +1,20 @@ +package org.mifos.integrationtest.config; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +@Component +public class NetflixConductorConfig { + + @Value("${netflix-conductor.server.contactpoint}") + public String conductorServerContactPoint; + + @Value("${netflix-conductor.server.endpoints.home}") + public String homeEndpoint; + + @Value("${netflix-conductor.server.endpoints.health}") + public String healthEndpoint; + + @Value("${netflix-conductor.server.endpoints.workflow}") + public String workflowEndpoint; +} diff --git a/ph-ee-integration-test/src/main/java/org/mifos/integrationtest/config/OperationsAppConfig.java b/ph-ee-integration-test/src/main/java/org/mifos/integrationtest/config/OperationsAppConfig.java new file mode 100644 index 000000000..da6c7473b --- /dev/null +++ b/ph-ee-integration-test/src/main/java/org/mifos/integrationtest/config/OperationsAppConfig.java @@ -0,0 +1,77 @@ +package org.mifos.integrationtest.config; + +import javax.annotation.PostConstruct; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +@Component +public class OperationsAppConfig { + + @Value("${operations-app.contactpoint}") + public String operationAppContactPoint; + + @Value("${operations-app.dpgcontactpoint}") + public String dpgOperationAppContactPoint; + + @Value("${operations-app.endpoints.batch-transaction}") + public String batchTransactionEndpoint; + + @Value("${operations-app.endpoints.batch-summary}") + public String batchSummaryEndpoint; + + @Value("${operations-app.endpoints.batch-details}") + public String batchDetailsEndpoint; + + @Value("${operations-app.endpoints.batch-aggregate}") + public String batchAggregateEndpoint; + + @Value("${operations-app.endpoints.auth}") + public String authEndpoint; + + @Value("${operations-app.endpoints.transfers}") + public String transfersEndpoint; + + @Value("${operations-app.endpoints.variables}") + public String variablesEndpoint; + + @Value("${operations-app.endpoints.transactionRequests}") + public String transactionRequestsEndpoint; + + @Value("${operations-app.endpoints.batches}") + public String batchesEndpoint; + + @Value("${operations-app.username}") + public String username; + + @Value("${operations-app.password}") + public String password; + + public String batchTransactionUrl; + + public String batchSummaryUrl; + + public String batchDetailsUrl; + + public String batchAggregateUrl; + + public String transfersUrl; + + public String transactionRequestsUrl; + + public String batchesUrl; + + public String authUrl; + + @PostConstruct + private void setup() { + batchTransactionUrl = operationAppContactPoint + batchTransactionEndpoint; + batchSummaryUrl = operationAppContactPoint + batchSummaryEndpoint; + batchDetailsUrl = operationAppContactPoint + batchDetailsEndpoint; + batchAggregateUrl = operationAppContactPoint + batchAggregateEndpoint; + authUrl = operationAppContactPoint + authEndpoint; + transfersUrl = operationAppContactPoint + transfersEndpoint; + transactionRequestsUrl = operationAppContactPoint + transactionRequestsEndpoint; + batchesUrl = operationAppContactPoint + batchesEndpoint; + } + +} diff --git a/ph-ee-integration-test/src/main/java/org/mifos/integrationtest/config/PaybillConfig.java b/ph-ee-integration-test/src/main/java/org/mifos/integrationtest/config/PaybillConfig.java new file mode 100644 index 000000000..13d136771 --- /dev/null +++ b/ph-ee-integration-test/src/main/java/org/mifos/integrationtest/config/PaybillConfig.java @@ -0,0 +1,24 @@ +package org.mifos.integrationtest.config; + +import javax.annotation.PostConstruct; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +@Component +public class PaybillConfig { + + @Value("${paybill.mpesa-connector.contactpoint}") + public String mpesaContactPoint; + @Value("${paybill.mpesa-connector.endpoints.validation}") + public String mpesaValidateEndpoint; + @Value("${paybill.mpesa-connector.endpoints.settlement}") + public String mpesaSettlementEndpoint; + public String mpesaValidateUrl; + public String mpesaSettlementUrl; + + @PostConstruct + public void setup() { + mpesaValidateUrl = mpesaContactPoint + mpesaValidateEndpoint; + mpesaSettlementUrl = mpesaContactPoint + mpesaSettlementEndpoint; + } +} diff --git a/ph-ee-integration-test/src/main/java/org/mifos/integrationtest/config/PayerFundTransferConfig.java b/ph-ee-integration-test/src/main/java/org/mifos/integrationtest/config/PayerFundTransferConfig.java new file mode 100644 index 000000000..f8965c5de --- /dev/null +++ b/ph-ee-integration-test/src/main/java/org/mifos/integrationtest/config/PayerFundTransferConfig.java @@ -0,0 +1,43 @@ +package org.mifos.integrationtest.config; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +@Component +public class PayerFundTransferConfig { + + @Value("${payerFundTransfer.tenant.payer}") + public String payerTenant; + + @Value("${payerFundTransfer.tenant.payee1}") + public String payeeTenant; + + @Value("${payerFundTransfer.tenant.payee2}") + public String payeeTenant2; + + @Value("${payerFundTransfer.tenant.payee3}") + public String payeeTenant3; + + @Value("${savings.base-url}") + public String clientBaseUrl; + @Value("${savings.endpoints.client-endpoint}") + public String clientEndpoint; + + @Value("${savings.base-url}") + public String savingsBaseUrl; + + @Value("${savings.endpoints.product-endpoint}") + public String savingsProductEndpoint; + @Value("${savings.endpoints.approve-endpoint}") + public String savingsApproveEndpoint; + @Value("${savings.endpoints.account-endpoint}") + public String savingsAccountEndpoint; + @Value("${savings.endpoints.activate-endpoint}") + public String savingsActivateEndpoint; + @Value("${savings.endpoints.interop-identifier-endpoint}") + public String interopIdentifierEndpoint; + @Value("${savings.endpoints.deposit-endpoint}") + public String savingsDepositAccountEndpoint; + @Value("${callback_url}") + public String callbackURL; +} diff --git a/ph-ee-integration-test/src/main/java/org/mifos/integrationtest/config/PaymentStatusCheckConfig.java b/ph-ee-integration-test/src/main/java/org/mifos/integrationtest/config/PaymentStatusCheckConfig.java new file mode 100644 index 000000000..21bc34def --- /dev/null +++ b/ph-ee-integration-test/src/main/java/org/mifos/integrationtest/config/PaymentStatusCheckConfig.java @@ -0,0 +1,17 @@ +package org.mifos.integrationtest.config; + +import java.util.ArrayList; +import java.util.List; +import javax.annotation.PostConstruct; +import org.springframework.stereotype.Component; + +@Component +public class PaymentStatusCheckConfig { + + public List requestIds = new ArrayList<>(); + + @PostConstruct + public void setup() { + + } +} diff --git a/ph-ee-integration-test/src/main/java/org/mifos/integrationtest/config/TenantConfig.java b/ph-ee-integration-test/src/main/java/org/mifos/integrationtest/config/TenantConfig.java new file mode 100644 index 000000000..8b3aa8bc3 --- /dev/null +++ b/ph-ee-integration-test/src/main/java/org/mifos/integrationtest/config/TenantConfig.java @@ -0,0 +1,26 @@ +package org.mifos.integrationtest.config; + +import java.util.HashMap; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Configuration; + +@Configuration +@EnableConfigurationProperties +@ConfigurationProperties(prefix = "tenantconfig") +public class TenantConfig { + + public void setTenants(HashMap tenants) { + this.tenants = tenants; + } + + public HashMap getTenants() { + return tenants; + } + + public String getTenant(String key) { + return tenants.get(key); + } + + private HashMap tenants; +} diff --git a/ph-ee-integration-test/src/main/java/org/mifos/integrationtest/config/VoucherManagementConfig.java b/ph-ee-integration-test/src/main/java/org/mifos/integrationtest/config/VoucherManagementConfig.java new file mode 100644 index 000000000..9cc694ea3 --- /dev/null +++ b/ph-ee-integration-test/src/main/java/org/mifos/integrationtest/config/VoucherManagementConfig.java @@ -0,0 +1,23 @@ +package org.mifos.integrationtest.config; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +@Component +public class VoucherManagementConfig { + + @Value("${voucher-management.contactpoint}") + public String voucherManagementContactPoint; + + @Value("${voucher-management.endpoints.create-voucher}") + public String createVoucherEndpoint; + @Value("${voucher-management.endpoints.voucher-lifecycle}") + public String voucherLifecycleEndpoint; + @Value("${voucher-management.endpoints.voucher-validity}") + public String voucherValidityEndpoint; + @Value("${voucher-management.endpoints.fetch}") + public String fetchVoucherEndpoint; + + @Value("${voucher-management.endpoints.voucher-status}") + public String voucherStatus; +} diff --git a/ph-ee-integration-test/src/main/resources/application.yaml b/ph-ee-integration-test/src/main/resources/application.yaml new file mode 100644 index 000000000..7f2b52f3f --- /dev/null +++ b/ph-ee-integration-test/src/main/resources/application.yaml @@ -0,0 +1,281 @@ +operations-app: + contactpoint: "https://ops-bk.sandbox.fynarfin.io" + dpgcontactpoint: "https://ops-bk-dpg.sandbox.fynarfin.io" + username: "mifos" + password: "password" + auth: + enabled: false + header: "Basic Y2xpZW50Og==" + endpoints: + auth: "/oauth/token" + batch-summary: "/api/v1/batch" + batch-details: "api/v1/batch/detail" + batch-transaction: "/api/v1/batch/transactions" + batches: "/api/v1/batches" + batch-aggregate: "/api/v1/batch/" + transfers: "/api/v1/transfers?size=1&page=0" + variables: "/api/v1/variables" + transactionRequests: "/api/v1/transactionRequests" + actuator: "/actuator/health" + +paybill: + mpesa-connector: + contactpoint: https://mpesa.sandbox.fynarfin.io + endpoints: + validation: "/validation" + settlement: "/confirmation" + +bulk-processor: + contactpoint: "https://bulk-connector.sandbox.fynarfin.io" + endpoints: + bulk-transactions: "/batchtransactions" + simulate: "/simulate" + actuator: "/actuator/health" + + +channel-connector: + contactpoint: "https://channel.sandbox.fynarfin.io" + endpoints: + transfer: "/channel/transfer" + gsma-p2p: "/channel/gsma/transfer" + gsma-deposit: "/channel/gsma/deposit" + gsma-transaction: "/channel/gsma/transaction" + collection: "/channel/collection" + transferReq: "/channel/transactionRequest" + actuator: "/actuator/health" + + + +max-retry-count: 5 +retry-interval: 15000 + +defaults: + tenant: "gorilla" + authorization: "Basic bWlmb3M6cGFzc3dvcmQ=" + +channel: + base-url: https://channel.sandbox.fynarfin.io + endpoint: /channel/gsma/transaction + +amsmifos: + mock: + base-url: https://ams-mifos-mock.sandbox.fynarfin.io + endpoints: + repayment-endpoint: /fineract/transactions/loanrepayment + deposit-endpoint: /fineract/savingsaccount/transfers + +ams: + base-url: https://ams-mifos.sandbox.fynarfin.io + balance-endpoint: /ams/accounts/{IdentifierType}/{IdentifierId}/balance + status-endpoint: /ams/accounts/{IdentifierType}/{IdentifierId}/status + name-endpoint: /ams/accounts/{IdentifierType}/{IdentifierId}/accountname + +loan: + base-url: https://fynams.sandbox.fynarfin.io + endpoints: + product-endpoint: /fineract-provider/api/v1/loanproducts + account-endpoint: /fineract-provider/api/v1/loans + approve-endpoint: /fineract-provider/api/v1/loans/{{loanAccId}} + disburse-endpoint: /fineract-provider/api/v1/loans/{{loanAccId}} + repayment-endpoint: /fineract-provider/api/v1/interoperation/transactions/{{loanAccId}}/loanrepayment + accountid-endpoint: /fineract-provider/api/v1/loans/{{loanAccId}} + +savings: + base-url: https://fynams.sandbox.fynarfin.io + endpoints: + client-endpoint: /fineract-provider/api/v1/clients + product-endpoint: /fineract-provider/api/v1/savingsproducts + account-endpoint: /fineract-provider/api/v1/savingsaccounts + approve-endpoint: /fineract-provider/api/v1/savingsaccounts/{{savingsAccId}} + activate-endpoint: /fineract-provider/api/v1/savingsaccounts/{{savingsAccId}} + deposit-endpoint: /fineract-provider/api/v1/savingsaccounts/{{savingsAccId}}/transactions + interop-identifier-endpoint: /fineract-provider/api/v1/interoperation/parties/{{identifierType}}/{{identifier}} + balance-endpoint: /fineract-provider/api/v1/savingsaccounts/{savingsAccId}} + +mock-server: + port: 53013 + +callback_url: ${CALLBACK_URL:localhost} + +json-web-signature: + privateKey: "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC07fxdEQlsvWvggBgrork401cdyZ9MqV6FF/RgX6+Om23gP/rME5sE5//OoG61KU3dEj9phcHH845TuyNEyc4Vhqxe1gzl4VIZkOj+/2qxYvCsP1Sv3twTs+fDfFv5NA1ZXqiswTlgjR2Lpf1tevFQEOzB9WYvH/Bu9kgr2AlHMPV6+b7gcJij/7W1hndiCk2ahbi7oXjjODF4yEU9yNAhopibe4zzMX+FO4eFYpUmrjS5wvv6aAanfoeIMTwhF81Gj9V3rHf4UsD3VEx773q7GPuXlZSLyiNrUCdvxITh+dW8Y9ICuCTy3bFbp1/HzoPdzkkUlzPNKLlLiV2w4EcxAgMBAAECggEAMjqHfwbFyQxlMHQfQa3xIdd6LejVcqDqfqSB0Wd/A2YfAMyCQbmHpbsKh0B+u4h191OjixX5EBuLfa9MQUKNFejHXaSq+/6rnjFenbwm0IwZKJiEWDbUfhvJ0blqhypuMktXJG6YETfb5fL1AjnJWGL6d3Y7IgYJ56QzsQhOuxZidSqw468xc4sIF0CoTeJdrSC2yDCVuVlLNifm/2SXBJD8mgc1WCz0rkJhvvpW4k5G9rRSkS5f0013ZNfsfiDXoqiKkafoYNEbk7TZQNInqSuONm/UECn5GLm6IXdXSGfm1O2Lt0Kk7uxW/3W00mIPeZD+hiOObheRm/2HoOEKiQKBgQDreVFQihXAEDviIB2s6fphvPcMw/IonE8tX565i3303ubQMDIyZmsi3apN5pqSjm1TKq1KIgY2D4vYTu6vO5x9MhEO2CCZWNwC+awrIYa32FwiT8D8eZ9g+DJ4/IwXyz1fG38RCz/eIsJ0NsS9z8RKBIbfMmM+WnXRez3Fq+cbRwKBgQDEs35qXThbbFUYo1QkO0vIo85iczu9NllRxo1nAqQkfu1oTYQQobxcGk/aZk0B02r9kt2eob8zfG+X3LadIhQ0/LalnGNKI9jWLkdW4dxi7xMU99MYc3NRXmR49xGxgOVkLzKyGMisUvkTnE5v/S1nhu5uFr3JPkWcCScLOTjVxwKBgHNWsDq3+GFkUkC3pHF/BhJ7wbLyA5pavfmmnZOavO6FhB8zjFLdkdq5IuMXcl0ZAHm9LLZkJhCy2rfwKb+RflxgerR/rrAOM24Np4RU3q0MgEyaLhg85pFT4T0bzu8UsRH14O6TSQxgkEjmTsX+j9IFl56aCryPCKi8Kgy53/CfAoGAdV2kUFLPDb3WCJ1r1zKKRW1398ZKHtwO73xJYu1wg1Y40cNuyX23pj0M6IOh7zT24dZ/5ecc7tuQukw3qgprhDJFyQtHMzWwbBuw9WZO2blM6XX1vuEkLajkykihhggi12RSG3IuSqQ3ejwJkUi/jsYz/fwTwcAmSLQtV8UM5IECgYEAh4h1EkMx3NXzVFmLsb4QLMXw8+Rnn9oG+NGObldQ+nmknUPu7iz5kl9lTJy+jWtqHlHL8ZtV1cZZSZnFxX5WQH5/lcz/UD+GqWoSlWuTU34PPTJqLKSYgkoOJQDEZVMVphLySS9tuo+K/h10lRS1r9KDm3RZASa1JnnWopBZIz4=" + x509Certificate: "MIIDvDCCAqQCCQDZK/l5vKIt7jANBgkqhkiG9w0BAQsFADCBnzELMAkGA1UEBhMCSU4xEjAQBgNVBAgMCUtBUk5BVEFLQTETMBEGA1UEBwwKRE9NQVNBTkRSQTERMA8GA1UECgwIRllOQVJGSU4xFDASBgNVBAsMC0RFVkVMT1BNRU5UMR0wGwYDVQQDDBRodHRwczovL2Z5bmFyZmluLmlvLzEfMB0GCSqGSIb3DQEJARYQYXZpa0BmeW5hcmZpbi5pbzAeFw0yMzA0MDUwNjExMDNaFw0yMzA1MDUwNjExMDNaMIGfMQswCQYDVQQGEwJJTjESMBAGA1UECAwJS0FSTkFUQUtBMRMwEQYDVQQHDApET01BU0FORFJBMREwDwYDVQQKDAhGWU5BUkZJTjEUMBIGA1UECwwLREVWRUxPUE1FTlQxHTAbBgNVBAMMFGh0dHBzOi8vZnluYXJmaW4uaW8vMR8wHQYJKoZIhvcNAQkBFhBhdmlrQGZ5bmFyZmluLmlvMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtO38XREJbL1r4IAYK6K5ONNXHcmfTKlehRf0YF+vjptt4D/6zBObBOf/zqButSlN3RI/aYXBx/OOU7sjRMnOFYasXtYM5eFSGZDo/v9qsWLwrD9Ur97cE7Pnw3xb+TQNWV6orME5YI0di6X9bXrxUBDswfVmLx/wbvZIK9gJRzD1evm+4HCYo/+1tYZ3YgpNmoW4u6F44zgxeMhFPcjQIaKYm3uM8zF/hTuHhWKVJq40ucL7+mgGp36HiDE8IRfNRo/Vd6x3+FLA91RMe+96uxj7l5WUi8oja1Anb8SE4fnVvGPSArgk8t2xW6dfx86D3c5JFJczzSi5S4ldsOBHMQIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQBPhTd+DhzbUGqAvsU6T34Iu3k+6Br4N6m90dkvBeMgYL8J7J6Fa7hm7f6xEeDqM+RTPhuFXNlS5swjqUYg/j85jKqVtgYAB6IE7z7BTwBAtF4tJ+jVOV4PfS/lSqvfxwo/qThqU1iXFz9xU38zlqxH5JuWZjeV58uUP/vZC8Ys44RDhU4X1qDbt51Vs8E+DeV1A4aweoEVc/txEdShbxnR2MVpPpca1NOElYW2cTAWjJypgw5bJZX4G0gZmHCZhQtgXSIMC1KSqMM7DK+HA7xTfKNJ+vnD08FOzBAb6nl2cHVb/zySdNWwsPu6w3FmzgFit9Hq2zE2F41167GvRBEL" + +identity-account-mapper: + contactpoint: "https://identity-mapper.sandbox.fynarfin.io" + endpoints: + register-beneficiary: /beneficiary + add-payment-modality: /paymentModality + update-payment-modality: /paymentModality + account-lookup: /beneficiary + batch-account-lookup: /accountLookup + fetch-beneficiary: /beneficiaries + actuator: "/actuator/health" + +kong: + admin-contactpoint: "http://kong-admin.sandbox.fynarfin.io" + endpoint: + consumers: /consumers + createKey: /consumers/{username}/key-auth + services: /services + createRoute: /services/{serviceId}/routes + createPlugin: /services/{serviceId}/plugins + routes: /routes + plugins: /plugins + plugin: + oidc: + scope: "openid" + bearerTokenOnly: true + header: + apikey: "X-API-KEY" + service: + host: "ph-ee-connector-bulk.paymenthub.80.svc" + channel-connector: "https://ph-ee-connector-channel.paymenthub.8443.svc" + route: + host: "bulk-connector.sandbox.fynarfin.io" + channel: + host: "channel.sandbox.fynarfin.io" + path: "/channel/transfer" + +voucher-management: + contactpoint: "https://vouchers.sandbox.fynarfin.io" + endpoints: + create-voucher: /vouchers + voucher-lifecycle: /vouchers + voucher-validity: /voucher/validity + fetch: /vouchers + actuator: "/actuator/health" + voucher-status: "/voucher/{{serialNumber}}?fields=status" + + +mock-payment-schema: + contactpoint: "https://mockpaymentschema.sandbox.fynarfin.io" + endpoints: + mock-batch-authorization: "/batches/" + actuator: "/actuator/health" + + +netflix-conductor: + server: + contactpoint: "https://conductor-server.sandbox.fynarfin.io" + endpoints: + home: "/" + health: "/health" + workflow: "/api/workflow" + +keycloak: + contactpoint: http://keycloak.sandbox.fynarfin.io + realm: "paymenthub" + introspectionEndpoint: "http://keycloak.sandbox.fynarfin.io/auth/realms/{realm}/protocol/openid-connect/token/introspect" + discoveryUrl: "http://keycloak.sandbox.fynarfin.io/auth/realms/{realm}/.well-known/openid-configuration" + endpoint: + token: /auth/realms/{realm}/protocol/openid-connect/token + user: /auth/admin/realms/{realm}/users + userResetPassword: /auth/admin/realms/{realm}/users/{userId}/reset-password + config: + admin: + username: "admin" + password: "admin" + client: + id: "kong-oidc" + secret: "QAnfEBawUTHOVCDGtf88tn23buodUHUC" + grant_type: "password" + +config: + completion-threshold-check: + completion-threshold: 90 + +payerFundTransfer: + tenant: + payer: "wakanda" + payee1: "jupiter" + payee2: "pluto" + payee3: "venus" + +mojaloop: + fspid: + payer: "payerfsp" + payee1: "payeefsp" + payee2: "payeefsp2" + payee3: "payeefsp3" + contactpoint: http://account-lookup-service.sandbox.fynarfin.io + central-ledger-contactpoint: http://central-ledger.sandbox.fynarfin.io + account-lookup-admin-contactpoint: http://account-lookup-service-admin.sandbox.fynarfin.io + endpoint: + als: /participants/{{identifierType}}/{{identifier}} + hub-account: /participants/Hub/accounts + settlement-model: /settlementModels + participant: /participants + position-and-limits: /participants/{{fsp}}/initialPositionAndLimits + add-callback: /participants/{{fsp}}/endpoints + record-fund: /participants/{{fsp}}/accounts/{{payerfspSettlementAccountId}} + oracle: /oracles + callback-endpoints: + - type: "FSPIOP_CALLBACK_URL_PARTICIPANT_PUT" + value: "{{CALLBACK_HOST}}/{{fsp}}/participants/{{partyIdType}}/{{partyIdentifier}}" + - type: "FSPIOP_CALLBACK_URL_PARTICIPANT_PUT_ERROR" + value: "{{CALLBACK_HOST}}/{{fsp}}/participants/{{partyIdType}}/{{partyIdentifier}}/error" + - type: "FSPIOP_CALLBACK_URL_PARTIES_GET" + value: "{{CALLBACK_HOST}}/switch/parties/{{partyIdType}}/{{partyIdentifier}}" + - type: "FSPIOP_CALLBACK_URL_PARTIES_PUT" + value: "{{CALLBACK_HOST}}/switch/parties/{{partyIdType}}/{{partyIdentifier}}" + - type: "FSPIOP_CALLBACK_URL_PARTIES_PUT_ERROR" + value: "{{CALLBACK_HOST}}/switch/parties/{{partyIdType}}/{{partyIdentifier}}/error" + - type: "FSPIOP_CALLBACK_URL_QUOTES" + value: "{{CALLBACK_HOST}}/switch" + - type: "FSPIOP_CALLBACK_URL_TRANSFER_POST" + value: "{{CALLBACK_HOST}}/switch/transfers" + - type: "FSPIOP_CALLBACK_URL_TRANSFER_PUT" + value: "{{CALLBACK_HOST}}/switch/transfers/{{transferId}}" + - type: "FSPIOP_CALLBACK_URL_TRANSFER_ERROR" + value: "{{CALLBACK_HOST}}/switch/transfers/{{transferId}}/error" + - type: "FSPIOP_CALLBACK_URL_TRX_REQ_SERVICE" + value: "{{CALLBACK_HOST}}" + - type: "FSPIOP_CALLBACK_URL_AUTHORIZATIONS" + value: "{{CALLBACK_HOST}}" + +ml-connector: + host: "mojaloop.sandbox.fynarfin.io" + contactpoint: "https://mojaloop.sandbox.fynarfin.io" + endpoint: + get-party: "/switch/parties/{{identifierType}}/{{identifier}}" + get-quote: "/switch/quotes" + transfer: "switch/transfers" + +global_wait_time_ms : 10000 + + +billPay: + contactpoint: https://bill-pay.sandbox.fynarfin.io + endpoints: + inquiry: /bills/{billId} + payments: /paymentNotifications + billerRtpRequest: /billTransferRequests + billStatus: /transferRequests/{{correlationId}} + +awaitly: + maxWaitTime: 25 + pollDelaySeconds: 2 + pollIntervalSeconds: 1 + +tenantconfig: + tenants: + paymentbb1: "rhino" + paymentbb2: "gorilla" + payerfsp: "wakanda" + payeefsp1: "pluto" + payeefsp2: "venus" + payeefsp3: "jupiter" + +fspconfig: + payeefsp: + payeefsp1: "pluto" + payeefsp2: "venus" + payeefsp3: "jupiter" + payerfsp: + payerfsp1: "wakanda" + payerfsp2: "gorilla" + +totalvouchers: 30 + +amsName: "mifos" diff --git a/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/ClientCorrelationIdTest.java b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/ClientCorrelationIdTest.java new file mode 100644 index 000000000..d467f355a --- /dev/null +++ b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/ClientCorrelationIdTest.java @@ -0,0 +1,83 @@ +package org.mifos.integrationtest; + +import static com.google.common.truth.Truth.assertThat; + +import com.google.gson.Gson; +import io.restassured.RestAssured; +import io.restassured.builder.RequestSpecBuilder; +import io.restassured.builder.ResponseSpecBuilder; +import io.restassured.http.ContentType; +import io.restassured.specification.RequestSpecification; +import io.restassured.specification.ResponseSpecification; +import org.json.JSONException; +import org.json.JSONObject; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.mifos.integrationtest.common.CollectionHelper; +import org.mifos.integrationtest.common.Utils; +import org.mifos.integrationtest.common.dto.CollectionResponse; +import org.mifos.integrationtest.common.dto.operationsapp.GetTransactionRequestResponse; +import org.mifos.integrationtest.common.dto.operationsapp.TransactionRequest; +import org.mifos.integrationtest.config.ChannelConnectorConfig; +import org.mifos.integrationtest.config.OperationsAppConfig; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; + +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +public class ClientCorrelationIdTest { + + Logger logger = LoggerFactory.getLogger(this.getClass()); + + private ResponseSpecification statusOkResponseSpec; + private RequestSpecification requestSpec; + + private String transactionId = "fce838977c90oKNEILYY"; + private String clientCorrelationId = "123456789"; + + @BeforeAll + public void setup() { + this.requestSpec = new RequestSpecBuilder().setContentType(ContentType.JSON).build(); + this.requestSpec.header(Utils.TENANT_PARAM_NAME, Utils.DEFAULT_TENANT); + this.statusOkResponseSpec = new ResponseSpecBuilder().expectStatusCode(200).build(); + } + + @Autowired + OperationsAppConfig operationsAppConfig; + + @Autowired + ChannelConnectorConfig channelConnectorConfig; + + @Test + @Disabled + public void testSendCollectionRequest() throws JSONException { + requestSpec.header(Utils.X_CORRELATIONID, clientCorrelationId); + JSONObject collectionRequestBody = CollectionHelper.getCollectionRequestBody("1", "254708374149", "24450523"); + logger.info(String.valueOf(collectionRequestBody)); + String json = RestAssured.given(requestSpec).baseUri(channelConnectorConfig.channelConnectorContactPoint) + .body(collectionRequestBody.toString()).expect().spec(statusOkResponseSpec).when().post("/channel/collection").andReturn() + .asString(); + CollectionResponse response = (new Gson()).fromJson(json, CollectionResponse.class); + assertThat(response.getTransactionId()).isNotEmpty(); + logger.debug(response.getTransactionId()); + this.transactionId = response.getTransactionId(); + } + + @Test + @Disabled + public void testGetTransactionRequestApi() { + Utils.sleep(5); + logger.info("Getting transactionRequestObject with transactionId {} ", this.transactionId); + RequestSpecification localSpec = requestSpec; + localSpec.queryParam("transactionId", this.transactionId); + String json = RestAssured.given(localSpec).baseUri(operationsAppConfig.operationAppContactPoint).expect().spec(statusOkResponseSpec) + .when().get("/api/v1/transactionRequests").andReturn().asString(); + GetTransactionRequestResponse transactionRequestResponse = (new Gson()).fromJson(json, GetTransactionRequestResponse.class); + assertThat(transactionRequestResponse.getContent().size()).isEqualTo(1); + TransactionRequest transactionRequest = transactionRequestResponse.getContent().get(0); + this.clientCorrelationId = transactionRequest.getClientCorrelationId(); + } + +} diff --git a/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/ExternalIdTest.java b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/ExternalIdTest.java new file mode 100644 index 000000000..17ccb2961 --- /dev/null +++ b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/ExternalIdTest.java @@ -0,0 +1,85 @@ +package org.mifos.integrationtest; + +import static com.google.common.truth.Truth.assertThat; + +import com.google.gson.Gson; +import io.restassured.RestAssured; +import io.restassured.builder.RequestSpecBuilder; +import io.restassured.builder.ResponseSpecBuilder; +import io.restassured.http.ContentType; +import io.restassured.specification.RequestSpecification; +import io.restassured.specification.ResponseSpecification; +import org.json.JSONException; +import org.json.JSONObject; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.mifos.integrationtest.common.CollectionHelper; +import org.mifos.integrationtest.common.Utils; +import org.mifos.integrationtest.common.dto.CollectionResponse; +import org.mifos.integrationtest.common.dto.OperationsHelper; +import org.mifos.integrationtest.common.dto.operationsapp.GetTransactionRequestResponse; +import org.mifos.integrationtest.common.dto.operationsapp.TransactionRequest; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +public class ExternalIdTest { + + private static final Logger log = LoggerFactory.getLogger(ExternalIdTest.class); + private ResponseSpecification statusOkResponseSpec; + private RequestSpecification requestSpec; + + private String transactionId = "fce838977c90oKNEILYY"; + private String externalId = "123"; + + @BeforeAll + public void setup() { + this.requestSpec = new RequestSpecBuilder().setContentType(ContentType.JSON).build(); + this.requestSpec.header(Utils.TENANT_PARAM_NAME, Utils.DEFAULT_TENANT); + this.statusOkResponseSpec = new ResponseSpecBuilder().expectStatusCode(200).build(); + } + + @Test + @Disabled + public void testSendCollectionRequest() throws JSONException { + JSONObject collectionRequestBody = CollectionHelper.getCollectionRequestBody("1", "254708374149", "24450523"); + log.debug("{}", collectionRequestBody); + String json = RestAssured.given(requestSpec).baseUri("http://localhost:5002").body(collectionRequestBody.toString()).expect() + .spec(statusOkResponseSpec).when().post("/channel/collection").andReturn().asString(); + CollectionResponse response = (new Gson()).fromJson(json, CollectionResponse.class); + assertThat(response.getTransactionId()).isNotEmpty(); + log.debug("{}", response.getTransactionId()); + this.transactionId = response.getTransactionId(); + } + + @Test + @Disabled + public void testGetTransactionRequestApi() { + Utils.sleep(5); + log.debug("Getting transactionRequestObject with transactionId {}", this.transactionId); + RequestSpecification localSpec = requestSpec; + localSpec.queryParam("transactionId", this.transactionId); + String json = RestAssured.given(localSpec).baseUri("http://localhost:5000").expect().spec(statusOkResponseSpec).when() + .get("/api/v1/transactionRequests").andReturn().asString(); + GetTransactionRequestResponse transactionRequestResponse = (new Gson()).fromJson(json, GetTransactionRequestResponse.class); + assertThat(transactionRequestResponse.getContent().size()).isEqualTo(1); + TransactionRequest transactionRequest = transactionRequestResponse.getContent().get(0); + this.externalId = transactionRequest.getExternalId(); + } + + @Test + @Disabled + public void testBulkFilterApi() throws JSONException { + Utils.sleep(10); + log.debug("Executing bulk filter api using externalId {}", this.externalId); + JSONObject bulkFilterRequestBody = OperationsHelper.getBulkFilterRequestBodyForExternalId(this.externalId); + log.debug("{}", bulkFilterRequestBody); + String json = RestAssured.given(requestSpec).baseUri("http://localhost:5000").body(bulkFilterRequestBody.toString()).expect() + .spec(statusOkResponseSpec).when().post("/api/v1/transactionRequests/export").andReturn().asString(); + log.debug("{}", json); + assertThat(json.split("\n").length).isEqualTo(2); + } + +} diff --git a/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/PhEeConnectorIntegrationTestApplicationTests.java b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/PhEeConnectorIntegrationTestApplicationTests.java new file mode 100644 index 000000000..25880a0da --- /dev/null +++ b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/PhEeConnectorIntegrationTestApplicationTests.java @@ -0,0 +1,12 @@ +package org.mifos.integrationtest; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +class PhEeConnectorIntegrationTestApplicationTests { + + @Test + void contextLoads() {} + +} diff --git a/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/TestRunner.java b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/TestRunner.java new file mode 100644 index 000000000..d6cbae096 --- /dev/null +++ b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/TestRunner.java @@ -0,0 +1,11 @@ +package org.mifos.integrationtest; + +import io.cucumber.junit.Cucumber; +import io.cucumber.junit.CucumberOptions; +import org.junit.runner.RunWith; + +@RunWith(Cucumber.class) +@CucumberOptions(features = { "src/test/java/resources" }, glue = { "org.mifos.integrationtest.cucumber" }, plugin = { + "html:cucumber-report", "json:cucumber.json", "pretty", "html:build/cucumber-report.html", "json:build/cucumber-report.json", + "junit:build/cucumber.xml" }) +public class TestRunner {} diff --git a/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/AuthorizationRequest.java b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/AuthorizationRequest.java new file mode 100644 index 000000000..401fcd7cf --- /dev/null +++ b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/AuthorizationRequest.java @@ -0,0 +1,22 @@ +package org.mifos.integrationtest.common; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +public class AuthorizationRequest { + + private String batchId; + + private String payerIdentifier; + + private String currency; + + private String amount; + +} diff --git a/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/BatchSummaryResponse.java b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/BatchSummaryResponse.java new file mode 100644 index 000000000..79e44e5af --- /dev/null +++ b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/BatchSummaryResponse.java @@ -0,0 +1,230 @@ +package org.mifos.integrationtest.common; + +import java.math.BigDecimal; + +public class BatchSummaryResponse { + + private String batchId; + + private String requestId; + + private Long total; + + private Long ongoing; + + private Long failed; + + private Long successful; + + private BigDecimal totalAmount; + + private BigDecimal successfulAmount; + + private BigDecimal pendingAmount; + + private BigDecimal failedAmount; + + private String file; + + private String notes; + + private String createdAt; + + private String status; + + private String modes; + + private String purpose; + + private String failPercentage; + + private String successPercentage; + + public String getFailPercentage() { + return failPercentage; + } + + public void setFailPercentage(String failPercentage) { + this.failPercentage = failPercentage; + } + + public String getSuccessPercentage() { + return successPercentage; + } + + public void setSuccessPercentage(String successPercentage) { + this.successPercentage = successPercentage; + } + + public BatchSummaryResponse() {} + + public BatchSummaryResponse(String batchId, String requestId, Long totalTransactions, Long ongoing, Long failed, Long completed, + BigDecimal total_amount, BigDecimal completed_amount, BigDecimal ongoing_amount, BigDecimal failed_amount, String result_file, + String note, String failPercentage, String successPercentage) { + this.batchId = batchId; + this.requestId = requestId; + this.total = totalTransactions; + this.ongoing = ongoing; + this.failed = failed; + this.successful = completed; + this.totalAmount = total_amount; + this.successfulAmount = completed_amount; + this.pendingAmount = ongoing_amount; + this.failedAmount = failed_amount; + this.file = result_file; + this.notes = note; + this.failPercentage = failPercentage; + this.successPercentage = successPercentage; + } + + public BatchSummaryResponse(String batch_id, String request_id, Long total, Long ongoing, Long failed, Long successful, + BigDecimal totalAmount, BigDecimal successfulAmount, BigDecimal pendingAmount, BigDecimal failedAmount, String file, + String notes, String created_at, String status, String modes, String purpose, String failPercentage, String successPercentage) { + this.batchId = batch_id; + this.requestId = request_id; + this.total = total; + this.ongoing = ongoing; + this.failed = failed; + this.successful = successful; + this.totalAmount = totalAmount; + this.successfulAmount = successfulAmount; + this.pendingAmount = pendingAmount; + this.failedAmount = failedAmount; + this.file = file; + this.notes = notes; + this.createdAt = created_at; + this.status = status; + this.modes = modes; + this.purpose = purpose; + this.failPercentage = failPercentage; + this.successPercentage = successPercentage; + } + + public String getBatch_id() { + return batchId; + } + + public void setBatch_id(String batch_id) { + this.batchId = batch_id; + } + + public String getRequest_id() { + return requestId; + } + + public void setRequest_id(String request_id) { + this.requestId = request_id; + } + + public Long getTotal() { + return total; + } + + public void setTotal(Long total) { + this.total = total; + } + + public Long getOngoing() { + return ongoing; + } + + public void setOngoing(Long ongoing) { + this.ongoing = ongoing; + } + + public Long getFailed() { + return failed; + } + + public void setFailed(Long failed) { + this.failed = failed; + } + + public Long getSuccessful() { + return successful; + } + + public void setSuccessful(Long successful) { + this.successful = successful; + } + + public BigDecimal getTotalAmount() { + return totalAmount; + } + + public void setTotalAmount(BigDecimal totalAmount) { + this.totalAmount = totalAmount; + } + + public BigDecimal getSuccessfulAmount() { + return successfulAmount; + } + + public void setSuccessfulAmount(BigDecimal successfulAmount) { + this.successfulAmount = successfulAmount; + } + + public BigDecimal getPendingAmount() { + return pendingAmount; + } + + public void setPendingAmount(BigDecimal pendingAmount) { + this.pendingAmount = pendingAmount; + } + + public BigDecimal getFailedAmount() { + return failedAmount; + } + + public void setFailedAmount(BigDecimal failedAmount) { + this.failedAmount = failedAmount; + } + + public String getFile() { + return file; + } + + public void setFile(String file) { + this.file = file; + } + + public String getNotes() { + return notes; + } + + public void setNotes(String notes) { + this.notes = notes; + } + + public String getCreated_at() { + return createdAt; + } + + public void setCreated_at(String created_at) { + this.createdAt = created_at; + } + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } + + public String getModes() { + return modes; + } + + public void setModes(String modes) { + this.modes = modes; + } + + public String getPurpose() { + return purpose; + } + + public void setPurpose(String purpose) { + this.purpose = purpose; + } +} diff --git a/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/CollectionHelper.java b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/CollectionHelper.java new file mode 100644 index 000000000..6da79a960 --- /dev/null +++ b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/CollectionHelper.java @@ -0,0 +1,77 @@ +package org.mifos.integrationtest.common; + +import java.util.ArrayList; +import java.util.List; +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +/** + * { "payer": [ { "key": "MSISDN", "value": "254708374149" }, { "key": "ACCOUNTID", "value": "24450523" } ], "amount": { + * "amount": "1", "currency": "USD" }, "transactionType": { "scenario": "MPESA", "subScenario": "BUYGOODS", "initiator": + * "PAYEE", "initiatorType": "BUSINESS" } } + */ +public final class CollectionHelper { + + private CollectionHelper() {} + + public static JSONObject getCollectionRequestBody(String amount, String msisdn, String accountId) throws JSONException { + List> payers = new ArrayList<>(); + payers.add(new Pair<>("MSISDN", msisdn)); + payers.add(new Pair<>("ACCOUNTID", accountId)); + + JSONObject body = new JSONObject(); + body.put("payer", getPayerArray(payers)); + body.put("amount", getAmountObject(amount)); + body.put("transactionType", getTransactionTypeObject()); + return body; + } + + public static JSONObject getCollectionRequestBody(String key1, String key2) throws JSONException { + List> payers = new ArrayList<>(); + payers.add(new Pair<>(key1, "254708374149")); + payers.add(new Pair<>(key2, "24450523")); + + JSONObject body = new JSONObject(); + body.put("payer", getPayerArray(payers)); + body.put("amount", getAmountObject("1")); + body.put("transactionType", getTransactionTypeObject()); + return body; + } + + private static JSONArray getPayerArray(List> payers) { + JSONArray payerArray = new JSONArray(); + payers.forEach(payer -> { + try { + payerArray.put(getPayerObject(payer.getKey(), payer.getValue())); + } catch (JSONException e) { + throw new RuntimeException(e); + } + }); + return payerArray; + } + + private static JSONObject getPayerObject(String key, String value) throws JSONException { + JSONObject payerObject = new JSONObject(); + payerObject.put("key", key); + payerObject.put("value", value); + return payerObject; + } + + private static JSONObject getAmountObject(String amount) throws JSONException { + JSONObject amountObject = new JSONObject(); + amountObject.put("currency", "USD"); + amountObject.put("amount", amount); + return amountObject; + } + + private static JSONObject getTransactionTypeObject() throws JSONException { + JSONObject txnType = new JSONObject(); + txnType.put("scenario", "MPESA"); + txnType.put("subScenario", "BUYGOODS"); + txnType.put("initiator", "PAYEE"); + txnType.put("initiatorType", "BUSINESS"); + return txnType; + } + +} diff --git a/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/CsvHelper.java b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/CsvHelper.java new file mode 100644 index 000000000..521fc3929 --- /dev/null +++ b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/CsvHelper.java @@ -0,0 +1,29 @@ +package org.mifos.integrationtest.common; + +import com.opencsv.CSVWriter; +import com.opencsv.CSVWriterBuilder; +import java.io.FileWriter; +import java.io.IOException; +import org.springframework.stereotype.Component; + +@Component +public class CsvHelper { + + public void createCsvFileWithHeaders(String filePath, String[] header) throws IOException { + CSVWriter writer = (CSVWriter) new CSVWriterBuilder(new FileWriter(filePath)).withQuoteChar('\0').build(); + writer.writeNext(header); + writer.close(); + } + + public void addRow(String filePath, String[] row) throws IOException { + CSVWriter writer = (CSVWriter) new CSVWriterBuilder(new FileWriter(filePath, true)).withQuoteChar('\0').build(); + writer.writeNext(row); + writer.close(); + } + + public void addLastRow(String filePath, String[] row) throws IOException { + CSVWriter writer = (CSVWriter) new CSVWriterBuilder(new FileWriter(filePath, true)).withQuoteChar('\0').withLineEnd("").build(); + writer.writeNext(row); + writer.close(); + } +} diff --git a/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/GSMATransferHelper.java b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/GSMATransferHelper.java new file mode 100644 index 000000000..8395b132b --- /dev/null +++ b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/GSMATransferHelper.java @@ -0,0 +1,122 @@ +package org.mifos.integrationtest.common; + +import org.json.JSONException; +import org.mifos.connector.common.gsma.dto.Fee; +import org.mifos.connector.common.gsma.dto.GSMATransaction; +import org.mifos.connector.common.gsma.dto.GsmaParty; +import org.mifos.connector.common.gsma.dto.IdDocument; +import org.mifos.connector.common.gsma.dto.InternationalTransferInformation; +import org.mifos.connector.common.gsma.dto.Kyc; +import org.mifos.connector.common.gsma.dto.PostalAddress; +import org.mifos.connector.common.gsma.dto.SubjectName; + +public class GSMATransferHelper { + + public GSMATransaction gsmaTransactionRequestBodyHelper(String amount, GsmaParty payer, GsmaParty payee, String currency, + String requestingOrganisationTransactionReference, String originalTransactionReference, String subType, String type, + String descriptionText, Fee fees, String geocCode, InternationalTransferInformation internationalTransferInformation, + String oneTimeCode, Kyc receiverKyc, Kyc senderKyc, String servicingIdentity, String requestDate) throws JSONException { + GSMATransaction gsmaTransaction = new GSMATransaction(); + gsmaTransaction.setAmount(amount); + gsmaTransaction.setCurrency(currency); + gsmaTransaction.setCreditParty(new GsmaParty[] { payee }); + gsmaTransaction.setDebitParty(new GsmaParty[] { payer }); + gsmaTransaction.setRequestingOrganisationTransactionReference(requestingOrganisationTransactionReference); + gsmaTransaction.setOriginalTransactionReference(originalTransactionReference); + gsmaTransaction.setType(type); + gsmaTransaction.setSubType(subType); + gsmaTransaction.setDescriptionText(descriptionText); + gsmaTransaction.setFees(new Fee[] { fees }); + gsmaTransaction.setGeoCode(geocCode); + gsmaTransaction.setInternationalTransferInformation(internationalTransferInformation); + gsmaTransaction.setOneTimeCode(oneTimeCode); + gsmaTransaction.setReceiverKyc(receiverKyc); + gsmaTransaction.setSenderKyc(senderKyc); + gsmaTransaction.setServicingIdentity(servicingIdentity); + gsmaTransaction.setRequestDate(requestDate); + return gsmaTransaction; + } + + public GsmaParty gsmaPartyHelper(String key, String value) { + GsmaParty gsmaParty = new GsmaParty(); + gsmaParty.setKey(key); + gsmaParty.setValue(value); + return gsmaParty; + } + + public Fee feeHelper(String amount, String currency, String feeType) { + Fee fee = new Fee(); + fee.setFeeAmount(amount); + fee.setFeeCurrency(currency); + fee.setFeeType(feeType); + return fee; + } + + public InternationalTransferInformation internationalTransferInformationHelper(String quotationReference, String quoteId, + String deliveryMethod, String originCountry, String receivingCountry, String relationshipSender, String remittancePurpose) { + InternationalTransferInformation internationalTransferInformation = new InternationalTransferInformation(); + internationalTransferInformation.setQuotationReference(quotationReference); + internationalTransferInformation.setQuoteId(quoteId); + internationalTransferInformation.setDeliveryMethod(deliveryMethod); + internationalTransferInformation.setOriginCountry(originCountry); + internationalTransferInformation.setReceivingCountry(receivingCountry); + internationalTransferInformation.setRelationshipSender(relationshipSender); + internationalTransferInformation.setRemittancePurpose(remittancePurpose); + return internationalTransferInformation; + } + + public IdDocument idDocumentHelper(String idType, String idNumber, String issuerCountry, String expiryDate, String issueDate, + String issuer, String issuerPlace) { + IdDocument idDocument = new IdDocument(); + idDocument.setIdType(idType); + idDocument.setIdNumber(idNumber); + idDocument.setIssuerCountry(issuerCountry); + idDocument.setIssuerCountry(expiryDate); + idDocument.setIssueDate(issueDate); + idDocument.setIssuer(issuer); + idDocument.setIssuerPlace(issuerPlace); + return idDocument; + } + + public PostalAddress postalAddressHelper(String addressLine1, String addressLine2, String addressLine3, String city, String country, + String postalCode, String stateProvince) { + PostalAddress postalAddress = new PostalAddress(); + postalAddress.setAddressLine1(addressLine1); + postalAddress.setAddressLine2(addressLine2); + postalAddress.setAddressLine3(addressLine3); + postalAddress.setCity(city); + postalAddress.setCountry(country); + postalAddress.setPostalCode(postalCode); + postalAddress.setStateProvince(stateProvince); + return postalAddress; + } + + public SubjectName subjectNameHelper(String firstName, String lastName, String middleName, String title, String nativeName) { + SubjectName subjectName = new SubjectName(); + subjectName.setFirstName(firstName); + subjectName.setLastName(lastName); + subjectName.setMiddleName(middleName); + subjectName.setTitle(title); + subjectName.setNativeName(nativeName); + return subjectName; + } + + public Kyc kycHelper(String birthCountry, String dateOfBirth, String contactPhone, String emailAddress, String employerName, + char gender, IdDocument idDocument, String nationality, String occupation, PostalAddress postalAddress, + SubjectName subjectName) { + Kyc kyc = new Kyc(); + kyc.setIdDocument(new IdDocument[] { idDocument }); + kyc.setBirthCountry(birthCountry); + kyc.setDateOfBirth(dateOfBirth); + kyc.setContactPhone(contactPhone); + kyc.setEmployerName(employerName); + kyc.setEmailAddress(emailAddress); + kyc.setGender(gender); + kyc.setNationality(nationality); + kyc.setOccupation(occupation); + kyc.setPostalAddress(postalAddress); + kyc.setSubjectName(subjectName); + return kyc; + } + +} diff --git a/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/GsmaTransactionHelper.java b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/GsmaTransactionHelper.java new file mode 100644 index 000000000..783c97c5a --- /dev/null +++ b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/GsmaTransactionHelper.java @@ -0,0 +1,35 @@ +package org.mifos.integrationtest.common; + +import java.util.ArrayList; +import java.util.List; +import org.mifos.connector.common.gsma.dto.CustomData; +import org.mifos.connector.common.gsma.dto.GsmaTransfer; +import org.mifos.connector.common.gsma.dto.Party; + +public class GsmaTransactionHelper { + + public GsmaTransfer gsmaTransferHelper(String requestingOrganisationTransactionReference, String subType, String type, String amount, + String currency, String descriptionText, String requestDate, List customData, List payer, + List payee) { + GsmaTransfer requestDTO = new GsmaTransfer(requestingOrganisationTransactionReference, subType, type, amount, currency, + descriptionText, requestDate, customData, payer, payee); + return requestDTO; + } + + public List customDataListHelper(List customDataList, String key, String value) { + CustomData customData = new CustomData(); + customData.setKey(key); + customData.setValue(value); + customDataList.add(customData); + return customDataList; + } + + public List partyListHelper(String partyIdType, String partyIdIdentifier) { + List partyList = new ArrayList<>(); + Party party = new Party(); + party.setPartyIdType(partyIdType); + party.setPartyIdIdentifier(partyIdIdentifier); + partyList.add(party); + return partyList; + } +} diff --git a/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/HttpMethod.java b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/HttpMethod.java new file mode 100644 index 000000000..4c9072b52 --- /dev/null +++ b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/HttpMethod.java @@ -0,0 +1,5 @@ +package org.mifos.integrationtest.common; + +public enum HttpMethod { + GET, POST, PUT, DELETE +} diff --git a/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/Pair.java b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/Pair.java new file mode 100644 index 000000000..c5b148762 --- /dev/null +++ b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/Pair.java @@ -0,0 +1,28 @@ +package org.mifos.integrationtest.common; + +public class Pair { + + private K key; + private V value; + + public Pair(K key, V value) { + this.key = key; + this.value = value; + } + + public K getKey() { + return key; + } + + public void setKey(K key) { + this.key = key; + } + + public V getValue() { + return value; + } + + public void setValue(V value) { + this.value = value; + } +} diff --git a/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/TransactionHelper.java b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/TransactionHelper.java new file mode 100644 index 000000000..c4e7f6940 --- /dev/null +++ b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/TransactionHelper.java @@ -0,0 +1,32 @@ +package org.mifos.integrationtest.common; + +import org.mifos.connector.common.channel.dto.TransactionChannelRequestDTO; +import org.mifos.connector.common.mojaloop.dto.MoneyData; +import org.mifos.connector.common.mojaloop.dto.Party; +import org.mifos.connector.common.mojaloop.dto.PartyIdInfo; +import org.mifos.connector.common.mojaloop.type.IdentifierType; + +public class TransactionHelper { + + public TransactionChannelRequestDTO transactionChannelRequestHelper(Party payer, Party payee, MoneyData amount) { + TransactionChannelRequestDTO requestDTO = new TransactionChannelRequestDTO(); + requestDTO.setPayer(payer); + requestDTO.setPayee(payee); + requestDTO.setAmount(amount); + return requestDTO; + } + + public Party partyHelper(IdentifierType partyIdType, String partyIdentifier) { + PartyIdInfo partyIdInfo = new PartyIdInfo(partyIdType, partyIdentifier); + Party party = new Party(); + party.setPartyIdInfo(partyIdInfo); + return party; + } + + public MoneyData amountHelper(String amount, String currency) { + MoneyData moneyData = new MoneyData(); + moneyData.setAmount(amount); + moneyData.setCurrency(currency); + return moneyData; + } +} diff --git a/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/TransferHelper.java b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/TransferHelper.java new file mode 100644 index 000000000..30d9211bd --- /dev/null +++ b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/TransferHelper.java @@ -0,0 +1,54 @@ +package org.mifos.integrationtest.common; + +import org.json.JSONException; +import org.json.JSONObject; + +public final class TransferHelper { + + private TransferHelper() {} + + public static JSONObject getTransferRequestBody() throws JSONException { + + JSONObject body = new JSONObject(); + body.put("payer", getPartyObject("27710101999")); + body.put("payee", getPartyObject("27710102999")); + body.put("amount", getAmountObject("1")); + return body; + } + + public static JSONObject getTransferRequestBody(String payerIdentifier) throws JSONException { + + JSONObject body = new JSONObject(); + body.put("payer", getPartyObject(payerIdentifier)); + body.put("payee", getPartyObject(payerIdentifier)); + body.put("amount", getAmountObject("1")); + return body; + } + + public static JSONObject getTransferRequestBody(String payerIdentifier, String payeeIdentifier, String amount) throws JSONException { + + JSONObject body = new JSONObject(); + body.put("payer", getPartyObject(payerIdentifier)); + body.put("payee", getPartyObject(payeeIdentifier)); + body.put("amount", getAmountObject(amount)); + return body; + } + + private static JSONObject getPartyObject(String value) throws JSONException { + + JSONObject partyIdObject = new JSONObject(); + partyIdObject.put("partyIdType", "MSISDN"); + partyIdObject.put("partyIdentifier", value); + + JSONObject partyObject = new JSONObject(); + partyObject.put("partyIdInfo", partyIdObject); + return partyObject; + } + + private static JSONObject getAmountObject(String amount) throws JSONException { + JSONObject amountObject = new JSONObject(); + amountObject.put("currency", "USD"); + amountObject.put("amount", amount); + return amountObject; + } +} diff --git a/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/UniqueNumberGenerator.java b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/UniqueNumberGenerator.java new file mode 100644 index 000000000..42f8b6e51 --- /dev/null +++ b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/UniqueNumberGenerator.java @@ -0,0 +1,49 @@ +package org.mifos.integrationtest.common; + +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.UUID; + +@SuppressWarnings("HideUtilityClassConstructor") +public class UniqueNumberGenerator { + + public static String generateUniqueNumber(int length) { + if (length <= 0) { + throw new IllegalArgumentException("Length must be greater than zero"); + } + + StringBuilder sb = new StringBuilder(); + + while (sb.length() < length) { + UUID uuid = UUID.randomUUID(); + String randomUUIDString = uuid.toString(); + + String hashedString = hashString(randomUUIDString); + + StringBuilder numericStringBuilder = new StringBuilder(); + for (char c : hashedString.toCharArray()) { + if (Character.isDigit(c)) { + numericStringBuilder.append(c); + } + } + + sb.append(numericStringBuilder); + } + + return sb.substring(0, length); + } + + private static String hashString(String input) { + try { + MessageDigest md = MessageDigest.getInstance("MD5"); + byte[] messageDigest = md.digest(input.getBytes()); + StringBuilder sb = new StringBuilder(); + for (byte b : messageDigest) { + sb.append(String.format("%02x", b)); + } + return sb.toString(); + } catch (NoSuchAlgorithmException e) { + throw new RuntimeException("Error occurred while hashing the string", e); + } + } +} diff --git a/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/Utils.java b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/Utils.java new file mode 100644 index 000000000..4114e53f7 --- /dev/null +++ b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/Utils.java @@ -0,0 +1,113 @@ +package org.mifos.integrationtest.common; + +import io.restassured.RestAssured; +import io.restassured.builder.RequestSpecBuilder; +import io.restassured.specification.RequestSpecification; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; +import java.util.List; +import org.apache.commons.io.IOUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public final class Utils { + + private Utils() {} + + private static final Logger log = LoggerFactory.getLogger(Utils.class); + public static final String TENANT_PARAM_NAME = "Platform-TenantId"; + public static final String REQUEST_TYPE_PARAM_NAME = "requestType"; + public static final String DEFAULT_TENANT = "gorilla"; + public static final String X_CORRELATIONID = "X-CorrelationID"; + public static final String X_CallbackURL = "X-CallbackURL"; + public static final String CONTENT_TYPE = "Content-Type"; + public static final String CONTENT_TYPE_VALUE = "application/json"; + public static final String HEADER_JWS_SIGNATURE = "X-SIGNATURE"; + public static final String HEADER_FILENAME = "filename"; + public static final String HEADER_PURPOSE = "purpose"; + public static final String QUERY_PARAM_TYPE = "type"; + public static final String HEADER_REGISTERING_INSTITUTE_ID = "X-Registering-Institution-ID"; + public static final String HEADER_PROGRAM_ID = "X-Program-ID"; + + public static void initializeRESTAssured() { + RestAssured.baseURI = "https://localhost"; + RestAssured.port = 8443; + } + + public static void sleep(int seconds) { + try { + Thread.sleep(seconds * 1000); + } catch (InterruptedException e) { + log.debug("Unexpected InterruptedException {}", e); + throw new IllegalStateException("Unexpected InterruptedException", e); + } + } + + public static RequestSpecification getDefaultSpec() { + RequestSpecification requestSpec = new RequestSpecBuilder().build(); + requestSpec.relaxedHTTPSValidation(); + return requestSpec; + } + + public static RequestSpecification getDefaultSpec(String tenant, String clientCorrelationId) { + RequestSpecification requestSpec = getDefaultSpec(); + requestSpec.header(TENANT_PARAM_NAME, tenant); + requestSpec.header(X_CORRELATIONID, clientCorrelationId); + requestSpec.header(CONTENT_TYPE, "application/json"); + return requestSpec; + } + + public static RequestSpecification getDefaultSpec(String tenant) { + RequestSpecification requestSpec = getDefaultSpec(); + requestSpec.header(TENANT_PARAM_NAME, tenant); + // requestSpec.header(X_CORRELATIONID, "123456789"); + requestSpec.header(CONTENT_TYPE, "application/json"); + return requestSpec; + } + + public static String getAbsoluteFilePathToResource(String fileName) { + return "src/test/java/resources/batch_demo_csv/" + fileName; + } + + public static RequestSpecification getRequestType(String requestType) { + RequestSpecification requestSpec = getDefaultSpec(); + requestSpec.header(REQUEST_TYPE_PARAM_NAME, requestType); + return requestSpec; + } + + public static String getUTCFormat(String dateTime, String interfaceTimezone) { + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); + LocalDateTime localDateTime = LocalDateTime.parse(dateTime, formatter); + ZoneId interfaceZone = ZoneId.of(interfaceTimezone); + ZonedDateTime interfaceDateTime = ZonedDateTime.of(localDateTime, interfaceZone); + ZonedDateTime gmtDateTime = interfaceDateTime.withZoneSameInstant(ZoneId.of("GMT")); + DateTimeFormatter gmtFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); + String gmtDateTimeString = gmtDateTime.format(gmtFormatter); + return gmtDateTimeString; + } + + public static List extractClientCorrelationIdFromCsv(String filename, List requestIds) { + File file = new File(Utils.getAbsoluteFilePathToResource(filename)); + try { + InputStream inputStream = new FileInputStream(file); + List line = IOUtils.readLines(inputStream, StandardCharsets.UTF_8); + line.remove(0); + while (line.size() > 0) { + String[] temp = line.get(0).split(","); + requestIds.add(temp[1]); + line.remove(0); + } + } catch (IOException e) { + log.debug(e.getMessage()); + } + return requestIds; + } + +} diff --git a/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/Alias.java b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/Alias.java new file mode 100644 index 000000000..345846457 --- /dev/null +++ b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/Alias.java @@ -0,0 +1,16 @@ +package org.mifos.integrationtest.common.dto; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +public class Alias { + + private String aliasType; + private String aliasId; +} diff --git a/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/BatchApiResponseDTO.java b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/BatchApiResponseDTO.java new file mode 100644 index 000000000..1f83f0865 --- /dev/null +++ b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/BatchApiResponseDTO.java @@ -0,0 +1,19 @@ +package org.mifos.integrationtest.common.dto; + +import io.cucumber.core.internal.com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public class BatchApiResponseDTO { + + @JsonProperty("batch_id") + private String batchId; + + @JsonProperty("request_id") + private String requestId; + @JsonProperty("status") + private String status; + +} diff --git a/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/BatchRequestDTO.java b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/BatchRequestDTO.java new file mode 100644 index 000000000..22a746436 --- /dev/null +++ b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/BatchRequestDTO.java @@ -0,0 +1,25 @@ +package org.mifos.integrationtest.common.dto; + +import java.util.List; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +public class BatchRequestDTO { + + String requestId; + + List creditParty; + List debitParty; + + String paymentMode; + String amount; + String currency; + String descriptionText; + +} diff --git a/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/Bill.java b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/Bill.java new file mode 100644 index 000000000..057cc097b --- /dev/null +++ b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/Bill.java @@ -0,0 +1,16 @@ +package org.mifos.integrationtest.common.dto; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +public class Bill { + + private String billerName; + private double amount; +} diff --git a/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/BillDetails.java b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/BillDetails.java new file mode 100644 index 000000000..298f1fe1f --- /dev/null +++ b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/BillDetails.java @@ -0,0 +1,17 @@ +package org.mifos.integrationtest.common.dto; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +public class BillDetails { + + private String billId; + private String billerName; + private Double amount; +} diff --git a/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/BillRTPReqDTO.java b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/BillRTPReqDTO.java new file mode 100644 index 000000000..985143314 --- /dev/null +++ b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/BillRTPReqDTO.java @@ -0,0 +1,37 @@ +package org.mifos.integrationtest.common.dto; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +public class BillRTPReqDTO { + + private String clientCorrelationId; + private String billID; + private String requestType; + private PayerFSPDetail payerFspDetails; + private Alias alias; + private Bill billDetails; + + public BillRTPReqDTO(String clientCorrelationId, String billId, String requestType, PayerFSPDetail payerFSPDetail, Bill bill) { + this.clientCorrelationId = clientCorrelationId; + this.billDetails = bill; + this.billID = billId; + this.requestType = requestType; + this.payerFspDetails = payerFSPDetail; + } + + public BillRTPReqDTO(String clientCorrelationId, String billId, String requestType, Alias alias, Bill bill) { + this.clientCorrelationId = clientCorrelationId; + this.billDetails = bill; + this.billID = billId; + this.requestType = requestType; + this.alias = alias; + } + +} diff --git a/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/BillStatusReqDTO.java b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/BillStatusReqDTO.java new file mode 100644 index 000000000..7f6a027b5 --- /dev/null +++ b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/BillStatusReqDTO.java @@ -0,0 +1,14 @@ +package org.mifos.integrationtest.common.dto; + +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public class BillStatusReqDTO { + + private String rtpId; + private String requestId; + + public BillStatusReqDTO(String rtpId, String requestId) {} +} diff --git a/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/CollectionResponse.java b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/CollectionResponse.java new file mode 100644 index 000000000..c21377db6 --- /dev/null +++ b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/CollectionResponse.java @@ -0,0 +1,20 @@ +package org.mifos.integrationtest.common.dto; + +public class CollectionResponse { + + private String transactionId; + + public CollectionResponse(String transactionId) { + this.transactionId = transactionId; + } + + public CollectionResponse() {} + + public String getTransactionId() { + return transactionId; + } + + public void setTransactionId(String transactionId) { + this.transactionId = transactionId; + } +} diff --git a/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/ErrorDetails.java b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/ErrorDetails.java new file mode 100644 index 000000000..55a401278 --- /dev/null +++ b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/ErrorDetails.java @@ -0,0 +1,16 @@ +package org.mifos.integrationtest.common.dto; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +public class ErrorDetails { + + private String errorCode; + private String errorDescription; +} diff --git a/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/KeycloakTokenResponse.java b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/KeycloakTokenResponse.java new file mode 100644 index 000000000..95653c884 --- /dev/null +++ b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/KeycloakTokenResponse.java @@ -0,0 +1,39 @@ +package org.mifos.integrationtest.common.dto; + +import io.cucumber.core.internal.com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +public class KeycloakTokenResponse { + + @JsonProperty("access_token") + String accessToken; + + @JsonProperty("refresh_token") + String refreshToken; + + @JsonProperty("token_type") + String tokenType; + + @JsonProperty("session_state") + String sessionState; + + @JsonProperty("scope") + String scope; + + @JsonProperty("expires_in") + int expiresIn; + + @JsonProperty("refresh_expires_in") + int refreshTokenExpiresIn; + + @JsonProperty("not-before-policy") + int notBeforePolicy; + +} diff --git a/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/OperationsHelper.java b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/OperationsHelper.java new file mode 100644 index 000000000..c379c3bc4 --- /dev/null +++ b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/OperationsHelper.java @@ -0,0 +1,31 @@ +package org.mifos.integrationtest.common.dto; + +import java.util.ArrayList; +import java.util.List; +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +public final class OperationsHelper { + + private OperationsHelper() {} + + public static JSONObject getBulkFilterRequestBodyForExternalId(List externalIds) throws JSONException { + JSONObject body = new JSONObject(); + body.put("externalId", getJSONArray(externalIds)); + return body; + } + + public static JSONObject getBulkFilterRequestBodyForExternalId(String externalId) throws JSONException { + List externalIds = new ArrayList<>(); + externalIds.add(externalId); + return getBulkFilterRequestBodyForExternalId(externalIds); + } + + private static JSONArray getJSONArray(List externalIds) { + JSONArray array = new JSONArray(); + externalIds.forEach(array::put); + return array; + } + +} diff --git a/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/Party.java b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/Party.java new file mode 100644 index 000000000..d854fb964 --- /dev/null +++ b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/Party.java @@ -0,0 +1,17 @@ +package org.mifos.integrationtest.common.dto; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +public class Party { + + String key; + String value; + +} diff --git a/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/PayerFSPDetail.java b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/PayerFSPDetail.java new file mode 100644 index 000000000..17ebff360 --- /dev/null +++ b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/PayerFSPDetail.java @@ -0,0 +1,16 @@ +package org.mifos.integrationtest.common.dto; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +public class PayerFSPDetail { + + private String payerFSPID; + private String financialAddress; +} diff --git a/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/PayerRequestDTO.java b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/PayerRequestDTO.java new file mode 100644 index 000000000..bed6be646 --- /dev/null +++ b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/PayerRequestDTO.java @@ -0,0 +1,18 @@ +package org.mifos.integrationtest.common.dto; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +public class PayerRequestDTO { + + private String transactionId; + private Integer rtpId; + private BillDetails billDetails; + +} diff --git a/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/PaymentStatusCheckReqDto.java b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/PaymentStatusCheckReqDto.java new file mode 100644 index 000000000..ef5808e3d --- /dev/null +++ b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/PaymentStatusCheckReqDto.java @@ -0,0 +1,34 @@ +package org.mifos.integrationtest.common.dto; + +import java.util.List; + +public class PaymentStatusCheckReqDto { + + @Override + public String toString() { + return "PaymentStatusCheckReqDto{" + "requestIds:" + requestIds + ", payeePartyIds:" + payeePartyIds + '}'; + } + + List requestIds; + List payeePartyIds; + + public PaymentStatusCheckReqDto() { + + } + + public List getRequestIds() { + return requestIds; + } + + public void setRequestIds(List requestIds) { + this.requestIds = requestIds; + } + + public List getPayeePartyIds() { + return payeePartyIds; + } + + public void setPayeePartyIds(List payeePartyIds) { + this.payeePartyIds = payeePartyIds; + } +} diff --git a/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/billpayp2g/BillPaymentsReqDTO.java b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/billpayp2g/BillPaymentsReqDTO.java new file mode 100644 index 000000000..51102e212 --- /dev/null +++ b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/billpayp2g/BillPaymentsReqDTO.java @@ -0,0 +1,61 @@ +package org.mifos.integrationtest.common.dto.billpayp2g; + +import java.io.Serializable; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import org.springframework.stereotype.Component; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +@Component +public class BillPaymentsReqDTO implements Serializable { + + @Override + public String toString() { + return "BillPaymentsReqDTO{" + "billInquiryRequestId='" + billInquiryRequestId + '\'' + ", billId='" + billId + '\'' + + ", paymentReferenceID='" + paymentReferenceID + '\'' + '}'; + } + + private String billInquiryRequestId; + private String billId; + private String paymentReferenceID; + + private String clientCorrelationId; + + public String getClientCorrelationId() { + return clientCorrelationId; + } + + public void setClientCorrelationId(String clientCorrelationId) { + this.clientCorrelationId = clientCorrelationId; + } + + public String getBillInquiryRequestId() { + return billInquiryRequestId; + } + + public void setBillInquiryRequestId(String billInquiryRequestId) { + this.billInquiryRequestId = billInquiryRequestId; + } + + public String getBillId() { + return billId; + } + + public void setBillId(String billId) { + this.billId = billId; + } + + public String getPaymentReferenceID() { + return paymentReferenceID; + } + + public void setPaymentReferenceID(String paymentReferenceID) { + this.paymentReferenceID = paymentReferenceID; + } + +} diff --git a/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/kong/Access.java b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/kong/Access.java new file mode 100644 index 000000000..24d546782 --- /dev/null +++ b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/kong/Access.java @@ -0,0 +1,15 @@ +package org.mifos.integrationtest.common.dto.kong; + +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public class Access { + + public boolean manageGroupMembership; + public boolean view; + public boolean mapRoles; + public boolean impersonate; + public boolean manage; +} diff --git a/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/kong/KeycloakUpdateRequest.java b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/kong/KeycloakUpdateRequest.java new file mode 100644 index 000000000..ac62a0f70 --- /dev/null +++ b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/kong/KeycloakUpdateRequest.java @@ -0,0 +1,13 @@ +package org.mifos.integrationtest.common.dto.kong; + +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public class KeycloakUpdateRequest { + + private String type; + private String value; + private boolean temporary; +} diff --git a/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/kong/KeycloakUser.java b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/kong/KeycloakUser.java new file mode 100644 index 000000000..48b3dc453 --- /dev/null +++ b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/kong/KeycloakUser.java @@ -0,0 +1,28 @@ +package org.mifos.integrationtest.common.dto.kong; + +import java.util.ArrayList; +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public class KeycloakUser { + + public String id; + public String username; + public String firstName; + public String lastName; + + public boolean enabled; + public boolean emailVerified; + public Access access; + public ArrayList realmRoles; + + public void addRealmRoles(String role) { + if (realmRoles == null) { + realmRoles = new ArrayList<>(); + } + realmRoles.add(role); + } + +} diff --git a/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/kong/KongConsumer.java b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/kong/KongConsumer.java new file mode 100644 index 000000000..fdad18999 --- /dev/null +++ b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/kong/KongConsumer.java @@ -0,0 +1,22 @@ +package org.mifos.integrationtest.common.dto.kong; + +import io.cucumber.core.internal.com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +public class KongConsumer { + + private String id; + + private String username; + + @JsonProperty("custom_id") + private String customId; + +} diff --git a/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/kong/KongConsumerKey.java b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/kong/KongConsumerKey.java new file mode 100644 index 000000000..1c53b8753 --- /dev/null +++ b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/kong/KongConsumerKey.java @@ -0,0 +1,17 @@ +package org.mifos.integrationtest.common.dto.kong; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +public class KongConsumerKey { + + private String id; + + private String key; +} diff --git a/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/kong/KongKeyAuthPluginConfig.java b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/kong/KongKeyAuthPluginConfig.java new file mode 100644 index 000000000..600269969 --- /dev/null +++ b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/kong/KongKeyAuthPluginConfig.java @@ -0,0 +1,15 @@ +package org.mifos.integrationtest.common.dto.kong; + +import io.cucumber.core.internal.com.fasterxml.jackson.annotation.JsonProperty; +import java.util.ArrayList; +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public class KongKeyAuthPluginConfig { + + @JsonProperty("key_names") + private ArrayList keyNames; + +} diff --git a/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/kong/KongPlugin.java b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/kong/KongPlugin.java new file mode 100644 index 000000000..1965b3224 --- /dev/null +++ b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/kong/KongPlugin.java @@ -0,0 +1,23 @@ +package org.mifos.integrationtest.common.dto.kong; + +import java.util.Map; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +public class KongPlugin { + + private String id; + + private String name; + + private Map config; + + private boolean enabled; + +} diff --git a/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/kong/KongRoute.java b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/kong/KongRoute.java new file mode 100644 index 000000000..da97c075c --- /dev/null +++ b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/kong/KongRoute.java @@ -0,0 +1,23 @@ +package org.mifos.integrationtest.common.dto.kong; + +import java.util.ArrayList; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +public class KongRoute { + + private String id; + + private String name; + + private ArrayList hosts; + + private ArrayList paths; + +} diff --git a/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/kong/KongService.java b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/kong/KongService.java new file mode 100644 index 000000000..79ec0697c --- /dev/null +++ b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/kong/KongService.java @@ -0,0 +1,22 @@ +package org.mifos.integrationtest.common.dto.kong; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +public class KongService { + + private String id; + + private String url; + + private String name; + + private String protocol; + +} diff --git a/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/mojaloop/AddParticipantRequestBody.java b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/mojaloop/AddParticipantRequestBody.java new file mode 100644 index 000000000..1ee0c21f5 --- /dev/null +++ b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/mojaloop/AddParticipantRequestBody.java @@ -0,0 +1,15 @@ +package org.mifos.integrationtest.common.dto.mojaloop; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.Setter; + +@AllArgsConstructor +@Getter +@Setter +public class AddParticipantRequestBody { + + String name; + + String currency; +} diff --git a/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/mojaloop/AddUserAlsRequest.java b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/mojaloop/AddUserAlsRequest.java new file mode 100644 index 000000000..a32149c4a --- /dev/null +++ b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/mojaloop/AddUserAlsRequest.java @@ -0,0 +1,15 @@ +package org.mifos.integrationtest.common.dto.mojaloop; + +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@NoArgsConstructor +public class AddUserAlsRequest { + + String fspId; + + String currency; +} diff --git a/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/mojaloop/Amount.java b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/mojaloop/Amount.java new file mode 100644 index 000000000..da7372fa2 --- /dev/null +++ b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/mojaloop/Amount.java @@ -0,0 +1,13 @@ +package org.mifos.integrationtest.common.dto.mojaloop; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +@Getter +@AllArgsConstructor +public class Amount { + + Long amount; + + String currency; +} diff --git a/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/mojaloop/CallbackRequestBody.java b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/mojaloop/CallbackRequestBody.java new file mode 100644 index 000000000..bb091487c --- /dev/null +++ b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/mojaloop/CallbackRequestBody.java @@ -0,0 +1,15 @@ +package org.mifos.integrationtest.common.dto.mojaloop; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.Setter; + +@AllArgsConstructor +@Getter +@Setter +public class CallbackRequestBody { + + String type; + + String value; +} diff --git a/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/mojaloop/Endpoint.java b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/mojaloop/Endpoint.java new file mode 100644 index 000000000..3c65f2bb2 --- /dev/null +++ b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/mojaloop/Endpoint.java @@ -0,0 +1,13 @@ +package org.mifos.integrationtest.common.dto.mojaloop; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +@AllArgsConstructor +@Getter +public class Endpoint { + + String value; + + String endpointType; +} diff --git a/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/mojaloop/HubAccountSetupRequestBody.java b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/mojaloop/HubAccountSetupRequestBody.java new file mode 100644 index 000000000..a80640c2e --- /dev/null +++ b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/mojaloop/HubAccountSetupRequestBody.java @@ -0,0 +1,13 @@ +package org.mifos.integrationtest.common.dto.mojaloop; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +@AllArgsConstructor +@Getter +public class HubAccountSetupRequestBody { + + String type; + + String currency; +} diff --git a/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/mojaloop/InitialPositionAndLimitRequestBody.java b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/mojaloop/InitialPositionAndLimitRequestBody.java new file mode 100644 index 000000000..c59ac23e8 --- /dev/null +++ b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/mojaloop/InitialPositionAndLimitRequestBody.java @@ -0,0 +1,17 @@ +package org.mifos.integrationtest.common.dto.mojaloop; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.Setter; + +@AllArgsConstructor +@Getter +@Setter +public class InitialPositionAndLimitRequestBody { + + String currency; + + Limit limit; + + Long initialPosition; +} diff --git a/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/mojaloop/Limit.java b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/mojaloop/Limit.java new file mode 100644 index 000000000..393749be2 --- /dev/null +++ b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/mojaloop/Limit.java @@ -0,0 +1,14 @@ +package org.mifos.integrationtest.common.dto.mojaloop; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.Setter; + +@AllArgsConstructor +@Getter +@Setter +public class Limit { + + String type; + Long value; +} diff --git a/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/mojaloop/OracleOnboardRequestBody.java b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/mojaloop/OracleOnboardRequestBody.java new file mode 100644 index 000000000..377872bb9 --- /dev/null +++ b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/mojaloop/OracleOnboardRequestBody.java @@ -0,0 +1,14 @@ +package org.mifos.integrationtest.common.dto.mojaloop; + +import lombok.Builder; +import lombok.Getter; + +@Builder +@Getter +public class OracleOnboardRequestBody { + + String oracleIdType; + Endpoint endpoint; + String currency; + Boolean isDefault; +} diff --git a/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/mojaloop/RecordFundsRequestBody.java b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/mojaloop/RecordFundsRequestBody.java new file mode 100644 index 000000000..6651d7806 --- /dev/null +++ b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/mojaloop/RecordFundsRequestBody.java @@ -0,0 +1,19 @@ +package org.mifos.integrationtest.common.dto.mojaloop; + +import lombok.Builder; +import lombok.Getter; + +@Getter +@Builder +public class RecordFundsRequestBody { + + String transferId; + + String externalReference; + + String action; + + String reason; + + Amount amount; +} diff --git a/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/mojaloop/SettlementModelRequestBody.java b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/mojaloop/SettlementModelRequestBody.java new file mode 100644 index 000000000..61894e5fb --- /dev/null +++ b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/mojaloop/SettlementModelRequestBody.java @@ -0,0 +1,21 @@ +package org.mifos.integrationtest.common.dto.mojaloop; + +import lombok.Builder; +import lombok.Getter; +import lombok.Setter; + +@Builder +@Getter +@Setter +public class SettlementModelRequestBody { + + private String name; + private String settlementGranularity; + private String settlementInterchange; + private String settlementDelay; + private String currency; + private boolean requireLiquidityCheck; + private String ledgerAccountType; + private boolean autoPositionReset; + private String settlementAccountType; +} diff --git a/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/operationsapp/ActuatorResponse.java b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/operationsapp/ActuatorResponse.java new file mode 100644 index 000000000..0c5bb7d77 --- /dev/null +++ b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/operationsapp/ActuatorResponse.java @@ -0,0 +1,13 @@ +package org.mifos.integrationtest.common.dto.operationsapp; + +import java.util.ArrayList; +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public class ActuatorResponse { + + public String status; + public ArrayList groups; +} diff --git a/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/operationsapp/Batch.java b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/operationsapp/Batch.java new file mode 100644 index 000000000..0772a8259 --- /dev/null +++ b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/operationsapp/Batch.java @@ -0,0 +1,44 @@ +package org.mifos.integrationtest.common.dto.operationsapp; + +import java.util.Date; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +@SuppressWarnings("checkstyle:membername") +public class Batch { + + private String batchId; + private String subBatchId; + private String requestId; + private String requestFile; + private String result_file; + // Please update this variable name in the batch and remove the suppressWaning annotation + private String note; + private String paymentMode; + private String registeringInstitutionId; + private String payerFsp; + private String correlationId; + + private Long totalTransactions; + private Long ongoing; + private Long failed; + private Long completed; + private Long totalAmount; + private Long ongoingAmount; + private Long failedAmount; + private Long completedAmount; + private Long workflowKey; + private Long workflowInstanceKey; + private Long approvedAmount; + private Long approvedCount; + + private Date resultGeneratedAt; + private Date startedAt; + private Date completedAt; +} diff --git a/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/operationsapp/BatchAndSubBatchSummaryResponse.java b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/operationsapp/BatchAndSubBatchSummaryResponse.java new file mode 100644 index 000000000..6a257d59b --- /dev/null +++ b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/operationsapp/BatchAndSubBatchSummaryResponse.java @@ -0,0 +1,72 @@ +package org.mifos.integrationtest.common.dto.operationsapp; + +import com.fasterxml.jackson.annotation.JsonInclude; +import java.math.BigDecimal; +import java.util.Date; +import java.util.List; +import java.util.Set; +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public class BatchAndSubBatchSummaryResponse { + + private String batchId; + + private String requestId; + + private Date startedAt; + + private Date completedAt; + + private String registeringInstitutionId; + + private Long total; + + private Long ongoing; + + private Long successful; + + private Long failed; + + private BigDecimal totalAmount; + + private BigDecimal pendingAmount; + + private BigDecimal successfulAmount; + + private BigDecimal failedAmount; + + private String file; + + private String notes; + + private String createdAt; + + private String status; + + private String modes; + + private String purpose; + + private String failedPercentage; + + private String successPercentage; + + private String payerFsp; + private Set payeeFsp; + + private String generatedBy; + + private String generatedAt; + + private Long totalSubBatches; + + private Long approvedTransactionCount; + + private Long approvedAmount; + @JsonInclude(JsonInclude.Include.NON_NULL) + private List subBatchSummaryList; + private Long totalInstructionCount; +} diff --git a/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/operationsapp/BatchDTO.java b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/operationsapp/BatchDTO.java new file mode 100644 index 000000000..19c918521 --- /dev/null +++ b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/operationsapp/BatchDTO.java @@ -0,0 +1,36 @@ +package org.mifos.integrationtest.common.dto.operationsapp; + +import java.math.BigDecimal; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +public class BatchDTO { + + private String batchId; + private String requestId; + private String file; + private String notes; + private String createdAt; + private String status; + private String modes; + private String purpose; + private String failPercentage; + private String successPercentage; + private Long total; + private Long ongoing; + private Long failed; + private Long successful; + private BigDecimal totalAmount; + private BigDecimal successfulAmount; + private BigDecimal pendingAmount; + private BigDecimal failedAmount; + private BigDecimal approvedAmount; + private BigDecimal approvedCount; + +} diff --git a/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/operationsapp/BatchDetailResponse.java b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/operationsapp/BatchDetailResponse.java new file mode 100644 index 000000000..988c995b2 --- /dev/null +++ b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/operationsapp/BatchDetailResponse.java @@ -0,0 +1,15 @@ +package org.mifos.integrationtest.common.dto.operationsapp; + +import java.util.List; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import org.mifos.connector.common.operations.dto.Transfer; + +@Getter +@Setter +@NoArgsConstructor +public class BatchDetailResponse { + + List content; +} diff --git a/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/operationsapp/BatchPaginatedResponse.java b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/operationsapp/BatchPaginatedResponse.java new file mode 100644 index 000000000..6e475d32e --- /dev/null +++ b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/operationsapp/BatchPaginatedResponse.java @@ -0,0 +1,18 @@ +package org.mifos.integrationtest.common.dto.operationsapp; + +import java.util.List; +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public class BatchPaginatedResponse { + + long totalBatches; + long totalTransactions; + long totalAmount; + long totalApprovedCount; + long totalApprovedAmount; + long totalSubBatchesCreated; + List data; +} diff --git a/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/operationsapp/BatchTransactionResponse.java b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/operationsapp/BatchTransactionResponse.java new file mode 100644 index 000000000..67cfcfc76 --- /dev/null +++ b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/operationsapp/BatchTransactionResponse.java @@ -0,0 +1,20 @@ +package org.mifos.integrationtest.common.dto.operationsapp; + +import io.cucumber.core.internal.com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +public class BatchTransactionResponse { + + @JsonProperty("PollingPath") + private String pollingPath; + + @JsonProperty("SuggestedCallbackSeconds") + private String suggestedCallbackSeconds; +} diff --git a/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/operationsapp/GetTransactionRequestResponse.java b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/operationsapp/GetTransactionRequestResponse.java new file mode 100644 index 000000000..a3416a298 --- /dev/null +++ b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/operationsapp/GetTransactionRequestResponse.java @@ -0,0 +1,90 @@ +package org.mifos.integrationtest.common.dto.operationsapp; + +import java.util.ArrayList; + +public class GetTransactionRequestResponse { + + private ArrayList content; + private int totalPages; + private int totalElements; + private boolean last; + private int numberOfElements; + private Sort sort; + private boolean first; + private int size; + private int number; + + public GetTransactionRequestResponse() {} + + public ArrayList getContent() { + return content; + } + + public void setContent(ArrayList content) { + this.content = content; + } + + public int getTotalPages() { + return totalPages; + } + + public void setTotalPages(int totalPages) { + this.totalPages = totalPages; + } + + public int getTotalElements() { + return totalElements; + } + + public void setTotalElements(int totalElements) { + this.totalElements = totalElements; + } + + public boolean isLast() { + return last; + } + + public void setLast(boolean last) { + this.last = last; + } + + public int getNumberOfElements() { + return numberOfElements; + } + + public void setNumberOfElements(int numberOfElements) { + this.numberOfElements = numberOfElements; + } + + public Sort getSort() { + return sort; + } + + public void setSort(Sort sort) { + this.sort = sort; + } + + public boolean isFirst() { + return first; + } + + public void setFirst(boolean first) { + this.first = first; + } + + public int getSize() { + return size; + } + + public void setSize(int size) { + this.size = size; + } + + public int getNumber() { + return number; + } + + public void setNumber(int number) { + this.number = number; + } +} diff --git a/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/operationsapp/Instruction.java b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/operationsapp/Instruction.java new file mode 100644 index 000000000..233b99f2e --- /dev/null +++ b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/operationsapp/Instruction.java @@ -0,0 +1,22 @@ +package org.mifos.integrationtest.common.dto.operationsapp; + +import java.math.BigDecimal; +import java.util.Date; +import lombok.Getter; +import lombok.Setter; +import org.mifos.connector.common.operations.type.TransferStatus; + +@Getter +@Setter +public class Instruction { + + private String instructionId; + private String payerFsp; + private String payeeFunctionalId; + private BigDecimal amount; + private TransferStatus status; + private String reason; + private Date startedAt; + private Date completedAt; + private String subBatchId; +} diff --git a/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/operationsapp/PaymentBatchDetail.java b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/operationsapp/PaymentBatchDetail.java new file mode 100644 index 000000000..8a2c634f9 --- /dev/null +++ b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/operationsapp/PaymentBatchDetail.java @@ -0,0 +1,34 @@ +package org.mifos.integrationtest.common.dto.operationsapp; + +import java.math.BigDecimal; +import java.util.Date; +import java.util.List; +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public class PaymentBatchDetail { + + private String batchId; + private String payerFsp; + private String reportGeneratedBy; + private String reportGeneratedAt; + private Date startedAt; + private Date completedAt; + private String registeringInstitutionId; + private String status; + private List subBatchList; + private List instructionList; + private Long total; + private Long ongoing; + private Long successful; + private Long failed; + private BigDecimal totalAmount; + private BigDecimal pendingAmount; + private BigDecimal successfulAmount; + private BigDecimal failedAmount; + private Long totalInstruction; + private Long totalBatchAmount; + private String clientCorrelationId; +} diff --git a/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/operationsapp/Sort.java b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/operationsapp/Sort.java new file mode 100644 index 000000000..4d41ed7b5 --- /dev/null +++ b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/operationsapp/Sort.java @@ -0,0 +1,61 @@ +package org.mifos.integrationtest.common.dto.operationsapp; + +public class Sort { + + private String direction; + private String property; + private boolean ignoreCase; + private String nullHandling; + private boolean descending; + private boolean ascending; + + public Sort() {} + + public String getDirection() { + return direction; + } + + public void setDirection(String direction) { + this.direction = direction; + } + + public String getProperty() { + return property; + } + + public void setProperty(String property) { + this.property = property; + } + + public boolean isIgnoreCase() { + return ignoreCase; + } + + public void setIgnoreCase(boolean ignoreCase) { + this.ignoreCase = ignoreCase; + } + + public String getNullHandling() { + return nullHandling; + } + + public void setNullHandling(String nullHandling) { + this.nullHandling = nullHandling; + } + + public boolean isDescending() { + return descending; + } + + public void setDescending(boolean descending) { + this.descending = descending; + } + + public boolean isAscending() { + return ascending; + } + + public void setAscending(boolean ascending) { + this.ascending = ascending; + } +} diff --git a/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/operationsapp/SubBatchSummary.java b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/operationsapp/SubBatchSummary.java new file mode 100644 index 000000000..02dbc6e2d --- /dev/null +++ b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/operationsapp/SubBatchSummary.java @@ -0,0 +1,76 @@ +package org.mifos.integrationtest.common.dto.operationsapp; + +import java.math.BigDecimal; +import java.util.Date; +import java.util.List; +import java.util.Set; +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public class SubBatchSummary { + + private String subBatchId; + + private String batchId; + + private Date startedAt; + + private Date completedAt; + + private String registeringInstitutionId; + + private String requestId; + + private Long total; + + private Long ongoing; + + private Long successful; + + private Long failed; + + private BigDecimal totalAmount; + + private BigDecimal pendingAmount; + + private BigDecimal successfulAmount; + + private BigDecimal failedAmount; + + private String file; + + private String notes; + + private String createdAt; + + private String status; + + private String modes; + + private String purpose; + + private String failedPercentage; + + private String successPercentage; + + private String payerFsp; + + private Long approvedAmount; + + private Long approvedTransactionCount; + + private Set payeeFspSet; + + private List instructionList; + + private String budgetAccount; + + private String generatedBy; + + private String generatedAt; + + private Long totalInstructionCount; + +} diff --git a/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/operationsapp/TransactionRequest.java b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/operationsapp/TransactionRequest.java new file mode 100644 index 000000000..7c6593e80 --- /dev/null +++ b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/operationsapp/TransactionRequest.java @@ -0,0 +1,225 @@ +package org.mifos.integrationtest.common.dto.operationsapp; + +public class TransactionRequest { + + private int id; + private String workflowInstanceKey; + private String transactionId; + private long startedAt; + private Object completedAt; + private String state; + private Object payeeDfspId; + private String payeePartyId; + private String payeePartyIdType; + private Object payeeFee; + private Object payeeQuoteCode; + private Object payerDfspId; + private String payerPartyId; + private String payerPartyIdType; + private Object payerFee; + private Object payerQuoteCode; + private int amount; + private String currency; + private String direction; + private Object authType; + private String initiatorType; + private String scenario; + + private String externalId; + + private String clientCorrelationId; + + public TransactionRequest() {} + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getWorkflowInstanceKey() { + return workflowInstanceKey; + } + + public void setWorkflowInstanceKey(String workflowInstanceKey) { + this.workflowInstanceKey = workflowInstanceKey; + } + + public String getTransactionId() { + return transactionId; + } + + public void setTransactionId(String transactionId) { + this.transactionId = transactionId; + } + + public long getStartedAt() { + return startedAt; + } + + public void setStartedAt(long startedAt) { + this.startedAt = startedAt; + } + + public Object getCompletedAt() { + return completedAt; + } + + public void setCompletedAt(Object completedAt) { + this.completedAt = completedAt; + } + + public String getState() { + return state; + } + + public void setState(String state) { + this.state = state; + } + + public Object getPayeeDfspId() { + return payeeDfspId; + } + + public void setPayeeDfspId(Object payeeDfspId) { + this.payeeDfspId = payeeDfspId; + } + + public String getPayeePartyId() { + return payeePartyId; + } + + public void setPayeePartyId(String payeePartyId) { + this.payeePartyId = payeePartyId; + } + + public String getPayeePartyIdType() { + return payeePartyIdType; + } + + public void setPayeePartyIdType(String payeePartyIdType) { + this.payeePartyIdType = payeePartyIdType; + } + + public Object getPayeeFee() { + return payeeFee; + } + + public void setPayeeFee(Object payeeFee) { + this.payeeFee = payeeFee; + } + + public Object getPayeeQuoteCode() { + return payeeQuoteCode; + } + + public void setPayeeQuoteCode(Object payeeQuoteCode) { + this.payeeQuoteCode = payeeQuoteCode; + } + + public Object getPayerDfspId() { + return payerDfspId; + } + + public void setPayerDfspId(Object payerDfspId) { + this.payerDfspId = payerDfspId; + } + + public String getPayerPartyId() { + return payerPartyId; + } + + public void setPayerPartyId(String payerPartyId) { + this.payerPartyId = payerPartyId; + } + + public String getPayerPartyIdType() { + return payerPartyIdType; + } + + public void setPayerPartyIdType(String payerPartyIdType) { + this.payerPartyIdType = payerPartyIdType; + } + + public Object getPayerFee() { + return payerFee; + } + + public void setPayerFee(Object payerFee) { + this.payerFee = payerFee; + } + + public Object getPayerQuoteCode() { + return payerQuoteCode; + } + + public void setPayerQuoteCode(Object payerQuoteCode) { + this.payerQuoteCode = payerQuoteCode; + } + + public int getAmount() { + return amount; + } + + public void setAmount(int amount) { + this.amount = amount; + } + + public String getCurrency() { + return currency; + } + + public void setCurrency(String currency) { + this.currency = currency; + } + + public String getDirection() { + return direction; + } + + public void setDirection(String direction) { + this.direction = direction; + } + + public Object getAuthType() { + return authType; + } + + public void setAuthType(Object authType) { + this.authType = authType; + } + + public String getInitiatorType() { + return initiatorType; + } + + public void setInitiatorType(String initiatorType) { + this.initiatorType = initiatorType; + } + + public String getScenario() { + return scenario; + } + + public void setScenario(String scenario) { + this.scenario = scenario; + } + + public String getExternalId() { + return externalId; + } + + public void setExternalId(String externalId) { + this.externalId = externalId; + } + + public String getClientCorrelationId() { + return clientCorrelationId; + } + + public void setClientCorrelationId(String clientCorrelationId) { + this.clientCorrelationId = clientCorrelationId; + } +} diff --git a/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/paybill/PayBillRequestDTO.java b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/paybill/PayBillRequestDTO.java new file mode 100644 index 000000000..ab6420940 --- /dev/null +++ b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/paybill/PayBillRequestDTO.java @@ -0,0 +1,50 @@ +package org.mifos.integrationtest.common.dto.paybill; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +//{ +// "TransactionType":"Pay Bill", +// "TransID":"RKTQDM7W6S", +// "TransTime":"20191122063845", +// "TransAmount":"10", +// "BusinessShortCode":"24322607", +// "BillRefNumber":"24322607", +// "InvoiceNumber":"", +// "OrgAccountBalance":"49197.00", +// "ThirdPartyTransID":"", +// "MSISDN":"254797668592", +// "FirstName":"John" +//} +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +public class PayBillRequestDTO { + + @JsonProperty("TransactionType") + public String transactionType; + @JsonProperty("TransID") + public String transID; + @JsonProperty("TransTime") + public String transTime; + @JsonProperty("TransAmount") + public String transAmount; + @JsonProperty("BusinessShortCode") + public String businessShortCode; + @JsonProperty("BillRefNumber") + public String billRefNumber; + @JsonProperty("InvoiceNumber") + public String invoiceNumber; + @JsonProperty("OrgAccountBalance") + public String orgAccountBalance; + @JsonProperty("ThirdPartyTransID") + public String thirdPartyTransID; + @JsonProperty("MSISDN") + public String msisdn; + @JsonProperty("FirstName") + public String firstName; +} diff --git a/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/voucher/FailedCaseDTO.java b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/voucher/FailedCaseDTO.java new file mode 100644 index 000000000..c97c06ee1 --- /dev/null +++ b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/voucher/FailedCaseDTO.java @@ -0,0 +1,16 @@ +package org.mifos.integrationtest.common.dto.voucher; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +public class FailedCaseDTO { + + private String serialNumber; + private String failureReason; +} diff --git a/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/voucher/RedeemVoucherRequestDTO.java b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/voucher/RedeemVoucherRequestDTO.java new file mode 100644 index 000000000..18c8918a9 --- /dev/null +++ b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/voucher/RedeemVoucherRequestDTO.java @@ -0,0 +1,18 @@ +package org.mifos.integrationtest.common.dto.voucher; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +public class RedeemVoucherRequestDTO { + + private String requestId; + private String agentId; + private String voucherSerialNumber; + private String voucherSecretNumber; +} diff --git a/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/voucher/RequestDTO.java b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/voucher/RequestDTO.java new file mode 100644 index 000000000..78e4b65a9 --- /dev/null +++ b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/voucher/RequestDTO.java @@ -0,0 +1,18 @@ +package org.mifos.integrationtest.common.dto.voucher; + +import java.util.ArrayList; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +public class RequestDTO { + + public String requestID; + public String batchID; + public ArrayList voucherInstructions; +} diff --git a/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/voucher/VoucherInstruction.java b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/voucher/VoucherInstruction.java new file mode 100644 index 000000000..66dec7002 --- /dev/null +++ b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/voucher/VoucherInstruction.java @@ -0,0 +1,24 @@ +package org.mifos.integrationtest.common.dto.voucher; + +import java.math.BigDecimal; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +public class VoucherInstruction { + + private String instructionID; + private String groupCode; + private String currency; + private BigDecimal amount; + private String payeeFunctionalID; + private String narration; + private String voucherNumber; + private String serialNumber; + private String status; +} diff --git a/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/voucher/VoucherLifecycleCallbackResponseDTO.java b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/voucher/VoucherLifecycleCallbackResponseDTO.java new file mode 100644 index 000000000..7aa1914a4 --- /dev/null +++ b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/common/dto/voucher/VoucherLifecycleCallbackResponseDTO.java @@ -0,0 +1,19 @@ +package org.mifos.integrationtest.common.dto.voucher; + +import java.util.List; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +public class VoucherLifecycleCallbackResponseDTO { + + private String requestID; + private String registerRequestID; + private Integer numberFailedCases; + private List failedCases; +} diff --git a/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/config/MockServer.java b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/config/MockServer.java new file mode 100644 index 000000000..09baa2d8b --- /dev/null +++ b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/config/MockServer.java @@ -0,0 +1,10 @@ +package org.mifos.integrationtest.config; + +import com.github.tomakehurst.wiremock.WireMockServer; + +public interface MockServer { + + WireMockServer getMockServer(); + + String getBaseUri(); +} diff --git a/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/config/MockServerConfig.java b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/config/MockServerConfig.java new file mode 100644 index 000000000..d8514b9e8 --- /dev/null +++ b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/config/MockServerConfig.java @@ -0,0 +1,33 @@ +package org.mifos.integrationtest.config; + +import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.wireMockConfig; + +import com.github.tomakehurst.wiremock.WireMockServer; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Configuration; + +@Configuration +@Slf4j +public class MockServerConfig implements MockServer { + + private static WireMockServer singleInstance = null; + + @Value("${mock-server.port}") + private int port; + + public WireMockServer getMockServer() { + if (MockServerConfig.singleInstance == null) { + MockServerConfig.singleInstance = new WireMockServer(wireMockConfig().port(this.port)); + log.debug("PORT {}", port); + } + + return MockServerConfig.singleInstance; + } + + @Override + public String getBaseUri() { + return "http://localhost:" + getMockServer().port(); + } + +} diff --git a/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/cucumber/CucumberContext.java b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/cucumber/CucumberContext.java new file mode 100644 index 000000000..dc73f9bd8 --- /dev/null +++ b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/cucumber/CucumberContext.java @@ -0,0 +1,16 @@ +package org.mifos.integrationtest.cucumber; + +import io.cucumber.junit.CucumberOptions; +import io.cucumber.spring.CucumberContextConfiguration; +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +@CucumberContextConfiguration +@CucumberOptions(publish = true) +@SpringBootTest +public class CucumberContext { + + @Test + void contextLoads() {} + +} diff --git a/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/cucumber/stepdef/AuthStepDef.java b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/cucumber/stepdef/AuthStepDef.java new file mode 100644 index 000000000..37b84bd16 --- /dev/null +++ b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/cucumber/stepdef/AuthStepDef.java @@ -0,0 +1,72 @@ +package org.mifos.integrationtest.cucumber.stepdef; + +import static com.google.common.truth.Truth.assertThat; + +import com.google.gson.Gson; +import io.cucumber.java.en.Then; +import io.cucumber.java.en.When; +import io.restassured.RestAssured; +import io.restassured.builder.ResponseSpecBuilder; +import io.restassured.specification.RequestSpecification; +import java.util.HashMap; +import org.mifos.integrationtest.common.Utils; +import org.mifos.integrationtest.config.KeycloakConfig; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; + +public class AuthStepDef extends BaseStepDef { + + @Value("${operations-app.auth.enabled}") + public Boolean authEnabled; + + @Value("${operations-app.auth.header}") + public String authHeader; + + @Autowired + KeycloakConfig keycloakConfig; + + @When("I call the operations-app auth endpoint with username: {string} and password: {string}") + public void authenticateWithUsernameAndPassword(String username, String password) { + if (authEnabled) { + RequestSpecification requestSpec = Utils.getDefaultSpec(scenarioScopeState.tenant); + requestSpec.header("Authorization", authHeader); + requestSpec.queryParam("username", username); + requestSpec.queryParam("password", password); + requestSpec.queryParam("grant_type", "password"); + + scenarioScopeState.response = RestAssured.given(requestSpec).baseUri(operationsAppConfig.operationAppContactPoint).body("{}") + .expect().spec(new ResponseSpecBuilder().expectStatusCode(200).build()).when().post(operationsAppConfig.authEndpoint) + .andReturn().asString(); + } + + } + + @Then("I should get a valid token") + public void checkToken() { + if (authEnabled) { + HashMap authResponse = new Gson().fromJson(scenarioScopeState.response, HashMap.class); + String token; + try { + token = (String) authResponse.get("access_token"); + } catch (Exception e) { + token = null; + } + assertThat(token).isNotEmpty(); + scenarioScopeState.accessToken = token; + logger.info("Access token: " + scenarioScopeState.accessToken); + } + } + + @When("I call the auth endpoint") + public void iCallTheAuthEndpoint() { + RequestSpecification requestSpec = Utils.getDefaultSpec(scenarioScopeState.tenant); + requestSpec.header("Authorization", "Basic Y2xpZW50Og=="); + requestSpec.queryParam("username", operationsAppConfig.username); + requestSpec.queryParam("password", operationsAppConfig.password); + requestSpec.queryParam("grant_type", "password"); + + scenarioScopeState.response = RestAssured.given(requestSpec).baseUri(operationsAppConfig.operationAppContactPoint).body("{}") + .expect().spec(new ResponseSpecBuilder().expectStatusCode(200).build()).when().post(operationsAppConfig.authEndpoint) + .andReturn().asString(); + } +} diff --git a/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/cucumber/stepdef/BaseStepDef.java b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/cucumber/stepdef/BaseStepDef.java new file mode 100644 index 000000000..c00b55eb1 --- /dev/null +++ b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/cucumber/stepdef/BaseStepDef.java @@ -0,0 +1,123 @@ +package org.mifos.integrationtest.cucumber.stepdef; + +import static com.google.common.truth.Truth.assertThat; + +import io.cucumber.core.internal.com.fasterxml.jackson.databind.ObjectMapper; +import java.io.IOException; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.security.cert.X509Certificate; +import java.security.spec.InvalidKeySpecException; +import java.time.ZoneId; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; +import java.util.List; +import javax.crypto.BadPaddingException; +import javax.crypto.IllegalBlockSizeException; +import javax.crypto.NoSuchPaddingException; +import org.mifos.connector.common.util.JsonWebSignature; +import org.mifos.integrationtest.common.Utils; +import org.mifos.integrationtest.common.dto.BatchRequestDTO; +import org.mifos.integrationtest.config.BulkProcessorConfig; +import org.mifos.integrationtest.config.ChannelConnectorConfig; +import org.mifos.integrationtest.config.FspConfig; +import org.mifos.integrationtest.config.IdentityMapperConfig; +import org.mifos.integrationtest.config.MockServer; +import org.mifos.integrationtest.config.OperationsAppConfig; +import org.mifos.integrationtest.config.TenantConfig; +import org.mifos.integrationtest.config.VoucherManagementConfig; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; + +// this class is the base for all the cucumber step definitions +public class BaseStepDef { + + @Autowired + ObjectMapper objectMapper; + + @Autowired + OperationsAppConfig operationsAppConfig; + + @Autowired + BulkProcessorConfig bulkProcessorConfig; + + @Autowired + ChannelConnectorConfig channelConnectorConfig; + + @Autowired + MockServer mockServer; + + @Autowired + IdentityMapperConfig identityMapperConfig; + + @Autowired + VoucherManagementConfig voucherManagementConfig; + + @Autowired + TenantConfig tenantConfig; + + @Autowired + FspConfig payeeFspConfig; + @Value("${totalvouchers}") + public Integer totalVouchers; + + @Value("${operations-app.auth.enabled}") + public Boolean authEnabled; + + @Value("${awaitly.maxWaitTime}") + public Long awaitMost; + + @Value("${awaitly.pollDelaySeconds}") + public Long pollDelay; + + @Value("${awaitly.pollIntervalSeconds}") + public Long pollInterval; + + @Autowired + ScenarioScopeState scenarioScopeState; + + Logger logger = LoggerFactory.getLogger(this.getClass()); + protected static BatchRequestDTO batchRequestDTO; + protected static String batchRawRequest; + protected static String defaultFileName = "ph-ee-bulk-demo-6.csv"; + protected static X509Certificate x509Certificate; + protected static String jwsDataSeparator = ":"; + protected static String dateFormat = "yyyy-MM-dd HH:mm:ss"; + protected static String keycloakCurrentUserPassword = "password"; + + protected static String getCurrentDateInFormat() { + ZoneId zoneId = ZoneId.of("Asia/Kolkata"); + // Get the current time in the specified time zone + ZonedDateTime currentTimeInZone = ZonedDateTime.now(zoneId); + // Define a format for the output + DateTimeFormatter formatter = DateTimeFormatter.ofPattern(dateFormat); + return currentTimeInZone.format(formatter); + } + + protected static String billId; + + // if data passed as a filename/absoluteFilePath then pass isDataAFile as true or else false + protected String generateSignature(String clientCorrelationId, String tenant, String data, boolean isDataAFile) + throws IOException, NoSuchPaddingException, IllegalBlockSizeException, NoSuchAlgorithmException, BadPaddingException, + InvalidKeySpecException, InvalidKeyException { + + JsonWebSignature jsonWebSignature = new JsonWebSignature.JsonWebSignatureBuilder().setClientCorrelationId(clientCorrelationId) + .setTenantId(tenant).setIsDataAsFile(isDataAFile) + .setData(isDataAFile ? Utils.getAbsoluteFilePathToResource(scenarioScopeState.filename) : data).build(); + + return jsonWebSignature.getSignature(scenarioScopeState.privateKeyString); + } + + private void assertNonEmptyArray(List objects) { + assertNotNull(objects); + assertThat(objects).isNotEmpty(); + assertThat(objects.size()).isGreaterThan(0); + } + + protected void assertNotNull(T object) { + assertThat(object).isNotNull(); + } + +} diff --git a/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/cucumber/stepdef/BatchApiStepDef.java b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/cucumber/stepdef/BatchApiStepDef.java new file mode 100644 index 000000000..174697c6a --- /dev/null +++ b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/cucumber/stepdef/BatchApiStepDef.java @@ -0,0 +1,864 @@ +package org.mifos.integrationtest.cucumber.stepdef; + +import static com.github.tomakehurst.wiremock.client.WireMock.getAllServeEvents; +import static com.google.common.truth.Truth.assertThat; +import static java.util.concurrent.TimeUnit.SECONDS; +import static org.awaitility.Awaitility.await; +import static org.mifos.integrationtest.common.Utils.HEADER_FILENAME; +import static org.mifos.integrationtest.common.Utils.HEADER_JWS_SIGNATURE; +import static org.mifos.integrationtest.common.Utils.HEADER_PROGRAM_ID; +import static org.mifos.integrationtest.common.Utils.HEADER_PURPOSE; +import static org.mifos.integrationtest.common.Utils.HEADER_REGISTERING_INSTITUTE_ID; +import static org.mifos.integrationtest.common.Utils.QUERY_PARAM_TYPE; + +import com.github.tomakehurst.wiremock.stubbing.ServeEvent; +import io.cucumber.core.internal.com.fasterxml.jackson.core.JsonProcessingException; +import io.cucumber.core.internal.com.fasterxml.jackson.databind.JsonNode; +import io.cucumber.java.After; +import io.cucumber.java.en.And; +import io.cucumber.java.en.Given; +import io.cucumber.java.en.Then; +import io.cucumber.java.en.When; +import io.restassured.RestAssured; +import io.restassured.builder.ResponseSpecBuilder; +import io.restassured.http.Header; +import io.restassured.http.Headers; +import io.restassured.response.Response; +import io.restassured.specification.RequestSpecification; +import java.io.File; +import java.io.FileReader; +import java.io.IOException; +import java.io.Reader; +import java.math.BigDecimal; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.security.spec.InvalidKeySpecException; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; +import javax.crypto.BadPaddingException; +import javax.crypto.IllegalBlockSizeException; +import javax.crypto.NoSuchPaddingException; +import org.apache.commons.csv.CSVFormat; +import org.apache.commons.csv.CSVParser; +import org.apache.commons.csv.CSVRecord; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.validator.routines.UrlValidator; +import org.json.JSONException; +import org.json.JSONObject; +import org.mifos.connector.common.operations.dto.Transfer; +import org.mifos.connector.common.operations.type.TransferStatus; +import org.mifos.integrationtest.common.Utils; +import org.mifos.integrationtest.common.dto.BatchRequestDTO; +import org.mifos.integrationtest.common.dto.Party; +import org.mifos.integrationtest.common.dto.operationsapp.ActuatorResponse; +import org.mifos.integrationtest.common.dto.operationsapp.BatchAndSubBatchSummaryResponse; +import org.mifos.integrationtest.common.dto.operationsapp.BatchDTO; +import org.mifos.integrationtest.common.dto.operationsapp.BatchDetailResponse; +import org.mifos.integrationtest.common.dto.operationsapp.BatchTransactionResponse; +import org.mifos.integrationtest.common.dto.operationsapp.PaymentBatchDetail; +import org.mifos.integrationtest.common.dto.operationsapp.SubBatchSummary; +import org.mifos.integrationtest.config.BulkProcessorConfig; +import org.mifos.integrationtest.config.ChannelConnectorConfig; +import org.mifos.integrationtest.config.MockPaymentSchemaConfig; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.core.env.Environment; + +public class BatchApiStepDef extends BaseStepDef { + + @Autowired + BulkProcessorConfig bulkProcessorConfig; + + @Value("${callback_url}") + public String callbackURL; + @Autowired + MockPaymentSchemaConfig mockPaymentSchemaConfig; + + @Autowired + ChannelConnectorConfig channelConnectorConfig; + + @Autowired + Environment environment; + + @Given("I have a batch id from previous scenario") + public void setBatchId() { + // todo fix this + if (scenarioScopeState.batchId == null || scenarioScopeState.batchId.isEmpty()) { + scenarioScopeState.batchId = UUID.randomUUID().toString(); + } + assertThat(scenarioScopeState.batchId).isNotNull(); + } + + @Given("I have a batch with id {string}") + public void setBatchId(String batchId) { + scenarioScopeState.batchId = batchId; + assertThat(scenarioScopeState.batchId).isNotEmpty(); + } + + @Given("I have the demo csv file {string}") + public void setFilename(String filename) { + scenarioScopeState.filename = filename; + File f = new File(Utils.getAbsoluteFilePathToResource(scenarioScopeState.filename)); + assertThat(f.exists()).isTrue(); + assertThat(scenarioScopeState.filename).isNotEmpty(); + } + + @And("I make sure there is no file") + public void removeTheFilename() { + clearFilename(); + assertThat(scenarioScopeState.filename).isNull(); + } + + public void clearFilename() { + scenarioScopeState.filename = null; + } + + @And("I have the registeringInstituteId {string}") + public void setRegisteringInstituteId(String registeringInstituteId) { + scenarioScopeState.registeringInstituteId = registeringInstituteId; + assertThat(scenarioScopeState.registeringInstituteId).isNotNull(); + } + + @And("I have the programId {string}") + public void setProgramId(String programId) { + scenarioScopeState.programId = programId; + assertThat(scenarioScopeState.programId).isNotNull(); + } + + @When("I call the batch summary API with expected status of {int} with total {int} txns") + public void callBatchSummaryAPI(int expectedStatus, int totalTxns) { + await().atMost(awaitMost, SECONDS).pollDelay(pollDelay, SECONDS).pollInterval(pollInterval, SECONDS).untilAsserted(() -> { + RequestSpecification requestSpec = Utils.getDefaultSpec(scenarioScopeState.tenant); + if (authEnabled) { + requestSpec.header("Authorization", "Bearer " + scenarioScopeState.accessToken); + } + // requestSpec.queryParam("batchId", scenarioScopeDef.batchId); + logger.info("Calling with batch id: {}", scenarioScopeState.batchId); + + scenarioScopeState.response = RestAssured.given(requestSpec).baseUri(operationsAppConfig.operationAppContactPoint).expect() + .spec(new ResponseSpecBuilder().expectStatusCode(expectedStatus).build()).when() + .get(operationsAppConfig.batchSummaryEndpoint + "/" + scenarioScopeState.batchId).andReturn().asString(); + + logger.info("Batch Summary Response: " + scenarioScopeState.response); + BatchDTO res = objectMapper.readValue(scenarioScopeState.response, BatchDTO.class); + assertThat(res.getTotal()).isEqualTo(totalTxns); + assertThat(res.getStatus()).isEqualTo("COMPLETED"); + }); + } + + @When("I call the batch summary API with expected status of {int} with total successfull {int} txns") + public void callBatchSummaryAPIBulk(int expectedStatus, int totalTxns) { + await().atMost(awaitMost, SECONDS).pollDelay(pollDelay, SECONDS).pollInterval(pollInterval, SECONDS).untilAsserted(() -> { + RequestSpecification requestSpec = Utils.getDefaultSpec(scenarioScopeState.tenant); + if (authEnabled) { + requestSpec.header("Authorization", "Bearer " + scenarioScopeState.accessToken); + } + // requestSpec.queryParam("batchId", scenarioScopeDef.batchId); + logger.info("Calling with batch id: {}", scenarioScopeState.batchId); + + scenarioScopeState.response = RestAssured.given(requestSpec).baseUri(operationsAppConfig.operationAppContactPoint).expect() + .spec(new ResponseSpecBuilder().expectStatusCode(expectedStatus).build()).when() + .get(operationsAppConfig.batchSummaryEndpoint + "/" + scenarioScopeState.batchId).andReturn().asString(); + + logger.info("Batch Summary Response: " + scenarioScopeState.response); + BatchDTO res = objectMapper.readValue(scenarioScopeState.response, BatchDTO.class); + assertThat(res.getTotal()).isEqualTo(totalTxns); + }); + } + + @When("I call the batch summary API for gsma with expected status of {int} with total {int} txns") + public void callBatchSummaryAPIGSMA(int expectedStatus, int totalTxns) { + await().atMost(awaitMost, SECONDS).pollDelay(pollDelay, SECONDS).pollInterval(pollInterval, SECONDS).untilAsserted(() -> { + RequestSpecification requestSpec = Utils.getDefaultSpec(scenarioScopeState.tenant); + if (authEnabled) { + requestSpec.header("Authorization", "Bearer " + scenarioScopeState.accessToken); + } + // requestSpec.queryParam("batchId", scenarioScopeDef.batchId); + logger.info("Calling with batch id: {}", scenarioScopeState.batchId); + + scenarioScopeState.response = RestAssured.given(requestSpec).baseUri(operationsAppConfig.operationAppContactPoint).expect() + .spec(new ResponseSpecBuilder().expectStatusCode(expectedStatus).build()).when() + .get(operationsAppConfig.batchSummaryEndpoint + "/" + scenarioScopeState.batchId).andReturn().asString(); + + logger.info("Batch Summary Response: " + scenarioScopeState.response); + BatchDTO res = objectMapper.readValue(scenarioScopeState.response, BatchDTO.class); + assertThat(res.getTotal()).isEqualTo(totalTxns); + assertThat(res.getTotal()).isEqualTo(res.getSuccessful()); + }); + } + + @Then("I am able to parse batch summary response") + public void parseBatchSummaryResponse() { + await().atMost(awaitMost, SECONDS).pollDelay(pollDelay, SECONDS).pollInterval(pollInterval, SECONDS).untilAsserted(() -> { + BatchDTO batchDTO = null; + assertThat(scenarioScopeState.response).isNotNull(); + assertThat(scenarioScopeState.response).isNotEmpty(); + try { + batchDTO = objectMapper.readValue(scenarioScopeState.response, BatchDTO.class); + scenarioScopeState.batchDTO = batchDTO; + } catch (Exception e) { + logger.error("Error parsing the batch summary response", e); + } + assertThat(scenarioScopeState.batchDTO).isNotNull(); + }); + } + + @And("Status of transaction is {string}") + public void checkIfCreatedAtIsNotNull(String status) { + assertThat(scenarioScopeState.batchDTO).isNotNull(); + assertThat(scenarioScopeState.batchDTO.getStatus()).isEqualTo(status); + } + + @When("I call the batch details API with expected status of {int} with total {int} txns") + public void callBatchDetailsAPI(int expectedStatus, int totalTxns) { + await().atMost(awaitMost, SECONDS).pollDelay(pollDelay, SECONDS).pollInterval(pollInterval, SECONDS).untilAsserted(() -> { + RequestSpecification requestSpec = Utils.getDefaultSpec(scenarioScopeState.tenant); + if (authEnabled) { + requestSpec.header("Authorization", "Bearer " + scenarioScopeState.accessToken); + } + requestSpec.queryParam("batchId", scenarioScopeState.batchId); + logger.info("Calling with batch id : {}", scenarioScopeState.batchId); + + scenarioScopeState.response = RestAssured.given(requestSpec).baseUri(operationsAppConfig.operationAppContactPoint).expect() + .spec(new ResponseSpecBuilder().expectStatusCode(expectedStatus).build()).when() + .get(operationsAppConfig.batchDetailsEndpoint).andReturn().asString(); + + logger.info("Batch Details Response: " + scenarioScopeState.response); + BatchDetailResponse res = parseBatchDetailResponse(scenarioScopeState.response); + assertThat(res.getContent().size()).isEqualTo(totalTxns); + + }); + } + + @When("I call the batch transactions endpoint with expected status of {int} without payload") + public void iCallTheBatchTransactionsEndpointWithExpectedStatusOfWithoutPayload(int expectedStatus) { + RequestSpecification requestSpec = Utils.getDefaultSpec(scenarioScopeState.tenant, scenarioScopeState.clientCorrelationId); + requestSpec.header(HEADER_PURPOSE, "Integration test"); + requestSpec.header(HEADER_FILENAME, ""); + requestSpec.header(QUERY_PARAM_TYPE, "CSV"); + if (StringUtils.isNotBlank(scenarioScopeState.filename)) { + requestSpec.header(HEADER_FILENAME, scenarioScopeState.filename); + } + if (scenarioScopeState.signature != null && !scenarioScopeState.signature.isEmpty()) { + requestSpec.header(HEADER_JWS_SIGNATURE, scenarioScopeState.signature); + } + scenarioScopeState.response = RestAssured.given(requestSpec).baseUri(bulkProcessorConfig.bulkProcessorContactPoint).expect().when() + .post(bulkProcessorConfig.bulkTransactionEndpoint).andReturn().asString(); + + logger.info("Batch Transactions without payload Response: " + scenarioScopeState.response); + } + + @And("I should get batchId in response") + public void iShouldGetBatchIdInResponse() throws JSONException { + JSONObject jsonObject = new JSONObject(scenarioScopeState.response); + String pollingPath = (String) jsonObject.get("PollingPath"); + String[] response = pollingPath.split("/"); + logger.info("Batch Id: {}", response[response.length - 1]); + scenarioScopeState.batchId = response[response.length - 1]; + + } + + @When("I should call callbackUrl api") + public void iShouldCallCallbackUrlApi() throws NoSuchPaddingException, IllegalBlockSizeException, IOException, NoSuchAlgorithmException, + BadPaddingException, InvalidKeySpecException, InvalidKeyException { + RequestSpecification requestSpec = Utils.getDefaultSpec(scenarioScopeState.tenant, scenarioScopeState.clientCorrelationId); + String callbackReq = new String("The Batch Aggregation API was complete"); + logger.info(callbackReq); + String jwsSignature = generateSignature(scenarioScopeState.clientCorrelationId, scenarioScopeState.tenant, callbackReq, false); + + requestSpec.header(HEADER_JWS_SIGNATURE, jwsSignature); + + scenarioScopeState.statusCode = RestAssured.given(requestSpec).body(callbackReq).post(bulkProcessorConfig.getCallbackUrl()) + .andReturn().getStatusCode(); + } + + @And("I have callbackUrl as {string}") + public void iHaveCallbackUrlAs(String callBackUrl) { + assertThat(callBackUrl).isNotEmpty(); + bulkProcessorConfig.setCallbackUrl(callBackUrl); + scenarioScopeState.callbackUrl = callBackUrl; + } + + @Then("I should get expected status of {int}") + public void iShouldGetExpectedStatusOf(int expectedStatus) throws NoSuchPaddingException, IllegalBlockSizeException, IOException, + NoSuchAlgorithmException, BadPaddingException, InvalidKeySpecException, InvalidKeyException { + assertThat(scenarioScopeState.statusCode).isNotNull(); + assertThat(scenarioScopeState.statusCode).isEqualTo(expectedStatus); + if (expectedStatus != 200) { + bulkProcessorConfig.setRetryCount(bulkProcessorConfig.getRetryCount() - 1); + iShouldCallCallbackUrlApi(); + } + + } + + @And("I have retry count as {int}") + public void iHaveRetryCountAs(int retryCount) { + assertThat(retryCount).isNotNull(); + bulkProcessorConfig.setRetryCount(retryCount); + } + + @Then("I should get non empty response with failure and success percentage") + public void iShouldGetNonEmptyResponseWithFailureAndSuccessPercentage() { + assertThat(scenarioScopeState.response).isNotNull(); + assertThat(scenarioScopeState.response.contains("failPercentage")); + assertThat(scenarioScopeState.response.contains("successPercentage")); + } + + @When("I call the batch transactions endpoint with expected status of {int}") + public void callBatchTransactionsEndpoint(int expectedStatus) { + await().atMost(awaitMost, SECONDS).pollDelay(pollDelay, SECONDS).pollInterval(pollInterval, SECONDS).untilAsserted(() -> { + RequestSpecification requestSpec = Utils.getDefaultSpec(scenarioScopeState.tenant, scenarioScopeState.clientCorrelationId); + requestSpec.header(HEADER_PURPOSE, "Integartion test"); + requestSpec.header(HEADER_FILENAME, scenarioScopeState.filename); + requestSpec.queryParam(QUERY_PARAM_TYPE, "CSV"); + requestSpec.header(QUERY_PARAM_TYPE, "CSV"); + if (scenarioScopeState.signature != null && !scenarioScopeState.signature.isEmpty()) { + requestSpec.header(HEADER_JWS_SIGNATURE, scenarioScopeState.signature); + } + if (StringUtils.isNotBlank(scenarioScopeState.registeringInstituteId) && StringUtils.isNotBlank(scenarioScopeState.programId)) { + requestSpec.header(HEADER_REGISTERING_INSTITUTE_ID, scenarioScopeState.registeringInstituteId); + requestSpec.header(HEADER_PROGRAM_ID, scenarioScopeState.programId); + } + + File f = new File(Utils.getAbsoluteFilePathToResource(scenarioScopeState.filename)); + Response resp = RestAssured.given(requestSpec).baseUri(bulkProcessorConfig.bulkProcessorContactPoint) + .contentType("multipart/form-data").multiPart("data", f).expect() + .spec(new ResponseSpecBuilder().expectStatusCode(expectedStatus).build()).when() + .post(bulkProcessorConfig.bulkTransactionEndpoint).then().extract().response(); + + scenarioScopeState.response = resp.andReturn().asString(); + scenarioScopeState.restResponseObject = resp; + + Headers allHeaders = resp.getHeaders(); + for (Header header : allHeaders) { + logger.debug("{}", header.getName()); + logger.debug("{}", header.getValue()); + } + logger.info("Batch Transactions Response: {}", scenarioScopeState.response); + }); + } + + @And("I should have {string} and {string} in response") + public void iShouldHaveAndInResponse(String pollingpath, String suggestedcallback) { + assertThat(scenarioScopeState.response).contains(pollingpath); + assertThat(scenarioScopeState.response).contains(suggestedcallback); + + } + + @And("I have callbackUrl as simulated url") + public void iHaveCallbackUrlAsSimulatedUrl() { + bulkProcessorConfig.setCallbackUrl(bulkProcessorConfig.simulateEndpoint); + scenarioScopeState.callbackUrl = bulkProcessorConfig.getCallbackUrl(); + } + + @And("I fetch batch ID from batch transaction API's response") + public void iFetchBatchIDFromBatchTransactionAPISResponse() { + + assertThat(scenarioScopeState.batchTransactionResponse).isNotNull(); + scenarioScopeState.batchId = fetchBatchId(scenarioScopeState.batchTransactionResponse); + logger.info("batchId: {}", scenarioScopeState.batchId); + assertThat(scenarioScopeState.batchId).isNotEmpty(); + } + + @Then("I check for result file URL validity") + public void iCheckForResultFileURLValidity() { + assertThat(isValidURL(scenarioScopeState.batchAndSubBatchSummaryResponse.getFile())).isTrue(); + } + + boolean isValidURL(String url) { + UrlValidator validator = new UrlValidator(UrlValidator.ALLOW_LOCAL_URLS); + return validator.isValid(url); + } + + @And("I am able to parse batch transactions response") + public void parseBatchTransactionsResponseStep() { + parseBatchTransactionsResponse(); + } + + private String fetchBatchId(BatchTransactionResponse batchTransactionResponse) { + String pollingPath = batchTransactionResponse.getPollingPath().replace("\"", ""); + String[] pollingPathSplitResult = pollingPath.split("/"); + return pollingPathSplitResult[pollingPathSplitResult.length - 1]; + } + + private void parseBatchTransactionsResponse() { + assertThat(scenarioScopeState.response).isNotEmpty(); + BatchTransactionResponse response = null; + try { + response = objectMapper.readValue(scenarioScopeState.response, BatchTransactionResponse.class); + scenarioScopeState.batchTransactionResponse = response; + } catch (Exception e) { + logger.error("Error parsing the batch transaction response", e); + } + assertThat(scenarioScopeState.batchTransactionResponse).isNotNull(); + } + + @And("I should have matching total txn count and successful txn count in response") + public void iShouldHaveMatchingTotalTxnCountAndSuccessfulTxnCountInResponse() { + await().atMost(awaitMost, SECONDS).untilAsserted(() -> { + assertThat(scenarioScopeState.batchDTO).isNotNull(); + assertThat(scenarioScopeState.batchDTO.getTotal()).isNotNull(); + assertThat(scenarioScopeState.batchDTO.getSuccessful()).isNotNull(); + assertThat(scenarioScopeState.batchDTO.getTotal()).isGreaterThan(0); + assertThat(scenarioScopeState.batchDTO.getSuccessful()).isGreaterThan(0); + assertThat(scenarioScopeState.batchDTO.getTotal()).isEqualTo(scenarioScopeState.batchDTO.getSuccessful()); + + }); + } + + @And("My total txns {} and successful txn count in response should Match") + public void iShouldHaveMatchingTotalTxnCountAndSuccessfulTxnCount(int totalTxnsCount) { + await().atMost(awaitMost, SECONDS).untilAsserted(() -> { + assertThat(scenarioScopeState.batchDTO).isNotNull(); + assertThat(scenarioScopeState.batchDTO.getTotal()).isNotNull(); + assertThat(scenarioScopeState.batchDTO.getSuccessful()).isNotNull(); + assertThat(scenarioScopeState.batchDTO.getTotal()).isGreaterThan(0); + assertThat(scenarioScopeState.batchDTO.getSuccessful()).isGreaterThan(0); + assertThat(totalTxnsCount).isEqualTo(scenarioScopeState.batchDTO.getSuccessful()); + + }); + } + + @When("I can assert the approved count as {int} and approved amount as {int}") + public void iCanAssertTheApprovedCountAsAndApprovedAmountAs(int count, int amount) { + BigDecimal approvedCount = scenarioScopeState.batchDTO.getApprovedCount(); + BigDecimal approvedAmount = scenarioScopeState.batchDTO.getApprovedAmount(); + assertThat(approvedCount).isEqualTo(new BigDecimal(count)); + assertThat(approvedAmount).isEqualTo(new BigDecimal(amount)); + } + + @When("I call the batch transactions raw endpoint with expected status of {int}") + public void callBatchTransactionsRawEndpoint(int expectedStatus) { + RequestSpecification requestSpec = Utils.getDefaultSpec(scenarioScopeState.tenant, scenarioScopeState.clientCorrelationId); + requestSpec.header(HEADER_PURPOSE, "Integartion test"); + requestSpec.header(HEADER_FILENAME, ""); + requestSpec.header(QUERY_PARAM_TYPE, "RAW"); + if (scenarioScopeState.signature != null && !scenarioScopeState.signature.isEmpty()) { + requestSpec.header(HEADER_JWS_SIGNATURE, scenarioScopeState.signature); + } + if (StringUtils.isNotBlank(scenarioScopeState.registeringInstituteId) && StringUtils.isNotBlank(scenarioScopeState.programId)) { + requestSpec.header(HEADER_REGISTERING_INSTITUTE_ID, scenarioScopeState.registeringInstituteId); + requestSpec.header(HEADER_PROGRAM_ID, scenarioScopeState.programId); + } + + File f = new File(Utils.getAbsoluteFilePathToResource(scenarioScopeState.filename)); + Response resp = RestAssured.given(requestSpec).baseUri(bulkProcessorConfig.bulkProcessorContactPoint) + .contentType("application/json").body(scenarioScopeState.batchRawRequest).expect() + // .spec(new ResponseSpecBuilder().expectStatusCode(expectedStatus).build()) + .when().post(bulkProcessorConfig.bulkTransactionEndpoint).then().extract().response(); + + scenarioScopeState.response = resp.andReturn().asString(); + scenarioScopeState.restResponseObject = resp; + + Headers allHeaders = resp.getHeaders(); + for (Header header : allHeaders) { + logger.info(" : {}", header.getName()); + logger.info("{}", header.getValue()); + } + logger.info("Batch Transactions Response: " + scenarioScopeState.response); + } + + @And("I can mock the Batch Transaction Request DTO without payer info") + public void mockBatchTransactionRequestDTOWithoutPayer() throws JsonProcessingException { + BatchRequestDTO batchRequestDTO = mockBatchTransactionRequestDTO("mojaloop"); + batchRequestDTO = setCreditPartyInMockBatchTransactionRequestDTO(batchRequestDTO); + batchRequestDTO = setDebitPartyInMockBatchTransactionRequestDTO(batchRequestDTO); + assertThat(batchRequestDTO).isNotNull(); + assertThat(batchRequestDTO.getCurrency()).isNotEmpty(); + assertThat(batchRequestDTO.getAmount()).isNotEmpty(); + assertThat(batchRequestDTO.getPaymentMode()).isNotEmpty(); + assertThat(batchRequestDTO.getCreditParty()).isNotEmpty(); + scenarioScopeState.batchRequestDTO = batchRequestDTO; + + List batchRequestDTOS = new ArrayList<>(); + batchRequestDTOS.add(batchRequestDTO); + scenarioScopeState.batchRawRequest = objectMapper.writeValueAsString(batchRequestDTOS); + assertThat(scenarioScopeState.batchRawRequest).isNotEmpty(); + } + + public BatchDetailResponse parseBatchDetailResponse(String jsonString) { + BatchDetailResponse batchDetailResponse = null; + try { + batchDetailResponse = objectMapper.readValue(jsonString, BatchDetailResponse.class); + } catch (Exception e) { + logger.error("Error parsing the batch detail response", e); + } + return batchDetailResponse; + } + + @Then("I should get transactions with note set as {string}") + public void iShouldGetTransactionsWithNoteSetAs(String duplicateTransactionNote) { + logger.info(scenarioScopeState.response); + BatchDetailResponse batchDetailResponse = parseBatchDetailResponse(scenarioScopeState.response); + int duplicateRecordCount = 0; + assertThat(batchDetailResponse).isNotNull(); + List transfers = batchDetailResponse.getContent(); + + for (Transfer transfer : transfers) { + if (transfer.getErrorInformation() == null) { + continue; + } + if (transfer.getErrorInformation().toLowerCase().contains(duplicateTransactionNote.toLowerCase())) { + duplicateRecordCount++; + } + } + assertThat(duplicateRecordCount).isGreaterThan(0); + } + + @And("All the duplicate transaction should have status as Failed") + public void duplicateTransactionStatusShouldBeFailed() { + BatchDetailResponse batchDetailResponse = parseBatchDetailResponse(scenarioScopeState.response); + assertThat(batchDetailResponse).isNotNull(); + List transfers = batchDetailResponse.getContent(); + + for (Transfer transfer : transfers) { + if (transfer.getErrorInformation() == null) { + continue; + } + if (transfer.getErrorInformation().toLowerCase().contains("duplicate")) { + assertThat(transfer.getStatus().equals(TransferStatus.FAILED)); + } + } + } + + @After("@batch-teardown") + public void operationsBatchTestTearDown() { + logger.info("Running @ops-batch-teardown"); + batchTearDown(); + } + + @When("I call the batch aggregate API with expected status of {int} with total {int} txns") + public void iCallTheBatchAggregateAPIWithExpectedStatusOf(int expectedStatus, int totalTxns) { + await().atMost(awaitMost, SECONDS).pollDelay(5, SECONDS).pollInterval(pollInterval, SECONDS).untilAsserted(() -> { + + RequestSpecification requestSpec = Utils.getDefaultSpec(scenarioScopeState.tenant); + logger.info("Calling with batch id: {}", scenarioScopeState.batchId); + + scenarioScopeState.response = RestAssured.given(requestSpec).baseUri(operationsAppConfig.operationAppContactPoint).expect() + .spec(new ResponseSpecBuilder().expectStatusCode(expectedStatus).build()).when() + .get(operationsAppConfig.batchAggregateEndpoint + scenarioScopeState.batchId).andReturn().asString(); + logger.info("Batch Aggregate Response: " + scenarioScopeState.response); + BatchDTO res = objectMapper.readValue(scenarioScopeState.response, BatchDTO.class); + assertThat(res.getTotal()).isEqualTo(totalTxns); + }); + } + + public void batchTearDown() { + scenarioScopeState.filename = null; + scenarioScopeState.batchId = null; + scenarioScopeState.response = null; + } + + public BatchRequestDTO mockBatchTransactionRequestDTO(String paymentMode) { + BatchRequestDTO batchRequestDTO = new BatchRequestDTO(); + batchRequestDTO.setAmount("100"); + batchRequestDTO.setCurrency("USD"); + batchRequestDTO.setPaymentMode(paymentMode); + batchRequestDTO.setDescriptionText("Integration test"); + batchRequestDTO.setRequestId(UUID.randomUUID().toString()); + return batchRequestDTO; + } + + public BatchRequestDTO setCreditPartyInMockBatchTransactionRequestDTO(BatchRequestDTO batchRequestDTO) { + List creditParties = new ArrayList<>(); + creditParties.add(new Party("accountNumber", "003001003873110196")); + batchRequestDTO.setCreditParty(creditParties); + return batchRequestDTO; + } + + public BatchRequestDTO setDebitPartyInMockBatchTransactionRequestDTO(BatchRequestDTO batchRequestDTO) { + List debitParties = new ArrayList<>(); + debitParties.add(new Party("accountNumber", "003001003879112168")); + batchRequestDTO.setDebitParty(debitParties); + return batchRequestDTO; + } + + private String fetchBatchId(String response) { + String[] split = response.split(","); + return split[0].substring(31); + } + + @Given("I have a batch id {string}") + public void iHaveABatchId(String batchID) { + scenarioScopeState.batchId = batchID; + } + + @And("I call the batch summary API for sub batch summary with expected status of {int}") + public void iCallTheBatchSummaryAPIForSubBatchSummaryWithExpectedStatusOf(int expectedStatus) { + RequestSpecification requestSpec = Utils.getDefaultSpec(scenarioScopeState.tenant); + if (authEnabled) { + requestSpec.header("Authorization", "Bearer " + scenarioScopeState.accessToken); + } + // requestSpec.queryParam("batchId", scenarioScopeDef.batchId); + logger.info("Calling with batch id: {}", scenarioScopeState.batchId); + + scenarioScopeState.response = RestAssured.given(requestSpec).baseUri(operationsAppConfig.operationAppContactPoint).expect() + .spec(new ResponseSpecBuilder().expectStatusCode(expectedStatus).build()).when() + .get(operationsAppConfig.batchSummaryEndpoint + scenarioScopeState.batchId).andReturn().asString(); + + logger.info("Batch Summary Response: " + scenarioScopeState.response); + } + + @Then("I am able to parse sub batch summary response") + public void iAmAbleToParseSubBatchSummaryResponse() { + scenarioScopeState.batchAndSubBatchSummaryResponse = null; + assertThat(scenarioScopeState.response).isNotNull(); + assertThat(scenarioScopeState.response).isNotEmpty(); + try { + scenarioScopeState.batchAndSubBatchSummaryResponse = objectMapper.readValue(scenarioScopeState.response, + BatchAndSubBatchSummaryResponse.class); + } catch (Exception e) { + logger.error("Error parsing the batch summary response", e); + } + assertThat(scenarioScopeState.batchAndSubBatchSummaryResponse).isNotNull(); + } + + @And("I call the sub batch summary API for sub batch summary with expected status of {int} and total count {int}") + public void iCallTheSubBatchSummaryAPIForSubBatchSummaryWithExpectedStatusOf(int expectedStatus, int totalCount) { + await().atMost(awaitMost + 15, SECONDS).pollDelay(pollDelay, SECONDS).pollInterval(pollInterval, SECONDS).untilAsserted(() -> { + RequestSpecification requestSpec = Utils.getDefaultSpec(scenarioScopeState.tenant); + requestSpec.header("X-Correlation-ID", scenarioScopeState.clientCorrelationId); + if (authEnabled) { + requestSpec.header("Authorization", "Bearer " + scenarioScopeState.accessToken); + } + // requestSpec.queryParam("batchId", scenarioScopeDef.batchId); + logger.info("Calling with batch id: {}", scenarioScopeState.clientCorrelationId); + logger.info("Calling with batch id: {}", + operationsAppConfig.operationAppContactPoint + operationsAppConfig.batchesEndpoint + "/" + scenarioScopeState.batchId); + + scenarioScopeState.response = RestAssured.given(requestSpec).baseUri(operationsAppConfig.operationAppContactPoint).expect() + .spec(new ResponseSpecBuilder().expectStatusCode(expectedStatus).build()).when() + .get(operationsAppConfig.batchesEndpoint + "/" + scenarioScopeState.batchId).andReturn().asString(); + + logger.info("Sub batch Summary Response: " + scenarioScopeState.response); + + BatchAndSubBatchSummaryResponse res = objectMapper.readValue(scenarioScopeState.response, + BatchAndSubBatchSummaryResponse.class); + assertThat(totalCount).isEqualTo(res.getSuccessful()); + }); + } + + @And("I call the sub batch summary API for result file url with expected status of {int}") + public void iCallTheSubBatchSummaryAPIForResutlFileURLWithExpectedStatusOf(int expectedStatus) { + await().atMost(awaitMost, SECONDS).pollDelay(pollDelay, SECONDS).pollInterval(pollInterval, SECONDS).untilAsserted(() -> { + RequestSpecification requestSpec = Utils.getDefaultSpec(scenarioScopeState.tenant); + requestSpec.header("X-Correlation-ID", scenarioScopeState.clientCorrelationId); + if (authEnabled) { + requestSpec.header("Authorization", "Bearer " + scenarioScopeState.accessToken); + } + // requestSpec.queryParam("batchId", scenarioScopeDef.batchId); + logger.info("Calling with batch id: {}", scenarioScopeState.clientCorrelationId); + logger.info("Calling with batch id: {}", + operationsAppConfig.operationAppContactPoint + operationsAppConfig.batchesEndpoint + "/" + scenarioScopeState.batchId); + + scenarioScopeState.response = RestAssured.given(requestSpec).baseUri(operationsAppConfig.operationAppContactPoint).expect() + .spec(new ResponseSpecBuilder().expectStatusCode(expectedStatus).build()).when() + .get(operationsAppConfig.batchesEndpoint + "/" + scenarioScopeState.batchId).andReturn().asString(); + + logger.info("Sub batch Summary Response: " + scenarioScopeState.response); + + BatchAndSubBatchSummaryResponse res = objectMapper.readValue(scenarioScopeState.response, + BatchAndSubBatchSummaryResponse.class); + assertThat(res.getFile()).isNotNull(); + }); + } + + @And("I should assert total txn count and successful txn count in response") + public void iShouldAssertTotalTxnCountAndSuccessfulTxnCountInResponse() { + await().atMost(awaitMost, SECONDS).untilAsserted(() -> { + assertThat(scenarioScopeState.batchAndSubBatchSummaryResponse.getTotal()).isGreaterThan(0); + assertThat(scenarioScopeState.batchAndSubBatchSummaryResponse.getSuccessful()).isGreaterThan(0); + assertThat(scenarioScopeState.batchAndSubBatchSummaryResponse.getTotal()) + .isEqualTo(scenarioScopeState.batchAndSubBatchSummaryResponse.getSuccessful()); + }); + } + + @And("Total transaction in batch should add up to total transaction in each sub batch") + public void matchTotalSubBatchTxnAndBatchTxnCount() { + assertThat(scenarioScopeState.batchAndSubBatchSummaryResponse).isNotNull(); + assertThat(Integer.parseInt(String.valueOf(scenarioScopeState.batchAndSubBatchSummaryResponse.getTotalSubBatches()))) + .isGreaterThan(1); + long batchTotal = scenarioScopeState.batchAndSubBatchSummaryResponse.getTotal(); + long subBatchTotal = 0L; + for (SubBatchSummary subBatchSummary : scenarioScopeState.batchAndSubBatchSummaryResponse.getSubBatchSummaryList()) { + subBatchTotal += subBatchSummary.getTotal(); + } + assertThat(batchTotal).isEqualTo(subBatchTotal); + } + + @And("I call the payment batch detail API with expected status of {int} with total {int} txns") + public void iCallThePaymentBatchDetailAPIWithExpectedStatusOf(int expectedStatus, int totaltxns) { + await().atMost(awaitMost, SECONDS).pollDelay(pollDelay, SECONDS).pollInterval(pollInterval, SECONDS).untilAsserted(() -> { + RequestSpecification requestSpec = Utils.getDefaultSpec(scenarioScopeState.tenant); + requestSpec.header("X-Correlation-ID", scenarioScopeState.clientCorrelationId); + requestSpec.queryParam("associations", "all"); + if (authEnabled) { + requestSpec.header("Authorization", "Bearer " + scenarioScopeState.accessToken); + } + // requestSpec.queryParam("batchId", scenarioScopeDef.batchId); + logger.info("Calling with batch id: {}", scenarioScopeState.batchId); + logger.info("Calling with URL: {}", + operationsAppConfig.operationAppContactPoint + operationsAppConfig.batchesEndpoint + "/" + scenarioScopeState.batchId); + + scenarioScopeState.response = RestAssured.given(requestSpec).baseUri(operationsAppConfig.operationAppContactPoint).expect() + .spec(new ResponseSpecBuilder().expectStatusCode(expectedStatus).build()).when() + .get(operationsAppConfig.batchesEndpoint + "/" + scenarioScopeState.batchId).andReturn().asString(); + + logger.info("Batch Payment Detail Response: " + scenarioScopeState.response); + PaymentBatchDetail res = objectMapper.readValue(scenarioScopeState.response, PaymentBatchDetail.class); + assertThat(res.getInstructionList().size()).isEqualTo(totaltxns); + assertThat(res.getSuccessful()).isEqualTo(totaltxns); + }); + } + + @Then("I am able to parse payment batch detail response") + public void iAmAbleToParsePaymentBatchDetailResponse() { + scenarioScopeState.paymentBatchDetail = null; + assertThat(scenarioScopeState.response).isNotNull(); + assertThat(scenarioScopeState.response).isNotEmpty(); + try { + scenarioScopeState.paymentBatchDetail = objectMapper.readValue(scenarioScopeState.response, PaymentBatchDetail.class); + } catch (Exception e) { + logger.error("Error parsing the payment batch detail response", e); + } + assertThat(scenarioScopeState.paymentBatchDetail).isNotNull(); + } + + @And("I should assert total txn count and successful txn count in payment batch detail response") + public void iShouldAssertTotalTxnCountAndSuccessfulTxnCountInPaymentBatchDetailResponse() { + assertThat(scenarioScopeState.paymentBatchDetail).isNotNull(); + assertThat(scenarioScopeState.paymentBatchDetail.getSubBatchList().size()).isEqualTo(3); + assertThat(scenarioScopeState.paymentBatchDetail.getInstructionList().size()).isEqualTo(12); + assertThat(scenarioScopeState.paymentBatchDetail.getTotal()).isEqualTo(scenarioScopeState.paymentBatchDetail.getSuccessful()); + assertThat(scenarioScopeState.paymentBatchDetail.getStatus().equals("COMPLETED")); + assertThat(scenarioScopeState.paymentBatchDetail.getCompletedAt()).isNotNull(); + } + + @Then("I should be able to extract response body from callback for batch") + public void iShouldBeAbleToExtractResponseBodyFromCallbackForBatch() { + boolean flag = false; + List allServeEvents = getAllServeEvents(); + for (int i = allServeEvents.size() - 1; i >= 0; i--) { + ServeEvent request = allServeEvents.get(i); + if (!(request.getRequest().getBodyAsString()).isEmpty()) { + JsonNode rootNode = null; + flag = true; + try { + rootNode = objectMapper.readTree(request.getRequest().getBody()); + logger.info("Rootnode value:" + rootNode); + assertThat(rootNode).isNotNull(); + } catch (IOException e) { + throw new RuntimeException(e); + } + + } + assertThat(flag).isTrue(); + } + } + + @When("I call the batch transactions endpoint with expected status of {int} and callbackurl as {string}") + public void iCallTheBatchTransactionsEndpointWithExpectedStatusOfAndCallbackurlAs(int expectedStatus, String callback) { + RequestSpecification requestSpec = Utils.getDefaultSpec(scenarioScopeState.tenant, scenarioScopeState.clientCorrelationId); + requestSpec.header(HEADER_PURPOSE, "Integration test"); + requestSpec.header(HEADER_FILENAME, scenarioScopeState.filename); + requestSpec.queryParam(QUERY_PARAM_TYPE, "CSV"); + requestSpec.header(QUERY_PARAM_TYPE, "CSV"); + requestSpec.header("X-CallbackURL", callbackURL + callback); + if (scenarioScopeState.signature != null && !scenarioScopeState.signature.isEmpty()) { + requestSpec.header(HEADER_JWS_SIGNATURE, scenarioScopeState.signature); + } + if (StringUtils.isNotBlank(scenarioScopeState.registeringInstituteId) && StringUtils.isNotBlank(scenarioScopeState.programId)) { + requestSpec.header(HEADER_REGISTERING_INSTITUTE_ID, scenarioScopeState.registeringInstituteId); + requestSpec.header(HEADER_PROGRAM_ID, scenarioScopeState.programId); + } + + File f = new File(Utils.getAbsoluteFilePathToResource(scenarioScopeState.filename)); + Response resp = RestAssured.given(requestSpec).baseUri(bulkProcessorConfig.bulkProcessorContactPoint) + .contentType("multipart/form-data").multiPart("data", f).expect() + .spec(new ResponseSpecBuilder().expectStatusCode(expectedStatus).build()).when() + .post(bulkProcessorConfig.bulkTransactionEndpoint).then().extract().response(); + + scenarioScopeState.response = resp.andReturn().asString(); + scenarioScopeState.restResponseObject = resp; + + Headers allHeaders = resp.getHeaders(); + for (Header header : allHeaders) { + logger.info("{}", header.getName()); + logger.info(header.getValue()); + } + logger.info("Batch Transactions Response: " + scenarioScopeState.response); + } + + @And("I should assert total txn count and successful txn count in payment batch detail response for batch account lookup") + public void iShouldAssertTotalTxnCountAndSuccessfulTxnCountInPaymentBatchDetailResponseForBatchAccountLookup() { + assertThat(scenarioScopeState.paymentBatchDetail).isNotNull(); + assertThat(scenarioScopeState.paymentBatchDetail.getInstructionList().size()).isEqualTo(3); + } + + @And("I am able to parse actuator response") + public void iAmAbleToParseActuatorResponse() { + ActuatorResponse actuatorResponse = null; + assertThat(scenarioScopeState.response).isNotNull(); + assertThat(scenarioScopeState.response).isNotEmpty(); + try { + actuatorResponse = objectMapper.readValue(scenarioScopeState.response, ActuatorResponse.class); + scenarioScopeState.actuatorResponse = actuatorResponse; + } catch (Exception e) { + logger.error("Error parsing the actuator response", e); + } + assertThat(scenarioScopeState.actuatorResponse).isNotNull(); + } + + @And("Status of service is {string}") + public void statusOfServiceIs(String status) { + assertThat(scenarioScopeState.actuatorResponse).isNotNull(); + assertThat(scenarioScopeState.actuatorResponse.getStatus()).isEqualTo(status); + } + + @When("I call the actuator API with Contactpoint {string} and endpoint {string}") + public void iCallTheActuatorAPIWithContactpointAndEndpoint(String config, String endpoint) { + RequestSpecification requestSpec = Utils.getDefaultSpec(); + + Response resp = RestAssured.given(requestSpec).baseUri(environment.getProperty(config)).expect() + .spec(new ResponseSpecBuilder().build()).when().get(endpoint).then().extract().response(); + + scenarioScopeState.response = resp.andReturn().asString(); + scenarioScopeState.restResponseObject = resp; + + logger.info("Actuator Response: " + scenarioScopeState.response); + } + + @And("I can mock the Batch Transaction Request DTO without closed loop") + public void iCanMockTheBatchTransactionRequestDTOWithoutClosedLoop() throws JsonProcessingException { + BatchRequestDTO batchRequestDTO = mockBatchTransactionRequestDTO("closedloop"); + batchRequestDTO = setCreditPartyInMockBatchTransactionRequestDTO(batchRequestDTO); + batchRequestDTO = setDebitPartyInMockBatchTransactionRequestDTO(batchRequestDTO); + assertThat(batchRequestDTO).isNotNull(); + assertThat(batchRequestDTO.getCurrency()).isNotEmpty(); + assertThat(batchRequestDTO.getAmount()).isNotEmpty(); + assertThat(batchRequestDTO.getPaymentMode()).isNotEmpty(); + assertThat(batchRequestDTO.getCreditParty()).isNotEmpty(); + BaseStepDef.batchRequestDTO = batchRequestDTO; + + List batchRequestDTOS = new ArrayList<>(); + batchRequestDTOS.add(batchRequestDTO); + BaseStepDef.batchRawRequest = objectMapper.writeValueAsString(batchRequestDTOS); + assertThat(BaseStepDef.batchRawRequest).isNotEmpty(); + } + + @And("I create a list of payee identifiers from csv file") + public void iCreateAListOfPayeeIdentifiersFromCsvFile() { + String csvFile = Utils.getAbsoluteFilePathToResource(scenarioScopeState.filename); + scenarioScopeState.payeeIdentifiers = new ArrayList<>(); + try (Reader reader = new FileReader(csvFile); + CSVParser csvParser = new CSVParser(reader, CSVFormat.DEFAULT.withFirstRecordAsHeader())) { + for (CSVRecord csvRecord : csvParser) { + String payeeIdentifier = csvRecord.get("payee_identifier"); + scenarioScopeState.payeeIdentifiers.add(payeeIdentifier); + } + } catch (Exception e) { + logger.error(e.getMessage()); + } + } +} diff --git a/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/cucumber/stepdef/BatchAuthorizationStepDef.java b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/cucumber/stepdef/BatchAuthorizationStepDef.java new file mode 100644 index 000000000..d23a887b7 --- /dev/null +++ b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/cucumber/stepdef/BatchAuthorizationStepDef.java @@ -0,0 +1,76 @@ +package org.mifos.integrationtest.cucumber.stepdef; + +import static com.github.tomakehurst.wiremock.client.WireMock.equalTo; +import static com.github.tomakehurst.wiremock.client.WireMock.matchingJsonPath; +import static com.github.tomakehurst.wiremock.client.WireMock.postRequestedFor; +import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo; +import static com.github.tomakehurst.wiremock.client.WireMock.verify; +import static com.google.common.truth.Truth.assertThat; +import static java.util.concurrent.TimeUnit.SECONDS; +import static org.awaitility.Awaitility.await; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import io.cucumber.java.en.Then; +import io.cucumber.java.en.When; +import io.restassured.RestAssured; +import io.restassured.builder.ResponseSpecBuilder; +import io.restassured.specification.RequestSpecification; +import org.mifos.integrationtest.common.AuthorizationRequest; +import org.mifos.integrationtest.common.BatchSummaryResponse; +import org.mifos.integrationtest.common.Utils; +import org.mifos.integrationtest.config.IdentityMapperConfig; +import org.mifos.integrationtest.config.MockPaymentSchemaConfig; +import org.springframework.beans.factory.annotation.Autowired; + +public class BatchAuthorizationStepDef extends BaseStepDef { + + @Autowired + MockPaymentSchemaConfig mockPaymentSchemaConfig; + + @Autowired + IdentityMapperConfig identityMapperConfig; + + @Autowired + ScenarioScopeState scenarioScopeState; + + private static AuthorizationRequest authorizationRequest; + + @Then("I should get batch status as {string}") + public void iShouldGetBatchStatusAs(String status) { + String response = scenarioScopeState.response; + BatchSummaryResponse batchSummaryResponse; + ObjectMapper objectMapper = new ObjectMapper(); + try { + batchSummaryResponse = objectMapper.readValue(response, BatchSummaryResponse.class); + } catch (JsonProcessingException e) { + throw new RuntimeException(e); + } + assertThat(batchSummaryResponse.getStatus()).isEqualTo(status); + } + + @Then("I should be able to verify that the {string} method to {string} endpoint received a request with authorization status") + public void iShouldBeAbleToVerifyThatTheMethodToEndpointReceivedARequestWithAuthorizationStatus(String httpMethod, String endpoint) { + await().atMost(awaitMost, SECONDS).pollInterval(pollInterval, SECONDS).untilAsserted(() -> { + verify(postRequestedFor(urlEqualTo(endpoint)).withRequestBody(matchingJsonPath("$.status", equalTo("Y")))); + }); + } + + @When("I call the Authorization API with batchId as {string} and expected status of {int} and stub {string}") + public void iCallTheAuthorizationAPIWithBatchIdAsAndExpectedStatusOfAndStub(String batchId, int expectedStatus, String stub) { + RequestSpecification requestSpec = Utils.getDefaultSpec(); + scenarioScopeState.response = RestAssured.given(requestSpec).header("Content-Type", "application/json") + .header("X-CallbackURL", identityMapperConfig.callbackURL + stub).header("X-Client-Correlation-ID", "998877") + .queryParam("command", "authorize").baseUri(mockPaymentSchemaConfig.mockPaymentSchemaContactPoint) + .body(authorizationRequest).expect().spec(new ResponseSpecBuilder().expectStatusCode(expectedStatus).build()).when() + .post(mockPaymentSchemaConfig.mockBatchAuthorizationEndpoint + batchId).andReturn().asString(); + + logger.info("Authorization Response: {}", scenarioScopeState.response); + } + + @When("I create an AuthorizationRequest for Batch Authorization with batch ID as {string}, payerIdentifier as {string}, currency as {string} and amount as {string}") + public void iCreateAnAuthorizationRequestForBatchAuthorizationWithBatchIDAsPayerIdentifierAsCurrencyAsAndAmountAs(String batchId, + String payerIdentifier, String currency, String amount) { + authorizationRequest = new AuthorizationRequest(batchId, payerIdentifier, currency, amount); + } +} diff --git a/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/cucumber/stepdef/BillPayStepDef.java b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/cucumber/stepdef/BillPayStepDef.java new file mode 100644 index 000000000..912c8d313 --- /dev/null +++ b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/cucumber/stepdef/BillPayStepDef.java @@ -0,0 +1,768 @@ +package org.mifos.integrationtest.cucumber.stepdef; + +import static com.github.tomakehurst.wiremock.client.WireMock.getAllServeEvents; +import static com.github.tomakehurst.wiremock.client.WireMock.matchingJsonPath; +import static com.github.tomakehurst.wiremock.client.WireMock.putRequestedFor; +import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo; +import static com.github.tomakehurst.wiremock.client.WireMock.verify; +import static com.google.common.truth.Truth.assertThat; +import static java.util.concurrent.TimeUnit.SECONDS; +import static org.awaitility.Awaitility.await; +import static org.mifos.integrationtest.common.Utils.CONTENT_TYPE; +import static org.mifos.integrationtest.common.Utils.getDefaultSpec; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.github.tomakehurst.wiremock.client.WireMock; +import com.github.tomakehurst.wiremock.stubbing.ServeEvent; +import io.cucumber.core.internal.com.fasterxml.jackson.core.JsonProcessingException; +import io.cucumber.core.internal.com.fasterxml.jackson.databind.JsonNode; +import io.cucumber.java.en.And; +import io.cucumber.java.en.Given; +import io.cucumber.java.en.Then; +import io.cucumber.java.en.When; +import io.restassured.RestAssured; +import io.restassured.builder.ResponseSpecBuilder; +import io.restassured.specification.RequestSpecification; +import java.io.IOException; +import java.util.List; +import java.util.UUID; +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; +import org.mifos.connector.common.channel.dto.PhErrorDTO; +import org.mifos.integrationtest.common.UniqueNumberGenerator; +import org.mifos.integrationtest.common.Utils; +import org.mifos.integrationtest.common.dto.Alias; +import org.mifos.integrationtest.common.dto.Bill; +import org.mifos.integrationtest.common.dto.BillRTPReqDTO; +import org.mifos.integrationtest.common.dto.BillStatusReqDTO; +import org.mifos.integrationtest.common.dto.ErrorDetails; +import org.mifos.integrationtest.common.dto.PayerFSPDetail; +import org.mifos.integrationtest.common.dto.billpayp2g.BillPaymentsReqDTO; +import org.mifos.integrationtest.config.BillPayConnectorConfig; +import org.springframework.beans.factory.annotation.Autowired; + +public class BillPayStepDef extends BaseStepDef { + + @Autowired + BillPaymentsReqDTO billPaymentsReqDTO; + + @Autowired + private BillPayConnectorConfig billPayConnectorConfig; + private static String billerId; + private static BillRTPReqDTO billRTPReqDTO; + + private static BillStatusReqDTO billStatusReqDTO; + private static String billId = "12345"; + private static String rtpId = "123456"; + private static String rtpResponse; + private static String statusResponse; + + @Then("I can create DTO for Biller RTP Request") + public void iCanCreateDTOForBillerRTPRequest() { + Bill bill = new Bill("Test", 100.0); + String payeeFsp = payeeFspConfig.getPayerFsp("payerfsp1"); + PayerFSPDetail payerFSPDetail = new PayerFSPDetail(payeeFsp, "1223455"); + billRTPReqDTO = new BillRTPReqDTO("123445", scenarioScopeState.billId, "00", payerFSPDetail, bill); + + } + + @And("I have bill id as {string}") + public void iHaveBillIdAs(String billId) { + scenarioScopeState.billId = billId; + assertThat(scenarioScopeState.billId).isNotEmpty(); + } + + @When("I call the get bills api with billid with expected status of {int} and callbackurl as {string}") + public void iCallTheGetBillsApiWithBillidWithExpectedStatusOf(int expectedStatus, String callbackUrl) + throws JsonProcessingException, JSONException { + RequestSpecification requestSpec = Utils.getDefaultSpec(scenarioScopeState.tenant); + + requestSpec.header("X-CorrelationID", scenarioScopeState.clientCorrelationId.toString()); + requestSpec.header("X-CallbackURL", billPayConnectorConfig.callbackURL + callbackUrl); + String fsp = payeeFspConfig.getPayerFsp("payerfsp1"); + requestSpec.header("Payer-FSP-Id", fsp); + requestSpec.queryParam("fields", "inquiry"); + scenarioScopeState.response = RestAssured.given(requestSpec).baseUri(billPayConnectorConfig.billPayContactPoint).expect() + .spec(new ResponseSpecBuilder().expectStatusCode(expectedStatus).build()).when() + .get(billPayConnectorConfig.inquiryEndpoint.replace("{billId}", scenarioScopeState.billId)).andReturn().asString(); + + logger.info("Bill Pay response: {}", scenarioScopeState.response); + JSONObject jsonObject = new JSONObject(scenarioScopeState.response); + scenarioScopeState.transactionId = jsonObject.getString("transactionId"); + assertThat(scenarioScopeState.transactionId.equals("NA")).isFalse(); + + } + + @And("I should get transactionId in response") + public void iShouldGetBatchIdInResponse() throws JSONException { + JSONObject jsonObject = new JSONObject(scenarioScopeState.response); + assertThat(jsonObject.getString("transactionId").equals("NA")).isFalse(); + scenarioScopeState.transactionId = jsonObject.getString("transactionId"); + + } + + @And("I should have startedAt and completedAt and workflowInstanceKey in response and not null") + public void iShouldHaveStartedAtAndCompletedAtAndWorkflowInstanceKeyInResponse() throws JSONException { + assertThat(scenarioScopeState.response).containsMatch("startedAt"); + assertThat(scenarioScopeState.response).containsMatch("completedAt"); + assertThat(scenarioScopeState.response).containsMatch("workflowInstanceKey"); + + JSONObject jsonObject = new JSONObject(scenarioScopeState.response); + JSONArray jsonArray = (JSONArray) jsonObject.get("content"); + JSONObject content = (JSONObject) jsonArray.get(0); + String value = content.get("startedAt").toString(); + assertThat(value).isNotNull(); + value = content.get("completedAt").toString(); + assertThat(value).isNotNull(); + value = content.get("workflowInstanceKey").toString(); + assertThat(value).isNotNull(); + + } + + @And("I can mock payment notification request") + public void iCanMockPaymentNotificationRequest() throws JsonProcessingException { + BillPaymentsReqDTO billPaymentsReqDTO = new BillPaymentsReqDTO(); + billPaymentsReqDTO.setBillId(scenarioScopeState.billId); + billPaymentsReqDTO.setPaymentReferenceID(UniqueNumberGenerator.generateUniqueNumber(14)); + billPaymentsReqDTO.setClientCorrelationId(scenarioScopeState.clientCorrelationId); + billPaymentsReqDTO.setBillInquiryRequestId(scenarioScopeState.clientCorrelationId); + scenarioScopeState.inboundTransferReqP2G = billPaymentsReqDTO; + logger.info("inboundTransferReqP2G: {}", scenarioScopeState.inboundTransferReqP2G); + assertThat(scenarioScopeState.inboundTransferReqP2G).isNotNull(); + + } + + @And("I can mock payment notification request with missing values") + public void iCanMockPaymentNotificationRequestwithMissingValues() throws JsonProcessingException { + BillPaymentsReqDTO billPaymentsReqDTO = new BillPaymentsReqDTO(); + billPaymentsReqDTO.setPaymentReferenceID(UniqueNumberGenerator.generateUniqueNumber(12)); + billPaymentsReqDTO.setClientCorrelationId(scenarioScopeState.clientCorrelationId); + scenarioScopeState.inboundTransferReqP2G = billPaymentsReqDTO; + logger.info("inboundTransferReqP2G: {}", scenarioScopeState.inboundTransferReqP2G); + assertThat(scenarioScopeState.inboundTransferReqP2G).isNotNull(); + + } + + @And("I can mock payment notification request with missing bill id") + public void iCanMockPaymentNotificationRequestwithMissingBillId() throws JsonProcessingException { + BillPaymentsReqDTO billPaymentsReqDTO = new BillPaymentsReqDTO(); + billPaymentsReqDTO.setPaymentReferenceID(UUID.randomUUID().toString()); + billPaymentsReqDTO.setClientCorrelationId(scenarioScopeState.clientCorrelationId); + billPaymentsReqDTO.setBillInquiryRequestId(scenarioScopeState.clientCorrelationId); + scenarioScopeState.inboundTransferReqP2G = billPaymentsReqDTO; + logger.info("inboundTransferReqP2G: {}", scenarioScopeState.inboundTransferReqP2G); + assertThat(scenarioScopeState.inboundTransferReqP2G).isNotNull(); + + } + + @When("I call the payment notification api expected status of {int} and callbackurl as {string}") + public void iCallThePaymentNotificationApiExpectedStatusOf(int expectedStatus, String callbackurl) throws JSONException { + RequestSpecification requestSpec = getDefaultSpec(); + requestSpec.header(CONTENT_TYPE, "application/json"); + requestSpec.header("X-Platform-TenantId", scenarioScopeState.tenant); + requestSpec.header("X-CorrelationID", scenarioScopeState.clientCorrelationId); + String fsp = payeeFspConfig.getPayerFsp("payerfsp1"); + requestSpec.header("X-PayerFSP-Id", fsp); + requestSpec.queryParam("fields", "inquiry"); + requestSpec.header("X-CallbackURL", billPayConnectorConfig.callbackURL + callbackurl); + scenarioScopeState.response = RestAssured.given(requestSpec).baseUri(billPayConnectorConfig.billPayContactPoint) + .body(scenarioScopeState.inboundTransferReqP2G).expect() + .spec(new ResponseSpecBuilder().expectStatusCode(expectedStatus).build()).when() + .post(billPayConnectorConfig.paymentsEndpoint).andReturn().asString(); + + logger.info("Payment notiifcation response: {}", scenarioScopeState.response); + } + + @When("I call the mock get bills api from PBB to Biller with billid with expected status of {int}") + public void iCallTheMockGetBillsApiPBBToBillerAggWithBillidWithExpectedStatusOf(int expectedStatus) { + RequestSpecification requestSpec = Utils.getDefaultSpec(scenarioScopeState.tenant); + requestSpec.header("X-CorrelationID", scenarioScopeState.clientCorrelationId); + String fsp = payeeFspConfig.getPayerFsp("payerfsp1"); + requestSpec.header("Payer-FSP-Id", fsp); + requestSpec.header("X-CallbackURL", billPayConnectorConfig.callbackURL + "/billInquiry"); + + scenarioScopeState.response = RestAssured.given(requestSpec).baseUri(billPayConnectorConfig.billPayContactPoint).expect() + .spec(new ResponseSpecBuilder().expectStatusCode(expectedStatus).build()).when() + .get(billPayConnectorConfig.inquiryEndpoint.replace("{billId}", billId)).andReturn().asString(); + + logger.info("Txn Req response: {}", scenarioScopeState.response); + + } + + @When("I call the mock bills payment api from PBB to Biller with billid with expected status of {int}") + public void iCallTheMockBillsPaymentApiFromPBBToBillerWithBillidWithExpectedStatusOf(int expectedStatus) { + RequestSpecification requestSpec = Utils.getDefaultSpec(); + requestSpec.header(CONTENT_TYPE, "application/json"); + requestSpec.header("X-Platform-TenantId", scenarioScopeState.tenant); + requestSpec.header("X-CorrelationID", scenarioScopeState.clientCorrelationId); + String fsp = payeeFspConfig.getPayerFsp("payerfsp1"); + requestSpec.header("X-PayerFSP-Id", fsp); + requestSpec.header("X-CallbackURL", "https://webhook.site/b44174ab-04b4-4b0d-8426-a3c54bc2f794"); + scenarioScopeState.response = RestAssured.given(requestSpec).baseUri(billPayConnectorConfig.billPayContactPoint) + .body(scenarioScopeState.inboundTransferReqP2G).expect() + .spec(new ResponseSpecBuilder().expectStatusCode(expectedStatus).build()).when() + .post(billPayConnectorConfig.paymentsEndpoint).andReturn().asString(); + + logger.info("Txn Req response: {}", scenarioScopeState.response); + } + + @Then("I should be able to verify that the {string} method to {string} endpoint received a request with code in body") + public void iShouldBeAbleToVerifyThatTheMethodToEndpointReceivedRequestWithASpecificBody(String httpmethod, String endpoint) { + verify(putRequestedFor(urlEqualTo(endpoint)).withRequestBody(matchingJsonPath("$.code"))); + } + + @Then("I should be able to extract response body from callback for bill pay") + public void iShouldBeAbleToExtractResponseBodyFromCallbackForBillPay() { + await().atMost(awaitMost, SECONDS).pollInterval(pollInterval, SECONDS).untilAsserted(() -> { + boolean flag = false; + List allServeEvents = getAllServeEvents(); + for (int i = allServeEvents.size() - 1; i >= 0; i--) { + ServeEvent request = allServeEvents.get(i); + if (!(request.getRequest().getBodyAsString()).isEmpty() && request.getRequest().getUrl().equals("/billInquiry")) { + JsonNode rootNode = null; + flag = true; + try { + rootNode = objectMapper.readTree(request.getRequest().getBody()); + logger.info("Rootnode value:" + rootNode); + } catch (IOException e) { + throw new RuntimeException(e); + } + if (rootNode != null && rootNode.has("billId") && rootNode.get("billId").asText().equals("001")) { + String reason = null; + if (rootNode.has("reason")) { + reason = rootNode.get("reason").asText(); + } + assertThat(reason).isNotEmpty(); + String rtpStatus = null; + if (rootNode.has("code")) { + rtpStatus = rootNode.get("code").asText(); + } + assertThat(rtpStatus).isNotEmpty(); + String billId = null; + if (rootNode.has("billId")) { + billId = rootNode.get("billId").asText(); + } + assertThat(billId).isNotEmpty(); + } + } + + } + assertThat(flag).isTrue(); + }); + } + + @Then("I should be able to extract response body from callback for bill notification") + public void iShouldBeAbleToExtractResponseBodyFromCallbackForBillNotification() { + await().atMost(awaitMost, SECONDS).pollInterval(pollInterval, SECONDS).untilAsserted(() -> { + boolean flag = false; + List allServeEvents = getAllServeEvents(); + for (int i = allServeEvents.size() - 1; i >= 0; i--) { + ServeEvent request = allServeEvents.get(i); + if (!(request.getRequest().getBodyAsString()).isEmpty() && request.getRequest().getUrl().equals("/billNotification")) { + JsonNode rootNode = null; + flag = true; + try { + rootNode = objectMapper.readTree(request.getRequest().getBody()); + logger.info("Rootnode value:" + rootNode); + } catch (IOException e) { + throw new RuntimeException(e); + } + if (rootNode != null && rootNode.has("billId") && rootNode.get("billId").asText().equals("001")) { + String requestId = null; + if (rootNode.has("billRequestId")) { + requestId = rootNode.get("billRequestId").asText(); + } + assertThat("billRequestId").isNotEmpty(); + String rtpStatus = null; + if (rootNode.has("code")) { + rtpStatus = rootNode.get("code").asText(); + } + assertThat(rtpStatus).isNotEmpty(); + String billId = null; + if (rootNode.has("billId")) { + billId = rootNode.get("billId").asText(); + } + assertThat(billId).isNotEmpty(); + } + } + + } + assertThat(flag).isTrue(); + }); + } + + @And("I can call the biller RTP request API with expected status of {int} and {string} endpoint") + public void iCanCallTheBillerRTPRequestAPIWithExpectedStatusOfAndEndpoint(int expectedStatus, String stub) + throws JsonProcessingException, com.fasterxml.jackson.core.JsonProcessingException { + ObjectMapper objectMapper = new ObjectMapper(); + String jsonPayload = objectMapper.writeValueAsString(billRTPReqDTO); + RequestSpecification requestSpec = Utils.getDefaultSpec(); + scenarioScopeState.response = RestAssured.given(requestSpec).header("Content-Type", "application/json") + .header("X-Callback-URL", billPayConnectorConfig.callbackURL + stub).header("X-Biller-Id", billerId) + .header("X-Client-Correlation-ID", scenarioScopeState.clientCorrelationId) + .header("X-Platform-TenantId", scenarioScopeState.tenant).baseUri(billPayConnectorConfig.billPayContactPoint) + .body(billRTPReqDTO).expect().spec(new ResponseSpecBuilder().expectStatusCode(expectedStatus).build()).when() + .post(billPayConnectorConfig.billerRtpEndpoint).andReturn().asString(); + + rtpResponse = scenarioScopeState.response; + logger.info("RTP Response: {}", scenarioScopeState.response); + } + + @And("I have a billerId as {string}") + public void iHaveABillerIdAs(String biller) { + billerId = biller; + } + + @And("I can extract the callback body and assert the rtpStatus") + public void iCanExtractTheCallbackBodyAndAssertTheRtpStatus() { + await().atMost(awaitMost, SECONDS).pollInterval(pollInterval, SECONDS).untilAsserted(() -> { + boolean flag = false; + List allServeEvents = getAllServeEvents(); + for (int i = allServeEvents.size() - 1; i >= 0; i--) { + ServeEvent request = allServeEvents.get(i); + if (!(request.getRequest().getBodyAsString()).isEmpty()) { + JsonNode rootNode = null; + flag = true; + try { + rootNode = objectMapper.readTree(request.getRequest().getBody()); + logger.info("Rootnode value:" + rootNode); + } catch (IOException e) { + throw new RuntimeException(e); + } + if (rootNode != null && rootNode.has("rtpId") && rootNode.get("rtpId").asText().equals(rtpId)) { + String requestId = null; + if (rootNode.has("requestId")) { + requestId = rootNode.get("requestId").asText(); + scenarioScopeState.requestId = requestId; + } + assertThat(requestId).isNotEmpty(); + String rtpStatus = null; + if (rootNode.has("rtpStatus")) { + rtpStatus = rootNode.get("rtpStatus").asText(); + } + assertThat(rtpStatus).isNotEmpty(); + String rtpId = null; + if (rootNode.has("rtpId")) { + rtpId = rootNode.get("rtpId").asText(); + scenarioScopeState.rtpId = rtpId; + } + assertThat(rtpId).isNotEmpty(); + String billId = null; + if (rootNode.has("billId")) { + billId = rootNode.get("billId").asText(); + } + assertThat(billId).isNotEmpty(); + } + } + + } + assertThat(flag).isTrue(); + }); + } + + @Then("I should be able to extract response body from callback for biller unidentified") + public void iShouldBeAbleToExtractResponseBodyFromCallbackForBillerUnidentified() { + await().atMost(awaitMost, SECONDS).pollInterval(pollInterval, SECONDS).untilAsserted(() -> { + boolean flag = false; + List allServeEvents = getAllServeEvents(); + for (int i = allServeEvents.size() - 1; i >= 0; i--) { + ServeEvent request = allServeEvents.get(i); + if (!(request.getRequest().getBodyAsString()).isEmpty() + && request.getRequest().getUrl().equals("/billInquiryPrefixInvalid")) { + JsonNode rootNode = null; + flag = true; + try { + rootNode = objectMapper.readTree(request.getRequest().getBody()); + logger.info("Rootnode value:" + rootNode); + } catch (IOException e) { + throw new RuntimeException(e); + } + if (rootNode != null && rootNode.has("responseCode") && rootNode.get("responseCode").asText().equals("01")) { + String responseDescription = null; + if (rootNode.has("responseDescription")) { + responseDescription = rootNode.get("responseDescription").asText(); + } + assertThat(responseDescription).isNotEmpty(); + assertThat(responseDescription).contains("Unindentified Biller"); + String responseCode = null; + if (rootNode.has("responseCode")) { + responseCode = rootNode.get("responseCode").asText(); + } + assertThat(responseCode).isNotEmpty(); + } + } + + } + assertThat(flag).isTrue(); + }); + } + + @Then("I should be able to extract response body from callback for bill invalid") + public void iShouldBeAbleToExtractResponseBodyFromCallbackForBillInvalid() { + await().atMost(awaitMost, SECONDS).pollInterval(pollInterval, SECONDS).untilAsserted(() -> { + boolean flag = false; + List allServeEvents = getAllServeEvents(); + for (int i = allServeEvents.size() - 1; i >= 0; i--) { + ServeEvent request = allServeEvents.get(i); + if (!(request.getRequest().getBodyAsString()).isEmpty() && request.getRequest().getUrl().equals("/invalidbillInquiry")) { + JsonNode rootNode = null; + flag = true; + try { + rootNode = objectMapper.readTree(request.getRequest().getBody()); + logger.info("Rootnode value:" + rootNode); + } catch (IOException e) { + throw new RuntimeException(e); + } + if (rootNode != null && rootNode.has("code") && rootNode.get("code").asText().equals("01")) { + String reason = null; + if (rootNode.has("reason")) { + reason = rootNode.get("reason").asText(); + } + assertThat(reason).isNotEmpty(); + assertThat(reason).contains("Invalid Bill ID"); + String code = null; + if (rootNode.has("code")) { + code = rootNode.get("code").asText(); + } + assertThat(code).isNotEmpty(); + } + } + + } + assertThat(flag).isTrue(); + }); + } + + @And("I should get Payer FSP not found in response") + public void iShouldGetDataInResponse() throws JSONException { + JSONObject jsonObject = new JSONObject(scenarioScopeState.response); + scenarioScopeState.transactionId = jsonObject.getString("transactionId"); + assertThat(scenarioScopeState.transactionId.equals("Participant Not Onboarded")).isTrue(); + } + + @Then("I should be able to extract response body from callback for empty bill id") + public void iShouldBeAbleToExtractResponseBodyFromCallbackForEmptyBillId() { + await().atMost(awaitMost, SECONDS).pollInterval(pollInterval, SECONDS).untilAsserted(() -> { + boolean flag = false; + List allServeEvents = getAllServeEvents(); + for (int i = allServeEvents.size() - 1; i >= 0; i--) { + ServeEvent request = allServeEvents.get(i); + if (!(request.getRequest().getBodyAsString()).isEmpty() && request.getRequest().getUrl().equals("/billInquiryEmpty")) { + JsonNode rootNode = null; + flag = true; + try { + rootNode = objectMapper.readTree(request.getRequest().getBody()); + logger.info("Rootnode value:" + rootNode); + } catch (IOException e) { + throw new RuntimeException(e); + } + if (rootNode != null && rootNode.has("code") && rootNode.get("code").asText().equals("01")) { + if (rootNode.get("clientCorrelationId").asText().equals(scenarioScopeState.clientCorrelationId)) { + String reason = null; + if (rootNode.has("reason")) { + reason = rootNode.get("reason").asText(); + } + assertThat(reason).isNotEmpty(); + assertThat(reason).contains("Empty Bill ID"); + String code = null; + if (rootNode.has("code")) { + code = rootNode.get("code").asText(); + } + assertThat(code).isNotEmpty(); + } + } + + } + + } + assertThat(flag).isTrue(); + }); + } + + @Then("I should be able to extract response body from callback for bill notification with missing values") + public void iShouldBeAbleToExtractResponseBodyFromCallbackForBillNotificationWithMissingValues() throws JSONException { + await().atMost(awaitMost, SECONDS).pollInterval(pollInterval, SECONDS).untilAsserted(() -> { + + JSONObject jsonObject = new JSONObject(scenarioScopeState.response); + assertThat(jsonObject.getString("error") + .equals("Invalid Request: Mandatory Fields Missing, Missing field is billInquiryRequestId")).isTrue(); + }); + } + + @Then("I should be able to extract response body from callback for bill notification with missing bill id") + public void iShouldBeAbleToExtractResponseBodyFromCallbackForBillNotificationWithMissingBillId() throws JSONException { + await().atMost(awaitMost, SECONDS).pollInterval(pollInterval, SECONDS).untilAsserted(() -> { + + JSONObject jsonObject = new JSONObject(scenarioScopeState.response); + assertThat(jsonObject.getString("error").equals("Invalid Request: Bill Id Empty")).isTrue(); + }); + } + + @Then("I should be able to extract response body from callback for bill already paid") + public void iShouldBeAbleToExtractResponseBodyFromCallbackForBillAlreadyPaid() { + await().atMost(awaitMost, SECONDS).pollInterval(pollInterval, SECONDS).untilAsserted(() -> { + boolean flag = false; + List allServeEvents = getAllServeEvents(); + for (int i = allServeEvents.size() - 1; i >= 0; i--) { + ServeEvent request = allServeEvents.get(i); + if (!(request.getRequest().getBodyAsString()).isEmpty() && request.getRequest().getUrl().equals("/billNotificationPaid")) { + JsonNode rootNode = null; + flag = true; + try { + rootNode = objectMapper.readTree(request.getRequest().getBody()); + logger.info("Rootnode value:" + rootNode); + } catch (IOException e) { + throw new RuntimeException(e); + } + if (rootNode != null && rootNode.has("code") && rootNode.get("code").asText().equals("01")) { + if (rootNode.has("requestID") + && rootNode.get("requestID").asText().equals(scenarioScopeState.clientCorrelationId)) { + String reason = null; + if (rootNode.has("reason")) { + reason = rootNode.get("reason").asText(); + } + assertThat(reason).isNotEmpty(); + assertThat(reason).contains("Bill Payment Failed: Bill Already Paid"); + String code = null; + if (rootNode.has("code")) { + code = rootNode.get("code").asText(); + } + assertThat(code).isNotEmpty(); + } + } + } + + } + assertThat(flag).isTrue(); + }); + } + + @Then("I should remove all server events") + public void iShouldNotBeAbleToRemoveAllServerEvents() { + boolean flag = false; + WireMock.resetAllRequests(); + List allServeEvents = getAllServeEvents(); + assertThat(allServeEvents.size()).isEqualTo(0); + } + + @Then("I should not get a response from callback for bill") + public void iShouldNotBeAbleToExtractResponseBodyFromCallbackForBill() { + await().atMost(awaitMost, SECONDS).pollDelay(pollDelay, SECONDS).pollInterval(pollInterval, SECONDS).untilAsserted(() -> { + boolean flag = false; + List allServeEvents = getAllServeEvents(); + if (allServeEvents.isEmpty()) { + flag = true; + } else { + for (int i = allServeEvents.size() - 1; i >= 0; i--) { + ServeEvent request = allServeEvents.get(i); + if (!(request.getRequest().getUrl().equals("/billNotificationsTimeout"))) { + flag = true; + } + } + } + assertThat(flag).isTrue(); + + }); + } + + @Then("I should be able to extract response body from callback for bill paid after timeout") + public void iShouldBeAbleToExtractResponseBodyFromCallbackForBillPaidAfterTimeout() { + await().atMost(awaitMost, SECONDS).pollDelay(pollDelay, SECONDS).pollInterval(pollInterval, SECONDS).untilAsserted(() -> { + boolean flag = false; + List allServeEvents = getAllServeEvents(); + for (int i = allServeEvents.size() - 1; i >= 0; i--) { + ServeEvent request = allServeEvents.get(i); + if (!(request.getRequest().getBodyAsString()).isEmpty() + && request.getRequest().getUrl().equals("/billNotificationsTimeout")) { + JsonNode rootNode = null; + flag = true; + try { + rootNode = objectMapper.readTree(request.getRequest().getBody()); + logger.info("Rootnode value:" + rootNode); + } catch (IOException e) { + throw new RuntimeException(e); + } + if (rootNode != null && rootNode.has("code") && rootNode.get("code").asText().equals("01")) { + if (rootNode.get("requestID").asText().equals(scenarioScopeState.clientCorrelationId)) { + String reason = null; + if (rootNode.has("reason")) { + reason = rootNode.get("reason").asText(); + } + assertThat(reason).isNotEmpty(); + assertThat(reason).contains("Bill Payment Failed: Bill Paid After Timeout"); + String code = null; + if (rootNode.has("code")) { + code = rootNode.get("code").asText(); + } + assertThat(code).isNotEmpty(); + } + } + + } + + } + assertThat(flag).isTrue(); + }); + } + + @Then("I can create DTO for Biller RTP Request without alias details") + public void iCanCreateDTOForBillerRTPRequestWithoutAliasDetails() { + Bill bill = new Bill("Test", 100.0); + billRTPReqDTO = new BillRTPReqDTO("123445", billId, "00", new Alias(), bill); + } + + @Then("I can create DTO for Biller RTP Request with incorrect rtp type") + public void iCanCreateDTOForBillerRTPRequestWithIncorrectRtpType() { + Bill bill = new Bill("Test", 100.0); + billRTPReqDTO = new BillRTPReqDTO("123445", billId, "03", new Alias(), bill); + } + + @Then("I can create DTO for Biller RTP Request with incorrect rtp information") + public void iCanCreateDTOForBillerRTPRequestWithIncorrectRtpInformation() { + Bill bill = new Bill("Test", 100.0); + String payeeFsp = payeeFspConfig.getPayerFsp("payerfsp1"); + PayerFSPDetail payerFSPDetail = new PayerFSPDetail(payeeFsp, "1223455"); + billRTPReqDTO = new BillRTPReqDTO("123445", billId, "01", payerFSPDetail, bill); + } + + @Then("I can create DTO for Biller RTP Request with incorrect alias details") + public void iCanCreateDTOForBillerRTPRequestWithIncorrectAliasDetails() { + Bill bill = new Bill("Test", 100.0); + billRTPReqDTO = new BillRTPReqDTO("123445", billId, "03", new Alias("05", "12345"), bill); + } + + @Then("I can create DTO for Biller RTP Request to mock payer fi unreachable") + public void iCanCreateDTOForBillerRTPRequestToMockPayerFiUnreachable() { + Bill bill = new Bill("Test", 100.0); + String payerfsp = tenantConfig.getTenant("paymentbb1".toLowerCase()); + PayerFSPDetail payerFSPDetail = new PayerFSPDetail(payerfsp, "122333"); + billRTPReqDTO = new BillRTPReqDTO("123445", billId, "00", payerFSPDetail, bill); + } + + @Then("I can create DTO for Biller RTP Request to mock payer fsp failed to debit amount") + public void iCanCreateDTOForBillerRTPRequestToMockPayerFspFailedToDebitAmount() { + Bill bill = new Bill("Test", 100.0); + String payerfsp = tenantConfig.getTenant("paymentbb1".toLowerCase()); + PayerFSPDetail payerFSPDetail = new PayerFSPDetail(payerfsp, "1223334444"); + billRTPReqDTO = new BillRTPReqDTO(scenarioScopeState.clientCorrelationId, scenarioScopeState.billId, "00", payerFSPDetail, bill); + } + + @And("I can extract the error from response body and assert the error information as {string}") + public void iCanExtractTheErrorFromResponseBodyAndAssertTheErrorInformationAs(String errorMessage) { + PhErrorDTO errorInformation; + try { + JSONObject jsonObject = new JSONObject(scenarioScopeState.response); + errorInformation = objectMapper.readValue(jsonObject.toString(), PhErrorDTO.class); + + } catch (JSONException | JsonProcessingException e) { + throw new RuntimeException(e); + } + assertThat(errorInformation.getErrors().get(0).getErrorDescription()).isEqualTo(errorMessage); + } + + @And("I can extract the error from callback body and assert error message as {string}") + public void iCanExtractTheErrorFromCallbackBodyAndAssertErrorMessageAs(String errorMessage) { + await().atMost(awaitMost, SECONDS).pollInterval(pollInterval, SECONDS).untilAsserted(() -> { + boolean flag = false; + List allServeEvents = getAllServeEvents(); + for (int i = allServeEvents.size() - 1; i >= 0; i--) { + ServeEvent request = allServeEvents.get(i); + if (!(request.getRequest().getBodyAsString()).isEmpty()) { + JsonNode rootNode = null; + flag = true; + try { + rootNode = objectMapper.readTree(request.getRequest().getBody()); + logger.info("Rootnode value:" + rootNode); + } catch (IOException e) { + throw new RuntimeException(e); + } + if (rootNode != null && rootNode.has("errorMessage")) { + if (request.getRequest().getHeader("X-Client-Correlation-ID").equals(scenarioScopeState.clientCorrelationId)) { + String error = null; + if (rootNode.has("errorMessage")) { + error = rootNode.get("errorMessage").asText(); + } + assertThat(error).isEqualTo(errorMessage); + } + } + } + } + }); + } + + @Then("I should be able to extract response body from callback for bill notification with empty bill id") + public void iShouldBeAbleToExtractResponseBodyFromCallbackForBillNotificationWithEmptyBillId() throws JSONException { + await().atMost(awaitMost, SECONDS).pollInterval(pollInterval, SECONDS).untilAsserted(() -> { + + JSONObject jsonObject = new JSONObject(scenarioScopeState.response); + scenarioScopeState.transactionId = jsonObject.getString("error"); + assertThat(scenarioScopeState.transactionId.equals("Invalid Request: Bill Id Empty")).isTrue(); + }); + } + + @Given("I can create a request for status api") + public void iCanCreateARequestForStatusApi() { + billStatusReqDTO = new BillStatusReqDTO(scenarioScopeState.rtpId, scenarioScopeState.requestId); + + } + + @And("I can call the biller RTP status API with expected status of {int} until I get the rtpStatus as {string}") + public void iCanCallTheBillerRTPStatusAPIWithExpectedStatusOf(int expectedStatus, String status) + throws com.fasterxml.jackson.core.JsonProcessingException { + await().atMost(awaitMost, SECONDS).pollDelay(pollDelay, SECONDS).pollInterval(pollInterval, SECONDS).untilAsserted(() -> { + ObjectMapper objectMapper = new ObjectMapper(); + String jsonPayload = objectMapper.writeValueAsString(billStatusReqDTO); + RequestSpecification requestSpec = Utils.getDefaultSpec(scenarioScopeState.tenant); + requestSpec.header("X-CorrelationID", "123"); + requestSpec.header("billId", scenarioScopeState.billId); + String endpoint = billPayConnectorConfig.statusEndpoint; + endpoint = String.format(endpoint.replace("{{correlationId}}", "%s"), scenarioScopeState.clientCorrelationId); + scenarioScopeState.response = RestAssured.given(requestSpec).header("Content-Type", "application/json") + .header("X-Biller-Id", billerId).header("X-CorrelationID", scenarioScopeState.clientCorrelationId) + .baseUri(billPayConnectorConfig.billPayContactPoint).body(jsonPayload).expect() + .spec(new ResponseSpecBuilder().expectStatusCode(expectedStatus).build()).when().get(endpoint).andReturn().asString(); + + statusResponse = scenarioScopeState.response; + logger.info("Status Response: {}", scenarioScopeState.response); + assertThat(scenarioScopeState.response.contains(status)).isTrue(); + }); + } + + @When("I call the mock bills payment api with invalid header from PBB to Biller with billid with expected status of {int}") + public void iCallTheMockBillsPaymentApiWithInvalidFromPBBToBillerWithBillidWithExpectedStatusOf(int expectedStatus) { + RequestSpecification requestSpec = Utils.getDefaultSpec(); + requestSpec.header(CONTENT_TYPE, "application/json"); + requestSpec.header("X-Platform-TenantId", scenarioScopeState.tenant); + requestSpec.header("X-CorrelationID", scenarioScopeState.clientCorrelationId); + requestSpec.header("X-PayerFSP-Id", "lion"); + requestSpec.header("X-CallbackURL", "https://webhook.site/b44174ab-04b4-4b0d-8426-a3c54bc2f794"); + requestSpec.header("invalid-header", "test"); + scenarioScopeState.response = RestAssured.given(requestSpec).baseUri(billPayConnectorConfig.billPayContactPoint) + .body(scenarioScopeState.inboundTransferReqP2G).expect() + .spec(new ResponseSpecBuilder().expectStatusCode(expectedStatus).build()).when() + .post(billPayConnectorConfig.paymentsEndpoint).andReturn().asString(); + + logger.info("Txn Req response: {}", scenarioScopeState.response); + } + + @And("I should be able to assert negative response body") + public void iWillAssertTheFieldsFromCreateVoucherValidationResponse() { + try { + JsonNode rootNode = objectMapper.readTree(scenarioScopeState.response); + + ErrorDetails errorDetails = objectMapper.treeToValue(rootNode, ErrorDetails.class); + + assertThat(errorDetails.getErrorCode()).isEqualTo("error.msg.schema.validation.errors"); + assertThat(errorDetails.getErrorDescription()).isEqualTo("The request is invalid"); + + } catch (Exception e) { + logger.info("An error occurred : {}", e); + } + } + + @Then("I will assert that response contains {string}") + public void iShouldBeAbleToVerifyThatTheMethodToEndpointReceivedRequestWithASpecificBody(String message) { + assertThat(scenarioScopeState.response.contains(message)); + } +} diff --git a/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/cucumber/stepdef/BulkPaymentStepDef.java b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/cucumber/stepdef/BulkPaymentStepDef.java new file mode 100644 index 000000000..3ae08634c --- /dev/null +++ b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/cucumber/stepdef/BulkPaymentStepDef.java @@ -0,0 +1,151 @@ +package org.mifos.integrationtest.cucumber.stepdef; + +import static com.google.common.truth.Truth.assertThat; + +import com.google.gson.Gson; +import io.cucumber.java.en.And; +import io.cucumber.java.en.Given; +import io.cucumber.java.en.Then; +import io.cucumber.java.en.When; +import io.restassured.RestAssured; +import io.restassured.builder.MultiPartSpecBuilder; +import io.restassured.builder.RequestSpecBuilder; +import io.restassured.builder.ResponseSpecBuilder; +import io.restassured.specification.MultiPartSpecification; +import io.restassured.specification.RequestSpecification; +import java.io.File; +import java.io.FileReader; +import java.io.IOException; +import java.io.Reader; +import java.net.URL; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; +import java.util.StringJoiner; +import org.apache.commons.csv.CSVFormat; +import org.apache.commons.csv.CSVParser; +import org.apache.commons.csv.CSVRecord; +import org.mifos.integrationtest.common.BatchSummaryResponse; +import org.mifos.integrationtest.common.Utils; +import org.mifos.integrationtest.config.BulkProcessorConfig; +import org.mifos.integrationtest.config.OperationsAppConfig; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; + +public class BulkPaymentStepDef extends BaseStepDef { + + private String batchId; + + private int completionPercent; + + @Value("${config.completion-threshold-check.completion-threshold}") + private int thresholdPercent; + + @Autowired + BulkProcessorConfig bulkProcessorConfig; + + @Autowired + OperationsAppConfig operationsAppConfig; + + @Given("the CSV file is available") + public boolean isCsvFileAvailable() { + String fileName = "bulk-payment.csv"; + ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); + URL resource = classLoader.getResource(fileName); + return resource != null && resource.getPath().endsWith(".csv"); + } + + @When("initiate the batch transaction API with the input CSV file with tenant as {string}") + public void initiateTheBatchTransactionAPIWithTheInputCSVFileWithTenantAs(String tenant) { + Map headers = new HashMap<>(); + headers.put("Purpose", "test payment"); + headers.put("filename", "bulk_payment.csv"); + headers.put("X-CorrelationID", "12345678-6897-6798-6798-098765432134"); + headers.put("Platform-TenantId", tenant); + String fileContent = getFileContent("bulk-payment.csv"); + logger.info("file content: " + fileContent); + RequestSpecification requestSpec = getDefaultSpec(); + String response = RestAssured.given(requestSpec).baseUri(bulkProcessorConfig.bulkProcessorContactPoint) + .multiPart(getMultiPart(fileContent)).queryParam("type", "csv").headers(headers).expect() + .spec(new ResponseSpecBuilder().expectStatusCode(200).build()).when().post(bulkProcessorConfig.bulkTransactionEndpoint) + .andReturn().asString(); + batchId = fetchBatchId(response); + logger.info(batchId); + logger.info("Batch transaction API response: " + response); + } + + @Given("the batch ID for the submitted CSV file") + public void isBatchIdAvailable() { + assertThat(batchId).isNotEmpty(); + } + + @And("poll the batch summary API using the batch ID and tenant as {string}") + public void pollTheBatchSummaryAPIUsingTheBatchIDAndTenantAs(String tenant) { + int retries = 5; + int intervalInSeconds = 30; + + Map headers = new HashMap<>(); + headers.put("Platform-TenantId", tenant); + RequestSpecification requestSpec = getDefaultSpec(); + + for (int index = 0; index < retries; index++) { + String response = RestAssured.given(requestSpec).baseUri(operationsAppConfig.operationAppContactPoint).param("batchId", batchId) + .headers(headers).expect().spec(new ResponseSpecBuilder().expectStatusCode(200).build()).when() + .get(operationsAppConfig.batchSummaryEndpoint).andReturn().asString(); + Gson gson = new Gson(); + BatchSummaryResponse batchSummaryResponse = gson.fromJson(response, BatchSummaryResponse.class); + assertThat(batchSummaryResponse).isNotNull(); + + if (batchSummaryResponse.getTotal() != 0) { + completionPercent = (int) (batchSummaryResponse.getSuccessful() / batchSummaryResponse.getTotal() * 100); + } + Utils.sleep(intervalInSeconds); + } + } + + @Then("successful transactions percentage should be greater than or equal to minimum threshold") + public void batchSummarySuccessful() { + assertThat(completionPercent).isNotNull(); + assertThat(completionPercent).isGreaterThan(thresholdPercent); + } + + private static RequestSpecification getDefaultSpec() { + RequestSpecification requestSpec = new RequestSpecBuilder().build(); + requestSpec.relaxedHTTPSValidation(); + return requestSpec; + } + + private MultiPartSpecification getMultiPart(String fileContent) { + return new MultiPartSpecBuilder(fileContent.getBytes()).fileName("test.csv").controlName("file").mimeType("text/plain").build(); + } + + private String getFileContent(String filePath) { + File file = new File(filePath); + Reader reader; + CSVFormat csvFormat; + CSVParser csvParser = null; + try { + reader = new FileReader(file); + csvFormat = CSVFormat.DEFAULT.withDelimiter(','); + csvParser = new CSVParser(reader, csvFormat); + } catch (IOException e) { + throw new RuntimeException(e); + } + StringJoiner stringJoiner = new StringJoiner("\n"); + + for (CSVRecord csvRecord : csvParser) { + stringJoiner.add(csvRecord.toString()); + } + return stringJoiner.toString(); + } + + private String fetchBatchId(String response) { + String[] split = response.split(","); + return split[0].substring(31); + } + + @And("I initialize the payee list") + public void iInitializeThePayeeList() { + scenarioScopeState.payeeIdentifiers = new ArrayList<>(); + } +} diff --git a/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/cucumber/stepdef/CertificateStepDef.java b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/cucumber/stepdef/CertificateStepDef.java new file mode 100644 index 000000000..721c650f5 --- /dev/null +++ b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/cucumber/stepdef/CertificateStepDef.java @@ -0,0 +1,50 @@ +package org.mifos.integrationtest.cucumber.stepdef; + +import static com.google.common.truth.Truth.assertThat; + +import io.cucumber.java.en.And; +import io.cucumber.java.en.Given; +import io.cucumber.java.en.Then; +import io.cucumber.java.en.When; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; +import org.mifos.connector.common.util.CertificateUtil; + +public class CertificateStepDef extends BaseStepDef { + + @Given("I have X509 certificate {string}") + public void setX509CertificateString(String certificate) { + scenarioScopeState.certificateString = certificate; + } + + @When("I have null certificate") + public void assertNullCertificate() { + assertThat(scenarioScopeState.certificateString).isNotEmpty(); + } + + @Then("I should be able to parse the certificate using CertificateUtils") + public void assertParseCertificate() throws CertificateException { + X509Certificate certificate = parseCertificate(); + assertThat(certificate).isNotNull(); + } + + @And("I can create certificate object") + public void notNullParseCertificate() throws CertificateException { + BaseStepDef.x509Certificate = parseCertificate(); + } + + @When("I parse the public key") + public void fetchPublicKeyFromX509Certificate() { + scenarioScopeState.publicKey = CertificateUtil.parseRSAPublicKey(BaseStepDef.x509Certificate); + } + + @Then("Public key should be non empty") + public void publicKeyNotEmptyCheck() { + assertThat(scenarioScopeState.publicKey).isNotNull(); + } + + public X509Certificate parseCertificate() throws CertificateException { + return CertificateUtil.parseX509Certificate(scenarioScopeState.certificateString); + } + +} diff --git a/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/cucumber/stepdef/ChannelClientIdDef.java b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/cucumber/stepdef/ChannelClientIdDef.java new file mode 100644 index 000000000..c17c8f22f --- /dev/null +++ b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/cucumber/stepdef/ChannelClientIdDef.java @@ -0,0 +1,64 @@ +package org.mifos.integrationtest.cucumber.stepdef; + +import static com.google.common.truth.Truth.assertThat; + +import io.cucumber.java.en.And; +import io.cucumber.java.en.When; +import io.restassured.RestAssured; +import io.restassured.builder.ResponseSpecBuilder; +import io.restassured.specification.RequestSpecification; +import org.mifos.integrationtest.common.Utils; +import org.mifos.integrationtest.config.ChannelConnectorConfig; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; + +public class ChannelClientIdDef extends BaseStepDef { + + @Value("${operations-app.auth.enabled}") + public Boolean authEnabled; + + @Autowired + ChannelConnectorConfig channelConnectorConfig; + + private String clientCorrelationId = "123456789"; + + @And("I have request type as {string}") + public void iHaveRequestTypeAs(String requestType) { + scenarioScopeState.requestType = requestType; + channelConnectorConfig.setRequestType(requestType); + assertThat(scenarioScopeState.requestType).isNotEmpty(); + } + + @And("I should have clientRefId in response") + public void iShouldHaveClientRefIdInResponse() { + assertThat(scenarioScopeState.response).containsMatch("clientRefId"); + } + + @When("I call the transfer API with expected status of {int}") + public void iCallTheTransferAPIWithExpectedStatusOf(int expectedStatus) { + RequestSpecification requestSpec = Utils.getDefaultSpec(scenarioScopeState.tenant); + if (authEnabled) { + requestSpec.header("Authorization", "Bearer " + scenarioScopeState.accessToken); + } + + scenarioScopeState.response = RestAssured.given(requestSpec).baseUri(operationsAppConfig.operationAppContactPoint).expect() + .spec(new ResponseSpecBuilder().expectStatusCode(expectedStatus).build()).when().get(operationsAppConfig.transfersEndpoint) + .andReturn().asString(); + + logger.info("Inbound transfer Response: {}", scenarioScopeState.response); + } + + @When("I call the txn State with client correlation id as {string} expected status of {int}") + public void iCallTheTxnStateWithClientCorrelationIdAsExpectedStatusOf(String XClientCorrelationId, int expectedStatus) { + RequestSpecification requestSpec = Utils.getDefaultSpec(scenarioScopeState.tenant); + if (authEnabled) { + requestSpec.header("Authorization", "Bearer " + scenarioScopeState.accessToken); + } + requestSpec.header(Utils.REQUEST_TYPE_PARAM_NAME, channelConnectorConfig.getRequestType()); + scenarioScopeState.response = RestAssured.given(requestSpec).baseUri(channelConnectorConfig.channelConnectorContactPoint).expect() + .spec(new ResponseSpecBuilder().expectStatusCode(expectedStatus).build()).when() + .get("/channel/txnState/" + XClientCorrelationId).andReturn().asString(); + + logger.info("Txn Req response: {}", scenarioScopeState.response); + } +} diff --git a/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/cucumber/stepdef/ChannelCollectionStepDef.java b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/cucumber/stepdef/ChannelCollectionStepDef.java new file mode 100644 index 000000000..9ba4fb840 --- /dev/null +++ b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/cucumber/stepdef/ChannelCollectionStepDef.java @@ -0,0 +1,81 @@ +package org.mifos.integrationtest.cucumber.stepdef; + +import static com.google.common.truth.Truth.assertThat; + +import com.google.gson.Gson; +import io.cucumber.java.en.And; +import io.cucumber.java.en.Then; +import io.cucumber.java.en.When; +import io.restassured.RestAssured; +import io.restassured.builder.ResponseSpecBuilder; +import io.restassured.specification.RequestSpecification; +import java.util.UUID; +import org.json.JSONException; +import org.json.JSONObject; +import org.mifos.integrationtest.common.CollectionHelper; +import org.mifos.integrationtest.common.Utils; +import org.mifos.integrationtest.common.dto.CollectionResponse; +import org.mifos.integrationtest.common.dto.operationsapp.GetTransactionRequestResponse; +import org.springframework.beans.factory.annotation.Autowired; + +public class ChannelCollectionStepDef extends BaseStepDef { + + @Autowired + ScenarioScopeState scenarioScopeState; + + @And("I have the request body with payer ams identifier keys as {string} and {string}") + public void iHaveRequestBody(String key1, String key2) throws JSONException { + JSONObject collectionRequestBody = CollectionHelper.getCollectionRequestBody(key1, key2); + scenarioScopeState.requestBody = collectionRequestBody; + logger.info(String.valueOf(scenarioScopeState.requestBody)); + } + + @When("I call the channel collection API with client correlation id and expected status of {int}") + public void iCallChannelCollectionAPI(int expectedStatus) { + RequestSpecification requestSpec = Utils.getDefaultSpec(scenarioScopeState.tenant); + requestSpec.header(Utils.X_CORRELATIONID, UUID.randomUUID()); + scenarioScopeState.response = RestAssured.given(requestSpec).baseUri(channelConnectorConfig.channelConnectorContactPoint) + // BaseStepDef.response = RestAssured.given(requestSpec).baseUri("https://localhost:8443") + .body(scenarioScopeState.requestBody.toString()).expect() + .spec(new ResponseSpecBuilder().expectStatusCode(expectedStatus).build()).when() + .post(channelConnectorConfig.collectionEndpoint).andReturn().asString(); + } + + @Then("I should get transaction id in response") + public void iGetTransactionIdInResponse() { + CollectionResponse response = (new Gson()).fromJson(scenarioScopeState.response, CollectionResponse.class); + scenarioScopeState.transactionId = response.getTransactionId(); + assertThat(response.getTransactionId()).isNotNull(); + } + + @Then("I should get transactionId with null value in response") + public void iGetErrorInResponse() { + CollectionResponse response = (new Gson()).fromJson(scenarioScopeState.response, CollectionResponse.class); + assertThat(response.getTransactionId()).isNull(); + } + + @When("I call the get txn API in ops app with transactionId as parameter") + public void iCallTheTxnAPIWithTransactionId() throws InterruptedException { + RequestSpecification requestSpec = Utils.getDefaultSpec(scenarioScopeState.tenant); + if (authEnabled) { + requestSpec.header("Authorization", "Bearer " + scenarioScopeState.accessToken); + } + requestSpec.queryParam("transactionId", scenarioScopeState.transactionId); + + scenarioScopeState.response = RestAssured.given(requestSpec).baseUri(operationsAppConfig.operationAppContactPoint).expect() + .spec(new ResponseSpecBuilder().expectStatusCode(200).build()).when().get(operationsAppConfig.transactionRequestsEndpoint) + .andReturn().asString(); + + logger.info("GetTxn Request Response: " + scenarioScopeState.response); + } + + @Then("I should get transaction state as completed and externalId not null") + public void assertValues() { + GetTransactionRequestResponse transactionRequestResponse = (new Gson()).fromJson(scenarioScopeState.response, + GetTransactionRequestResponse.class); + assertThat(transactionRequestResponse.getContent().size()).isEqualTo(1); + assertThat(transactionRequestResponse.getContent().get(0).getState()).isAnyOf("ACCEPTED", "FAILED"); + assertThat(transactionRequestResponse.getContent().get(0).getExternalId()).isNotNull(); + } + +} diff --git a/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/cucumber/stepdef/ContextStepDef.java b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/cucumber/stepdef/ContextStepDef.java new file mode 100644 index 000000000..6e9a18d12 --- /dev/null +++ b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/cucumber/stepdef/ContextStepDef.java @@ -0,0 +1,25 @@ +package org.mifos.integrationtest.cucumber.stepdef; + +import static com.google.common.truth.Truth.assertThat; + +import io.cucumber.java.en.Given; +import io.cucumber.java.en.Then; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; + +public class ContextStepDef extends BaseStepDef { + + @Autowired + private ApplicationContext applicationContext; + + @Given("I can autowire the object mapper bean") + public void checkIfObjectMapperIsInjected() { + assertThat(objectMapper).isNotNull(); + } + + @Then("Application context should be not null") + public void checkIfApplicationContextIsStarted() { + assertThat(this.applicationContext).isNotNull(); + } + +} diff --git a/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/cucumber/stepdef/ErrorCodeStepDef.java b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/cucumber/stepdef/ErrorCodeStepDef.java new file mode 100644 index 000000000..b33f8d4c6 --- /dev/null +++ b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/cucumber/stepdef/ErrorCodeStepDef.java @@ -0,0 +1,421 @@ +package org.mifos.integrationtest.cucumber.stepdef; + +import static com.google.common.truth.Truth.assertThat; +import static java.util.concurrent.TimeUnit.MILLISECONDS; +import static java.util.concurrent.TimeUnit.SECONDS; +import static org.awaitility.Awaitility.await; + +import io.cucumber.core.internal.com.fasterxml.jackson.core.JsonProcessingException; +import io.cucumber.core.internal.com.fasterxml.jackson.databind.JsonMappingException; +import io.cucumber.java.en.And; +import io.cucumber.java.en.Given; +import io.cucumber.java.en.Then; +import io.cucumber.java.en.When; +import io.restassured.RestAssured; +import io.restassured.builder.ResponseSpecBuilder; +import io.restassured.specification.RequestSpecification; +import org.apache.commons.lang3.StringEscapeUtils; +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; +import org.mifos.connector.common.channel.dto.PhErrorDTO; +import org.mifos.connector.common.channel.dto.TransactionChannelRequestDTO; +import org.mifos.connector.common.gsma.dto.Fee; +import org.mifos.connector.common.gsma.dto.GSMATransaction; +import org.mifos.connector.common.gsma.dto.GsmaParty; +import org.mifos.connector.common.gsma.dto.IdDocument; +import org.mifos.connector.common.gsma.dto.InternationalTransferInformation; +import org.mifos.connector.common.gsma.dto.Kyc; +import org.mifos.connector.common.gsma.dto.PostalAddress; +import org.mifos.connector.common.gsma.dto.SubjectName; +import org.mifos.integrationtest.common.GSMATransferHelper; +import org.mifos.integrationtest.common.Utils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; + +public class ErrorCodeStepDef extends BaseStepDef { + + @Value("${max-retry-count}") + private int maxRetryCount; + @Value("${retry-interval}") + private int retryInterval; + public static TransactionChannelRequestDTO mockTransactionChannelRequestDTO = null; + public String transactionId; + public static String randomTransactionId; + public static GSMATransaction gsmaTransaction = null; + public static PhErrorDTO errorInformation = null; + + @Autowired + GSMATransferStepDef gsmaTransferStepDef; + + @When("I call the GSMATransfer endpoint with expected status of {int}") + public void iCallTheGSMATransferEndpointWithExpectedStatusOf(int expectedStatus) { + RequestSpecification requestSpec = Utils.getDefaultSpec(scenarioScopeState.tenant); + logger.info("body: {}", gsmaTransaction.toString()); + logger.info("url: {}", channelConnectorConfig.gsmaP2PEndpoint); + scenarioScopeState.response = RestAssured.given(requestSpec).baseUri(channelConnectorConfig.channelConnectorContactPoint) + .body(gsmaTransaction).expect().spec(new ResponseSpecBuilder().expectStatusCode(expectedStatus).build()).when() + .post(channelConnectorConfig.gsmaP2PEndpoint).andReturn().asString(); + + logger.info("GSMA transfer Response: {}", scenarioScopeState.response); + } + + @When("I call the GSMATransfer Deposit endpoint with expected status of {int}") + public void iCallTheGSMATransferDepositEndpointWithExpectedStatusOf(int expectedStatus) { + RequestSpecification requestSpec = Utils.getDefaultSpec(scenarioScopeState.tenant); + logger.info("body: {}", gsmaTransaction.toString()); + logger.info("url: {}", channelConnectorConfig.gsmaP2PEndpoint); + scenarioScopeState.response = RestAssured.given(requestSpec).baseUri(channelConnectorConfig.channelConnectorContactPoint) + .body(gsmaTransaction).expect().spec(new ResponseSpecBuilder().expectStatusCode(expectedStatus).build()).when() + .post(channelConnectorConfig.gsmaP2PDepositEndpoint).andReturn().asString(); + + logger.info("GSMA transfer Response: {}", scenarioScopeState.response); + } + + @When("I call the transfer query endpoint with transactionId and expected status of {int}") + public void iCallTheTransferQueryEndpointWithTransactionIdAndExpectedStatusOf(int expectedStatus) { + RequestSpecification requestSpec = Utils.getDefaultSpec(scenarioScopeState.tenant); + String endPoint = operationsAppConfig.transfersEndpoint; + if (authEnabled) { + requestSpec.header("Authorization", "Bearer " + scenarioScopeState.accessToken); + } + requestSpec.queryParam("transactionId", transactionId); + logger.info("Transfer query Response: {}", endPoint); + logger.info("TxnId : {}", transactionId); + scenarioScopeState.response = RestAssured.given(requestSpec).baseUri(operationsAppConfig.operationAppContactPoint).expect() + .spec(new ResponseSpecBuilder().expectStatusCode(expectedStatus).build()).when().get(endPoint).andReturn().asString(); + + logger.info("Transfer query Response: {}", scenarioScopeState.response); + } + + @Then("I should poll the transfer query endpoint with transactionId until errorInformation is populated for the transactionId") + public void iShouldPollTheTransferQueryEndpointWithTransactionIdUntilErrorInformationIsPopulatedForTheTransactionId() { + RequestSpecification requestSpec = Utils.getDefaultSpec(scenarioScopeState.tenant); + String endPoint = operationsAppConfig.transfersEndpoint; + // requestSpec.header("Authorization", "Bearer " + BaseStepDef.accessToken); + requestSpec.queryParam("size", 10); + requestSpec.queryParam("page", 0); + requestSpec.queryParam("transactionId", transactionId); + logger.info("Transfer query Response: {}", endPoint); + logger.info("TxnId : {}", transactionId); + int retryCount = 0; + errorInformation = null; + while (errorInformation == null && retryCount < maxRetryCount) { + try { + iWillSleepForSecs(retryInterval); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + scenarioScopeState.response = RestAssured.given(requestSpec).baseUri(operationsAppConfig.operationAppContactPoint).expect() + .spec(new ResponseSpecBuilder().expectStatusCode(200).build()).when().get(endPoint).andReturn().asString(); + + logger.info("Transfer query Response: {}", scenarioScopeState.response); + checkForCallback(); + retryCount++; + } + } + + public void iWillSleepForSecs(int time) throws InterruptedException { + await().atMost(time, MILLISECONDS).pollInterval(pollInterval, SECONDS).until(() -> true); + } + + @And("I should be able to parse transactionId from response") + public void parseTransactionId() { + try { + JSONObject jsonObject = new JSONObject(scenarioScopeState.response); + transactionId = jsonObject.getString("transactionId"); + logger.info("Inbound transfer Id: {}", transactionId); + } catch (JSONException e) { + logger.error("Error parsing the transaction id from response", e); + assertThat(false).isTrue(); + return; + } + assertThat(transactionId).isNotNull(); + assertThat(transactionId).isNotEmpty(); + } + + public void checkForCallback() { + String responseError; + try { + JSONObject jsonObject = new JSONObject(scenarioScopeState.response); + JSONArray content = jsonObject.getJSONArray("content"); + if (content.getJSONObject(0).has("errorInformation")) { + responseError = content.getJSONObject(0).getString("errorInformation"); + errorInformation = objectMapper.readValue(StringEscapeUtils.unescapeJava(responseError), PhErrorDTO.class); + } + } catch (JsonMappingException e) { + throw new RuntimeException(e); + } catch (JSONException e) { + throw new RuntimeException(e); + } catch (JsonProcessingException e) { + throw new RuntimeException(e); + } + } + + @And("I should be able to parse {string} Error Code from response") + public void iShouldBeAbleToParseErrorCodeFromResponse(String errorCode) { + + assertThat(errorInformation.getErrorCode()).isNotNull(); + assertThat(errorInformation.getErrorCode()).matches(errorCode); + } + + @And("I should be able to parse {string} Error Code from GSMA Transfer response") + public void iShouldBeAbleToParseErrorCodeFromGSMATransferResponse(String errorCode) { + PhErrorDTO errorInformation; + try { + JSONObject jsonObject = new JSONObject(scenarioScopeState.response); + errorInformation = objectMapper.readValue(jsonObject.toString(), PhErrorDTO.class); + + } catch (JSONException | JsonProcessingException e) { + throw new RuntimeException(e); + } + assertThat(errorInformation.getErrorCode()).isNotNull(); + assertThat(errorInformation.getErrorCode()).matches(errorCode); + } + + @Given("I can create GSMATransferDTO with missing currency details") + public void iCanCreateGSMATransactionDTOWithMissingCurrency() { + GSMATransferHelper gsmaTransferHelper = new GSMATransferHelper(); + Fee fee = gsmaTransferHelper.feeHelper("11", "USD", "string"); + GsmaParty debitParty = gsmaTransferHelper.gsmaPartyHelper("msisdn", "449999999"); + GsmaParty creditParty = gsmaTransferHelper.gsmaPartyHelper("msisdn", "+449999112"); + InternationalTransferInformation internationalTransferInformation = gsmaTransferHelper + .internationalTransferInformationHelper("string", "string", "directtoaccount", "USA", "USA", "USA", "USA"); + IdDocument idDocument = gsmaTransferHelper.idDocumentHelper("passport", "string", "USA", "2022-09-28T12:51:19.260+00:00", + "2022-09-28T12:51:19.260+00:00", "string", "string"); + PostalAddress postalAddress = gsmaTransferHelper.postalAddressHelper("string", "string", "string", "string", "USA", "string", + "string"); + SubjectName subjectName = gsmaTransferHelper.subjectNameHelper("string", "string", "string", "string", "string"); + Kyc senderKyc = gsmaTransferHelper.kycHelper("USA", "2000-11-20", "string", "string", "string", 'm', idDocument, "USA", "string", + postalAddress, subjectName); + Kyc receiverKyc = gsmaTransferHelper.kycHelper("USA", "2000-11-20", "string", "string", "string", 'm', idDocument, "USA", "string", + postalAddress, subjectName); + try { + gsmaTransaction = gsmaTransferHelper.gsmaTransactionRequestBodyHelper("11", debitParty, creditParty, "", "string", "string", + "string", "transfer", "string", fee, "37.423825,-122.082900", internationalTransferInformation, "string", receiverKyc, + senderKyc, "string", "2023-01-12T12:51:19.260+00:00"); + } catch (JSONException e) { + throw new RuntimeException(e); + } + } + + @Given("I can create GSMATransferDTO with same payer and payee") + public void iCanCreateGSMATransactionDTOWithSamePayerAndPayee() { + GSMATransferHelper gsmaTransferHelper = new GSMATransferHelper(); + Fee fee = gsmaTransferHelper.feeHelper("11", "USD", "string"); + GsmaParty debitParty = gsmaTransferHelper.gsmaPartyHelper("msisdn", "+449999112"); + GsmaParty creditParty = gsmaTransferHelper.gsmaPartyHelper("msisdn", "+449999112"); + InternationalTransferInformation internationalTransferInformation = gsmaTransferHelper + .internationalTransferInformationHelper("string", "string", "directtoaccount", "USA", "USA", "USA", "USA"); + IdDocument idDocument = gsmaTransferHelper.idDocumentHelper("passport", "string", "USA", "2022-09-28T12:51:19.260+00:00", + "2022-09-28T12:51:19.260+00:00", "string", "string"); + PostalAddress postalAddress = gsmaTransferHelper.postalAddressHelper("string", "string", "string", "string", "USA", "string", + "string"); + SubjectName subjectName = gsmaTransferHelper.subjectNameHelper("string", "string", "string", "string", "string"); + Kyc senderKyc = gsmaTransferHelper.kycHelper("USA", "2000-11-20", "string", "string", "string", 'm', idDocument, "USA", "string", + postalAddress, subjectName); + Kyc receiverKyc = gsmaTransferHelper.kycHelper("USA", "2000-11-20", "string", "string", "string", 'm', idDocument, "USA", "string", + postalAddress, subjectName); + try { + gsmaTransaction = gsmaTransferHelper.gsmaTransactionRequestBodyHelper("11", debitParty, creditParty, "USD", "string", "string", + "string", "transfer", "string", fee, "37.423825,-122.082900", internationalTransferInformation, "string", receiverKyc, + senderKyc, "string", "2023-01-12T12:51:19.260+00:00"); + } catch (JSONException e) { + throw new RuntimeException(e); + } + } + + @Given("I can create GSMATransferDTO with Negative Amount") + public void iCanCreateGSMATransactionDTOWithNegativeAmount() { + GSMATransferHelper gsmaTransferHelper = new GSMATransferHelper(); + Fee fee = gsmaTransferHelper.feeHelper("11", "USD", "string"); + GsmaParty debitParty = gsmaTransferHelper.gsmaPartyHelper("msisdn", "+449999999"); + GsmaParty creditParty = gsmaTransferHelper.gsmaPartyHelper("msisdn", "+449999112"); + InternationalTransferInformation internationalTransferInformation = gsmaTransferHelper + .internationalTransferInformationHelper("string", "string", "directtoaccount", "USA", "USA", "USA", "USA"); + IdDocument idDocument = gsmaTransferHelper.idDocumentHelper("passport", "string", "USA", "2022-09-28T12:51:19.260+00:00", + "2022-09-28T12:51:19.260+00:00", "string", "string"); + PostalAddress postalAddress = gsmaTransferHelper.postalAddressHelper("string", "string", "string", "string", "USA", "string", + "string"); + SubjectName subjectName = gsmaTransferHelper.subjectNameHelper("string", "string", "string", "string", "string"); + Kyc senderKyc = gsmaTransferHelper.kycHelper("USA", "2000-11-20", "string", "string", "string", 'm', idDocument, "USA", "string", + postalAddress, subjectName); + Kyc receiverKyc = gsmaTransferHelper.kycHelper("USA", "2000-11-20", "string", "string", "string", 'm', idDocument, "USA", "string", + postalAddress, subjectName); + try { + gsmaTransaction = gsmaTransferHelper.gsmaTransactionRequestBodyHelper("-11", debitParty, creditParty, "USD", "string", "string", + "string", "transfer", "string", fee, "37.423825,-122.082900", internationalTransferInformation, "string", receiverKyc, + senderKyc, "string", "2023-01-12T12:51:19.260+00:00"); + } catch (JSONException e) { + throw new RuntimeException(e); + } + + } + + @Given("I can create GSMATransferDTO with invalid amount format") + public void iCanCreateGSMATransactionDTOWithInvalidAmountFormat() { + GSMATransferHelper gsmaTransferHelper = new GSMATransferHelper(); + Fee fee = gsmaTransferHelper.feeHelper("11", "USD", "string"); + GsmaParty debitParty = gsmaTransferHelper.gsmaPartyHelper("msisdn", "449999999"); + GsmaParty creditParty = gsmaTransferHelper.gsmaPartyHelper("msisdn", "+449999112"); + InternationalTransferInformation internationalTransferInformation = gsmaTransferHelper + .internationalTransferInformationHelper("string", "string", "directtoaccount", "USA", "USA", "USA", "USA"); + IdDocument idDocument = gsmaTransferHelper.idDocumentHelper("passport", "string", "USA", "2022-09-28T12:51:19.260+00:00", + "2022-09-28T12:51:19.260+00:00", "string", "string"); + PostalAddress postalAddress = gsmaTransferHelper.postalAddressHelper("string", "string", "string", "string", "USA", "string", + "string"); + SubjectName subjectName = gsmaTransferHelper.subjectNameHelper("string", "string", "string", "string", "string"); + Kyc senderKyc = gsmaTransferHelper.kycHelper("USA", "2000-11-20", "string", "string", "string", 'm', idDocument, "USA", "string", + postalAddress, subjectName); + Kyc receiverKyc = gsmaTransferHelper.kycHelper("USA", "2000-11-20", "string", "string", "string", 'm', idDocument, "USA", "string", + postalAddress, subjectName); + try { + gsmaTransaction = gsmaTransferHelper.gsmaTransactionRequestBodyHelper("ab", debitParty, creditParty, "USD", "string", "string", + "string", "transfer", "string", fee, "37.423825,-122.082900", internationalTransferInformation, "string", receiverKyc, + senderKyc, "string", "2023-01-12T12:51:19.260+00:00"); + } catch (JSONException e) { + throw new RuntimeException(e); + } + } + + @Given("I can create GSMATransferDTO with incorrect Payer") + public void iCanCreateGSMATransferDTOWithIncorrectPayerHelper() { + GSMATransferHelper gsmaTransferHelper = new GSMATransferHelper(); + Fee fee = gsmaTransferHelper.feeHelper("11", "USD", "string"); + GsmaParty debitParty = gsmaTransferHelper.gsmaPartyHelper("msisdn", "449999"); + GsmaParty creditParty = gsmaTransferHelper.gsmaPartyHelper("msisdn", "835322416"); + InternationalTransferInformation internationalTransferInformation = gsmaTransferHelper + .internationalTransferInformationHelper("string", "string", "directtoaccount", "USA", "USA", "USA", "USA"); + IdDocument idDocument = gsmaTransferHelper.idDocumentHelper("passport", "string", "USA", "2022-09-28T12:51:19.260+00:00", + "2022-09-28T12:51:19.260+00:00", "string", "string"); + PostalAddress postalAddress = gsmaTransferHelper.postalAddressHelper("string", "string", "string", "string", "USA", "string", + "string"); + SubjectName subjectName = gsmaTransferHelper.subjectNameHelper("string", "string", "string", "string", "string"); + Kyc senderKyc = gsmaTransferHelper.kycHelper("USA", "2000-11-20", "string", "string", "string", 'm', idDocument, "USA", "string", + postalAddress, subjectName); + Kyc receiverKyc = gsmaTransferHelper.kycHelper("USA", "2000-11-20", "string", "string", "string", 'm', idDocument, "USA", "string", + postalAddress, subjectName); + try { + gsmaTransaction = gsmaTransferHelper.gsmaTransactionRequestBodyHelper("11", debitParty, creditParty, "USD", "string", "string", + "string", "transfer", "string", fee, "37.423825,-122.082900", internationalTransferInformation, "string", receiverKyc, + senderKyc, "string", "2023-01-12T12:51:19.260+00:00"); + } catch (JSONException e) { + throw new RuntimeException(e); + } + } + + @Given("I can create GSMATransferDTO with Payer Insufficient Balance") + public void iCanCreateGSMATransferDTOWithPayerInsufficientBalance() { + GSMATransferHelper gsmaTransferHelper = new GSMATransferHelper(); + Fee fee = gsmaTransferHelper.feeHelper("110", "USD", "string"); + GsmaParty debitParty = gsmaTransferHelper.gsmaPartyHelper("msisdn", "835322416"); + GsmaParty creditParty = gsmaTransferHelper.gsmaPartyHelper("msisdn", "398714218"); + InternationalTransferInformation internationalTransferInformation = gsmaTransferHelper + .internationalTransferInformationHelper("string", "string", "directtoaccount", "USA", "USA", "USA", "USA"); + IdDocument idDocument = gsmaTransferHelper.idDocumentHelper("passport", "string", "USA", "2022-09-28T12:51:19.260+00:00", + "2022-09-28T12:51:19.260+00:00", "string", "string"); + PostalAddress postalAddress = gsmaTransferHelper.postalAddressHelper("string", "string", "string", "string", "USA", "string", + "string"); + SubjectName subjectName = gsmaTransferHelper.subjectNameHelper("string", "string", "string", "string", "string"); + Kyc senderKyc = gsmaTransferHelper.kycHelper("USA", "2000-11-20", "string", "string", "string", 'm', idDocument, "USA", "string", + postalAddress, subjectName); + Kyc receiverKyc = gsmaTransferHelper.kycHelper("USA", "2000-11-20", "string", "string", "string", 'm', idDocument, "USA", "string", + postalAddress, subjectName); + try { + gsmaTransaction = gsmaTransferHelper.gsmaTransactionRequestBodyHelper("11000", debitParty, creditParty, "USD", "string", + "string", "string", "transfer", "string", fee, "37.423825,-122.082900", internationalTransferInformation, "string", + receiverKyc, senderKyc, "string", "2023-01-12T12:51:19.260+00:00"); + } catch (JSONException e) { + throw new RuntimeException(e); + } + } + + @Given("I can create GSMATransferDTO with invalid payer information") + public void iCanCreateGSMATransferDTOWithInvalidData() { + GSMATransferHelper gsmaTransferHelper = new GSMATransferHelper(); + Fee fee = gsmaTransferHelper.feeHelper("11", "USD", "string"); + GsmaParty debitParty = gsmaTransferHelper.gsmaPartyHelper("msisdn", "449999hhhhdsda"); + GsmaParty creditParty = gsmaTransferHelper.gsmaPartyHelper("msisdn", "835322416ffgg"); + InternationalTransferInformation internationalTransferInformation = gsmaTransferHelper + .internationalTransferInformationHelper("string", "string", "directtoaccount", "USA", "USA", "USA", "USA"); + IdDocument idDocument = gsmaTransferHelper.idDocumentHelper("passport", "string", "USA", "2022-09-28T12:51:19.260+00:00", + "2022-09-28T12:51:19.260+00:00", "string", "string"); + PostalAddress postalAddress = gsmaTransferHelper.postalAddressHelper("string", "string", "string", "string", "USA", "string", + "string"); + SubjectName subjectName = gsmaTransferHelper.subjectNameHelper("string", "string", "string", "string", "string"); + Kyc senderKyc = gsmaTransferHelper.kycHelper("USA", "2000-11-20", "string", "string", "string", 'm', idDocument, "USA", "string", + postalAddress, subjectName); + Kyc receiverKyc = gsmaTransferHelper.kycHelper("USA", "2000-11-20", "string", "string", "string", 'm', idDocument, "USA", "string", + postalAddress, subjectName); + try { + gsmaTransaction = gsmaTransferHelper.gsmaTransactionRequestBodyHelper("11", debitParty, creditParty, "USD", "string", "string", + "string", "transfer", "string", fee, "37.423825,-122.082900", internationalTransferInformation, "string", receiverKyc, + senderKyc, "string", "2023-01-12T12:51:19.260+00:00"); + } catch (JSONException e) { + throw new RuntimeException(e); + } + } + + @Then("I should poll the transfer query endpoint with transactionId until status is populated for the transactionId") + public void iShouldPollTheTransferQueryEndpointWithTransactionIdUntilStatusIsPopulatedForTheTransactionId() { + await().atMost(awaitMost, SECONDS).pollDelay(pollDelay, SECONDS).pollInterval(pollInterval, SECONDS).untilAsserted(() -> { + RequestSpecification requestSpec = Utils.getDefaultSpec(scenarioScopeState.tenant); + String endPoint = operationsAppConfig.transfersEndpoint; + if (authEnabled) { + requestSpec.header("Authorization", "Bearer " + scenarioScopeState.accessToken); + } + requestSpec.queryParam("transactionId", transactionId); + logger.info("Endpoint: {}", endPoint); + logger.info("TxnId : {}", transactionId); + + scenarioScopeState.response = RestAssured.given(requestSpec).baseUri(operationsAppConfig.operationAppContactPoint).expect() + .spec(new ResponseSpecBuilder().expectStatusCode(200).build()).when().get(endPoint).andReturn().asString(); + logger.info("Transfer query Response: {}", scenarioScopeState.response); + assertThat(scenarioScopeState.response).isNotNull(); + String status = checkForStatus(); + logger.info("Status: {}", status); + assertThat(status).isNotNull(); + }); + } + + @When("I can create GSMATransferDTO with different payer and payee") + public void iCanCreateGSMATransactionDTOWithDifferentPayerAndPayee() { + GSMATransferHelper gsmaTransferHelper = new GSMATransferHelper(); + Fee fee = gsmaTransferHelper.feeHelper("11", "USD", "string"); + GsmaParty debit = gsmaTransferHelper.gsmaPartyHelper("msisdn", scenarioScopeState.debitParty); + GsmaParty credit = gsmaTransferHelper.gsmaPartyHelper("msisdn", scenarioScopeState.creditParty); + InternationalTransferInformation internationalTransferInformation = gsmaTransferHelper + .internationalTransferInformationHelper("string", "string", "directtoaccount", "USA", "USA", "USA", "USA"); + IdDocument idDocument = gsmaTransferHelper.idDocumentHelper("passport", "string", "USA", "2022-09-28T12:51:19.260+00:00", + "2022-09-28T12:51:19.260+00:00", "string", "string"); + PostalAddress postalAddress = gsmaTransferHelper.postalAddressHelper("string", "string", "string", "string", "USA", "string", + "string"); + SubjectName subjectName = gsmaTransferHelper.subjectNameHelper("string", "string", "string", "string", "string"); + Kyc senderKyc = gsmaTransferHelper.kycHelper("USA", "2000-11-20", "string", "string", "string", 'm', idDocument, "USA", "string", + postalAddress, subjectName); + Kyc receiverKyc = gsmaTransferHelper.kycHelper("USA", "2000-11-20", "string", "string", "string", 'm', idDocument, "USA", "string", + postalAddress, subjectName); + scenarioScopeState.gsmaP2PAmtDebit = 11; + try { + ErrorCodeStepDef.gsmaTransaction = gsmaTransferHelper.gsmaTransactionRequestBodyHelper("11", debit, credit, "USD", "string", + "string", "string", "transfer", "string", fee, "37.423825,-122.082900", internationalTransferInformation, "string", + receiverKyc, senderKyc, "string", "2023-01-12T12:51:19.260+00:00"); + } catch (JSONException e) { + throw new RuntimeException(e); + } + } + + public String checkForStatus() { + String status = null; + try { + JSONObject jsonObject = new JSONObject(scenarioScopeState.response); + JSONArray content = jsonObject.getJSONArray("content"); + if (content.getJSONObject(0).has("status")) { + status = content.getJSONObject(0).getString("errorInformation"); + } + } catch (JSONException e) { + throw new RuntimeException(e); + } + return status; + } +} diff --git a/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/cucumber/stepdef/GSMATransferDef.java b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/cucumber/stepdef/GSMATransferDef.java new file mode 100644 index 000000000..d933124c1 --- /dev/null +++ b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/cucumber/stepdef/GSMATransferDef.java @@ -0,0 +1,383 @@ +package org.mifos.integrationtest.cucumber.stepdef; + +import io.cucumber.core.internal.com.fasterxml.jackson.core.JsonProcessingException; +import io.cucumber.core.internal.com.fasterxml.jackson.databind.ObjectMapper; +import io.restassured.RestAssured; +import io.restassured.builder.ResponseSpecBuilder; +import io.restassured.specification.RequestSpecification; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Date; +import java.util.UUID; +import org.apache.fineract.client.models.InteropIdentifierRequestData; +import org.apache.fineract.client.models.PostClientsRequest; +import org.apache.fineract.client.models.PostClientsResponse; +import org.apache.fineract.client.models.PostLoanProductsRequest; +import org.apache.fineract.client.models.PostLoanProductsResponse; +import org.apache.fineract.client.models.PostLoansLoanIdTransactionsTransactionIdRequest; +import org.apache.fineract.client.models.PostRecurringDepositAccountsRecurringDepositAccountIdTransactionsRequest; +import org.apache.fineract.client.models.PostSavingsAccountsAccountIdRequest; +import org.apache.fineract.client.models.PostSavingsAccountsRequest; +import org.apache.fineract.client.models.PostSavingsAccountsResponse; +import org.apache.fineract.client.models.PostSavingsProductsRequest; +import org.apache.fineract.client.models.PostSavingsProductsResponse; +import org.apache.fineract.client.models.PostSelfLoansLoanIdApprove; +import org.apache.fineract.client.models.PostSelfLoansLoanIdDisburse; +import org.apache.fineract.client.models.PostSelfLoansLoanIdResponse; +import org.apache.fineract.client.models.PostSelfLoansRequest; +import org.json.JSONException; +import org.json.JSONObject; +import org.mifos.connector.common.gsma.dto.CustomData; +import org.mifos.connector.common.gsma.dto.GsmaTransfer; +import org.mifos.connector.common.gsma.dto.Party; +import org.mifos.integrationtest.common.Utils; +import org.mifos.integrationtest.config.GsmaConfig; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +@Component +public class GSMATransferDef extends GsmaConfig { + + public String gsmaTransferBody; + public String loanProductBody; + public String amsName; + public int amount; + public String accountId; + public String acccountHoldingInstitutionId; + public String gsmaTransactionResponse; + public String responseLoanProduct; + public String tenant; + public String currentDate; + protected String loanAccountBody; + protected String responseLoanAccount; + protected String loanApproveBody; + protected String responseLoanApprove; + protected String loanRepaymentBody; + protected String responseLoanRepayment; + protected String savingsProductBody; + protected String responseSavingsProduct; + protected String savingsApproveBody; + protected String responseSavingsApprove; + protected String savingsAccountBody; + protected String interopIdentifierBody; + protected String responseSavingsAccount; + protected String responseInteropIdentifier; + protected String savingsActivateBody; + protected String responseSavingsActivate; + protected String savingsDepositAccountBody; + protected String responseSavingsDepositAccount; + protected String createPayerClientBody; + protected String responsePayerClient; + protected String payerClientBody; + protected String loanDisburseBody; + protected String responseLoanDisburse; + protected String externalId; + @Autowired + ObjectMapper objectMapper; + + @Value("${defaults.authorization}") + public String authorizationToken; + + Logger logger = LoggerFactory.getLogger(this.getClass()); + + public void setAccountId(String acId) { + accountId = acId; + } + + public void setHeadersMifos(String ams, String aHIId, int amnt) { + amsName = ams; + acccountHoldingInstitutionId = aHIId; + amount = amnt; + } + + protected void setTenant(String tenantName) { + tenant = tenantName; + } + + protected void setcurrentDate(String date) { + currentDate = date; + } + + protected RequestSpecification setHeaders(RequestSpecification requestSpec) { + requestSpec.header("Fineract-Platform-TenantId", tenant); + requestSpec.header("Authorization", authorizationToken); + requestSpec.header("Content-Type", "application/json;charset=UTF-8"); + return requestSpec; + } + + protected String setBodyLoanProduct() throws JsonProcessingException { + // Generating product name and shortname + String name = new StringBuilder().append(getAlphaNumericString(4)).append(tenant).toString(); + String shortName = getAlphaNumericString(4); + PostLoanProductsRequest loanProductsRequest = new PostLoanProductsRequest(); + loanProductsRequest.setCurrencyCode("USD"); + loanProductsRequest.setInMultiplesOf(2); + loanProductsRequest.setDigitsAfterDecimal(2); + loanProductsRequest.setDaysInYearType(1); + loanProductsRequest.setInterestCalculationPeriodType(0); + loanProductsRequest.setIsInterestRecalculationEnabled(false); + loanProductsRequest.setName(name); + loanProductsRequest.setShortName(shortName); + loanProductsRequest.setInMultiplesOf(12); + loanProductsRequest.setPrincipal((double) 3000); + loanProductsRequest.setNumberOfRepayments(36); + loanProductsRequest.setRepaymentFrequencyType(2); + loanProductsRequest.setInterestType(1); + loanProductsRequest.setInterestRatePerPeriod(19.0); + loanProductsRequest.setRepaymentEvery(1); + loanProductsRequest.setTransactionProcessingStrategyCode("mifos-standard-strategy"); + loanProductsRequest.setAmortizationType(1); + loanProductsRequest.setAccountingRule(1); + loanProductsRequest.setInterestRateFrequencyType(2); + loanProductsRequest.setDaysInMonthType(1); + loanProductsRequest.setLocale("en"); + loanProductsRequest.setDateFormat("dd MMMM yyyy"); + + return objectMapper.writeValueAsString(loanProductsRequest); + } + + protected String setBodyLoanAccount() throws JsonProcessingException { + + String date = getCurrentDate(); + setcurrentDate(date); + PostClientsResponse createPayerClientResponse = objectMapper.readValue(responsePayerClient, PostClientsResponse.class); + PostLoanProductsResponse loanProductResponse = objectMapper.readValue(responseLoanProduct, PostLoanProductsResponse.class); + Integer clientId = createPayerClientResponse.getClientId(); + Integer resourceId = loanProductResponse.getResourceId(); + + PostSelfLoansRequest loanAccountData = new PostSelfLoansRequest(); + loanAccountData.setClientId(clientId); + loanAccountData.setProductId(resourceId); + loanAccountData.setDisbursementData(null); + loanAccountData.setPrincipal(7800.00); + loanAccountData.setLoanTermFrequency(12); + loanAccountData.setLoanTermFrequencyType(2); + loanAccountData.setNumberOfRepayments(12); + loanAccountData.setRepaymentEvery(1); + loanAccountData.setRepaymentFrequencyType(2); + loanAccountData.setInterestRatePerPeriod(8.9); + loanAccountData.setAmortizationType(1); + loanAccountData.setInterestType(0); + loanAccountData.setInterestCalculationPeriodType(0); + loanAccountData.setTransactionProcessingStrategyCode("mifos-standard-strategy"); + loanAccountData.setLocale("en"); + loanAccountData.setDateFormat("dd MMMM yyyy"); + loanAccountData.setLoanType("individual"); + loanAccountData.setExpectedDisbursementDate(currentDate); + loanAccountData.setSubmittedOnDate(currentDate); + return objectMapper.writeValueAsString(loanAccountData); + } + + private String getCurrentDate() { + Date date = new Date(); + return new SimpleDateFormat("dd MMMM yyyy").format(date); + } + + protected String setBodyLoanApprove(int amount) throws JsonProcessingException { + PostSelfLoansLoanIdApprove loanApprove = new PostSelfLoansLoanIdApprove(); + loanApprove.setApprovedOnDate(currentDate); + loanApprove.setApprovedLoanAmount(amount); + loanApprove.setLocale("en"); + loanApprove.setDateFormat("dd MMMM yyyy"); + return objectMapper.writeValueAsString(loanApprove); + } + + protected String setBodyLoanRepayment(String amount) throws JsonProcessingException { + PostLoansLoanIdTransactionsTransactionIdRequest loanRepayment = new PostLoansLoanIdTransactionsTransactionIdRequest(); + loanRepayment.setTransactionDate(currentDate); + loanRepayment.setPaymentTypeId(1); + loanRepayment.setTransactionAmount(Double.valueOf(amount)); + loanRepayment.setLocale("en"); + loanRepayment.setDateFormat("dd MMMM yyyy"); + return objectMapper.writeValueAsString(loanRepayment); + } + + String getAlphaNumericString(int size) { + String AlphaNumericString = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "0123456789" + "abcdefghijklmnopqrstuvxyz"; + StringBuilder sb = new StringBuilder(size); + for (int i = 0; i < size; i++) { + int index = (int) (AlphaNumericString.length() * Math.random()); + sb.append(AlphaNumericString.charAt(index)); + } + return sb.toString(); + } + + protected String setBodySavingsProduct() throws JsonProcessingException { + // Generating product name and shortname + String name = new StringBuilder().append(getAlphaNumericString(4)).toString(); + String shortName = getAlphaNumericString(4); + + PostSavingsProductsRequest savingsProductsRequest = new PostSavingsProductsRequest(); + savingsProductsRequest.setCurrencyCode("USD"); + savingsProductsRequest.setDigitsAfterDecimal(2); + savingsProductsRequest.setInterestCompoundingPeriodType(1); + savingsProductsRequest.setInterestPostingPeriodType(4); + savingsProductsRequest.setInterestCalculationType(1); + savingsProductsRequest.setInterestCalculationDaysInYearType(365); + savingsProductsRequest.setAccountingRule(1); + savingsProductsRequest.setName(name); + savingsProductsRequest.setShortName(shortName); + savingsProductsRequest.setInMultiplesOf(1); + savingsProductsRequest.setNominalAnnualInterestRate(5.0); + savingsProductsRequest.setLocale("en"); + + return objectMapper.writeValueAsString(savingsProductsRequest); + } + + protected String setBodySavingsApprove() throws JsonProcessingException { + PostSavingsAccountsAccountIdRequest savingsApprove = new PostSavingsAccountsAccountIdRequest(); + savingsApprove.setApprovedOnDate(currentDate); + savingsApprove.setLocale("en"); + savingsApprove.setDateFormat("dd MMMM yyyy"); + return objectMapper.writeValueAsString(savingsApprove); + } + + protected String setBodySavingsAccount() throws JsonProcessingException { + // Getting resourceId and clientId + PostClientsResponse createPayerClientResponse = objectMapper.readValue(responsePayerClient, PostClientsResponse.class); + PostSavingsProductsResponse savingsProductResponse = objectMapper.readValue(responseSavingsProduct, + PostSavingsProductsResponse.class); + String date = getCurrentDate(); + setcurrentDate(date); + externalId = UUID.randomUUID().toString(); + PostSavingsAccountsRequest savingsAccountsRequest = new PostSavingsAccountsRequest(); + savingsAccountsRequest.setClientId(createPayerClientResponse.getClientId()); + savingsAccountsRequest.setProductId(savingsProductResponse.getResourceId()); + savingsAccountsRequest.setDateFormat("dd MMMM yyyy"); + savingsAccountsRequest.setLocale("en"); + savingsAccountsRequest.setSubmittedOnDate(currentDate); + savingsAccountsRequest.setExternalId(externalId); + + return objectMapper.writeValueAsString(savingsAccountsRequest); + } + + protected String setBodyInteropIdentifier() throws JsonProcessingException { + PostSavingsAccountsResponse savingsAccountResponse = objectMapper.readValue(responseSavingsProduct, + PostSavingsAccountsResponse.class); + String date = getCurrentDate(); + setcurrentDate(date); + + InteropIdentifierRequestData interopIdentifier = new InteropIdentifierRequestData(); + interopIdentifier.setAccountId(externalId); + + return objectMapper.writeValueAsString(interopIdentifier); + } + + protected String setBodySavingsActivate() throws JsonProcessingException { + PostSavingsAccountsAccountIdRequest savingsActivate = new PostSavingsAccountsAccountIdRequest(); + savingsActivate.setActivatedOnDate(currentDate); + savingsActivate.setLocale("en"); + savingsActivate.setDateFormat("dd MMMM yyyy"); + return objectMapper.writeValueAsString(savingsActivate); + } + + protected String setSavingsDepositAccount(int amount) throws JsonProcessingException { + PostRecurringDepositAccountsRecurringDepositAccountIdTransactionsRequest savingsAccountDeposit = new PostRecurringDepositAccountsRecurringDepositAccountIdTransactionsRequest(); + savingsAccountDeposit.setLocale("en"); + savingsAccountDeposit.setDateFormat("dd MMMM yyyy"); + savingsAccountDeposit.setPaymentTypeId(1); + savingsAccountDeposit.setTransactionAmount((double) amount); + savingsAccountDeposit.setTransactionDate(currentDate); + + return objectMapper.writeValueAsString(savingsAccountDeposit); + } + + protected String setBodyPayerClient() throws JsonProcessingException { + String date = getCurrentDate(); + PostClientsRequest postClientsRequest = new PostClientsRequest(); + postClientsRequest.setOfficeId(1); + postClientsRequest.setLegalFormId(1); + postClientsRequest.setFirstname("John"); + postClientsRequest.setLastname("Wick"); + postClientsRequest.setActive(true); + postClientsRequest.setLocale("en"); + postClientsRequest.setDateFormat("dd MMMM yyyy"); + postClientsRequest.setActivationDate(date); + postClientsRequest.setSubmittedOnDate(date); + return objectMapper.writeValueAsString(postClientsRequest); + } + + protected String setBodyLoanDisburse(int amount) throws JsonProcessingException { + String date = getCurrentDate(); + setcurrentDate(date); + PostSelfLoansLoanIdDisburse loanDisburse = new PostSelfLoansLoanIdDisburse(); + loanDisburse.setPaymentTypeId(1); + loanDisburse.setTransactionAmount(amount); + loanDisburse.setActualDisbursementDate(currentDate); + loanDisburse.setLocale("en"); + loanDisburse.setDateFormat("dd MMMM yyyy"); + return objectMapper.writeValueAsString(loanDisburse); + } + + protected String setGsmaTransactionBody(String prefix) throws JsonProcessingException { + String accountId = getAccountId(prefix); + ArrayList customData = new ArrayList<>(); + CustomData customDataObj = new CustomData(); + customDataObj.setKey("key"); + customDataObj.setValue("value"); + customData.add(customDataObj); + + ArrayList payer = new ArrayList<>(); + Party payerObject = new Party(); + payerObject.setPartyIdType("MSISDN"); + payerObject.setPartyIdIdentifier("+44999911"); + payer.add(payerObject); + + ArrayList payee = new ArrayList<>(); + Party payeeObject = new Party(); + payeeObject.setPartyIdType("accountId"); + payeeObject.setPartyIdIdentifier(accountId); + payee.add(payeeObject); + + String dateFormatGiven = "yyyy-MM-dd'T'HH:mm:ss.SSSXXX"; + String currentDate = new SimpleDateFormat(dateFormatGiven).format(new Date()); + + GsmaTransfer gsmaTransfer = new GsmaTransfer("RKTQDM7W6S", "inbound", "transfer", Integer.toString(amount), "USD", "note", + currentDate, customData, payer, payee); + return objectMapper.writeValueAsString(gsmaTransfer); + } + + private String getAccountId(String prefix) throws JsonProcessingException { + String accountNumber = ""; + if (prefix.equalsIgnoreCase("S")) { + accountNumber = getSavingsAccountId(); + } else { + accountNumber = getLoanAccountId(); + } + String accountId = new StringBuilder().append(prefix).append(accountNumber).toString(); + return accountId; + } + + private String getSavingsAccountId() throws JsonProcessingException { + PostSavingsAccountsResponse savingsAccountResponse = objectMapper.readValue(responseSavingsAccount, + PostSavingsAccountsResponse.class); + return savingsAccountResponse.getSavingsId().toString(); + } + + private String getLoanAccountId() throws JsonProcessingException { + PostSelfLoansLoanIdResponse loanAccountResponse = objectMapper.readValue(responseLoanAccount, PostSelfLoansLoanIdResponse.class); + String loanId = loanAccountResponse.getLoanId().toString(); + return getLoanIdFromFineract(loanId); + } + + private String getLoanIdFromFineract(String loanId) { + RequestSpecification requestSpecification = Utils.getDefaultSpec(); + requestSpecification = setHeaders(requestSpecification); + loanGetAccountIdEndpoint = loanGetAccountIdEndpoint.replaceAll("\\{\\{loanAccId\\}\\}", loanId); + String response = RestAssured.given(requestSpecification).baseUri(loanBaseUrl).expect() + .spec(new ResponseSpecBuilder().expectStatusCode(200).build()).when().get(loanGetAccountIdEndpoint).andReturn().asString(); + String accountNp = ""; + + try { + JSONObject jsonResponse = new JSONObject(response); + accountNp = jsonResponse.getString("accountNo"); + } catch (JSONException e) { + throw new RuntimeException(e); + } + return accountNp; + + } +} diff --git a/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/cucumber/stepdef/GSMATransferStepDef.java b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/cucumber/stepdef/GSMATransferStepDef.java new file mode 100644 index 000000000..3b0c2a380 --- /dev/null +++ b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/cucumber/stepdef/GSMATransferStepDef.java @@ -0,0 +1,909 @@ +package org.mifos.integrationtest.cucumber.stepdef; + +import static com.github.tomakehurst.wiremock.client.WireMock.getAllServeEvents; +import static com.google.common.truth.Truth.assertThat; +import static java.util.concurrent.TimeUnit.SECONDS; +import static org.awaitility.Awaitility.await; +import static org.mifos.integrationtest.common.Utils.CONTENT_TYPE; +import static org.mifos.integrationtest.common.Utils.CONTENT_TYPE_VALUE; +import static org.mifos.integrationtest.common.Utils.X_CORRELATIONID; +import static org.mifos.integrationtest.common.Utils.X_CallbackURL; + +import com.github.tomakehurst.wiremock.stubbing.ServeEvent; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import io.cucumber.core.internal.com.fasterxml.jackson.core.JsonProcessingException; +import io.cucumber.core.internal.com.fasterxml.jackson.databind.JsonNode; +import io.cucumber.core.internal.com.fasterxml.jackson.databind.ObjectMapper; +import io.cucumber.java.en.And; +import io.cucumber.java.en.Given; +import io.cucumber.java.en.Then; +import io.cucumber.java.en.When; +import io.restassured.RestAssured; +import io.restassured.builder.ResponseSpecBuilder; +import io.restassured.specification.RequestSpecification; +import java.io.File; +import java.io.FileNotFoundException; +import java.util.ArrayList; +import java.util.List; +import java.util.Random; +import java.util.Scanner; +import org.apache.fineract.client.models.PostSavingsAccountsResponse; +import org.apache.fineract.client.models.PostSelfLoansLoanIdResponse; +import org.mifos.connector.common.ams.dto.InteropAccountDTO; +import org.mifos.connector.common.identityaccountmapper.dto.AccountMapperRequestDTO; +import org.mifos.connector.common.identityaccountmapper.dto.BeneficiaryDTO; +import org.mifos.integrationtest.common.Utils; +import org.mifos.integrationtest.config.GsmaConfig; +import org.mifos.integrationtest.util.Util; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; + +public class GSMATransferStepDef extends BaseStepDef { + + @Value("${ams.base-url}") + String amsBaseUrl; + @Value("${ams.balance-endpoint}") + String amsBalanceEndpoint; + @Value("${ams.status-endpoint}") + String amsStatusEndpoint; + + @Value("${ams.name-endpoint}") + String amsNameEndpoint; + @Autowired + GsmaConfig gsmaConfig; + + @Autowired + GSMATransferDef gsmaTransferDef; + @Autowired + ObjectMapper objectMapper; + @Autowired + ScenarioScopeState scenarioScopeState; + Logger logger = LoggerFactory.getLogger(this.getClass()); + + private static AccountMapperRequestDTO registerBeneficiaryBody = null; + private static String registeringInstitutionId = "SocialWelfare"; + + @Given("I have Fineract-Platform-TenantId as {string}") + public void setTenantLoan(String fspId) { + // Setting tenant + if (fspId.startsWith("payee")) { + scenarioScopeState.fspId = payeeFspConfig.getPayeeFsp(fspId.toLowerCase()); + } else { + scenarioScopeState.fspId = payeeFspConfig.getPayerFsp(fspId.toLowerCase()); + } + assertThat(scenarioScopeState.fspId).isNotEmpty(); + gsmaTransferDef.setTenant(scenarioScopeState.fspId); + } + + @When("I call the create payer client endpoint") + public void callCreatePayerClientEndpoint() throws JsonProcessingException { + RequestSpecification requestSpec = Utils.getDefaultSpec(); + requestSpec = gsmaTransferDef.setHeaders(requestSpec); + gsmaTransferDef.createPayerClientBody = gsmaTransferDef.setBodyPayerClient(); + // Calling savings product endpoint + gsmaTransferDef.responsePayerClient = RestAssured.given(requestSpec).baseUri(gsmaConfig.payerClientBaseUrl) + .body(gsmaTransferDef.createPayerClientBody).expect().spec(new ResponseSpecBuilder().expectStatusCode(200).build()).when() + .post(gsmaConfig.payerClientEndpoint).andReturn().asString(); + + logger.info("Create Payer Client Response: " + gsmaTransferDef.responsePayerClient); + assertThat(gsmaTransferDef.responsePayerClient).isNotEmpty(); + } + + @Then("I call the create savings product endpoint") + public void callCreateSavingsProductEndpoint() throws JsonProcessingException { + // Setting headers and body + RequestSpecification requestSpec = Utils.getDefaultSpec(); + requestSpec = gsmaTransferDef.setHeaders(requestSpec); + gsmaTransferDef.savingsProductBody = gsmaTransferDef.setBodySavingsProduct(); + // Calling savings product endpoint + gsmaTransferDef.responseSavingsProduct = RestAssured.given(requestSpec).baseUri(gsmaConfig.savingsBaseUrl) + .body(gsmaTransferDef.savingsProductBody).expect().spec(new ResponseSpecBuilder().expectStatusCode(200).build()).when() + .post(gsmaConfig.savingsProductEndpoint).andReturn().asString(); + + logger.info("Savings Product Response: " + gsmaTransferDef.responseSavingsProduct); + assertThat(gsmaTransferDef.responseSavingsProduct).isNotEmpty(); + } + + @When("I call the create savings account endpoint") + public void callCreateSavingsAccountEndpoint() throws JsonProcessingException { + // Setting headers and body + RequestSpecification requestSpec = Utils.getDefaultSpec(); + requestSpec = gsmaTransferDef.setHeaders(requestSpec); + gsmaTransferDef.savingsAccountBody = gsmaTransferDef.setBodySavingsAccount(); + // Calling savings product endpoint + gsmaTransferDef.responseSavingsAccount = RestAssured.given(requestSpec).baseUri(gsmaConfig.savingsBaseUrl) + .body(gsmaTransferDef.savingsAccountBody).expect().spec(new ResponseSpecBuilder().expectStatusCode(200).build()).when() + .post(gsmaConfig.savingsAccountEndpoint).andReturn().asString(); + + logger.info("Savings Account Response: " + gsmaTransferDef.responseSavingsAccount); + assertThat(gsmaTransferDef.responseSavingsAccount).isNotEmpty(); + } + + @Then("I call the interop identifier endpoint") + public void callCreateInteropIdentifierEndpoint() throws JsonProcessingException { + // Setting headers and body + RequestSpecification requestSpec = Utils.getDefaultSpec(); + requestSpec = gsmaTransferDef.setHeaders(requestSpec); + gsmaTransferDef.interopIdentifierBody = gsmaTransferDef.setBodyInteropIdentifier(); + // Setting account ID in path + PostSavingsAccountsResponse savingsAccountResponse = objectMapper.readValue(gsmaTransferDef.responseSavingsAccount, + PostSavingsAccountsResponse.class); + scenarioScopeState.payerIdentifier = savingsAccountResponse.getSavingsId().toString(); + gsmaConfig.interopIdentifierEndpoint = gsmaConfig.interopIdentifierEndpoint.replaceAll("\\{\\{identifierType\\}\\}", "MSISDN"); + gsmaConfig.interopIdentifierEndpoint = gsmaConfig.interopIdentifierEndpoint.replaceAll("\\{\\{identifier\\}\\}", + scenarioScopeState.payerIdentifier); + // Calling Interop Identifier endpoint + gsmaTransferDef.responseInteropIdentifier = RestAssured.given(requestSpec).baseUri(gsmaConfig.savingsBaseUrl) + .body(gsmaTransferDef.interopIdentifierBody).expect().spec(new ResponseSpecBuilder().expectStatusCode(200).build()).when() + .post(gsmaConfig.interopIdentifierEndpoint).andReturn().asString(); + + logger.info("Interop Identifier Response: " + gsmaTransferDef.responseInteropIdentifier); + assertThat(gsmaTransferDef.responseInteropIdentifier).isNotEmpty(); + } + + @Then("I approve the deposit with command {string}") + public void callApproveSavingsEndpoint(String command) throws JsonProcessingException { + // Setting headers and body + RequestSpecification requestSpec = Utils.getDefaultSpec(); + requestSpec = gsmaTransferDef.setHeaders(requestSpec); + requestSpec.queryParam("command", command); + gsmaTransferDef.savingsApproveBody = gsmaTransferDef.setBodySavingsApprove(); + // Setting account ID in path + PostSavingsAccountsResponse savingsAccountResponse = objectMapper.readValue(gsmaTransferDef.responseSavingsAccount, + PostSavingsAccountsResponse.class); + String savingsApproveEndpoint = gsmaConfig.savingsApproveEndpoint; + savingsApproveEndpoint = savingsApproveEndpoint.replaceAll("\\{\\{savingsAccId\\}\\}", + savingsAccountResponse.getSavingsId().toString()); + // Calling create loan account endpoint + gsmaTransferDef.responseSavingsApprove = RestAssured.given(requestSpec).baseUri(gsmaConfig.savingsBaseUrl) + .body(gsmaTransferDef.savingsApproveBody).expect().spec(new ResponseSpecBuilder().expectStatusCode(200).build()).when() + .post(savingsApproveEndpoint).andReturn().asString(); + + logger.info("Savings Approve Response: " + gsmaTransferDef.responseSavingsApprove); + assertThat(gsmaTransferDef.responseSavingsApprove).isNotEmpty(); + } + + @When("I activate the account with command {string}") + public void callSavingsActivateEndpoint(String command) throws JsonProcessingException { + // Setting headers and body + RequestSpecification requestSpec = Utils.getDefaultSpec(); + requestSpec = gsmaTransferDef.setHeaders(requestSpec); + requestSpec.queryParam("command", command); + gsmaTransferDef.savingsActivateBody = gsmaTransferDef.setBodySavingsActivate(); + // Setting account ID + PostSavingsAccountsResponse savingsAccountResponse = objectMapper.readValue(gsmaTransferDef.responseSavingsAccount, + PostSavingsAccountsResponse.class); + String savingsApproveEndpoint = gsmaConfig.savingsApproveEndpoint; + savingsApproveEndpoint = savingsApproveEndpoint.replaceAll("\\{\\{savingsAccId\\}\\}", + savingsAccountResponse.getSavingsId().toString()); + // Calling create loan account endpoint + gsmaTransferDef.responseSavingsActivate = RestAssured.given(requestSpec).baseUri(gsmaConfig.savingsBaseUrl) + .body(gsmaTransferDef.savingsActivateBody).expect().spec(new ResponseSpecBuilder().expectStatusCode(200).build()).when() + .post(savingsApproveEndpoint).andReturn().asString(); + + logger.info("Savings Activate Response: " + gsmaTransferDef.responseSavingsActivate); + assertThat(gsmaTransferDef.responseSavingsActivate).isNotEmpty(); + } + + @Then("I call the deposit account endpoint with command {string} for amount {int}") + public void callDepositAccountEndpoint(String command, int amount) throws JsonProcessingException { + // Setting headers and body + RequestSpecification requestSpec = Utils.getDefaultSpec(); + requestSpec = gsmaTransferDef.setHeaders(requestSpec); + requestSpec.queryParam("command", command); + gsmaTransferDef.savingsDepositAccountBody = gsmaTransferDef.setSavingsDepositAccount(amount); + // Setting account ID + PostSavingsAccountsResponse savingsAccountResponse = objectMapper.readValue(gsmaTransferDef.responseSavingsAccount, + PostSavingsAccountsResponse.class); + String savingsDepositEndpoint = gsmaConfig.savingsDepositAccountEndpoint; + savingsDepositEndpoint = savingsDepositEndpoint.replaceAll("\\{\\{savingsAccId\\}\\}", + savingsAccountResponse.getSavingsId().toString()); + // Calling create loan account endpoint + gsmaTransferDef.responseSavingsDepositAccount = RestAssured.given(requestSpec).baseUri(gsmaConfig.savingsBaseUrl) + .body(gsmaTransferDef.savingsDepositAccountBody).expect().spec(new ResponseSpecBuilder().expectStatusCode(200).build()) + .when().post(savingsDepositEndpoint).andReturn().asString(); + + logger.info("Savings Deposit Response: " + gsmaTransferDef.responseSavingsDepositAccount); + assertThat(gsmaTransferDef.responseSavingsDepositAccount).isNotEmpty(); + + } + + @Then("I call the deposit account endpoint for {string} with command {string} for amount {int}") + public void callDepositAccountEndpoint(String client, String command, int amount) throws JsonProcessingException { + // Setting headers and body + RequestSpecification requestSpec = Utils.getDefaultSpec(); + requestSpec = gsmaTransferDef.setHeaders(requestSpec); + requestSpec.queryParam("command", command); + if (client.equals("payer")) { + scenarioScopeState.initialBalForPayer = amount; + } else if (client.equals("payee")) { + scenarioScopeState.initialBalForPayee = amount; + } + gsmaTransferDef.savingsDepositAccountBody = gsmaTransferDef.setSavingsDepositAccount(amount); + // Setting account ID + PostSavingsAccountsResponse savingsAccountResponse = objectMapper.readValue(gsmaTransferDef.responseSavingsAccount, + PostSavingsAccountsResponse.class); + String savingsDepositEndpoint = gsmaConfig.savingsDepositAccountEndpoint; + savingsDepositEndpoint = savingsDepositEndpoint.replaceAll("\\{\\{savingsAccId\\}\\}", + savingsAccountResponse.getSavingsId().toString()); + // Calling create loan account endpoint + gsmaTransferDef.responseSavingsDepositAccount = RestAssured.given(requestSpec).baseUri(gsmaConfig.savingsBaseUrl) + .body(gsmaTransferDef.savingsDepositAccountBody).expect().spec(new ResponseSpecBuilder().expectStatusCode(200).build()) + .when().post(savingsDepositEndpoint).andReturn().asString(); + + logger.info("Savings Deposit Response: " + gsmaTransferDef.responseSavingsDepositAccount); + assertThat(gsmaTransferDef.responseSavingsDepositAccount).isNotEmpty(); + + } + + @And("I call the create loan product endpoint") + public void callLoanProductEndpoint() throws JsonProcessingException { + // Setting headers and body + RequestSpecification requestSpec = Utils.getDefaultSpec(); + requestSpec = gsmaTransferDef.setHeaders(requestSpec); + gsmaTransferDef.loanProductBody = gsmaTransferDef.setBodyLoanProduct(); + // Calling loan product endpoint + gsmaTransferDef.responseLoanProduct = RestAssured.given(requestSpec).baseUri(gsmaConfig.loanBaseUrl) + .body(gsmaTransferDef.loanProductBody).expect().spec(new ResponseSpecBuilder().expectStatusCode(200).build()).when() + .post(gsmaConfig.loanProductEndpoint).andReturn().asString(); + + logger.info("Loan Product Response: " + gsmaTransferDef.responseLoanProduct); + assertThat(gsmaTransferDef.responseLoanProduct).isNotEmpty(); + } + + @When("I call the create loan account") + public void callCreateLoanAccountEndpoint() throws JsonProcessingException { + // Setting headers and body + RequestSpecification requestSpec = Utils.getDefaultSpec(); + requestSpec = gsmaTransferDef.setHeaders(requestSpec); + gsmaTransferDef.loanAccountBody = gsmaTransferDef.setBodyLoanAccount(); + // Calling create loan account endpoint + gsmaTransferDef.responseLoanAccount = RestAssured.given(requestSpec).baseUri(gsmaConfig.loanBaseUrl) + .body(gsmaTransferDef.loanAccountBody).expect().spec(new ResponseSpecBuilder().expectStatusCode(200).build()).when() + .post(gsmaConfig.loanAccountEndpoint).andReturn().asString(); + + logger.info("Loan Account Response: " + gsmaTransferDef.responseLoanAccount); + assertThat(gsmaTransferDef.responseLoanAccount).isNotEmpty(); + } + + @Then("I approve the loan account with command {string} for amount {int}") + public void callApproveLoanEndpoint(String command, int amount) throws JsonProcessingException { + // Setting headers and body + RequestSpecification requestSpec = Utils.getDefaultSpec(); + requestSpec = gsmaTransferDef.setHeaders(requestSpec); + requestSpec.queryParam("command", command); + gsmaTransferDef.loanApproveBody = gsmaTransferDef.setBodyLoanApprove(amount); + // Setting account ID + PostSelfLoansLoanIdResponse loanAccountResponse = objectMapper.readValue(gsmaTransferDef.responseLoanAccount, + PostSelfLoansLoanIdResponse.class); + String loanAccountId = String.valueOf(loanAccountResponse.getLoanId()); + gsmaConfig.loanApproveEndpoint = gsmaConfig.loanApproveEndpoint.replaceAll("\\{\\{loanAccId\\}\\}", loanAccountId); + // Calling create loan account endpoint + gsmaTransferDef.responseLoanApprove = RestAssured.given(requestSpec).baseUri(gsmaConfig.loanBaseUrl) + .body(gsmaTransferDef.loanApproveBody).expect().spec(new ResponseSpecBuilder().expectStatusCode(200).build()).when() + .post(gsmaConfig.loanApproveEndpoint).andReturn().asString(); + + logger.info("Loan Approve Response: " + gsmaTransferDef.responseLoanApprove); + assertThat(gsmaTransferDef.responseLoanApprove).isNotEmpty(); + } + + @When("I call the loan disburse endpoint with command {string} for amount {int}") + public void callLoanDisburseEndpoint(String command, int amount) throws JsonProcessingException { + RequestSpecification requestSpec = Utils.getDefaultSpec(); + requestSpec = gsmaTransferDef.setHeaders(requestSpec); + requestSpec.queryParam("command", command); + gsmaTransferDef.loanDisburseBody = gsmaTransferDef.setBodyLoanDisburse(amount); + // Setting account ID + PostSelfLoansLoanIdResponse loanAccountResponse = objectMapper.readValue(gsmaTransferDef.responseLoanAccount, + PostSelfLoansLoanIdResponse.class); + String loanAccountId = String.valueOf(loanAccountResponse.getLoanId()); + gsmaConfig.loanDisburseEndpoint = gsmaConfig.loanDisburseEndpoint.replaceAll("\\{\\{loanAccId\\}\\}", loanAccountId); + // Calling create loan account endpoint + gsmaTransferDef.responseLoanDisburse = RestAssured.given(requestSpec).baseUri(gsmaConfig.loanBaseUrl) + .body(gsmaTransferDef.loanDisburseBody).expect().spec(new ResponseSpecBuilder().expectStatusCode(200).build()).when() + .post(gsmaConfig.loanDisburseEndpoint).andReturn().asString(); + + logger.info("Loan Approve Response: " + gsmaTransferDef.responseLoanDisburse); + assertThat(gsmaTransferDef.responseLoanDisburse).isNotEmpty(); + } + + @Then("I call the loan repayment endpoint for amount {int}") + public void callLoanRepaymentEndpoint(int amount) throws JsonProcessingException { + // Setting headers and body + RequestSpecification requestSpec = Utils.getDefaultSpec(); + requestSpec = gsmaTransferDef.setHeaders(requestSpec); + gsmaTransferDef.loanRepaymentBody = gsmaTransferDef.setBodyLoanRepayment(String.valueOf(amount)); + // Setting account ID + PostSelfLoansLoanIdResponse loanAccountResponse = objectMapper.readValue(gsmaTransferDef.responseLoanAccount, + PostSelfLoansLoanIdResponse.class); + String loanId = Integer.toString(loanAccountResponse.getLoanId()); + String loanAccountId = String.format("%0" + (9 - loanId.length()) + "d%s", 0, loanId); + gsmaConfig.loanRepaymentEndpoint = gsmaConfig.loanRepaymentEndpoint.replaceAll("\\{\\{loanAccId\\}\\}", loanAccountId); + // Calling create loan account endpoint + gsmaTransferDef.responseLoanRepayment = RestAssured.given(requestSpec).baseUri(gsmaConfig.loanBaseUrl) + .body(gsmaTransferDef.loanRepaymentBody).expect().spec(new ResponseSpecBuilder().expectStatusCode(200).build()).when() + .post(gsmaConfig.loanRepaymentEndpoint).andReturn().asString(); + + logger.info("Loan Repayment Response: " + gsmaTransferDef.responseLoanRepayment); + assertThat(gsmaTransferDef.responseLoanRepayment).isNotEmpty(); + } + + @When("I have amsName as {string} and acccountHoldingInstitutionId as {string} and amount as {int}") + public void setHeaders(String amsName, String acccountHoldingInstitutionId, int amount) { + gsmaTransferDef.setHeadersMifos(amsName, acccountHoldingInstitutionId, amount); + assertThat(gsmaTransferDef.amsName).isNotEmpty(); + assertThat(gsmaTransferDef.acccountHoldingInstitutionId).isNotEmpty(); + assertThat(gsmaTransferDef.amount).isNotNull(); + + } + + @Then("I call the channel connector API for savings account with expected status of {int} and stub {string}") + public void sendRequestToGSMAEndpointSavings(int status, String stub) throws JsonProcessingException { + RequestSpecification requestSpec = Utils.getDefaultSpec(); + requestSpec.header("amsName", gsmaTransferDef.amsName); + requestSpec.header("accountHoldingInstitutionId", gsmaTransferDef.acccountHoldingInstitutionId); + requestSpec.header(X_CORRELATIONID, "123456789"); + requestSpec.header(X_CallbackURL, gsmaConfig.callbackURL + stub); + requestSpec.header(CONTENT_TYPE, CONTENT_TYPE_VALUE); + + gsmaTransferDef.gsmaTransferBody = gsmaTransferDef.setGsmaTransactionBody("S"); + + gsmaTransferDef.gsmaTransactionResponse = RestAssured.given(requestSpec).baseUri(gsmaConfig.channelConnectorBaseUrl) + .body(gsmaTransferDef.gsmaTransferBody).expect().spec(new ResponseSpecBuilder().expectStatusCode(status).build()).when() + .post(gsmaConfig.gsmaEndpoint).andReturn().asString(); + + logger.info("GSMA Transaction Response: " + gsmaTransferDef.gsmaTransactionResponse); + assertThat(gsmaTransferDef.gsmaTransactionResponse).isNotEmpty(); + } + + @Then("I call the channel connector API for loan account with expected status of {int} and stub {string}") + public void sendRequestToGSMAEndpointLoan(int status, String stub) throws JsonProcessingException { + RequestSpecification requestSpec = Utils.getDefaultSpec(); + requestSpec.header("amsName", gsmaTransferDef.amsName); + requestSpec.header("accountHoldingInstitutionId", gsmaTransferDef.acccountHoldingInstitutionId); + requestSpec.header(X_CORRELATIONID, "123456789"); + requestSpec.header(CONTENT_TYPE, CONTENT_TYPE_VALUE); + requestSpec.header(X_CallbackURL, gsmaConfig.callbackURL + stub); + + gsmaTransferDef.gsmaTransferBody = gsmaTransferDef.setGsmaTransactionBody("L"); + + gsmaTransferDef.gsmaTransactionResponse = RestAssured.given(requestSpec).baseUri(gsmaConfig.channelConnectorBaseUrl) + .body(gsmaTransferDef.gsmaTransferBody).expect().spec(new ResponseSpecBuilder().expectStatusCode(status).build()).when() + .post(gsmaConfig.gsmaEndpoint).andReturn().asString(); + + logger.info("GSMA Transaction Response: " + gsmaTransferDef.gsmaTransactionResponse); + assertThat(gsmaTransferDef.gsmaTransactionResponse).isNotEmpty(); + } + + @Then("I call the debit interop identifier endpoint with MSISDN") + public void callCreateDebitInteropIdentifierEndpointMSISDN() throws JsonProcessingException { + // Setting headers and body + RequestSpecification requestSpec = Utils.getDefaultSpec(); + requestSpec = gsmaTransferDef.setHeaders(requestSpec); + gsmaTransferDef.interopIdentifierBody = gsmaTransferDef.setBodyInteropIdentifier(); + // Setting account ID in path + PostSavingsAccountsResponse savingsAccountResponse = objectMapper.readValue(gsmaTransferDef.responseSavingsAccount, + PostSavingsAccountsResponse.class); + String payer_identifier = scenarioScopeState.debitParty; + String debitInteropEndpoint = gsmaConfig.interopIdentifierEndpoint; + + debitInteropEndpoint = debitInteropEndpoint.replaceAll("\\{\\{identifierType\\}\\}", "MSISDN"); + debitInteropEndpoint = debitInteropEndpoint.replaceAll("\\{\\{identifier\\}\\}", payer_identifier); + // Calling Interop Identifier endpoint + logger.info("Interop Identifier Request: " + debitInteropEndpoint); + gsmaTransferDef.responseInteropIdentifier = RestAssured.given(requestSpec).baseUri(gsmaConfig.savingsBaseUrl) + .body(gsmaTransferDef.interopIdentifierBody).expect().spec(new ResponseSpecBuilder().expectStatusCode(200).build()).when() + .post(debitInteropEndpoint).andReturn().asString(); + + logger.info("Interop Identifier Response: " + gsmaTransferDef.responseInteropIdentifier); + assertThat(gsmaTransferDef.responseInteropIdentifier).isNotEmpty(); + } + + @Then("I call the credit interop identifier endpoint with MSISDN") + public void callCreateCreditInteropIdentifierEndpointMSISDN() throws JsonProcessingException { + // Setting headers and body + RequestSpecification requestSpec = Utils.getDefaultSpec(); + requestSpec = gsmaTransferDef.setHeaders(requestSpec); + gsmaTransferDef.interopIdentifierBody = gsmaTransferDef.setBodyInteropIdentifier(); + // Setting account ID in path + PostSavingsAccountsResponse savingsAccountResponse = objectMapper.readValue(gsmaTransferDef.responseSavingsAccount, + PostSavingsAccountsResponse.class); + String payer_identifier = scenarioScopeState.creditParty; + String creditInteropEndpoint = gsmaConfig.interopIdentifierEndpoint; + creditInteropEndpoint = creditInteropEndpoint.replaceAll("\\{\\{identifierType\\}\\}", "MSISDN"); + creditInteropEndpoint = creditInteropEndpoint.replaceAll("\\{\\{identifier\\}\\}", payer_identifier); + // Calling Interop Identifier endpoint + logger.info("Interop Identifier Request: " + creditInteropEndpoint); + gsmaTransferDef.responseInteropIdentifier = RestAssured.given(requestSpec).baseUri(gsmaConfig.savingsBaseUrl) + .body(gsmaTransferDef.interopIdentifierBody).expect().spec(new ResponseSpecBuilder().expectStatusCode(200).build()).when() + .post(creditInteropEndpoint).andReturn().asString(); + + logger.info("Interop Identifier Response: " + gsmaTransferDef.responseInteropIdentifier); + assertThat(gsmaTransferDef.responseInteropIdentifier).isNotEmpty(); + } + + @Then("I call the balance api for payer balance") + public void iCallTheBalanceApiForPayerBalance() throws JsonProcessingException { + RequestSpecification requestSpec = Utils.getDefaultSpec(scenarioScopeState.tenant); + String finalEndpoint = amsBalanceEndpoint; + finalEndpoint = finalEndpoint.replace("{IdentifierType}", "MSISDN"); + finalEndpoint = finalEndpoint.replace("{IdentifierId}", + scenarioScopeState.debitParty.isEmpty() ? scenarioScopeState.payerIdentifier : scenarioScopeState.debitParty); + logger.info("Endpoint: {}", finalEndpoint); + scenarioScopeState.response = RestAssured.given(requestSpec).baseUri(amsBaseUrl).body("").expect() + .spec(new ResponseSpecBuilder().expectStatusCode(200).build()).when().get(finalEndpoint).andReturn().asString(); + logger.info("Balance Response: {}", scenarioScopeState.response); + InteropAccountDTO interopAccountDTO = objectMapper.readValue(scenarioScopeState.response, InteropAccountDTO.class); + assertThat(interopAccountDTO.getAvailableBalance().intValue() <= scenarioScopeState.initialBalForPayer).isTrue(); + scenarioScopeState.gsmaP2PAmtDebit = 0; + + } + + @Then("I call the balance api for payee balance") + public void iCallTheBalanceApiForPayeeBalance() throws JsonProcessingException { + RequestSpecification requestSpec = Utils.getDefaultSpec(scenarioScopeState.tenant); + String finalEndpoint = amsBalanceEndpoint; + finalEndpoint = finalEndpoint.replace("{IdentifierType}", "MSISDN"); + finalEndpoint = finalEndpoint.replace("{IdentifierId}", + scenarioScopeState.creditParty.isEmpty() ? scenarioScopeState.payeeIdentifier : scenarioScopeState.creditParty); + logger.info("Endpoint: {}", finalEndpoint); + scenarioScopeState.response = RestAssured.given(requestSpec).baseUri(amsBaseUrl).body("").expect() + .spec(new ResponseSpecBuilder().expectStatusCode(200).build()).when().get(finalEndpoint).andReturn().asString(); + logger.info("Balance Response: {}", scenarioScopeState.response); + InteropAccountDTO interopAccountDTO = objectMapper.readValue(scenarioScopeState.response, InteropAccountDTO.class); + assertThat(interopAccountDTO.getAvailableBalance().intValue() >= scenarioScopeState.initialBalForPayee).isTrue(); + + } + + @Then("I call the balance api for payer balance after debit") + public void iCallTheBalanceApiForPayerBalanceAfterDebit() throws JsonProcessingException { + await().atMost(awaitMost, SECONDS).pollInterval(pollInterval, SECONDS).untilAsserted(() -> { + RequestSpecification requestSpec = Utils.getDefaultSpec(scenarioScopeState.tenant); + String finalEndpoint = amsBalanceEndpoint; + finalEndpoint = finalEndpoint.replace("{IdentifierType}", "MSISDN"); + finalEndpoint = finalEndpoint.replace("{IdentifierId}", + scenarioScopeState.debitParty.isEmpty() ? scenarioScopeState.payerIdentifier : scenarioScopeState.debitParty); + logger.info("Endpoint: " + finalEndpoint); + scenarioScopeState.response = RestAssured.given(requestSpec).baseUri(amsBaseUrl).body("").expect() + .spec(new ResponseSpecBuilder().expectStatusCode(200).build()).when().get(finalEndpoint).andReturn().asString(); + logger.info("Balance Response: {}", scenarioScopeState.response); + InteropAccountDTO interopAccountDTO = objectMapper.readValue(scenarioScopeState.response, InteropAccountDTO.class); + assertThat(interopAccountDTO.getAvailableBalance().intValue() == scenarioScopeState.initialBalForPayer + - scenarioScopeState.gsmaP2PAmtDebit).isTrue(); + + }); + } + + @Then("I call the balance api for payee balance after credit") + public void iCallTheBalanceApiForPayeeBalanceAfterCredit() throws JsonProcessingException { + await().atMost(awaitMost, SECONDS).pollInterval(pollInterval, SECONDS).untilAsserted(() -> { + RequestSpecification requestSpec = Utils.getDefaultSpec(scenarioScopeState.tenant); + String finalEndpoint = amsBalanceEndpoint; + finalEndpoint = finalEndpoint.replace("{IdentifierType}", "MSISDN"); + finalEndpoint = finalEndpoint.replace("{IdentifierId}", + scenarioScopeState.creditParty.isEmpty() ? scenarioScopeState.payeeIdentifier : scenarioScopeState.creditParty); + logger.info("Endpoint: {}", finalEndpoint); + scenarioScopeState.response = RestAssured.given(requestSpec).baseUri(amsBaseUrl).body("").expect() + .spec(new ResponseSpecBuilder().expectStatusCode(200).build()).when().get(finalEndpoint).andReturn().asString(); + logger.info("Balance Response: {}", scenarioScopeState.response); + InteropAccountDTO interopAccountDTO = objectMapper.readValue(scenarioScopeState.response, InteropAccountDTO.class); + assertThat(interopAccountDTO.getAvailableBalance().intValue() == scenarioScopeState.initialBalForPayee + + scenarioScopeState.gsmaP2PAmtDebit).isTrue(); + + }); + } + + @When("I create a set of debit and credit party") + public void iCreateASetOfDebitAndCreditParty() { + Random random = new Random(); + scenarioScopeState.debitParty = String.valueOf(random.nextInt(900000000) + 1000000000); + scenarioScopeState.creditParty = String.valueOf(random.nextInt(900000000) + 1000000000); + assertThat(scenarioScopeState.debitParty).isNotEmpty(); + assertThat(scenarioScopeState.creditParty).isNotEmpty(); + assertThat(scenarioScopeState.debitParty).isNotEqualTo(scenarioScopeState.creditParty); + + } + + @Then("I create an IdentityMapperDTO for Register Beneficiary with identifier from previous step") + public void iCreateAnIdentityMapperDTOForRegisterBeneficiaryWithIdentifierFromPreviousStep() { + List beneficiaryDTOList = new ArrayList<>(); + scenarioScopeState.payeeIdentity = generateUniqueNumber(12); + BeneficiaryDTO beneficiaryDTO = new BeneficiaryDTO(scenarioScopeState.payeeIdentity, "01", scenarioScopeState.payerIdentifier, + scenarioScopeState.fspId); + beneficiaryDTOList.add(beneficiaryDTO); + scenarioScopeState.requestId = generateUniqueNumber(12); + registerBeneficiaryBody = new AccountMapperRequestDTO(scenarioScopeState.requestId, "", beneficiaryDTOList); + scenarioScopeState.beneficiaryPayeeIdentity = scenarioScopeState.payeeIdentity; + } + + public static String generateUniqueNumber(int length) { + Random rand = new Random(); + long timestamp = System.currentTimeMillis(); + long randomLong = rand.nextLong(100000000); + String uniqueNumber = timestamp + "" + randomLong; + return uniqueNumber.substring(0, length); + } + + @When("I call the register beneficiary API with expected status of {int} and callback stub {string}") + public void iCallTheRegisterBeneficiaryAPIWithExpectedStatusOfAndCallbackStub(int expectedStatus, String stub) { + RequestSpecification requestSpec = Utils.getDefaultSpec(); + scenarioScopeState.response = RestAssured.given(requestSpec).header("Content-Type", "application/json") + .header("X-Registering-Institution-ID", registeringInstitutionId) + .header("X-CallbackURL", identityMapperConfig.callbackURL + stub).baseUri(identityMapperConfig.identityMapperContactPoint) + .body(registerBeneficiaryBody).expect().spec(new ResponseSpecBuilder().expectStatusCode(expectedStatus).build()).when() + .post(identityMapperConfig.registerBeneficiaryEndpoint).andReturn().asString(); + + logger.info("Identity Mapper Response: {}", scenarioScopeState.response); + } + + @Then("I call the account lookup API with expected status of {int} and callback stub {string}") + public void iCallTheAccountLookupAPIWithExpectedStatusOfAndCallbackStub(int expectedStatus, String stub) { + await().atMost(awaitMost, SECONDS).untilAsserted(() -> { + scenarioScopeState.requestId = generateUniqueNumber(10); + RequestSpecification requestSpec = Utils.getDefaultSpec(); + scenarioScopeState.response = RestAssured.given(requestSpec).header("Content-Type", "application/json") + .header("X-Registering-Institution-ID", registeringInstitutionId) + .header("X-CallbackURL", identityMapperConfig.callbackURL + stub) + .queryParam("payeeIdentity", scenarioScopeState.payeeIdentity).queryParam("paymentModality", "01") + .queryParam("requestId", scenarioScopeState.requestId).baseUri(identityMapperConfig.identityMapperContactPoint).expect() + .spec(new ResponseSpecBuilder().expectStatusCode(expectedStatus).build()).when() + .get(identityMapperConfig.accountLookupEndpoint).andReturn().asString(); + + logger.info("Identity Mapper Response: {}", scenarioScopeState.response); + }); + } + + @And("I should be able to verify that the {string} method to {string} endpoint received a request with validation") + public void iShouldBeAbleToVerifyThatTheMethodToEndpointReceivedARequestWithValidation(String arg0, String endpoint) { + await().atMost(awaitMost, SECONDS).pollDelay(pollDelay, SECONDS).pollInterval(pollInterval, SECONDS).untilAsserted(() -> { + + List allServeEvents = getAllServeEvents(); + Boolean isValidated = null; + + for (int i = 0; i < allServeEvents.size(); i++) { + ServeEvent request = allServeEvents.get(i); + + if (!(request.getRequest().getBodyAsString()).isEmpty()) { + try { + JsonNode rootNode = objectMapper.readTree(request.getRequest().getBodyAsString()); + String requestID = rootNode.get("requestId").asText(); + + if (scenarioScopeState.requestId.equals(requestID)) { + scenarioScopeState.callbackBody = request.getRequest().getBodyAsString(); + } + } catch (Exception e) { + logger.debug("{}", e.getMessage()); + } + + } + } + try { + JsonNode rootNode = objectMapper.readTree(scenarioScopeState.callbackBody); + isValidated = rootNode.get("isValidated").asBoolean(); + + } catch (Exception e) { + logger.debug("{}", e.getMessage()); + } + assertThat(isValidated).isTrue(); + }); + } + + @When("I call the AMS Mifos Deposit Mock API with expected status of {int}") + public void sendRequestToGSMADepositMockEndpoint(int status) throws JsonProcessingException { + RequestSpecification requestSpec = Utils.getDefaultSpec(); + requestSpec.header(CONTENT_TYPE, CONTENT_TYPE_VALUE); + String body = "{}"; + RestAssured.given(requestSpec).baseUri(gsmaConfig.amsMifosBasseUrl).body(body).expect() + .spec(new ResponseSpecBuilder().expectStatusCode(status).build()).when().post(gsmaConfig.savingsDepositAccountMockEndpoint) + .andReturn().asString(); + } + + @When("I call the AMS Mifos Loan Repayment Mock API with expected status of {int}") + public void sendRequestToGSMALoanRepaymentMockEndpoint(int status) throws JsonProcessingException { + RequestSpecification requestSpec = Utils.getDefaultSpec(); + requestSpec.header(CONTENT_TYPE, CONTENT_TYPE_VALUE); + String body = "{}"; + RestAssured.given(requestSpec).baseUri(gsmaConfig.amsMifosBasseUrl).body(body).expect() + .spec(new ResponseSpecBuilder().expectStatusCode(status).build()).when().post(gsmaConfig.loanRepaymentMockEndpoint) + .andReturn().asString(); + } + + @When("I call the savings account endpoint to get the current Balance") + public void getCurrentBalance() throws JsonProcessingException { + RequestSpecification requestSpec = Utils.getDefaultSpec(); + requestSpec = gsmaTransferDef.setHeaders(requestSpec); + // Setting account ID in path + PostSavingsAccountsResponse savingsAccountResponse = objectMapper.readValue(gsmaTransferDef.responseSavingsAccount, + PostSavingsAccountsResponse.class); + gsmaConfig.savingsApproveEndpoint = gsmaConfig.savingsApproveEndpoint.replaceAll("\\{\\{savingsAccId\\}\\}", + savingsAccountResponse.getSavingsId().toString()); + + String responseBody = RestAssured.given(requestSpec).baseUri(gsmaConfig.savingsBaseUrl).expect() + .spec(new ResponseSpecBuilder().expectStatusCode(200).build()).when().get(gsmaConfig.savingsApproveEndpoint).andReturn() + .asString(); + + JsonObject jsonObject = JsonParser.parseString(responseBody).getAsJsonObject(); + + scenarioScopeState.currentBalance = jsonObject.get("summary").getAsJsonObject().get("accountBalance").getAsLong(); + logger.info(String.valueOf(scenarioScopeState.currentBalance)); + } + + @When("I create a set of debit and credit party from file {string}") + public void iCreateASetOfDebitAndCreditPartyFromFile(String filename) { + try { + scenarioScopeState.filename = filename; + File f = new File(Utils.getAbsoluteFilePathToResource(scenarioScopeState.filename)); + assertThat(f.exists()).isTrue(); + assertThat(scenarioScopeState.filename).isNotEmpty(); + Scanner scanner = new Scanner(f); + String line = scanner.nextLine(); + while (scanner.hasNextLine() && !line.isEmpty()) { + String line2 = scanner.nextLine(); + String[] parts = line2.split(","); + scenarioScopeState.debitParty = parts[4]; + scenarioScopeState.creditParty = parts[6]; + assertThat(scenarioScopeState.debitParty).isNotEmpty(); + assertThat(scenarioScopeState.creditParty).isNotEmpty(); + assertThat(scenarioScopeState.debitParty).isNotEqualTo(scenarioScopeState.creditParty); + } + scanner.close(); + } catch (FileNotFoundException e) { + logger.info("File not found"); + } + + } + + @And("I parse amount to be debited and credited from file {string}") + public void iParseAmountToBeDebitedAndCreditedFromFile(String filename) { + try { + scenarioScopeState.filename = filename; + File f = new File(Utils.getAbsoluteFilePathToResource(scenarioScopeState.filename)); + assertThat(f.exists()).isTrue(); + assertThat(scenarioScopeState.filename).isNotEmpty(); + Scanner scanner = new Scanner(f); + String line = scanner.nextLine(); + while (scanner.hasNextLine() && !line.isEmpty()) { + String line2 = scanner.nextLine(); + String[] parts = line2.split(","); + scenarioScopeState.gsmaP2PAmtDebit = scenarioScopeState.gsmaP2PAmtDebit + Integer.parseInt(parts[7]); + assertThat(scenarioScopeState.gsmaP2PAmtDebit).isNotNull(); + } + scanner.close(); + } catch (FileNotFoundException e) { + logger.info("File not found"); + } + + } + + @Then("I call the balance api for payee {string} balance") + public void iCallTheBalanceApiForPayeeBalance(String id) throws JsonProcessingException { + RequestSpecification requestSpec = Utils.getDefaultSpec(scenarioScopeState.tenant); + String finalEndpoint = amsBalanceEndpoint; + if (scenarioScopeState.payeeIdentifierforBatch == null) { + scenarioScopeState.payeeIdentifierforBatch = new String[4]; + } + scenarioScopeState.payeeIdentifierforBatch[Integer.parseInt(id)] = scenarioScopeState.payeeIdentifier; + finalEndpoint = finalEndpoint.replace("{IdentifierType}", "MSISDN"); + finalEndpoint = finalEndpoint.replace("{IdentifierId}", scenarioScopeState.payeeIdentifier); + logger.info("Endpoint: " + finalEndpoint); + scenarioScopeState.response = RestAssured.given(requestSpec).baseUri(amsBaseUrl).body("").expect() + .spec(new ResponseSpecBuilder().expectStatusCode(200).build()).when().get(finalEndpoint).andReturn().asString(); + logger.info("Balance Response: {}", scenarioScopeState.response); + InteropAccountDTO interopAccountDTO = objectMapper.readValue(scenarioScopeState.response, InteropAccountDTO.class); + assertThat( + interopAccountDTO.getAvailableBalance().intValue() >= scenarioScopeState.initialBalForPayeeForBatch[Integer.parseInt(id)]) + .isTrue(); + + } + + @Then("I call the balance api for payee {string} balance for combine test cases") + public void iCallTheBalanceApiForPayeeBalanceForCombinedTestsCases(String id) throws JsonProcessingException { + RequestSpecification requestSpec = Utils.getDefaultSpec(scenarioScopeState.tenant); + String finalEndpoint = amsBalanceEndpoint; + if (scenarioScopeState.payeeIdentifierforBatch == null) { + scenarioScopeState.payeeIdentifierforBatch = new String[9]; + } + scenarioScopeState.payeeIdentifierforBatch[Integer.parseInt(id)] = scenarioScopeState.payeeIdentifier; + finalEndpoint = finalEndpoint.replace("{IdentifierType}", "MSISDN"); + finalEndpoint = finalEndpoint.replace("{IdentifierId}", + scenarioScopeState.creditParty == null ? scenarioScopeState.payeeIdentifier : scenarioScopeState.creditParty); + logger.info("Endpoint: " + finalEndpoint); + scenarioScopeState.response = RestAssured.given(requestSpec).baseUri(amsBaseUrl).body("").expect() + .spec(new ResponseSpecBuilder().expectStatusCode(200).build()).when().get(finalEndpoint).andReturn().asString(); + logger.info("Balance Response: {}", scenarioScopeState.response); + InteropAccountDTO interopAccountDTO = objectMapper.readValue(scenarioScopeState.response, InteropAccountDTO.class); + assertThat( + interopAccountDTO.getAvailableBalance().intValue() >= scenarioScopeState.initialBalForPayeeForBatch[Integer.parseInt(id)]) + .isTrue(); + + } + + @Then("I call the balance api for payer {string} balance for all combine test cases") + public void iCallTheBalanceApiForAllPayerBalanceForCombinedTestCases(String id) throws JsonProcessingException { + RequestSpecification requestSpec = Utils.getDefaultSpec(scenarioScopeState.tenant); + String finalEndpoint = amsBalanceEndpoint; + // Check whether a new batch been initialized + initializeIfNotInitialized(id); + scenarioScopeState.payerIdentifierforBatch[Integer.parseInt(id)] = scenarioScopeState.payerIdentifier; + String accountId = (scenarioScopeState.debitParty == null) ? scenarioScopeState.payerIdentifier : scenarioScopeState.debitParty; + String identifierType = "MSISDN"; + finalEndpoint = Util.getFormattedEndpoint(finalEndpoint, "{IdentifierType}", identifierType); + finalEndpoint = Util.getFormattedEndpoint(finalEndpoint, "{IdentifierId}", accountId); + logger.info("Endpoint: {} ", finalEndpoint); + scenarioScopeState.response = RestAssured.given(requestSpec).baseUri(amsBaseUrl).body("").expect() + .spec(new ResponseSpecBuilder().expectStatusCode(200).build()).when().get(finalEndpoint).andReturn().asString(); + logger.info("Balance Response: {}", scenarioScopeState.response); + InteropAccountDTO interopAccountDTO = objectMapper.readValue(scenarioScopeState.response, InteropAccountDTO.class); + assertThat( + interopAccountDTO.getAvailableBalance().intValue() >= scenarioScopeState.initialBalForPayerForBatch[Integer.parseInt(id)]) + .isTrue(); + } + + public void initializeIfNotInitialized(String id) { + if (shouldInitializeArray(id)) { + scenarioScopeState.payerIdentifierforBatch = new String[15]; + } + } + + private boolean shouldInitializeArray(String id) { + return scenarioScopeState.payerIdentifierforBatch == null || id.equals("1"); + } + + public void initializeIfNotInitializedForPayee(String id) { + if (shouldInitializeArrayForPayee(id)) { + scenarioScopeState.payeeIdentifierforBatch = new String[15]; + } + } + + private boolean shouldInitializeArrayForPayee(String id) { + return scenarioScopeState.payeeIdentifierforBatch == null || id.equals("1"); + } + + @Then("I call the balance api for payee {string} balance for all combine test cases") + public void iCallTheBalanceApiForPayeeBalanceForAllCombinedTestsCases(String id) throws JsonProcessingException { + RequestSpecification requestSpec = Utils.getDefaultSpec(scenarioScopeState.tenant); + String finalEndpoint = amsBalanceEndpoint; + + initializeIfNotInitializedForPayee(id); + scenarioScopeState.payeeIdentifierforBatch[Integer.parseInt(id)] = scenarioScopeState.payeeIdentifier; + String identifierId = (scenarioScopeState.creditParty == null) ? scenarioScopeState.payeeIdentifier + : scenarioScopeState.creditParty; + String identifierType = "MSISDN"; + finalEndpoint = Util.getFormattedEndpoint(finalEndpoint, "{IdentifierType}", identifierType); + finalEndpoint = Util.getFormattedEndpoint(finalEndpoint, "{IdentifierId}", identifierId); + logger.info("Endpoint: {}", finalEndpoint); + scenarioScopeState.response = RestAssured.given(requestSpec).baseUri(amsBaseUrl).body("").expect() + .spec(new ResponseSpecBuilder().expectStatusCode(200).build()).when().get(finalEndpoint).andReturn().asString(); + logger.info("Balance Response: {}", scenarioScopeState.response); + InteropAccountDTO interopAccountDTO = objectMapper.readValue(scenarioScopeState.response, InteropAccountDTO.class); + assertThat( + interopAccountDTO.getAvailableBalance().intValue() >= scenarioScopeState.initialBalForPayeeForBatch[Integer.parseInt(id)]) + .isTrue(); + + } + + @Then("I call the balance api for payee with id {string} balance after credit") + public void iCallTheBalanceApiForPayeeBalanceAfterCredit(String id) throws JsonProcessingException { + RequestSpecification requestSpec = Utils.getDefaultSpec(scenarioScopeState.tenant); + String finalEndpoint = amsBalanceEndpoint; + String identifierId = (scenarioScopeState.creditParty == null) ? scenarioScopeState.payeeIdentifier + : scenarioScopeState.creditParty; + String identifierType = "MSISDN"; + finalEndpoint = Util.getFormattedEndpoint(finalEndpoint, "{IdentifierType}", identifierType); + finalEndpoint = Util.getFormattedEndpoint(finalEndpoint, "{IdentifierId}", identifierId); + logger.info("Endpoint: {}", finalEndpoint); + scenarioScopeState.response = RestAssured.given(requestSpec).baseUri(amsBaseUrl).body("").expect() + .spec(new ResponseSpecBuilder().expectStatusCode(200).build()).when().get(finalEndpoint).andReturn().asString(); + logger.info("Balance Response: {}", scenarioScopeState.response); + InteropAccountDTO interopAccountDTO = objectMapper.readValue(scenarioScopeState.response, InteropAccountDTO.class); + assertThat(interopAccountDTO.getAvailableBalance().intValue() == scenarioScopeState.initialBalForPayeeForBatch[Integer.parseInt(id)] + + scenarioScopeState.gsmaP2PAmtDebitForBatch[Integer.parseInt(id)]).isTrue(); + } + + @Then("I call the balance api for payer {string} balance") + public void iCallTheBalanceApiForPayerBalance(String id) throws JsonProcessingException { + RequestSpecification requestSpec = Utils.getDefaultSpec(scenarioScopeState.tenant); + String finalEndpoint = amsBalanceEndpoint; + if (scenarioScopeState.payerIdentifierforBatch == null) { + scenarioScopeState.payerIdentifierforBatch = new String[4]; + } + scenarioScopeState.payerIdentifierforBatch[Integer.parseInt(id)] = scenarioScopeState.payerIdentifier; + finalEndpoint = finalEndpoint.replace("{IdentifierType}", "MSISDN"); + finalEndpoint = finalEndpoint.replace("{IdentifierId}", scenarioScopeState.payerIdentifier); + logger.info("Endpoint: " + finalEndpoint); + scenarioScopeState.response = RestAssured.given(requestSpec).baseUri(amsBaseUrl).body("").expect() + .spec(new ResponseSpecBuilder().expectStatusCode(200).build()).when().get(finalEndpoint).andReturn().asString(); + logger.info("Balance Response: {}", scenarioScopeState.response); + InteropAccountDTO interopAccountDTO = objectMapper.readValue(scenarioScopeState.response, InteropAccountDTO.class); + assertThat( + interopAccountDTO.getAvailableBalance().intValue() >= scenarioScopeState.initialBalForPayerForBatch[Integer.parseInt(id)]) + .isTrue(); + + } + + @Then("I call the balance api for payer {string} balance for combine test cases") + public void iCallTheBalanceApiForPayerBalanceForCombinedTestCases(String id) throws JsonProcessingException { + RequestSpecification requestSpec = Utils.getDefaultSpec(scenarioScopeState.tenant); + String finalEndpoint = amsBalanceEndpoint; + if (scenarioScopeState.payerIdentifierforBatch == null) { + scenarioScopeState.payerIdentifierforBatch = new String[9]; + } + scenarioScopeState.payerIdentifierforBatch[Integer.parseInt(id)] = scenarioScopeState.payerIdentifier; + finalEndpoint = finalEndpoint.replace("{IdentifierType}", "MSISDN"); + finalEndpoint = finalEndpoint.replace("{IdentifierId}", + (scenarioScopeState.debitParty == null) ? scenarioScopeState.payerIdentifier : scenarioScopeState.debitParty); + logger.info("Endpoint: " + finalEndpoint); + scenarioScopeState.response = RestAssured.given(requestSpec).baseUri(amsBaseUrl).body("").expect() + .spec(new ResponseSpecBuilder().expectStatusCode(200).build()).when().get(finalEndpoint).andReturn().asString(); + logger.info("Balance Response: {}", scenarioScopeState.response); + InteropAccountDTO interopAccountDTO = objectMapper.readValue(scenarioScopeState.response, InteropAccountDTO.class); + assertThat( + interopAccountDTO.getAvailableBalance().intValue() >= scenarioScopeState.initialBalForPayerForBatch[Integer.parseInt(id)]) + .isTrue(); + + } + + @Then("I call the balance api for payer with id {string} balance after debit") + public void iCallTheBalanceApiForPayerBalanceAfterDebit(String id) throws JsonProcessingException { + RequestSpecification requestSpec = Utils.getDefaultSpec(scenarioScopeState.tenant); + String finalEndpoint = amsBalanceEndpoint; + finalEndpoint = finalEndpoint.replace("{IdentifierType}", "MSISDN"); + finalEndpoint = finalEndpoint.replace("{IdentifierId}", scenarioScopeState.payerIdentifierforBatch[Integer.parseInt(id)]); + logger.info("Endpoint: " + finalEndpoint); + scenarioScopeState.response = RestAssured.given(requestSpec).baseUri(amsBaseUrl).body("").expect() + .spec(new ResponseSpecBuilder().expectStatusCode(200).build()).when().get(finalEndpoint).andReturn().asString(); + logger.info("Balance Response: {}", scenarioScopeState.response); + InteropAccountDTO interopAccountDTO = objectMapper.readValue(scenarioScopeState.response, InteropAccountDTO.class); + int originBal = scenarioScopeState.initialBalForPayerForBatch[Integer.parseInt(id)]; + int debitAmt = scenarioScopeState.gsmaP2PAmtDebitForBatch[Integer.parseInt(id)]; + int avlBal = interopAccountDTO.getAvailableBalance().intValue(); + assertThat(avlBal == originBal - debitAmt).isTrue(); + + } + + @Then("I call the account status api") + public void iCallTheAccountStatus() throws JsonProcessingException { + RequestSpecification requestSpec = Utils.getDefaultSpec(scenarioScopeState.tenant); + String finalEndpoint = amsStatusEndpoint; + finalEndpoint = finalEndpoint.replace("{IdentifierType}", "MSISDN"); + finalEndpoint = finalEndpoint.replace("{IdentifierId}", scenarioScopeState.debitParty); + logger.info("Endpoint: " + finalEndpoint); + scenarioScopeState.response = RestAssured.given(requestSpec).baseUri(amsBaseUrl).body("").expect() + .spec(new ResponseSpecBuilder().expectStatusCode(200).build()).when().get(finalEndpoint).andReturn().asString(); + logger.info("Status Response: " + scenarioScopeState.response); + + } + + @And("I can assert {string} status in response") + public void iCanAssertStatusInResponse(String status) { + assertThat(scenarioScopeState.response.contains(status)).isTrue(); + } + + @Then("I call the account name api") + public void iCallTheAccountName() throws JsonProcessingException { + RequestSpecification requestSpec = Utils.getDefaultSpec(scenarioScopeState.tenant); + String finalEndpoint = amsNameEndpoint; + finalEndpoint = finalEndpoint.replace("{IdentifierType}", "MSISDN"); + finalEndpoint = finalEndpoint.replace("{IdentifierId}", scenarioScopeState.debitParty); + logger.info("Endpoint: " + finalEndpoint); + scenarioScopeState.response = RestAssured.given(requestSpec).baseUri(amsBaseUrl).body("").expect() + .spec(new ResponseSpecBuilder().expectStatusCode(200).build()).when().get(finalEndpoint).andReturn().asString(); + logger.info("Status Response: " + scenarioScopeState.response); + + } + + @And("I can assert name in response") + public void iCanAssertNameInResponse() throws JsonProcessingException { + ObjectMapper mapper = new ObjectMapper(); + JsonNode jsonNode = mapper.readTree(scenarioScopeState.response); + + String firstName = jsonNode.get("name").get("firstName").asText(); + String lastName = jsonNode.get("name").get("lastName").asText(); + logger.info("Name is {} {}", firstName, lastName); + assertThat(firstName.isEmpty()).isFalse(); + assertThat(lastName.isEmpty()).isFalse(); + } +} diff --git a/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/cucumber/stepdef/GenericStepDef.java b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/cucumber/stepdef/GenericStepDef.java new file mode 100644 index 000000000..42a5ec6ee --- /dev/null +++ b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/cucumber/stepdef/GenericStepDef.java @@ -0,0 +1,61 @@ +package org.mifos.integrationtest.cucumber.stepdef; + +import static com.google.common.truth.Truth.assertThat; + +import io.cucumber.java.en.And; +import io.cucumber.java.en.Then; +import java.util.UUID; +import org.mifos.integrationtest.config.TenantConfig; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; + +/** + * This class contains the generic step def which is or can be common for multiple test cases.
+ * It's very important to not write any payment schema specific code here. + * + * @author danishjamal + */ +public class GenericStepDef extends BaseStepDef { + + @Autowired + TenantConfig tenantConfig; + + @Value("${global_wait_time_ms}") + private int globalWaitTime; + + @And("I have tenant as {string}") + public void payeefsp3tenantAnd(String tenant) { + scenarioScopeState.tenant = tenantConfig.getTenant(tenant.toLowerCase()); + } + + @Then("I should get non empty response") + public void nonEmptyResponseCheck() { + assertNonEmpty(scenarioScopeState.response); + } + + @And("I will sleep for {int} millisecond") + public void iWillSleepForSecs(int time) throws InterruptedException { + Thread.sleep(time + globalWaitTime); + } + + @And("I store this time as start time") + public void storeCurrentTime() { + scenarioScopeState.dateTime = getCurrentDateInFormat(); + } + + private void setTenant(String tenant) { + scenarioScopeState.tenant = tenant; + assertThat(scenarioScopeState.tenant).isNotEmpty(); + scenarioScopeState.clientCorrelationId = UUID.randomUUID().toString(); + } + + private void assertNonEmpty(String data) { + assertThat(data).isNotNull(); + } + + @Then("I will assert that response body contains {string}") + public void verifyTheResponseContains(String message) { + assertThat(scenarioScopeState.response.contains(message)); + } + +} diff --git a/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/cucumber/stepdef/GetTxnApiDef.java b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/cucumber/stepdef/GetTxnApiDef.java new file mode 100644 index 000000000..6d6b74860 --- /dev/null +++ b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/cucumber/stepdef/GetTxnApiDef.java @@ -0,0 +1,92 @@ +package org.mifos.integrationtest.cucumber.stepdef; + +import static com.google.common.truth.Truth.assertThat; +import static java.util.concurrent.TimeUnit.SECONDS; +import static org.awaitility.Awaitility.await; + +import com.google.gson.Gson; +import io.cucumber.java.en.And; +import io.cucumber.java.en.When; +import io.restassured.RestAssured; +import io.restassured.builder.ResponseSpecBuilder; +import io.restassured.specification.RequestSpecification; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import org.json.JSONException; +import org.json.JSONObject; +import org.mifos.integrationtest.common.CollectionHelper; +import org.mifos.integrationtest.common.Utils; +import org.mifos.integrationtest.common.dto.CollectionResponse; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; + +public class GetTxnApiDef extends BaseStepDef { + + @Autowired + ScenarioScopeState scenarioScopeState; + private String clientCorrelationId = "123456789"; + + @Value("${operations-app.auth.enabled}") + public Boolean authEnabled; + + @When("I call the get txn API with expected status of {int}") + public void callTxnReqApi(int expectedStatus) { + await().atMost(awaitMost, SECONDS).pollDelay(pollDelay, SECONDS).pollInterval(pollInterval, SECONDS).untilAsserted(() -> { + RequestSpecification requestSpec = Utils.getDefaultSpec(scenarioScopeState.tenant); + if (authEnabled) { + requestSpec.header("Authorization", "Bearer " + scenarioScopeState.accessToken); + } + + scenarioScopeState.response = RestAssured.given(requestSpec).baseUri(operationsAppConfig.operationAppContactPoint).expect() + .spec(new ResponseSpecBuilder().expectStatusCode(expectedStatus).build()).when() + .get(operationsAppConfig.transactionRequestsEndpoint).andReturn().asString(); + assertThat(scenarioScopeState.response).isNotNull(); + logger.info("GetTxn Request Response: " + scenarioScopeState.response); + }); + } + + @And("I should have clientCorrelationId in response") + public void checkClientCorrelationId() { + assertThat(scenarioScopeState.response).containsMatch("clientCorrelationId"); + } + + @When("I call the get txn API with date today minus {int} day and {string} with expected status of {int}") + public void callTxnReqApiwithParams(int daydiff, String endDate, int expectedStatus) { + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd hh:mm:ss"); + if ("current date".equals(endDate)) { + endDate = formatter.format(LocalDateTime.now().plusDays(1)); + } + String startDate = formatter.format(LocalDateTime.now().minusDays(daydiff)); + RequestSpecification requestSpec = Utils.getDefaultSpec(scenarioScopeState.tenant); + if (authEnabled) { + requestSpec.header("Authorization", "Bearer " + scenarioScopeState.accessToken); + } + requestSpec.queryParam("startFrom", startDate); + requestSpec.queryParam("startTo", endDate); + scenarioScopeState.response = RestAssured.given(requestSpec).baseUri(operationsAppConfig.operationAppContactPoint).expect() + .spec(new ResponseSpecBuilder().expectStatusCode(expectedStatus).build()).when() + .get(operationsAppConfig.transactionRequestsEndpoint).andReturn().asString(); + + logger.info("GetTxn Request Response: " + scenarioScopeState.response); + + } + + @And("I should have startedAt and completedAt in response") + public void checkDate() { + assertThat(scenarioScopeState.response).containsMatch("startedAt"); + assertThat(scenarioScopeState.response).containsMatch("completedAt"); + } + + @And("I call collection api with expected status {int}") + public void iCallCollectionApiWithExpectedStatus(int expectedStatus) throws JSONException { + RequestSpecification requestSpec = Utils.getDefaultSpec(scenarioScopeState.tenant); + requestSpec.header(Utils.X_CORRELATIONID, clientCorrelationId); + JSONObject collectionRequestBody = CollectionHelper.getCollectionRequestBody("1", "254708374149", "24450523"); + logger.info(String.valueOf(collectionRequestBody)); + String json = RestAssured.given(requestSpec).baseUri(channelConnectorConfig.channelConnectorContactPoint) + .body(collectionRequestBody.toString()).expect().spec(new ResponseSpecBuilder().expectStatusCode(expectedStatus).build()) + .when().post("/channel/collection").andReturn().asString(); + CollectionResponse response = (new Gson()).fromJson(json, CollectionResponse.class); + assertThat(response.getTransactionId()).isNotEmpty(); + } +} diff --git a/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/cucumber/stepdef/IdempotencyStepDef.java b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/cucumber/stepdef/IdempotencyStepDef.java new file mode 100644 index 000000000..d2acfc273 --- /dev/null +++ b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/cucumber/stepdef/IdempotencyStepDef.java @@ -0,0 +1,143 @@ +package org.mifos.integrationtest.cucumber.stepdef; + +import static com.google.common.truth.Truth.assertThat; +import static org.mifos.integrationtest.common.Utils.CONTENT_TYPE; +import static org.mifos.integrationtest.common.Utils.CONTENT_TYPE_VALUE; +import static org.mifos.integrationtest.common.Utils.X_CORRELATIONID; + +import com.google.gson.Gson; +import io.cucumber.core.internal.com.fasterxml.jackson.core.JsonProcessingException; +import io.cucumber.java.en.And; +import io.cucumber.java.en.Given; +import io.cucumber.java.en.When; +import io.restassured.RestAssured; +import io.restassured.builder.ResponseSpecBuilder; +import io.restassured.specification.RequestSpecification; +import java.util.UUID; +import org.json.JSONException; +import org.json.JSONObject; +import org.mifos.integrationtest.common.CollectionHelper; +import org.mifos.integrationtest.common.Utils; +import org.mifos.integrationtest.common.dto.CollectionResponse; +import org.mifos.integrationtest.config.GsmaConfig; +import org.springframework.beans.factory.annotation.Autowired; + +public class IdempotencyStepDef extends BaseStepDef { + + @Autowired + GSMATransferDef gsmaTransferDef; + + @Autowired + GsmaConfig gsmaConfig; + + @Autowired + GSMATransferStepDef gsmaTransferStepDef; + + @When("I call collection api with client correlation id expected status {int}") + public void iCallCollectionApiWithClientCorrelationIdExpectedStatus(int expectedStatus) throws JSONException { + RequestSpecification requestSpec = Utils.getDefaultSpec(scenarioScopeState.tenant); + requestSpec.header(Utils.X_CORRELATIONID, scenarioScopeState.clientCorrelationId); + logger.info("X-CorrelationId: {}", scenarioScopeState.clientCorrelationId); + JSONObject collectionRequestBody = CollectionHelper.getCollectionRequestBody("1", "254708374149", "24450523"); + String json = RestAssured.given(requestSpec).baseUri(channelConnectorConfig.channelConnectorContactPoint) + .body(collectionRequestBody.toString()).expect().spec(new ResponseSpecBuilder().expectStatusCode(expectedStatus).build()) + .when().post(channelConnectorConfig.collectionEndpoint).andReturn().asString(); + CollectionResponse response = (new Gson()).fromJson(json, CollectionResponse.class); + assertThat(response.getTransactionId()).isNotEmpty(); + } + + @When("I call collection api to fail with client correlation id expected status {int}") + public void iCallCollectionApiWithClientCorrelationIdErrorExpectedStatus(int expectedStatus) throws JSONException { + RequestSpecification requestSpec = Utils.getDefaultSpec(scenarioScopeState.tenant); + requestSpec.header(Utils.X_CORRELATIONID, scenarioScopeState.clientCorrelationId); + JSONObject collectionRequestBody = CollectionHelper.getCollectionRequestBody("1", "254708374149", "24450523"); + scenarioScopeState.response = RestAssured.given(requestSpec).baseUri(channelConnectorConfig.channelConnectorContactPoint) + .body(collectionRequestBody.toString()).expect().spec(new ResponseSpecBuilder().expectStatusCode(expectedStatus).build()) + .when().post(channelConnectorConfig.collectionEndpoint).andReturn().asString(); + // CollectionResponse response = (new Gson()).fromJson(json, CollectionResponse.class); + assertThat(scenarioScopeState.response).isNotEmpty(); + } + + @Given("I have same clientCorrelationId") + public void iHaveSameClientCorrelationId() { + if (scenarioScopeState.clientCorrelationId == null || scenarioScopeState.clientCorrelationId.isEmpty()) { + scenarioScopeState.clientCorrelationId = "123"; + } + assertThat(scenarioScopeState.clientCorrelationId).isNotNull(); + } + + @And("I should have error as Transaction already Exists") + public void iShouldHaveErrorAsTransactionAlreadyExists() throws Exception { + assertThat(scenarioScopeState.response).contains("Transaction already exists"); + } + + @When("I call gsma transaction api with client correlation id expected status {int}") + public void sendRequestToGSMAEndpointSavings(int status) throws JsonProcessingException { + gsmaTransferStepDef.setTenantLoan("goriila"); + gsmaTransferStepDef.callCreatePayerClientEndpoint(); + gsmaTransferStepDef.callCreateSavingsProductEndpoint(); + gsmaTransferStepDef.callApproveSavingsEndpoint("approve"); + gsmaTransferStepDef.callSavingsActivateEndpoint("activate"); + gsmaTransferStepDef.callDepositAccountEndpoint("deposit", 11); + gsmaTransferStepDef.setHeaders("mifos", "gorilla", 11); + RequestSpecification requestSpec = Utils.getDefaultSpec(); + requestSpec.header(X_CORRELATIONID, scenarioScopeState.clientCorrelationId); + requestSpec.header(CONTENT_TYPE, CONTENT_TYPE_VALUE); + + gsmaTransferDef.gsmaTransferBody = gsmaTransferDef.setGsmaTransactionBody("S"); + + gsmaTransferDef.gsmaTransactionResponse = RestAssured.given(requestSpec).baseUri(gsmaConfig.channelConnectorBaseUrl) + .body(gsmaTransferDef.gsmaTransferBody).expect().spec(new ResponseSpecBuilder().expectStatusCode(status).build()).when() + .post(gsmaConfig.gsmaEndpoint).andReturn().asString(); + + logger.info("GSMA Transaction Response: " + gsmaTransferDef.gsmaTransactionResponse); + assertThat(gsmaTransferDef.gsmaTransactionResponse).isNotEmpty(); + } + + @When("I call gsma transaction to fail with client correlation id expected status {int}") + public void iCallGsmaTransactionToFailWithClientCorrelationIdExpectedStatus(int status) throws JsonProcessingException { + RequestSpecification requestSpec = Utils.getDefaultSpec(); + requestSpec.header("amsName", gsmaTransferDef.amsName); + requestSpec.header("accountHoldingInstitutionId", gsmaTransferDef.acccountHoldingInstitutionId); + requestSpec.header(X_CORRELATIONID, scenarioScopeState.clientCorrelationId); + requestSpec.header(CONTENT_TYPE, CONTENT_TYPE_VALUE); + + gsmaTransferDef.gsmaTransferBody = gsmaTransferDef.setGsmaTransactionBody("S"); + + gsmaTransferDef.gsmaTransactionResponse = RestAssured.given(requestSpec).baseUri(gsmaConfig.channelConnectorBaseUrl) + .body(gsmaTransferDef.gsmaTransferBody).expect().spec(new ResponseSpecBuilder().expectStatusCode(status).build()).when() + .post(gsmaConfig.gsmaEndpoint).andReturn().asString(); + + logger.info("GSMA Transaction Response: " + gsmaTransferDef.gsmaTransactionResponse); + } + + @When("I call inbound transfer api with client correlation id expected status {int}") + public void iCallInboundTransferApiWithClientCorrelationIdExpectedStatus(int expectedStatus) { + RequestSpecification requestSpec = Utils.getDefaultSpec(scenarioScopeState.tenant); + requestSpec.header(Utils.X_CORRELATIONID, scenarioScopeState.clientCorrelationId); + scenarioScopeState.response = RestAssured.given(requestSpec).baseUri(channelConnectorConfig.channelConnectorContactPoint) + .body(scenarioScopeState.inboundTransferMockReq).expect() + .spec(new ResponseSpecBuilder().expectStatusCode(expectedStatus).build()).when() + .post(channelConnectorConfig.transferEndpoint).andReturn().asString(); + + logger.info("Inbound transfer Response: {}", scenarioScopeState.response); + } + + @When("I call Inbound transaction Req api with client correlation id expected status {int}") + public void iCallInboundTransferReqApiWithClientCorrelationIdExpectedStatus(int expectedStatus) { + RequestSpecification requestSpec = Utils.getDefaultSpec(scenarioScopeState.tenant); + requestSpec.header(Utils.X_CORRELATIONID, scenarioScopeState.clientCorrelationId); + scenarioScopeState.response = RestAssured.given(requestSpec).baseUri(channelConnectorConfig.channelConnectorContactPoint) + .body(scenarioScopeState.inboundTransferMockReq).expect() + .spec(new ResponseSpecBuilder().expectStatusCode(expectedStatus).build()).when() + .post(channelConnectorConfig.transferReqEndpoint).andReturn().asString(); + + logger.info("Inbound transfer Response: {}", scenarioScopeState.response); + } + + @Given("I create a new clientCorrelationId") + public void iCreateANewClientCorrelationId() { + scenarioScopeState.clientCorrelationId = UUID.randomUUID().toString(); + assertThat(scenarioScopeState.clientCorrelationId).isNotNull(); + } +} diff --git a/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/cucumber/stepdef/IdentityMapperStepDef.java b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/cucumber/stepdef/IdentityMapperStepDef.java new file mode 100644 index 000000000..954c01c91 --- /dev/null +++ b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/cucumber/stepdef/IdentityMapperStepDef.java @@ -0,0 +1,704 @@ +package org.mifos.integrationtest.cucumber.stepdef; + +import static com.github.tomakehurst.wiremock.client.WireMock.equalTo; +import static com.github.tomakehurst.wiremock.client.WireMock.getAllServeEvents; +import static com.github.tomakehurst.wiremock.client.WireMock.matchingJsonPath; +import static com.github.tomakehurst.wiremock.client.WireMock.putRequestedFor; +import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo; +import static com.github.tomakehurst.wiremock.client.WireMock.verify; +import static com.google.common.truth.Truth.assertThat; +import static java.util.concurrent.TimeUnit.SECONDS; +import static org.awaitility.Awaitility.await; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import com.github.tomakehurst.wiremock.client.VerificationException; +import com.github.tomakehurst.wiremock.stubbing.ServeEvent; +import io.cucumber.core.internal.com.fasterxml.jackson.core.JsonProcessingException; +import io.cucumber.core.internal.com.fasterxml.jackson.databind.JsonNode; +import io.cucumber.java.en.And; +import io.cucumber.java.en.Given; +import io.cucumber.java.en.Then; +import io.cucumber.java.en.When; +import io.restassured.RestAssured; +import io.restassured.builder.ResponseSpecBuilder; +import io.restassured.specification.RequestSpecification; +import java.io.File; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.UUID; +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; +import org.mifos.connector.common.channel.dto.TransactionChannelRequestDTO; +import org.mifos.connector.common.identityaccountmapper.dto.AccountMapperRequestDTO; +import org.mifos.connector.common.identityaccountmapper.dto.BeneficiaryDTO; +import org.mifos.integrationtest.common.Utils; +import org.springframework.beans.factory.annotation.Autowired; + +public class IdentityMapperStepDef extends BaseStepDef { + + @Autowired + ScenarioScopeState scenarioScopeState; + private static String identityMapperBody = null; + private static AccountMapperRequestDTO registerBeneficiaryBody = null; + private static AccountMapperRequestDTO addPaymentModalityBody = null; + private static AccountMapperRequestDTO updatePaymentModalityBody = null; + private static String payeeIdentity; + private static int getApiCount = 0; + private static String fieldName = "numberFailedCases"; + private static String fieldValue = "0"; + private static String requestId; + private static final String payeeIdentityAccountLookup = "003001003873110196"; + private static TransactionChannelRequestDTO transactionChannelRequestDTO = new TransactionChannelRequestDTO(); + private static String transactionId; + private static String tenant; + private static String payeeDfspId; + private static String sourceBBID = "SocialWelfare"; + private static List beneficiaryList = new ArrayList<>(); + private static AccountMapperRequestDTO batchAccountLookupBody = null; + private static String callbackBody; + private static String fetchBeneficiaryBody; + private static Map paymentModalityList = new HashMap<>(); + + static { + paymentModalityList.put("ACCOUNT_ID", "00"); + paymentModalityList.put("MSISDN", "01"); + paymentModalityList.put("VIRTUAL_ADDRESS", "02"); + paymentModalityList.put("WALLET_ID", "03"); + paymentModalityList.put("VOUCHER", "04"); + } + + @When("I call the register beneficiary API with expected status of {int} and stub {string}") + public void iCallTheRegisterBeneficiaryAPIWithExpectedStatusOf(int expectedStatus, String stub) { + RequestSpecification requestSpec = Utils.getDefaultSpec(); + scenarioScopeState.response = RestAssured.given(requestSpec).header("Content-Type", "application/json") + .header("X-Registering-Institution-ID", scenarioScopeState.registeringInstituteId) + .header("X-CallbackURL", identityMapperConfig.callbackURL + stub).baseUri(identityMapperConfig.identityMapperContactPoint) + .body(registerBeneficiaryBody).expect().spec(new ResponseSpecBuilder().expectStatusCode(expectedStatus).build()).when() + .post(identityMapperConfig.registerBeneficiaryEndpoint).andReturn().asString(); + + logger.info("Identity Mapper Response: {}", scenarioScopeState.response); + } + + @When("I call the add payment modality API with expected status of {int} and stub {string}") + public void iCallTheAddPaymentModalityAPIWithExpectedStatusOf(int expectedStatus, String stub) { + RequestSpecification requestSpec = Utils.getDefaultSpec(); + scenarioScopeState.response = RestAssured.given(requestSpec).header("Content-Type", "application/json") + .header("X-Registering-Institution-ID", sourceBBID).header("X-CallbackURL", identityMapperConfig.callbackURL + stub) + .baseUri(identityMapperConfig.identityMapperContactPoint).body(addPaymentModalityBody).expect() + .spec(new ResponseSpecBuilder().expectStatusCode(expectedStatus).build()).when() + .post(identityMapperConfig.addPaymentModalityEndpoint).andReturn().asString(); + + logger.info("Identity Mapper Response: {}", scenarioScopeState.response); + } + + @When("I call the update payment modality API with expected status of {int} and stub {string}") + public void iCallTheUpdatePaymentModalityAPIWithExpectedStatusOf(int expectedStatus, String stub) { + RequestSpecification requestSpec = Utils.getDefaultSpec(); + scenarioScopeState.response = RestAssured.given(requestSpec).header("Content-Type", "application/json") + .header("X-Registering-Institution-ID", sourceBBID).header("X-CallbackURL", identityMapperConfig.callbackURL + stub) + .baseUri(identityMapperConfig.identityMapperContactPoint).body(updatePaymentModalityBody).expect() + .spec(new ResponseSpecBuilder().expectStatusCode(expectedStatus).build()).when() + .put(identityMapperConfig.updatePaymentModalityEndpoint).andReturn().asString(); + + logger.info("Identity Mapper Response: {}", scenarioScopeState.response); + } + + @And("I create an IdentityMapperDTO for Register Beneficiary") + public void iCreateAnIdentityMapperDTOForRegisterBeneficiary() { + List beneficiaryDTOList = new ArrayList<>(); + payeeIdentity = generateUniqueNumber(12); + BeneficiaryDTO beneficiaryDTO = new BeneficiaryDTO(payeeIdentity, null, null, null); + beneficiaryDTOList.add(beneficiaryDTO); + requestId = generateUniqueNumber(12); + registerBeneficiaryBody = new AccountMapperRequestDTO(requestId, sourceBBID, beneficiaryDTOList); + + } + + @And("I create an IdentityMapperDTO for Add Payment Modality") + public void iCreateAnIdentityMapperDTOForAddPaymentModality() { + List beneficiaryDTOList = new ArrayList<>(); + + BeneficiaryDTO beneficiaryDTO = new BeneficiaryDTO(payeeIdentity, "00", "12345678", "gorilla"); + beneficiaryDTOList.add(beneficiaryDTO); + requestId = generateUniqueNumber(12); + addPaymentModalityBody = new AccountMapperRequestDTO(requestId, sourceBBID, beneficiaryDTOList); + + } + + @And("I create an IdentityMapperDTO for Update Payment Modality") + public void iCreateAnIdentityMapperDTOForUpdatePaymentModality() { + List beneficiaryDTOList = new ArrayList<>(); + + BeneficiaryDTO beneficiaryDTO = new BeneficiaryDTO(payeeIdentity, "00", "LB28369763644714781256435714", "test"); + beneficiaryDTOList.add(beneficiaryDTO); + requestId = generateUniqueNumber(10); + updatePaymentModalityBody = new AccountMapperRequestDTO(requestId, sourceBBID, beneficiaryDTOList); + } + + @Then("I call the account lookup API with expected status of {int} and stub {string}") + public void iCallTheAccountLookupAPIWithExpectedStatusOf(int expectedStatus, String stub) { + RequestSpecification requestSpec = Utils.getDefaultSpec(); + scenarioScopeState.response = RestAssured.given(requestSpec).header("Content-Type", "application/json") + .header("X-Registering-Institution-ID", sourceBBID).header("X-CallbackURL", identityMapperConfig.callbackURL + stub) + .queryParam("payeeIdentity", payeeIdentity).queryParam("paymentModality", "00") + .queryParam("requestId", generateUniqueNumber(10)).baseUri(identityMapperConfig.identityMapperContactPoint).expect() + .spec(new ResponseSpecBuilder().expectStatusCode(expectedStatus).build()).when() + .get(identityMapperConfig.accountLookupEndpoint).andReturn().asString(); + + logger.info("Identity Mapper Response: {}", scenarioScopeState.response); + } + + @Then("I call the account lookup API {int} times with expected status of {int} and stub {string}") + public void iCallTheAccountLookupAPITimesWithExpectedStatusOf(int count, int expectedStatus, String endpoint) { + getApiCount = count; + RequestSpecification requestSpec = Utils.getDefaultSpec(); + // int i=0; + for (int i = 1; i < count; i++) { + + scenarioScopeState.response = RestAssured.given(requestSpec).header("Content-Type", "application/json") + .header("X-Registering-Institution-ID", sourceBBID).header("X-CallbackURL", identityMapperConfig.callbackURL + endpoint) + .queryParam("payeeIdentity", payeeIdentity).queryParam("paymentModality", "00") + .queryParam("requestId", generateUniqueNumber(10)).queryParam("sourceBBID", sourceBBID) + .baseUri(identityMapperConfig.identityMapperContactPoint).expect() + .spec(new ResponseSpecBuilder().expectStatusCode(expectedStatus).build()).when() + .get(identityMapperConfig.accountLookupEndpoint).andReturn().asString(); + + } + } + + @Then("I should be able to verify that the {string} method to {string} endpoint received a request with required parameter in body") + public void iShouldBeAbleToVerifyThatTheMethodToEndpointReceivedRequestWithASpecificBody(String httpmethod, String endpoint) { + await().atMost(awaitMost, SECONDS).untilAsserted(() -> { + try { + verify(putRequestedFor(urlEqualTo(endpoint)).withRequestBody(matchingJsonPath("$.registerRequestID", equalTo(requestId)))); + verify(putRequestedFor(urlEqualTo(endpoint)).withRequestBody(matchingJsonPath("$.numberFailedCases", equalTo("0")))); + assertTrue(true); + } catch (VerificationException e) { + assertTrue(false);// failure + } + }); + } + + @Then("I should be able to verify that the {string} method to {string} endpoint received a request with same payeeIdentity") + public void iShouldBeAbleToVerifyThatTheMethodToEndpointReceivedARequestWithSamePayeeIdentity(String httpmethod, String endpoint) { + await().atMost(awaitMost, SECONDS).untilAsserted(() -> { + try { + verify(putRequestedFor(urlEqualTo(endpoint)).withRequestBody(matchingJsonPath("$.payeeIdentity", equalTo(payeeIdentity)))); + assertTrue(true); + } catch (VerificationException e) { + assertTrue(false); + } + }); + } + + /* + * public static String generateUniqueNumber(int length) { Random rand = new Random(); //long timestamp = + * System.currentTimeMillis(); long randomLong = rand.nextLong(100000000); //String uniqueNumber = timestamp + "" + + * randomLong; //return uniqueNumber.substring(0, length); return randomLong } + */ + public String generateUniqueNumber(int length) { + StringBuilder sb = new StringBuilder(); + while (sb.length() < length) { + sb.append(UUID.randomUUID().toString().replaceAll("-", "")); + } + return sb.substring(0, length); + } + + @When("I call the register beneficiary API with expected status of {int}") + public void iCallTheRegisterBeneficiaryAPIWithAMSISDNAndDFSPIDAs(int expectedStatus) { + RequestSpecification requestSpec = Utils.getDefaultSpec(); + scenarioScopeState.response = RestAssured.given(requestSpec).header("Content-Type", "application/json") + .header("X-Registering-Institution-ID", sourceBBID) + .header("X-CallbackURL", identityMapperConfig.callbackURL + "/registerBeneficiary") + .baseUri(identityMapperConfig.identityMapperContactPoint).body(registerBeneficiaryBody).expect() + .spec(new ResponseSpecBuilder().expectStatusCode(expectedStatus).build()).when() + .post(identityMapperConfig.registerBeneficiaryEndpoint).andReturn().asString(); + + logger.info("Identity Mapper Response: {}", scenarioScopeState.response); + } + + @When("I create an IdentityMapperDTO for registering beneficiary with {string} as DFSPID") + public void iCreateAnIdentityMapperDTOForRegisteringBeneficiaryWithAsDFSPID(String dfspId) { + payeeDfspId = dfspId; + + List beneficiaryDTOList = new ArrayList<>(); + + BeneficiaryDTO beneficiaryDTO = new BeneficiaryDTO(payeeIdentityAccountLookup, "01", "12345678", dfspId); + beneficiaryDTOList.add(beneficiaryDTO); + requestId = generateUniqueNumber(10); + registerBeneficiaryBody = new AccountMapperRequestDTO(requestId, "SocialWelfare", beneficiaryDTOList); + } + + @Then("I can call ops app transfer api with expected status of {int}") + public void iCanCallOpsAppTransferApiWithExpectedStatusOf(int expectedStatus) { + RequestSpecification requestSpec = Utils.getDefaultSpec(tenant); + requestSpec.header("transactionId", transactionId); + scenarioScopeState.response = RestAssured.given(requestSpec).baseUri(channelConnectorConfig.channelConnectorContactPoint) + .body(scenarioScopeState.inboundTransferMockReq).expect() + .spec(new ResponseSpecBuilder().expectStatusCode(expectedStatus).build()).when() + .post(channelConnectorConfig.transferEndpoint).andReturn().asString(); + + logger.info("Inbound transfer Response: {}", scenarioScopeState.response); + } + + @And("I can assert the payee DFSPID is same as used to register beneficiary id type from response") + public void iCanAssertThePayeePartyIdTypeFromResponse() { + String payeeDfsp = null; + try { + JSONArray jsonArray = new JSONArray(scenarioScopeState.response); + JSONObject transactionStatus = jsonArray.getJSONObject(0); + payeeDfsp = transactionStatus.get("payeeDfspId").toString(); + + } catch (Exception e) { + logger.error("Error parsing the response", e); + } + assertThat(payeeDfspId).isEqualTo(payeeDfsp); + } + + @When("I call the batch transactions endpoint with expected response status of {int}") + public void callBatchTransactionsEndpoint(int expectedStatus) { + RequestSpecification requestSpec = Utils.getDefaultSpec(scenarioScopeState.tenant); + requestSpec.header("filename", scenarioScopeState.filename); + requestSpec.header("X-CorrelationID", UUID.randomUUID().toString()); + requestSpec.queryParam("type", "CSV"); + scenarioScopeState.response = RestAssured.given(requestSpec).baseUri(bulkProcessorConfig.bulkProcessorContactPoint) + .contentType("multipart/form-data") + .multiPart("file", new File(Utils.getAbsoluteFilePathToResource(scenarioScopeState.filename))).expect() + .spec(new ResponseSpecBuilder().expectStatusCode(expectedStatus).build()).when() + .post(bulkProcessorConfig.bulkTransactionEndpoint).andReturn().asString(); + + logger.info("Batch Transactions API Response: " + scenarioScopeState.response); + } + + @Then("I should be able to parse batch id from response") + public void iShouldBeAbleToParseBatchIdFromResponse() { + JSONObject jsonObject = null; + try { + jsonObject = new JSONObject(scenarioScopeState.response); + } catch (JSONException e) { + throw new RuntimeException(e); + } + String pollingPath = null; + try { + pollingPath = jsonObject.getString("PollingPath"); + } catch (JSONException e) { + throw new RuntimeException(e); + } + // Extract the batch ID + scenarioScopeState.batchId = pollingPath.substring(pollingPath.lastIndexOf("/") + 1); + } + + @When("I call the batch details API with expected response status of {int}") + public void callBatchDetailsAPI(int expectedStatus) { + RequestSpecification requestSpec = Utils.getDefaultSpec(scenarioScopeState.tenant); + if (authEnabled) { + requestSpec.header("Authorization", "Bearer " + scenarioScopeState.accessToken); + } + requestSpec.queryParam("batchId", scenarioScopeState.batchId); + + scenarioScopeState.response = RestAssured.given(requestSpec).baseUri(operationsAppConfig.operationAppContactPoint).expect() + .spec(new ResponseSpecBuilder().expectStatusCode(expectedStatus).build()).when() + .get(operationsAppConfig.batchDetailsEndpoint).andReturn().asString(); + + logger.info("Batch Details Response: " + scenarioScopeState.response); + } + + @When("I create an IdentityMapperDTO for adding {int} beneficiary") + public void iCreateAnIdentityMapperDTOForAddingBeneficiary(int count) { + List beneficiaryDTOList = new ArrayList<>(); + for (int i = 0; i < count; i++) { + BeneficiaryDTO beneficiaryDTO = new BeneficiaryDTO(generateUniqueNumber(12), null, null, null); + beneficiaryList.add(beneficiaryDTO); + beneficiaryDTOList.add(beneficiaryDTO); + } + requestId = generateUniqueNumber(12); + registerBeneficiaryBody = new AccountMapperRequestDTO(requestId, sourceBBID, beneficiaryDTOList); + } + + @When("I call the register beneficiary API with {string} as registering institution id expected status of {int} and stub {string}") + public void iCallTheRegisterBeneficiaryAPIWithAsRegisteringInstitutionIdExpectedStatusOf(String registeringInstitutionId, + int expectedStatus, String stub) { + RequestSpecification requestSpec = Utils.getDefaultSpec(); + scenarioScopeState.response = RestAssured.given(requestSpec).header("Content-Type", "application/json") + .header("X-Registering-Institution-ID", registeringInstitutionId) + .header("X-CallbackURL", identityMapperConfig.callbackURL + stub).baseUri(identityMapperConfig.identityMapperContactPoint) + .body(registerBeneficiaryBody).expect().spec(new ResponseSpecBuilder().expectStatusCode(expectedStatus).build()).when() + .post(identityMapperConfig.registerBeneficiaryEndpoint).andReturn().asString(); + + logger.info("Identity Mapper Response: {}", scenarioScopeState.response); + } + + @Then("I call bulk account lookup API with these {int} beneficiaries and {string} as registering institution id and stub {string}") + public void iCallBulkAccountLookupAPIWithTheseBeneficiariesAndAsRegisteringInstitutionId(int noOfBeneficiaries, + String registeringInstitutionId, String stub) { + RequestSpecification requestSpec = Utils.getDefaultSpec(); + scenarioScopeState.response = RestAssured.given(requestSpec).header("Content-Type", "application/json") + .header("X-Registering-Institution-ID", registeringInstitutionId) + .header("X-CallbackURL", identityMapperConfig.callbackURL + stub).baseUri(identityMapperConfig.identityMapperContactPoint) + .body(batchAccountLookupBody).expect().spec(new ResponseSpecBuilder().expectStatusCode(202).build()).when() + .post(identityMapperConfig.batchAccountLookupEndpoint).andReturn().asString(); + + logger.info("Identity Mapper Response: {}", scenarioScopeState.response); + } + + @And("I create request body for batch account lookup API") + public void iCreateRequestBodyForBatchAccountLookupAPI() { + batchAccountLookupBody = null; + requestId = generateUniqueNumber(12); + batchAccountLookupBody = new AccountMapperRequestDTO(requestId, "", beneficiaryList); + } + + @And("I should be able to verify that the {string} method to {string} receive {int} request") + public void iShouldBeAbleToVerifyThatTheMethodToReceiveRequest(String httpMethod, String stub, int noOfRequest) + throws JsonProcessingException { + await().atMost(awaitMost, SECONDS).untilAsserted(() -> { + + List allServeEvents = getAllServeEvents(); + + for (int i = 0; i < allServeEvents.size(); i++) { + ServeEvent request = allServeEvents.get(i); + + if (!(request.getRequest().getBodyAsString()).isEmpty()) { + try { + JsonNode rootNode = objectMapper.readTree(request.getRequest().getBodyAsString()); + String requestID = rootNode.get("requestID").asText(); + + if (requestId.equals(requestID)) { + callbackBody = request.getRequest().getBodyAsString(); + } + } catch (Exception e) { + logger.debug(e.getMessage()); + } + + } + } + int count = 0; + try { + JsonNode rootNode = objectMapper.readTree(callbackBody); + + JsonNode beneficiaryDTOList = rootNode.get("beneficiaryDTOList"); + if (beneficiaryDTOList.isArray()) { + for (JsonNode beneficiary : beneficiaryDTOList) { + count++; + } + } + } catch (Exception e) { + logger.debug(e.getMessage()); + } + assertThat(count).isEqualTo(noOfRequest); + beneficiaryList = new ArrayList<>(); + }); + } + + @When("I create an IdentityMapperDTO for {int} Register Beneficiary with payment modality as {string}") + public void iCreateAnIdentityMapperDTOForRegisterBeneficiaryWithPaymentModalityAs(int noOfBeneficiary, String paymentModality) { + List beneficiaryDTOList = new ArrayList<>(); + scenarioScopeState.registeredBeneficiary = new ArrayList<>(); + for (int i = 0; i < noOfBeneficiary; i++) { + String payeeIdentity = generateUniqueNumber(12); + scenarioScopeState.registeredBeneficiary.add(payeeIdentity); + BeneficiaryDTO beneficiaryDTO = new BeneficiaryDTO(payeeIdentity, getPaymentModality(paymentModality), "12345678", "ABCDEF"); + beneficiaryDTOList.add(beneficiaryDTO); + } + requestId = generateUniqueNumber(10); + registerBeneficiaryBody = new AccountMapperRequestDTO(requestId, sourceBBID, beneficiaryDTOList); + } + + public String getPaymentModality(String paymentModality) { + return paymentModalityList.get(paymentModality); + } + + @When("I call the update beneficiary API with expected status of {int} and stub {string}") + public void iCallTheUpdateBeneficiaryAPIWithExpectedStatusOfAndStub(int expectedStatus, String stub) { + RequestSpecification requestSpec = Utils.getDefaultSpec(); + scenarioScopeState.response = RestAssured.given(requestSpec).header("Content-Type", "application/json") + .header("X-Registering-Institution-ID", sourceBBID).header("X-CallbackURL", identityMapperConfig.callbackURL + stub) + .baseUri(identityMapperConfig.identityMapperContactPoint).body(registerBeneficiaryBody).expect() + .spec(new ResponseSpecBuilder().expectStatusCode(expectedStatus).build()).when() + .put(identityMapperConfig.registerBeneficiaryEndpoint).andReturn().asString(); + + logger.info("Identity Mapper Response: {}", scenarioScopeState.response); + + } + + @When("I create an IdentityMapperDTO for {int} update Beneficiary with payment modality as {string}") + public void iCreateAnIdentityMapperDTOForUpdateBeneficiaryWithPaymentModalityAs(int noOfBeneficiary, String paymentModality) { + List beneficiaryDTOList = new ArrayList<>(); + for (int i = 0; i < noOfBeneficiary; i++) { + BeneficiaryDTO beneficiaryDTO = registerBeneficiaryBody.getBeneficiaries().get(i); + beneficiaryDTO.setPaymentModality(getPaymentModality(paymentModality)); + // BeneficiaryDTO beneficiaryDTO = new BeneficiaryDTO("94049169714828912115", + // getPaymentModality(paymentModality), "12345678", "ABCDEF"); + beneficiaryDTOList.add(beneficiaryDTO); + } + requestId = generateUniqueNumber(10); + registerBeneficiaryBody = new AccountMapperRequestDTO(requestId, sourceBBID, beneficiaryDTOList); + } + + @When("I create an IdentityMapperDTO for {int} update Beneficiary with banking institution code as {string}") + public void iCreateAnIdentityMapperDTOForUpdateBeneficiaryWithBankingInstitutionCodeAs(int noOfBeneficiary, + String bankingInstitutionCode) { + List beneficiaryDTOList = new ArrayList<>(); + for (int i = 0; i < noOfBeneficiary; i++) { + BeneficiaryDTO beneficiaryDTO = registerBeneficiaryBody.getBeneficiaries().get(i); + beneficiaryDTO.setBankingInstitutionCode(bankingInstitutionCode); + // BeneficiaryDTO beneficiaryDTO = new BeneficiaryDTO("94049169714828912115","00", "12345678", + // bankingInstitutionCode); + beneficiaryDTOList.add(beneficiaryDTO); + } + requestId = generateUniqueNumber(10); + registerBeneficiaryBody = new AccountMapperRequestDTO(requestId, sourceBBID, beneficiaryDTOList); + } + + @When("I create an IdentityMapperDTO for {int} update Beneficiary with financial address code as {string}") + public void iCreateAnIdentityMapperDTOForUpdateBeneficiaryWithFinancialAddressCodeAs(int noOfBeneficiary, String financialAddress) { + List beneficiaryDTOList = new ArrayList<>(); + for (int i = 0; i < noOfBeneficiary; i++) { + BeneficiaryDTO beneficiaryDTO = registerBeneficiaryBody.getBeneficiaries().get(i); + beneficiaryDTO.setFinancialAddress(financialAddress); + // BeneficiaryDTO beneficiaryDTO = new BeneficiaryDTO("94049169714828912115","00", "12345678", + // bankingInstitutionCode); + beneficiaryDTOList.add(beneficiaryDTO); + } + requestId = generateUniqueNumber(10); + registerBeneficiaryBody = new AccountMapperRequestDTO(requestId, sourceBBID, beneficiaryDTOList); + } + + @Then("I will call the fetch beneficiary API with expected status of {int}") + public void iWillCallTheFetchBeneficiaryAPIWithExpectedStatusOf(int expectedStatus) { + RequestSpecification requestSpec = Utils.getDefaultSpec(); + scenarioScopeState.response = RestAssured.given(requestSpec).header("Content-Type", "application/json") + .header("X-Registering-Institution-ID", sourceBBID).baseUri(identityMapperConfig.identityMapperContactPoint).expect() + .spec(new ResponseSpecBuilder().expectStatusCode(expectedStatus).build()).when() + .get(identityMapperConfig.fetchBeneficiaryEndpoint + "/" + payeeIdentity).andReturn().asString(); + + fetchBeneficiaryBody = scenarioScopeState.response; + + logger.info("Identity Mapper Response: {}", scenarioScopeState.response); + } + + @And("I will assert the fields from fetch beneficiary response") + public void iWillAssertTheFieldsFromFetchBeneficiaryResponse() { + try { + JsonNode rootNode = objectMapper.readTree(fetchBeneficiaryBody); + + String payeeIdentityResponse = rootNode.get("payeeIdentity").asText(); + String registeringInstitutionIdResponse = rootNode.get("registeringInstitutionId").asText(); + assertThat(payeeIdentityResponse).isEqualTo(payeeIdentity); + assertThat(registeringInstitutionIdResponse).isEqualTo(sourceBBID); + } catch (Exception e) { + logger.debug("{}", e.getMessage()); + } + } + + @Given("I create an IdentityMapperDTO for Register Beneficiary from csv file") + public void iCreateAnIdentityMapperDTOForRegisterBeneficiaryFromCsvFile() { + List beneficiaryDTOList = new ArrayList<>(); + payeeIdentity = generateUniqueNumber(16); + BeneficiaryDTO beneficiaryDTO = new BeneficiaryDTO("3001003873110196", "00", null, "gorilla"); + beneficiaryDTOList.add(beneficiaryDTO); + beneficiaryDTO = new BeneficiaryDTO("3001003874120160", "00", null, "gorilla"); + beneficiaryDTOList.add(beneficiaryDTO); + beneficiaryDTO = new BeneficiaryDTO("3001003873110195", "00", null, "rhino"); + beneficiaryDTOList.add(beneficiaryDTO); + requestId = generateUniqueNumber(12); + registerBeneficiaryBody = new AccountMapperRequestDTO(requestId, sourceBBID, beneficiaryDTOList); + } + + @And("I create a IdentityMapperDTO for registering beneficiary") + public void iCreateAIdentityMapperDTOForRegisteringBeneficiary() { + List beneficiaryDTOList = new ArrayList<>(); + String[] payeeFspArray = { "payeefsp1", "payeefsp2", "payeefsp3" }; + int fspIndex = 0; + for (String payeeIdentifier : scenarioScopeState.payeeIdentifiers) { + if (fspIndex >= payeeFspArray.length) { + fspIndex = 0; + } + String payeeFsp = payeeFspArray[fspIndex]; + BeneficiaryDTO beneficiaryDTO = new BeneficiaryDTO(payeeIdentifier, "00", "1234", payeeFspConfig.getPayeeFsp(payeeFsp)); + beneficiaryDTOList.add(beneficiaryDTO); + fspIndex++; + } + requestId = generateUniqueNumber(12); + registerBeneficiaryBody = new AccountMapperRequestDTO(requestId, sourceBBID, beneficiaryDTOList); + } + + @And("I create a IdentityMapperDTO for registering payee with IAM") + public void iCreateAIdentityMapperDTOForRegisteringPayee() { + List beneficiaryDTOList = new ArrayList<>(); + String payeeFsp = "payeefsp3"; + String[] financialAddressArray = { "1234", "1235", "1236" }; + int fspIndex = 0; + Set payeeIdentifiers = new HashSet<>(scenarioScopeState.payeeIdentifiers); + for (String payeeIdentifier : payeeIdentifiers) { + BeneficiaryDTO beneficiaryDTO = new BeneficiaryDTO(payeeIdentifier, "00", financialAddressArray[fspIndex], + payeeFspConfig.getPayeeFsp(payeeFsp)); + beneficiaryDTOList.add(beneficiaryDTO); + fspIndex++; + } + requestId = generateUniqueNumber(12); + registerBeneficiaryBody = new AccountMapperRequestDTO(requestId, sourceBBID, beneficiaryDTOList); + } + + @And("I should be able to verify that the {string} method to {string} endpoint received a request with successfull registration") + public void iShouldBeAbleToVerifyThatTheMethodToEndpointReceivedARequestWithSuccessfullRegistration(String httpMethod, String stub) { + await().atMost(awaitMost, SECONDS).untilAsserted(() -> { + + List allServeEvents = getAllServeEvents(); + + for (int i = 0; i < allServeEvents.size(); i++) { + ServeEvent request = allServeEvents.get(i); + + if (!(request.getRequest().getBodyAsString()).isEmpty()) { + try { + JsonNode rootNode = objectMapper.readTree(request.getRequest().getBodyAsString()); + String requestID = rootNode.get("requestID").asText(); + + if (requestId.equals(requestID)) { + callbackBody = request.getRequest().getBodyAsString(); + } + } catch (Exception e) { + logger.debug(e.getMessage()); + } + + } + } + int count = 0; + try { + JsonNode rootNode = objectMapper.readTree(callbackBody); + + JsonNode beneficiaryDTOList = rootNode.get("beneficiaryDTOList"); + if (beneficiaryDTOList.isArray()) { + for (JsonNode beneficiary : beneficiaryDTOList) { + count++; + } + } + } catch (Exception e) { + logger.debug(e.getMessage()); + } + assertThat(count).isEqualTo(0); + beneficiaryList = new ArrayList<>(); + }); + } + + @When("I create an IdentityMapperDTO for {int} Register Beneficiary with payment modality as {string} and {int} with invalid payment modality") + public void iCreateAnIdentityMapperDTOForRegisterBeneficiaryWithPaymentModalityAsAndWithInvalidPaymentModality(int noOfBeneficiary, + String paymentModality, int arg2) { + List beneficiaryDTOList = new ArrayList<>(); + for (int i = 0; i < noOfBeneficiary; i++) { + BeneficiaryDTO beneficiaryDTO = new BeneficiaryDTO(generateUniqueNumber(12), getPaymentModality(paymentModality), "12345678", + "ABCDEF"); + beneficiaryDTOList.add(beneficiaryDTO); + } + BeneficiaryDTO beneficiaryDTO = new BeneficiaryDTO(generateUniqueNumber(22), "11", "12345678", "ABCDEF"); + beneficiaryDTOList.add(beneficiaryDTO); + requestId = generateUniqueNumber(10); + registerBeneficiaryBody = new AccountMapperRequestDTO(requestId, sourceBBID, beneficiaryDTOList); + } + + @When("I create an IdentityMapperDTO for {int} Register Beneficiary with payment modality as {string} and {int} with invalid functionalID") + public void iCreateAnIdentityMapperDTOForRegisterBeneficiaryWithPaymentModalityAsAndWithInvalidFunctionalID(int noOfBeneficiary, + String paymentModality, int arg2) { + List beneficiaryDTOList = new ArrayList<>(); + for (int i = 0; i < noOfBeneficiary; i++) { + BeneficiaryDTO beneficiaryDTO = new BeneficiaryDTO(generateUniqueNumber(12), getPaymentModality(paymentModality), "12345678", + "ABCDEF"); + beneficiaryDTOList.add(beneficiaryDTO); + } + BeneficiaryDTO beneficiaryDTO = new BeneficiaryDTO(generateUniqueNumber(26), "11", "12345678", "ABCDEF"); + beneficiaryDTOList.add(beneficiaryDTO); + requestId = generateUniqueNumber(10); + registerBeneficiaryBody = new AccountMapperRequestDTO(requestId, sourceBBID, beneficiaryDTOList); + } + + @Then("I should be able to verify that the {string} method to {string} endpoint received a request with no of failed cases as {int}") + public void iShouldBeAbleToVerifyThatTheMethodToEndpointReceivedARequestWithNoOfFailedCasesAs(String method, String endpoint, + int noOfFailedCases) { + await().atMost(awaitMost, SECONDS).untilAsserted(() -> { + try { + verify(putRequestedFor(urlEqualTo(endpoint)).withRequestBody(matchingJsonPath("$.registerRequestID", equalTo(requestId)))); + verify(putRequestedFor(urlEqualTo(endpoint)) + .withRequestBody(matchingJsonPath("$.numberFailedCases", equalTo(String.valueOf(noOfFailedCases))))); + assertTrue(true); + } catch (VerificationException e) { + assertTrue(false);// failure + } + }); + } + + @When("I create an IdentityMapperDTO for {int} Register Beneficiary with no payment modality") + public void iCreateAnIdentityMapperDTOForRegisterBeneficiaryWithNoPaymentModality(int noOfBeneficiary) { + List beneficiaryDTOList = new ArrayList<>(); + for (int i = 0; i < noOfBeneficiary; i++) { + BeneficiaryDTO beneficiaryDTO = new BeneficiaryDTO(generateUniqueNumber(12), "04", "", ""); + beneficiaryDTOList.add(beneficiaryDTO); + } + requestId = generateUniqueNumber(10); + registerBeneficiaryBody = new AccountMapperRequestDTO(requestId, sourceBBID, beneficiaryDTOList); + } + + @When("I create an IdentityMapperDTO for {int} update Beneficiary with correct payment modality and {int} with incorrect payment modality") + public void iCreateAnIdentityMapperDTOForUpdateBeneficiaryWithCorrectPaymentModalityAndWithIncorrectPaymentModality( + int correctPaymentModality, int incorrectPaymentModality) { + List beneficiaryDTOList = new ArrayList<>(); + for (int i = 0; i < correctPaymentModality; i++) { + BeneficiaryDTO beneficiaryDTO = registerBeneficiaryBody.getBeneficiaries().get(i); + beneficiaryDTO.setPaymentModality("00"); + beneficiaryDTO.setBankingInstitutionCode("123456"); + beneficiaryDTOList.add(beneficiaryDTO); + } + for (int i = correctPaymentModality; i < correctPaymentModality + incorrectPaymentModality; i++) { + BeneficiaryDTO beneficiaryDTO = registerBeneficiaryBody.getBeneficiaries().get(i); + beneficiaryDTO.setPaymentModality("11"); + beneficiaryDTOList.add(beneficiaryDTO); + } + requestId = generateUniqueNumber(10); + registerBeneficiaryBody = new AccountMapperRequestDTO(requestId, sourceBBID, beneficiaryDTOList); + } + + @When("I create an IdentityMapperDTO for {int} update Beneficiary with correct financial address code and {int} with incorrect Financial address") + public void iCreateAnIdentityMapperDTOForUpdateBeneficiaryWithCorrectFinancialAddressCodeAndWithIncorrectFinancialAddress( + int correctFinancialAddress, int incorrectFinancialAddress) { + List beneficiaryDTOList = new ArrayList<>(); + for (int i = 0; i < correctFinancialAddress; i++) { + BeneficiaryDTO beneficiaryDTO = registerBeneficiaryBody.getBeneficiaries().get(i); + beneficiaryDTO.setFinancialAddress(generateUniqueNumber(10)); + beneficiaryDTOList.add(beneficiaryDTO); + } + for (int i = correctFinancialAddress; i < correctFinancialAddress + incorrectFinancialAddress; i++) { + BeneficiaryDTO beneficiaryDTO = registerBeneficiaryBody.getBeneficiaries().get(i); + beneficiaryDTO.setFinancialAddress(generateUniqueNumber(40)); + beneficiaryDTOList.add(beneficiaryDTO); + } + requestId = generateUniqueNumber(10); + registerBeneficiaryBody = new AccountMapperRequestDTO(requestId, sourceBBID, beneficiaryDTOList); + } + + @Then("I add the {int} registered beneficiary in the DTO") + public void iAddTheRegisteredBeneficiaryInTheDTO(int noOfRegisteredBeneficiary) { + + } + + @When("I create an IdentityMapperDTO for {int} Register Beneficiary with payment modality as {string} and {int} existing beneficiary") + public void iCreateAnIdentityMapperDTOForRegisterBeneficiaryWithPaymentModalityAsAndExistingBeneficiary(int noOfBeneficiary, + String paymentModality, int noOfRegisteredBeneficiary) { + List beneficiaryDTOList = new ArrayList<>(); + for (int i = 0; i < noOfBeneficiary; i++) { + BeneficiaryDTO beneficiaryDTO = new BeneficiaryDTO(generateUniqueNumber(12), getPaymentModality(paymentModality), "12345678", + "ABCDEF"); + beneficiaryDTOList.add(beneficiaryDTO); + } + for (int i = 0; i < noOfRegisteredBeneficiary; i++) { + BeneficiaryDTO beneficiaryDTO = new BeneficiaryDTO(scenarioScopeState.registeredBeneficiary.get(i), + getPaymentModality(paymentModality), "12345678", "ABCDEF"); + beneficiaryDTOList.add(beneficiaryDTO); + } + requestId = generateUniqueNumber(10); + registerBeneficiaryBody = new AccountMapperRequestDTO(requestId, sourceBBID, beneficiaryDTOList); + } +} diff --git a/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/cucumber/stepdef/InboundStepDef.java b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/cucumber/stepdef/InboundStepDef.java new file mode 100644 index 000000000..fa6e95972 --- /dev/null +++ b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/cucumber/stepdef/InboundStepDef.java @@ -0,0 +1,115 @@ +package org.mifos.integrationtest.cucumber.stepdef; + +import static com.google.common.truth.Truth.assertThat; +import static java.util.concurrent.TimeUnit.SECONDS; +import static org.awaitility.Awaitility.await; +import static org.hamcrest.Matchers.anyOf; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.not; + +import io.cucumber.core.internal.com.fasterxml.jackson.core.JsonProcessingException; +import io.cucumber.java.en.And; +import io.cucumber.java.en.Given; +import io.cucumber.java.en.When; +import io.restassured.RestAssured; +import io.restassured.builder.ResponseSpecBuilder; +import io.restassured.specification.RequestSpecification; +import io.restassured.specification.ResponseSpecification; +import org.json.JSONException; +import org.json.JSONObject; +import org.mifos.connector.common.channel.dto.TransactionChannelRequestDTO; +import org.mifos.integrationtest.common.Utils; + +public class InboundStepDef extends BaseStepDef { + + public static TransactionChannelRequestDTO mockTransactionChannelRequestDTO = null; + + @Given("I can mock TransactionChannelRequestDTO") + public void mockTransactionChannelRequestDTO() throws JsonProcessingException { + if (mockTransactionChannelRequestDTO != null) { + assertThat(mockTransactionChannelRequestDTO).isNotNull(); + return; + } + StringBuilder jsonBuilder = new StringBuilder(); + jsonBuilder.append("{").append("\"payer\": {").append("\"partyIdInfo\": {").append("\"partyIdType\": \"MSISDN\",") + .append("\"partyIdentifier\": \"27710101999\"").append("}},").append("\"payee\": {").append("\"partyIdInfo\": {") + .append("\"partyIdType\": \"MSISDN\",").append("\"partyIdentifier\": \"27710102999\"").append("}},").append("\"amount\": {") + .append("\"amount\": 230,").append("\"currency\": \"TZS\"").append("}}"); + String json = jsonBuilder.toString(); + mockTransactionChannelRequestDTO = objectMapper.readValue(json, TransactionChannelRequestDTO.class); + assertThat(mockTransactionChannelRequestDTO).isNotNull(); + scenarioScopeState.inboundTransferMockReq = mockTransactionChannelRequestDTO; + } + + @When("I call the inbound transfer endpoint with expected status of {int}") + public void callBatchSummaryAPILegacy(int expectedStatus) { + callBatchSummaryAPI(expectedStatus); + } + + @When("I call the inbound transfer endpoint with expected status of {int} and no authentication") + public void callBatchSummaryAPINoAuth(int expectedStatus) { + callBatchSummaryAPI(expectedStatus); + } + + @And("I call the inbound transfer endpoint with authentication") + public void callBatchSummaryAPIWithAuth() { + RequestSpecification requestSpec = Utils.getDefaultSpec(scenarioScopeState.tenant); + requestSpec.header("Authorization", "Bearer " + scenarioScopeState.keycloakTokenResponse.getAccessToken()); + + // since after authentication channel can return anything apart from 400 and 401 + ResponseSpecification responseSpecBuilder = new ResponseSpecBuilder().expectStatusCode(anyOf(not(anyOf(is(400), is(401))))).build(); + + scenarioScopeState.response = RestAssured.given(requestSpec).baseUri(channelConnectorConfig.channelConnectorContactPoint) + .body(mockTransactionChannelRequestDTO).expect().spec(responseSpecBuilder).when() + .post(channelConnectorConfig.transferEndpoint).andReturn().asString(); + assertNonEmpty(scenarioScopeState.response); + } + + public void callBatchSummaryAPI(int expectedStatus) { + await().atMost(awaitMost, SECONDS).pollInterval(pollInterval, SECONDS).untilAsserted(() -> { + RequestSpecification requestSpec = Utils.getDefaultSpec(scenarioScopeState.tenant); + scenarioScopeState.response = RestAssured.given(requestSpec).baseUri(channelConnectorConfig.channelConnectorContactPoint) + .body(mockTransactionChannelRequestDTO).expect() + .spec(new ResponseSpecBuilder().expectStatusCode(expectedStatus).build()).when() + .post(channelConnectorConfig.transferEndpoint).andReturn().asString(); + logger.info("Inbound transfer Response: {}", scenarioScopeState.response); + assertNonEmpty(scenarioScopeState.response); + }); + } + + @And("I should be able to parse transactionId") + public void parseTransactionId() { + String transactionId; + try { + JSONObject jsonObject = new JSONObject(scenarioScopeState.response); + transactionId = jsonObject.getString("transactionId"); + } catch (JSONException e) { + logger.error("Error parsing the transaction id", e); + assertThat(false).isTrue(); + return; + } + assertThat(transactionId).isNotNull(); + assertThat(transactionId).isNotEmpty(); + } + + @Given("I can mock TransactionChannelRequestDTO for account lookup") + public void iCanMockTransactionChannelRequestDTOForAccountLookup() throws JsonProcessingException { + StringBuilder jsonBuilder = new StringBuilder(); + jsonBuilder.append("{").append("\"payer\": {").append("\"partyIdInfo\": {").append("\"partyIdType\": \"MSISDN\",") + .append("\"partyIdentifier\": \"27710101999\"").append("}").append("},").append("\"payee\": {").append("\"partyIdInfo\": {") + .append("\"partyIdType\": \"MSISDN\",").append("\"partyIdentifier\": ").append("\"") + .append(scenarioScopeState.beneficiaryPayeeIdentity).append("\"") // Replace with the variable here + .append("}").append("},").append("\"amount\": {").append("\"amount\": 2240,").append("\"currency\": \"TZS\"").append("}") + .append("}"); + + String json = jsonBuilder.toString(); + mockTransactionChannelRequestDTO = objectMapper.readValue(json, TransactionChannelRequestDTO.class); + assertThat(mockTransactionChannelRequestDTO).isNotNull(); + scenarioScopeState.inboundTransferMockReq = mockTransactionChannelRequestDTO; + } + + private void assertNonEmpty(String data) { + assertThat(data).isNotNull(); + } + +} diff --git a/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/cucumber/stepdef/JWSStepDef.java b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/cucumber/stepdef/JWSStepDef.java new file mode 100644 index 000000000..a9d41d502 --- /dev/null +++ b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/cucumber/stepdef/JWSStepDef.java @@ -0,0 +1,85 @@ +package org.mifos.integrationtest.cucumber.stepdef; + +import static com.google.common.truth.Truth.assertThat; + +import io.cucumber.java.en.And; +import java.io.IOException; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.security.cert.CertificateException; +import java.security.spec.InvalidKeySpecException; +import javax.crypto.BadPaddingException; +import javax.crypto.IllegalBlockSizeException; +import javax.crypto.NoSuchPaddingException; +import org.mifos.connector.common.util.CertificateUtil; +import org.mifos.connector.common.util.Constant; +import org.mifos.connector.common.util.SecurityUtil; +import org.mifos.integrationtest.common.UniqueNumberGenerator; +import org.mifos.integrationtest.config.JWSKeyConfig; +import org.springframework.beans.factory.annotation.Autowired; + +public class JWSStepDef extends BaseStepDef { + + @Autowired + JWSKeyConfig jwsKeyConfig; + + @And("I generate clientCorrelationId") + public void setClientCorrelationId() { + scenarioScopeState.clientCorrelationId = UniqueNumberGenerator.generateUniqueNumber(12); + assertThat(scenarioScopeState.clientCorrelationId).isNotEmpty(); + } + + @And("I generate signature") + public void generateSignatureStep() throws IOException, NoSuchPaddingException, IllegalBlockSizeException, NoSuchAlgorithmException, + BadPaddingException, InvalidKeySpecException, InvalidKeyException { + if (scenarioScopeState.filename != null) { + scenarioScopeState.signature = generateSignature(scenarioScopeState.clientCorrelationId, scenarioScopeState.tenant, + scenarioScopeState.filename, true); + } else { + scenarioScopeState.signature = generateSignature(scenarioScopeState.clientCorrelationId, scenarioScopeState.tenant, + scenarioScopeState.batchRawRequest, false); + } + assertThat(scenarioScopeState.signature).isNotEmpty(); + logger.info("Generated signature: {}", scenarioScopeState.signature); + } + + @And("The response should have non empty header X-SIGNATURE") + public void checkNonEmptySignatureKey() { + assertThat(scenarioScopeState.restResponseObject).isNotNull(); + String signatureHeaderValue = scenarioScopeState.restResponseObject.getHeader(Constant.HEADER_JWS); + logger.info("Response signature: {}", signatureHeaderValue); + assertThat(signatureHeaderValue).isNotEmpty(); + scenarioScopeState.signature = signatureHeaderValue; + } + + @And("The signature should be able successfully validated against certificate") + public void verifyResponseSignature() { + assertThat(scenarioScopeState.restResponseObject).isNotNull(); + assertThat(jwsKeyConfig).isNotNull(); + String data = scenarioScopeState.response; + String signature = scenarioScopeState.restResponseObject.getHeader(Constant.HEADER_JWS); + + Boolean isValidSignature = null; + try { + isValidSignature = validateSignature(signature, data, jwsKeyConfig.x509Certificate); + } catch (Exception e) { + logger.error("Failed step verifyResponseSignature" + + " \"The signature should be able successfully validated against certificate {string}\""); + } + assertThat(isValidSignature).isNotNull(); + assertThat(isValidSignature).isTrue(); + } + + public boolean validateSignature(String signature, String data, String x509Certificate) + throws CertificateException, NoSuchPaddingException, IllegalBlockSizeException, NoSuchAlgorithmException, BadPaddingException, + InvalidKeySpecException, InvalidKeyException { + String publicKey = CertificateUtil.getPublicKey(x509Certificate); + logger.info("Data to be hashed: {}", data); + String hashedData = SecurityUtil.hash(data); + logger.info("Hashed data: {}", hashedData); + String decodedHash = SecurityUtil.decryptUsingPublicKey(signature, publicKey); + logger.info("Decoded hash: {}", decodedHash); + return hashedData.equals(decodedHash); + } + +} diff --git a/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/cucumber/stepdef/KeycloakStepDef.java b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/cucumber/stepdef/KeycloakStepDef.java new file mode 100644 index 000000000..6a90dcd3a --- /dev/null +++ b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/cucumber/stepdef/KeycloakStepDef.java @@ -0,0 +1,180 @@ +package org.mifos.integrationtest.cucumber.stepdef; + +import static com.google.common.truth.Truth.assertThat; +import static org.mifos.integrationtest.common.Utils.CONTENT_TYPE; + +import io.cucumber.core.internal.com.fasterxml.jackson.core.JsonProcessingException; +import io.cucumber.core.internal.com.fasterxml.jackson.core.type.TypeReference; +import io.cucumber.java.After; +import io.cucumber.java.Before; +import io.cucumber.java.en.And; +import io.cucumber.java.en.When; +import io.restassured.RestAssured; +import io.restassured.builder.ResponseSpecBuilder; +import io.restassured.specification.RequestSpecification; +import java.util.List; +import java.util.UUID; +import org.mifos.integrationtest.common.Utils; +import org.mifos.integrationtest.common.dto.KeycloakTokenResponse; +import org.mifos.integrationtest.common.dto.kong.Access; +import org.mifos.integrationtest.common.dto.kong.KeycloakUpdateRequest; +import org.mifos.integrationtest.common.dto.kong.KeycloakUser; +import org.mifos.integrationtest.config.KeycloakConfig; +import org.springframework.beans.factory.annotation.Autowired; + +public class KeycloakStepDef extends BaseStepDef { + + @Autowired + KeycloakConfig keycloakConfig; + + @Before("@keycloak-user-setup") + public void keycloakUserSetup() throws JsonProcessingException { + logger.info("Running keycloak-user-setup"); + String username = UUID.randomUUID().toString(); + doAdminAuthentication(); + createUser(username); + scenarioScopeState.keycloakUser = fetchKeycloakUserUsingUsername(username); + logger.debug("Keycloak user: {}", objectMapper.writeValueAsString(scenarioScopeState.keycloakUser)); + BaseStepDef.keycloakCurrentUserPassword = "password"; + resetUserPassword(scenarioScopeState.keycloakUser.getId(), BaseStepDef.keycloakCurrentUserPassword); + } + + @After("@keycloak-user-teardown") + public void keycloakUserTeardown() { + logger.info("Running keycloak-user-teardown"); + doAdminAuthentication(); + deleteUser(scenarioScopeState.keycloakUser.getId()); + } + + @And("I authenticate with new keycloak user") + public void authenticateCurrentKeycloakUser() throws JsonProcessingException { + if (scenarioScopeState.keycloakUser == null || BaseStepDef.keycloakCurrentUserPassword == null) { + throw new RuntimeException( + "Current keycloak user or password is not present." + "Make sure to call create the new user using admin step"); + } + getTokenFromKeycloakUser(scenarioScopeState.keycloakUser.username, BaseStepDef.keycloakCurrentUserPassword); + } + + @When("I call the keycloak auth api with {string} username and {string} password") + public void getTokenFromKeycloakUser(String username, String password) { + RequestSpecification requestSpecification = Utils.getDefaultSpec(); + requestSpecification.header(CONTENT_TYPE, "application/x-www-form-urlencoded"); + requestSpecification.formParam(KeycloakConfig.headerUsernameKey, username).formParam(KeycloakConfig.headerPasswordKey, password) + .formParam(KeycloakConfig.headerClientIdKey, keycloakConfig.clientId) + .formParam(KeycloakConfig.headerClientSecretKey, keycloakConfig.clientSecret) + .formParam(KeycloakConfig.headerGrantTypeKey, keycloakConfig.grantType); + scenarioScopeState.response = RestAssured.given(requestSpecification).baseUri(keycloakConfig.keycloakContactPoint).expect() + .spec(new ResponseSpecBuilder().expectStatusCode(200).build()).when() + .post(keycloakConfig.tokenEndpoint, keycloakConfig.realm).andReturn().asString(); + try { + scenarioScopeState.keycloakTokenResponse = objectMapper.readValue(scenarioScopeState.response, KeycloakTokenResponse.class); + } catch (Exception e) { + scenarioScopeState.keycloakTokenResponse = null; + } + logger.debug("Auth response {}", scenarioScopeState.response); + assertThat(scenarioScopeState.keycloakTokenResponse).isNotNull(); + assertThat(scenarioScopeState.keycloakTokenResponse.getAccessToken()).isNotNull(); + } + + public void doAdminAuthentication() { + logger.info("Doing admin auth"); + getTokenFromKeycloakUser(keycloakConfig.adminUsername, keycloakConfig.adminPassword); + } + + public void deleteUser(String userId) { + RequestSpecification requestSpecification = Utils.getDefaultSpec(); + requestSpecification.header(CONTENT_TYPE, "application/json"); + if (scenarioScopeState.keycloakTokenResponse != null) { + requestSpecification.header("Authorization", "Bearer " + scenarioScopeState.keycloakTokenResponse.getAccessToken()); + } + + scenarioScopeState.response = RestAssured.given(requestSpecification).baseUri(keycloakConfig.keycloakContactPoint) + .body(scenarioScopeState.keycloakUser).expect().spec(new ResponseSpecBuilder().expectStatusCode(204).build()).when() + .delete(keycloakConfig.userEndpoint + "/{userId}", keycloakConfig.realm, userId).andReturn().asString(); + } + + public void createUser(String username) { + RequestSpecification requestSpecification = Utils.getDefaultSpec(); + requestSpecification.header(CONTENT_TYPE, "application/json"); + if (scenarioScopeState.keycloakTokenResponse != null) { + requestSpecification.header("Authorization", "Bearer " + scenarioScopeState.keycloakTokenResponse.getAccessToken()); + } + + KeycloakUser keycloakUser = getDefaultKeycloakUser(); + keycloakUser.setUsername(username); + + scenarioScopeState.response = RestAssured.given(requestSpecification).baseUri(keycloakConfig.keycloakContactPoint) + .body(keycloakUser).expect().spec(new ResponseSpecBuilder().expectStatusCode(201).build()).when() + .post(keycloakConfig.userEndpoint, keycloakConfig.realm).andReturn().asString(); + } + + public KeycloakUser fetchKeycloakUserUsingUsername(String username) { + RequestSpecification requestSpecification = Utils.getDefaultSpec(); + requestSpecification.header(CONTENT_TYPE, "application/json"); + if (scenarioScopeState.keycloakTokenResponse != null) { + requestSpecification.header("Authorization", "Bearer " + scenarioScopeState.keycloakTokenResponse.getAccessToken()); + } + + KeycloakUser keycloakUser = getDefaultKeycloakUser(); + keycloakUser.setUsername(username); + + scenarioScopeState.response = RestAssured.given(requestSpecification).baseUri(keycloakConfig.keycloakContactPoint) + .queryParam("search", username).expect().spec(new ResponseSpecBuilder().expectStatusCode(200).build()).when() + .get(keycloakConfig.userEndpoint, keycloakConfig.realm).andReturn().asString(); + + List parsedUsers = null; + try { + parsedUsers = objectMapper.readValue(scenarioScopeState.response, new TypeReference>() {}); + if (parsedUsers.size() == 1) { + return parsedUsers.get(0); + } + return null; + } catch (JsonProcessingException e) { + return null; + } + } + + public void resetUserPassword(String userId, String password) { + RequestSpecification requestSpecification = Utils.getDefaultSpec(); + requestSpecification.header(CONTENT_TYPE, "application/json"); + if (scenarioScopeState.keycloakTokenResponse != null) { + requestSpecification.header("Authorization", "Bearer " + scenarioScopeState.keycloakTokenResponse.getAccessToken()); + } + KeycloakUpdateRequest keycloakUpdateRequest = getDefaultKeycloakResetPasswordObject(); + keycloakUpdateRequest.setValue(password); + + scenarioScopeState.response = RestAssured.given(requestSpecification).baseUri(keycloakConfig.keycloakContactPoint) + .body(keycloakUpdateRequest).expect().spec(new ResponseSpecBuilder().expectStatusCode(204).build()).when() + .put(keycloakConfig.userPasswordResetEndpoint, keycloakConfig.realm, userId).andReturn().asString(); + } + + public static KeycloakUser getDefaultKeycloakUser() { + KeycloakUser keycloakUser = new KeycloakUser(); + keycloakUser.setEnabled(true); + keycloakUser.setEmailVerified(true); + keycloakUser.setFirstName("Test First Name"); + keycloakUser.setLastName("Test Last Name"); + keycloakUser.setAccess(getDefaultKeycloakAccessObject()); + keycloakUser.addRealmRoles("admin"); + return keycloakUser; + } + + public static Access getDefaultKeycloakAccessObject() { + Access access = new Access(); + access.setManageGroupMembership(true); + access.setView(true); + access.setMapRoles(true); + access.setImpersonate(true); + access.setManage(true); + return access; + } + + public static KeycloakUpdateRequest getDefaultKeycloakResetPasswordObject() { + KeycloakUpdateRequest keycloakUpdateRequest = new KeycloakUpdateRequest(); + keycloakUpdateRequest.setType("password"); + keycloakUpdateRequest.setValue("password"); + keycloakUpdateRequest.setTemporary(false); + return keycloakUpdateRequest; + } + +} diff --git a/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/cucumber/stepdef/KongStepDef.java b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/cucumber/stepdef/KongStepDef.java new file mode 100644 index 000000000..fcf93dadf --- /dev/null +++ b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/cucumber/stepdef/KongStepDef.java @@ -0,0 +1,405 @@ +package org.mifos.integrationtest.cucumber.stepdef; + +import static com.google.common.truth.Truth.assertThat; + +import io.cucumber.core.internal.com.fasterxml.jackson.core.JsonProcessingException; +import io.cucumber.java.After; +import io.cucumber.java.en.And; +import io.cucumber.java.en.Given; +import io.cucumber.java.en.Then; +import io.cucumber.java.en.When; +import io.restassured.RestAssured; +import io.restassured.builder.ResponseSpecBuilder; +import io.restassured.response.Response; +import io.restassured.specification.RequestSpecification; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; +import org.apache.commons.lang3.StringUtils; +import org.mifos.integrationtest.common.Utils; +import org.mifos.integrationtest.common.dto.kong.KongConsumer; +import org.mifos.integrationtest.common.dto.kong.KongConsumerKey; +import org.mifos.integrationtest.common.dto.kong.KongPlugin; +import org.mifos.integrationtest.common.dto.kong.KongRoute; +import org.mifos.integrationtest.common.dto.kong.KongService; +import org.mifos.integrationtest.config.KeycloakConfig; +import org.mifos.integrationtest.config.KongConfig; +import org.mifos.integrationtest.config.KongOidcPluginConfig; +import org.springframework.beans.factory.annotation.Autowired; + +@SuppressWarnings("AvoidDoubleBraceInitialization") +public class KongStepDef extends BaseStepDef { + + @Autowired + public KongConfig kongConfig; + + @Autowired + public KeycloakConfig keycloakConfig; + + @Autowired + public KongOidcPluginConfig kongOidcPluginConfig; + + @Given("I have required Kong configuration") + public void checkKongConfigNotNull() { + assertThat(this.kongConfig).isNotNull(); + } + + @When("I create new consumer") + public void createNewConsumer() throws JsonProcessingException { + KongConsumer consumer = new KongConsumer(); + consumer.setCustomId("custom_" + System.currentTimeMillis()); + consumer.setId(UUID.randomUUID().toString()); + consumer.setUsername("user_" + System.currentTimeMillis()); + + RequestSpecification baseReqSpec = Utils.getDefaultSpec(); + + scenarioScopeState.response = RestAssured.given(baseReqSpec).baseUri(kongConfig.adminContactPoint) + .header("Content-Type", "application/json").body(objectMapper.writeValueAsString(consumer)).expect() + .spec(new ResponseSpecBuilder().expectStatusCode(201).build()).when().post(kongConfig.consumerEndpoint).andReturn() + .asString(); + + logger.debug("Create new consumer response from kong: {}", scenarioScopeState.response); + try { + scenarioScopeState.kongConsumer = objectMapper.readValue(scenarioScopeState.response, KongConsumer.class); + logger.debug("Kong consumer: {}", objectMapper.writeValueAsString(scenarioScopeState.kongConsumer)); + } catch (Exception e) { + scenarioScopeState.kongConsumer = null; + } + + assertThat(scenarioScopeState.kongConsumer).isNotNull(); + } + + @And("I am able to create a key for above consumer") + public void createKey() throws JsonProcessingException { + KongConsumerKey consumerKey = new KongConsumerKey(); + consumerKey.setKey(UUID.randomUUID().toString()); + consumerKey.setId(UUID.randomUUID().toString()); + + RequestSpecification baseReqSpec = Utils.getDefaultSpec(); + scenarioScopeState.response = RestAssured.given(baseReqSpec).baseUri(kongConfig.adminContactPoint) + .header("Content-Type", "application/json").body(objectMapper.writeValueAsString(consumerKey)).expect() + .spec(new ResponseSpecBuilder().expectStatusCode(201).build()).when() + .post(kongConfig.createKeyEndpoint, scenarioScopeState.kongConsumer.getUsername()).andReturn().asString(); + + logger.debug("Create new key response from kong: {}", scenarioScopeState.response); + try { + scenarioScopeState.kongConsumerKey = objectMapper.readValue(scenarioScopeState.response, KongConsumerKey.class); + logger.debug("Kong consumer key: {}", objectMapper.writeValueAsString(scenarioScopeState.kongConsumerKey)); + } catch (Exception e) { + scenarioScopeState.kongConsumerKey = null; + } + + assertThat(scenarioScopeState.kongConsumerKey).isNotNull(); + } + + @And("I register a service in kong") + public void registerService() throws JsonProcessingException { + registerService(kongConfig.serviceUrl, "https"); + assertThat(scenarioScopeState.kongService).isNotNull(); + } + + @And("I register a route to above service in kong") + public void registerRouteInService() throws JsonProcessingException { + registerRouteInService(new ArrayList<>() { + + { + add("/"); + } + }, new ArrayList<>() { + + { + add(kongConfig.routeHost); + } + }, scenarioScopeState.kongService.getId()); + assertThat(scenarioScopeState.kongRoute).isNotNull(); + } + + @And("I add the key-auth plugin in above service") + public void enableKeyAuthPlugin() throws JsonProcessingException { + Map config = new HashMap<>() { + + { + put("key_names", new ArrayList() { + + { + add(kongConfig.apiKeyHeader); + } + }); + } + }; + enablePluginForService(scenarioScopeState.kongService.getId(), "key-auth", config); + assertThat(scenarioScopeState.kongPlugin).isNotNull(); + } + + @Then("When I call the service endpoint with api key I should get {int}") + public void callServiceEndpoint(int expectedStatus) { + logger.debug("Key: {}", scenarioScopeState.kongConsumerKey.getKey()); + logger.debug("Host: {}", kongConfig.routeHost); + RequestSpecification baseReqSpec = Utils.getDefaultSpec(); + try { + Response resp = RestAssured.given(baseReqSpec).baseUri("https://" + kongConfig.routeHost) + .header(kongConfig.apiKeyHeader, scenarioScopeState.kongConsumerKey.getKey()).expect() + .spec(new ResponseSpecBuilder().expectStatusCode(expectedStatus).build()).when().get("/actuator/health/liveness") + .andReturn(); + scenarioScopeState.response = resp.asString(); + + logger.debug("Status Code: {}", resp.getStatusCode()); + logger.debug("Response: {}", scenarioScopeState.response); + } catch (Exception e) { + logger.debug("{}", e.getMessage()); + clearKongData(); + } + } + + @After("@kong-teardown") + public void removeKeyAuth() { + logger.debug("Running kong teardown"); + clearKongData(); + } + + @And("I wait for {int} seconds") + public void waitForSometime(int seconds) { + Utils.sleep(seconds); + } + + @And("I register channel service using config") + public void registerChannelServiceFromConfig() throws JsonProcessingException { + registerService(kongConfig.channelServiceUrl, "https"); + } + + @And("I register service with url {string} and {string} protocol") + public void commonRegisterService(String serviceUrl, String protocol) throws JsonProcessingException { + registerService(serviceUrl, protocol); + assertThat(scenarioScopeState.kongService).isNotNull(); + } + + @And("I register channel route using config") + public void registerChannelRouteFromConfig() throws JsonProcessingException { + commonRegisterRouteInService(kongConfig.channelRouteHost, kongConfig.channelRoutePath); + } + + @And("I register route with route host {string} and path {string}") + public void commonRegisterRouteInService(String routeHost, String path) throws JsonProcessingException { + registerRouteInService(new ArrayList<>() { + + { + add(path); + } + }, new ArrayList<>() { + + { + add(routeHost); + } + }, scenarioScopeState.kongService.getId()); + assertThat(scenarioScopeState.kongRoute).isNotNull(); + } + + @And("I enable oidc plugin") + public void enableOidcPluginForService() throws JsonProcessingException { + Map config = new HashMap<>() { + + { + put("discovery", keycloakConfig.discoveryUrl.replace("{realm}", keycloakConfig.realm)); + put("client_id", keycloakConfig.clientId); + put("client_secret", keycloakConfig.clientSecret); + put("introspection_endpoint", keycloakConfig.introspectionUrl.replace("{realm}", keycloakConfig.realm)); + put("bearer_only", kongOidcPluginConfig.bearerTokenOnly ? "yes" : "no"); + put("scope", kongOidcPluginConfig.scope); + put("realm", keycloakConfig.realm); + } + }; + enablePluginForService(scenarioScopeState.kongService.getId(), "oidc", config); + assertThat(scenarioScopeState.kongPlugin).isNotNull(); + } + + public void registerService(String serviceUrl, String protocol) throws JsonProcessingException { + KongService service = new KongService(); + service.setId(UUID.randomUUID().toString()); + service.setUrl(serviceUrl); + service.setName("name_" + service.getId()); + service.setProtocol(protocol); + + RequestSpecification baseReqSpec = Utils.getDefaultSpec(); + scenarioScopeState.response = RestAssured.given(baseReqSpec).baseUri(kongConfig.adminContactPoint) + .header("Content-Type", "application/json").body(objectMapper.writeValueAsString(service)).expect() + .spec(new ResponseSpecBuilder().expectStatusCode(201).build()).when().post(kongConfig.servicesEndpoint).andReturn() + .asString(); + + logger.debug("Create new service response from kong: {}", scenarioScopeState.response); + try { + scenarioScopeState.kongService = objectMapper.readValue(scenarioScopeState.response, KongService.class); + logger.debug("Kong service: {}", objectMapper.writeValueAsString(scenarioScopeState.kongService)); + } catch (Exception e) { + scenarioScopeState.kongService = null; + } + } + + public void registerRouteInService(ArrayList paths, ArrayList routeHosts, String serviceId) + throws JsonProcessingException { + KongRoute route = new KongRoute(); + route.setId(UUID.randomUUID().toString()); + route.setName("name_" + route.getId()); + route.setPaths(paths); + route.setHosts(routeHosts); + + RequestSpecification baseReqSpec = Utils.getDefaultSpec(); + scenarioScopeState.response = RestAssured.given(baseReqSpec).baseUri(kongConfig.adminContactPoint) + .header("Content-Type", "application/json").body(objectMapper.writeValueAsString(route)).expect() + .spec(new ResponseSpecBuilder().expectStatusCode(201).build()).when().post(kongConfig.createRouteEndpoint, serviceId) + .andReturn().asString(); + + logger.debug("Create new route response from kong: {}", scenarioScopeState.response); + try { + scenarioScopeState.kongRoute = objectMapper.readValue(scenarioScopeState.response, KongRoute.class); + logger.debug("Kong route: {}", objectMapper.writeValueAsString(scenarioScopeState.kongRoute)); + } catch (Exception e) { + scenarioScopeState.kongRoute = null; + } + } + + public void enablePluginForService(String serviceId, String pluginName, Map config) throws JsonProcessingException { + KongPlugin kongPlugin = new KongPlugin(); + kongPlugin.setId(UUID.randomUUID().toString()); + kongPlugin.setName(pluginName); + kongPlugin.setEnabled(true); + kongPlugin.setConfig(config); + + RequestSpecification baseReqSpec = Utils.getDefaultSpec(); + scenarioScopeState.response = RestAssured.given(baseReqSpec).baseUri(kongConfig.adminContactPoint) + .header("Content-Type", "application/json").body(objectMapper.writeValueAsString(kongPlugin)).expect() + .spec(new ResponseSpecBuilder().expectStatusCode(201).build()).when().post(kongConfig.createPluginEndpoint, serviceId) + .andReturn().asString(); + + logger.debug("Enable plugin response from kong: {}", scenarioScopeState.response); + try { + scenarioScopeState.kongPlugin = objectMapper.readValue(scenarioScopeState.response, KongPlugin.class); + logger.debug("Kong plugin: {}", objectMapper.writeValueAsString(scenarioScopeState.kongPlugin)); + } catch (Exception e) { + scenarioScopeState.kongPlugin = null; + } + } + + // cals respective methods for clearing kong related resources + private void clearKongData() { + if (scenarioScopeState.kongConsumer != null) { + deleteConsumer(scenarioScopeState.kongConsumer.getId()); + scenarioScopeState.kongConsumer = null; + scenarioScopeState.kongConsumerKey = null; + } + if (scenarioScopeState.kongPlugin != null && StringUtils.isNotBlank(scenarioScopeState.kongPlugin.getId())) { + deletePlugin(scenarioScopeState.kongPlugin.getId()); + scenarioScopeState.kongPlugin = null; + } + if (scenarioScopeState.kongRoute != null) { + deleteRoute(scenarioScopeState.kongRoute.getId()); + scenarioScopeState.kongRoute = null; + } + if (scenarioScopeState.kongService != null) { + deleteService(scenarioScopeState.kongService.getId()); + scenarioScopeState.kongService = null; + } + } + + // deletes the consumer in kong by calling admin api + private void deleteConsumer(String consumerId) { + RequestSpecification baseReqSpec = Utils.getDefaultSpec(); + String deleteResponse = RestAssured.given(baseReqSpec).baseUri(kongConfig.adminContactPoint) + .delete(kongConfig.consumerEndpoint + "/{consumerId}", consumerId).andReturn().asString(); + logger.debug("Consumer delete response: {}", deleteResponse); + } + + // deletes the plugin in kong by calling admin api + private void deletePlugin(String pluginId) { + RequestSpecification baseReqSpec = Utils.getDefaultSpec(); + String deleteResponse = RestAssured.given(baseReqSpec).baseUri(kongConfig.adminContactPoint) + .delete(kongConfig.pluginsEndpoint + "/{pluginId}", pluginId).andReturn().asString(); + logger.debug("Plugin delete response: {}", deleteResponse); + } + + // deletes the route in kong by calling admin api + private void deleteRoute(String routeId) { + RequestSpecification baseReqSpec = Utils.getDefaultSpec(); + String deleteResponse = RestAssured.given(baseReqSpec).baseUri(kongConfig.adminContactPoint) + .delete(kongConfig.routesEndpoint + "/{routeId}", routeId).andReturn().asString(); + logger.debug("Route delete response: {}", deleteResponse); + } + + // deletes the service in kong by calling admin api + private void deleteService(String serviceId) { + RequestSpecification baseReqSpec = Utils.getDefaultSpec(); + String deleteResponse = RestAssured.given(baseReqSpec).baseUri(kongConfig.adminContactPoint) + .delete(kongConfig.servicesEndpoint + "/{serviceId}", serviceId).andReturn().asString(); + logger.debug("Service delete response: {}", deleteResponse); + } + + @And("I add the ratelimiter plugin in above service") + public void enableRateLimitPlugin() throws JsonProcessingException { + KongPlugin kongPlugin = new KongPlugin(); + kongPlugin.setId(UUID.randomUUID().toString()); + kongPlugin.setName("rate-limiting"); + kongPlugin.setEnabled(true); + kongPlugin.setConfig(new HashMap<>() { + + { + put("policy", "cluster"); + put("minute", 2); + put("limit_by", "consumer"); + } + }); + + RequestSpecification baseReqSpec = Utils.getDefaultSpec(); + scenarioScopeState.response = RestAssured.given(baseReqSpec).baseUri(kongConfig.adminContactPoint) + .header("Content-Type", "application/json").body(objectMapper.writeValueAsString(kongPlugin)).expect() + .spec(new ResponseSpecBuilder().expectStatusCode(201).build()).when() + .post(kongConfig.createPluginEndpoint, scenarioScopeState.kongService.getId()).andReturn().asString(); + + logger.info("Enable ratelimiter plugin response from kong: {}", scenarioScopeState.response); + try { + scenarioScopeState.kongPlugin = objectMapper.readValue(scenarioScopeState.response, KongPlugin.class); + logger.info("Kong plugin: {}", objectMapper.writeValueAsString(scenarioScopeState.kongPlugin)); + } catch (Exception e) { + scenarioScopeState.kongPlugin = null; + } + + assertThat(scenarioScopeState.kongPlugin).isNotNull(); + } + + @And("I add the ratelimiter plugin in kong") + public void iAddTheRatelimiterPluginInKong() throws JsonProcessingException { + KongPlugin kongPlugin = new KongPlugin(); + kongPlugin.setId(UUID.randomUUID().toString()); + kongPlugin.setName("rate-limiting"); + kongPlugin.setEnabled(true); + kongPlugin.setConfig(new HashMap<>() { + + { + put("policy", "cluster"); + put("second", 1); + put("minute", 5); + put("limit_by", "consumer"); + } + }); + + RequestSpecification baseReqSpec = Utils.getDefaultSpec(); + scenarioScopeState.response = RestAssured.given(baseReqSpec).baseUri(kongConfig.adminContactPoint) + .header("Content-Type", "application/json").body(objectMapper.writeValueAsString(kongPlugin)).expect() + .spec(new ResponseSpecBuilder().expectStatusCode(201).build()).when().post(kongConfig.pluginsEndpoint).andReturn() + .asString(); + + logger.info("Creating ratelimiter plugin response from kong: {}", scenarioScopeState.response); + try { + scenarioScopeState.kongPlugin = objectMapper.readValue(scenarioScopeState.response, KongPlugin.class); + logger.info("Kong plugin: {}", objectMapper.writeValueAsString(scenarioScopeState.kongPlugin)); + } catch (Exception e) { + scenarioScopeState.kongPlugin = null; + } + + assertThat(scenarioScopeState.kongPlugin).isNotNull(); + } + + @And("I should have {string} in response body") + public void iShouldHaveInResponseBody(String expectedResponse) { + assertThat(scenarioScopeState.response).contains(expectedResponse); + } +} diff --git a/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/cucumber/stepdef/MockFlowTestDef.java b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/cucumber/stepdef/MockFlowTestDef.java new file mode 100644 index 000000000..fbfa986ac --- /dev/null +++ b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/cucumber/stepdef/MockFlowTestDef.java @@ -0,0 +1,120 @@ +package org.mifos.integrationtest.cucumber.stepdef; + +import static com.google.common.truth.Truth.assertThat; +import static java.util.concurrent.TimeUnit.SECONDS; +import static org.awaitility.Awaitility.await; + +import io.cucumber.java.en.And; +import io.cucumber.java.en.When; +import io.restassured.RestAssured; +import io.restassured.builder.ResponseSpecBuilder; +import io.restassured.specification.RequestSpecification; +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; +import org.mifos.integrationtest.common.Utils; +import org.mifos.integrationtest.config.OperationsAppConfig; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; + +public class MockFlowTestDef extends BaseStepDef { + + @Value("${operations-app.auth.enabled}") + public Boolean authEnabled; + + @Autowired + OperationsAppConfig operationsAppConfig; + + @Autowired + ScenarioScopeState scenarioScopeState; + + @When("I call the outbound transfer endpoint with expected status {int}") + public void iCallTheOutboundTransferEndpointWithExpectedStatus(int expectedStatus) { + RequestSpecification requestSpec = Utils.getDefaultSpec(scenarioScopeState.tenant); + logger.info("X-CorrelationId: {}", scenarioScopeState.clientCorrelationId); + requestSpec.header(Utils.X_CORRELATIONID, scenarioScopeState.clientCorrelationId); + requestSpec.header("X-Registering-Institution-ID", "SocialWelfare"); + scenarioScopeState.response = RestAssured.given(requestSpec).baseUri(channelConnectorConfig.channelConnectorContactPoint) + .body(scenarioScopeState.inboundTransferMockReq).expect() + .spec(new ResponseSpecBuilder().expectStatusCode(expectedStatus).build()).when() + .post(channelConnectorConfig.transferEndpoint).andReturn().asString(); + + logger.info("Inbound transfer Response: {}", scenarioScopeState.response); + scenarioScopeState.transactionId = scenarioScopeState.response.split(":")[1].split(",")[0].split("\"")[1]; + logger.info("TransactionId: {}", scenarioScopeState.transactionId); + } + + @And("I should have PayerFspId as not null") + public void iShouldHavePayerFspIdAsNotNull() throws JSONException { + assert scenarioScopeState.response.contains("payerDfspId"); + JSONObject jsonObject = new JSONObject(scenarioScopeState.response); + JSONArray jsonArray = (JSONArray) jsonObject.get("content"); + JSONObject content = (JSONObject) jsonArray.get(0); + String value = content.get("payerDfspId").toString(); + assert value != null; + } + + @When("I call the get txn API with expected status of {int} and txnId") + public void iCallTheGetTxnAPIWithExpectedStatusOfAndTxnId(int expectedStatus) { + await().atMost(awaitMost, SECONDS).pollInterval(pollInterval, SECONDS).untilAsserted(() -> { + RequestSpecification requestSpec = Utils.getDefaultSpec(scenarioScopeState.tenant); + requestSpec.queryParam("transactionId", scenarioScopeState.transactionId); + requestSpec.queryParam("size", "1"); + requestSpec.header("page", "0"); + if (authEnabled) { + requestSpec.header("Authorization", "Bearer " + scenarioScopeState.accessToken); + } + + scenarioScopeState.response = RestAssured.given(requestSpec).baseUri(operationsAppConfig.operationAppContactPoint).expect() + .spec(new ResponseSpecBuilder().expectStatusCode(expectedStatus).build()).when() + .get(operationsAppConfig.transfersEndpoint).andReturn().asString(); + + logger.info("GetTxn Request Response: " + scenarioScopeState.response); + assertThat(scenarioScopeState.response).containsMatch("startedAt"); + assertThat(scenarioScopeState.response).containsMatch("completedAt"); + }); + } + + @When("I call the get txn API with expected status of {int} and txnId with PayeeDFSPId check") + public void iCallTheGetTxnAPIWithExpectedStatusOfAndTxnIdWithPayeeDFSPIdCheck(int expectedStatus) { + await().atMost(awaitMost, SECONDS).pollInterval(pollInterval, SECONDS).untilAsserted(() -> { + RequestSpecification requestSpec = Utils.getDefaultSpec(scenarioScopeState.tenant); + requestSpec.queryParam("transactionId", scenarioScopeState.transactionId); + requestSpec.queryParam("size", "1"); + requestSpec.header("page", "0"); + if (authEnabled) { + requestSpec.header("Authorization", "Bearer " + scenarioScopeState.accessToken); + } + + scenarioScopeState.response = RestAssured.given(requestSpec).baseUri(operationsAppConfig.operationAppContactPoint).expect() + .spec(new ResponseSpecBuilder().expectStatusCode(expectedStatus).build()).when() + .get(operationsAppConfig.transfersEndpoint).andReturn().asString(); + + logger.info("GetTxn Request Response: " + scenarioScopeState.response); + assertThat(scenarioScopeState.response).containsMatch("startedAt"); + assertThat(scenarioScopeState.response).containsMatch("completedAt"); + assert scenarioScopeState.response.contains("payeeDfspId"); + JSONObject jsonObject = new JSONObject(scenarioScopeState.response); + JSONArray jsonArray = (JSONArray) jsonObject.get("content"); + JSONObject content = (JSONObject) jsonArray.get(0); + String payeeDfspId = content.get("payeeDfspId").toString(); + assertThat(payeeDfspId).isNotEmpty(); + assertThat(payeeDfspId).isNotEqualTo("null"); + String payeeIdentifier = content.get("payeePartyId").toString(); + // assertThat(payeeIdentifier).isEqualTo(scenarioScopeState.payerIdentifier); + }); + } + + @And("I should have PayeeFspId as {string}") + public void iShouldHavePayeeFspIdAs(String payeeDfspId) throws JSONException { + assert scenarioScopeState.response.contains("payeeDfspId"); + JSONObject jsonObject = new JSONObject(scenarioScopeState.response); + JSONArray jsonArray = (JSONArray) jsonObject.get("content"); + JSONObject content = (JSONObject) jsonArray.get(0); + String value = content.get("payeeDfspId").toString(); + String payeeIdentifier = content.get("payeePartyId").toString(); + assertThat(value).isEqualTo(payeeDfspId); + // assertThat(payeeIdentifier).isEqualTo(scenarioScopeState.payerIdentifier); + } + +} diff --git a/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/cucumber/stepdef/MockServerStepDef.java b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/cucumber/stepdef/MockServerStepDef.java new file mode 100644 index 000000000..55bd7288a --- /dev/null +++ b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/cucumber/stepdef/MockServerStepDef.java @@ -0,0 +1,148 @@ +package org.mifos.integrationtest.cucumber.stepdef; + +import static com.github.tomakehurst.wiremock.client.WireMock.configureFor; +import static com.github.tomakehurst.wiremock.client.WireMock.delete; +import static com.github.tomakehurst.wiremock.client.WireMock.deleteRequestedFor; +import static com.github.tomakehurst.wiremock.client.WireMock.get; +import static com.github.tomakehurst.wiremock.client.WireMock.getRequestedFor; +import static com.github.tomakehurst.wiremock.client.WireMock.post; +import static com.github.tomakehurst.wiremock.client.WireMock.postRequestedFor; +import static com.github.tomakehurst.wiremock.client.WireMock.put; +import static com.github.tomakehurst.wiremock.client.WireMock.putRequestedFor; +import static com.github.tomakehurst.wiremock.client.WireMock.status; +import static com.github.tomakehurst.wiremock.client.WireMock.stubFor; +import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo; +import static com.github.tomakehurst.wiremock.client.WireMock.urlPathMatching; +import static com.github.tomakehurst.wiremock.client.WireMock.verify; +import static com.google.common.truth.Truth.assertThat; +import static java.util.concurrent.TimeUnit.SECONDS; +import static org.awaitility.Awaitility.await; +import static org.mifos.integrationtest.common.Utils.getDefaultSpec; + +import io.cucumber.java.ParameterType; +import io.cucumber.java.en.And; +import io.cucumber.java.en.Given; +import io.cucumber.java.en.Then; +import io.cucumber.java.en.When; +import io.restassured.RestAssured; +import io.restassured.builder.ResponseSpecBuilder; +import io.restassured.specification.RequestSender; +import org.mifos.integrationtest.common.HttpMethod; +import org.springframework.beans.factory.annotation.Value; + +public class MockServerStepDef extends BaseStepDef { + + private static Boolean wiremockStarted = false; + + @Value("${mock-server.port}") + private int mockServerPortFromConfig; + + @Given("I can inject MockServer") + public void checkIfMockServerIsInjected() { + assertThat(mockServer).isNotNull(); + } + + @Then("I should be able to get instance of mock server") + public void getInstanceOfMockServer() throws InterruptedException { + assertThat(mockServer.getMockServer()).isNotNull(); + assertThat(mockServer.getMockServer().port()).isEqualTo(mockServerPortFromConfig); + } + + @ParameterType(name = "httpMethod", value = ".*") + public HttpMethod httpMethod(String httpMethod) { + httpMethod = httpMethod.replace("\"", ""); + logger.debug("HTTP METHOD: $$$$$$: {}", httpMethod); + return HttpMethod.valueOf(httpMethod); + } + + @And("I can register the stub with {string} endpoint for {httpMethod} request with status of {int}") + public void startStub(String endpoint, HttpMethod httpMethod, int status) { + switch (httpMethod) { + case GET -> { + stubFor(get(urlPathMatching(endpoint)).willReturn(status(status))); + } + case POST -> { + stubFor(post(urlPathMatching(endpoint)).willReturn(status(status))); + } + case PUT -> { + stubFor(put(urlPathMatching(endpoint)).willReturn(status(status))); + } + case DELETE -> { + stubFor(delete(urlPathMatching(endpoint)).willReturn(status(status))); + } + } + } + + @When("I make the {httpMethod} request to {string} endpoint with expected status of {int}") + public void hitStubEndpoint(HttpMethod httpMethod, String endpoint, int expectedStatus) { + RequestSender requestSender = RestAssured.given(getDefaultSpec()).baseUri(mockServer.getBaseUri()).expect() + .spec(new ResponseSpecBuilder().expectStatusCode(expectedStatus).build()).when(); + + switch (httpMethod) { + case GET -> { + requestSender.get(endpoint); + } + case POST -> { + requestSender.post(endpoint).andReturn().asString(); + } + case PUT -> { + requestSender.put(endpoint).andReturn().asString(); + } + case DELETE -> { + requestSender.delete(endpoint); + } + } + } + + @Then("I should be able to verify that the {httpMethod} method to {string} endpoint received {int} request") + public void verifyStub(HttpMethod httpMethod, String endpoint, int numberOfRequest) { + await().atMost(awaitMost, SECONDS).pollInterval(pollInterval, SECONDS).untilAsserted(() -> { + switch (httpMethod) { + case GET -> { + verify(numberOfRequest, getRequestedFor(urlEqualTo(endpoint))); + } + case POST -> { + verify(numberOfRequest, postRequestedFor(urlEqualTo(endpoint))); + } + case PUT -> { + verify(numberOfRequest, putRequestedFor(urlEqualTo(endpoint))); + } + case DELETE -> { + verify(numberOfRequest, deleteRequestedFor(urlEqualTo(endpoint))); + } + } + }); + } + + @And("I can start mock server") + public void startMockServer() { + mockServer.getMockServer().start(); + configureFor("localhost", mockServer.getMockServer().port()); + } + + @And("I can stop mock server") + public void stopMockServer() { + mockServer.getMockServer().stop(); + } + + @Given("I will start the mock server") + public void iWillStartTheMockServer() { + if (!wiremockStarted) { + checkIfMockServerIsInjected(); + startMockServer(); + } + } + + @And("I will register the stub with {string} endpoint for {httpMethod} request with status of {int}") + public void iWillRegisterTheStubWithEndpointForRequestWithStatusOf(String endpoint, HttpMethod httpMethod, int status) { + if (!wiremockStarted) { + startStub(endpoint, httpMethod, status); + + } + } + + @Then("I will update the mock server and register stub as done") + public void iWillUpdateTheMockServerAndRegisterStubAsDone() { + wiremockStarted = true; + } +} diff --git a/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/cucumber/stepdef/MojaloopDef.java b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/cucumber/stepdef/MojaloopDef.java new file mode 100644 index 000000000..cbb0ede07 --- /dev/null +++ b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/cucumber/stepdef/MojaloopDef.java @@ -0,0 +1,278 @@ +package org.mifos.integrationtest.cucumber.stepdef; + +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import io.cucumber.core.internal.com.fasterxml.jackson.core.JsonProcessingException; +import io.cucumber.core.internal.com.fasterxml.jackson.databind.ObjectMapper; +import io.restassured.RestAssured; +import io.restassured.builder.ResponseSpecBuilder; +import io.restassured.response.Response; +import io.restassured.specification.RequestSpecification; +import java.util.UUID; +import org.mifos.integrationtest.common.Utils; +import org.mifos.integrationtest.common.dto.mojaloop.AddParticipantRequestBody; +import org.mifos.integrationtest.common.dto.mojaloop.AddUserAlsRequest; +import org.mifos.integrationtest.common.dto.mojaloop.Amount; +import org.mifos.integrationtest.common.dto.mojaloop.CallbackRequestBody; +import org.mifos.integrationtest.common.dto.mojaloop.Endpoint; +import org.mifos.integrationtest.common.dto.mojaloop.HubAccountSetupRequestBody; +import org.mifos.integrationtest.common.dto.mojaloop.InitialPositionAndLimitRequestBody; +import org.mifos.integrationtest.common.dto.mojaloop.Limit; +import org.mifos.integrationtest.common.dto.mojaloop.OracleOnboardRequestBody; +import org.mifos.integrationtest.common.dto.mojaloop.RecordFundsRequestBody; +import org.mifos.integrationtest.common.dto.mojaloop.SettlementModelRequestBody; +import org.mifos.integrationtest.config.MojaloopCallbackEndpoints; +import org.mifos.integrationtest.config.MojaloopConfig; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component +public class MojaloopDef { + + @Autowired + MojaloopConfig mojaloopConfig; + + @Autowired + ObjectMapper objectMapper; + + @Autowired + MojaloopCallbackEndpoints callbackEndpoints; + + Logger logger = LoggerFactory.getLogger(this.getClass()); + + private static final String CURRENCY = "USD"; + + protected String setBodyAddAlsUser(String fspId) throws JsonProcessingException { + AddUserAlsRequest addUserAlsRequest = new AddUserAlsRequest(); + addUserAlsRequest.setCurrency(CURRENCY); + addUserAlsRequest.setFspId(fspId); + return objectMapper.writeValueAsString(addUserAlsRequest); + } + + protected Boolean isHubAccountTypesAdded() { + + RequestSpecification requestSpec = Utils.getDefaultSpec(); + String endpoint = mojaloopConfig.mojaloopHubAccount; + String response = RestAssured.given(requestSpec).baseUri(mojaloopConfig.mojaloopCentralLedgerBaseurl).when().expect() + .spec(new ResponseSpecBuilder().expectStatusCode(200).build()).when().get(endpoint).andReturn().asString(); + + int count = JsonParser.parseString(response).getAsJsonArray().size(); + logger.info(String.valueOf(count)); + return count >= 2; + } + + protected void hubMultilateralSettlement() throws JsonProcessingException { + + RequestSpecification requestSpec = Utils.getDefaultSpec(); + requestSpec.header("Content-Type", "application/json"); + String endpoint = mojaloopConfig.mojaloopHubAccount; + String requestBody = objectMapper.writeValueAsString(new HubAccountSetupRequestBody("HUB_MULTILATERAL_SETTLEMENT", CURRENCY)); + Response response = RestAssured.given(requestSpec).baseUri(mojaloopConfig.mojaloopCentralLedgerBaseurl).body(requestBody).when() + .post(endpoint); + + validateResponse(response, "3003"); + } + + protected void hubReconciliation() throws JsonProcessingException { + + RequestSpecification requestSpec = Utils.getDefaultSpec(); + requestSpec.header("Content-Type", "application/json"); + String endpoint = mojaloopConfig.mojaloopHubAccount; + String requestBody = objectMapper.writeValueAsString(new HubAccountSetupRequestBody("HUB_RECONCILIATION", CURRENCY)); + Response response = RestAssured.given(requestSpec).baseUri(mojaloopConfig.mojaloopCentralLedgerBaseurl).body(requestBody).when() + .post(endpoint); + + validateResponse(response, "3003"); + } + + protected Boolean isSettlementModelsCreated() { + RequestSpecification requestSpec = Utils.getDefaultSpec(); + String endpoint = mojaloopConfig.settlementModel; + String response = RestAssured.given(requestSpec).baseUri(mojaloopConfig.mojaloopCentralLedgerBaseurl).when().expect() + .spec(new ResponseSpecBuilder().expectStatusCode(200).build()).when().get(endpoint).andReturn().asString(); + + int count = JsonParser.parseString(response).getAsJsonArray().size(); + logger.info(String.valueOf(count)); + return count >= 2; + } + + protected void createSettlementModelDeferredNet() throws JsonProcessingException { + + RequestSpecification requestSpec = Utils.getDefaultSpec(); + requestSpec.header("Content-Type", "application/json"); + String endpoint = mojaloopConfig.settlementModel; + String requestBody = objectMapper.writeValueAsString(settlementModelRequestBody("DEFERREDNET")); + + Response response = RestAssured.given(requestSpec).baseUri(mojaloopConfig.mojaloopCentralLedgerBaseurl).body(requestBody).when() + .post(endpoint); + + validateResponse(response, "3000"); + } + + protected void createSettlementModelDeferredNetUSD() { + + RequestSpecification requestSpec = Utils.getDefaultSpec(); + requestSpec.header("Content-Type", "application/json"); + String endpoint = mojaloopConfig.settlementModel; + SettlementModelRequestBody requestBody = settlementModelRequestBody("DEFERREDNETUSD"); + requestBody.setCurrency(CURRENCY); + + Response response = RestAssured.given(requestSpec).baseUri(mojaloopConfig.mojaloopCentralLedgerBaseurl).body(requestBody).when() + .post(endpoint); + + validateResponse(response, "3000"); + } + + protected SettlementModelRequestBody settlementModelRequestBody(String name) { + SettlementModelRequestBody requestBody = SettlementModelRequestBody.builder().name(name).settlementGranularity("NET") + .settlementInterchange("MULTILATERAL").settlementDelay("DEFERRED").requireLiquidityCheck(true).ledgerAccountType("POSITION") + .autoPositionReset(true).settlementAccountType("SETTLEMENT").build(); + return requestBody; + } + + protected void addFsp(String fsp) throws JsonProcessingException { + + RequestSpecification requestSpec = Utils.getDefaultSpec(); + requestSpec.header("Content-Type", "application/json"); + String endpoint = mojaloopConfig.participant; + String requestBody = objectMapper.writeValueAsString(new AddParticipantRequestBody(fsp, CURRENCY)); + + Response response = RestAssured.given(requestSpec).baseUri(mojaloopConfig.mojaloopCentralLedgerBaseurl).body(requestBody).when() + .post(endpoint); + + validateResponse(response, "3000"); + } + + protected void addInitialPositionAndLimit(String fsp) throws JsonProcessingException { + + RequestSpecification requestSpec = Utils.getDefaultSpec(); + requestSpec.header("Content-Type", "application/json"); + String endpoint = mojaloopConfig.initialPositionAndLimitEndpoint.replaceAll("\\{\\{fsp\\}\\}", fsp); + + Response response = RestAssured.given(requestSpec).baseUri(mojaloopConfig.mojaloopCentralLedgerBaseurl) + .body(getInitialPositionAndLimitRequestBody()).when().post(endpoint); + + validateResponse(response, "2001"); + } + + public String getInitialPositionAndLimitRequestBody() throws JsonProcessingException { + Limit limit = new Limit("NET_DEBIT_CAP", 1000000L); + InitialPositionAndLimitRequestBody requestBody = new InitialPositionAndLimitRequestBody(CURRENCY, limit, 0L); + return objectMapper.writeValueAsString(requestBody); + } + + protected void addCallbackEndpoint(String client, String type, String value) throws JsonProcessingException { + + value = value.replaceAll("\\{\\{fsp\\}\\}", client); + CallbackRequestBody requestBody = new CallbackRequestBody(type, value); + logger.info(objectMapper.writeValueAsString(requestBody)); + RequestSpecification requestSpec = Utils.getDefaultSpec(); + requestSpec.header("Content-Type", "application/json"); + String endpoint = mojaloopConfig.addCallbackEndpoint.replaceAll("\\{\\{fsp\\}\\}", client); + + Response responseBody = RestAssured.given(requestSpec).baseUri(mojaloopConfig.mojaloopCentralLedgerBaseurl) + .body(objectMapper.writeValueAsString(requestBody)).expect().spec(new ResponseSpecBuilder().expectStatusCode(201).build()) + .when().post(endpoint).andReturn(); + + } + + protected Boolean getCallbackEndpoints(String client) { + RequestSpecification requestSpec = Utils.getDefaultSpec(); + String endpoint = mojaloopConfig.addCallbackEndpoint.replaceAll("\\{\\{fsp\\}\\}", client); + + String responseBody = RestAssured.given(requestSpec).baseUri(mojaloopConfig.mojaloopCentralLedgerBaseurl).expect() + .spec(new ResponseSpecBuilder().expectStatusCode(200).build()).when().get(endpoint).andReturn().asString(); + + int count = JsonParser.parseString(responseBody).getAsJsonArray().size(); + logger.info(String.valueOf(count)); + int callbackEndpointsRegistered = callbackEndpoints.getCallbackEndpoints().size(); + return count >= callbackEndpointsRegistered; + } + + protected void setCallbackEndpoints() { + + String payerFsp = mojaloopConfig.payerFspId; + String payeeFsp = mojaloopConfig.payeeFspId; + String payeeFsp2 = mojaloopConfig.payeeFspId2; + String payeeFsp3 = mojaloopConfig.payeeFspId3; + callbackEndpoints.getCallbackEndpoints().forEach(callback -> { + String value = callback.getValue().replaceAll("\\{\\{CALLBACK_HOST\\}\\}", "http://" + mojaloopConfig.mlConnectorHost); + try { + addCallbackEndpoint(payerFsp, callback.getType(), value); + addCallbackEndpoint(payeeFsp, callback.getType(), value); + addCallbackEndpoint(payeeFsp2, callback.getType(), value); + addCallbackEndpoint(payeeFsp3, callback.getType(), value); + } catch (JsonProcessingException e) { + throw new RuntimeException(e); + } + }); + } + + protected void recordFunds(String fsp) throws JsonProcessingException { + + RequestSpecification requestSpec = Utils.getDefaultSpec(); + requestSpec.header("Content-Type", "application/json"); + String endpoint = mojaloopConfig.recordFundsEndpoint.replaceAll("\\{\\{fsp\\}\\}", fsp) + .replaceAll("\\{\\{payerfspSettlementAccountId\\}\\}", "4"); + String requestBody = objectMapper.writeValueAsString(getRecordFundsRequestBody()); + + Response responseBody = RestAssured.given(requestSpec).baseUri(mojaloopConfig.mojaloopCentralLedgerBaseurl).body(requestBody) + .expect().spec(new ResponseSpecBuilder().expectStatusCode(202).build()).when().post(endpoint).andReturn(); + } + + private RecordFundsRequestBody getRecordFundsRequestBody() { + Amount amount = new Amount(5000L, CURRENCY); + return RecordFundsRequestBody.builder().transferId(UUID.randomUUID().toString()).externalReference("string").action("recordFundsIn") + .reason("string").amount(amount).build(); + } + + protected Boolean oracleExists() { + RequestSpecification requestSpec = Utils.getDefaultSpec(); + requestSpec.header("Content-Type", "application/json"); + requestSpec.header("Date", ""); + String endpoint = mojaloopConfig.oracleEndpoint; + Response response = RestAssured.given(requestSpec).baseUri(mojaloopConfig.mojaloopAccountLookupAdminBaseurl).when().expect() + .spec(new ResponseSpecBuilder().expectStatusCode(200).build()).when().get(endpoint); + int count = JsonParser.parseString(response.getBody().asString()).getAsJsonArray().size(); + logger.info(String.valueOf(count)); + return count >= 1; + } + + protected void oracleOnboard() throws JsonProcessingException { + RequestSpecification requestSpec = Utils.getDefaultSpec(); + requestSpec.header("Content-Type", "application/json"); + requestSpec.header("Date", ""); + String endpoint = mojaloopConfig.oracleEndpoint; + String requestBody = objectMapper.writeValueAsString(getOracleOnboardRequestBody()); + + Response response = RestAssured.given(requestSpec).baseUri(mojaloopConfig.mojaloopAccountLookupAdminBaseurl).body(requestBody) + .when().post(endpoint); + + validateResponse(response, "2001"); + } + + private OracleOnboardRequestBody getOracleOnboardRequestBody() { + Endpoint endpoint = new Endpoint("http://moja-simulator/oracle", "URL"); + return OracleOnboardRequestBody.builder().oracleIdType("MSISDN").endpoint(endpoint).currency(CURRENCY).isDefault(true).build(); + } + + private void validateResponse(Response response, String acceptedErrorCode) { + + if (response.getStatusCode() == 400 || response.getStatusCode() == 500) { + JsonObject jsonObject = JsonParser.parseString(response.getBody().asString()).getAsJsonObject(); + String errorCode = jsonObject.getAsJsonObject().get("errorInformation").getAsJsonObject().get("errorCode").getAsString(); + String errorDesc = jsonObject.getAsJsonObject().get("errorInformation").getAsJsonObject().get("errorDescription").getAsString(); + logger.info(errorCode); + logger.info(errorDesc); + if (!errorCode.equals(acceptedErrorCode) || !errorDesc.contains("already")) { + + throw new RuntimeException(); + } + // todo - validate message as well + } else if (!String.valueOf(response.getStatusCode()).matches("2\\d{2}")) { + throw new RuntimeException(); + } + } +} diff --git a/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/cucumber/stepdef/MojaloopStepDef.java b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/cucumber/stepdef/MojaloopStepDef.java new file mode 100644 index 000000000..3f839c578 --- /dev/null +++ b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/cucumber/stepdef/MojaloopStepDef.java @@ -0,0 +1,175 @@ +package org.mifos.integrationtest.cucumber.stepdef; + +import static com.google.common.truth.Truth.assertThat; +import static io.restassured.config.EncoderConfig.encoderConfig; + +import io.cucumber.core.internal.com.fasterxml.jackson.core.JsonProcessingException; +import io.cucumber.java.en.Given; +import io.cucumber.java.en.Then; +import io.restassured.RestAssured; +import io.restassured.builder.ResponseSpecBuilder; +import io.restassured.specification.RequestSpecification; +import org.mifos.integrationtest.common.Utils; +import org.mifos.integrationtest.config.MojaloopConfig; +import org.mifos.integrationtest.util.Util; +import org.springframework.beans.factory.annotation.Autowired; + +public class MojaloopStepDef extends BaseStepDef { + + @Autowired + MojaloopConfig mojaloopConfig; + + @Autowired + MojaloopDef mojaloopDef; + + @Autowired + ScenarioScopeState scenarioScopeState; + + private static final String CONTENT_TYPE = "application/vnd.interoperability.participants+json;version=1.0"; + + @Then("I add {string} to als") + public void addUsersToALS(String client) throws JsonProcessingException { + + String clientIdentifierId; + String fspId; + switch (client) { + case "payer" -> { + clientIdentifierId = scenarioScopeState.payerIdentifier; + fspId = mojaloopConfig.payerFspId; + } + case "payee2" -> { + clientIdentifierId = scenarioScopeState.payeeIdentifier; + fspId = mojaloopConfig.payeeFspId2; + } + case "payee3" -> { + clientIdentifierId = scenarioScopeState.payeeIdentifier; + fspId = mojaloopConfig.payeeFspId3; + } + default -> { + clientIdentifierId = scenarioScopeState.payeeIdentifier; + fspId = mojaloopConfig.payeeFspId; + } + } + + RequestSpecification requestSpec = Utils.getDefaultSpec(); + requestSpec.header("FSPIOP-Source", fspId); + requestSpec.header("Date", getCurrentDateInFormat()); + requestSpec.header("Accept", CONTENT_TYPE); + // requestSpec.header("Content-Type", "application/vnd.interoperability.participants+json;version=1.0"); + + String endpoint = mojaloopConfig.addUserToAlsEndpoint; + endpoint = endpoint.replaceAll("\\{\\{identifierType\\}\\}", "MSISDN"); + endpoint = endpoint.replaceAll("\\{\\{identifier\\}\\}", clientIdentifierId); + + String requestBody = mojaloopDef.setBodyAddAlsUser(fspId); + + logger.info(mojaloopConfig.mojaloopBaseurl); + logger.info(requestBody); + logger.info(endpoint); + + String response = RestAssured.given(requestSpec).baseUri(mojaloopConfig.mojaloopBaseurl) + .config(RestAssured.config().encoderConfig(encoderConfig().appendDefaultContentCharsetToContentTypeIfUndefined(false))) + .body(requestBody).contentType(CONTENT_TYPE).expect().spec(new ResponseSpecBuilder().expectStatusCode(202).build()).when() + .post(endpoint).andReturn().asString(); + + logger.info(response); + assertThat(response).isNotNull(); + } + + @Then("I add {string} with account id {string} to als") + public void addBudgetAccountToALS(String client, String accountId) throws JsonProcessingException { + + String clientIdentifierId; + String fspId; + switch (client) { + case "payer" -> { + clientIdentifierId = scenarioScopeState.payerIdentifier; + fspId = mojaloopConfig.payerFspId; + } + case "payee2" -> { + clientIdentifierId = scenarioScopeState.payeeIdentifier; + fspId = mojaloopConfig.payeeFspId2; + } + case "payee3" -> { + clientIdentifierId = scenarioScopeState.payeeIdentifier; + fspId = mojaloopConfig.payeeFspId3; + } + default -> { + clientIdentifierId = scenarioScopeState.payeeIdentifier; + fspId = mojaloopConfig.payeeFspId; + } + } + + RequestSpecification requestSpec = Utils.getDefaultSpec(); + requestSpec.header("FSPIOP-Source", fspId); + requestSpec.header("Date", getCurrentDateInFormat()); + requestSpec.header("Accept", CONTENT_TYPE); + + String endpoint = mojaloopConfig.addUserToAlsEndpoint; + String identifierType = "MSISDN"; + endpoint = Util.getFormattedEndpoint(endpoint, "{{identifierType}}", identifierType); + endpoint = Util.getFormattedEndpoint(endpoint, "{{identifier}}", accountId); + String identifierId = (scenarioScopeState.creditParty == null) ? scenarioScopeState.payeeIdentifier + : scenarioScopeState.creditParty; + endpoint = String.format(endpoint, identifierType, identifierId); + String requestBody = mojaloopDef.setBodyAddAlsUser(fspId); + + logger.info(mojaloopConfig.mojaloopBaseurl); + logger.info(requestBody); + logger.info(endpoint); + + String response = RestAssured.given(requestSpec).baseUri(mojaloopConfig.mojaloopBaseurl) + .config(RestAssured.config().encoderConfig(encoderConfig().appendDefaultContentCharsetToContentTypeIfUndefined(false))) + .body(requestBody).contentType(CONTENT_TYPE).expect().spec(new ResponseSpecBuilder().expectStatusCode(202).build()).when() + .post(endpoint).andReturn().asString(); + + logger.info(response); + assertThat(response).isNotNull(); + } + + @Given("I am setting up Mojaloop") + public void mojaloopSetup() throws JsonProcessingException { + + String payerFsp = mojaloopConfig.payerFspId; + String payeeFsp = mojaloopConfig.payeeFspId; + String payeeFsp2 = mojaloopConfig.payeeFspId2; + String payeeFsp3 = mojaloopConfig.payeeFspId3; + + if (!mojaloopDef.isHubAccountTypesAdded()) { + + logger.info("Calling hub account apis"); + + mojaloopDef.hubMultilateralSettlement(); + mojaloopDef.hubReconciliation(); + } + + if (!mojaloopDef.isSettlementModelsCreated()) { + + logger.info("Calling Settlement Models apis"); + + mojaloopDef.createSettlementModelDeferredNet(); + mojaloopDef.createSettlementModelDeferredNetUSD(); + } + + mojaloopDef.addFsp(payerFsp); + mojaloopDef.addFsp(payeeFsp); + mojaloopDef.addFsp(payeeFsp2); + mojaloopDef.addFsp(payeeFsp3); + mojaloopDef.addInitialPositionAndLimit(payerFsp); + mojaloopDef.addInitialPositionAndLimit(payeeFsp); + mojaloopDef.addInitialPositionAndLimit(payeeFsp2); + mojaloopDef.addInitialPositionAndLimit(payeeFsp3); + + if (!mojaloopDef.getCallbackEndpoints(payerFsp) || !mojaloopDef.getCallbackEndpoints(payeeFsp) + || !mojaloopDef.getCallbackEndpoints(payeeFsp2) || !mojaloopDef.getCallbackEndpoints(payeeFsp3)) { + mojaloopDef.setCallbackEndpoints(); + } + + mojaloopDef.recordFunds(payerFsp); + + if (!mojaloopDef.oracleExists()) { + mojaloopDef.oracleOnboard(); + } + } + +} diff --git a/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/cucumber/stepdef/NCStepDef.java b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/cucumber/stepdef/NCStepDef.java new file mode 100644 index 000000000..33c7834aa --- /dev/null +++ b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/cucumber/stepdef/NCStepDef.java @@ -0,0 +1,129 @@ +package org.mifos.integrationtest.cucumber.stepdef; + +import static com.google.common.truth.Truth.assertThat; +import static java.util.concurrent.TimeUnit.SECONDS; +import static org.awaitility.Awaitility.await; + +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import io.cucumber.java.en.And; +import io.cucumber.java.en.Then; +import io.cucumber.java.en.When; +import io.restassured.RestAssured; +import io.restassured.builder.ResponseSpecBuilder; +import io.restassured.specification.RequestSpecification; +import java.util.UUID; +import org.awaitility.core.ConditionTimeoutException; +import org.json.JSONException; +import org.json.JSONObject; +import org.mifos.integrationtest.common.TransferHelper; +import org.mifos.integrationtest.common.Utils; +import org.mifos.integrationtest.config.NetflixConductorConfig; +import org.springframework.beans.factory.annotation.Autowired; + +public class NCStepDef extends BaseStepDef { + + @Autowired + NetflixConductorConfig netflixConductorConfig; + + @Autowired + ScenarioScopeState scenarioScopeState; + + @When("I make a call to nc server health API with expected status 200") + public void ncHealthAPICall() { + RequestSpecification requestSpec = Utils.getDefaultSpec(); + scenarioScopeState.response = RestAssured.given(requestSpec).baseUri(netflixConductorConfig.conductorServerContactPoint).expect() + .spec(new ResponseSpecBuilder().expectStatusCode(200).build()).when().get(netflixConductorConfig.healthEndpoint).andReturn() + .asString(); + } + + @Then("I get the value of Healthy as true in response") + public void checkHealthyState() throws JSONException { + JSONObject response = new JSONObject(scenarioScopeState.response); + assertThat(response).isNotNull(); + String healthStatus = response.getString("healthy"); + assertThat(healthStatus).isEqualTo("true"); + } + + @And("I have the request body for transfer") + public void iHaveRequestBody() throws JSONException { + String payerIdentifier = scenarioScopeState.payerIdentifier; + JSONObject collectionRequestBody; + + if (payerIdentifier != null) { + collectionRequestBody = TransferHelper.getTransferRequestBody(payerIdentifier); + } else { + collectionRequestBody = TransferHelper.getTransferRequestBody(); + } + + scenarioScopeState.requestBody = collectionRequestBody; + logger.info(String.valueOf(scenarioScopeState.requestBody)); + } + + @When("I call the channel transfer API with client correlation id and expected status of {int}") + public void channelTransferAPICall(int expectedStatus) { + RequestSpecification requestSpec = Utils.getDefaultSpec(scenarioScopeState.tenant); + requestSpec.header(Utils.X_CORRELATIONID, UUID.randomUUID()); + scenarioScopeState.response = RestAssured.given(requestSpec).baseUri("http://dpga-connector-chanel.sandbox.fynarfin.io/") + .body(scenarioScopeState.requestBody.toString()).expect() + .spec(new ResponseSpecBuilder().expectStatusCode(expectedStatus).build()).when() + .post(channelConnectorConfig.transferEndpoint).andReturn().asString(); + } + + @When("I call the get workflow API in with workflow id as path variable") + public void getWorkflow() { + RequestSpecification requestSpec = Utils.getDefaultSpec(); + requestSpec.param("includeTasks", false); + scenarioScopeState.response = RestAssured.given(requestSpec).baseUri(netflixConductorConfig.conductorServerContactPoint).expect() + .spec(new ResponseSpecBuilder().expectStatusCode(200).build()).when() + .get(netflixConductorConfig.workflowEndpoint + "/" + scenarioScopeState.transactionId).andReturn().asString(); + } + + @Then("I should get valid status") + public void checkStatus() throws JSONException { + JSONObject response = new JSONObject(scenarioScopeState.response); + assertThat(response).isNotNull(); + String status = response.getString("status"); + assertThat(status).isAnyOf("COMPLETED", "TERMINATED", "RUNNING"); + } + + @When("I call the get transfer API in ops app with transactionId as parameter") + public void iCallTheTransferAPIWithTransactionId() throws InterruptedException { + RequestSpecification requestSpec = Utils.getDefaultSpec(scenarioScopeState.tenant); + if (authEnabled) { + requestSpec.header("Authorization", "Bearer " + scenarioScopeState.accessToken); + } + requestSpec.queryParam("transactionId", scenarioScopeState.transactionId); + + try { + await().atMost(awaitMost, SECONDS).pollInterval(pollInterval, SECONDS).until(() -> { + scenarioScopeState.response = RestAssured.given(requestSpec).baseUri(operationsAppConfig.dpgOperationAppContactPoint) + .expect().spec(new ResponseSpecBuilder().expectStatusCode(200).build()).when() + .get(operationsAppConfig.transfersEndpoint).andReturn().asString(); + + logger.info(scenarioScopeState.transactionId); + logger.info("Get Transfer Response: " + scenarioScopeState.response); + return true; // Replace this with the actual condition you are waiting for + }); + } catch (ConditionTimeoutException e) { + logger.debug("Timeout waiting for condition", e); + throw new IllegalStateException("Timeout waiting for condition", e); + } + + logger.info(scenarioScopeState.transactionId); + logger.info("Get Transfer Response: " + scenarioScopeState.response); + } + + @Then("I should get transfer state as completed") + public void assertValues() throws JSONException { + JsonObject jsonObject = JsonParser.parseString(scenarioScopeState.response).getAsJsonObject(); + String status = jsonObject.getAsJsonArray("content").get(0).getAsJsonObject().get("status").getAsString(); + assertThat(status).isAnyOf("COMPLETED", "TERMINATED"); + } + + @Then("I verify that the current balance is {long}") + public void isAccountBalanceValid(long expectedBalance) { + assertThat(scenarioScopeState.currentBalance).isEqualTo(expectedBalance); + } + +} diff --git a/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/cucumber/stepdef/OperationsStepDef.java b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/cucumber/stepdef/OperationsStepDef.java new file mode 100644 index 000000000..5fa0588c3 --- /dev/null +++ b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/cucumber/stepdef/OperationsStepDef.java @@ -0,0 +1,170 @@ +package org.mifos.integrationtest.cucumber.stepdef; + +import static com.google.common.truth.Truth.assertThat; +import static java.util.concurrent.TimeUnit.SECONDS; +import static org.awaitility.Awaitility.await; + +import io.cucumber.core.internal.com.fasterxml.jackson.core.JsonProcessingException; +import io.cucumber.java.After; +import io.cucumber.java.Before; +import io.cucumber.java.en.And; +import io.cucumber.java.en.Given; +import io.cucumber.java.en.Then; +import io.cucumber.java.en.When; +import io.restassured.RestAssured; +import io.restassured.builder.ResponseSpecBuilder; +import io.restassured.specification.RequestSpecification; +import java.util.HashMap; +import java.util.Map; +import lombok.extern.slf4j.Slf4j; +import org.mifos.integrationtest.common.Utils; +import org.mifos.integrationtest.common.dto.operationsapp.BatchPaginatedResponse; + +@Slf4j +public class OperationsStepDef extends BaseStepDef { + + // todo remove once @gov-223 testing is done + @Given("I am happy") + public void happy() { + assertThat(1).isEqualTo(1); + } + + // todo remove once @gov-223 testing is done + @When("I get chocolate") + public void whenHappy() { + assertThat(1).isEqualTo(1); + } + + // todo remove once @gov-223 testing is done + @Then("I get more happy") + public void moreHappy() { + assertThat(1).isEqualTo(1); + } + + @Before("@ops-batch-setup") + public void operationsBatchTestSetup() { + log.info("Running @ops-batch-setup"); + batchDbSetup(); + } + + @After("@ops-batch-teardown") + public void operationsBatchTestTearDown() { + log.info("Running @ops-batch-teardown"); + batchDbTearDown(); + } + + @When("I call the batches endpoint with expected status of {int} with total batches {int}") + public void simpleBatchesApiCallWithNoHeader(int expectedStatus, int totalBatches) { + await().atMost(awaitMost, SECONDS).pollDelay(pollDelay, SECONDS).pollInterval(pollInterval, SECONDS).untilAsserted(() -> { + String date = BaseStepDef.getCurrentDateInFormat(); + updateQueryParam(scenarioScopeState.batchesEndpointQueryParam, "dateTo", date); + log.info("Query params: {}", scenarioScopeState.batchesEndpointQueryParam); + callBatchesEndpoint(expectedStatus, scenarioScopeState.batchesEndpointQueryParam, totalBatches); + }); + } + + @And("The count of batches should be {int}") + public void assertCountOfBatches(int expectedCount) { + assertThat(scenarioScopeState.batchesResponse).isNotNull(); + assertThat(scenarioScopeState.batchesResponse.getData()).isNotNull(); + assertThat(scenarioScopeState.batchesResponse.getData().size()).isEqualTo(expectedCount); + } + + @Then("I am able to parse batch paginated response into DTO") + public void parseBatchPaginatedDto() { + assertThat(scenarioScopeState.response).isNotNull(); + parseBatchesResponse(scenarioScopeState.response); + } + + @And("I add the query param key: {string} value: {string}") + public void updateQueryParam(String key, Object value) { + updateQueryParam(scenarioScopeState.batchesEndpointQueryParam, key, value); + } + + @And("I add batchId query param") + public void addBatchIdQueryParam() { + assertNotNull(scenarioScopeState.batchId); + updateQueryParam(scenarioScopeState.batchesEndpointQueryParam, "batchId", scenarioScopeState.batchId); + } + + @And("I add date from filter") + public void addDateFromFilter() { + String date = scenarioScopeState.dateTime; + updateQueryParam(scenarioScopeState.batchesEndpointQueryParam, "dateFrom", date); + } + + @And("I add date to filter") + public void addDateToFilter() { + String date = BaseStepDef.getCurrentDateInFormat(); + updateQueryParam(scenarioScopeState.batchesEndpointQueryParam, "dateTo", date); + } + + @And("I add limit filter {int}") + public void addLimitFilter(int limit) { + updateQueryParam(scenarioScopeState.batchesEndpointQueryParam, "limit", limit); + } + + @And("I add offset filter {int}") + public void addOffsetFilter(int offset) { + updateQueryParam(scenarioScopeState.batchesEndpointQueryParam, "offset", offset); + } + + @Then("I am able to assert {int} totalBatches") + public void assertTotalSubBatches(int count) { + assertThat(scenarioScopeState.batchesResponse.getTotalBatches()).isEqualTo(count); + } + + private void batchDbSetup() { + // instantiate the shared query param variable if null + if (scenarioScopeState.batchesEndpointQueryParam == null) { + scenarioScopeState.batchesEndpointQueryParam = new HashMap<>(); + } + } + + private void batchDbTearDown() { + // clearing the query parameter shared variable + if (scenarioScopeState.batchesEndpointQueryParam.size() > 0) { + scenarioScopeState.batchesEndpointQueryParam.clear(); + } + } + + private void updateQueryParam(Map queryParam, String key, Object object) { + queryParam.put(key, object); + } + + private void callBatchesEndpoint(int expectedStatusCode, Map queryParams, int totalBatches) + throws JsonProcessingException { + log.info("Tenant I am passing is: {}", scenarioScopeState.tenant); + RequestSpecification requestSpec = Utils.getDefaultSpec(scenarioScopeState.tenant); + if (authEnabled) { + requestSpec.header("Authorization", "Bearer " + scenarioScopeState.accessToken); + } + if (queryParams != null) { + queryParams.forEach(requestSpec::queryParam); + } + + scenarioScopeState.response = RestAssured.given(requestSpec).baseUri(operationsAppConfig.operationAppContactPoint).expect() + .spec(new ResponseSpecBuilder().expectStatusCode(expectedStatusCode).build()).when() + .get(operationsAppConfig.batchesEndpoint).andReturn().asString(); + + logger.info("Batches api Response: " + scenarioScopeState.response); + assertThat(scenarioScopeState.response).isNotEmpty(); + BatchPaginatedResponse batchResponse = objectMapper.readValue(scenarioScopeState.response, BatchPaginatedResponse.class); + if (totalBatches != -1) { + assertThat(batchResponse.getData().size()).isEqualTo(totalBatches); + } + } + + private void parseBatchesResponse(String response) { + try { + scenarioScopeState.batchesResponse = objectMapper.readValue(response, BatchPaginatedResponse.class); + } catch (Exception e) { + log.error(e.getLocalizedMessage()); + } + } + + private void assertBatchPaginatedResponse(BatchPaginatedResponse response) { + + } + +} diff --git a/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/cucumber/stepdef/PaybillApiStepDef.java b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/cucumber/stepdef/PaybillApiStepDef.java new file mode 100644 index 000000000..d3d234a30 --- /dev/null +++ b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/cucumber/stepdef/PaybillApiStepDef.java @@ -0,0 +1,86 @@ +package org.mifos.integrationtest.cucumber.stepdef; + +import static com.google.common.truth.Truth.assertThat; +import static org.mifos.integrationtest.common.Utils.CONTENT_TYPE; +import static org.mifos.integrationtest.common.Utils.CONTENT_TYPE_VALUE; + +import io.cucumber.core.internal.com.fasterxml.jackson.databind.ObjectMapper; +import io.cucumber.java.en.And; +import io.cucumber.java.en.Given; +import io.cucumber.java.en.Then; +import io.cucumber.java.en.When; +import io.restassured.RestAssured; +import io.restassured.builder.ResponseSpecBuilder; +import io.restassured.specification.RequestSpecification; +import org.mifos.integrationtest.common.Utils; +import org.mifos.integrationtest.common.dto.paybill.PayBillRequestDTO; +import org.mifos.integrationtest.config.PaybillConfig; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; + +public class PaybillApiStepDef { + + @Autowired + PaybillStepDef paybillStepDef; + @Autowired + PaybillConfig paybillConfig; + Logger logger = LoggerFactory.getLogger(this.getClass()); + @Autowired + ObjectMapper objectMapper; + + @Given("The mpesaValidateUrl is not null") + public void nonEmptympesaValidateUrl() { + assertThat(paybillConfig.mpesaValidateUrl).isNotNull(); + } + + @Given("The mpesaSettlementUrl is not null") + public void nonEmptympesaSettlementUrl() { + assertThat(paybillConfig.mpesaSettlementUrl).isNotNull(); + } + + @Given("I have businessShortCode {string} with transactionId {string}") + public void setShortCodeAndTxnId(String shortCode, String transactionId) { + paybillStepDef.businessShortCode = shortCode; + paybillStepDef.transactionId = transactionId; + assertThat(paybillStepDef.businessShortCode).isNotEmpty(); + assertThat(paybillStepDef.transactionId).isNotEmpty(); + } + + @And("I have MSISDN {string} and BillRefNo {string} for amount {string}") + public void setMsisdnBillRefAmount(String msisdn, String billRefNo, String amount) { + paybillStepDef.msisdn = msisdn; + paybillStepDef.billRefNo = billRefNo; + paybillStepDef.amount = amount; + assertThat(paybillStepDef.msisdn).isNotEmpty(); + assertThat(paybillStepDef.billRefNo).isNotEmpty(); + assertThat(paybillStepDef.amount).isNotEmpty(); + } + + @When("I call the mpesa-connector validate webhook api with expected status code of {int}") + public void callMpesaConnector(int expectedStatus) { + RequestSpecification requestSpecification = Utils.getDefaultSpec(); + // Paybill Request DTO for Validation + PayBillRequestDTO payBillRequestDTO = paybillStepDef.setPaybillRequestDTO(); + requestSpecification.body(payBillRequestDTO); + requestSpecification.header(CONTENT_TYPE, CONTENT_TYPE_VALUE); + paybillStepDef.response = RestAssured.given(requestSpecification).contentType(CONTENT_TYPE_VALUE).expect() + .spec(new ResponseSpecBuilder().expectStatusCode(expectedStatus).build()).when().post(paybillConfig.mpesaValidateUrl) + .andReturn().asString(); + logger.info("Mpesa Validation Response : {}", paybillStepDef.response); + } + + @Then("I call the confirmation webhook API with expected status of {int}") + public void callConfirmationWebhook(int expectedStatus) { + RequestSpecification requestSpecification = Utils.getDefaultSpec(); + // Paybill Request DTO for Settlement + PayBillRequestDTO payBillRequestDTO = paybillStepDef.setPaybillRequestDTO(); + requestSpecification.body(payBillRequestDTO); + requestSpecification.header(CONTENT_TYPE, CONTENT_TYPE_VALUE); + + paybillStepDef.response = RestAssured.given(requestSpecification).contentType(CONTENT_TYPE_VALUE).expect() + .spec(new ResponseSpecBuilder().expectStatusCode(expectedStatus).build()).when().post(paybillConfig.mpesaSettlementUrl) + .andReturn().asString(); + logger.info("Paybill Settlement Response: {}", paybillStepDef.response); + } +} diff --git a/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/cucumber/stepdef/PaybillStepDef.java b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/cucumber/stepdef/PaybillStepDef.java new file mode 100644 index 000000000..c5818b705 --- /dev/null +++ b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/cucumber/stepdef/PaybillStepDef.java @@ -0,0 +1,25 @@ +package org.mifos.integrationtest.cucumber.stepdef; + +import org.mifos.integrationtest.common.dto.paybill.PayBillRequestDTO; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; + +@Component +public class PaybillStepDef { + + public String businessShortCode; + public String billRefNo; + public String msisdn; + public String transactionId; + public String amount; + public String response; + + Logger logger = LoggerFactory.getLogger(this.getClass()); + + public PayBillRequestDTO setPaybillRequestDTO() { + PayBillRequestDTO payBillRequestDTO = new PayBillRequestDTO("Pay Bill", transactionId, "20191122063845", amount, businessShortCode, + billRefNo, "", "49197.00", "", msisdn, "John"); + return payBillRequestDTO; + } +} diff --git a/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/cucumber/stepdef/PayerFundTransferDef.java b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/cucumber/stepdef/PayerFundTransferDef.java new file mode 100644 index 000000000..4bdc7621b --- /dev/null +++ b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/cucumber/stepdef/PayerFundTransferDef.java @@ -0,0 +1,286 @@ +package org.mifos.integrationtest.cucumber.stepdef; + +import io.cucumber.core.internal.com.fasterxml.jackson.core.JsonProcessingException; +import io.cucumber.core.internal.com.fasterxml.jackson.databind.ObjectMapper; +import io.restassured.specification.RequestSpecification; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.UUID; +import org.apache.fineract.client.models.InteropIdentifierRequestData; +import org.apache.fineract.client.models.PostClientsRequest; +import org.apache.fineract.client.models.PostClientsResponse; +import org.apache.fineract.client.models.PostRecurringDepositAccountsRecurringDepositAccountIdTransactionsRequest; +import org.apache.fineract.client.models.PostSavingsAccountsAccountIdRequest; +import org.apache.fineract.client.models.PostSavingsAccountsRequest; +import org.apache.fineract.client.models.PostSavingsAccountsResponse; +import org.apache.fineract.client.models.PostSavingsProductsRequest; +import org.apache.fineract.client.models.PostSavingsProductsResponse; +import org.mifos.connector.common.mojaloop.dto.MoneyData; +import org.mifos.connector.common.mojaloop.dto.Party; +import org.mifos.connector.common.mojaloop.dto.PartyIdInfo; +import org.mifos.connector.common.mojaloop.dto.QuoteSwitchRequestDTO; +import org.mifos.connector.common.mojaloop.dto.TransactionType; +import org.mifos.connector.common.mojaloop.dto.TransferSwitchRequestDTO; +import org.mifos.connector.common.mojaloop.type.AmountType; +import org.mifos.connector.common.mojaloop.type.IdentifierType; +import org.mifos.connector.common.mojaloop.type.InitiatorType; +import org.mifos.connector.common.mojaloop.type.Scenario; +import org.mifos.connector.common.mojaloop.type.TransactionRole; +import org.mifos.integrationtest.config.MojaloopConfig; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +@Component +public class PayerFundTransferDef { + + public String amsName; + public int amount; + public String accountId; + public String acccountHoldingInstitutionId; + + public String tenant; + public String payerTenant; + public String payeeTenant; + public String currentDate; + protected String savingsProductBody; + protected String responseSavingsProduct; + protected String savingsApproveBody; + protected String responseSavingsApprove; + protected String savingsAccountBody; + protected String interopIdentifierBody; + protected String responseSavingsAccountPayer; + protected String responseSavingsAccountPayee; + protected String responseInteropIdentifier; + protected String savingsActivateBody; + protected String responseSavingsActivate; + protected String savingsDepositAccountBody; + protected String responseSavingsDepositAccount; + protected String createClientBody; + protected String responsePayerClient; + protected String responsePayeeClient; + protected String externalId; + @Autowired + ObjectMapper objectMapper; + + @Autowired + MojaloopConfig mojaloopConfig; + + @Value("${defaults.authorization}") + public String authorizationToken; + + Logger logger = LoggerFactory.getLogger(this.getClass()); + + public void setAccountId(String acId) { + accountId = acId; + } + + public void setHeadersMifos(String ams, String aHIId, int amnt) { + amsName = ams; + acccountHoldingInstitutionId = aHIId; + amount = amnt; + } + + protected void setTenant(String tenantName) { + tenant = tenantName; + } + + public void setPayerTenant(String payerTenant) { + this.payerTenant = payerTenant; + } + + public void setPayeeTenant(String payeeTenant) { + this.payeeTenant = payeeTenant; + } + + protected void setcurrentDate(String date) { + currentDate = date; + } + + protected RequestSpecification setHeaders(RequestSpecification requestSpec) { + requestSpec.header("Fineract-Platform-TenantId", tenant); + requestSpec.header("Authorization", authorizationToken); + requestSpec.header("Content-Type", "application/json;charset=UTF-8"); + return requestSpec; + } + + private String getCurrentDate() { + Date date = new Date(); + return new SimpleDateFormat("dd MMMM yyyy").format(date); + } + + String getAlphaNumericString(int size) { + String AlphaNumericString = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "0123456789" + "abcdefghijklmnopqrstuvxyz"; + StringBuilder sb = new StringBuilder(size); + for (int i = 0; i < size; i++) { + int index = (int) (AlphaNumericString.length() * Math.random()); + sb.append(AlphaNumericString.charAt(index)); + } + return sb.toString(); + } + + protected String setBodySavingsProduct() throws JsonProcessingException { + // Generating product name and shortname + String name = new StringBuilder().append(getAlphaNumericString(4)).toString(); + String shortName = getAlphaNumericString(4); + + PostSavingsProductsRequest savingsProductsRequest = new PostSavingsProductsRequest(); + savingsProductsRequest.setCurrencyCode("USD"); + savingsProductsRequest.setDigitsAfterDecimal(2); + savingsProductsRequest.setInterestCompoundingPeriodType(1); + savingsProductsRequest.setInterestPostingPeriodType(4); + savingsProductsRequest.setInterestCalculationType(1); + savingsProductsRequest.setInterestCalculationDaysInYearType(365); + savingsProductsRequest.setAccountingRule(1); + savingsProductsRequest.setName(name); + savingsProductsRequest.setShortName(shortName); + savingsProductsRequest.setInMultiplesOf(1); + savingsProductsRequest.setNominalAnnualInterestRate(5.0); + savingsProductsRequest.setLocale("en"); + + return objectMapper.writeValueAsString(savingsProductsRequest); + } + + protected String setBodySavingsApprove() throws JsonProcessingException { + PostSavingsAccountsAccountIdRequest savingsApprove = new PostSavingsAccountsAccountIdRequest(); + savingsApprove.setApprovedOnDate(currentDate); + savingsApprove.setLocale("en"); + savingsApprove.setDateFormat("dd MMMM yyyy"); + return objectMapper.writeValueAsString(savingsApprove); + } + + protected String setBodySavingsAccount(String client) throws JsonProcessingException { + // Getting resourceId and clientId + PostClientsResponse createPayerClientResponse; + + if (("payer").equals(client)) { + createPayerClientResponse = objectMapper.readValue(responsePayerClient, PostClientsResponse.class); + } else { + createPayerClientResponse = objectMapper.readValue(responsePayeeClient, PostClientsResponse.class); + } + + PostSavingsProductsResponse savingsProductResponse = objectMapper.readValue(responseSavingsProduct, + PostSavingsProductsResponse.class); + String date = getCurrentDate(); + setcurrentDate(date); + externalId = UUID.randomUUID().toString(); + PostSavingsAccountsRequest savingsAccountsRequest = new PostSavingsAccountsRequest(); + savingsAccountsRequest.setClientId(createPayerClientResponse.getClientId()); + savingsAccountsRequest.setProductId(savingsProductResponse.getResourceId()); + savingsAccountsRequest.setDateFormat("dd MMMM yyyy"); + savingsAccountsRequest.setLocale("en"); + savingsAccountsRequest.setSubmittedOnDate(currentDate); + savingsAccountsRequest.setExternalId(externalId); + + return objectMapper.writeValueAsString(savingsAccountsRequest); + } + + protected String setBodyInteropIdentifier() throws JsonProcessingException { + PostSavingsAccountsResponse savingsAccountResponse = objectMapper.readValue(responseSavingsProduct, + PostSavingsAccountsResponse.class); + String date = getCurrentDate(); + setcurrentDate(date); + + InteropIdentifierRequestData interopIdentifier = new InteropIdentifierRequestData(); + interopIdentifier.setAccountId(externalId); + + return objectMapper.writeValueAsString(interopIdentifier); + } + + protected String setBodySavingsActivate() throws JsonProcessingException { + PostSavingsAccountsAccountIdRequest savingsActivate = new PostSavingsAccountsAccountIdRequest(); + savingsActivate.setActivatedOnDate(currentDate); + savingsActivate.setLocale("en"); + savingsActivate.setDateFormat("dd MMMM yyyy"); + return objectMapper.writeValueAsString(savingsActivate); + } + + protected String setSavingsDepositAccount(int amount) throws JsonProcessingException { + PostRecurringDepositAccountsRecurringDepositAccountIdTransactionsRequest savingsAccountDeposit = new PostRecurringDepositAccountsRecurringDepositAccountIdTransactionsRequest(); + savingsAccountDeposit.setLocale("en"); + savingsAccountDeposit.setDateFormat("dd MMMM yyyy"); + savingsAccountDeposit.setPaymentTypeId(1); + savingsAccountDeposit.setTransactionAmount((double) amount); + savingsAccountDeposit.setTransactionDate(currentDate); + + return objectMapper.writeValueAsString(savingsAccountDeposit); + } + + protected String setBodyPayerClient() throws JsonProcessingException { + String date = getCurrentDate(); + PostClientsRequest postClientsRequest = new PostClientsRequest(); + postClientsRequest.setOfficeId(1); + postClientsRequest.setLegalFormId(1); + postClientsRequest.setFirstname("John"); + postClientsRequest.setLastname("Wick"); + postClientsRequest.setActive(true); + postClientsRequest.setLocale("en"); + postClientsRequest.setDateFormat("dd MMMM yyyy"); + postClientsRequest.setActivationDate(date); + postClientsRequest.setSubmittedOnDate(date); + return objectMapper.writeValueAsString(postClientsRequest); + } + + protected String setBodyPayeeClient() throws JsonProcessingException { + String date = getCurrentDate(); + PostClientsRequest postClientsRequest = new PostClientsRequest(); + postClientsRequest.setOfficeId(1); + postClientsRequest.setLegalFormId(1); + postClientsRequest.setFirstname("John"); + postClientsRequest.setLastname("Wick"); + postClientsRequest.setActive(true); + postClientsRequest.setLocale("en"); + postClientsRequest.setDateFormat("dd MMMM yyyy"); + postClientsRequest.setActivationDate(date); + postClientsRequest.setSubmittedOnDate(date); + return objectMapper.writeValueAsString(postClientsRequest); + } + + protected String setBodyClient(String client) throws JsonProcessingException { + if (client.equals("payer")) { + return setBodyPayerClient(); + } else if (client.equals("payee")) { + return setBodyPayeeClient(); + } + return client; + } + + protected String setBodyPayeeQuoteRequest(String payerIdentifier, String payeeIdentifier, String amount, String quoteId) + throws JsonProcessingException { + QuoteSwitchRequestDTO requestDTO = new QuoteSwitchRequestDTO(); + + requestDTO.setPayer(getParty(payerIdentifier, mojaloopConfig.payerFspId)); + requestDTO.setPayee(getParty(payeeIdentifier, mojaloopConfig.payeeFspId)); + requestDTO.setAmountType(AmountType.RECEIVE); + requestDTO.setAmount(new MoneyData(amount, "USD")); + requestDTO.setTransactionId(UUID.randomUUID().toString()); + requestDTO.setQuoteId(quoteId); + TransactionType transactionType = new TransactionType(); + transactionType.setInitiatorType(InitiatorType.CONSUMER); + transactionType.setInitiator(TransactionRole.PAYER); + transactionType.setScenario(Scenario.TRANSFER); + requestDTO.setTransactionType(transactionType); + return objectMapper.writeValueAsString(requestDTO); + } + + private Party getParty(String identifier, String fspId) { + PartyIdInfo partyIdInfo = new PartyIdInfo(IdentifierType.MSISDN, identifier); + partyIdInfo.setFspId(fspId); + Party party = new Party(partyIdInfo); + return party; + } + + protected String setBodyPayeeTransferRequest(String amount, String ilpPacket, String condition) throws JsonProcessingException { + TransferSwitchRequestDTO requestDTO = new TransferSwitchRequestDTO(); + requestDTO.setTransferId(UUID.randomUUID().toString()); + requestDTO.setPayeeFsp(mojaloopConfig.payerFspId); + requestDTO.setPayeeFsp(mojaloopConfig.payeeFspId); + requestDTO.setAmount(new MoneyData(amount, "USD")); + requestDTO.setIlpPacket(ilpPacket); + requestDTO.setCondition(condition); + return objectMapper.writeValueAsString(requestDTO); + } + +} diff --git a/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/cucumber/stepdef/PayerFundTransferStepDef.java b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/cucumber/stepdef/PayerFundTransferStepDef.java new file mode 100644 index 000000000..373b8f6d2 --- /dev/null +++ b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/cucumber/stepdef/PayerFundTransferStepDef.java @@ -0,0 +1,772 @@ +package org.mifos.integrationtest.cucumber.stepdef; + +import static com.github.tomakehurst.wiremock.client.WireMock.getAllServeEvents; +import static com.google.common.truth.Truth.assertThat; +import static java.util.concurrent.TimeUnit.SECONDS; +import static org.awaitility.Awaitility.await; + +import com.github.tomakehurst.wiremock.stubbing.ServeEvent; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import io.cucumber.core.internal.com.fasterxml.jackson.core.JsonProcessingException; +import io.cucumber.java.en.And; +import io.cucumber.java.en.Given; +import io.cucumber.java.en.Then; +import io.cucumber.java.en.When; +import io.restassured.RestAssured; +import io.restassured.builder.ResponseSpecBuilder; +import io.restassured.specification.RequestSpecification; +import java.io.IOException; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.time.format.DateTimeFormatter; +import java.util.Date; +import java.util.List; +import java.util.UUID; +import org.apache.fineract.client.models.PostSavingsAccountsResponse; +import org.json.JSONException; +import org.mifos.connector.common.mojaloop.type.TransferState; +import org.mifos.integrationtest.common.CsvHelper; +import org.mifos.integrationtest.common.HttpMethod; +import org.mifos.integrationtest.common.TransferHelper; +import org.mifos.integrationtest.common.Utils; +import org.mifos.integrationtest.config.MojaloopConfig; +import org.mifos.integrationtest.config.PayerFundTransferConfig; +import org.mifos.integrationtest.util.Util; +import org.springframework.beans.factory.annotation.Autowired; + +public class PayerFundTransferStepDef extends BaseStepDef { + + @Autowired + PayerFundTransferDef fundTransferDef; + + private static String payer_identifier; + + private static String savings_account_id; + + private static String payee_identifier; + + private static String quoteId; + + private static String quotationCallback; + + @Autowired + PayerFundTransferConfig transferConfig; + + @Autowired + MojaloopConfig mojaloopConfig; + + @Autowired + MockServerStepDef mockServerStepDef; + + @Autowired + CsvHelper csvHelper; + + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("EEE, dd MMM yyyy HH:mm:ss 'GMT'"); + + @Given("I have Fineract-Platform-TenantId for {string}") + public void setTenantForPayer(String client) { + String tenant; + logger.info(client); + switch (client) { + case "payer" -> { + tenant = transferConfig.payerTenant; + fundTransferDef.setPayerTenant(tenant); + } + case "payee2" -> { + tenant = transferConfig.payeeTenant2; + fundTransferDef.setPayeeTenant(tenant); + } + case "payee3" -> { + tenant = transferConfig.payeeTenant3; + fundTransferDef.setPayeeTenant(tenant); + } + default -> { + tenant = transferConfig.payeeTenant; + fundTransferDef.setPayeeTenant(tenant); + } + } + scenarioScopeState.tenant = tenant; + assertThat(tenant).isNotEmpty(); + fundTransferDef.setTenant(tenant); + logger.info(tenant); + } + + @When("I call the create client endpoint for {string}") + public void callCreateClientEndpoint(String client) throws JsonProcessingException { + RequestSpecification requestSpec = Utils.getDefaultSpec(); + requestSpec = fundTransferDef.setHeaders(requestSpec); + + logger.info(client); + + fundTransferDef.createClientBody = fundTransferDef.setBodyClient(client); + // Calling savings product endpoint + String clientResponse = RestAssured.given(requestSpec).baseUri(transferConfig.clientBaseUrl).body(fundTransferDef.createClientBody) + .expect().spec(new ResponseSpecBuilder().expectStatusCode(200).build()).when().post(transferConfig.clientEndpoint) + .andReturn().asString(); + + if ("payer".equals(client)) { + fundTransferDef.responsePayerClient = clientResponse; + assertThat(fundTransferDef.responsePayerClient).isNotEmpty(); + } else { + fundTransferDef.responsePayeeClient = clientResponse; + assertThat(fundTransferDef.responsePayeeClient).isNotEmpty(); + } + logger.info("Create {} Client Response: {}", client, clientResponse); + } + + @Then("I call the create savings product endpoint for {string}") + public void callCreateSavingsProductEndpoint(String client) throws JsonProcessingException { + // Setting headers and body + RequestSpecification requestSpec = Utils.getDefaultSpec(); + requestSpec = fundTransferDef.setHeaders(requestSpec); + fundTransferDef.savingsProductBody = fundTransferDef.setBodySavingsProduct(); + // Calling savings product endpoint + fundTransferDef.responseSavingsProduct = RestAssured.given(requestSpec).baseUri(transferConfig.savingsBaseUrl) + .body(fundTransferDef.savingsProductBody).expect().spec(new ResponseSpecBuilder().expectStatusCode(200).build()).when() + .post(transferConfig.savingsProductEndpoint).andReturn().asString(); + + logger.info("Savings Product Response: " + fundTransferDef.responseSavingsProduct); + assertThat(fundTransferDef.responseSavingsProduct).isNotEmpty(); + } + + @When("I call the create savings account endpoint for {string}") + public void callCreateSavingsAccountEndpoint(String client) throws JsonProcessingException { + // Setting headers and body + RequestSpecification requestSpec = Utils.getDefaultSpec(); + requestSpec = fundTransferDef.setHeaders(requestSpec); + fundTransferDef.savingsAccountBody = fundTransferDef.setBodySavingsAccount(client); + // Calling savings product endpoint + String responseSavingsAccount = RestAssured.given(requestSpec).baseUri(transferConfig.savingsBaseUrl) + .body(fundTransferDef.savingsAccountBody).expect().spec(new ResponseSpecBuilder().expectStatusCode(200).build()).when() + .post(transferConfig.savingsAccountEndpoint).andReturn().asString(); + + logger.info("Savings Account Response: " + responseSavingsAccount); + + if (client.equals("payer")) { + fundTransferDef.responseSavingsAccountPayer = responseSavingsAccount; + assertThat(fundTransferDef.responseSavingsAccountPayer).isNotEmpty(); + } else { + fundTransferDef.responseSavingsAccountPayee = responseSavingsAccount; + assertThat(fundTransferDef.responseSavingsAccountPayee).isNotEmpty(); + } + } + + @Then("I call the interop identifier endpoint for {string}") + public void callCreateInteropIdentifierEndpoint(String client) throws JsonProcessingException { + // Setting headers and body + RequestSpecification requestSpec = Utils.getDefaultSpec(); + requestSpec = fundTransferDef.setHeaders(requestSpec); + fundTransferDef.interopIdentifierBody = fundTransferDef.setBodyInteropIdentifier(); + // Setting account ID in path + + String responseSavingsAccount = ("payer").equals(client) ? fundTransferDef.responseSavingsAccountPayer + : fundTransferDef.responseSavingsAccountPayee; + + PostSavingsAccountsResponse savingsAccountResponse = objectMapper.readValue(responseSavingsAccount, + PostSavingsAccountsResponse.class); + String identifier = savingsAccountResponse.getSavingsId().toString(); + + if (client.equals("payer")) { + payer_identifier = identifier; + scenarioScopeState.payerIdentifier = identifier; + } else { + payee_identifier = identifier; + scenarioScopeState.payeeIdentifier = identifier; + } + + String endpoint = transferConfig.interopIdentifierEndpoint; + endpoint = endpoint.replaceAll("\\{\\{identifierType\\}\\}", "MSISDN"); + endpoint = endpoint.replaceAll("\\{\\{identifier\\}\\}", identifier); + + // Calling Interop Identifier endpoint + fundTransferDef.responseInteropIdentifier = RestAssured.given(requestSpec).baseUri(transferConfig.savingsBaseUrl) + .body(fundTransferDef.interopIdentifierBody).expect().spec(new ResponseSpecBuilder().expectStatusCode(200).build()).when() + .post(endpoint).andReturn().asString(); + + logger.info("Interop Identifier Response: {}", fundTransferDef.responseInteropIdentifier); + assertThat(fundTransferDef.responseInteropIdentifier).isNotEmpty(); + } + + @Then("I call the interop identifier endpoint for {string} and accountId {string}") + public void callCreateInteropBudgetIdentifierEndpoint(String client, String accountId) throws JsonProcessingException { + // Setting headers and body + RequestSpecification requestSpec = Utils.getDefaultSpec(); + requestSpec = fundTransferDef.setHeaders(requestSpec); + fundTransferDef.interopIdentifierBody = fundTransferDef.setBodyInteropIdentifier(); + // Setting account ID in path + + String responseSavingsAccount = ("payer").equals(client) ? fundTransferDef.responseSavingsAccountPayer + : fundTransferDef.responseSavingsAccountPayee; + + PostSavingsAccountsResponse savingsAccountResponse = objectMapper.readValue(responseSavingsAccount, + PostSavingsAccountsResponse.class); + savings_account_id = savingsAccountResponse.getSavingsId().toString(); + + if (client.equals("payer")) { + payer_identifier = accountId; + scenarioScopeState.payerIdentifier = accountId; + } else { + payee_identifier = accountId; + scenarioScopeState.payeeIdentifier = accountId; + } + + String endpoint = transferConfig.interopIdentifierEndpoint; + String identifierType = "MSISDN"; + endpoint = Util.getFormattedEndpoint(endpoint, "{{identifierType}}", identifierType); + endpoint = Util.getFormattedEndpoint(endpoint, "{{identifier}}", accountId); + + // Calling Interop Identifier endpoint + fundTransferDef.responseInteropIdentifier = RestAssured.given(requestSpec).baseUri(transferConfig.savingsBaseUrl) + .body(fundTransferDef.interopIdentifierBody).expect().spec(new ResponseSpecBuilder().expectStatusCode(200).build()).when() + .post(endpoint).andReturn().asString(); + + logger.info("Interop Identifier Response: {}", fundTransferDef.responseInteropIdentifier); + assertThat(fundTransferDef.responseInteropIdentifier).isNotEmpty(); + } + + @Then("I approve the deposit with command {string} for {string}") + public void callApproveSavingsEndpoint(String command, String client) throws JsonProcessingException { + // Setting headers and body + RequestSpecification requestSpec = Utils.getDefaultSpec(); + requestSpec = fundTransferDef.setHeaders(requestSpec); + requestSpec.queryParam("command", command); + fundTransferDef.savingsApproveBody = fundTransferDef.setBodySavingsApprove(); + String endpoint = transferConfig.savingsApproveEndpoint; + + if (client.equals("payer")) { + endpoint = endpoint.replaceAll("\\{\\{savingsAccId\\}\\}", payer_identifier); + } else { + endpoint = endpoint.replaceAll("\\{\\{savingsAccId\\}\\}", payee_identifier); + } + + // Calling create loan account endpoint + fundTransferDef.responseSavingsApprove = RestAssured.given(requestSpec).baseUri(transferConfig.savingsBaseUrl) + .body(fundTransferDef.savingsApproveBody).expect().spec(new ResponseSpecBuilder().expectStatusCode(200).build()).when() + .post(endpoint).andReturn().asString(); + + logger.info("Savings Approve Response: {}", fundTransferDef.responseSavingsApprove); + assertThat(fundTransferDef.responseSavingsApprove).isNotEmpty(); + } + + @Then("I approve the deposit for Budget Account with command {string} for {string}") + public void callApproveBudgetAccountEndpoint(String command, String client) throws JsonProcessingException { + // Setting headers and body + RequestSpecification requestSpec = Utils.getDefaultSpec(); + requestSpec = fundTransferDef.setHeaders(requestSpec); + requestSpec.queryParam("command", command); + fundTransferDef.savingsApproveBody = fundTransferDef.setBodySavingsApprove(); + String endpoint = transferConfig.savingsApproveEndpoint; + + if (client.equals("payer")) { + endpoint = Util.getFormattedEndpoint(endpoint, "{{savingsAccId}}", savings_account_id); + } else { + endpoint = Util.getFormattedEndpoint(endpoint, "{{savingsAccId}}", savings_account_id); + } + + // Calling create loan account endpoint + fundTransferDef.responseSavingsApprove = RestAssured.given(requestSpec).baseUri(transferConfig.savingsBaseUrl) + .body(fundTransferDef.savingsApproveBody).expect().spec(new ResponseSpecBuilder().expectStatusCode(200).build()).when() + .post(endpoint).andReturn().asString(); + + logger.info("Savings Approve Response: {}", fundTransferDef.responseSavingsApprove); + assertThat(fundTransferDef.responseSavingsApprove).isNotEmpty(); + } + + @When("I activate the account with command {string} for {string}") + public void callSavingsActivateEndpoint(String command, String client) throws JsonProcessingException { + // Setting headers and body + RequestSpecification requestSpec = Utils.getDefaultSpec(); + requestSpec = fundTransferDef.setHeaders(requestSpec); + requestSpec.queryParam("command", command); + fundTransferDef.savingsActivateBody = fundTransferDef.setBodySavingsActivate(); + + String endpoint = transferConfig.savingsActivateEndpoint; + if (client.equals("payer")) { + endpoint = endpoint.replaceAll("\\{\\{savingsAccId\\}\\}", payer_identifier); + } else { + endpoint = endpoint.replaceAll("\\{\\{savingsAccId\\}\\}", payee_identifier); + } + // Calling create loan account endpoint + fundTransferDef.responseSavingsActivate = RestAssured.given(requestSpec).baseUri(transferConfig.savingsBaseUrl) + .body(fundTransferDef.savingsActivateBody).expect().spec(new ResponseSpecBuilder().expectStatusCode(200).build()).when() + .post(endpoint).andReturn().asString(); + + logger.info("Savings Activate Response: {}", fundTransferDef.responseSavingsActivate); + assertThat(fundTransferDef.responseSavingsActivate).isNotEmpty(); + } + + @When("I activate the budget account with command {string} for {string}") + public void callBudgetAccountActivateEndpoint(String command, String client) throws JsonProcessingException { + // Setting headers and body + RequestSpecification requestSpec = Utils.getDefaultSpec(); + requestSpec = fundTransferDef.setHeaders(requestSpec); + requestSpec.queryParam("command", command); + fundTransferDef.savingsActivateBody = fundTransferDef.setBodySavingsActivate(); + + String endpoint = transferConfig.savingsActivateEndpoint; + if (client.equals("payer")) { + endpoint = Util.getFormattedEndpoint(endpoint, "{{savingsAccId}}", savings_account_id); + } else { + endpoint = Util.getFormattedEndpoint(endpoint, "{{savingsAccId}}", savings_account_id); + } + // Calling create loan account endpoint + fundTransferDef.responseSavingsActivate = RestAssured.given(requestSpec).baseUri(transferConfig.savingsBaseUrl) + .body(fundTransferDef.savingsActivateBody).expect().spec(new ResponseSpecBuilder().expectStatusCode(200).build()).when() + .post(endpoint).andReturn().asString(); + + logger.info("Savings Activate Response: {}", fundTransferDef.responseSavingsActivate); + assertThat(fundTransferDef.responseSavingsActivate).isNotEmpty(); + } + + @Then("I call the deposit account endpoint with command {string} for amount {int} for {string}") + public void callDepositAccountEndpoint(String command, int amount, String client) throws JsonProcessingException { + // Setting headers and body + RequestSpecification requestSpec = Utils.getDefaultSpec(); + requestSpec = fundTransferDef.setHeaders(requestSpec); + requestSpec.queryParam("command", command); + fundTransferDef.savingsDepositAccountBody = fundTransferDef.setSavingsDepositAccount(amount); + // Setting account ID + PostSavingsAccountsResponse savingsAccountResponse; + if (client.equals("payer")) { + savingsAccountResponse = objectMapper.readValue(fundTransferDef.responseSavingsAccountPayer, PostSavingsAccountsResponse.class); + } else { + savingsAccountResponse = objectMapper.readValue(fundTransferDef.responseSavingsAccountPayee, PostSavingsAccountsResponse.class); + } + + String endpoint = transferConfig.savingsDepositAccountEndpoint.replaceAll("\\{\\{savingsAccId\\}\\}", + savingsAccountResponse.getSavingsId().toString()); + + // Calling create loan account endpoint + fundTransferDef.responseSavingsDepositAccount = RestAssured.given(requestSpec).baseUri(transferConfig.savingsBaseUrl) + .body(fundTransferDef.savingsDepositAccountBody).expect().spec(new ResponseSpecBuilder().expectStatusCode(200).build()) + .when().post(endpoint).andReturn().asString(); + + logger.info("Savings Deposit Response: " + fundTransferDef.responseSavingsDepositAccount); + assertThat(fundTransferDef.responseSavingsDepositAccount).isNotEmpty(); + } + + @Then("I can register the stub for callback endpoint of party lookup") + public void registerStubForPartyLookup() { + String endpoint = "parties/MSISDN/" + scenarioScopeState.payeeIdentifier; + mockServerStepDef.startStub(endpoint, HttpMethod.PUT, 200); + } + + @Then("I can register the stub for callback endpoint of quotation") + public void registerStubForQuotation() { + quoteId = UUID.randomUUID().toString(); + String endpoint = "quotes/" + quoteId; + mockServerStepDef.startStub(endpoint, HttpMethod.POST, 200); + } + + @Then("I can register the stub for callback endpoint of transfer") + public void registerStubForTransfer() { + quoteId = UUID.randomUUID().toString(); + String endpoint = "transfers/\\{id\\}"; + mockServerStepDef.startStub(endpoint, HttpMethod.PUT, 200); + } + + @Then("I call the get parties api in ml connector for {string}") + public void callGetPartiesApi(String client) { + RequestSpecification requestSpec = Utils.getDefaultSpec(); + requestSpec.header("Accept", "application/vnd.interoperability.participants+json;version=1.0"); + requestSpec.header("Content-Type", "application/vnd.interoperability.parties+json;version=1.0"); + requestSpec.header("Date", new Date()); + requestSpec.header("Fspiop-Destination", mojaloopConfig.payeeFspId); + requestSpec.header("Fspiop-Source", mojaloopConfig.payerFspId); + requestSpec.header("partyId", scenarioScopeState.payeeIdentifier); + requestSpec.header("partyIdType", "MSISDN"); + requestSpec.header("Traceparent", UUID.randomUUID()); + requestSpec.header("X-Lookup-Callback-Url", transferConfig.callbackURL); + + String identifier; + if (client.equals("payer")) { + identifier = scenarioScopeState.payerIdentifier; + } else { + identifier = scenarioScopeState.payeeIdentifier; + } + + String endpoint = mojaloopConfig.mlConnectorGetPartyEndpoint; + endpoint = endpoint.replaceAll("\\{\\{identifierType\\}\\}", "MSISDN"); + endpoint = endpoint.replaceAll("\\{\\{identifier\\}\\}", identifier); + + scenarioScopeState.response = RestAssured.given(requestSpec).baseUri("https://" + mojaloopConfig.mlConnectorHost).expect() + .spec(new ResponseSpecBuilder().expectStatusCode(202).build()).when().get(endpoint).andReturn().asString(); + + assertThat(scenarioScopeState.response).isNotNull(); + } + + @Then("I call the get quotation api in ml connector for {string}") + public void callGetQuoteApi(String client) throws JsonProcessingException { + RequestSpecification requestSpec = Utils.getDefaultSpec(); + requestSpec.header("Date", new Date()); + requestSpec.header("Traceparent", UUID.randomUUID()); + requestSpec.header("X-Quote-Callback-Url", transferConfig.callbackURL); + + String quoteRequestBody; + if (client.equals("payer")) { + quoteRequestBody = fundTransferDef.setBodyPayeeQuoteRequest(scenarioScopeState.payerIdentifier, "1234", "1", quoteId); + } else { + quoteRequestBody = fundTransferDef.setBodyPayeeQuoteRequest("1234", scenarioScopeState.payeeIdentifier, "1", quoteId); + } + + scenarioScopeState.response = RestAssured.given(requestSpec).baseUri("https://" + mojaloopConfig.mlConnectorHost) + .body(quoteRequestBody).expect().spec(new ResponseSpecBuilder().expectStatusCode(202).build()).when() + .post(mojaloopConfig.mlConnectorGetQuoteEndpoint).andReturn().asString(); + + } + + @Then("I call the transfer api in ml connector for {string}") + public void callTransferApi(String client) throws JsonProcessingException { + RequestSpecification requestSpec = Utils.getDefaultSpec(); + requestSpec.header("Date", LocalDateTime.now(ZoneId.of("GMT")).minusMinutes(2).format(formatter)); + requestSpec.header("Traceparent", UUID.randomUUID()); + requestSpec.header("X-Transfer-Callback-Url", transferConfig.callbackURL); + + JsonObject jsonObject = JsonParser.parseString(quotationCallback).getAsJsonObject(); + String ilpPacket = jsonObject.get("ilpPacket").getAsString(); + String condition = jsonObject.get("condition").getAsString(); + String transferRequestBody = fundTransferDef.setBodyPayeeTransferRequest("1", ilpPacket, condition); + + scenarioScopeState.response = RestAssured.given(requestSpec).baseUri("https://" + mojaloopConfig.mlConnectorHost) + .body(transferRequestBody).expect().spec(new ResponseSpecBuilder().expectStatusCode(202).build()).when() + .post(mojaloopConfig.mlConnectorTransferEndpoint).andReturn().asString(); + + } + + @Then("I should be able to verify the callback for lookup") + public void verifyGetPartyCallback() { + await().atMost(awaitMost, SECONDS).pollDelay(pollDelay, SECONDS).pollInterval(pollInterval, SECONDS).untilAsserted(() -> { + List serveEvents = getAllServeEvents(); + logger.info(String.valueOf(serveEvents.size())); + assertThat(serveEvents.size()).isGreaterThan(0); + serveEvents.subList(0, 1).forEach(serveEvent -> { + if (!serveEvent.getRequest().getBodyAsString().isEmpty()) { + logger.info(serveEvent.getRequest().getBodyAsString()); + } + JsonObject jsonObject = JsonParser.parseString(serveEvent.getRequest().getBodyAsString()).getAsJsonObject(); + String firstName = jsonObject.getAsJsonObject("party").getAsJsonObject("personalInfo").getAsJsonObject("complexName") + .get("firstName").getAsString(); + assertThat(firstName).isNotNull(); + }); + }); + } + + @Then("I should be able to verify the callback for quotation") + public void verifyGetQuotationCallback() { + await().atMost(awaitMost, SECONDS).pollDelay(pollDelay, SECONDS).pollInterval(pollInterval, SECONDS).untilAsserted(() -> { + List serveEvents = getAllServeEvents(); + logger.info(String.valueOf(serveEvents.size())); + assertThat(serveEvents.size()).isGreaterThan(0); + serveEvents.subList(0, 1).forEach(serveEvent -> { + if (!serveEvent.getRequest().getBodyAsString().isEmpty()) { + logger.info(serveEvent.getRequest().getBodyAsString()); + } + quotationCallback = serveEvent.getRequest().getBodyAsString(); + JsonObject jsonObject = JsonParser.parseString(serveEvent.getRequest().getBodyAsString()).getAsJsonObject(); + String amount = jsonObject.getAsJsonObject("payeeReceiveAmount").get("amount").getAsString(); + assertThat(amount).isEqualTo("1"); + }); + }); + } + + @Then("I should be able to verify the callback for transfer") + public void verifyGetTransferCallback() { + await().atMost(awaitMost, SECONDS).pollDelay(pollDelay, SECONDS).pollInterval(pollInterval, SECONDS).untilAsserted(() -> { + List serveEvents = getAllServeEvents(); + logger.info(String.valueOf(serveEvents.size())); + assertThat(serveEvents.size()).isGreaterThan(0); + serveEvents.subList(0, 1).forEach(serveEvent -> { + if (!serveEvent.getRequest().getBodyAsString().isEmpty()) { + logger.info(serveEvent.getRequest().getBodyAsString()); + } + JsonObject jsonObject = JsonParser.parseString(serveEvent.getRequest().getBodyAsString()).getAsJsonObject(); + String transferState = jsonObject.get("transferState").getAsString(); + assertThat(transferState).isEqualTo(TransferState.COMMITTED.toString()); + }); + }); + } + + @Then("I call the payer fund transfer api to transfer amount {string} from payer to payee") + public void payerFundTransfer(String amount) throws JSONException { + + RequestSpecification requestSpec = Utils.getDefaultSpec(transferConfig.payerTenant); + requestSpec.header(Utils.X_CORRELATIONID, UUID.randomUUID()); + requestSpec.header("X-PayeeDFSP-ID", fundTransferDef.payeeTenant); + // requestSpec.header("Platform-TenantId", transferConfig.payerTenant); + + String requestBody = TransferHelper + .getTransferRequestBody(scenarioScopeState.payerIdentifier, scenarioScopeState.payeeIdentifier, amount).toString(); + scenarioScopeState.response = RestAssured.given(requestSpec).baseUri(channelConnectorConfig.channelConnectorContactPoint) + .body(requestBody).expect().spec(new ResponseSpecBuilder().expectStatusCode(200).build()).when() + .post(channelConnectorConfig.transferEndpoint).andReturn().asString(); + + } + + @When("I call the transfer API in ops app with transactionId as parameter") + public void iCallTheTransferAPIWithTransactionId() throws InterruptedException { + await().atMost(awaitMost, SECONDS).pollDelay(pollDelay, SECONDS).pollInterval(pollInterval, SECONDS).untilAsserted(() -> { + RequestSpecification requestSpec = Utils.getDefaultSpec(transferConfig.payerTenant); + if (authEnabled) { + requestSpec.header("Authorization", "Bearer " + scenarioScopeState.accessToken); + } + requestSpec.queryParam("transactionId", scenarioScopeState.transactionId); + + scenarioScopeState.response = RestAssured.given(requestSpec).baseUri(operationsAppConfig.operationAppContactPoint).expect() + .spec(new ResponseSpecBuilder().expectStatusCode(200).build()).when().get(operationsAppConfig.transfersEndpoint) + .andReturn().asString(); + + logger.info(scenarioScopeState.transactionId); + logger.info("Get Transfer Response: " + scenarioScopeState.response); + }); + } + + @Then("I check for error related to {}") + public void checkForError(String action) { + + JsonObject jsonObject = JsonParser.parseString(scenarioScopeState.response).getAsJsonObject(); + + JsonElement errorInformation = jsonObject.getAsJsonArray("content").get(0).getAsJsonObject().get("errorInformation"); + + boolean actionError = (errorInformation != null) && (errorInformation.isJsonObject() || errorInformation.isJsonArray()) + && errorInformation.getAsString().contains(action); + assertThat(actionError).isFalse(); + } + + @And("I assert the {} is {}") + public void checkSubPartStatus(String variable, String expectedValue) { + RequestSpecification requestSpec = Utils.getDefaultSpec(transferConfig.payerTenant); + if (authEnabled) { + requestSpec.header("Authorization", "Bearer " + scenarioScopeState.accessToken); + } + String endpoint = operationsAppConfig.variablesEndpoint + "/" + scenarioScopeState.transactionId; + String response = RestAssured.given(requestSpec).baseUri(operationsAppConfig.operationAppContactPoint).expect() + .spec(new ResponseSpecBuilder().expectStatusCode(200).build()).when().get(endpoint).andReturn().asString(); + + JsonObject jsonObject = JsonParser.parseString(response).getAsJsonObject(); + assertThat(jsonObject.get(variable)).isNotNull(); + + if (jsonObject.get(variable) != null) { + String status = jsonObject.get(variable).getAsString(); + assertThat(status).isEqualTo(expectedValue); + } + } + + @Then("I assert {string} balance to be {long}") + public void getCurrentBalance(String client, Long amount) throws JsonProcessingException { + RequestSpecification requestSpec = Utils.getDefaultSpec(); + if (client.equals("payer")) { + fundTransferDef.tenant = fundTransferDef.payerTenant; + } else { + fundTransferDef.tenant = fundTransferDef.payeeTenant; + } + requestSpec = fundTransferDef.setHeaders(requestSpec); + // Setting account ID in path + PostSavingsAccountsResponse savingsAccountResponse; + if (client.equals("payer")) { + savingsAccountResponse = objectMapper.readValue(fundTransferDef.responseSavingsAccountPayer, PostSavingsAccountsResponse.class); + } else { + savingsAccountResponse = objectMapper.readValue(fundTransferDef.responseSavingsAccountPayee, PostSavingsAccountsResponse.class); + } + String endpoint = transferConfig.savingsApproveEndpoint.replaceAll("\\{\\{savingsAccId\\}\\}", + savingsAccountResponse.getSavingsId().toString()); + + logger.info(endpoint); + String responseBody = RestAssured.given(requestSpec).baseUri(transferConfig.savingsBaseUrl).expect() + .spec(new ResponseSpecBuilder().expectStatusCode(200).build()).when().get(endpoint).andReturn().asString(); + + JsonObject jsonObject = JsonParser.parseString(responseBody).getAsJsonObject(); + + scenarioScopeState.currentBalance = jsonObject.get("summary").getAsJsonObject().get("accountBalance").getAsLong(); + logger.info(String.valueOf(scenarioScopeState.currentBalance)); + assertThat(scenarioScopeState.currentBalance).isEqualTo(amount); + } + + @When("I create and setup a {string} with account balance of {int}") + public void consolidatedPayerCreationSteps(String client, int amount) throws JsonProcessingException { + setTenantForPayer(client); + callCreateClientEndpoint(client); + callCreateSavingsProductEndpoint(client); + callCreateSavingsAccountEndpoint(client); + callCreateInteropIdentifierEndpoint(client); + callApproveSavingsEndpoint("approve", client); + callSavingsActivateEndpoint("activate", client); + callDepositAccountEndpoint("deposit", amount, client); + if (client.equals("payer")) { + scenarioScopeState.initialBalForPayer = amount; + assertThat(scenarioScopeState.initialBalForPayer).isNotNull(); + } else if (client.equals("payee")) { + scenarioScopeState.initialBalForPayee = amount; + assertThat(scenarioScopeState.initialBalForPayee).isNotNull(); + } + } + + @Then("Create a csv file with file name {string}") + public void createCsvWithHeaders(String fileName) throws IOException { + String filePath = Utils.getAbsoluteFilePathToResource(fileName); + String[] header = { "id", "request_id", "payment_mode", "payer_identifier_type", "payer_identifier", "payee_identifier_type", + "payee_identifier", "amount", "currency", "note" }; + scenarioScopeState.filename = fileName; + csvHelper.createCsvFileWithHeaders(filePath, header); + } + + @Then("add row to csv with current payer and payee, payment mode as {string} and transfer amount {int} and id {int}") + public void addRowToCsvFile(String paymentMode, int transferAmount, int id) throws IOException { + + String[] row = { String.valueOf(id), UUID.randomUUID().toString(), paymentMode, "msisdn", scenarioScopeState.payerIdentifier, + "msisdn", scenarioScopeState.payeeIdentifier, String.valueOf(transferAmount), "USD", "Test Payee Payment" }; + String filePath = Utils.getAbsoluteFilePathToResource(scenarioScopeState.filename); + csvHelper.addRow(filePath, row); + scenarioScopeState.gsmaP2PAmtDebit = scenarioScopeState.gsmaP2PAmtDebit + transferAmount; + if (scenarioScopeState.gsmaP2PAmtDebitForBatch == null) { + scenarioScopeState.gsmaP2PAmtDebitForBatch = new int[4]; + } + scenarioScopeState.gsmaP2PAmtDebitForBatch[id + 1] = transferAmount; + } + + @Then("add row to csv with current payer and payee, payment mode as {string} and transfer amount {int} and id {int} for combine test cases") + public void addRowToCsvFileForCombinedTestCases(String paymentMode, int transferAmount, int id) throws IOException { + if (paymentMode.equals("closedloop")) { + scenarioScopeState.payeeIdentifiers.add(scenarioScopeState.payeeIdentifier); + } + + String[] row = { String.valueOf(id), UUID.randomUUID().toString(), paymentMode, "msisdn", scenarioScopeState.payerIdentifier, + "msisdn", scenarioScopeState.payeeIdentifier, String.valueOf(transferAmount), "USD", "Test Payee Payment" }; + String filePath = Utils.getAbsoluteFilePathToResource(scenarioScopeState.filename); + csvHelper.addRow(filePath, row); + scenarioScopeState.gsmaP2PAmtDebit = scenarioScopeState.gsmaP2PAmtDebit + transferAmount; + if (scenarioScopeState.gsmaP2PAmtDebitForBatch == null) { + scenarioScopeState.gsmaP2PAmtDebitForBatch = new int[9]; + } + scenarioScopeState.gsmaP2PAmtDebitForBatch[id + 1] = transferAmount; + } + + @When("I create and setup a {string} with id {string} and account balance of {int} for all combine test cases") + public void consolidatedPayeeCreationStepsForAllCombinedTestsCases(String client, String id, int amount) + throws JsonProcessingException { + setTenantForPayer(client); + callCreateClientEndpoint(client); + callCreateSavingsProductEndpoint(client); + callCreateSavingsAccountEndpoint(client); + callCreateInteropIdentifierEndpoint(client); + callApproveSavingsEndpoint("approve", client); + callSavingsActivateEndpoint("activate", client); + callDepositAccountEndpoint("deposit", amount, client); + if (client.equals("payer")) { + if (scenarioScopeState.initialBalForPayerForBatch == null || id.equals("1")) { + scenarioScopeState.initialBalForPayerForBatch = new int[14]; + } + scenarioScopeState.initialBalForPayerForBatch[Integer.parseInt(id)] = amount; + assertThat(scenarioScopeState.initialBalForPayerForBatch[Integer.parseInt(id)]).isNotNull(); + + } else if (("payee").equals(client)) { + if (scenarioScopeState.initialBalForPayeeForBatch == null || id.equals("1")) { + scenarioScopeState.initialBalForPayeeForBatch = new int[14]; + } + scenarioScopeState.initialBalForPayeeForBatch[Integer.parseInt(id)] = amount; + assertThat(scenarioScopeState.initialBalForPayeeForBatch[Integer.parseInt(id)]).isNotNull(); + } + } + + @Then("add row to csv with current payer and payee, payment mode as {string} and transfer amount {int} and id {int} for all combine test cases") + public void addRowToCsvFileForAllCombinedTestCases(String paymentMode, int transferAmount, int id) throws IOException { + + String[] row = { String.valueOf(id), UUID.randomUUID().toString(), paymentMode, "msisdn", scenarioScopeState.payerIdentifier, + "msisdn", scenarioScopeState.payeeIdentifier, String.valueOf(transferAmount), "USD", "Test Payee Payment" }; + String filePath = Utils.getAbsoluteFilePathToResource(scenarioScopeState.filename); + csvHelper.addRow(filePath, row); + scenarioScopeState.gsmaP2PAmtDebit = scenarioScopeState.gsmaP2PAmtDebit + transferAmount; + if (scenarioScopeState.gsmaP2PAmtDebitForBatch == null || id == 1) { + scenarioScopeState.gsmaP2PAmtDebitForBatch = new int[14]; + } + scenarioScopeState.gsmaP2PAmtDebitForBatch[id + 1] = transferAmount; + } + + @Then("add last row to csv with current payer and payee, payment mode as {string} and transfer amount {int} and id {int}") + public void addLastRowToCsvFile(String paymentMode, int transferAmount, int id) throws IOException { + + String[] row = { String.valueOf(id), UUID.randomUUID().toString(), paymentMode, "msisdn", scenarioScopeState.payerIdentifier, + "msisdn", scenarioScopeState.payeeIdentifier, String.valueOf(transferAmount), "USD", "Test Payee Payment" }; + String filePath = Utils.getAbsoluteFilePathToResource(scenarioScopeState.filename); + csvHelper.addLastRow(filePath, row); + scenarioScopeState.gsmaP2PAmtDebit = scenarioScopeState.gsmaP2PAmtDebit + transferAmount; + scenarioScopeState.gsmaP2PAmtDebitForBatch[id + 1] = transferAmount; + + } + + @When("I create and setup a {string} with id {string} and account balance of {int}") + public void consolidatedPayeeCreationSteps(String client, String id, int amount) throws JsonProcessingException { + setTenantForPayer(client); + callCreateClientEndpoint(client); + callCreateSavingsProductEndpoint(client); + callCreateSavingsAccountEndpoint(client); + callCreateInteropIdentifierEndpoint(client); + callApproveSavingsEndpoint("approve", client); + callSavingsActivateEndpoint("activate", client); + callDepositAccountEndpoint("deposit", amount, client); + if (("payer").equals(client)) { + if (scenarioScopeState.initialBalForPayerForBatch == null) { + scenarioScopeState.initialBalForPayerForBatch = new int[4]; + } + scenarioScopeState.initialBalForPayerForBatch[Integer.parseInt(id)] = amount; + assertThat(scenarioScopeState.initialBalForPayerForBatch[Integer.parseInt(id)]).isNotNull(); + + } else if (("payee").equals(client)) { + if (scenarioScopeState.initialBalForPayeeForBatch == null) { + scenarioScopeState.initialBalForPayeeForBatch = new int[4]; + } + scenarioScopeState.initialBalForPayeeForBatch[Integer.parseInt(id)] = amount; + assertThat(scenarioScopeState.initialBalForPayeeForBatch[Integer.parseInt(id)]).isNotNull(); + } + } + + @When("I create and setup a {string} with id {string} and account balance of {int} for combine test cases") + public void consolidatedPayeeCreationStepsForCombinedTestsCases(String client, String id, int amount) throws JsonProcessingException { + setTenantForPayer(client); + callCreateClientEndpoint(client); + callCreateSavingsProductEndpoint(client); + callCreateSavingsAccountEndpoint(client); + callCreateInteropIdentifierEndpoint(client); + callApproveSavingsEndpoint("approve", client); + callSavingsActivateEndpoint("activate", client); + callDepositAccountEndpoint("deposit", amount, client); + if (client.equals("payer")) { + if (scenarioScopeState.initialBalForPayerForBatch == null) { + scenarioScopeState.initialBalForPayerForBatch = new int[9]; + } + scenarioScopeState.initialBalForPayerForBatch[Integer.parseInt(id)] = amount; + assertThat(scenarioScopeState.initialBalForPayerForBatch[Integer.parseInt(id)]).isNotNull(); + + } else if (client.equals("payee")) { + if (scenarioScopeState.initialBalForPayeeForBatch == null) { + scenarioScopeState.initialBalForPayeeForBatch = new int[9]; + } + scenarioScopeState.initialBalForPayeeForBatch[Integer.parseInt(id)] = amount; + assertThat(scenarioScopeState.initialBalForPayeeForBatch[Integer.parseInt(id)]).isNotNull(); + } + } + + @Then("I check whether budget account exists with accoundId {string}") + public void budgetAccountExistsWithAccoundId(String accountId) throws JsonProcessingException { + RequestSpecification requestSpec = Utils.getDefaultSpec(); + requestSpec = fundTransferDef.setHeaders(requestSpec); + // Setting account ID in path + + String endpoint = transferConfig.interopIdentifierEndpoint; + String identifierType = "MSISDN"; + endpoint = Util.getFormattedEndpoint(endpoint, "{{identifierType}}", identifierType); + endpoint = Util.getFormattedEndpoint(endpoint, "{{identifier}}", accountId); + try { + // Calling Interop Identifier endpoint + fundTransferDef.responseInteropIdentifier = RestAssured.given(requestSpec).baseUri(transferConfig.savingsBaseUrl).expect() + .spec(new ResponseSpecBuilder().build()).when().delete(endpoint).andReturn().asString(); + } catch (Exception e) { + logger.error("Error checking account existence: ", e); + throw new RuntimeException("Failed to check account existence", e); + } + logger.info("Interop Identifier Response: {}", fundTransferDef.responseInteropIdentifier); + assertThat(fundTransferDef.responseInteropIdentifier).isNotEmpty(); + } + +} diff --git a/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/cucumber/stepdef/PaymentStatusCheckDef.java b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/cucumber/stepdef/PaymentStatusCheckDef.java new file mode 100644 index 000000000..a4d1f1d0b --- /dev/null +++ b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/cucumber/stepdef/PaymentStatusCheckDef.java @@ -0,0 +1,73 @@ +package org.mifos.integrationtest.cucumber.stepdef; + +import static com.google.common.truth.Truth.assertThat; + +import io.cucumber.java.en.And; +import io.cucumber.java.en.Given; +import io.cucumber.java.en.When; +import io.restassured.RestAssured; +import io.restassured.builder.ResponseSpecBuilder; +import io.restassured.specification.RequestSpecification; +import org.mifos.integrationtest.common.Utils; +import org.mifos.integrationtest.common.dto.PaymentStatusCheckReqDto; +import org.mifos.integrationtest.config.PaymentStatusCheckConfig; +import org.springframework.beans.factory.annotation.Autowired; + +public class PaymentStatusCheckDef extends BaseStepDef { + + @Autowired + PaymentStatusCheckConfig paymentStatusCheckConfig; + + PaymentStatusCheckReqDto paymentStatusCheckReqDto = new PaymentStatusCheckReqDto(); + + @And("I extracted clientCorrelationId from response") + public void iExtractedClientCorrelationIdFromResponse() { + assertThat(scenarioScopeState.clientCorrelationId).isNotNull(); + paymentStatusCheckConfig.requestIds.add(scenarioScopeState.clientCorrelationId); + } + + @When("I should have clean request id list") + public void iShouldHaveCleanRequestIdList() { + paymentStatusCheckConfig.requestIds.clear(); + assertThat(paymentStatusCheckConfig.requestIds).isEmpty(); + } + + @Given("I can create a mock request body from above clientCorrelationIds") + public void iCanCreateAMockRequestBodyFromAboveClientCorrelationIds() { + assertThat(paymentStatusCheckConfig.requestIds).isNotEmpty(); + paymentStatusCheckReqDto.setRequestIds(paymentStatusCheckConfig.requestIds); + StringBuilder jsonBuilder = new StringBuilder(); + jsonBuilder.append("{"); + jsonBuilder.append("\"requestIds\": [").append("\"" + "\\" + "\"" + paymentStatusCheckConfig.requestIds.get(0) + "\\" + "\"" + "\"") + .append(",").append("\"" + "\\" + "\"" + paymentStatusCheckConfig.requestIds.get(1) + "\\" + "\"" + "\"").append("],"); + jsonBuilder.append("\"payeePartyIds\": []"); + jsonBuilder.append("}"); + String jsonString = jsonBuilder.toString(); + scenarioScopeState.paymentStatusCheckReqDto = jsonString; + assertThat(scenarioScopeState.paymentStatusCheckReqDto).isNotNull(); + logger.info("Payment Status Check Request Body: " + scenarioScopeState.paymentStatusCheckReqDto); + + } + + @When("I call the payment status check endpoint with expected status {int}") + public void iCallThePaymentStatusCheckEndpointWithExpectedStatus(int expectedStatus) { + RequestSpecification requestSpec = Utils.getDefaultSpec(scenarioScopeState.tenant); + if (authEnabled) { + requestSpec.header("Authorization", "Bearer " + scenarioScopeState.accessToken); + } + scenarioScopeState.response = RestAssured.given(requestSpec).baseUri(operationsAppConfig.operationAppContactPoint) + .body(scenarioScopeState.paymentStatusCheckReqDto).expect() + .spec(new ResponseSpecBuilder().expectStatusCode(expectedStatus).build()).when().post(operationsAppConfig.transfersEndpoint) + .andReturn().asString(); + + logger.info("Batch Details Response: " + scenarioScopeState.response); + } + + @And("I extracted clientCorrelationId from the demo csv file {string}") + public void iExtractedClientCorrelationIdFromTheDemoCsvFile(String filename) { + assertThat(filename).isNotNull(); + paymentStatusCheckConfig.requestIds.clear(); + paymentStatusCheckConfig.requestIds = Utils.extractClientCorrelationIdFromCsv(filename, paymentStatusCheckConfig.requestIds); + assertThat(paymentStatusCheckConfig.requestIds).isNotEmpty(); + } +} diff --git a/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/cucumber/stepdef/ScenarioScopeState.java b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/cucumber/stepdef/ScenarioScopeState.java new file mode 100644 index 000000000..0bc37d16d --- /dev/null +++ b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/cucumber/stepdef/ScenarioScopeState.java @@ -0,0 +1,125 @@ +package org.mifos.integrationtest.cucumber.stepdef; + +import io.cucumber.spring.ScenarioScope; +import io.restassured.response.Response; +import java.security.PublicKey; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.json.JSONObject; +import org.mifos.connector.common.channel.dto.TransactionChannelRequestDTO; +import org.mifos.integrationtest.common.dto.BatchRequestDTO; +import org.mifos.integrationtest.common.dto.KeycloakTokenResponse; +import org.mifos.integrationtest.common.dto.billpayp2g.BillPaymentsReqDTO; +import org.mifos.integrationtest.common.dto.kong.KeycloakUser; +import org.mifos.integrationtest.common.dto.kong.KongConsumer; +import org.mifos.integrationtest.common.dto.kong.KongConsumerKey; +import org.mifos.integrationtest.common.dto.kong.KongPlugin; +import org.mifos.integrationtest.common.dto.kong.KongRoute; +import org.mifos.integrationtest.common.dto.kong.KongService; +import org.mifos.integrationtest.common.dto.operationsapp.ActuatorResponse; +import org.mifos.integrationtest.common.dto.operationsapp.BatchAndSubBatchSummaryResponse; +import org.mifos.integrationtest.common.dto.operationsapp.BatchDTO; +import org.mifos.integrationtest.common.dto.operationsapp.BatchPaginatedResponse; +import org.mifos.integrationtest.common.dto.operationsapp.BatchTransactionResponse; +import org.mifos.integrationtest.common.dto.operationsapp.PaymentBatchDetail; +import org.springframework.stereotype.Component; + +@Component +@ScenarioScope +public class ScenarioScopeState { + + protected String payerIdentifier; + protected String payeeIdentifier; + + protected String fspId; + + protected String batchId; + protected String tenant; + protected String response; + protected String request; + + protected String payeeIdentity; + protected String requestId; + protected String callbackBody; + + protected Integer statusCode; + protected String accessToken; + protected String filename; + protected String requestType; + protected String clientCorrelationId; + protected String transactionId; + protected TransactionChannelRequestDTO inboundTransferMockReq; + protected String paymentStatusCheckReqDto; + protected BillPaymentsReqDTO inboundTransferReqP2G; + + protected String billId; + protected String callbackUrl; + protected KeycloakTokenResponse keycloakTokenResponse; + protected String randomData; + protected String encryptedData; + protected String decryptedData; + protected String privateKeyString; + protected String publicKeyString; + protected String newPublicKeyString; + protected PublicKey publicKey; + protected String certificateString; + + protected String status; + protected PaymentBatchDetail paymentBatchDetail; + protected Map batchesEndpointQueryParam = new HashMap<>(); + protected JSONObject requestBody; + protected BatchRequestDTO batchRequestDTO; + protected String batchRawRequest; + protected BatchAndSubBatchSummaryResponse batchAndSubBatchSummaryResponse; + protected Long currentBalance; + protected String beneficiaryPayeeIdentity; + protected KeycloakUser keycloakUser; + protected String signature; + protected Response restResponseObject; + protected String registeringInstituteId; + protected String programId; + protected BatchDTO batchDTO; + + protected ActuatorResponse actuatorResponse; + protected String dateTime; + public BatchTransactionResponse batchTransactionResponse; + protected KongConsumer kongConsumer; + protected KongConsumerKey kongConsumerKey; + protected KongService kongService; + protected KongRoute kongRoute; + protected KongPlugin kongPlugin; + protected BatchPaginatedResponse batchesResponse; + protected int gsmaP2PAmtDebit; + protected List payeeIdentifiers; + + protected int initialBalForPayer; + protected int initialBalForPayee; + protected String debitParty; + protected String creditParty; + protected String[] payeeIdentifierforBatch; + protected String[] payerIdentifierforBatch; + protected int[] initialBalForPayeeForBatch; + protected int[] initialBalForPayerForBatch; + protected int[] gsmaP2PAmtDebitForBatch; + protected List registeredBeneficiary = new ArrayList<>(); + protected String serialNumber; + + protected String requstId; + protected String createVoucherBody; + protected String activateVoucherBody; + protected String redeemVoucherBody; + protected String redeemVoucherResponseBody; + protected String voucherNumber; + protected String cancelVoucherBody; + protected String suspendVoucherBody; + protected String registeringInstitutionId; + protected String accountHoldingInstitutionId; + protected String amsName; + protected String agentId; + protected String fetchVoucherResponseBody; + protected String createTransactionChannelRequestBody; + protected String createGsmaTransferRequestBody; + protected String rtpId; +} diff --git a/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/cucumber/stepdef/ScenarioScopedBean.java b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/cucumber/stepdef/ScenarioScopedBean.java new file mode 100644 index 000000000..5222f20dc --- /dev/null +++ b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/cucumber/stepdef/ScenarioScopedBean.java @@ -0,0 +1,19 @@ +package org.mifos.integrationtest.cucumber.stepdef; + +import io.cucumber.spring.ScenarioScope; +import org.springframework.stereotype.Component; + +@Component +@ScenarioScope +public class ScenarioScopedBean { + + private String data; + + public String getData() { + return data; + } + + public void setData(String data) { + this.data = data; + } +} diff --git a/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/cucumber/stepdef/SecurityUtilStepDef.java b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/cucumber/stepdef/SecurityUtilStepDef.java new file mode 100644 index 000000000..7b461a6cf --- /dev/null +++ b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/cucumber/stepdef/SecurityUtilStepDef.java @@ -0,0 +1,88 @@ +package org.mifos.integrationtest.cucumber.stepdef; + +import static com.google.common.truth.Truth.assertThat; + +import io.cucumber.java.en.And; +import io.cucumber.java.en.Given; +import io.cucumber.java.en.Then; +import io.cucumber.java.en.When; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.security.spec.InvalidKeySpecException; +import java.util.UUID; +import javax.crypto.BadPaddingException; +import javax.crypto.IllegalBlockSizeException; +import javax.crypto.NoSuchPaddingException; +import org.mifos.connector.common.util.SecurityUtil; +import org.mifos.integrationtest.config.JWSKeyConfig; +import org.springframework.beans.factory.annotation.Autowired; + +public class SecurityUtilStepDef extends BaseStepDef { + + @Autowired + JWSKeyConfig jwsKeyConfig; + + @Given("generate random data") + public void generateRandomData() { + // Write code here that turns the phrase above into concrete actions + scenarioScopeState.randomData = UUID.randomUUID().toString(); + logger.debug("Random data: {}", scenarioScopeState.randomData); + } + + @When("encrypt the data with the {string}") + public void encryptTheDataWithThe(String encryptionKey) throws NoSuchPaddingException, IllegalBlockSizeException, + NoSuchAlgorithmException, BadPaddingException, InvalidKeySpecException, InvalidKeyException { + scenarioScopeState.encryptedData = SecurityUtil.encryptUsingPublicKey(scenarioScopeState.randomData, encryptionKey); + logger.debug("Encrypted data: {}", scenarioScopeState.encryptedData); + } + + @Then("encrypted data is not null") + public void encryptedDataIsNotNull() { + assertThat(scenarioScopeState.encryptedData).isNotNull(); + } + + @When("encrypted data is decrypted using the {string}") + public void encryptedDataIsDecryptedUsingThe(String decryptionKey) throws NoSuchPaddingException, IllegalBlockSizeException, + NoSuchAlgorithmException, BadPaddingException, InvalidKeySpecException, InvalidKeyException { + scenarioScopeState.decryptedData = SecurityUtil.decryptUsingPrivateKey(scenarioScopeState.encryptedData, decryptionKey); + logger.debug("Decrypted data: {} ", scenarioScopeState.decryptedData); + } + + @Then("compare the decrypted data with the original data") + public void compareTheDecryptedDataWithTheOriginalData() { + assertThat(scenarioScopeState.decryptedData).isEqualTo(scenarioScopeState.randomData); + } + + @Given("I have public key {string}") + public void setPublicKey(String publicKeyString) { + scenarioScopeState.publicKeyString = publicKeyString; + assertThat(scenarioScopeState.publicKeyString).isNotEmpty(); + } + + @And("I have private key") + public void setPrivateKey() { + assertThat(jwsKeyConfig).isNotNull(); + scenarioScopeState.privateKeyString = jwsKeyConfig.privateKey; + assertThat(scenarioScopeState.privateKeyString).isNotEmpty(); + } + + @When("I get the publicKey object from string") + public void getPublicKeyObject() throws NoSuchAlgorithmException, InvalidKeySpecException { + scenarioScopeState.publicKey = SecurityUtil.getPublicKeyFromString(scenarioScopeState.publicKeyString); + assertThat(scenarioScopeState.publicKey).isNotNull(); + } + + @Then("I should be able to get string from publicKey object") + public void getPublicKeyStringFromPublicKey() { + String pkString = SecurityUtil.getStringFromPublicKey(this.scenarioScopeState.publicKey); + assertThat(pkString).isNotEmpty(); + scenarioScopeState.newPublicKeyString = pkString; + logger.debug("Parsed public key: {}", pkString); + } + + @And("It should be equal to original key") + public void comparePublicKeyString() { + assertThat(scenarioScopeState.publicKeyString).isEqualTo(scenarioScopeState.newPublicKeyString); + } + +} diff --git a/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/cucumber/stepdef/StepDefinitions.java b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/cucumber/stepdef/StepDefinitions.java new file mode 100644 index 000000000..5e0c4e881 --- /dev/null +++ b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/cucumber/stepdef/StepDefinitions.java @@ -0,0 +1,27 @@ +package org.mifos.integrationtest.cucumber.stepdef; + +import io.cucumber.java.en.Given; +import io.cucumber.java.en.Then; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; + +public class StepDefinitions { + + @Autowired + private ScenarioScopedBean scenarioScopedBean; + + Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Given("I set the variable to {string}") + public void setVariable(String value) { + scenarioScopedBean.setData(value); + } + + @Then("I retrieve the variable") + public void retrieveVariable() { + String retrievedData = scenarioScopedBean.getData(); + logger.info("Retrieved data: {}", retrievedData); + // You can log or assert the retrievedData as needed + } +} diff --git a/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/cucumber/stepdef/ValidateChannelDef.java b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/cucumber/stepdef/ValidateChannelDef.java new file mode 100644 index 000000000..7d7597770 --- /dev/null +++ b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/cucumber/stepdef/ValidateChannelDef.java @@ -0,0 +1,170 @@ +package org.mifos.integrationtest.cucumber.stepdef; + +import static com.google.common.truth.Truth.assertThat; + +import io.cucumber.core.internal.com.fasterxml.jackson.databind.JsonNode; +import io.cucumber.core.internal.com.fasterxml.jackson.databind.ObjectMapper; +import io.cucumber.java.en.And; +import io.cucumber.java.en.Given; +import io.cucumber.java.en.When; +import io.restassured.RestAssured; +import io.restassured.builder.ResponseSpecBuilder; +import io.restassured.specification.RequestSpecification; +import org.mifos.connector.common.channel.dto.TransactionChannelRequestDTO; +import org.mifos.connector.common.mojaloop.dto.MoneyData; +import org.mifos.connector.common.mojaloop.dto.Party; +import org.mifos.connector.common.mojaloop.type.IdentifierType; +import org.mifos.integrationtest.common.TransactionHelper; +import org.mifos.integrationtest.common.Utils; +import org.mifos.integrationtest.common.dto.ErrorDetails; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; + +public class ValidateChannelDef extends BaseStepDef { + + @Autowired + ScenarioScopeState scenarioScopeState; + + Logger logger = LoggerFactory.getLogger(VoucherManagementStepDef.class); + + @Value("${tenantconfig.tenants.paymentbb2}") + private String tenant; + + private String tenantHeader = "Platform-TenantId"; + + @Given("I can create a TransactionChannelRequestDTO with no payee") + public void iCanCreateATransactionChannelRequestDTOWithNoPayee() { + TransactionHelper transactionHelper = new TransactionHelper(); + Party payer = transactionHelper.partyHelper(IdentifierType.MSISDN, "27710101999"); + MoneyData amount = transactionHelper.amountHelper("100", "SNR"); + TransactionChannelRequestDTO requestDTO = transactionHelper.transactionChannelRequestHelper(payer, null, amount); + ObjectMapper objectMapper = new ObjectMapper(); + try { + scenarioScopeState.createTransactionChannelRequestBody = objectMapper.writeValueAsString(requestDTO); + } catch (Exception e) { + logger.error("An Exception occurred", e); + } + } + + @When("I call the post transfer API with expected status of {int}") + public void iCallThePostTransferAPIWithExpectedStatusOf(int expectedStatus) { + RequestSpecification requestSpec = Utils.getDefaultSpec(); + scenarioScopeState.tenant = tenant; + scenarioScopeState.response = RestAssured.given(requestSpec).header("Content-Type", "application/json") + .header(tenantHeader, scenarioScopeState.tenant).baseUri(channelConnectorConfig.channelConnectorContactPoint) + .body(scenarioScopeState.createTransactionChannelRequestBody).expect() + .spec(new ResponseSpecBuilder().expectStatusCode(expectedStatus).build()).when() + .post(channelConnectorConfig.transferEndpoint).andReturn().asString(); + + logger.info("Post Transfer Response: {}", scenarioScopeState.response); + } + + @When("I call the transaction request API with expected status of {int}") + public void iCallTheTransactionRequestAPIWithExpectedStatusOf(int expectedStatus) { + RequestSpecification requestSpec = Utils.getDefaultSpec(); + + scenarioScopeState.tenant = tenant; + scenarioScopeState.response = RestAssured.given(requestSpec).header("Content-Type", "application/json") + .header(tenantHeader, scenarioScopeState.tenant).baseUri(channelConnectorConfig.channelConnectorContactPoint) + .body(scenarioScopeState.createTransactionChannelRequestBody).expect() + .spec(new ResponseSpecBuilder().expectStatusCode(expectedStatus).build()).when() + .post(channelConnectorConfig.transferReqEndpoint).andReturn().asString(); + + logger.info("Transaction Request Response: {}", scenarioScopeState.response); + } + + @And("I should be able to assert the api validation for schema validation error response") + public void iWillAssertTheFieldsFromValidationResponseForSchemaValidation() { + try { + JsonNode rootNode = objectMapper.readTree(scenarioScopeState.response); + + ErrorDetails errorDetails = objectMapper.treeToValue(rootNode, ErrorDetails.class); + + assertThat(errorDetails.getErrorCode()).isEqualTo("error.msg.schema.validation.errors"); + assertThat(errorDetails.getErrorDescription()).isEqualTo("The request is invalid"); + + } catch (Exception e) { + logger.info("An error occurred : {}", e); + } + } + + @And("I should be able to assert the api validation for header validation error response") + public void iWillAssertTheFieldsFromValidationResponseForHeaderValidation() { + try { + JsonNode rootNode = objectMapper.readTree(scenarioScopeState.response); + + ErrorDetails errorDetails = objectMapper.treeToValue(rootNode, ErrorDetails.class); + + assertThat(errorDetails.getErrorCode()).isEqualTo("error.msg.header.validation.errors"); + assertThat(errorDetails.getErrorDescription()).isEqualTo("The headers are invalid"); + + } catch (Exception e) { + logger.info("An error occurred : {}", e); + } + } + + @Given("I can create a TransactionChannelRequestDTO") + public void iCreateATransactionChannelRequestDTO() { + TransactionHelper transactionHelper = new TransactionHelper(); + Party payer = transactionHelper.partyHelper(IdentifierType.MSISDN, "27710101999"); + Party payee = transactionHelper.partyHelper(IdentifierType.MSISDN, "27710101999"); + MoneyData amount = transactionHelper.amountHelper("100", "SNR"); + TransactionChannelRequestDTO requestDTO = transactionHelper.transactionChannelRequestHelper(payer, payee, amount); + ObjectMapper objectMapper = new ObjectMapper(); + try { + scenarioScopeState.createTransactionChannelRequestBody = objectMapper.writeValueAsString(requestDTO); + } catch (Exception e) { + logger.error("An Exception occurred", e); + } + } + + @When("I call the post transfer API having unsupported header with expected status of {int}") + public void iCallThePostTransferAPIHavingUnsupportedHeaderWithExpectedStatusOf(int expectedStatus) { + RequestSpecification requestSpec = Utils.getDefaultSpec(); + scenarioScopeState.tenant = tenant; + scenarioScopeState.response = RestAssured.given(requestSpec).header("Content-Type", "application/json") + .header(tenantHeader, scenarioScopeState.tenant).header("invalid-header", "test") + .baseUri(channelConnectorConfig.channelConnectorContactPoint).body(scenarioScopeState.createTransactionChannelRequestBody) + .expect().spec(new ResponseSpecBuilder().expectStatusCode(expectedStatus).build()).when() + .post(channelConnectorConfig.transferEndpoint).andReturn().asString(); + + logger.info("Post Transfer Response: {}", scenarioScopeState.response); + } + + @When("I call the transaction request API having unsupported header with expected status of {int}") + public void iCallTheTransactionRequestAPIHavingUnsupportedHeaderWithExpectedStatusOf(int expectedStatus) { + RequestSpecification requestSpec = Utils.getDefaultSpec(); + scenarioScopeState.tenant = tenant; + scenarioScopeState.response = RestAssured.given(requestSpec).header("Content-Type", "application/json") + .header(tenantHeader, scenarioScopeState.tenant).header("invalid-header", "test") + .baseUri(channelConnectorConfig.channelConnectorContactPoint).body(scenarioScopeState.createTransactionChannelRequestBody) + .expect().spec(new ResponseSpecBuilder().expectStatusCode(expectedStatus).build()).when() + .post(channelConnectorConfig.transferReqEndpoint).andReturn().asString(); + + logger.info("Transaction Request Response: {}", scenarioScopeState.response); + } + + @When("I call the post transfer API without required header Platform-TenantId with expected status of {int}") + public void iCallThePostTransferAPINotHavingRequiredHeaderPlatformTenantIdWithExpectedStatusOf(int expectedStatus) { + RequestSpecification requestSpec = Utils.getDefaultSpec(); + scenarioScopeState.response = RestAssured.given(requestSpec).header("Content-Type", "application/json") + .baseUri(channelConnectorConfig.channelConnectorContactPoint).body(scenarioScopeState.createTransactionChannelRequestBody) + .expect().spec(new ResponseSpecBuilder().expectStatusCode(expectedStatus).build()).when() + .post(channelConnectorConfig.transferEndpoint).andReturn().asString(); + + logger.info("Post Transfer Response: {}", scenarioScopeState.response); + } + + @When("I call the transaction request API without required header Platform-TenantId with expected status of {int}") + public void iCallTheTransactionRequestAPINotHavingRequiredHeaderPlatformTenantIdWithExpectedStatusOf(int expectedStatus) { + RequestSpecification requestSpec = Utils.getDefaultSpec(); + scenarioScopeState.response = RestAssured.given(requestSpec).header("Content-Type", "application/json") + .baseUri(channelConnectorConfig.channelConnectorContactPoint).body(scenarioScopeState.createTransactionChannelRequestBody) + .expect().spec(new ResponseSpecBuilder().expectStatusCode(expectedStatus).build()).when() + .post(channelConnectorConfig.transferReqEndpoint).andReturn().asString(); + + logger.info("Transaction Request Response: {}", scenarioScopeState.response); + } +} diff --git a/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/cucumber/stepdef/ValidateGsmaDef.java b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/cucumber/stepdef/ValidateGsmaDef.java new file mode 100644 index 000000000..5a9cf29f3 --- /dev/null +++ b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/cucumber/stepdef/ValidateGsmaDef.java @@ -0,0 +1,124 @@ +package org.mifos.integrationtest.cucumber.stepdef; + +import io.cucumber.core.internal.com.fasterxml.jackson.core.JsonProcessingException; +import io.cucumber.core.internal.com.fasterxml.jackson.databind.ObjectMapper; +import io.cucumber.java.en.Given; +import io.cucumber.java.en.When; +import io.restassured.RestAssured; +import io.restassured.builder.ResponseSpecBuilder; +import io.restassured.specification.RequestSpecification; +import java.util.ArrayList; +import java.util.List; +import org.mifos.connector.common.gsma.dto.CustomData; +import org.mifos.connector.common.gsma.dto.GsmaTransfer; +import org.mifos.connector.common.gsma.dto.Party; +import org.mifos.integrationtest.common.GsmaTransactionHelper; +import org.mifos.integrationtest.common.Utils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; + +public class ValidateGsmaDef extends BaseStepDef { + + @Autowired + ScenarioScopeState scenarioScopeState; + + Logger logger = LoggerFactory.getLogger(VoucherManagementStepDef.class); + + @Value("${callback_url}") + private String callbackUrl; + + @Value("${amsName}") + private String amsName; + + @Value("${tenantconfig.tenants.payerfsp}") + private String accountHoldingInstitutionId; + + private String accountHoldingInstitutionIdHeader = "accountHoldingInstitutionId"; + + private String amsNameHeader = "amsName"; + + private String callbackUrlHeader = "X-CallbackURL"; + + @Given("I can create a GsmaTransfer DTO with no payee list") + public void iCanCreateANegativeGsmaTransferDTO() { + GsmaTransactionHelper gsmaTransactionHelper = new GsmaTransactionHelper(); + List customDataList = new ArrayList<>(); + customDataList = gsmaTransactionHelper.customDataListHelper(customDataList, "string", "string"); + List payerList = gsmaTransactionHelper.partyListHelper("MSISDN", "+44999911"); + GsmaTransfer gsmaTransferDTO = gsmaTransactionHelper.gsmaTransferHelper("string", "inbound", "transfer", "100", "SNR", "string", + "2022-09-28T12:51:19.260+00:00", customDataList, payerList, null); + ObjectMapper objectMapper = new ObjectMapper(); + try { + scenarioScopeState.createGsmaTransferRequestBody = objectMapper.writeValueAsString(gsmaTransferDTO); + } catch (JsonProcessingException e) { + logger.error("Unable to convert the DTO : {}", e); + } + } + + @Given("I can create a GsmaTransfer DTO") + public void iCanCreateAGsmaTransferDTO() { + GsmaTransactionHelper gsmaTransactionHelper = new GsmaTransactionHelper(); + List customDataList = new ArrayList<>(); + customDataList = gsmaTransactionHelper.customDataListHelper(customDataList, "string", "string"); + List payerList = gsmaTransactionHelper.partyListHelper("MSISDN", "+44999911"); + List payeeList = gsmaTransactionHelper.partyListHelper("MSISDN", "+44999911"); + GsmaTransfer gsmaTransferDTO = gsmaTransactionHelper.gsmaTransferHelper("string", "inbound", "transfer", "100", "SNR", "string", + "2022-09-28T12:51:19.260+00:00", customDataList, payerList, payeeList); + ObjectMapper objectMapper = new ObjectMapper(); + try { + scenarioScopeState.createGsmaTransferRequestBody = objectMapper.writeValueAsString(gsmaTransferDTO); + } catch (JsonProcessingException e) { + logger.error("Unable to convert the DTO : {}", e); + } + } + + @When("I call the GSMA transaction API with expected status of {int}") + public void iCallTheGsmaTransactionAPIWithExpectedStatusOf(int expectedStatus) { + RequestSpecification requestSpec = Utils.getDefaultSpec(); + scenarioScopeState.callbackUrl = callbackUrl; + scenarioScopeState.amsName = amsName; + scenarioScopeState.accountHoldingInstitutionId = accountHoldingInstitutionId; + scenarioScopeState.response = RestAssured.given(requestSpec).header("Content-Type", "application/json") + .header(accountHoldingInstitutionIdHeader, scenarioScopeState.accountHoldingInstitutionId) + .header(amsNameHeader, scenarioScopeState.amsName).header(callbackUrlHeader, scenarioScopeState.callbackUrl) + .baseUri(channelConnectorConfig.channelConnectorContactPoint).body(scenarioScopeState.createGsmaTransferRequestBody) + .expect().spec(new ResponseSpecBuilder().expectStatusCode(expectedStatus).build()).when() + .post(channelConnectorConfig.getGsmaTransactionEndpoint()).andReturn().asString(); + + logger.info("Gsma transaction Response: {}", scenarioScopeState.response); + } + + @When("I call the gsma transaction API having unsupported header with expected status of {int}") + public void iCallTheGsmaTransactionAPIHavingUnsupportedHeaderWithExpectedStatusOf(int expectedStatus) { + RequestSpecification requestSpec = Utils.getDefaultSpec(); + scenarioScopeState.callbackUrl = callbackUrl; + scenarioScopeState.amsName = amsName; + scenarioScopeState.accountHoldingInstitutionId = accountHoldingInstitutionId; + scenarioScopeState.response = RestAssured.given(requestSpec).header("Content-Type", "application/json") + .header(accountHoldingInstitutionIdHeader, scenarioScopeState.accountHoldingInstitutionId) + .header(amsNameHeader, scenarioScopeState.amsName).header(callbackUrlHeader, scenarioScopeState.callbackUrl) + .header("invalid-header", "test").baseUri(channelConnectorConfig.channelConnectorContactPoint) + .body(scenarioScopeState.createGsmaTransferRequestBody).expect() + .spec(new ResponseSpecBuilder().expectStatusCode(expectedStatus).build()).when() + .post(channelConnectorConfig.getGsmaTransactionEndpoint()).andReturn().asString(); + + logger.info("Transaction Request Response: {}", scenarioScopeState.response); + } + + @When("I call the gsma transaction API without required header accountHoldingInstitutionId with expected status of {int}") + public void iCallTheGsmaTransactionAPINotHavingRequiredHeaderAccountHoldingInstitutionIdWithExpectedStatusOf(int expectedStatus) { + RequestSpecification requestSpec = Utils.getDefaultSpec(); + scenarioScopeState.callbackUrl = callbackUrl; + scenarioScopeState.amsName = amsName; + scenarioScopeState.response = RestAssured.given(requestSpec).header("Content-Type", "application/json") + .header(amsNameHeader, scenarioScopeState.amsName).header(callbackUrlHeader, scenarioScopeState.callbackUrl) + .baseUri(channelConnectorConfig.channelConnectorContactPoint).body(scenarioScopeState.createGsmaTransferRequestBody) + .expect().spec(new ResponseSpecBuilder().expectStatusCode(expectedStatus).build()).when() + .post(channelConnectorConfig.getGsmaTransactionEndpoint()).andReturn().asString(); + + logger.info("GSMA Transaction Response: {}", scenarioScopeState.response); + } + +} diff --git a/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/cucumber/stepdef/ValidateTxnDef.java b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/cucumber/stepdef/ValidateTxnDef.java new file mode 100644 index 000000000..e6a358635 --- /dev/null +++ b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/cucumber/stepdef/ValidateTxnDef.java @@ -0,0 +1,30 @@ +package org.mifos.integrationtest.cucumber.stepdef; + +import static com.google.common.truth.Truth.assertThat; + +import io.cucumber.core.internal.com.fasterxml.jackson.core.JsonProcessingException; +import io.cucumber.java.en.Given; +import org.mifos.connector.common.channel.dto.TransactionChannelRequestDTO; + +public class ValidateTxnDef extends BaseStepDef { + + public static TransactionChannelRequestDTO mockTransactionChannelRequestDTO = null; + + @Given("I can mock TransactionChannelRequestDTO with wrong msisdn") + public void iCanMockTransactionChannelRequestDTOWithWrongMsisdn() throws JsonProcessingException { + if (mockTransactionChannelRequestDTO != null) { + assertThat(mockTransactionChannelRequestDTO).isNotNull(); + return; + } + StringBuilder jsonBuilder = new StringBuilder(); + jsonBuilder.append("{").append("\"payer\": {").append("\"partyIdInfo\": {").append("\"partyIdType\": \"MSISDN\",") + .append("\"partyIdentifier\": \"277101019bbv\"").append("}},").append("\"payee\": {").append("\"partyIdInfo\": {") + .append("\"partyIdType\": \"MSISDN\",").append("\"partyIdentifier\": \"27710102999\"").append("}},").append("\"amount\": {") + .append("\"amount\": 230,").append("\"currency\": \"TZS\"").append("}}"); + String json = jsonBuilder.toString(); + mockTransactionChannelRequestDTO = objectMapper.readValue(json, TransactionChannelRequestDTO.class); + assertThat(mockTransactionChannelRequestDTO).isNotNull(); + scenarioScopeState.inboundTransferMockReq = mockTransactionChannelRequestDTO; + } + +} diff --git a/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/cucumber/stepdef/VoucherManagementStepDef.java b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/cucumber/stepdef/VoucherManagementStepDef.java new file mode 100644 index 000000000..539d5cbb1 --- /dev/null +++ b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/cucumber/stepdef/VoucherManagementStepDef.java @@ -0,0 +1,693 @@ +package org.mifos.integrationtest.cucumber.stepdef; + +import static com.github.tomakehurst.wiremock.client.WireMock.equalTo; +import static com.github.tomakehurst.wiremock.client.WireMock.getAllServeEvents; +import static com.github.tomakehurst.wiremock.client.WireMock.matchingJsonPath; +import static com.github.tomakehurst.wiremock.client.WireMock.putRequestedFor; +import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo; +import static com.github.tomakehurst.wiremock.client.WireMock.verify; +import static com.google.common.truth.Truth.assertThat; +import static java.util.concurrent.TimeUnit.SECONDS; +import static org.awaitility.Awaitility.await; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mifos.integrationtest.common.HttpMethod.PUT; + +import com.github.tomakehurst.wiremock.client.VerificationException; +import com.github.tomakehurst.wiremock.stubbing.ServeEvent; +import com.opencsv.CSVWriter; +import io.cucumber.core.internal.com.fasterxml.jackson.core.JsonProcessingException; +import io.cucumber.core.internal.com.fasterxml.jackson.databind.JsonNode; +import io.cucumber.core.internal.com.fasterxml.jackson.databind.ObjectMapper; +import io.cucumber.core.internal.com.fasterxml.jackson.databind.node.ObjectNode; +import io.cucumber.java.After; +import io.cucumber.java.Before; +import io.cucumber.java.en.And; +import io.cucumber.java.en.Given; +import io.cucumber.java.en.Then; +import io.cucumber.java.en.When; +import io.restassured.RestAssured; +import io.restassured.builder.ResponseSpecBuilder; +import io.restassured.specification.RequestSpecification; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.List; +import org.mifos.integrationtest.common.UniqueNumberGenerator; +import org.mifos.integrationtest.common.Utils; +import org.mifos.integrationtest.common.dto.ErrorDetails; +import org.mifos.integrationtest.common.dto.voucher.RedeemVoucherRequestDTO; +import org.mifos.integrationtest.common.dto.voucher.RequestDTO; +import org.mifos.integrationtest.common.dto.voucher.VoucherInstruction; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; + +public class VoucherManagementStepDef extends BaseStepDef { + + @Autowired + MockServerStepDef mockServerStepDef; + + @Autowired + ScenarioScopeState scenarioScopeState; + + Logger logger = LoggerFactory.getLogger(VoucherManagementStepDef.class); + + @Given("I can create an VoucherRequestDTO for voucher creation") + public void iCreateAnIdentityMapperDTOForRegisterBeneficiary() { + scenarioScopeState.requestId = generateUniqueNumber(12); + scenarioScopeState.batchId = generateUniqueNumber(10); + RequestDTO voucherDTO = new RequestDTO(); + voucherDTO.setRequestID(scenarioScopeState.requestId); + voucherDTO.setBatchID(scenarioScopeState.batchId); + + VoucherInstruction voucherInstruction = new VoucherInstruction(); + voucherInstruction.setInstructionID(generateUniqueNumber(16)); + voucherInstruction.setGroupCode("021"); + voucherInstruction.setCurrency("SGD"); + voucherInstruction.setAmount(BigDecimal.valueOf(9000)); + voucherInstruction.setPayeeFunctionalID("63310590322288932682"); + voucherInstruction.setNarration("Social Support Payment for the Month of Jan"); + + ArrayList voucherInstructions = new ArrayList<>(); + voucherInstructions.add(voucherInstruction); + + voucherDTO.setVoucherInstructions(voucherInstructions); + + ObjectMapper objectMapper = new ObjectMapper(); + try { + scenarioScopeState.createVoucherBody = objectMapper.writeValueAsString(voucherDTO); + } catch (JsonProcessingException e) { + logger.error("Unable to convert the DTO : {}", e); + } + } + + @When("I call the create voucher API with expected status of {int} and stub {string}") + public void iCallTheVoucherCreateAPIWithExpectedStatusOf(int expectedStatus, String stub) { + await().atMost(awaitMost, SECONDS).pollDelay(pollDelay, SECONDS).pollInterval(pollInterval, SECONDS).untilAsserted(() -> { + RequestSpecification requestSpec = Utils.getDefaultSpec(); + scenarioScopeState.registeringInstitutionId = "SocialWelfare"; + scenarioScopeState.response = RestAssured.given(requestSpec).header("Content-Type", "application/json") + .header("X-CallbackURL", identityMapperConfig.callbackURL + stub) + .header("X-Registering-Institution-ID", scenarioScopeState.registeringInstitutionId) + .baseUri(voucherManagementConfig.voucherManagementContactPoint).body(scenarioScopeState.createVoucherBody).expect() + .spec(new ResponseSpecBuilder().expectStatusCode(expectedStatus).build()).when() + .post(voucherManagementConfig.createVoucherEndpoint).andReturn().asString(); + + logger.info("Create Voucher Response: {}", scenarioScopeState.response); + }); + } + + @When("I call the create voucher API having invalid header with expected status of {int} and stub {string}") + public void iCallTheVoucherCreateAPIHavingInvalidHeaderWithExpectedStatusOf(int expectedStatus, String stub) { + await().atMost(awaitMost, SECONDS).pollDelay(pollDelay, SECONDS).pollInterval(pollInterval, SECONDS).untilAsserted(() -> { + RequestSpecification requestSpec = Utils.getDefaultSpec(); + scenarioScopeState.registeringInstitutionId = "SocialWelfare"; + scenarioScopeState.response = RestAssured.given(requestSpec).header("Content-Type", "application/json") + .header("X-CallbackURL", identityMapperConfig.callbackURL + stub) + .header("X-Registering-Institution-ID", scenarioScopeState.registeringInstitutionId).header("invalid-header", "test") + .baseUri(voucherManagementConfig.voucherManagementContactPoint).body(scenarioScopeState.createVoucherBody).expect() + .spec(new ResponseSpecBuilder().expectStatusCode(expectedStatus).build()).when() + .post(voucherManagementConfig.createVoucherEndpoint).andReturn().asString(); + + logger.info("Create Voucher Response: {}", scenarioScopeState.response); + }); + } + + public static String generateUniqueNumber(int length) { + return UniqueNumberGenerator.generateUniqueNumber(length); + } + + @When("I can create an VoucherRequestDTO for voucher activation") + public void iCanCreateAnVoucherRequestDTOForVoucherActivation() { + + VoucherInstruction voucherInstruction = new VoucherInstruction(); + voucherInstruction.setSerialNumber(scenarioScopeState.serialNumber); + voucherInstruction.setStatus("02"); + + ArrayList voucherInstructions = new ArrayList<>(); + voucherInstructions.add(voucherInstruction); + + RequestDTO requestDTO = new RequestDTO(scenarioScopeState.requestId, scenarioScopeState.batchId, voucherInstructions); + ObjectMapper objectMapper = new ObjectMapper(); + try { + scenarioScopeState.activateVoucherBody = objectMapper.writeValueAsString(requestDTO); + } catch (JsonProcessingException e) { + logger.error("Unable to convert the DTO : {}", e); + } + } + + @When("I call the activate voucher API with expected status of {int} and stub {string}") + public void iCallTheActivateVoucherAPIWithExpectedStatusOfAndStub(int expectedStatus, String stub) { + await().atMost(awaitMost, SECONDS).pollDelay(pollDelay, SECONDS).pollInterval(pollInterval, SECONDS).untilAsserted(() -> { + RequestSpecification requestSpec = Utils.getDefaultSpec(); + scenarioScopeState.response = RestAssured.given(requestSpec).header("Content-Type", "application/json") + .header("X-CallbackURL", identityMapperConfig.callbackURL + stub) + .header("X-Registering-Institution-ID", scenarioScopeState.registeringInstitutionId).header("X-Program-ID", "123") + .queryParam("command", "activate").baseUri(voucherManagementConfig.voucherManagementContactPoint) + .body(scenarioScopeState.activateVoucherBody).expect() + .spec(new ResponseSpecBuilder().expectStatusCode(expectedStatus).build()).when() + .put(voucherManagementConfig.voucherLifecycleEndpoint).andReturn().asString(); + + logger.info("Activate Voucher Response: {}", scenarioScopeState.response); + }); + } + + @When("I can create an VoucherRequestDTO for voucher cancellation") + public void iCanCreateAnVoucherRequestDTOForVoucherCancellation() { + VoucherInstruction voucherInstruction = new VoucherInstruction(); + voucherInstruction.setSerialNumber(scenarioScopeState.serialNumber); + voucherInstruction.setStatus("03"); + + ArrayList voucherInstructions = new ArrayList<>(); + voucherInstructions.add(voucherInstruction); + + RequestDTO requestDTO = new RequestDTO(scenarioScopeState.requestId, scenarioScopeState.batchId, voucherInstructions); + ObjectMapper objectMapper = new ObjectMapper(); + try { + scenarioScopeState.cancelVoucherBody = objectMapper.writeValueAsString(requestDTO); + } catch (JsonProcessingException e) { + logger.error("Unable to convert the DTO : {}", e); + } + } + + @Then("I should be able to verify that the {string} method to {string} endpoint received a request with required parameter in cancel voucher callback body") + public void iShouldBeAbleToVerifyThatTheMethodToEndpointReceivedARequestWithRequiredParameterInCancelVoucherCallbackBody(String arg0, + String endpoint) { + verify(putRequestedFor(urlEqualTo(endpoint)) + .withRequestBody(matchingJsonPath("$.requestID", equalTo(scenarioScopeState.requstId)))); + + } + + @When("I call the cancel voucher API with expected status of {int} and stub {string}") + public void iCallTheCancelVoucherAPIWithExpectedStatusOfAndStub(int expectedStatus, String stub) { + RequestSpecification requestSpec = Utils.getDefaultSpec(); + scenarioScopeState.response = RestAssured.given(requestSpec).header("Content-Type", "application/json") + .header("X-CallbackURL", identityMapperConfig.callbackURL + stub) + .header("X-Registering-Institution-ID", scenarioScopeState.registeringInstitutionId).header("X-Program-ID", "123") + .queryParam("command", "cancel").baseUri(voucherManagementConfig.voucherManagementContactPoint) + .body(scenarioScopeState.cancelVoucherBody).expect() + .spec(new ResponseSpecBuilder().expectStatusCode(expectedStatus).build()).when() + .post(voucherManagementConfig.voucherLifecycleEndpoint).andReturn().asString(); + + logger.info("Voucher Response: {}", scenarioScopeState.response); + } + + @Then("I should be able to verify that the {string} method to {string} endpoint received a request with required parameter in redeem voucher callback body") + public void iShouldBeAbleToVerifyThatTheMethodToEndpointReceivedARequestWithRequiredParameterInRedeemVoucherCallbackBody(String arg0, + String endpoint) { + verify(putRequestedFor(urlEqualTo(endpoint)) + .withRequestBody(matchingJsonPath("$.requestID", equalTo(scenarioScopeState.requstId)))); + } + + @Then("I should be able to verify that the {string} method to {string} endpoint received a request with required parameter in suspend voucher callback body") + public void iShouldBeAbleToVerifyThatTheMethodToEndpointReceivedARequestWithRequiredParameterInSuspendVoucherCallbackBody(String arg0, + String endpoint) { + verify(putRequestedFor(urlEqualTo(endpoint)) + .withRequestBody(matchingJsonPath("$.requestID", equalTo(scenarioScopeState.requstId)))); + } + + @Then("I should be able to extract response body from callback") + public void iShouldBeAbleToExtractResponseBodyFromCallback() { + await().atMost(awaitMost, SECONDS).pollDelay(pollDelay, SECONDS).pollInterval(pollInterval, SECONDS).untilAsserted(() -> { + List allServeEvents = getAllServeEvents(); + + for (int i = 0; i < allServeEvents.size(); i++) { + ServeEvent request = allServeEvents.get(i); + + if (!(request.getRequest().getBodyAsString()).isEmpty()) { + JsonNode rootNode = null; + try { + rootNode = objectMapper.readTree(request.getRequest().getBodyAsString()); + } catch (JsonProcessingException e) { + throw new RuntimeException(e); + } + String requestID = null; + if (rootNode.has("requestID")) { + requestID = rootNode.get("requestID").asText(); + } + if (rootNode.has("batchID")) { + scenarioScopeState.batchId = rootNode.get("batchID").asText(); + } + if (scenarioScopeState.requestId.equals(requestID)) { + scenarioScopeState.callbackBody = request.getRequest().getBodyAsString(); + } + + } + } + + try { + // ObjectMapper objectMapper = new ObjectMapper(); + JsonNode rootNode = objectMapper.readTree(scenarioScopeState.callbackBody); + + JsonNode voucherInstructionsNode = rootNode.get("voucherInstructions"); + if (voucherInstructionsNode.isArray()) { + for (JsonNode voucherNode : voucherInstructionsNode) { + scenarioScopeState.serialNumber = voucherNode.get("serialNumber").asText(); + scenarioScopeState.voucherNumber = voucherNode.get("voucherNumber").asText(); + } + } + } catch (Exception e) { + logger.debug(e.getMessage()); + } + assertThat(scenarioScopeState.serialNumber).isNotEmpty(); + }); + } + + @Then("I add voucher serial number and voucher number in csv file") + public void addVoucherSerialNumberandVoucherNumberInCSV(String file) { + createOrAppendCSVFile(file, new String[] { "voucherNumber", "serialNumber" }, + new String[] { scenarioScopeState.voucherNumber, scenarioScopeState.serialNumber }); + } + + public void createOrAppendCSVFile(String filePath, String[] header, String[] data) { + File file = new File(filePath); + + try (CSVWriter writer = new CSVWriter(new FileWriter(file, true))) { + // If the file doesn't exist, write the header + if (!file.exists() || file.length() == 0) { + writer.writeNext(header); + } + + // Write data + writer.writeNext(data); + } catch (IOException e) { + logger.debug("Error: {}", e.getMessage()); + } + } + + @Then("I call the create, Activate voucher API and store it in {string}") + public void createActivateVoucherInBulkAndCreateCSVFile(String file) { + logger.info("Creating and activating {} vouchers", totalVouchers); + for (int i = 0; i < totalVouchers; i++) { + iCreateAnIdentityMapperDTOForRegisterBeneficiary(); + iCallTheVoucherCreateAPIWithExpectedStatusOf(202, "/createVoucher"); + try { + Thread.sleep(2000); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + iShouldBeAbleToExtractResponseBodyFromCallback(); + addVoucherSerialNumberandVoucherNumberInCSV(file); + iCanCreateAnVoucherRequestDTOForVoucherActivation(); + iCallTheActivateVoucherAPIWithExpectedStatusOfAndStub(202, "/activateVoucher"); + } + } + + @Given("I can create an RedeemVoucherRequestDTO for voucher redemption") + public void iCanCreateAnRedeemVoucherRequestDTOForVoucherRedemption() { + await().atMost(awaitMost, SECONDS).pollDelay(pollDelay, SECONDS).pollInterval(pollInterval, SECONDS).untilAsserted(() -> { + scenarioScopeState.agentId = generateUniqueNumber(10); + + RedeemVoucherRequestDTO requestDTO = new RedeemVoucherRequestDTO(scenarioScopeState.requestId, scenarioScopeState.agentId, + scenarioScopeState.serialNumber, scenarioScopeState.voucherNumber); + + ObjectMapper objectMapper = new ObjectMapper(); + try { + scenarioScopeState.redeemVoucherBody = objectMapper.writeValueAsString(requestDTO); + assertThat(scenarioScopeState.redeemVoucherBody).isNotNull(); + } catch (JsonProcessingException e) { + logger.error("Unable to convert the DTO : {}", e); + } + }); + } + + @When("I call the redeem voucher API with expected status of {int}") + public void iCallTheRedeemVoucherAPIWithExpectedStatusOf(int responseCode) { + RequestSpecification requestSpec = Utils.getDefaultSpec(); + scenarioScopeState.response = RestAssured.given(requestSpec).header("Content-Type", "application/json") + .queryParam("command", "redeem").header("X-Registering-Institution-ID", scenarioScopeState.registeringInstitutionId) + .header("X-CallbackURL", "").header("X-Program-ID", "123").baseUri(voucherManagementConfig.voucherManagementContactPoint) + .body(scenarioScopeState.redeemVoucherBody).expect().spec(new ResponseSpecBuilder().expectStatusCode(responseCode).build()) + .when().post(voucherManagementConfig.voucherLifecycleEndpoint).andReturn().asString(); + + scenarioScopeState.redeemVoucherResponseBody = scenarioScopeState.response; + logger.info("Redeem Voucher Response: {}", scenarioScopeState.response); + } + + @Then("I can assert that redemption was successful by asserting the status in response") + public void iCanAssertThatRedemptionWasSuccessfulByAssertingTheStatusInResponse() { + await().atMost(awaitMost, SECONDS).pollDelay(pollDelay, SECONDS).pollInterval(pollInterval, SECONDS).untilAsserted(() -> { + + try { + JsonNode rootNode = objectMapper.readTree(scenarioScopeState.redeemVoucherResponseBody); + + String status = rootNode.get("status").asText(); + logger.info("Status {}", status); + assertThat(status).isEqualTo("01"); + logger.info("Response for successful redemption {}:", scenarioScopeState.redeemVoucherResponseBody); + } catch (Exception e) { + logger.debug(e.getMessage()); + } + + }); + } + + public void assertUnsuccessfulRedemption() { + try { + JsonNode rootNode = objectMapper.readTree(scenarioScopeState.redeemVoucherResponseBody); + + String status = rootNode.get("status").asText(); + assertThat(status).isEqualTo("00"); + } catch (Exception e) { + logger.debug(e.getMessage()); + } + } + + @Before("@createAndActivateVoucher") + public void createAndActivateVoucherUsingAnnotation() { + createAndActivateVoucher(); + } + + @Given("I can create and activate a voucher") + public void createAndActivateVoucher() { + iCreateAnIdentityMapperDTOForRegisterBeneficiary(); + mockServerStepDef.checkIfMockServerIsInjected(); + mockServerStepDef.startMockServer(); + mockServerStepDef.startStub("/createVoucher", PUT, 200); + mockServerStepDef.startStub("/activateVoucher", PUT, 200); + iCallTheVoucherCreateAPIWithExpectedStatusOf(202, "/createVoucher"); + iShouldBeAbleToExtractResponseBodyFromCallback(); + iCanCreateAnVoucherRequestDTOForVoucherActivation(); + iCallTheActivateVoucherAPIWithExpectedStatusOfAndStub(202, "/activateVoucher"); + } + + @Before("@createVoucher") + public void createVoucherUsingAnnotation() { + createVoucher(); + } + + @Given("I can create a voucher") + public void createVoucher() { + iCreateAnIdentityMapperDTOForRegisterBeneficiary(); + mockServerStepDef.checkIfMockServerIsInjected(); + mockServerStepDef.startMockServer(); + mockServerStepDef.startStub("/createVoucher", PUT, 200); + mockServerStepDef.startStub("/activateVoucher", PUT, 200); + iCallTheVoucherCreateAPIWithExpectedStatusOf(202, "/createVoucher"); + iShouldBeAbleToExtractResponseBodyFromCallback(); + } + + @After("@redeemVoucherFailure") + public void redeemVoucherFailureUsingAnnotation() { + redeemVoucherFailure(); + } + + @Then("I check for redeem voucher failure") + public void redeemVoucherFailure() { + iCanCreateAnRedeemVoucherRequestDTOForVoucherRedemption(); + iCallTheRedeemVoucherAPIWithExpectedStatusOf(200); + assertUnsuccessfulRedemption(); + } + + @After("@redeemVoucherSuccess") + public void redeemVoucherSuccessUsingAnnotation() { + redeemVoucherSuccess(); + } + + @Then("I check for redeem voucher success") + public void redeemVoucherSuccess() { + iCanCreateAnRedeemVoucherRequestDTOForVoucherRedemption(); + iCallTheRedeemVoucherAPIWithExpectedStatusOf(200); + iCanAssertThatRedemptionWasSuccessfulByAssertingTheStatusInResponse(); + } + + @Given("I can create an VoucherRequestDTO for voucher suspension") + public void iCanCreateAnVoucherRequestDTOForVoucherSuspension() { + VoucherInstruction voucherInstruction = new VoucherInstruction(); + voucherInstruction.setSerialNumber(scenarioScopeState.serialNumber); + voucherInstruction.setStatus("06"); + + ArrayList voucherInstructions = new ArrayList<>(); + voucherInstructions.add(voucherInstruction); + + RequestDTO requestDTO = new RequestDTO(scenarioScopeState.requestId, scenarioScopeState.batchId, voucherInstructions); + ObjectMapper objectMapper = new ObjectMapper(); + try { + scenarioScopeState.suspendVoucherBody = objectMapper.writeValueAsString(requestDTO); + } catch (JsonProcessingException e) { + logger.error("Unable to convert the DTO : {}", e); + } + } + + @When("I call the suspend voucher API with expected status of {int} and stub {string}") + public void iCallTheSuspendVoucherAPIWithExpectedStatusOfAndStub(int responseCode, String stub) { + RequestSpecification requestSpec = Utils.getDefaultSpec(); + scenarioScopeState.response = RestAssured.given(requestSpec).header("Content-Type", "application/json") + .queryParam("command", "suspend").header("X-Registering-Institution-ID", scenarioScopeState.registeringInstitutionId) + .header("X-CallbackURL", identityMapperConfig.callbackURL + stub).header("X-Program-ID", "123") + .baseUri(voucherManagementConfig.voucherManagementContactPoint).body(scenarioScopeState.suspendVoucherBody).expect() + .spec(new ResponseSpecBuilder().expectStatusCode(responseCode).build()).when() + .put(voucherManagementConfig.voucherLifecycleEndpoint).andReturn().asString(); + + scenarioScopeState.redeemVoucherResponseBody = scenarioScopeState.response; + logger.info("Suspend Voucher Response: {}", scenarioScopeState.response); + } + + @And("I can create an VoucherRequestDTO for voucher reactivation") + public void iCanCreateAnVoucherRequestDTOForVoucherReactivation() { + StringBuilder sb = new StringBuilder(); + sb.append("{\n"); + sb.append(" \"requestID\": \"").append(scenarioScopeState.requestId).append("\",\n"); + sb.append(" \"batchID\": \"").append(scenarioScopeState.batchId).append("\",\n"); // Replaced "045155518258" + // with batchId + // variable + sb.append(" \"voucherInstructions\": [\n"); + sb.append(" {\n"); + sb.append(" \"serialNumber\": \"").append(scenarioScopeState.serialNumber).append("\",\n"); + sb.append(" \"status\": \"02\"\n"); + sb.append(" }\n"); + sb.append(" ]\n"); + sb.append("}"); + + scenarioScopeState.suspendVoucherBody = sb.toString(); + } + + @When("I call the validity check API with expected status of {int} and stub {string}") + public void iCallTheValidityCheckAPIWithExpectedStatusOfAndStub(int responseCode, String stub) { + await().atMost(awaitMost, SECONDS).pollDelay(pollDelay, SECONDS).pollInterval(pollInterval, SECONDS).untilAsserted(() -> { + RequestSpecification requestSpec = Utils.getDefaultSpec(); + scenarioScopeState.response = RestAssured.given(requestSpec).header("Content-Type", "application/json") + .queryParam("serialNumber", scenarioScopeState.serialNumber).queryParam("isValid", "true") + .header("X-CallbackURL", identityMapperConfig.callbackURL + stub) + .header("X-Registering-Institution-ID", scenarioScopeState.registeringInstitutionId) + .baseUri(voucherManagementConfig.voucherManagementContactPoint).expect() + .spec(new ResponseSpecBuilder().expectStatusCode(responseCode).build()).when() + .get(voucherManagementConfig.voucherValidityEndpoint).andReturn().asString(); + + scenarioScopeState.redeemVoucherResponseBody = scenarioScopeState.response; + logger.info("Validity Voucher Response: {}", scenarioScopeState.response); + }); + } + + @And("I can extract result from validation callback and assert if validation is successful on {string}") + public void iCanExtractResultFromValidationCallbackAndAssertIfValidationIsSuccessful(String endpoint) { + await().atMost(awaitMost, SECONDS).pollDelay(pollDelay, SECONDS).pollInterval(pollInterval, SECONDS).untilAsserted(() -> { + + // (putRequestedFor(urlEqualTo(endpoint)).withRequestBody(matchingJsonPath("$.isValid", equalTo("true")))); + List allServeEvents = getAllServeEvents(); + String serialNo = null; + String isValid = null; + for (int i = 0; i < allServeEvents.size(); i++) { + ServeEvent request = allServeEvents.get(i); + + if (!(request.getRequest().getBodyAsString()).isEmpty()) { + JsonNode rootNode = null; + try { + rootNode = objectMapper.readTree(request.getRequest().getBodyAsString()); + } catch (JsonProcessingException e) { + throw new RuntimeException(e); + } + + if (rootNode.has("serialNumber")) { + serialNo = rootNode.get("serialNumber").asText(); + isValid = rootNode.get("isValid").asText(); + } + } + } + assertThat(isValid).isEqualTo("true"); + }); + } + + @Then("I can assert that redemption was unsuccessful by asserting the status in response") + public void iCanAssertThatRedemptionWasUnsuccessfulByAssertingTheStatusInResponse() { + try { + JsonNode rootNode = objectMapper.readTree(scenarioScopeState.redeemVoucherResponseBody); + + String status = rootNode.get("status").asText(); + assertThat(status).isEqualTo("00"); + } catch (Exception e) { + logger.debug(e.getMessage()); + } + } + + @Then("I should be able to assert response body from callback on {string}") + public void iShouldBeAbleToAssertResponseBodyFromCallback(String endpoint) { + await().atMost(awaitMost, SECONDS).untilAsserted(() -> { + try { + verify(putRequestedFor(urlEqualTo(endpoint)) + .withRequestBody(matchingJsonPath("$.registerRequestID", equalTo(scenarioScopeState.requestId)))); + verify(putRequestedFor(urlEqualTo(endpoint)).withRequestBody(matchingJsonPath("$.numberFailedCases", equalTo("0")))); + assertTrue(true);// success + } catch (VerificationException e) { + assertTrue(false);// failure + } + }); + } + + @Then("I will call the fetch voucher API with expected status of {int}") + public void iWillCallTheFetchVoucherAPIWithExpectedStatusOf(int responseCode) { + await().atMost(awaitMost, SECONDS).pollDelay(pollDelay, SECONDS).pollInterval(pollInterval, SECONDS).untilAsserted(() -> { + RequestSpecification requestSpec = Utils.getDefaultSpec(); + scenarioScopeState.response = RestAssured.given(requestSpec).header("Content-Type", "application/json") + .header("X-Registering-Institution-ID", scenarioScopeState.registeringInstitutionId) + .baseUri(voucherManagementConfig.voucherManagementContactPoint).expect() + .spec(new ResponseSpecBuilder().expectStatusCode(responseCode).build()).when() + .get(voucherManagementConfig.fetchVoucherEndpoint + "/" + scenarioScopeState.serialNumber).andReturn().asString(); + + scenarioScopeState.fetchVoucherResponseBody = scenarioScopeState.response; + logger.info("Voucher Response: {}", scenarioScopeState.response); + }); + } + + @And("I will assert the fields from fetch voucher response") + public void iWillAssertTheFieldsFromFetchVoucherResponse() { + try { + JsonNode rootNode = objectMapper.readTree(scenarioScopeState.fetchVoucherResponseBody); + + String serialNumberResponse = rootNode.get("serialNumber").asText(); + String registeringInstitutionIdResponse = rootNode.get("registeringInstitutionId").asText(); + assertThat(serialNumberResponse).isEqualTo(scenarioScopeState.serialNumber); + assertThat(registeringInstitutionIdResponse).isEqualTo(scenarioScopeState.registeringInstitutionId); + + } catch (Exception e) { + logger.debug(e.getMessage()); + } + } + + @Given("I can create an negative VoucherRequestDTO for voucher creation") + public void createNegativeVoucherRequestDTO() { + scenarioScopeState.requestId = generateUniqueNumber(18); + + RequestDTO requestDTO = new RequestDTO(); + requestDTO.setRequestID(scenarioScopeState.requestId); + requestDTO.setBatchID(generateUniqueNumber(10)); + + VoucherInstruction voucherInstruction = new VoucherInstruction(); + voucherInstruction.setInstructionID(generateUniqueNumber(16)); + voucherInstruction.setGroupCode("0215"); + voucherInstruction.setCurrency("SGDP"); + voucherInstruction.setAmount(BigDecimal.valueOf(-9000)); + voucherInstruction.setPayeeFunctionalID("6331059032228893278594709682"); + voucherInstruction.setNarration("Social Support Payment for the Month of Jan"); + + ArrayList voucherInstructions = new ArrayList<>(); + voucherInstructions.add(voucherInstruction); + requestDTO.setVoucherInstructions(voucherInstructions); + + ObjectMapper objectMapper = new ObjectMapper(); + try { + scenarioScopeState.createVoucherBody = objectMapper.writeValueAsString(requestDTO); + } catch (JsonProcessingException e) { + logger.error("Unable to convert the DTO : {}", e); + } + + } + + @And("I should be able to assert the create voucher validation for negative response") + public void iWillAssertTheFieldsFromCreateVoucherValidationResponse() { + try { + JsonNode rootNode = objectMapper.readTree(scenarioScopeState.response); + + ErrorDetails errorDetails = objectMapper.treeToValue(rootNode, ErrorDetails.class); + + assertThat(errorDetails.getErrorCode()).isEqualTo("error.msg.schema.validation.errors"); + assertThat(errorDetails.getErrorDescription()).isEqualTo("The request is invalid"); + + } catch (Exception e) { + logger.info("An error occurred : {}", e); + } + } + + @Given("I can create an negative RedeemVoucherRequestDTO to redeem a voucher") + public void createNegativeRedeemVoucherRequestDTO() { + RedeemVoucherRequestDTO requestDTO = new RedeemVoucherRequestDTO(); + requestDTO.setRequestId(generateUniqueNumber(18)); + requestDTO.setAgentId(generateUniqueNumber(15)); + requestDTO.setVoucherSecretNumber(generateUniqueNumber(10)); + + ObjectMapper objectMapper = new ObjectMapper(); + try { + scenarioScopeState.redeemVoucherBody = objectMapper.writeValueAsString(requestDTO); + } catch (JsonProcessingException e) { + logger.error("Unable to convert the DTO : {}", e); + } + } + + @Then("I will add the required headers") + public void makeNecessaryHeadersNonNull() { + scenarioScopeState.registeringInstitutionId = generateUniqueNumber(3); + } + + @And("I should be able to assert the redeem voucher validation for negative response") + public void iWillAssertTheFieldsFromRedeemVoucherValidationResponse() { + try { + JsonNode rootNode = objectMapper.readTree(scenarioScopeState.response); + + ErrorDetails errorDetails = objectMapper.treeToValue(rootNode, ErrorDetails.class); + + assertThat(errorDetails.getErrorCode()).isEqualTo("error.msg.redeem.voucher.validation.errors"); + assertThat(errorDetails.getErrorDescription()).isEqualTo("Redeem voucher validation failed"); + + } catch (Exception e) { + logger.info("An error occurred : {}", e); + } + } + + @Given("I can create an VoucherRequestDTO for voucher creation with unsupported parameter parameter") + public void iCreateAnIdentityMapperDTOForRegisterBeneficiaryWithUnsupportedParameter() { + iCreateAnIdentityMapperDTOForRegisterBeneficiary(); + scenarioScopeState.createVoucherBody = addUnsupportedParamsInRequestBody(scenarioScopeState.createVoucherBody); + } + + @And("I add unsupported parameter in my request body {string}") + public String addUnsupportedParamsInRequestBody(String requestBody) { + ObjectMapper objectMapper = new ObjectMapper(); + + try { + // Convert JSON string to JsonNode + JsonNode jsonNode = objectMapper.readTree(requestBody); + + // Add new key-value pair + ((ObjectNode) jsonNode).put("abcd", "12345"); + ((ObjectNode) jsonNode).put("efgh", "6789"); + + // Convert JsonNode back to JSON string + requestBody = objectMapper.writeValueAsString(jsonNode); + + } catch (Exception e) { + logger.info("An error occurred : {}", e); + } + + return requestBody; + } + + @And("I can call the voucher status API with expected status of {int} until I get the status as {string}") + public void iCanCallTheVoucherStatusAPIWithExpectedStatusOfUntilIGetTheStatusAs(int expectedStatus, String status) { + await().atMost(awaitMost, SECONDS).pollDelay(pollDelay, SECONDS).pollInterval(pollInterval, SECONDS).untilAsserted(() -> { + com.fasterxml.jackson.databind.ObjectMapper objectMapper = new com.fasterxml.jackson.databind.ObjectMapper(); + String endpoint = voucherManagementConfig.voucherStatus; + RequestSpecification requestSpec = Utils.getDefaultSpec(); + // requestSpec.queryParam("fields", "status"); + endpoint = String.format(endpoint.replace("{{serialNumber}}", "%s"), scenarioScopeState.serialNumber); + scenarioScopeState.response = RestAssured.given(requestSpec).header("Content-Type", "application/json") + .header("X-Registering-Institution-ID", scenarioScopeState.registeringInstitutionId) + .baseUri(voucherManagementConfig.voucherManagementContactPoint).expect() + .spec(new ResponseSpecBuilder().expectStatusCode(expectedStatus).build()).when().get(endpoint).andReturn().asString(); + + logger.info("Status Response: {}", scenarioScopeState.response); + assertThat(scenarioScopeState.response.contains(status)).isTrue(); + }); + } +} diff --git a/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/util/Util.java b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/util/Util.java new file mode 100644 index 000000000..f1507e39e --- /dev/null +++ b/ph-ee-integration-test/src/test/java/org/mifos/integrationtest/util/Util.java @@ -0,0 +1,12 @@ +package org.mifos.integrationtest.util; + +public final class Util { + + private Util() { + throw new UnsupportedOperationException("Utility class"); + } + + public static String getFormattedEndpoint(String formattedTemplate, String tobeReplaced, String replacedWith) { + return formattedTemplate.replace(tobeReplaced, replacedWith); + } +} diff --git a/ph-ee-integration-test/src/test/java/resources/account.feature b/ph-ee-integration-test/src/test/java/resources/account.feature new file mode 100644 index 000000000..251b425c5 --- /dev/null +++ b/ph-ee-integration-test/src/test/java/resources/account.feature @@ -0,0 +1,37 @@ +Feature: Account Status and Account Name Check api + + @common @amsIntegration + Scenario: Savings account Status Test + Given I have Fineract-Platform-TenantId as "payerfsp1" + When I create a set of debit and credit party + When I call the create payer client endpoint + Then I call the create savings product endpoint + When I call the create savings account endpoint + Then I call the debit interop identifier endpoint with MSISDN + Given I have tenant as "payerfsp" + Then I call the account status api + And I can assert "submitted" status in response + Then I approve the deposit with command "approve" + Given I have tenant as "payerfsp" + Then I call the account status api + And I can assert "approved" status in response + When I activate the account with command "activate" + Then I call the deposit account endpoint with command "deposit" for amount 11 + Given I have tenant as "payerfsp" + Then I call the account status api + And I can assert "active" status in response + + @common @amsIntegration + Scenario: Savings account Name Test + Given I have Fineract-Platform-TenantId as "payerfsp1" + When I create a set of debit and credit party + When I call the create payer client endpoint + Then I call the create savings product endpoint + When I call the create savings account endpoint + Then I call the debit interop identifier endpoint with MSISDN + Then I approve the deposit with command "approve" + When I activate the account with command "activate" + Then I call the deposit account endpoint with command "deposit" for amount 100 + Given I have tenant as "payerfsp" + Then I call the account name api + Then I can assert name in response \ No newline at end of file diff --git a/ph-ee-integration-test/src/test/java/resources/authentication.feature b/ph-ee-integration-test/src/test/java/resources/authentication.feature new file mode 100644 index 000000000..31144749e --- /dev/null +++ b/ph-ee-integration-test/src/test/java/resources/authentication.feature @@ -0,0 +1,23 @@ +@gov @ext +Feature: Authentication test for services routed through kong & keycloak + + @keycloak-user-setup @keycloak-user-teardown @kong-teardown + Scenario: Unauthorized channel-connector test + Given I have tenant as "paymentBB2" + And I can mock TransactionChannelRequestDTO + And I register channel service using config + And I register channel route using config + And I enable oidc plugin + When I call the inbound transfer endpoint with expected status of 401 and no authentication + Then I should get non empty response + + @keycloak-user-setup @keycloak-user-teardown @kong-teardown + Scenario: Authorized channel-connector test + Given I have tenant as "paymentBB2" + And I can mock TransactionChannelRequestDTO + And I register channel service using config + And I register channel route using config + And I enable oidc plugin + When I authenticate with new keycloak user + And I call the inbound transfer endpoint with authentication + Then I should get non empty response diff --git a/ph-ee-integration-test/src/test/java/resources/batch.feature b/ph-ee-integration-test/src/test/java/resources/batch.feature new file mode 100644 index 000000000..807ceb73d --- /dev/null +++ b/ph-ee-integration-test/src/test/java/resources/batch.feature @@ -0,0 +1,334 @@ +Feature: Batch Details API test + + @commonExtended @gov @batch-teardown + Scenario: BD-001 Batch transactions API Test + Given I have the demo csv file "ph-ee-bulk-demo-6.csv" + And I have tenant as "paymentBB2" + And I have the demo csv file "ph-ee-bulk-demo-6.csv" + And I generate clientCorrelationId + And I have private key + And I generate signature + When I call the batch transactions endpoint with expected status of 202 + Then I should get non empty response + + @commonExtended @gov @batch-teardown + Scenario: BD-002 Batch transactions API Test with polling callback url + Given I have the demo csv file "ph-ee-bulk-demo-6.csv" + And I have tenant as "paymentBB2" + And I generate clientCorrelationId + And I have private key + And I generate signature + When I call the batch transactions endpoint with expected status of 202 + Then I should get non empty response + And I should have "PollingPath" and "SuggestedCallbackSeconds" in response + + @commonExtended @gov @batch-teardown + Scenario: BD-003 Batch summary API Test + Given I have a batch id from previous scenario + And I have tenant as "paymentBB2" + And I have the demo csv file "ph-ee-bulk-demo-6.csv" + And I generate clientCorrelationId + And I have private key + And I generate signature + When I call the batch transactions endpoint with expected status of 202 + Then I should get non empty response + And I am able to parse batch transactions response + And I fetch batch ID from batch transaction API's response +# Then I will sleep for 5000 millisecond + When I call the operations-app auth endpoint with username: "mifos" and password: "password" + Then I should get a valid token + When I call the batch summary API with expected status of 200 with total 10 txns + Then I should get non empty response + + @commonExtended @gov @batch-teardown + Scenario: BD-004 Batch Details API Test + Given I have a batch id from previous scenario + And I have tenant as "paymentBB2" + And I have the demo csv file "ph-ee-bulk-demo-6.csv" + And I generate clientCorrelationId + And I have private key + And I generate signature + When I call the batch transactions endpoint with expected status of 202 + Then I should get non empty response + And I am able to parse batch transactions response + And I fetch batch ID from batch transaction API's response + When I call the operations-app auth endpoint with username: "mifos" and password: "password" + Then I should get a valid token + When I call the batch details API with expected status of 200 with total 10 txns + Then I should get non empty response + + + @commonExtended @gov @batch-teardown + Scenario: BD-005 Batch transaction API Test for Synchronous File Validation with empty file + Given I have tenant as "paymentBB2" + And I make sure there is no file + And I generate clientCorrelationId + And I have private key + And I generate signature + When I call the batch transactions endpoint with expected status of 400 without payload + Then I should get non empty response + And I should have "errorInformation" and "File not uploaded" in response + + @commonExtended @gov @batch-teardown + Scenario: BD-006 Batch transaction API Test for Synchronous File Validation with invalid file + Given I have tenant as "paymentBB2" + And I have the demo csv file "ph-ee-bulk-demoErrorSync-6.csv" + And I generate clientCorrelationId + And I have private key + And I generate signature + When I call the batch transactions endpoint with expected status of 400 + Then I should get non empty response + And I should have "Error Information" and "Invalid file structure" in response + + @commonExtended @gov @batch-teardown + Scenario: BD-007 Batch transaction API Test for Asynchronous File Validation + Given I have tenant as "paymentBB2" + And I have the demo csv file "ph-ee-bulk-demoErrorAsync-6.csv" + And I generate clientCorrelationId + And I have private key + And I generate signature + When I call the batch transactions endpoint with expected status of 202 + Then I should get non empty response + And I am able to parse batch transactions response + And I fetch batch ID from batch transaction API's response +# Then I will sleep for 8000 millisecond + And I have tenant as "paymentBB2" + When I call the operations-app auth endpoint with username: "mifos" and password: "password" + Then I should get a valid token + When I call the batch summary API with expected status of 200 with total 5 txns + Then I should get non empty response + + @commonExtended @gov @batch-teardown + Scenario: BD-008 Batch Phased Callback API Test Success + Given I have a batch id from previous scenario + And I have tenant as "paymentBB2" + And I have callbackUrl as simulated url + And I have the demo csv file "ph-ee-bulk-demo-6.csv" + And I generate clientCorrelationId + And I have private key + And I generate signature + When I call the batch transactions endpoint with expected status of 202 + Then I should get non empty response + And I have retry count as 2 + When I should call callbackUrl api + Then I should get expected status of 200 + + @govtodo @batch-teardown + Scenario: BD-009 Batch Phased Callback API Test Failure + Given I have a batch id from previous scenario + And I have tenant as "paymentBB2" + And I have the demo csv file "ph-ee-bulk-demo-6.csv" + And I generate clientCorrelationId + And I have private key + And I generate signature + And I have callbackUrl as "http://httpstat.us/503" + When I call the batch transactions endpoint with expected status of 202 + Then I should get non empty response + Given I have retry count as 2 + When I should call callbackUrl api + Then I should get expected status of 503 + + @commonExtended @gov @batch-teardown + Scenario: BD-010 Batch summary with failure percent API Test + Given I have a batch id from previous scenario + And I have tenant as "paymentBB2" + And I have the demo csv file "ph-ee-bulk-demo-6.csv" + And I generate clientCorrelationId + And I have private key + And I generate signature + When I call the batch transactions endpoint with expected status of 202 + Then I should get non empty response + And I am able to parse batch transactions response + And I fetch batch ID from batch transaction API's response + When I call the operations-app auth endpoint with username: "mifos" and password: "password" + Then I should get a valid token + When I call the batch details API with expected status of 200 with total 10 txns + Then I should get non empty response with failure and success percentage + + @gov @batch-teardown + Scenario: BD-011 Batch test for payerIdentifier resolution using budgetAccount info + Given I have tenant as "paymentBB2" + And I have the demo csv file "payerIdentifier-resolution-using-budgetAccount.csv" + And I have the registeringInstituteId "SocialWelfare" + And I have the programId "Education" + And I generate clientCorrelationId + And I have private key + And I generate signature + When I call the batch transactions endpoint with expected status of 202 + And I am able to parse batch transactions response + And I fetch batch ID from batch transaction API's response +# Then I will sleep for 15000 millisecond + When I call the batch summary API with expected status of 200 with total 10 txns + Then I am able to parse batch summary response + And Status of transaction is "COMPLETED" + + @commonExtended @gov @batch-teardown + Scenario: BD-012 Batch Transaction REST Api test + Given I have tenant as "paymentBB2" + And I create a new clientCorrelationId + And I can mock the Batch Transaction Request DTO without payer info + And I have private key + And I generate signature + When I call the batch transactions raw endpoint with expected status of 202 + And I am able to parse batch transactions response + And I fetch batch ID from batch transaction API's response +# Then I will sleep for 10000 millisecond + When I call the batch summary API with expected status of 200 with total 1 txns + Then I am able to parse batch summary response + And Status of transaction is "COMPLETED" + And I should have matching total txn count and successful txn count in response + + @commonExtended @gov @batch-teardown + Scenario: BD-013,BT-001 Batch aggregate API Test + Given I have tenant as "paymentBB2" + And I have the demo csv file "ph-ee-bulk-demo-7.csv" + And I create a new clientCorrelationId + And I have private key + And I generate signature + When I call the batch transactions endpoint with expected status of 202 + Then I should get non empty response + And I am able to parse batch transactions response + And I fetch batch ID from batch transaction API's response +# Then I will sleep for 10000 millisecond + When I call the batch aggregate API with expected status of 200 with total 3 txns + Then I should get non empty response + Then I am able to parse batch summary response + And Status of transaction is "COMPLETED" + And I should have matching total txn count and successful txn count in response + + @commonExtended @gov @ext @batch-teardown + Scenario: BD-014 Sub Batch summary API Test + Given I have tenant as "paymentBB2" + And I have the demo csv file "ph-ee-bulk-demo-7.csv" + And I create a new clientCorrelationId + And I have private key + And I generate signature + When I call the batch transactions endpoint with expected status of 202 + Then I should get non empty response + And I am able to parse batch transactions response + And I fetch batch ID from batch transaction API's response +# Then I will sleep for 10000 millisecond + And I call the sub batch summary API for sub batch summary with expected status of 200 and total count 3 + Then I am able to parse sub batch summary response + And I should assert total txn count and successful txn count in response + + @commonExtended @gov @batch-teardown + Scenario: BD-015 Batch splitting test + Given I have tenant as "paymentBB2" + And I have the demo csv file "ph-ee-bulk-splitting.csv" + And I create a new clientCorrelationId + And I have private key + And I generate signature + When I call the batch transactions endpoint with expected status of 202 + Then I should get non empty response + And I am able to parse batch transactions response + And I fetch batch ID from batch transaction API's response +# Then I will sleep for 10000 millisecond + When I call the batch summary API with expected status of 200 with total 12 txns + Then I am able to parse batch summary response + And Status of transaction is "COMPLETED" + And I should have matching total txn count and successful txn count in response + And I call the sub batch summary API for sub batch summary with expected status of 200 and total count 12 + Then I am able to parse sub batch summary response + And I should assert total txn count and successful txn count in response + And Total transaction in batch should add up to total transaction in each sub batch + + @commonExtended @gov @ext + Scenario: BD-016 Payment Batch Detail API Test + Given I have tenant as "paymentBB2" + And I have the demo csv file "ph-ee-bulk-splitting.csv" + And I create a new clientCorrelationId + And I have private key + And I generate signature + When I call the batch transactions endpoint with expected status of 202 + Then I should get non empty response + And I am able to parse batch transactions response + And I fetch batch ID from batch transaction API's response +# Then I will sleep for 10000 millisecond + And I call the payment batch detail API with expected status of 200 with total 12 txns + Then I am able to parse payment batch detail response + And I should assert total txn count and successful txn count in payment batch detail response + + @commonExtended @gov @batch-teardown + Scenario: BD-017 Batch test for de-duplicating payments + Given I have the demo csv file "deduplication-test.csv" + And I have tenant as "paymentBB2" + And I create a new clientCorrelationId + And I have private key + And I generate signature + When I call the batch transactions endpoint with expected status of 202 + And I am able to parse batch transactions response + And I fetch batch ID from batch transaction API's response +# Then I will sleep for 10000 millisecond + And I call the batch details API with expected status of 200 with total 3 txns + Then I should get transactions with note set as "Duplicate transaction" + And All the duplicate transaction should have status as Failed + + @commonExtended @gov + Scenario: BA-001 Batch Authorization API test + Given I will start the mock server + And I can register the stub with "/authorization/callback" endpoint for "POST" request with status of 200 + Then I will update the mock server and register stub as done + When I create an AuthorizationRequest for Batch Authorization with batch ID as "1234", payerIdentifier as "5678", currency as "USD" and amount as "30" + And I call the Authorization API with batchId as "1234" and expected status of 202 and stub "/authorization/callback" +# And I will sleep for 5000 millisecond + Then I should be able to verify that the "POST" method to "/authorization/callback" endpoint received a request with authorization status + + @commonExtended @gov @ext + Scenario: BD-018 Batch with callback + Given I can inject MockServer + And I can start mock server + And I can register the stub with "/callback" endpoint for "POST" request with status of 200 + Then I will update the mock server and register stub as done + Given I have tenant as "paymentBB2" + And I have the demo csv file "ph-ee-bulk-demo-7.csv" + And I create a new clientCorrelationId + And I have private key + And I generate signature + When I call the batch transactions endpoint with expected status of 202 and callbackurl as "/callback" + And I am able to parse batch transactions response + And I fetch batch ID from batch transaction API's response +# Then I will sleep for 5000 millisecond + When I call the batch summary API with expected status of 200 with total 3 txns +# And I will sleep for 15000 millisecond + Then I should be able to extract response body from callback for batch + When I make the "POST" request to "/callback" endpoint with expected status of 200 + Then I should be able to extract response body from callback for batch + And I can stop mock server + @commonExtended @gov @batch-teardown + Scenario: BD-019 Batch summary response result file URL Test + Given I have the demo csv file "ph-ee-bulk-demo-6.csv" + And I have tenant as "paymentBB2" + And I generate clientCorrelationId + And I have private key + And I generate signature + When I call the batch transactions endpoint with expected status of 202 + Then I should get non empty response + And I am able to parse batch transactions response + And I fetch batch ID from batch transaction API's response + When I call the operations-app auth endpoint with username: "mifos" and password: "password" + Then I should get a valid token + And I call the sub batch summary API for result file url with expected status of 200 + Then I am able to parse sub batch summary response + Then I check for result file URL validity + + @gov + Scenario: APT-001 actuator API test + When I call the actuator API with Contactpoint "mock-payment-schema.contactpoint" and endpoint "/actuator/health" + Then I am able to parse actuator response + And Status of service is "UP" + When I call the actuator API with Contactpoint "operations-app.contactpoint" and endpoint "/actuator/health" + Then I am able to parse actuator response + And Status of service is "UP" + When I call the actuator API with Contactpoint "bulk-processor.contactpoint" and endpoint "/actuator/health" + Then I am able to parse actuator response + And Status of service is "UP" + When I call the actuator API with Contactpoint "ml-connector.contactpoint" and endpoint "/actuator/health" + Then I am able to parse actuator response + And Status of service is "UP" + When I call the actuator API with Contactpoint "identity-account-mapper.contactpoint" and endpoint "/actuator/health" + Then I am able to parse actuator response + And Status of service is "UP" + When I call the actuator API with Contactpoint "voucher-management.contactpoint" and endpoint "/actuator/health" + Then I am able to parse actuator response + And Status of service is "UP" diff --git a/ph-ee-integration-test/src/test/java/resources/batch_demo_csv/batchTransactioClosedLoopMojaloopFundTransfer.csv b/ph-ee-integration-test/src/test/java/resources/batch_demo_csv/batchTransactioClosedLoopMojaloopFundTransfer.csv new file mode 100644 index 000000000..186f4b564 --- /dev/null +++ b/ph-ee-integration-test/src/test/java/resources/batch_demo_csv/batchTransactioClosedLoopMojaloopFundTransfer.csv @@ -0,0 +1,9 @@ +id,request_id,payment_mode,payer_identifier_type,payer_identifier,payee_identifier_type,payee_identifier,amount,currency,note +0,dbe1d284-1bea-4f03-bc0f-8faece9f5da2,closedloop,msisdn,2300,msisdn,1759,10,USD,Test Payee Payment +1,696a9340-adc2-48e3-a1d1-10a239bc412b,closedloop,msisdn,2301,msisdn,1760,5,USD,Test Payee Payment +2,8e2eaf78-4566-438e-9183-ec02288fd16b,closedloop,msisdn,2302,msisdn,1761,5,USD,Test Payee Payment +3,b9bc0bc8-cf25-417a-adbc-97345330737a,closedloop,msisdn,2303,msisdn,1762,5,USD,Test Payee Payment +4,a59acbe1-4ebb-4618-bda3-630f2c306e09,closedloop,msisdn,2304,msisdn,1763,5,USD,Test Payee Payment +5,d79a4bc6-f9ec-4eba-beb7-96277bd832b3,mojaloop,msisdn,2305,msisdn,1764,3,USD,Test Payee Payment +6,1f838585-5091-44ef-9432-77d13b9c4583,mojaloop,msisdn,2306,msisdn,1764,2,USD,Test Payee Payment +7,94fd7bd1-7482-4f4f-bf12-a21ab4b550a8,mojaloop,msisdn,2307,msisdn,1765,1,USD,Test Payee Payment \ No newline at end of file diff --git a/ph-ee-integration-test/src/test/java/resources/batch_demo_csv/batchTransaction.csv b/ph-ee-integration-test/src/test/java/resources/batch_demo_csv/batchTransaction.csv new file mode 100644 index 000000000..18905bd4d --- /dev/null +++ b/ph-ee-integration-test/src/test/java/resources/batch_demo_csv/batchTransaction.csv @@ -0,0 +1,4 @@ +id,request_id,payment_mode,payer_identifier_type,payer_identifier,payee_identifier_type,payee_identifier,amount,currency,note +0,ed6bf87e-4bda-44dc-be52-004e71438f0f,mojaloop,msisdn,345,msisdn,363,3,USD,Test Payee Payment +1,25ddc445-069a-417b-b62a-f5b952ac313e,mojaloop,msisdn,346,msisdn,363,2,USD,Test Payee Payment +2,0842d2df-0aec-4312-ada4-c3dd2be1ed80,mojaloop,msisdn,347,msisdn,364,1,USD,Test Payee Payment \ No newline at end of file diff --git a/ph-ee-integration-test/src/test/java/resources/batch_demo_csv/batchTransactionGsma.csv b/ph-ee-integration-test/src/test/java/resources/batch_demo_csv/batchTransactionGsma.csv new file mode 100644 index 000000000..e8e8fcd26 --- /dev/null +++ b/ph-ee-integration-test/src/test/java/resources/batch_demo_csv/batchTransactionGsma.csv @@ -0,0 +1,4 @@ +id,request_id,payment_mode,payer_identifier_type,payer_identifier,payee_identifier_type,payee_identifier,amount,currency,note +0,1fe8af66-9a34-4b92-bbd5-1a116b635bb5,gsma,msisdn,4004,msisdn,3815,10,USD,Test Payee Payment +1,dbbe52aa-20a0-4eb9-80a0-ad6df8068e40,gsma,msisdn,4005,msisdn,3816,5,USD,Test Payee Payment +2,021955bc-8a96-45d3-bec0-69e365d5369c,gsma,msisdn,4006,msisdn,3817,1,USD,Test Payee Payment \ No newline at end of file diff --git a/ph-ee-integration-test/src/test/java/resources/batch_demo_csv/bulk_payment.csv b/ph-ee-integration-test/src/test/java/resources/batch_demo_csv/bulk_payment.csv new file mode 100644 index 000000000..31c9cee76 --- /dev/null +++ b/ph-ee-integration-test/src/test/java/resources/batch_demo_csv/bulk_payment.csv @@ -0,0 +1,7 @@ +id,request_id,payment_mode,payer_identifier_type,payer_identifier,payee_identifier_type,payee_identifier,amount,currency,note +0,g1e22fe3-9740-4fba-97b6-78f43bfa7f2f,closedloop,accountNumber,003001003879112168,accountNumber,400173110196,850,USD,Test Payee Payment +1,72aa3ea4-e6f6-4880-877f-39f6ac4d052e,closedloop,accountNumber,003001003879112168,accountNumber,400174120160,222,USD,Test Payee Payment +2,f1e22fe3-9740-4fba-97b6-78f43bfa7f0f,closedloop,accountNumber,003001003879112168,accountNumber,400173110195,840,USD,Test Payee Payment +3,q1e22fe3-9740-4fba-97b6-78f43bfa7f2f,closedloop,accountNumber,003001003879112168,accountNumber,400173110196,750,USD,Test Payee Payment +4,a2aa3ea4-e6f6-4880-877f-39f6ac4d052e,closedloop,accountNumber,003001003879112168,accountNumber,400174120160,122,USD,Test Payee Payment +5,z1e22fe3-9740-4fba-97b6-78f43bfa7f0f,closedloop,accountNumber,003001003879112168,accountNumber,400173110195,740,USD,Test Payee Payment \ No newline at end of file diff --git a/ph-ee-integration-test/src/test/java/resources/batch_demo_csv/bulk_payment_closedl_mock_mojaloop.csv b/ph-ee-integration-test/src/test/java/resources/batch_demo_csv/bulk_payment_closedl_mock_mojaloop.csv new file mode 100644 index 000000000..fd9923ee8 --- /dev/null +++ b/ph-ee-integration-test/src/test/java/resources/batch_demo_csv/bulk_payment_closedl_mock_mojaloop.csv @@ -0,0 +1,9 @@ +id,request_id,payment_mode,payer_identifier_type,payer_identifier,payee_identifier_type,payee_identifier,amount,currency,note +0,g2e22fe3-9740-4fba-97b6-78f43bfa7f2f,closedloop,accountNumber,003001003879112168,accountNumber,400173110196,150,USD,Test Payee Payment +1,71aa3ea4-e6f6-4880-877f-39f6ac4d052e,closedloop,accountNumber,003001003879112168,accountNumber,400174120160,222,USD,Test Payee Payment +2,f4e22fe3-9740-4fba-97b6-78f43bfa7f0f,closedloop,accountNumber,003001003879112168,accountNumber,400173110195,140,USD,Test Payee Payment +3,72aa3ea4-e6f6-4880-877f-39f6ac4d052e,closedloop,accountNumber,003001003879112168,accountNumber,400174120160,220,USD,Test Payee Payment +4,77za3ea4-e6f6-4880-877f-39f6ac4d052e,closedloop,accountNumber,003001003879112168,accountNumber,400174120160,122,USD,Test Payee Payment +5,q0e22fe3-9740-4fba-97b6-78f43bfa7f2f,mojaloop,accountNumber,003001003879112168,accountNumber,400173110196,750,USD,Test Payee Payment +6,a4aa3ea4-e6f6-4880-877f-39f6ac4d052e,mojaloop,accountNumber,003001003879112168,accountNumber,400174120160,722,USD,Test Payee Payment +7,z4e22fe3-9740-4fba-97b6-78f43bfa7f0f,mojaloop,accountNumber,003001003879112168,accountNumber,400173110195,740,USD,Test Payee Payment \ No newline at end of file diff --git a/ph-ee-integration-test/src/test/java/resources/batch_demo_csv/deduplication-test.csv b/ph-ee-integration-test/src/test/java/resources/batch_demo_csv/deduplication-test.csv new file mode 100644 index 000000000..6a855cff8 --- /dev/null +++ b/ph-ee-integration-test/src/test/java/resources/batch_demo_csv/deduplication-test.csv @@ -0,0 +1,4 @@ +id,request_id,payment_mode,payer_identifier_type,payer_identifier,payee_identifier_type,payee_identifier,amount,currency,note +0,k1e22fe3-9740-4fba-97b6-78f43bfa7f2f,mojaloop,msisdn,835322416,msisdn,27713803912,10,USD,Moja bulk test +1,l9f6ac4d052e-72aa3ea4-e6f6-4880-877f,mojaloop,msisdn,835322416,msisdn,27713803912,10,USD,Moja bulk test +2,m27631f6-6dd4-4d69-b4fc-8932bd721913,mojaloop,msisdn,835322416,msisdn,27713803913,10,USD,Moja bulk test \ No newline at end of file diff --git a/ph-ee-integration-test/src/test/java/resources/batch_demo_csv/payerIdentifier-resolution-using-budgetAccount.csv b/ph-ee-integration-test/src/test/java/resources/batch_demo_csv/payerIdentifier-resolution-using-budgetAccount.csv new file mode 100644 index 000000000..879d73de3 --- /dev/null +++ b/ph-ee-integration-test/src/test/java/resources/batch_demo_csv/payerIdentifier-resolution-using-budgetAccount.csv @@ -0,0 +1,11 @@ +id,request_id,payment_mode,payer_identifier_type,payer_identifier,payee_identifier_type,payee_identifier,amount,currency,note +0,f1e22fe3-9740-4fba-97b6-78f43bfa7f2f,mojaloop,,,msisdn,27713803912,10,USD,Moja bulk test 1 +1,39f6ac4d052e-72aa3ea4-e6f6-4880-877f,mojaloop,,,msisdn,27713803913,20,USD,Moja bulk test 2 +2,a27631f6-6dd4-4d69-b4fc-8932bd721913,mojaloop,,,msisdn,27713803914,30,USD,Moja bulk test 3 +3,3d21e6ea-c583-44ed-b94f-af909fa7616e,mojaloop,,,msisdn,27713803915,40,USD,Moja bulk test 4 +4,15f9a0b0-2299-436d-8433-da564140ba66,mojaloop,,,msisdn,27713803916,50,USD,Moja bulk test 5 +5,f1e22fe3-9740-4fba-97b6-78f43bfa7f2f,mojaloop,,,msisdn,27713803917,60,USD,Moja bulk test 1 +6,39f6ac4d052e-72aa3ea4-e6f6-4880-877f,mojaloop,,,msisdn,27713803918,70,USD,Moja bulk test 2 +7,a27631f6-6dd4-4d69-b4fc-8932bd721913,mojaloop,,,msisdn,27713803919,80,USD,Moja bulk test 3 +8,3d21e6ea-c583-44ed-b94f-af909fa7616e,mojaloop,,,msisdn,27713803910,90,USD,Moja bulk test 4 +9,15f9a0b0-2299-436d-8433-da564140ba66,mojaloop,,,msisdn,27713803911,100,USD,Moja bulk test 5 \ No newline at end of file diff --git a/ph-ee-integration-test/src/test/java/resources/batch_demo_csv/ph-ee-bulk-demo-6.csv b/ph-ee-integration-test/src/test/java/resources/batch_demo_csv/ph-ee-bulk-demo-6.csv new file mode 100644 index 000000000..9e7158ee3 --- /dev/null +++ b/ph-ee-integration-test/src/test/java/resources/batch_demo_csv/ph-ee-bulk-demo-6.csv @@ -0,0 +1,11 @@ +id,request_id,payment_mode,payer_identifier_type,payer_identifier,payee_identifier_type,payee_identifier,amount,currency,note +0,f1e22fe3-9740-4fba-97b6-78f43bfa7f2f,mojaloop,accountNumber,0030010038791121681,accountNumber,0030010038731101961,850,USD,Test Payee Payment +1,72aa3ea4-e6f6-4880-877f-39f6ac4d052e,mojaloop,accountNumber,0030010038791121682,accountNumber,0030010038741201602,222,USD,Test Payee Payment +2,f1e22fe3-9740-4fba-97b6-78f43bfa7f2f,mojaloop,accountNumber,0030010038791121683,accountNumber,0030010038731101963,850,USD,Test Payee Payment +3,72aa3ea4-e6f6-4880-877f-39f6ac4d052e,mojaloop,accountNumber,0030010038791121684,accountNumber,0030010038741201604,222,USD,Test Payee Payment +4,f1e22fe3-9740-4fba-97b6-78f43bfa7f2f,mojaloop,accountNumber,0030010038791121685,accountNumber,0030010038731101965,850,USD,Test Payee Payment +5,72aa3ea4-e6f6-4880-877f-39f6ac4d052e,mojaloop,accountNumber,0030010038791121686,accountNumber,0030010038741201606,222,USD,Test Payee Payment +6,f1e22fe3-9740-4fba-97b6-78f43bfa7f2f,mojaloop,accountNumber,0030010038791121687,accountNumber,0030010038731101967,850,USD,Test Payee Payment +7,72aa3ea4-e6f6-4880-877f-39f6ac4d052e,mojaloop,accountNumber,0030010038791121688,accountNumber,0030010038741201608,222,USD,Test Payee Payment +8,f1e22fe3-9740-4fba-97b6-78f43bfa7f2f,mojaloop,accountNumber,0030010038791121689,accountNumber,0030010038731101969,850,USD,Test Payee Payment +9,72aa3ea4-e6f6-4880-877f-39f6ac4d052e,mojaloop,accountNumber,0030010038791121680,accountNumber,0030010038741201600,222,USD,Test Payee Payment \ No newline at end of file diff --git a/ph-ee-integration-test/src/test/java/resources/batch_demo_csv/ph-ee-bulk-demo-7.csv b/ph-ee-integration-test/src/test/java/resources/batch_demo_csv/ph-ee-bulk-demo-7.csv new file mode 100644 index 000000000..f3bcd6327 --- /dev/null +++ b/ph-ee-integration-test/src/test/java/resources/batch_demo_csv/ph-ee-bulk-demo-7.csv @@ -0,0 +1,4 @@ +id,request_id,payment_mode,payer_identifier_type,payer_identifier,payee_identifier_type,payee_identifier,amount,currency,note +0,f1e22fe3-9740-4fba-97b6-78f43bfa7f2f,mojaloop,accountNumber,003001003879112168,accountNumber,103873110196,850,USD,Test Payee Payment +1,72aa3ea4-e6f6-4880-877f-39f6ac4d052e,mojaloop,accountNumber,003001003879112168,accountNumber,103874120160,222,USD,Test Payee Payment +2,f1e22fe3-9740-4fba-97b6-78f43bfa7f2f,mojaloop,accountNumber,003001003879112168,accountNumber,103873110195,840,USD,Test Payee Payment \ No newline at end of file diff --git a/ph-ee-integration-test/src/test/java/resources/batch_demo_csv/ph-ee-bulk-demoErrorAsync-6.csv b/ph-ee-integration-test/src/test/java/resources/batch_demo_csv/ph-ee-bulk-demoErrorAsync-6.csv new file mode 100644 index 000000000..3572bb070 --- /dev/null +++ b/ph-ee-integration-test/src/test/java/resources/batch_demo_csv/ph-ee-bulk-demoErrorAsync-6.csv @@ -0,0 +1,6 @@ +id,request_id,payment_mode,payer_identifier_type,payer_identifier,payee_identifier_type,payee_identifier,amount,currency,note +0,f1e22fe3-9740-4fba-97b6-78f43bfa7f2f,mojaloop,msisdn,8353224161,msisdn,277138039121,10,USD,Moja bulk test 1 +1,39f6ac4d052e-72aa3ea4-e6f6-4880-877f,mojaloop,msisdn,8353224162,msisdn,277138039122,10,USD,Moja bulk test 2 +2,a27631f6-6dd4-4d69-b4fc-8932bd721913,mojaloop,msisdn,8353224163,msisdn,277138039124,10,USD,Moja bulk test 3 +3,3d21e6ea-c583-44ed-b94f-af909fa7616e,mojaloop,msisdn,8353224164,msisdn,277138039125,10,USD,Moja bulk test 4 +4,15f9a0b0-2299-436d-8433-da564140ba66,mojaloop,msisdn,55dghsdg667,msisdn,27713803912,10,USD,Moja bulk test 5 \ No newline at end of file diff --git a/ph-ee-integration-test/src/test/java/resources/batch_demo_csv/ph-ee-bulk-demoErrorSync-6.csv b/ph-ee-integration-test/src/test/java/resources/batch_demo_csv/ph-ee-bulk-demoErrorSync-6.csv new file mode 100644 index 000000000..13736b594 --- /dev/null +++ b/ph-ee-integration-test/src/test/java/resources/batch_demo_csv/ph-ee-bulk-demoErrorSync-6.csv @@ -0,0 +1,6 @@ +id,request_id,paymentmode,payer_identifier_type,payer_identifier,payee_identifier_type,payee_identifier,amount,currency,note +0,f1e22fe3-9740-4fba-97b6-78f43bfa7f2f,mojaloop,msisdn,835322416,msisdn,27713803912,10,USD,Moja bulk test 1 +1,39f6ac4d052e-72aa3ea4-e6f6-4880-877f,mojaloop,msisdn,835322416,msisdn,27713803912,10,USD,Moja bulk test 2 +2,a27631f6-6dd4-4d69-b4fc-8932bd721913,mojaloop,msisdn,835322416,msisdn,27713803912,10,USD,Moja bulk test 3 +3,3d21e6ea-c583-44ed-b94f-af909fa7616e,mojaloop,msisdn,835322416,msisdn,27713803912,10,USD,Moja bulk test 4 +4,15f9a0b0-2299-436d-8433-da564140ba66,mojaloop,msisdn,835322416,msisdn,27713803912,10,USD,Moja bulk test 5 \ No newline at end of file diff --git a/ph-ee-integration-test/src/test/java/resources/batch_demo_csv/ph-ee-bulk-splitting.csv b/ph-ee-integration-test/src/test/java/resources/batch_demo_csv/ph-ee-bulk-splitting.csv new file mode 100644 index 000000000..1a2bd83ec --- /dev/null +++ b/ph-ee-integration-test/src/test/java/resources/batch_demo_csv/ph-ee-bulk-splitting.csv @@ -0,0 +1,13 @@ +id,request_id,payment_mode,payer_identifier_type,payer_identifier,payee_identifier_type,payee_identifier,amount,currency,note +0,f1e22fe3-9740-4fba-97b6-78f43bfa7f2f,mojaloop,accountNumber,003001003879112168,accountNumber,003001003873110196,850,USD,Test Payee Payment +1,72aa3ea4-e6f6-4880-877f-39f6ac4d052e,mojaloop,accountNumber,003001003879112168,accountNumber,003001003874120160,222,USD,Test Payee Payment +2,a1e22fe3-9740-4fba-97b6-78f43bfa7f2f,mojaloop,accountNumber,003001003879112168,accountNumber,003001003873110196,840,USD,Test Payee Payment +3,l1e22fe3-9740-4fba-97b6-78f43bfa7f2f,mojaloop,accountNumber,003001003879112168,accountNumber,003001003873110196,830,USD,Test Payee Payment +4,k2aa3ea4-e6f6-4880-877f-39f6ac4d052e,mojaloop,accountNumber,003001003879112168,accountNumber,003001003874120160,333,USD,Test Payee Payment +5,c1e22fe3-9740-4fba-97b6-78f43bfa7f2f,mojaloop,accountNumber,003001003879112168,accountNumber,003001003873110196,820,USD,Test Payee Payment +6,x1e22fe3-9740-4fba-97b6-78f43bfa7f2f,mojaloop,accountNumber,003001003879112168,accountNumber,003001003873110196,810,USD,Test Payee Payment +7,m2aa3ea4-e6f6-4880-877f-39f6ac4d052e,mojaloop,accountNumber,003001003879112168,accountNumber,003001003874120160,444,USD,Test Payee Payment +8,p1e22fe3-9740-4fba-97b6-78f43bfa7f2f,mojaloop,accountNumber,003001003879112168,accountNumber,003001003873110196,800,USD,Test Payee Payment +9,q1e22fe3-9740-4fba-97b6-78f43bfa7f2f,mojaloop,accountNumber,003001003879112168,accountNumber,003001003873110196,860,USD,Test Payee Payment +10,e2aa3ea4-e6f6-4880-877f-39f6ac4d052e,mojaloop,accountNumber,003001003879112168,accountNumber,003001003874120160,555,USD,Test Payee Payment +11,t1e22fe3-9740-4fba-97b6-78f43bfa7f2f,mojaloop,accountNumber,003001003879112168,accountNumber,003001003873110196,870,USD,Test Payee Payment \ No newline at end of file diff --git a/ph-ee-integration-test/src/test/java/resources/billPay.feature b/ph-ee-integration-test/src/test/java/resources/billPay.feature new file mode 100644 index 000000000..a28c4898b --- /dev/null +++ b/ph-ee-integration-test/src/test/java/resources/billPay.feature @@ -0,0 +1,372 @@ + +Feature: Bill Payment P2G Test + + @gov + #this is an integration for bill inquiry stage w/o rtp, includes bill inquiry api only from PFI to PBB to Bill Agg and back + Scenario: BI-001 Bill Inquiry API for orchestration (PFI to PBB) + Given I can inject MockServer + And I can start mock server + And I can register the stub with "/billInquiry" endpoint for "POST" request with status of 200 + Given I have tenant as "paymentBB2" + And I generate clientCorrelationId + And I have bill id as "001" + When I call the get bills api with billid with expected status of 202 and callbackurl as "/billInquiry" + Then I should get non empty response + And I should get transactionId in response +# And I will sleep for 5000 millisecond + Then I should be able to extract response body from callback for bill pay + + @gov + #this is an integration for payment notification, includes api calls from PFI to PBB to Bill Agg and back (tests full flow) + Scenario: BP-001 Bill Payments API for orchestration (PFI to PBB) + Given I can inject MockServer + And I can start mock server + And I can register the stub with "/billNotification" endpoint for "POST" request with status of 200 + Given I have tenant as "paymentBB2" + And I have bill id as "001" + And I generate clientCorrelationId + And I can mock payment notification request + When I call the payment notification api expected status of 202 and callbackurl as "/billNotification" + Then I should get non empty response + And I should get transactionId in response +# And I will sleep for 5000 millisecond + Then I should be able to extract response body from callback for bill notification + + + #this is an integration for bill inquiry stage w/o rtp, includes bill inquiry api and payment notification from PFI to PBB to Bill Agg and back + Scenario: Bill Inquiry API for orchestration (PFI to PBB) + Given I can inject MockServer + And I can start mock server + And I can register the stub with "/billInquiry" endpoint for "POST" request with status of 200 + And I can register the stub with "/billNotification" endpoint for "POST" request with status of 200 + Given I have tenant as "paymentBB2" + And I generate clientCorrelationId + And I have bill id as "001" + When I call the get bills api with billid with expected status of 202 and callbackurl as "/billInquiry" + Then I should get non empty response + And I should get transactionId in response + Given I have tenant as "paymentBB2" + And I have bill id as "001" + And I generate clientCorrelationId + And I can mock payment notification request + When I call the payment notification api expected status of 202 and callbackurl as "/billNotification" + Then I should get non empty response + And I should get transactionId in response +# And I will sleep for 5000 millisecond + When I make the "POST" request to "/billNotification" endpoint with expected status of 200 + Then I should be able to extract response body from callback for bill pay + When I make the "POST" request to "/billInquiry" endpoint with expected status of 200 + Then I should be able to extract response body from callback for bill pay + + #this is an component test for bill inquiry stage w/o rtp, includes bill inquiry api from PBB to Bill Agg with mock + #response for bill inquiry api from Bill Agg to PBB to PFI + Scenario: Bill Inquiry API for P2G (PBB to Biller/Agg) + Given I have tenant as "paymentBB2" + And I generate clientCorrelationId + And I have bill id as "001" + When I call the mock get bills api from PBB to Biller with billid with expected status of 202 + Then I should get non empty response + + + #this is an component test for bill inquiry stage w/o rtp, includes bill inquiry api from PBB to Bill Agg with mock + #response for bill inquiry api from Bill Agg to PBB to PFI + Scenario: Bill Payments API for P2G (PBB to Biller/Agg) + Given I have tenant as "paymentBB2" + And I generate clientCorrelationId + And I have bill id as "001" + And I can mock payment notification request + When I call the mock bills payment api from PBB to Biller with billid with expected status of 202 + Then I should get non empty response + + @gov + Scenario: RTP-001 RTP Integration test + Given I can inject MockServer + And I can start mock server + And I can register the stub with "/testRTP" endpoint for "POST" request with status of 200 + Given I have tenant as "paymentBB2" + And I have a billerId as "GovBill" + And I have bill id as "1008" + And I generate clientCorrelationId + And I generate clientCorrelationId + Then I can create DTO for Biller RTP Request + And I can call the biller RTP request API with expected status of 202 and "/testRTP" endpoint +# Then I will sleep for 8000 millisecond + And I can extract the callback body and assert the rtpStatus + + @gov + Scenario: BI-002 Bill Inquiry API for orchestration fails due to invalid prefix (PFI to PBB) + Given I can inject MockServer + And I can start mock server + And I can register the stub with "/billInquiry" endpoint for "POST" request with status of 200 + Given I have tenant as "paymentBB2" + And I generate clientCorrelationId + And I have bill id as "101" + When I call the get bills api with billid with expected status of 202 and callbackurl as "/billInquiryPrefixInvalid" + Then I should get non empty response + And I should get transactionId in response +# And I will sleep for 5000 millisecond + Then I should be able to extract response body from callback for biller unidentified + + @gov + Scenario: BI-003A: Bill Inquiry API for orchestration fails due to invalid bill (PBB TO BA) + Given I can inject MockServer + And I can start mock server + And I can register the stub with "/billInquiry" endpoint for "POST" request with status of 200 + Given I have tenant as "paymentBB2" + And I generate clientCorrelationId + And I have bill id as "002" + When I call the get bills api with billid with expected status of 202 and callbackurl as "/invalidbillInquiry" + Then I should get non empty response + And I should get transactionId in response +# And I will sleep for 5000 millisecond + Then I should be able to extract response body from callback for bill invalid + + @gov + Scenario: BI-003B: Bill Inquiry API for orchestration fails due to payer fsp not onboarded (PFI TO PBB) + Given I can inject MockServer + And I can start mock server + And I can register the stub with "/billInquiryInvalid" endpoint for "POST" request with status of 200 + Given I have tenant as "paymentBB2" + And I generate clientCorrelationId + And I have bill id as "003" + When I call the get bills api with billid with expected status of 404 and callbackurl as "/billInquiryInvalid" + Then I should get non empty response + And I should get Payer FSP not found in response + + @gov + Scenario: BI-004: Bill Inquiry API for orchestration fails due to empty bill (PBB TO BA) + Given I can inject MockServer + And I can start mock server + And I can register the stub with "/billInquiryEmpty" endpoint for "POST" request with status of 200 + Given I have tenant as "paymentBB2" + And I generate clientCorrelationId + And I have bill id as "004" + When I call the get bills api with billid with expected status of 202 and callbackurl as "/billInquiryEmpty" + Then I should get non empty response + And I should get transactionId in response +# And I will sleep for 5000 millisecond + Then I should be able to extract response body from callback for empty bill id + + @gov + Scenario: BP-003 Bill Payments API fails due to mandatory fields missing (PFI to PBB) + Given I can inject MockServer + And I can start mock server + And I can register the stub with "/billNotificationMissing" endpoint for "POST" request with status of 200 + Given I have tenant as "paymentBB2" + And I have bill id as "001" + And I generate clientCorrelationId + And I can mock payment notification request with missing values + When I call the payment notification api expected status of 400 and callbackurl as "/billNotificationMissing" + Then I should get non empty response + And I should be able to assert negative response body + + @gov + Scenario: BP-003A Bill Payments API fails due to mandatory fields missing -Bill Id(PFI to PBB) + Given I can inject MockServer + And I can start mock server + And I can register the stub with "/billNotificationMissing" endpoint for "POST" request with status of 200 + Given I have tenant as "paymentBB2" + And I generate clientCorrelationId + And I can mock payment notification request with missing bill id + When I call the payment notification api expected status of 400 and callbackurl as "/billNotificationMissing" + Then I should get non empty response + And I should be able to assert negative response body + Then I will assert that response contains "error.msg.schema.bill.id.cannot.be.null.or.empty" + + @gov + Scenario: BP-004A Bill Payments API fails due to bill already marked paid (PFI to PBB) + Given I can inject MockServer + And I can start mock server + And I can register the stub with "/billNotificationPaid" endpoint for "POST" request with status of 200 + Given I have tenant as "paymentBB2" + And I have bill id as "003" + And I generate clientCorrelationId + And I can mock payment notification request + When I call the payment notification api expected status of 202 and callbackurl as "/billNotificationPaid" + Then I should get non empty response + And I should get transactionId in response +# And I will sleep for 5000 millisecond + Then I should be able to extract response body from callback for bill already paid + Then I can stop mock server + + @gov + Scenario: BP-004B Bill Payments API fails due to bill marked as paid after a timeout (PFI to PBB) + Given I can inject MockServer + And I can start mock server + And I can register the stub with "/billNotificationsTimeout" endpoint for "POST" request with status of 200 + Given I have tenant as "paymentBB2" + And I have bill id as "005" + And I generate clientCorrelationId + And I can mock payment notification request + When I call the payment notification api expected status of 202 and callbackurl as "/billNotificationsTimeout" + Then I should get non empty response + And I should get transactionId in response + And I should remove all server events +# And I will sleep for 1000 millisecond + Then I should not get a response from callback for bill +# And I will sleep for 5000 millisecond + Then I should be able to extract response body from callback for bill paid after timeout + + + @gov + Scenario: RTP-002 Request to Pay is unsuccessful because RtP type of Alias is not specified + Given I have tenant as "paymentBB2" + And I have a billerId as "GovBill" + And I have bill id as "1009" + And I generate clientCorrelationId + And I generate clientCorrelationId + Then I can create DTO for Biller RTP Request without alias details + And I can call the biller RTP request API with expected status of 400 and "/aliasSpecification" endpoint + And I should be able to assert negative response body + Then I will assert that response contains "error.msg.schema.payer.fsp.details.cannot.be.null.or.empty" + + @gov + Scenario: RTP-003 Request to Pay is unsuccessful because RtP type does not match with the information provided + Given I have tenant as "paymentBB2" + And I have a billerId as "GovBill" + And I generate clientCorrelationId + And I create a new clientCorrelationId + And I have bill id as "1010" + And I generate clientCorrelationId + Then I can create DTO for Biller RTP Request with incorrect rtp information + And I can call the biller RTP request API with expected status of 400 and "/informationMismatch" endpoint + And I should be able to assert negative response body + Then I will assert that response contains "error.msg.schema.alias.cannot.be.null.or.empty" + + @gov + Scenario: RTP-004 Request to Pay is unsuccessful because of invalid RTP type (alias or bank account) + Given I have tenant as "paymentBB2" + And I have a billerId as "GovBill" + And I generate clientCorrelationId + And I create a new clientCorrelationId + And I have bill id as "1011" + And I generate clientCorrelationId + Then I can create DTO for Biller RTP Request with incorrect rtp type + And I can call the biller RTP request API with expected status of 400 and "/invalidRtp" endpoint + And I should be able to assert negative response body + Then I will assert that response contains "error.msg.schema.request.type.is.invalid" + + @gov + Scenario: RTP-005 Request to Pay is unsuccessful because of Alias type and Alias information mismatch + Given I have tenant as "paymentBB2" + And I have a billerId as "GovBill" + And I generate clientCorrelationId + And I create a new clientCorrelationId + And I have bill id as "1012" + And I generate clientCorrelationId + Then I can create DTO for Biller RTP Request with incorrect alias details + And I can call the biller RTP request API with expected status of 400 and "/aliasMismatch" endpoint + And I should be able to assert negative response body + Then I will assert that response contains "error.msg.schema.request.type.is.invalid" + + @gov + Scenario: RTP-006 Request to Pay is unsuccessful because of invalid/incorrect BIC + Given I have tenant as "paymentBB2" + And I have a billerId as "GovBill" + And I generate clientCorrelationId + And I create a new clientCorrelationId + And I have bill id as "1013" + And I generate clientCorrelationId + Then I can create DTO for Biller RTP Request without alias details + And I can call the biller RTP request API with expected status of 400 and "/invalidBic" endpoint + And I should be able to assert negative response body + Then I will assert that response contains "error.msg.schema.payer.fsp.details.cannot.be.null.or.empty" + + @gov + Scenario: RTP-008 Request to Pay is unsuccessful because the specified account of the Payer FI was unreachable - did not respond (Txn timed out) + + Given I can inject MockServer + And I can start mock server + And I can register the stub with "/payerUnreachable" endpoint for "POST" request with status of 200 + Given I have tenant as "paymentBB2" + And I have a billerId as "GovBill" + And I generate clientCorrelationId + And I create a new clientCorrelationId + And I have bill id as "1014" + And I generate clientCorrelationId + Then I can create DTO for Biller RTP Request to mock payer fi unreachable + And I can call the biller RTP request API with expected status of 202 and "/payerUnreachable" endpoint +# Then I will sleep for 3000 millisecond + And I can extract the error from callback body and assert error message as "Payer FI was unreachable" + + @gov + Scenario: RTP-009 Request to Pay is unsuccessful because the Payer FSP is unable to debit amount (insufficient amount/ blocked account/ account hold etc) + (Payer FSP declines) + Given I can inject MockServer + And I can start mock server + And I can register the stub with "/debitFailed" endpoint for "POST" request with status of 200 + Given I have tenant as "paymentBB2" + And I have a billerId as "GovBill" + And I generate clientCorrelationId + And I have bill id as "1015" + Then I can create DTO for Biller RTP Request to mock payer fsp failed to debit amount + And I can call the biller RTP request API with expected status of 202 and "/debitFailed" endpoint +# Then I will sleep for 3000 millisecond + And I can extract the error from callback body and assert error message as "Payer FSP is unable to debit amount" + + @gov + Scenario: BS-001 Bill RTP Status API to get COMPLETED + Given I can inject MockServer + And I can start mock server + And I can register the stub with "/test1" endpoint for "POST" request with status of 200 + Given I have tenant as "paymentBB2" + And I have a billerId as "GovBill" + And I generate clientCorrelationId + And I have bill id as "001" + Then I can create DTO for Biller RTP Request + And I can call the biller RTP request API with expected status of 202 and "/test1" endpoint + And I can extract the callback body and assert the rtpStatus + Given I can create a request for status api + And I can call the biller RTP status API with expected status of 200 until I get the rtpStatus as "COM" + + @gov + Scenario: BS-002 Bill RTP Status API to get PENDING + Given I can inject MockServer + And I can start mock server + And I can register the stub with "/debitFailed" endpoint for "POST" request with status of 200 + Given I have tenant as "paymentBB2" + And I have a billerId as "GovBill" + And I generate clientCorrelationId + And I have bill id as "011" + Then I can create DTO for Biller RTP Request to mock payer fsp failed to debit amount + And I can call the biller RTP request API with expected status of 202 and "/debitFailed" endpoint + Given I can create a request for status api + And I can call the biller RTP status API with expected status of 200 until I get the rtpStatus as "PND" + + @gov + Scenario: BS-003 Bill RTP Status API to get req accepted + Given I can inject MockServer + And I can start mock server + And I can register the stub with "/test1" endpoint for "POST" request with status of 200 + Given I have tenant as "paymentBB2" + And I have a billerId as "GovBill" + And I generate clientCorrelationId + And I have bill id as "123" + Then I can create DTO for Biller RTP Request + And I can call the biller RTP request API with expected status of 202 and "/test1" endpoint + Given I can create a request for status api + And I can call the biller RTP status API with expected status of 200 until I get the rtpStatus as "REQUEST_ACCEPTED" + + @gov + Scenario: BS-004 Bill RTP Status API to get accepted + Given I can inject MockServer + And I can start mock server + And I can register the stub with "/test1" endpoint for "POST" request with status of 200 + Given I have tenant as "paymentBB2" + And I have a billerId as "GovBill" + And I generate clientCorrelationId + And I have bill id as "1234" + Then I can create DTO for Biller RTP Request + And I can call the biller RTP request API with expected status of 202 and "/test1" endpoint + Given I can create a request for status api + And I can call the biller RTP status API with expected status of 200 until I get the rtpStatus as "ACCEPTED" + + @gov + Scenario: Unsupported header validation for Bill Payments API + Given I have tenant as "paymentBB2" + And I generate clientCorrelationId + And I have bill id as "001" + And I can mock payment notification request + When I call the mock bills payment api with invalid header from PBB to Biller with billid with expected status of 400 + Then I should get non empty response + Then I will assert that response contains "error.msg.header.validation.errors" diff --git a/ph-ee-integration-test/src/test/java/resources/bulkPayment.feature b/ph-ee-integration-test/src/test/java/resources/bulkPayment.feature new file mode 100644 index 000000000..2ec0bff97 --- /dev/null +++ b/ph-ee-integration-test/src/test/java/resources/bulkPayment.feature @@ -0,0 +1,597 @@ +@e2e +Feature: Test ability to make payment to individual with bank account + + @commonExtended + Scenario: BB-FSP 001 Create Budget Account and Register Payee + Given I am setting up Mojaloop + And I have the registeringInstituteId "SocialWelfare" + And I have the programId "Education" + Given I have Fineract-Platform-TenantId for "payer" + When I call the create client endpoint for "payer" + Then I call the create savings product endpoint for "payer" + When I call the create savings account endpoint for "payer" + Then I check whether budget account exists with accoundId "123456789" + Then I call the interop identifier endpoint for "payer" and accountId "123456789" + Then I approve the deposit for Budget Account with command "approve" for "payer" + When I activate the budget account with command "activate" for "payer" + Then I call the deposit account endpoint with command "deposit" for amount 7000 for "payer" + #Registring account lookup + Then I add "payer" with account id "123456789" to als + + + When I call the create client endpoint for "payer" + Then I call the create savings product endpoint for "payer" + When I call the create savings account endpoint for "payer" + Then I check whether budget account exists with accoundId "223456789" + Then I call the interop identifier endpoint for "payer" and accountId "223456789" + Then I approve the deposit for Budget Account with command "approve" for "payer" + When I activate the budget account with command "activate" for "payer" + Then I call the deposit account endpoint with command "deposit" for amount 9000 for "payer" + Then I add "payer" with account id "223456789" to als + + + When I call the create client endpoint for "payer" + Then I call the create savings product endpoint for "payer" + When I call the create savings account endpoint for "payer" + Then I check whether budget account exists with accoundId "323456789" + Then I call the interop identifier endpoint for "payer" and accountId "323456789" + Then I approve the deposit for Budget Account with command "approve" for "payer" + When I activate the budget account with command "activate" for "payer" + Then I call the deposit account endpoint with command "deposit" for amount 9000 for "payer" + Then I add "payer" with account id "323456789" to als + + Given I have Fineract-Platform-TenantId for "payee1" + When I call the create client endpoint for "payee" + Then I call the create savings product endpoint for "payee" + When I call the create savings account endpoint for "payee" + Then I check whether budget account exists with accoundId "1234" + Then I call the interop identifier endpoint for "payee" and accountId "1234" + Then I approve the deposit for Budget Account with command "approve" for "payee" + When I activate the budget account with command "activate" for "payee" + Then I call the deposit account endpoint with command "deposit" for amount 1000 for "payee" + Then I add "payee1" with account id "1234" to als + + Given I have Fineract-Platform-TenantId for "payee2" + When I call the create client endpoint for "payee" + Then I call the create savings product endpoint for "payee" + When I call the create savings account endpoint for "payee" + Then I check whether budget account exists with accoundId "2235" + Then I call the interop identifier endpoint for "payee" and accountId "2235" + Then I approve the deposit for Budget Account with command "approve" for "payee" + When I activate the budget account with command "activate" for "payee" + Then I call the deposit account endpoint with command "deposit" for amount 2000 for "payee" + Then I add "payee2" with account id "2235" to als + + Given I have Fineract-Platform-TenantId for "payee3" + When I call the create client endpoint for "payee" + Then I call the create savings product endpoint for "payee" + When I call the create savings account endpoint for "payee" + Then I check whether budget account exists with accoundId "3235" + Then I call the interop identifier endpoint for "payee" and accountId "3235" + Then I approve the deposit for Budget Account with command "approve" for "payee" + When I activate the budget account with command "activate" for "payee" + Then I call the deposit account endpoint with command "deposit" for amount 3000 for "payee" + Then I add "payee3" with account id "3235" to als + + And I have the demo csv file "bulk_payment.csv" + When I can inject MockServer + Then I can start mock server + And I can register the stub with "/registerBeneficiary" endpoint for "PUT" request with status of 200 + And I create a list of payee identifiers from csv file + And I create a IdentityMapperDTO for registering payee with IAM + Then I call the register beneficiary API with expected status of 202 and stub "/registerBeneficiary" + And I should be able to verify that the "PUT" method to "/registerBeneficiary" endpoint received a request with successfull registration + + + Scenario: BB-FSP 002 Input CSV file using the batch transaction API and poll batch summary API till we get completed status + Given I have tenant as "paymentbb1" + And I have the demo csv file "bulk_payment.csv" + And I create a list of payee identifiers from csv file + When I can inject MockServer + Then I can start mock server + And I have the registeringInstituteId "SocialWelfare" + And I have the programId "Education" + And I can register the stub with "/registerBeneficiary" endpoint for "PUT" request with status of 200 + And I create a IdentityMapperDTO for registering payee with IAM + Then I call the register beneficiary API with expected status of 202 and stub "/registerBeneficiary" + And I should be able to verify that the "PUT" method to "/registerBeneficiary" endpoint received a request with successfull registration + + And I create a new clientCorrelationId + And I have private key + And I generate signature + + When I call the batch transactions endpoint with expected status of 202 + Then I should get non empty response + And I am able to parse batch transactions response + And I fetch batch ID from batch transaction API's response +# Then I will sleep for 10000 millisecond + Given I have tenant as "paymentbb1" + When I call the batch summary API with expected status of 200 with total 6 txns + Then I am able to parse batch summary response + And Status of transaction is "COMPLETED" + And I should have matching total txn count and successful txn count in response + + + Scenario: BB-FSP 003 Input CSV file using the batch transaction API and poll batch summary API till we get completed status + Given I have tenant as "paymentbb1" + And I have the demo csv file "bulk_payment.csv" + And I create a list of payee identifiers from csv file + When I can inject MockServer + Then I can start mock server + And I have the registeringInstituteId "SocialWelfare" + And I have the programId "UnconditionalCashTransfer" + And I can register the stub with "/registerBeneficiary" endpoint for "PUT" request with status of 200 + And I create a IdentityMapperDTO for registering payee with IAM + Then I call the register beneficiary API with expected status of 202 and stub "/registerBeneficiary" + And I should be able to verify that the "PUT" method to "/registerBeneficiary" endpoint received a request with successfull registration + And I create a new clientCorrelationId + And I have private key + And I generate signature + When I call the batch transactions endpoint with expected status of 202 + Then I should get non empty response + And I am able to parse batch transactions response + And I fetch batch ID from batch transaction API's response +# Then I will sleep for 10000 millisecond + Given I have tenant as "paymentbb1" + When I call the batch summary API with expected status of 200 with total 6 txns + Then I am able to parse batch summary response + And Status of transaction is "COMPLETED" + And I should have matching total txn count and successful txn count in response + + + Scenario: BB-FSP 004 Input CSV file using the batch transaction API and poll batch summary API till we get completed status + Given I have tenant as "paymentbb1" + And I have the demo csv file "bulk_payment.csv" + And I create a list of payee identifiers from csv file + When I can inject MockServer + Then I can start mock server + And I have the registeringInstituteId "Health" + And I have the programId "Maternity" + And I can register the stub with "/registerBeneficiary" endpoint for "PUT" request with status of 200 + And I create a IdentityMapperDTO for registering payee with IAM + Then I call the register beneficiary API with expected status of 202 and stub "/registerBeneficiary" + And I should be able to verify that the "PUT" method to "/registerBeneficiary" endpoint received a request with successfull registration + And I create a new clientCorrelationId + And I have private key + And I generate signature + When I call the batch transactions endpoint with expected status of 202 + Then I should get non empty response + And I am able to parse batch transactions response + And I fetch batch ID from batch transaction API's response +# Then I will sleep for 10000 millisecond + Given I have tenant as "paymentbb1" + When I call the batch summary API with expected status of 200 with total 6 txns + Then I am able to parse batch summary response + And Status of transaction is "COMPLETED" + And I should have matching total txn count and successful txn count in response + + Scenario:BB-FSP 005 Input CSV file using the batch transaction API and poll batch summary API till we get completed status + Given I have tenant as "paymentbb1" + And I have the demo csv file "bulk_payment.csv" + And I create a list of payee identifiers from csv file + When I can inject MockServer + Then I can start mock server + And I have the registeringInstituteId "SocialWelfare" + And I have the programId "Education" + And I can register the stub with "/registerBeneficiary" endpoint for "PUT" request with status of 200 + And I create a IdentityMapperDTO for registering beneficiary + Then I call the register beneficiary API with expected status of 202 and stub "/registerBeneficiary" + And I should be able to verify that the "PUT" method to "/registerBeneficiary" endpoint received a request with successfull registration + And I create a new clientCorrelationId + And I have private key + And I generate signature + When I call the batch transactions endpoint with expected status of 202 + Then I should get non empty response + And I am able to parse batch transactions response + And I fetch batch ID from batch transaction API's response +# Then I will sleep for 10000 millisecond + Given I have tenant as "paymentbb1" + When I call the batch summary API with expected status of 200 with total 6 txns + Then I am able to parse batch summary response + And Status of transaction is "COMPLETED" + And I should have matching total txn count and successful txn count in response + + Scenario:BB-FSP 006 Bulk Transfer with ClosedLoop and Mojaloop + Given I have tenant as "payerfsp" + And I have the demo csv file "bulk_payment_closedl_mock_mojaloop.csv" + And I create a list of payee identifiers from csv file + When I can inject MockServer + Then I can start mock server + And I have the registeringInstituteId "SocialWelfare" + And I have the programId "Education" + And I can register the stub with "/registerBeneficiary" endpoint for "PUT" request with status of 200 + And I create a IdentityMapperDTO for registering beneficiary + Then I call the register beneficiary API with expected status of 202 and stub "/registerBeneficiary" + And I should be able to verify that the "PUT" method to "/registerBeneficiary" endpoint received a request with successfull registration + And I create a new clientCorrelationId + And I have private key + And I generate signature + When I call the batch transactions endpoint with expected status of 202 + Then I should get non empty response + And I am able to parse batch transactions response + And I fetch batch ID from batch transaction API's response + Then I will sleep for 10000 millisecond + Given I have tenant as "payerfsp" + When I call the batch summary API with expected status of 200 with total successfull 8 txns + Then I am able to parse batch summary response + And Status of transaction is "COMPLETED" + And My total txns 8 and successful txn count in response should Match + + @commonExtended + Scenario:BB-FSP 007 Bulk Transfer with ClosedLoop and GSMA + #payer 1 creation + Given I have Fineract-Platform-TenantId as "payerfsp2" + And I initialize the payee list + When I create and setup a "payer" with id "1" and account balance of 100 for combine test cases + Given I have tenant as "payerfsp" + Then I call the balance api for payer "1" balance for combine test cases + #payee 1 creation + When I create and setup a "payee" with id "1" and account balance of 10 for combine test cases + Given I have tenant as "payeefsp3" + Then I call the balance api for payee "1" balance for combine test cases + + Then Create a csv file with file name "batchTransactionGsmaClosedLoop.csv" + Then add row to csv with current payer and payee, payment mode as "closedloop" and transfer amount 10 and id 0 for combine test cases + + #payer 2 creation + Given I have Fineract-Platform-TenantId as "payerfsp2" + When I create and setup a "payer" with id "2" and account balance of 50 for combine test cases + Given I have tenant as "payerfsp" + Then I call the balance api for payer "2" balance for combine test cases + #payee 2 creation + When I create and setup a "payee" with id "2" and account balance of 20 for combine test cases + Given I have tenant as "payeefsp3" + Then I call the balance api for payee "2" balance for combine test cases + + Then add row to csv with current payer and payee, payment mode as "closedloop" and transfer amount 5 and id 1 for combine test cases + + #payer 3 creation + Given I have Fineract-Platform-TenantId as "payerfsp2" + When I create and setup a "payer" with id "3" and account balance of 50 for combine test cases + Given I have tenant as "payerfsp" + Then I call the balance api for payer "3" balance + #payee 2 creation + When I create and setup a "payee" with id "3" and account balance of 20 for combine test cases + Given I have tenant as "payeefsp3" + Then I call the balance api for payee "3" balance for combine test cases + + Then add row to csv with current payer and payee, payment mode as "closedloop" and transfer amount 5 and id 2 for combine test cases + + #payer 4 creation + Given I have Fineract-Platform-TenantId as "payerfsp2" + When I create and setup a "payer" with id "4" and account balance of 50 for combine test cases + Given I have tenant as "payerfsp" + Then I call the balance api for payer "4" balance for combine test cases + #payee 2 creation + When I create and setup a "payee" with id "4" and account balance of 20 for combine test cases + Given I have tenant as "payeefsp3" + Then I call the balance api for payee "4" balance for combine test cases + + Then add row to csv with current payer and payee, payment mode as "closedloop" and transfer amount 5 and id 3 for combine test cases + #payer 4 creation + Given I have Fineract-Platform-TenantId as "payerfsp2" + When I create and setup a "payer" with id "5" and account balance of 50 for combine test cases + Given I have tenant as "payerfsp" + Then I call the balance api for payer "5" balance for combine test cases + #payee 2 creation + When I create and setup a "payee" with id "5" and account balance of 20 for combine test cases + Given I have tenant as "payeefsp3" + Then I call the balance api for payee "5" balance for combine test cases + + Then add row to csv with current payer and payee, payment mode as "closedloop" and transfer amount 5 and id 4 for combine test cases + + #payer 4 creation + Given I have Fineract-Platform-TenantId as "payerfsp2" + When I create and setup a "payer" with id "6" and account balance of 50 for combine test cases + Given I have tenant as "payerfsp" + Then I call the balance api for payer "6" balance for combine test cases + #payee 2 creation + When I create and setup a "payee" with id "6" and account balance of 20 for combine test cases + Given I have tenant as "payeefsp3" + Then I call the balance api for payee "6" balance for combine test cases + + Then add row to csv with current payer and payee, payment mode as "gsma" and transfer amount 6 and id 5 for combine test cases + + #payer 5 creation + Given I have Fineract-Platform-TenantId as "payerfsp2" + When I create and setup a "payer" with id "7" and account balance of 50 for combine test cases + Given I have tenant as "payerfsp" + Then I call the balance api for payer "7" balance for combine test cases + #payee 2 creation + When I create and setup a "payee" with id "7" and account balance of 20 for combine test cases + Given I have tenant as "payeefsp3" + Then I call the balance api for payee "7" balance for combine test cases + + Then add row to csv with current payer and payee, payment mode as "gsma" and transfer amount 7 and id 6 for combine test cases + #payer 6 creation + Given I have Fineract-Platform-TenantId as "payerfsp2" + When I create and setup a "payer" with id "8" and account balance of 30 for combine test cases + Given I have tenant as "payerfsp" + Then I call the balance api for payer "8" balance for combine test cases + #payee 3 creation + When I create and setup a "payee" with id "8" and account balance of 30 for combine test cases + Given I have tenant as "payeefsp3" + Then I call the balance api for payee "8" balance for combine test cases + + Then add last row to csv with current payer and payee, payment mode as "gsma" and transfer amount 8 and id 7 + + When I can inject MockServer + Then I can start mock server + And I have the registeringInstituteId "SocialWelfare" + And I have the programId "Education" + + And I can register the stub with "/registerBeneficiary" endpoint for "PUT" request with status of 200 + And I create a IdentityMapperDTO for registering beneficiary + Then I call the register beneficiary API with expected status of 202 and stub "/registerBeneficiary" + And I should be able to verify that the "PUT" method to "/registerBeneficiary" endpoint received a request with successfull registration + #batch process + Given I have tenant as "payerfsp" + And I have the demo csv file "batchTransactionGsmaClosedLoop.csv" + And I generate clientCorrelationId + And I have private key + And I generate signature + When I call the batch transactions endpoint with expected status of 202 + And I am able to parse batch transactions response + And I fetch batch ID from batch transaction API's response + Then I will sleep for 10000 millisecond + When I call the batch summary API with expected status of 200 with total successfull 8 txns + Then I should get non empty response + Then I am able to parse batch summary response + And Status of transaction is "COMPLETED" + And My total txns 8 and successful txn count in response should Match + + + Scenario:BB-FSP 008 Bulk Transfer with Closedloop and Real Mojaloop + #payer 1 creation + Given I have Fineract-Platform-TenantId as "payerfsp2" + And I initialize the payee list + When I create and setup a "payer" with id "1" and account balance of 100 for combine test cases + Given I have tenant as "payerfsp" + Then I call the balance api for payer "1" balance for combine test cases + #payee 1 creation + When I create and setup a "payee" with id "1" and account balance of 10 for combine test cases + Given I have tenant as "payeefsp3" + Then I call the balance api for payee "1" balance for combine test cases + + Then Create a csv file with file name "batchTransactioClosedLoopMojaloopFundTransfer.csv" + Then add row to csv with current payer and payee, payment mode as "closedloop" and transfer amount 10 and id 0 for combine test cases + + #payer 2 creation + Given I have Fineract-Platform-TenantId as "payerfsp2" + When I create and setup a "payer" with id "2" and account balance of 50 for combine test cases + Given I have tenant as "payerfsp" + Then I call the balance api for payer "2" balance for combine test cases + #payee 2 creation + When I create and setup a "payee" with id "2" and account balance of 20 for combine test cases + Given I have tenant as "payeefsp3" + Then I call the balance api for payee "2" balance for combine test cases + + Then add row to csv with current payer and payee, payment mode as "closedloop" and transfer amount 5 and id 1 for combine test cases + + #payer 3 creation + Given I have Fineract-Platform-TenantId as "payerfsp2" + When I create and setup a "payer" with id "3" and account balance of 50 for combine test cases + Given I have tenant as "payerfsp" + Then I call the balance api for payer "3" balance + #payee 3 creation + When I create and setup a "payee" with id "3" and account balance of 20 for combine test cases + Given I have tenant as "payeefsp3" + Then I call the balance api for payee "3" balance for combine test cases + + Then add row to csv with current payer and payee, payment mode as "closedloop" and transfer amount 5 and id 2 for combine test cases + + #payer 4 creation + Given I have Fineract-Platform-TenantId as "payerfsp2" + When I create and setup a "payer" with id "4" and account balance of 50 for combine test cases + Given I have tenant as "payerfsp" + Then I call the balance api for payer "4" balance for combine test cases + #payee 4 creation + When I create and setup a "payee" with id "4" and account balance of 20 for combine test cases + Given I have tenant as "payeefsp3" + Then I call the balance api for payee "4" balance for combine test cases + + Then add row to csv with current payer and payee, payment mode as "closedloop" and transfer amount 5 and id 3 for combine test cases + #payer 5 creation + Given I have Fineract-Platform-TenantId as "payerfsp2" + When I create and setup a "payer" with id "5" and account balance of 50 for combine test cases + Given I have tenant as "payerfsp" + Then I call the balance api for payer "5" balance for combine test cases + #payee 5 creation + When I create and setup a "payee" with id "5" and account balance of 20 for combine test cases + Given I have tenant as "payeefsp3" + Then I call the balance api for payee "5" balance for combine test cases + + Then add row to csv with current payer and payee, payment mode as "closedloop" and transfer amount 5 and id 4 for combine test cases + #Mojaloop + Given I am setting up Mojaloop + #payer and payee 6 for mojaloop [1] + When I create and setup a "payer" with account balance of 12 + When I create and setup a "payee" with account balance of 10 + Then I add "payer" to als + Then I add "payee" to als + Then add row to csv with current payer and payee, payment mode as "mojaloop" and transfer amount 3 and id 5 for combine test cases + + #payer and payee 7 for mojaloop [2] + Then I add "payer" to als + When I create and setup a "payer" with account balance of 120 + Then add row to csv with current payer and payee, payment mode as "mojaloop" and transfer amount 2 and id 6 for combine test cases + + When I create and setup a "payer" with account balance of 66 + When I create and setup a "payee" with account balance of 10 + Then I add "payer" to als + Then I add "payee" to als + Then add last row to csv with current payer and payee, payment mode as "mojaloop" and transfer amount 1 and id 7 + + Given I have Fineract-Platform-TenantId for "payer" + And I create a new clientCorrelationId + And I have private key + And I generate signature + + When I call the batch transactions endpoint with expected status of 202 + Then I should get non empty response + And I am able to parse batch transactions response + And I fetch batch ID from batch transaction API's response + Then I will sleep for 10000 millisecond + Given I have tenant as "payerfsp" + When I call the batch summary API with expected status of 200 with total successfull 8 txns + Then I am able to parse batch summary response + And Status of transaction is "COMPLETED" + And My total txns 8 and successful txn count in response should Match + + + Scenario:BB-FSP 009 Bulk Transfer with ClosedLoop, Real mojaloop and Real GSMA + #payer 1 creation + Given I have Fineract-Platform-TenantId as "payerfsp2" + And I initialize the payee list + When I create and setup a "payer" with id "1" and account balance of 100 for all combine test cases + Given I have tenant as "payerfsp" + Then I call the balance api for payer "1" balance for all combine test cases + #payee 1 creation + When I create and setup a "payee" with id "1" and account balance of 10 for all combine test cases + Given I have tenant as "payeefsp3" + Then I call the balance api for payee "1" balance for all combine test cases + + Then Create a csv file with file name "batchTransactionGsmaClosedLoopMojaloop.csv" + Then add row to csv with current payer and payee, payment mode as "closedloop" and transfer amount 10 and id 0 for all combine test cases + + #payer 2 creation + Given I have Fineract-Platform-TenantId as "payerfsp2" + When I create and setup a "payer" with id "2" and account balance of 50 for all combine test cases + Given I have tenant as "payerfsp" + Then I call the balance api for payer "2" balance for all combine test cases + #payee 2 creation + When I create and setup a "payee" with id "2" and account balance of 20 for all combine test cases + Given I have tenant as "payeefsp3" + Then I call the balance api for payee "2" balance for all combine test cases + + Then add row to csv with current payer and payee, payment mode as "closedloop" and transfer amount 5 and id 1 for all combine test cases + + #payer 3 creation + Given I have Fineract-Platform-TenantId as "payerfsp2" + When I create and setup a "payer" with id "3" and account balance of 50 for all combine test cases + Given I have tenant as "payerfsp" + Then I call the balance api for payer "3" balance for all combine test cases + #payee 3 creation + When I create and setup a "payee" with id "3" and account balance of 20 for all combine test cases + Given I have tenant as "payeefsp3" + Then I call the balance api for payee "3" balance for all combine test cases + + Then add row to csv with current payer and payee, payment mode as "closedloop" and transfer amount 5 and id 2 for all combine test cases + + #payer 4 creation + Given I have Fineract-Platform-TenantId as "payerfsp2" + When I create and setup a "payer" with id "4" and account balance of 50 + Given I have tenant as "payerfsp" + Then I call the balance api for payer "4" balance for all combine test cases + #payee 4 creation + When I create and setup a "payee" with id "4" and account balance of 20 for all combine test cases + Given I have tenant as "payeefsp3" + Then I call the balance api for payee "4" balance for all combine test cases + + Then add row to csv with current payer and payee, payment mode as "closedloop" and transfer amount 5 and id 3 for all combine test cases + #payer 5 creation + Given I have Fineract-Platform-TenantId as "payerfsp2" + When I create and setup a "payer" with id "5" and account balance of 50 for all combine test cases + Given I have tenant as "payerfsp" + Then I call the balance api for payer "5" balance for all combine test cases + #payee 5 creation + When I create and setup a "payee" with id "5" and account balance of 20 for all combine test cases + Given I have tenant as "payeefsp3" + Then I call the balance api for payee "5" balance for all combine test cases + + Then add row to csv with current payer and payee, payment mode as "closedloop" and transfer amount 5 and id 4 for all combine test cases + + #payer 6 creation + Given I have Fineract-Platform-TenantId as "payerfsp2" + When I create and setup a "payer" with id "6" and account balance of 50 for all combine test cases + Given I have tenant as "payerfsp" + Then I call the balance api for payer "6" balance for all combine test cases + #payee 6 creation + When I create and setup a "payee" with id "6" and account balance of 20 for all combine test cases + Given I have tenant as "payeefsp3" + Then I call the balance api for payee "6" balance for all combine test cases + + Then add row to csv with current payer and payee, payment mode as "gsma" and transfer amount 6 and id 5 for all combine test cases + + #payer 7 creation + Given I have Fineract-Platform-TenantId as "payerfsp2" + When I create and setup a "payer" with id "7" and account balance of 50 for all combine test cases + Given I have tenant as "payerfsp" + Then I call the balance api for payer "7" balance for all combine test cases + #payee 7 creation + When I create and setup a "payee" with id "7" and account balance of 20 for all combine test cases + Given I have tenant as "payeefsp3" + Then I call the balance api for payee "7" balance for all combine test cases + + Then add row to csv with current payer and payee, payment mode as "gsma" and transfer amount 7 and id 6 for all combine test cases + #payer 8 creation + Given I have Fineract-Platform-TenantId as "payerfsp2" + When I create and setup a "payer" with id "8" and account balance of 30 for all combine test cases + Given I have tenant as "payerfsp" + Then I call the balance api for payer "8" balance for all combine test cases + #payee 8 creation + When I create and setup a "payee" with id "8" and account balance of 30 for all combine test cases + Given I have tenant as "payeefsp3" + Then I call the balance api for payee "8" balance for all combine test cases + + Then add row to csv with current payer and payee, payment mode as "gsma" and transfer amount 8 and id 7 for all combine test cases + + #payer 9 creation + Given I have Fineract-Platform-TenantId as "payerfsp2" + When I create and setup a "payer" with id "9" and account balance of 50 for all combine test cases + Given I have tenant as "payerfsp" + Then I call the balance api for payer "9" balance for all combine test cases + #payee 9 creation + When I create and setup a "payee" with id "9" and account balance of 20 for all combine test cases + Given I have tenant as "payeefsp3" + Then I call the balance api for payee "9" balance for all combine test cases + + Then add row to csv with current payer and payee, payment mode as "gsma" and transfer amount 9 and id 8 for all combine test cases + #payer 10 creation + Given I have Fineract-Platform-TenantId as "payerfsp2" + When I create and setup a "payer" with id "10" and account balance of 30 for all combine test cases + Given I have tenant as "payerfsp" + Then I call the balance api for payer "10" balance for all combine test cases + #payee 10 creation + When I create and setup a "payee" with id "10" and account balance of 30 for all combine test cases + Given I have tenant as "payeefsp3" + Then I call the balance api for payee "10" balance for all combine test cases + + Then add row to csv with current payer and payee, payment mode as "gsma" and transfer amount 10 and id 9 for all combine test cases + + #Mojaloop batch setup + Given I am setting up Mojaloop + #payer and payee 10 for mojaloop [1] + When I create and setup a "payer" with account balance of 12 + When I create and setup a "payee" with account balance of 10 + Then I add "payer" to als + Then I add "payee" to als + Then add row to csv with current payer and payee, payment mode as "mojaloop" and transfer amount 3 and id 10 for all combine test cases + + #payer and payee 11 for mojaloop [2] + Then I add "payer" to als + When I create and setup a "payer" with account balance of 120 + Then add row to csv with current payer and payee, payment mode as "mojaloop" and transfer amount 2 and id 11 for all combine test cases + + #payer and payee 12 for mojaloop [3] + When I create and setup a "payer" with account balance of 66 + When I create and setup a "payee" with account balance of 10 + Then I add "payer" to als + Then I add "payee" to als + Then add last row to csv with current payer and payee, payment mode as "mojaloop" and transfer amount 1 and id 12 + + #batch process + Given I have tenant as "payerfsp" + And I have the demo csv file "batchTransactionGsmaClosedLoopMojaloop.csv" + And I generate clientCorrelationId + And I have private key + And I generate signature + When I call the batch transactions endpoint with expected status of 202 + And I am able to parse batch transactions response + And I fetch batch ID from batch transaction API's response + Then I will sleep for 10000 millisecond + When I call the batch summary API with expected status of 200 with total successfull 13 txns + Then I should get non empty response + Then I am able to parse batch summary response + And Status of transaction is "COMPLETED" + And My total txns 13 and successful txn count in response should Match diff --git a/ph-ee-integration-test/src/test/java/resources/certificate.feature b/ph-ee-integration-test/src/test/java/resources/certificate.feature new file mode 100644 index 000000000..ccaeefa47 --- /dev/null +++ b/ph-ee-integration-test/src/test/java/resources/certificate.feature @@ -0,0 +1,13 @@ +Feature: Test CertificateUtil + + Scenario: Parse X.509 Certificate + Given I have X509 certificate "MIIDijCCAnICCQCD+e5S4X72PDANBgkqhkiG9w0BAQsFADCBhjELMAkGA1UEBhMCSU4xEjAQBgNVBAgMCUtBUk5BVEFLQTESMBAGA1UEBwwJQkFOR0FMT1JFMREwDwYDVQQKDAhGWU5BUkZJTjEMMAoGA1UECwwDREVWMQswCQYDVQQDDAJOQTEhMB8GCSqGSIb3DQEJARYSREFOSVNIQEZZTkFSRklOLklPMB4XDTIzMDMyODExMzA1NloXDTI0MDMyNzExMzA1NlowgYYxCzAJBgNVBAYTAklOMRIwEAYDVQQIDAlLQVJOQVRBS0ExEjAQBgNVBAcMCUJBTkdBTE9SRTERMA8GA1UECgwIRllOQVJGSU4xDDAKBgNVBAsMA0RFVjELMAkGA1UEAwwCTkExITAfBgkqhkiG9w0BCQEWEkRBTklTSEBGWU5BUkZJTi5JTzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALtG8s4+UWeRZk4AMXSIS3kNo3aGBKStQC2ASRvMo+uv3xjq0irr2BxEzhwJvyk/qqyz6Uch3raaq2/vPFZ9GqAlGVeSHoQbvUeDh9bbpe7S98SWwxo7rKD88jhvKoIRZXdeu3qTQkZWXfeNXRZLCTCB/YLO9htETq+u+L4X5UZ7VCmkYXu5n8a2lBTlxuV9gBs6PNgZ7g/QAQeYLIUKuNg2hujOBZd5/FcGSv6uMEP+iwlFamqkOFg19SnYF0L8KVVTuOPiMs0g0gsXbv7KG1YaE+0ZKC+wU2jS9aWirIMaNA3alU54NGb/cZFXzrB8d0gE2CzcgFo9+XcMuKbOHyECAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAOn6tsJPUrSIDHZ13/jkuzy01bo2pAbLv+yYDBbFfQiI3PH32Y4mlHEBXr/1hZVXe5TuXKMKgYoXfbwWRebdO0OjcUsum4GV4vddTQcvQScBk4UAfplddHtouC5ddelqgenxFW596Ptd1g3Cox0b9hELryaVGYgn68qAf1rRlYUX8WCnZiDF3Fuo1G+yQNeYha2zvUZBotXwVB/JeYeoGmPk0ROb9uFr8gXAYJ1kVzFMzxbldetOocJcCc9yL8mFvjQcyIPIpl5ys2dKVcq7cSr1Do0Y80nbzIhp40bdsCCIz8THkFQ9vuoQPHkpQXsbH7p8NbNM317f1GYLpKTDdbg==" + When I have null certificate + Then I should be able to parse the certificate using CertificateUtils + + Scenario: Parse public key from certificate + Given I have X509 certificate "MIIDijCCAnICCQCD+e5S4X72PDANBgkqhkiG9w0BAQsFADCBhjELMAkGA1UEBhMCSU4xEjAQBgNVBAgMCUtBUk5BVEFLQTESMBAGA1UEBwwJQkFOR0FMT1JFMREwDwYDVQQKDAhGWU5BUkZJTjEMMAoGA1UECwwDREVWMQswCQYDVQQDDAJOQTEhMB8GCSqGSIb3DQEJARYSREFOSVNIQEZZTkFSRklOLklPMB4XDTIzMDMyODExMzA1NloXDTI0MDMyNzExMzA1NlowgYYxCzAJBgNVBAYTAklOMRIwEAYDVQQIDAlLQVJOQVRBS0ExEjAQBgNVBAcMCUJBTkdBTE9SRTERMA8GA1UECgwIRllOQVJGSU4xDDAKBgNVBAsMA0RFVjELMAkGA1UEAwwCTkExITAfBgkqhkiG9w0BCQEWEkRBTklTSEBGWU5BUkZJTi5JTzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALtG8s4+UWeRZk4AMXSIS3kNo3aGBKStQC2ASRvMo+uv3xjq0irr2BxEzhwJvyk/qqyz6Uch3raaq2/vPFZ9GqAlGVeSHoQbvUeDh9bbpe7S98SWwxo7rKD88jhvKoIRZXdeu3qTQkZWXfeNXRZLCTCB/YLO9htETq+u+L4X5UZ7VCmkYXu5n8a2lBTlxuV9gBs6PNgZ7g/QAQeYLIUKuNg2hujOBZd5/FcGSv6uMEP+iwlFamqkOFg19SnYF0L8KVVTuOPiMs0g0gsXbv7KG1YaE+0ZKC+wU2jS9aWirIMaNA3alU54NGb/cZFXzrB8d0gE2CzcgFo9+XcMuKbOHyECAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAOn6tsJPUrSIDHZ13/jkuzy01bo2pAbLv+yYDBbFfQiI3PH32Y4mlHEBXr/1hZVXe5TuXKMKgYoXfbwWRebdO0OjcUsum4GV4vddTQcvQScBk4UAfplddHtouC5ddelqgenxFW596Ptd1g3Cox0b9hELryaVGYgn68qAf1rRlYUX8WCnZiDF3Fuo1G+yQNeYha2zvUZBotXwVB/JeYeoGmPk0ROb9uFr8gXAYJ1kVzFMzxbldetOocJcCc9yL8mFvjQcyIPIpl5ys2dKVcq7cSr1Do0Y80nbzIhp40bdsCCIz8THkFQ9vuoQPHkpQXsbH7p8NbNM317f1GYLpKTDdbg==" + And I can create certificate object + When I parse the public key + Then Public key should be non empty + Then I should be able to get string from publicKey object diff --git a/ph-ee-integration-test/src/test/java/resources/channelClientId.feature b/ph-ee-integration-test/src/test/java/resources/channelClientId.feature new file mode 100644 index 000000000..618235c28 --- /dev/null +++ b/ph-ee-integration-test/src/test/java/resources/channelClientId.feature @@ -0,0 +1,20 @@ +@gov +Feature: Channel Get Txn by Client Id API test + + + Scenario: TS-001 Get Txn based on request type as transfers Test with Auth + Given I have tenant as "paymentBB2" + And I have request type as "transfers" + When I call the txn State with client correlation id as "f1e22fe3-9740-4fba-97b6-78f43bfa7f2f" expected status of 200 + Then I should get non empty response + + + + Scenario: TS-002 Get Txn based on request type as transaction request Test with Auth + Given I have tenant as "paymentBB2" + And I have request type as "transactionsReq" + When I call the txn State with client correlation id as "a2e22fe5-9740-4fba-97b6-78f43bfa7f2f" expected status of 200 + Then I should get non empty response + + + diff --git a/ph-ee-integration-test/src/test/java/resources/channelCollection.feature b/ph-ee-integration-test/src/test/java/resources/channelCollection.feature new file mode 100644 index 000000000..dd351f136 --- /dev/null +++ b/ph-ee-integration-test/src/test/java/resources/channelCollection.feature @@ -0,0 +1,32 @@ +Feature: Channel Collection API test + + + Scenario Outline: Post channel collection API with existing BPMN flows + Given I have tenant as "" + And I have the request body with payer ams identifier keys as "" and "" + When I call the channel collection API with client correlation id and expected status of 200 + Then I should get transaction id in response + + Examples: + | tenant | key1 | key2 | + | gorilla | MSISDN | accountid | + + + Scenario Outline: Post channel collection API with non-existing BPMN flows + Given I have tenant as "" + And I have the request body with payer ams identifier keys as "" and "" + When I call the channel collection API with client correlation id and expected status of 200 + Then I should get transactionId with null value in response + + Examples: + | tenant | key1 | key2 | + | lion | MSISDN | accountid | + + + Scenario: Post channel collection API for Minimal Mock Transfer Request flow + Given I have tenant as "rhino" + And I have the request body with payer ams identifier keys as "MSISDN" and "FOUNDATIONALID" + When I call the channel collection API with client correlation id and expected status of 200 + Then I should get transaction id in response + When I call the get txn API in ops app with transactionId as parameter + Then I should get transaction state as completed and externalId not null \ No newline at end of file diff --git a/ph-ee-integration-test/src/test/java/resources/context.feature b/ph-ee-integration-test/src/test/java/resources/context.feature new file mode 100644 index 000000000..771d8cb53 --- /dev/null +++ b/ph-ee-integration-test/src/test/java/resources/context.feature @@ -0,0 +1,5 @@ +Feature: Testing if context is loaded or not + + Scenario: Checking if application context is starter or not + Given I can autowire the object mapper bean + Then Application context should be not null diff --git a/ph-ee-integration-test/src/test/java/resources/getTransfer.feature b/ph-ee-integration-test/src/test/java/resources/getTransfer.feature new file mode 100644 index 000000000..6932586fe --- /dev/null +++ b/ph-ee-integration-test/src/test/java/resources/getTransfer.feature @@ -0,0 +1,12 @@ +@common @gov +@cucumberCli +Feature: Get Transfers API test + + + Scenario: GT-001 Get Transfers API With Auth + Given I have tenant as "paymentBB2" + When I call the operations-app auth endpoint with username: "mifos" and password: "password" + Then I should get a valid token + When I call the transfer API with expected status of 200 + Then I should get non empty response + And I should have clientCorrelationId in response diff --git a/ph-ee-integration-test/src/test/java/resources/getTxn.feature b/ph-ee-integration-test/src/test/java/resources/getTxn.feature new file mode 100644 index 000000000..e0fb56ecf --- /dev/null +++ b/ph-ee-integration-test/src/test/java/resources/getTxn.feature @@ -0,0 +1,21 @@ + +@common @gov +Feature: Get Txn Req API test + + Scenario: GTX-001 Get Txn Req API Test With Auth + Given I have tenant as "paymentbb2" + And I call collection api with expected status 200 + When I call the operations-app auth endpoint with username: "mifos" and password: "password" + Then I should get a valid token + When I call the get txn API with expected status of 200 + Then I should get non empty response + And I should have clientCorrelationId in response + + + Scenario: GTX-002 Get Txn Req API with Params + Given I have tenant as "paymentbb2" + When I call the operations-app auth endpoint with username: "mifos" and password: "password" + Then I should get a valid token + When I call the get txn API with date today minus 2 day and "current date" with expected status of 200 + Then I should get non empty response + And I should have startedAt and completedAt in response diff --git a/ph-ee-integration-test/src/test/java/resources/gsmaP2P.feature b/ph-ee-integration-test/src/test/java/resources/gsmaP2P.feature new file mode 100644 index 000000000..eaddd9f4b --- /dev/null +++ b/ph-ee-integration-test/src/test/java/resources/gsmaP2P.feature @@ -0,0 +1,159 @@ +@amsIntegration @govtodo + +Feature: GSMA Outbound Transfer test + + Scenario: GSMA Withdrawal Transfer testx (Payer Debit only) + Given I have Fineract-Platform-TenantId as "payerfsp1" + When I create a set of debit and credit party + When I call the create payer client endpoint + Then I call the create savings product endpoint + When I call the create savings account endpoint + Then I call the debit interop identifier endpoint with MSISDN + Then I approve the deposit with command "approve" + When I activate the account with command "activate" + Then I call the deposit account endpoint with command "deposit" for amount 100 + # Below section creates the Payee + Given I have Fineract-Platform-TenantId as "payeefsp3" + When I call the create payer client endpoint + Then I call the create savings product endpoint + When I call the create savings account endpoint + Then I call the credit interop identifier endpoint with MSISDN + Then I approve the deposit with command "approve" + When I activate the account with command "activate" + Then I call the deposit account endpoint for "payer" with command "deposit" for amount 100 + Given I have tenant as "payerfsp" + Then I call the balance api for payer balance + Given I have tenant as "payerfsp" + When I can create GSMATransferDTO with different payer and payee + Then I call the GSMATransfer endpoint with expected status of 200 + And I should be able to parse transactionId from response + Given I have tenant as "payerfsp" + When I call the transfer query endpoint with transactionId and expected status of 200 + Given I have tenant as "payerfsp" + Then I call the balance api for payer balance after debit + + Scenario: GSMA Deposit Transfer test + Given I have Fineract-Platform-TenantId as "payerfsp1" + When I create a set of debit and credit party + When I call the create payer client endpoint + Then I call the create savings product endpoint + When I call the create savings account endpoint + Then I call the debit interop identifier endpoint with MSISDN + Then I approve the deposit with command "approve" + When I activate the account with command "activate" + Then I call the deposit account endpoint for "payee" with command "deposit" for amount 100 + Given I have Fineract-Platform-TenantId as "payeefsp3" + When I call the create payer client endpoint + Then I call the create savings product endpoint + When I call the create savings account endpoint + Then I call the credit interop identifier endpoint with MSISDN + Then I approve the deposit with command "approve" + When I activate the account with command "activate" + Then I call the deposit account endpoint with command "deposit" for amount 100 + Given I have tenant as "payeefsp3" + Then I call the balance api for payee balance + Given I have tenant as "payeefsp3" + When I can create GSMATransferDTO with different payer and payee + Then I call the GSMATransfer Deposit endpoint with expected status of 200 + Given I have tenant as "payeefsp3" + Then I call the balance api for payee balance after credit + + Scenario: GSMA Deposit-Withdrawal Transfer test + Given I have Fineract-Platform-TenantId as "payerfsp1" + When I create a set of debit and credit party + When I call the create payer client endpoint + Then I call the create savings product endpoint + When I call the create savings account endpoint + Then I call the debit interop identifier endpoint with MSISDN + Then I approve the deposit with command "approve" + When I activate the account with command "activate" + Then I call the deposit account endpoint for "payer" with command "deposit" for amount 100 + Given I have Fineract-Platform-TenantId as "payeefsp3" + When I call the create payer client endpoint + Then I call the create savings product endpoint + When I call the create savings account endpoint + Then I call the credit interop identifier endpoint with MSISDN + Then I approve the deposit with command "approve" + When I activate the account with command "activate" + Then I call the deposit account endpoint for "payee" with command "deposit" for amount 100 + Given I have tenant as "payerfsp" + Then I call the balance api for payer balance + Given I have tenant as "payeefsp3" + Then I call the balance api for payee balance + Given I have tenant as "payerfsp" + When I can create GSMATransferDTO with different payer and payee + Then I call the GSMATransfer endpoint with expected status of 200 + And I should be able to parse transactionId from response + Given I have tenant as "payerfsp" + When I call the transfer query endpoint with transactionId and expected status of 200 + Given I have tenant as "payerfsp" + Then I call the balance api for payer balance after debit + Given I have tenant as "payeefsp3" + Then I call the balance api for payee balance after credit + + @batch-teardown + Scenario: Bulk Transfer with GSMA + #payer 1 creation + Given I have Fineract-Platform-TenantId as "payerfsp2" + When I create and setup a "payer" with id "1" and account balance of 100 + Given I have tenant as "payerfsp" + Then I call the balance api for payer "1" balance + #payee 1 creation + When I create and setup a "payee" with id "1" and account balance of 10 + Given I have tenant as "payeefsp3" + Then I call the balance api for payee "1" balance + + Then Create a csv file with file name "batchTransactionGsma.csv" + Then add row to csv with current payer and payee, payment mode as "gsma" and transfer amount 10 and id 0 + + #payer 2 creation + Given I have Fineract-Platform-TenantId as "payerfsp2" + When I create and setup a "payer" with id "2" and account balance of 50 + Given I have tenant as "payerfsp" + Then I call the balance api for payer "2" balance + #payee 2 creation + When I create and setup a "payee" with id "2" and account balance of 20 + Given I have tenant as "payeefsp3" + Then I call the balance api for payee "2" balance + + Then add row to csv with current payer and payee, payment mode as "gsma" and transfer amount 5 and id 1 + #payer 3 creation + Given I have Fineract-Platform-TenantId as "payerfsp2" + When I create and setup a "payer" with id "3" and account balance of 30 + Given I have tenant as "payerfsp" + Then I call the balance api for payer "3" balance + #payee 3 creation + When I create and setup a "payee" with id "3" and account balance of 30 + Given I have tenant as "payeefsp3" + Then I call the balance api for payee "3" balance + + Then add last row to csv with current payer and payee, payment mode as "gsma" and transfer amount 1 and id 2 + #batch process + Given I have tenant as "payerfsp" + And I have the demo csv file "batchTransactionGsma.csv" + And I generate clientCorrelationId + And I have private key + And I generate signature + When I call the batch transactions endpoint with expected status of 202 + And I am able to parse batch transactions response + And I fetch batch ID from batch transaction API's response + When I call the batch summary API for gsma with expected status of 200 with total 3 txns + Then I should get non empty response + Then I am able to parse batch summary response + And Status of transaction is "COMPLETED" + And I should have matching total txn count and successful txn count in response + #payer debit check + Given I have tenant as "payerfsp" + Then I call the balance api for payer with id "1" balance after debit + Given I have tenant as "payerfsp" + Then I call the balance api for payer with id "2" balance after debit + Given I have tenant as "payerfsp" + Then I call the balance api for payer with id "3" balance after debit + #payee credit check + Given I have tenant as "payeefsp3" + Then I call the balance api for payee with id "1" balance after credit + Given I have tenant as "payeefsp3" + Then I call the balance api for payee with id "2" balance after credit + Given I have tenant as "payeefsp3" + Then I call the balance api for payee with id "3" balance after credit + diff --git a/ph-ee-integration-test/src/test/java/resources/gsmaTxn.feature b/ph-ee-integration-test/src/test/java/resources/gsmaTxn.feature new file mode 100644 index 000000000..9b04ff7c2 --- /dev/null +++ b/ph-ee-integration-test/src/test/java/resources/gsmaTxn.feature @@ -0,0 +1,43 @@ +@common @amsIntegration +Feature: GSMA Transfer API Test for Account Identifier Worker + + Background: I will start mock server and register stub + Given I will start the mock server + And I can register the stub with "/depositCallback" endpoint for "POST" request with status of 200 + And I can register the stub with "/loanCallback" endpoint for "POST" request with status of 200 + + Scenario: Savings account Creation Test + Given I have Fineract-Platform-TenantId as "payerfsp1" + When I call the create payer client endpoint + Then I call the create savings product endpoint + When I call the create savings account endpoint + Then I call the interop identifier endpoint + Then I approve the deposit with command "approve" + When I activate the account with command "activate" + Then I call the deposit account endpoint with command "deposit" for amount 11 +# Savings account deposit using BPMN workflow. + When I have amsName as "mifos" and acccountHoldingInstitutionId as "wakanda" and amount as 11 + Then I call the channel connector API for savings account with expected status of 200 and stub "/depositCallback" + Then I will sleep for 3000 millisecond + Then I should be able to verify that the "POST" method to "/depositCallback" endpoint received 1 request + + + Scenario: Loan account Creation Test + Given I have Fineract-Platform-TenantId as "payerfsp1" + And I call the create loan product endpoint + When I call the create loan account + Then I approve the loan account with command "approve" for amount 7800 + When I call the loan disburse endpoint with command "disburse" for amount 7800 + Then I call the loan repayment endpoint for amount 21 +# Loan account repayment using BPMN workflow. + When I have amsName as "mifos" and acccountHoldingInstitutionId as "wakanda" and amount as 11 + Then I call the channel connector API for loan account with expected status of 200 and stub "/loanCallback" + Then I will sleep for 3000 millisecond + Then I should be able to verify that the "POST" method to "/loanCallback" endpoint received 1 request + +# AMS Mock API call integration test + Scenario: AMS Mifos Deposit Mock API Call Test + When I call the AMS Mifos Deposit Mock API with expected status of 200 + + Scenario: AMS Mifos Loan Repayment Mock API Call Test + When I call the AMS Mifos Loan Repayment Mock API with expected status of 200 diff --git a/ph-ee-integration-test/src/test/java/resources/idempotency1.feature b/ph-ee-integration-test/src/test/java/resources/idempotency1.feature new file mode 100644 index 000000000..3855d18ba --- /dev/null +++ b/ph-ee-integration-test/src/test/java/resources/idempotency1.feature @@ -0,0 +1,11 @@ +Feature: Client Correlation Id Idempotency Test + +@application.yaml + + Scenario: IT-001 Collection API Idempotency Test + Given I create a new clientCorrelationId + And I have tenant as "gorilla" + When I call collection api with client correlation id expected status 200 + Given I have same clientCorrelationId + When I call collection api to fail with client correlation id expected status 400 + Then I should have error as Transaction already Exists diff --git a/ph-ee-integration-test/src/test/java/resources/idempotency2.feature b/ph-ee-integration-test/src/test/java/resources/idempotency2.feature new file mode 100644 index 000000000..634d0c023 --- /dev/null +++ b/ph-ee-integration-test/src/test/java/resources/idempotency2.feature @@ -0,0 +1,12 @@ +Feature: Client Correlation Id Idempotency Test + +@application.yaml + + Scenario: IT-002 Gsma Transaction API Idempotency Test + Given I create a new clientCorrelationId + And I have tenant as "gorilla" + When I call gsma transaction api with client correlation id expected status 200 + Given I have same clientCorrelationId + When I call gsma transaction to fail with client correlation id expected status 400 + Then I should have error as Transaction already Exists + diff --git a/ph-ee-integration-test/src/test/java/resources/idempotency3.feature b/ph-ee-integration-test/src/test/java/resources/idempotency3.feature new file mode 100644 index 000000000..c26580739 --- /dev/null +++ b/ph-ee-integration-test/src/test/java/resources/idempotency3.feature @@ -0,0 +1,13 @@ +@govtodo +Feature: Client Correlation Id Idempotency Test + +@application.yaml + + Scenario: IT-003 Inbound Transfer API Idempotency Test + Given I create a new clientCorrelationId + And I have tenant as "gorilla" + Given I can mock TransactionChannelRequestDTO + When I call inbound transfer api with client correlation id expected status 200 + Given I have same clientCorrelationId + When I call inbound transfer api with client correlation id expected status 400 + Then I should have error as Transaction already Exists \ No newline at end of file diff --git a/ph-ee-integration-test/src/test/java/resources/idempotency4.feature b/ph-ee-integration-test/src/test/java/resources/idempotency4.feature new file mode 100644 index 000000000..f34516060 --- /dev/null +++ b/ph-ee-integration-test/src/test/java/resources/idempotency4.feature @@ -0,0 +1,11 @@ +Feature: Client Correlation Id Idempotency Test + +@application.yaml + + Scenario: IT-004 Inbound Transfer Req API Idempotency Test + Given I create a new clientCorrelationId + And I have tenant as "gorilla" + When I call Inbound transaction Req api with client correlation id expected status 200 + Given I have same clientCorrelationId + When I call Inbound transaction Req api with client correlation id expected status 400 + Then I should have error as Transaction already Exists diff --git a/ph-ee-integration-test/src/test/java/resources/identityMapperTest.feature b/ph-ee-integration-test/src/test/java/resources/identityMapperTest.feature new file mode 100644 index 000000000..553102ad4 --- /dev/null +++ b/ph-ee-integration-test/src/test/java/resources/identityMapperTest.feature @@ -0,0 +1,305 @@ + +Feature: Identity Account Mapper Api Test + + Background: I will start mock server and register stub + Given I will start the mock server + And I can register the stub with "/registerBeneficiaryApiTest" endpoint for "PUT" request with status of 200 + And I can register the stub with "/addPaymentModalityApiTest" endpoint for "PUT" request with status of 200 + And I can register the stub with "/updatePaymentModalityApiTest" endpoint for "PUT" request with status of 200 + And I can register the stub with "/accountLookupTest" endpoint for "PUT" request with status of 200 + And I can register the stub with "/accountLookup" endpoint for "PUT" request with status of 200 + And I can register the stub with "/batchAccountLookup" endpoint for "PUT" request with status of 200 + And I can register the stub with "/updateBeneficiaryApiTest" endpoint for "PUT" request with status of 200 + Then I will update the mock server and register stub as done + + @gov + Scenario: IAM-001 Register Beneficiary Api Test + Given I create an IdentityMapperDTO for Register Beneficiary + When I call the register beneficiary API with expected status of 202 and stub "/registerBeneficiaryApiTest" +# Then I will sleep for 7000 millisecond + And I should be able to verify that the "PUT" method to "/registerBeneficiaryApiTest" endpoint received a request with required parameter in body + @gov + Scenario: IAM-002 Add Payment Modality Api Test + Given I create an IdentityMapperDTO for Add Payment Modality + When I call the add payment modality API with expected status of 202 and stub "/addPaymentModalityApiTest" +# Then I will sleep for 3000 millisecond + And I should be able to verify that the "PUT" method to "/addPaymentModalityApiTest" endpoint received a request with required parameter in body + @gov + Scenario: IAM-003 Update Payment Modality Api Test + Given I create an IdentityMapperDTO for Update Payment Modality + When I call the update payment modality API with expected status of 202 and stub "/updatePaymentModalityApiTest" +# Then I will sleep for 3000 millisecond + And I should be able to verify that the "PUT" method to "/updatePaymentModalityApiTest" endpoint received a request with required parameter in body + @gov + Scenario: PPV-11/IAM-004 Account Lookup Api Test + When I call the account lookup API with expected status of 202 and stub "/accountLookupTest" +# Then I will sleep for 3000 millisecond + And I should be able to verify that the "PUT" method to "/accountLookupTest" endpoint received a request with same payeeIdentity + + @gov + Scenario: UB-003 Update a single beneficiary with Payment Modality - Mobile Money + When I create an IdentityMapperDTO for 1 Register Beneficiary with payment modality as "ACCOUNT_ID" + When I call the register beneficiary API with expected status of 202 and stub "/registerBeneficiaryApiTest" + When I create an IdentityMapperDTO for 1 update Beneficiary with payment modality as "MSISDN" + When I call the update beneficiary API with expected status of 202 and stub "/updateBeneficiaryApiTest" +# Then I will sleep for 3000 millisecond + Then I should be able to verify that the "PUT" method to "/updateBeneficiaryApiTest" endpoint received a request with required parameter in body + @gov + Scenario: UB-004 Update a single beneficiary with Payment Modality - Voucher + When I create an IdentityMapperDTO for 1 Register Beneficiary with payment modality as "MSISDN" + When I call the register beneficiary API with expected status of 202 and stub "/registerBeneficiaryApiTest" + When I create an IdentityMapperDTO for 1 update Beneficiary with payment modality as "VOUCHER" + When I call the update beneficiary API with expected status of 202 and stub "/updateBeneficiaryApiTest" +# Then I will sleep for 3000 millisecond + Then I should be able to verify that the "PUT" method to "/updateBeneficiaryApiTest" endpoint received a request with required parameter in body + @gov + Scenario: UB-006 Update a single beneficiary with Payment Modality - Proxy or Virtual Address + When I create an IdentityMapperDTO for 1 Register Beneficiary with payment modality as "VOUCHER" + When I call the register beneficiary API with expected status of 202 and stub "/registerBeneficiaryApiTest" + When I create an IdentityMapperDTO for 1 update Beneficiary with payment modality as "VIRTUAL_ADDRESS" + When I call the update beneficiary API with expected status of 202 and stub "/updateBeneficiaryApiTest" +# Then I will sleep for 3000 millisecond + Then I should be able to verify that the "PUT" method to "/updateBeneficiaryApiTest" endpoint received a request with required parameter in body + @gov + Scenario: UB-005 Update a single beneficiary with Payment Modality - Digital Wallet + When I create an IdentityMapperDTO for 1 Register Beneficiary with payment modality as "VOUCHER" + When I call the register beneficiary API with expected status of 202 and stub "/registerBeneficiaryApiTest" + When I create an IdentityMapperDTO for 1 update Beneficiary with payment modality as "WALLET_ID" + When I call the update beneficiary API with expected status of 202 and stub "/updateBeneficiaryApiTest" +# Then I will sleep for 3000 millisecond + Then I should be able to verify that the "PUT" method to "/updateBeneficiaryApiTest" endpoint received a request with required parameter in body + @gov + Scenario: UB-009 Update multiple beneficiary with Payment Modality - Mobile Money + When I create an IdentityMapperDTO for 4 Register Beneficiary with payment modality as "ACCOUNT_ID" + When I call the register beneficiary API with expected status of 202 and stub "/registerBeneficiaryApiTest" + When I create an IdentityMapperDTO for 4 update Beneficiary with payment modality as "MSISDN" + When I call the update beneficiary API with expected status of 202 and stub "/updateBeneficiaryApiTest" +# Then I will sleep for 3000 millisecond + Then I should be able to verify that the "PUT" method to "/updateBeneficiaryApiTest" endpoint received a request with required parameter in body + @gov + Scenario: UB-010 Update multiple beneficiary with Payment Modality - Voucher + When I create an IdentityMapperDTO for 4 Register Beneficiary with payment modality as "MSISDN" + When I call the register beneficiary API with expected status of 202 and stub "/registerBeneficiaryApiTest" + When I create an IdentityMapperDTO for 4 update Beneficiary with payment modality as "VOUCHER" + When I call the update beneficiary API with expected status of 202 and stub "/updateBeneficiaryApiTest" +# Then I will sleep for 3000 millisecond + Then I should be able to verify that the "PUT" method to "/updateBeneficiaryApiTest" endpoint received a request with required parameter in body + @gov + Scenario: UB-011 Update multiple beneficiary with Payment Modality - Digital Wallet + When I create an IdentityMapperDTO for 4 Register Beneficiary with payment modality as "VOUCHER" + When I call the register beneficiary API with expected status of 202 and stub "/registerBeneficiaryApiTest" + When I create an IdentityMapperDTO for 4 update Beneficiary with payment modality as "WALLET_ID" + When I call the update beneficiary API with expected status of 202 and stub "/updateBeneficiaryApiTest" +# Then I will sleep for 3000 millisecond + Then I should be able to verify that the "PUT" method to "/updateBeneficiaryApiTest" endpoint received a request with required parameter in body + @gov + Scenario: UB-012 Update multiple beneficiary with Payment Modality - Proxy or Virtual Address + When I create an IdentityMapperDTO for 4 Register Beneficiary with payment modality as "WALLET_ID" + When I call the register beneficiary API with expected status of 202 and stub "/registerBeneficiaryApiTest" + When I create an IdentityMapperDTO for 4 update Beneficiary with payment modality as "VIRTUAL_ADDRESS" + When I call the update beneficiary API with expected status of 202 and stub "/updateBeneficiaryApiTest" +# Then I will sleep for 3000 millisecond + Then I should be able to verify that the "PUT" method to "/updateBeneficiaryApiTest" endpoint received a request with required parameter in body + @gov + Scenario: Update a single beneficiary with Banking Institution Code + When I create an IdentityMapperDTO for 1 Register Beneficiary with payment modality as "ACCOUNT_ID" + When I call the register beneficiary API with expected status of 202 and stub "/registerBeneficiaryApiTest" + When I create an IdentityMapperDTO for 1 update Beneficiary with banking institution code as "lion" + When I call the update beneficiary API with expected status of 202 and stub "/updateBeneficiaryApiTest" +# Then I will sleep for 3000 millisecond + Then I should be able to verify that the "PUT" method to "/updateBeneficiaryApiTest" endpoint received a request with required parameter in body + @gov + Scenario: UB-002 Update a single beneficiary with Financial Address + When I create an IdentityMapperDTO for 1 Register Beneficiary with payment modality as "ACCOUNT_ID" + When I call the register beneficiary API with expected status of 202 and stub "/registerBeneficiaryApiTest" + When I create an IdentityMapperDTO for 1 update Beneficiary with financial address code as "123456789" + When I call the update beneficiary API with expected status of 202 and stub "/updateBeneficiaryApiTest" +# Then I will sleep for 3000 millisecond + Then I should be able to verify that the "PUT" method to "/updateBeneficiaryApiTest" endpoint received a request with required parameter in body + @gov + Scenario: UB-008 Update a multiple beneficiary with Financial Address + When I create an IdentityMapperDTO for 4 Register Beneficiary with payment modality as "ACCOUNT_ID" + When I call the register beneficiary API with expected status of 202 and stub "/registerBeneficiaryApiTest" + When I create an IdentityMapperDTO for 4 update Beneficiary with financial address code as "123456789" + When I call the update beneficiary API with expected status of 202 and stub "/updateBeneficiaryApiTest" +# Then I will sleep for 3000 millisecond + Then I should be able to verify that the "PUT" method to "/updateBeneficiaryApiTest" endpoint received a request with required parameter in body + @gov + Scenario: RB-001 Register a single beneficiary with Payment Modality - Bank Account + When I create an IdentityMapperDTO for 1 Register Beneficiary with payment modality as "ACCOUNT_ID" + When I call the register beneficiary API with expected status of 202 and stub "/registerBeneficiaryApiTest" +# Then I will sleep for 3000 millisecond + Then I should be able to verify that the "PUT" method to "/registerBeneficiaryApiTest" endpoint received a request with required parameter in body + @gov + Scenario: RB-002 Register a single beneficiary with Payment Modality - Mobile Money Account + When I create an IdentityMapperDTO for 1 Register Beneficiary with payment modality as "MSISDN" + When I call the register beneficiary API with expected status of 202 and stub "/registerBeneficiaryApiTest" +# Then I will sleep for 3000 millisecond + Then I should be able to verify that the "PUT" method to "/registerBeneficiaryApiTest" endpoint received a request with required parameter in body + @gov + Scenario: RB-003 Register a single beneficiary with Payment Modality - Proxy or Virtual Address + When I create an IdentityMapperDTO for 1 Register Beneficiary with payment modality as "VIRTUAL_ADDRESS" + When I call the register beneficiary API with expected status of 202 and stub "/registerBeneficiaryApiTest" +# Then I will sleep for 3000 millisecond + Then I should be able to verify that the "PUT" method to "/registerBeneficiaryApiTest" endpoint received a request with required parameter in body + @gov + Scenario: RB-004 Register a single beneficiary with Payment Modality - Digital Wallet ID + When I create an IdentityMapperDTO for 1 Register Beneficiary with payment modality as "WALLET_ID" + When I call the register beneficiary API with expected status of 202 and stub "/registerBeneficiaryApiTest" +# Then I will sleep for 3000 millisecond + Then I should be able to verify that the "PUT" method to "/registerBeneficiaryApiTest" endpoint received a request with required parameter in body + @gov + Scenario: RB-005 Register a single beneficiary with Payment Modality - Voucher + When I create an IdentityMapperDTO for 1 Register Beneficiary with payment modality as "VOUCHER" + When I call the register beneficiary API with expected status of 202 and stub "/registerBeneficiaryApiTest" +# Then I will sleep for 3000 millisecond + Then I should be able to verify that the "PUT" method to "/registerBeneficiaryApiTest" endpoint received a request with required parameter in body + @gov + Scenario: RB-006 Register multiple beneficiary with Payment Modality - Bank Account + When I create an IdentityMapperDTO for 5 Register Beneficiary with payment modality as "ACCOUNT_ID" + When I call the register beneficiary API with expected status of 202 and stub "/registerBeneficiaryApiTest" +# Then I will sleep for 3000 millisecond + Then I should be able to verify that the "PUT" method to "/registerBeneficiaryApiTest" endpoint received a request with required parameter in body + @gov + Scenario: RB-007 Register multiple beneficiary with Payment Modality - Mobile Money Account + When I create an IdentityMapperDTO for 5 Register Beneficiary with payment modality as "MSISDN" + When I call the register beneficiary API with expected status of 202 and stub "/registerBeneficiaryApiTest" +# Then I will sleep for 3000 millisecond + Then I should be able to verify that the "PUT" method to "/registerBeneficiaryApiTest" endpoint received a request with required parameter in body + @gov + Scenario: RB-008 Register multiple beneficiary with Payment Modality - Proxy or Virtual Address + When I create an IdentityMapperDTO for 5 Register Beneficiary with payment modality as "VIRTUAL_ADDRESS" + When I call the register beneficiary API with expected status of 202 and stub "/registerBeneficiaryApiTest" +# Then I will sleep for 3000 millisecond + Then I should be able to verify that the "PUT" method to "/registerBeneficiaryApiTest" endpoint received a request with required parameter in body + @gov + Scenario: RB-009 Register multiple beneficiary with Payment Modality - Digital Wallet ID + When I create an IdentityMapperDTO for 5 Register Beneficiary with payment modality as "WALLET_ID" + When I call the register beneficiary API with expected status of 202 and stub "/registerBeneficiaryApiTest" +# Then I will sleep for 3000 millisecond + Then I should be able to verify that the "PUT" method to "/registerBeneficiaryApiTest" endpoint received a request with required parameter in body + @gov + Scenario: RB-010 Register multiple beneficiary with Payment Modality - Voucher + When I create an IdentityMapperDTO for 5 Register Beneficiary with payment modality as "VOUCHER" + When I call the register beneficiary API with expected status of 202 and stub "/registerBeneficiaryApiTest" +# Then I will sleep for 3000 millisecond + Then I should be able to verify that the "PUT" method to "/registerBeneficiaryApiTest" endpoint received a request with required parameter in body + @gov + Scenario: PPV-04 Invalid Registering Institution Id + When I create an IdentityMapperDTO for adding 8 beneficiary + When I call the register beneficiary API with "SocialWelfare" as registering institution id expected status of 202 and stub "/registerBeneficiaryApiTest" + And I create an IdentityMapperDTO for adding 2 beneficiary + When I call the register beneficiary API with "Social" as registering institution id expected status of 202 and stub "/registerBeneficiaryApiTest" + And I create request body for batch account lookup API + Then I call bulk account lookup API with these 10 beneficiaries and "Social" as registering institution id and stub "/batchAccountLookup" +# Then I will sleep for 3000 millisecond + And I should be able to verify that the "PUT" method to "/batchAccountLookup" receive 2 request + @gov + Scenario: PPV-02 Beneficiary not registered + When I create an IdentityMapperDTO for adding 8 beneficiary + When I call the register beneficiary API with "SocialWelfare" as registering institution id expected status of 202 and stub "/registerBeneficiaryApiTest" + And I create an IdentityMapperDTO for adding 2 beneficiary + And I create request body for batch account lookup API + Then I call bulk account lookup API with these 10 beneficiaries and "SocialWelfare" as registering institution id and stub "/beneficiaryNotRegistered" +# Then I will sleep for 3000 millisecond + And I should be able to verify that the "PUT" method to "/beneficiaryNotRegistered" receive 8 request + @gov + Scenario: PPV-02 Batch Account Lookup API + When I create an IdentityMapperDTO for adding 8 beneficiary + When I call the register beneficiary API with "SocialWelfare" as registering institution id expected status of 202 and stub "/registerBeneficiaryApiTest" + And I create request body for batch account lookup API + Then I call bulk account lookup API with these 8 beneficiaries and "SocialWelfare" as registering institution id and stub "/batchAccountLookup" +# Then I will sleep for 3000 millisecond + And I should be able to verify that the "PUT" method to "/batchAccountLookup" receive 8 request + @gov + Scenario: PPV-003 Account lookup with GSMA + Given I have Fineract-Platform-TenantId as "payeefsp1" + When I call the create payer client endpoint + Then I call the create savings product endpoint + When I call the create savings account endpoint + Then I call the interop identifier endpoint + Then I approve the deposit with command "approve" + When I activate the account with command "activate" + Then I create an IdentityMapperDTO for Register Beneficiary with identifier from previous step + When I call the register beneficiary API with expected status of 202 and callback stub "/registerBeneficiaryApiTest" +# And I will sleep for 3000 millisecond + Then I call the account lookup API with expected status of 202 and callback stub "/accountLookupTest" +# And I will sleep for 3000 millisecond + And I should be able to verify that the "PUT" method to "/accountLookupTest" endpoint received a request with validation + + @gov + Scenario: Fetch Beneficiaries API Test + Given I create an IdentityMapperDTO for Register Beneficiary + When I call the register beneficiary API with expected status of 202 and stub "/registerBeneficiaryApiTest" +# And I will sleep for 3000 millisecond + Then I will call the fetch beneficiary API with expected status of 200 + And I will assert the fields from fetch beneficiary response + @gov @ext + Scenario: Batch Account Lookup Integration Test + Given I create an IdentityMapperDTO for Register Beneficiary from csv file + When I call the register beneficiary API with expected status of 202 and stub "/registerBeneficiaryApiTest" +# And I will sleep for 3000 millisecond + Given I have tenant as "paymentBB1" + And I have the demo csv file "ph-ee-bulk-demo-7.csv" + And I create a new clientCorrelationId + And I have private key + And I generate signature + When I call the batch transactions endpoint with expected status of 202 + And I am able to parse batch transactions response + And I fetch batch ID from batch transaction API's response +# Then I will sleep for 10000 millisecond + And I call the payment batch detail API with expected status of 200 with total 3 txns + Then I am able to parse payment batch detail response + And I should assert total txn count and successful txn count in payment batch detail response for batch account lookup + + @gov + Scenario: RB-011 Attempt to Register a 5 Beneficiary - 4 with a valid RegistrationInstitution and 1 with a invalid RegistrationInstitution not available in PayBB + When I create an IdentityMapperDTO for 4 Register Beneficiary with payment modality as "VOUCHER" and 1 with invalid functionalID + When I call the register beneficiary API with expected status of 202 and stub "/registerBeneficiaryApiTest" +# Then I will sleep for 3000 millisecond + Then I should be able to verify that the "PUT" method to "/registerBeneficiaryApiTest" endpoint received a request with no of failed cases as 1 + @gov + Scenario: RB-012 Attempt to Register a 5 Beneficiary - 4 with a valid format of FunctionalID and 1 with a invalid FunctionalID (not properly formatted) + When I create an IdentityMapperDTO for 4 Register Beneficiary with payment modality as "VOUCHER" and 1 with invalid functionalID + When I call the register beneficiary API with expected status of 202 and stub "/registerBeneficiaryApiTest" +# Then I will sleep for 3000 millisecond + Then I should be able to verify that the "PUT" method to "/registerBeneficiaryApiTest" endpoint received a request with no of failed cases as 1 + @gov + Scenario: RB-013 Attempt to Register a 5 Beneficiary - 4 with a valid format of FunctionalID and 1 with a invalid FunctionalID (not properly formatted) + When I create an IdentityMapperDTO for 2 Register Beneficiary with payment modality as "VOUCHER" and 1 with invalid payment modality + When I call the register beneficiary API with expected status of 202 and stub "/registerBeneficiaryApiTest" +# Then I will sleep for 3000 millisecond + Then I should be able to verify that the "PUT" method to "/registerBeneficiaryApiTest" endpoint received a request with no of failed cases as 1 + @gov + Scenario: RB-015 Attempt to register 10 Beneficiary, 8 Beneficiaries have been registered - 2 of them have been already registered (duplication of beneficiaries functional ID) + When I create an IdentityMapperDTO for 2 Register Beneficiary with payment modality as "VOUCHER" + When I call the register beneficiary API with expected status of 202 and stub "/registerBeneficiaryApiTest" + When I create an IdentityMapperDTO for 8 Register Beneficiary with payment modality as "VOUCHER" and 2 existing beneficiary + When I call the register beneficiary API with expected status of 202 and stub "/registerBeneficiaryApiTest" +# Then I will sleep for 3000 millisecond + Then I should be able to verify that the "PUT" method to "/registerBeneficiaryApiTest" endpoint received a request with no of failed cases as 2 + @gov + Scenario: UB-014 Attempt to update 10 Beneficiaries, 8 are successfully registered while 2 have invalid financial address. (not in correct format) + When I create an IdentityMapperDTO for 10 Register Beneficiary with payment modality as "ACCOUNT_ID" + When I call the register beneficiary API with expected status of 202 and stub "/registerBeneficiaryApiTest" + When I create an IdentityMapperDTO for 8 update Beneficiary with correct financial address code and 2 with incorrect Financial address + When I call the update beneficiary API with expected status of 202 and stub "/updateBeneficiaryApiTest" +# Then I will sleep for 3000 millisecond + Then I should be able to verify that the "PUT" method to "/updateBeneficiaryApiTest" endpoint received a request with no of failed cases as 2 + @gov + Scenario: UB-015 Attempt to update 10 Beneficiaries, 8 are successfully registered while 2 have invalid payment modality (not equal to 01,02,03,04,05). + When I create an IdentityMapperDTO for 10 Register Beneficiary with no payment modality + When I call the register beneficiary API with expected status of 202 and stub "/registerBeneficiaryApiTest" + When I create an IdentityMapperDTO for 8 update Beneficiary with correct payment modality and 2 with incorrect payment modality + When I call the update beneficiary API with expected status of 202 and stub "/updateBeneficiaryApiTest" +# Then I will sleep for 3000 millisecond + Then I should be able to verify that the "PUT" method to "/updateBeneficiaryApiTest" endpoint received a request with no of failed cases as 2 + + @gov + Scenario: IAM-005 Account Lookup Api Consistency Test + When I call the account lookup API 10 times with expected status of 202 and stub "/accountLookup" +# Then I will sleep for 3000 millisecond + And I can stop mock server + + + diff --git a/ph-ee-integration-test/src/test/java/resources/inbound.feature b/ph-ee-integration-test/src/test/java/resources/inbound.feature new file mode 100644 index 000000000..14fdb7281 --- /dev/null +++ b/ph-ee-integration-test/src/test/java/resources/inbound.feature @@ -0,0 +1,20 @@ +Feature: Inbound transaction test + + Scenario: Payer inbound transfer request + Given I can mock TransactionChannelRequestDTO + And I have tenant as "gorilla" + When I call the inbound transfer endpoint with expected status of 200 + Then I should get non empty response + And I should be able to parse transactionId + + Scenario: IAM-005 Bulk Processor Inbound Integration Test + When I create an IdentityMapperDTO for registering beneficiary with "gorilla" as DFSPID + Then I can inject MockServer + And I can start mock server + When I call the register beneficiary API with expected status of 202 + Given I have the demo csv file "ph-ee-bulk-demo-7.csv" + And I have tenant as "rhino" + When I call the batch transactions endpoint with expected response status of 200 + Then I should be able to parse batch id from response + When I call the batch details API with expected response status of 200 + And I can assert the payee DFSPID is same as used to register beneficiary id type from response \ No newline at end of file diff --git a/ph-ee-integration-test/src/test/java/resources/interopErrorCode.feature b/ph-ee-integration-test/src/test/java/resources/interopErrorCode.feature new file mode 100644 index 000000000..2effc4650 --- /dev/null +++ b/ph-ee-integration-test/src/test/java/resources/interopErrorCode.feature @@ -0,0 +1,20 @@ +@amsintegrationtest +Feature: Interop Error Code Test + + Scenario: IEC-001 GSMA Transfer Api PayerNotFound Test + Given I can create GSMATransferDTO with incorrect Payer + And I have tenant as "paymentBB2" + When I call the GSMATransfer endpoint with expected status of 200 + And I should be able to parse transactionId from response + Then I should poll the transfer query endpoint with transactionId until errorInformation is populated for the transactionId + And I should be able to parse "PayerNotFound" Error Code from response + + Scenario: IEC-002 GSMA Transfer Api PayerInsufficientBalance Test + Given I can create GSMATransferDTO with Payer Insufficient Balance + And I have tenant as "paymentBB2" + When I call the GSMATransfer endpoint with expected status of 200 + And I should be able to parse transactionId from response + Then I should poll the transfer query endpoint with transactionId until errorInformation is populated for the transactionId + And I should be able to parse "PayerInsufficientBalance" Error Code from response + + diff --git a/ph-ee-integration-test/src/test/java/resources/jsonWebSignature.feature b/ph-ee-integration-test/src/test/java/resources/jsonWebSignature.feature new file mode 100644 index 000000000..6cd5d8d75 --- /dev/null +++ b/ph-ee-integration-test/src/test/java/resources/jsonWebSignature.feature @@ -0,0 +1,22 @@ +@gov +Feature: Json Web Signature test + + Scenario: JWS-001 Test the jws for batchTransactions + Given I have the demo csv file "ph-ee-bulk-demo-6.csv" + And I have tenant as "paymentBB2" + And I generate clientCorrelationId + And I have private key + And I generate signature + When I call the batch transactions endpoint with expected status of 202 + Then I should get non empty response + + Scenario: JWS-002 Test the jws in response for batchTransactions + Given I have the demo csv file "ph-ee-bulk-demo-6.csv" + And I have tenant as "paymentBB2" + And I generate clientCorrelationId + And I have private key + And I generate signature + When I call the batch transactions endpoint with expected status of 202 + Then I should get non empty response + And The response should have non empty header X-SIGNATURE + And The signature should be able successfully validated against certificate diff --git a/ph-ee-integration-test/src/test/java/resources/kongSecurity.feature b/ph-ee-integration-test/src/test/java/resources/kongSecurity.feature new file mode 100644 index 000000000..fcd066b3b --- /dev/null +++ b/ph-ee-integration-test/src/test/java/resources/kongSecurity.feature @@ -0,0 +1,45 @@ +@gov-security +Feature: Kong security test + + @kong-teardown + Scenario: API-KEY authentication test + Given I have required Kong configuration + When I create new consumer + And I wait for 2 seconds + And I am able to create a key for above consumer + And I wait for 2 seconds + And I register a service in kong + And I wait for 2 seconds + And I register a route to above service in kong + And I wait for 2 seconds + And I add the key-auth plugin in above service + And I wait for 5 seconds + Then When I call the service endpoint with api key I should get 200 + + + @GOV-410 + @kong-teardown + Scenario: Kong Ratelimiter test + Given I have required Kong configuration + When I create new consumer + And I wait for 2 seconds + And I am able to create a key for above consumer + And I wait for 2 seconds + And I register a service in kong + And I wait for 2 seconds + And I register a route to above service in kong + And I wait for 2 seconds + And I add the ratelimiter plugin in kong + And I wait for 5 seconds + Then When I call the service endpoint with api key I should get 200 + And I wait for 1 seconds + Then When I call the service endpoint with api key I should get 200 + And I wait for 1 seconds + Then When I call the service endpoint with api key I should get 200 + And I wait for 1 seconds + Then When I call the service endpoint with api key I should get 200 + And I wait for 1 seconds + Then When I call the service endpoint with api key I should get 200 + And I wait for 1 seconds + Then When I call the service endpoint with api key I should get 429 + And I should have "API rate limit exceeded" in response body diff --git a/ph-ee-integration-test/src/test/java/resources/mockFlowTest.feature b/ph-ee-integration-test/src/test/java/resources/mockFlowTest.feature new file mode 100644 index 000000000..b72ee0158 --- /dev/null +++ b/ph-ee-integration-test/src/test/java/resources/mockFlowTest.feature @@ -0,0 +1,58 @@ +@gov +Feature: Mock Flow Test + + @ext + Scenario: Test for minimal mock fund transfer account lookup flow + Given I have Fineract-Platform-TenantId as "payeefsp1" + When I call the create payer client endpoint + Then I call the create savings product endpoint + When I call the create savings account endpoint + Then I call the interop identifier endpoint + Then I approve the deposit with command "approve" + When I activate the account with command "activate" + Then I create an IdentityMapperDTO for Register Beneficiary with identifier from previous step + When I call the register beneficiary API with expected status of 202 and callback stub "/registerBeneficiaryApiTest" + Then I have tenant as "paymentbb1" + And I create a new clientCorrelationId + Given I can mock TransactionChannelRequestDTO for account lookup + And I create a new clientCorrelationId + When I call the outbound transfer endpoint with expected status 200 + Then I should get non empty response + Given I can mock TransactionChannelRequestDTO + And I have tenant as "paymentbb1" + When I call the get txn API with expected status of 200 and txnId with PayeeDFSPId check + Then I should get non empty response + And I should have startedAt and completedAt in response + And I should have PayeeFspId as "pluto" + + @common + Scenario: MFT-001 Test for minimal mock fund transfer flow + Given I have tenant as "paymentBB2" + And I create a new clientCorrelationId + Given I can mock TransactionChannelRequestDTO + And I create a new clientCorrelationId + When I call the outbound transfer endpoint with expected status 200 + Then I should get non empty response + Given I can mock TransactionChannelRequestDTO + And I have tenant as "paymentBB2" + When I call the get txn API with expected status of 200 and txnId + Then I should get non empty response + And I should have startedAt and completedAt in response + And I should have PayerFspId as not null + + @common + Scenario: MFT-002 Test for minimal mock fund transfer flow with batch transactions + Given I have tenant as "paymentBB2" + And I have the demo csv file "ph-ee-bulk-demo-7.csv" + And I create a new clientCorrelationId + And I have private key + And I generate signature + When I call the batch transactions endpoint with expected status of 202 + And I am able to parse batch transactions response + And I fetch batch ID from batch transaction API's response + When I call the batch summary API with expected status of 200 with total 3 txns + Then I am able to parse batch summary response + And Status of transaction is "COMPLETED" + And I should have matching total txn count and successful txn count in response + + diff --git a/ph-ee-integration-test/src/test/java/resources/mockserver.feature b/ph-ee-integration-test/src/test/java/resources/mockserver.feature new file mode 100644 index 000000000..b17d07868 --- /dev/null +++ b/ph-ee-integration-test/src/test/java/resources/mockserver.feature @@ -0,0 +1,16 @@ +@common @gov +Feature: Testing the startup and working of mockserver + + Scenario: MS-001 Mockserver config test + Given I can inject MockServer + And I can start mock server + Then I should be able to get instance of mock server + And I can stop mock server + + Scenario: MS-002 Mockserver stub test + Given I can inject MockServer + And I can start mock server + And I can register the stub with "/testMockServer" endpoint for "POST" request with status of 200 + When I make the "POST" request to "/testMockServer" endpoint with expected status of 200 + Then I should be able to verify that the "POST" method to "/testMockServer" endpoint received 1 request + And I can stop mock server diff --git a/ph-ee-integration-test/src/test/java/resources/mojaloop.feature b/ph-ee-integration-test/src/test/java/resources/mojaloop.feature new file mode 100644 index 000000000..d88be4fe2 --- /dev/null +++ b/ph-ee-integration-test/src/test/java/resources/mojaloop.feature @@ -0,0 +1,140 @@ +@gov @ext +Feature: Mojaloop test + + Scenario: ML connector partial payee party lookup test + Given I am setting up Mojaloop + Given I have Fineract-Platform-TenantId for "payee" + When I call the create client endpoint for "payee" + Then I call the create savings product endpoint for "payee" + When I call the create savings account endpoint for "payee" + Then I call the interop identifier endpoint for "payee" + Then I approve the deposit with command "approve" for "payee" + When I activate the account with command "activate" for "payee" + When I can inject MockServer + Then I can start mock server + Then I can register the stub for callback endpoint of party lookup + Then I call the get parties api in ml connector for "payee" +# Then I will sleep for 5000 millisecond + Then I should be able to verify the callback for lookup + Then I can stop mock server + + Scenario: ML connector partial payee quotation test + Given I am setting up Mojaloop + Given I have Fineract-Platform-TenantId for "payee" + When I call the create client endpoint for "payee" + Then I call the create savings product endpoint for "payee" + When I call the create savings account endpoint for "payee" + Then I call the interop identifier endpoint for "payee" + Then I approve the deposit with command "approve" for "payee" + When I activate the account with command "activate" for "payee" + When I can inject MockServer + Then I can start mock server + Then I can register the stub for callback endpoint of quotation + Then I call the get quotation api in ml connector for "payee" +# Then I will sleep for 5000 millisecond + Then I should be able to verify the callback for quotation + Then I can stop mock server + + Scenario: ML connector partial payee transfer test + Given I am setting up Mojaloop + Given I have Fineract-Platform-TenantId for "payee" + When I call the create client endpoint for "payee" + Then I call the create savings product endpoint for "payee" + When I call the create savings account endpoint for "payee" + Then I call the interop identifier endpoint for "payee" + Then I approve the deposit with command "approve" for "payee" + When I activate the account with command "activate" for "payee" + When I can inject MockServer + Then I can start mock server + Then I can register the stub for callback endpoint of quotation + Then I call the get quotation api in ml connector for "payee" +# Then I will sleep for 5000 millisecond + Then I should be able to verify the callback for quotation + Then I can register the stub for callback endpoint of transfer + Then I call the transfer api in ml connector for "payee" +# Then I will sleep for 5000 millisecond + Then I should be able to verify the callback for transfer + Then I can stop mock server + + Scenario Outline: Payer Fund Transfer Flow test + Given I am setting up Mojaloop + Given I have Fineract-Platform-TenantId for "payer" + When I call the create client endpoint for "payer" + Then I call the create savings product endpoint for "payer" + When I call the create savings account endpoint for "payer" + Then I call the interop identifier endpoint for "payer" + Then I approve the deposit with command "approve" for "payer" + When I activate the account with command "activate" for "payer" + Then I call the deposit account endpoint with command "deposit" for amount 12 for "payer" + +# payee1/payee2/payee3 + Given I have Fineract-Platform-TenantId for "" + When I call the create client endpoint for "payee" + Then I call the create savings product endpoint for "payee" + When I call the create savings account endpoint for "payee" + Then I call the interop identifier endpoint for "payee" + Then I approve the deposit with command "approve" for "payee" + When I activate the account with command "activate" for "payee" + Then I call the deposit account endpoint with command "deposit" for amount 10 for "payee" + + Then I add "payer" to als +# payee1/payee2/payee3 + Then I add "" to als + + Then I call the payer fund transfer api to transfer amount "1" from payer to payee + Then I should get transaction id in response + +# Then I will sleep for 10000 millisecond + + When I call the transfer API in ops app with transactionId as parameter + + Then I check for error related to lookup + And I assert the partyLookupFailed is false + And I assert the partyLookupRetryCount is 0 + + Then I check for error related to quote + And I assert the quoteFailed is false + And I assert the quoteRetryCount is 0 + + Then I check for error related to transfer + And I assert the transferFailed is false + And I assert the transferRetryCount is 0 + + Then I assert "payer" balance to be 11 + Then I assert "payee" balance to be 11 + Examples: + | payee | + | payee1 | + | payee2 | + | payee3 | + + Scenario: Bulk Transfer with Mojaloop + Given I am setting up Mojaloop + When I create and setup a "payer" with account balance of 12 + When I create and setup a "payee" with account balance of 10 + Then I add "payer" to als + Then I add "payee" to als + Then Create a csv file with file name "batchTransaction.csv" + Then add row to csv with current payer and payee, payment mode as "mojaloop" and transfer amount 3 and id 0 + Then I add "payer" to als + When I create and setup a "payer" with account balance of 120 + Then add row to csv with current payer and payee, payment mode as "mojaloop" and transfer amount 2 and id 1 + When I create and setup a "payer" with account balance of 66 + When I create and setup a "payee" with account balance of 10 + Then I add "payer" to als + Then I add "payee" to als + Then add last row to csv with current payer and payee, payment mode as "mojaloop" and transfer amount 1 and id 2 + + Given I have Fineract-Platform-TenantId for "payer" + And I generate clientCorrelationId + And I have private key + And I generate signature + When I call the batch transactions endpoint with expected status of 202 + And I am able to parse batch transactions response + And I fetch batch ID from batch transaction API's response +# Then I will sleep for 10000 millisecond + When I call the batch aggregate API with expected status of 200 with total 3 txns + Then I should get non empty response + Then I am able to parse batch summary response + And Status of transaction is "COMPLETED" + And I should have matching total txn count and successful txn count in response diff --git a/ph-ee-integration-test/src/test/java/resources/netflixConductor.feature b/ph-ee-integration-test/src/test/java/resources/netflixConductor.feature new file mode 100644 index 000000000..80dd95d23 --- /dev/null +++ b/ph-ee-integration-test/src/test/java/resources/netflixConductor.feature @@ -0,0 +1,28 @@ +@dpg +Feature: DPGA API test + + Scenario: conductor server health test + When I make a call to nc server health API with expected status 200 + Then I get the value of Healthy as true in response + + Scenario: dpga transfer api test with ams withdrawal verification + Given I have Fineract-Platform-TenantId as "payerfsp1" + When I call the create payer client endpoint + Then I call the create savings product endpoint + When I call the create savings account endpoint + Then I call the interop identifier endpoint + Then I approve the deposit with command "approve" + When I activate the account with command "activate" + Then I call the deposit account endpoint with command "deposit" for amount 11 + When I have amsName as "mifos" and acccountHoldingInstitutionId as "lion" and amount as 11 + Given I have tenant as "lion" + And I have the request body for transfer + When I call the channel transfer API with client correlation id and expected status of 200 + Then I should get transaction id in response + When I call the get workflow API in with workflow id as path variable + Then I should get valid status + Then I will sleep for 3000 millisecond + When I call the get transfer API in ops app with transactionId as parameter + Then I should get transfer state as completed + When I call the savings account endpoint to get the current Balance + Then I verify that the current balance is 10 diff --git a/ph-ee-integration-test/src/test/java/resources/operationsBatch.feature b/ph-ee-integration-test/src/test/java/resources/operationsBatch.feature new file mode 100644 index 000000000..a9d5b9b8b --- /dev/null +++ b/ph-ee-integration-test/src/test/java/resources/operationsBatch.feature @@ -0,0 +1,138 @@ +@ext +Feature: Operations APP related feature + + @gov @ops-batch-setup @ops-batch-teardown + Scenario: Batches API no filter test + Given I have tenant as "paymentBB2" + When I call the operations-app auth endpoint with username: "mifos" and password: "password" + Then I should get a valid token + When I call the batches endpoint with expected status of 200 with total batches -1 + Then I should get non empty response + And I am able to parse batch paginated response into DTO + + @gov @ext @ops-batch-setup @ops-batch-teardown + Scenario: Batches API batchId filter test + Given I have tenant as "paymentBB2" + And I have the demo csv file "payerIdentifier-resolution-using-budgetAccount.csv" + And I have the registeringInstituteId "123" + And I have the programId "SocialWelfare" + And I generate clientCorrelationId + And I have private key + And I generate signature + When I call the batch transactions endpoint with expected status of 202 + And I am able to parse batch transactions response + And I fetch batch ID from batch transaction API's response +# Then I will sleep for 2000 millisecond + When I call the batch summary API with expected status of 200 with total 10 txns + Then I am able to parse batch summary response + And I should get non empty response + Then I add batchId query param + When I call the batches endpoint with expected status of 200 with total batches 1 + Then I should get non empty response + And I am able to parse batch paginated response into DTO + And I am able to assert 1 totalBatches + + # create 2 batch txn + # set offset to 0 and limit to 1 + # assert single batch is returned + # set offset to 1 and limit to 1 + @gov @ops-batch-setup @ops-batch-teardown + Scenario: Batches API pagination test + # Batch 1 call + Given I have tenant as "paymentBB2" + And I have the demo csv file "payerIdentifier-resolution-using-budgetAccount.csv" + And I have the registeringInstituteId "123" + And I have the programId "SocialWelfare" + And I generate clientCorrelationId + And I have private key + And I generate signature + When I call the batch transactions endpoint with expected status of 202 + # sleep for 1 sec +# Then I will sleep for 1000 millisecond + # Batch 2 call + And I have the demo csv file "payerIdentifier-resolution-using-budgetAccount.csv" + And I have the registeringInstituteId "123" + And I have the programId "SocialWelfare" + And I generate clientCorrelationId + And I have private key + And I generate signature + When I call the batch transactions endpoint with expected status of 202 + And I add limit filter 1 + And I add offset filter 0 + When I call the batches endpoint with expected status of 200 with total batches 1 + Then I should get non empty response + And I am able to parse batch paginated response into DTO + And The count of batches should be 1 + When I add limit filter 1 + And I add offset filter 1 + And I call the batches endpoint with expected status of 200 with total batches 1 + Then I should get non empty response + And I am able to parse batch paginated response into DTO + And The count of batches should be 1 + + # store startTime + # hit 5 batches + # sleep for some secs + # calculate endTime + # query using startTime and endTime ->> then I should get 5 txn + @gov @ext @ops-batch-setup @ops-batch-teardown + Scenario: Batches API date filter test +# Given I will sleep for 5000 millisecond + And I have tenant as "paymentBB2" + And I store this time as start time + # Batch 1 call + And I have the demo csv file "payerIdentifier-resolution-using-budgetAccount.csv" + And I have the registeringInstituteId "123" + And I have the programId "SocialWelfare" + And I generate clientCorrelationId + And I have private key + And I generate signature + Then I call the batch transactions endpoint with expected status of 202 + # sleep for 1 sec +# And I will sleep for 5000 millisecond + # Batch 2 call + And I have the demo csv file "payerIdentifier-resolution-using-budgetAccount.csv" + And I have the registeringInstituteId "123" + And I have the programId "SocialWelfare" + And I generate clientCorrelationId + And I have private key + And I generate signature + When I call the batch transactions endpoint with expected status of 202 + # sleep for 1 sec +# Then I will sleep for 5000 millisecond + # Batch 3 call + And I have the demo csv file "payerIdentifier-resolution-using-budgetAccount.csv" + And I have the registeringInstituteId "123" + And I have the programId "SocialWelfare" + And I generate clientCorrelationId + And I have private key + And I generate signature + When I call the batch transactions endpoint with expected status of 202 + # sleep for 1 sec +# Then I will sleep for 5000 millisecond + # Batch 4 call + And I have the demo csv file "payerIdentifier-resolution-using-budgetAccount.csv" + And I have the registeringInstituteId "123" + And I have the programId "SocialWelfare" + And I generate clientCorrelationId + And I have private key + And I generate signature + When I call the batch transactions endpoint with expected status of 202 + # sleep for 1 sec +# Then I will sleep for 5000 millisecond + # Batch 5 call + And I have the demo csv file "payerIdentifier-resolution-using-budgetAccount.csv" + And I have the registeringInstituteId "123" + And I have the programId "SocialWelfare" + And I generate clientCorrelationId + And I have private key + And I generate signature + When I call the batch transactions endpoint with expected status of 202 + # sleep for 5 sec + # Then I will sleep for 10000 millisecond + And I add date from filter + And I add date to filter + When I call the batches endpoint with expected status of 200 with total batches 5 + Then I should get non empty response + And I am able to parse batch paginated response into DTO + And I am able to assert 5 totalBatches diff --git a/ph-ee-integration-test/src/test/java/resources/paybill.feature b/ph-ee-integration-test/src/test/java/resources/paybill.feature new file mode 100644 index 000000000..fbc3bbe1f --- /dev/null +++ b/ph-ee-integration-test/src/test/java/resources/paybill.feature @@ -0,0 +1,17 @@ +Feature: Paybill API Tests + + Scenario: Paybill Config Test + Given The mpesaValidateUrl is not null + Given The mpesaSettlementUrl is not null + + Scenario: MPESA Connector Validate Webhook API Test for paygops + Given I have businessShortCode "24322607" with transactionId "8335b60090979AvUefSR" + And I have MSISDN "254797668592" and BillRefNo "24322607" for amount "11" + When I call the mpesa-connector validate webhook api with expected status code of 200 + Then I call the confirmation webhook API with expected status of 200 + + Scenario: MPESA Connector Validate Webhook API Test for roster + Given I have businessShortCode "12345678" with transactionId "670d65bd-4efd-4a6c-ae2c-7fdaa8cb4d60" + And I have MSISDN "2540726839144" and BillRefNo "33272035" for amount "11" + When I call the mpesa-connector validate webhook api with expected status code of 200 + Then I call the confirmation webhook API with expected status of 200 diff --git a/ph-ee-integration-test/src/test/java/resources/paymentStatusCheck.feature b/ph-ee-integration-test/src/test/java/resources/paymentStatusCheck.feature new file mode 100644 index 000000000..08408a0de --- /dev/null +++ b/ph-ee-integration-test/src/test/java/resources/paymentStatusCheck.feature @@ -0,0 +1,37 @@ +@govToDo +Feature: Payment Status Check API + + Scenario: Component Test for Payment Status Check API + Given I have tenant as "rhino" + And I create a new clientCorrelationId + Given I can mock TransactionChannelRequestDTO + And I create a new clientCorrelationId + When I call the outbound transfer endpoint with expected status 200 + Then I should get non empty response + When I should have clean request id list + And I extracted clientCorrelationId from response + Given I can mock TransactionChannelRequestDTO + And I create a new clientCorrelationId + When I call the outbound transfer endpoint with expected status 200 + Then I should get non empty response + And I extracted clientCorrelationId from response + Given I can create a mock request body from above clientCorrelationIds + When I call the payment status check endpoint with expected status 200 + Then I should get non empty response + And I should have startedAt and completedAt in response + And I should have PayerFspId as not null + + Scenario: Integration Test for Payment Status Check API with batch transactions + Given I have tenant as "rhino" + And I have the demo csv file "ph-ee-bulk-demo-7.csv" + And I create a new clientCorrelationId + And I have private key + And I generate signature + When I call the batch transactions endpoint with expected status of 202 + And I am able to parse batch transactions response + And I fetch batch ID from batch transaction API's response + And I extracted clientCorrelationId from the demo csv file "ph-ee-bulk-demo-7.csv" + Given I can create a mock request body from above clientCorrelationIds + When I call the payment status check endpoint with expected status 200 + Then I should get non empty response + And I should have startedAt and completedAt in response diff --git a/ph-ee-integration-test/src/test/java/resources/scopedBean.feature b/ph-ee-integration-test/src/test/java/resources/scopedBean.feature new file mode 100644 index 000000000..1a47ae67e --- /dev/null +++ b/ph-ee-integration-test/src/test/java/resources/scopedBean.feature @@ -0,0 +1,7 @@ +Feature: test the scoped scenario annotation + + Scenario: Set Variable + Given I set the variable to "Scenario 1 Value" + + Scenario: Retrieve Variable + Then I retrieve the variable diff --git a/ph-ee-integration-test/src/test/java/resources/security.feature b/ph-ee-integration-test/src/test/java/resources/security.feature new file mode 100644 index 000000000..c93ca1212 --- /dev/null +++ b/ph-ee-integration-test/src/test/java/resources/security.feature @@ -0,0 +1,13 @@ +Feature: The authorisation code verification + Scenario: Do the encryption and decryption on data + Given generate random data + When encrypt the data with the "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtO38XREJbL1r4IAYK6K5ONNXHcmfTKlehRf0YF+vjptt4D/6zBObBOf/zqButSlN3RI/aYXBx/OOU7sjRMnOFYasXtYM5eFSGZDo/v9qsWLwrD9Ur97cE7Pnw3xb+TQNWV6orME5YI0di6X9bXrxUBDswfVmLx/wbvZIK9gJRzD1evm+4HCYo/+1tYZ3YgpNmoW4u6F44zgxeMhFPcjQIaKYm3uM8zF/hTuHhWKVJq40ucL7+mgGp36HiDE8IRfNRo/Vd6x3+FLA91RMe+96uxj7l5WUi8oja1Anb8SE4fnVvGPSArgk8t2xW6dfx86D3c5JFJczzSi5S4ldsOBHMQIDAQAB" + Then encrypted data is not null + When encrypted data is decrypted using the "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC07fxdEQlsvWvggBgrork401cdyZ9MqV6FF/RgX6+Om23gP/rME5sE5//OoG61KU3dEj9phcHH845TuyNEyc4Vhqxe1gzl4VIZkOj+/2qxYvCsP1Sv3twTs+fDfFv5NA1ZXqiswTlgjR2Lpf1tevFQEOzB9WYvH/Bu9kgr2AlHMPV6+b7gcJij/7W1hndiCk2ahbi7oXjjODF4yEU9yNAhopibe4zzMX+FO4eFYpUmrjS5wvv6aAanfoeIMTwhF81Gj9V3rHf4UsD3VEx773q7GPuXlZSLyiNrUCdvxITh+dW8Y9ICuCTy3bFbp1/HzoPdzkkUlzPNKLlLiV2w4EcxAgMBAAECggEAMjqHfwbFyQxlMHQfQa3xIdd6LejVcqDqfqSB0Wd/A2YfAMyCQbmHpbsKh0B+u4h191OjixX5EBuLfa9MQUKNFejHXaSq+/6rnjFenbwm0IwZKJiEWDbUfhvJ0blqhypuMktXJG6YETfb5fL1AjnJWGL6d3Y7IgYJ56QzsQhOuxZidSqw468xc4sIF0CoTeJdrSC2yDCVuVlLNifm/2SXBJD8mgc1WCz0rkJhvvpW4k5G9rRSkS5f0013ZNfsfiDXoqiKkafoYNEbk7TZQNInqSuONm/UECn5GLm6IXdXSGfm1O2Lt0Kk7uxW/3W00mIPeZD+hiOObheRm/2HoOEKiQKBgQDreVFQihXAEDviIB2s6fphvPcMw/IonE8tX565i3303ubQMDIyZmsi3apN5pqSjm1TKq1KIgY2D4vYTu6vO5x9MhEO2CCZWNwC+awrIYa32FwiT8D8eZ9g+DJ4/IwXyz1fG38RCz/eIsJ0NsS9z8RKBIbfMmM+WnXRez3Fq+cbRwKBgQDEs35qXThbbFUYo1QkO0vIo85iczu9NllRxo1nAqQkfu1oTYQQobxcGk/aZk0B02r9kt2eob8zfG+X3LadIhQ0/LalnGNKI9jWLkdW4dxi7xMU99MYc3NRXmR49xGxgOVkLzKyGMisUvkTnE5v/S1nhu5uFr3JPkWcCScLOTjVxwKBgHNWsDq3+GFkUkC3pHF/BhJ7wbLyA5pavfmmnZOavO6FhB8zjFLdkdq5IuMXcl0ZAHm9LLZkJhCy2rfwKb+RflxgerR/rrAOM24Np4RU3q0MgEyaLhg85pFT4T0bzu8UsRH14O6TSQxgkEjmTsX+j9IFl56aCryPCKi8Kgy53/CfAoGAdV2kUFLPDb3WCJ1r1zKKRW1398ZKHtwO73xJYu1wg1Y40cNuyX23pj0M6IOh7zT24dZ/5ecc7tuQukw3qgprhDJFyQtHMzWwbBuw9WZO2blM6XX1vuEkLajkykihhggi12RSG3IuSqQ3ejwJkUi/jsYz/fwTwcAmSLQtV8UM5IECgYEAh4h1EkMx3NXzVFmLsb4QLMXw8+Rnn9oG+NGObldQ+nmknUPu7iz5kl9lTJy+jWtqHlHL8ZtV1cZZSZnFxX5WQH5/lcz/UD+GqWoSlWuTU34PPTJqLKSYgkoOJQDEZVMVphLySS9tuo+K/h10lRS1r9KDm3RZASa1JnnWopBZIz4=" + Then compare the decrypted data with the original data + + Scenario: PublicKey to String conversion + Given I have public key "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtO38XREJbL1r4IAYK6K5ONNXHcmfTKlehRf0YF+vjptt4D/6zBObBOf/zqButSlN3RI/aYXBx/OOU7sjRMnOFYasXtYM5eFSGZDo/v9qsWLwrD9Ur97cE7Pnw3xb+TQNWV6orME5YI0di6X9bXrxUBDswfVmLx/wbvZIK9gJRzD1evm+4HCYo/+1tYZ3YgpNmoW4u6F44zgxeMhFPcjQIaKYm3uM8zF/hTuHhWKVJq40ucL7+mgGp36HiDE8IRfNRo/Vd6x3+FLA91RMe+96uxj7l5WUi8oja1Anb8SE4fnVvGPSArgk8t2xW6dfx86D3c5JFJczzSi5S4ldsOBHMQIDAQAB" + When I get the publicKey object from string + Then I should be able to get string from publicKey object + And It should be equal to original key diff --git a/ph-ee-integration-test/src/test/java/resources/validateChannel.feature b/ph-ee-integration-test/src/test/java/resources/validateChannel.feature new file mode 100644 index 000000000..eab89b13a --- /dev/null +++ b/ph-ee-integration-test/src/test/java/resources/validateChannel.feature @@ -0,0 +1,52 @@ +Feature: Validate Channel Api Request Headers And Body + + Scenario: Error Validity check for Post Transfer API for request body with no payee + Given I can create a TransactionChannelRequestDTO with no payee + When I call the post transfer API with expected status of 400 + Then I should be able to assert the api validation for schema validation error response + + Scenario: Unsupported header validation for Post Transfer Api Test + Given I can create a TransactionChannelRequestDTO + When I call the post transfer API having unsupported header with expected status of 400 + Then I should get non empty response + Then I should be able to assert the api validation for header validation error response + + Scenario: Required header validation for Post Transfer Api Test + Given I can create a TransactionChannelRequestDTO + When I call the post transfer API without required header Platform-TenantId with expected status of 400 + Then I should get non empty response + Then I should be able to assert the api validation for header validation error response + + Scenario: Error Validity check for Transaction Request API for request body with no payee + Given I can create a TransactionChannelRequestDTO with no payee + When I call the transaction request API with expected status of 400 + Then I should be able to assert the api validation for schema validation error response + + Scenario: Unsupported header validation for Transaction Request Api Test + Given I can create a TransactionChannelRequestDTO + When I call the transaction request API having unsupported header with expected status of 400 + Then I should get non empty response + Then I should be able to assert the api validation for header validation error response + + Scenario: Required header validation for Transaction Request Api Test + Given I can create a TransactionChannelRequestDTO + When I call the transaction request API without required header Platform-TenantId with expected status of 400 + Then I should get non empty response + Then I should be able to assert the api validation for header validation error response + + Scenario: Error Validity check for GSMA Transaction API for request body with no payee list + Given I can create a GsmaTransfer DTO with no payee list + When I call the GSMA transaction API with expected status of 400 + Then I should be able to assert the api validation for schema validation error response + + Scenario: Unsupported header validation for GSMA Transaction Api Test + Given I can create a GsmaTransfer DTO + When I call the gsma transaction API having unsupported header with expected status of 400 + Then I should get non empty response + Then I should be able to assert the api validation for header validation error response + + Scenario: Required header validation for Transaction Request Api Test + Given I can create a GsmaTransfer DTO + When I call the gsma transaction API without required header accountHoldingInstitutionId with expected status of 400 + Then I should get non empty response + Then I should be able to assert the api validation for header validation error response \ No newline at end of file diff --git a/ph-ee-integration-test/src/test/java/resources/validateTxn.feature b/ph-ee-integration-test/src/test/java/resources/validateTxn.feature new file mode 100644 index 000000000..88c0c1110 --- /dev/null +++ b/ph-ee-integration-test/src/test/java/resources/validateTxn.feature @@ -0,0 +1,18 @@ + + Feature: Validate Txn Data + + Scenario: VT-001 GSMA Transfer Api Payer Invalid Test + Given I can create GSMATransferDTO with invalid payer information + And I have tenant as "paymentbb2" + When I call the GSMATransfer endpoint with expected status of 200 + And I should be able to parse transactionId from response + Then I should poll the transfer query endpoint with transactionId until status is populated for the transactionId + + + Scenario: VT-002 Inbound Transfer API Payer Invalid Test + Given I create a new clientCorrelationId + And I have tenant as "paymentbb2" + Given I can mock TransactionChannelRequestDTO with wrong msisdn + When I call inbound transfer api with client correlation id expected status 200 + And I should be able to parse transactionId from response + Then I should poll the transfer query endpoint with transactionId until status is populated for the transactionId \ No newline at end of file diff --git a/ph-ee-integration-test/src/test/java/resources/validationErrorCode.feature b/ph-ee-integration-test/src/test/java/resources/validationErrorCode.feature new file mode 100644 index 000000000..f9927d766 --- /dev/null +++ b/ph-ee-integration-test/src/test/java/resources/validationErrorCode.feature @@ -0,0 +1,29 @@ +@gov +Feature: Validation Error Code Test + + Scenario: ECV-001 GSMA Transfer Api NegativeValue Test + Given I can create GSMATransferDTO with Negative Amount + And I have tenant as "paymentBB2" + When I call the GSMATransfer endpoint with expected status of 400 + And I should be able to parse "NegativeValue" Error Code from GSMA Transfer response + + Scenario: ECV-002 GSMA Transfer Api MandatoryValueNotSupplied Test + Given I can create GSMATransferDTO with missing currency details + And I have tenant as "paymentBB2" + When I call the GSMATransfer endpoint with expected status of 400 + And I should be able to parse "MandatoryValueNotSupplied" Error Code from GSMA Transfer response + + Scenario: ECV-003 GSMA Transfer Api SamePartiesError Test + Given I can create GSMATransferDTO with same payer and payee + And I have tenant as "paymentBB2" + When I call the GSMATransfer endpoint with expected status of 400 + And I should be able to parse "SamePartiesError" Error Code from GSMA Transfer response + + Scenario: ECV-004 GSMA Transfer Api FormatError Test + Given I can create GSMATransferDTO with invalid amount format + And I have tenant as "paymentBB2" + When I call the GSMATransfer endpoint with expected status of 400 + And I should be able to parse "FormatError" Error Code from GSMA Transfer response + + + diff --git a/ph-ee-integration-test/src/test/java/resources/voucherManagementTest.feature b/ph-ee-integration-test/src/test/java/resources/voucherManagementTest.feature new file mode 100644 index 000000000..2921cd332 --- /dev/null +++ b/ph-ee-integration-test/src/test/java/resources/voucherManagementTest.feature @@ -0,0 +1,143 @@ + +Feature: Voucher Management Api Test + + @gov + Scenario: Create Voucher Api Test + When I can inject MockServer + Then I can start mock server + And I can register the stub with "/createVoucher" endpoint for "PUT" request with status of 200 + Given I can create an VoucherRequestDTO for voucher creation + When I call the create voucher API with expected status of 202 and stub "/createVoucher" + Then I should be able to extract response body from callback + + @gov @createVoucher + Scenario: Activate Voucher Api Test + Given I can create a voucher + Given I can create an VoucherRequestDTO for voucher activation + And I can register the stub with "/activateVoucher" endpoint for "PUT" request with status of 200 + When I call the activate voucher API with expected status of 202 and stub "/activateVoucher" + Then I should be able to assert response body from callback on "/activateVoucher" + + @gov @createAndActivateVoucher + Scenario: Redeem Voucher API Test + Then I check for redeem voucher success + + @gov @createAndActivateVoucher + Scenario: Reactivate Voucher Api Test + Given I can create an VoucherRequestDTO for voucher suspension + And I can register the stub with "/suspendVoucher" endpoint for "PUT" request with status of 200 + When I call the suspend voucher API with expected status of 202 and stub "/suspendVoucher" + And I can create an VoucherRequestDTO for voucher reactivation + And I can register the stub with "/reactivateVoucher" endpoint for "PUT" request with status of 200 + When I call the activate voucher API with expected status of 202 and stub "/reactivateVoucher" + Then I check for redeem voucher success + + @gov @createAndActivateVoucher + Scenario: Validity Check Voucher Api Test + When I can register the stub with "/validity" endpoint for "PUT" request with status of 200 + And I call the validity check API with expected status of 202 and stub "/validity" + Then I can extract result from validation callback and assert if validation is successful on "/validity" + + @gov @createAndActivateVoucher + Scenario: VR-006 Cancel Voucher Api Test + Given I can create an VoucherRequestDTO for voucher cancellation + And I can register the stub with "/cancelVoucher" endpoint for "PUT" request with status of 200 + When I call the cancel voucher API with expected status of 202 and stub "/cancelVoucher" + Then I check for redeem voucher failure + + @gov @createAndActivateVoucher + Scenario: VR-002 Suspend Voucher Api Test + Given I can create an VoucherRequestDTO for voucher suspension + And I can register the stub with "/suspendVoucher" endpoint for "PUT" request with status of 200 + When I call the suspend voucher API with expected status of 202 and stub "/suspendVoucher" + Then I check for redeem voucher failure + + @gov @createAndActivateVoucher + Scenario: Fetch Voucher Api Test + Then I will call the fetch voucher API with expected status of 200 + And I will assert the fields from fetch voucher response + And I can stop mock server + + @gov + Scenario: VC-001,002,003,004,005 Error Validity check for Create Voucher API for negative request body + Given I can create an negative VoucherRequestDTO for voucher creation + When I call the create voucher API with expected status of 400 and stub "/createVoucher" + Then I should be able to assert the create voucher validation for negative response + + @gov + Scenario: VR-003 Error Validity check for Redeem Voucher API for negative request body + Given I can create an negative RedeemVoucherRequestDTO to redeem a voucher + Then I will add the required headers + When I call the redeem voucher API with expected status of 400 + And I should be able to assert the redeem voucher validation for negative response + + @gov @createAndActivateVoucher + Scenario: VR-005 Redeem Voucher Api Negative Test when voucher is already redeemed + Given I can create an RedeemVoucherRequestDTO for voucher redemption + When I call the redeem voucher API with expected status of 200 + Then I check for redeem voucher failure + + @gov + Scenario: Unsupported Parameter Validation for Create Voucher API test + Given I can create an VoucherRequestDTO for voucher creation with unsupported parameter parameter + When I call the create voucher API with expected status of 400 and stub "/createVoucher" + Then I should be able to assert the create voucher validation for negative response + + @gov @createAndActivateVoucher + Scenario: Conflicting/unique data validations check for Create Voucher API + Then I will call the fetch voucher API with expected status of 200 + When I call the create voucher API with expected status of 409 and stub "/createVoucher" + + @gov + Scenario: Unsupported header validation for Create Voucher Api Test + Given I can create an VoucherRequestDTO for voucher creation + When I call the create voucher API having invalid header with expected status of 400 and stub "/createVoucher" + Then I should get non empty response + Then I will assert that response body contains "error.msg.header.validation.errors" + + @Ignore + Scenario: Create a csv file for voucher number and voucher serial number + When I can inject MockServer + Then I can start mock server + And I can register the stub with "/createVoucher" endpoint for "PUT" request with status of 200 + And I can register the stub with "/activateVoucher" endpoint for "PUT" request with status of 200 + When I call the create, Activate voucher API and store it in "vouchertest/loadTest_demo.csv" + + @gov + Scenario: Voucher Status Check for inactive voucher, active voucher and redeemed voucher + When I can inject MockServer + Then I can start mock server + And I can register the stub with "/createVoucher" endpoint for "PUT" request with status of 200 + Given I can create an VoucherRequestDTO for voucher creation + When I call the create voucher API with expected status of 202 and stub "/createVoucher" +# Then I will sleep for 10000 millisecond + Then I should be able to extract response body from callback + And I can call the voucher status API with expected status of 200 until I get the status as "01" + Given I can create an VoucherRequestDTO for voucher activation + And I can register the stub with "/activateVoucher" endpoint for "PUT" request with status of 200 + When I call the activate voucher API with expected status of 202 and stub "/activateVoucher" +# Then I will sleep for 5000 millisecond + Then I should be able to assert response body from callback on "/activateVoucher" + And I can call the voucher status API with expected status of 200 until I get the status as "02" + Given I can create an RedeemVoucherRequestDTO for voucher redemption + When I call the redeem voucher API with expected status of 200 + Then I can assert that redemption was successful by asserting the status in response + And I can call the voucher status API with expected status of 200 until I get the status as "05" + + + + @createAndActivateVoucher @gov + Scenario: Voucher Status Check for inactive voucher, active voucher, suspended and cancelled voucher + Given I can create an VoucherRequestDTO for voucher suspension + And I can register the stub with "/suspendVoucher" endpoint for "PUT" request with status of 200 + When I call the suspend voucher API with expected status of 202 and stub "/suspendVoucher" + And I can call the voucher status API with expected status of 200 until I get the status as "06" + And I can create an VoucherRequestDTO for voucher reactivation + And I can register the stub with "/reactivateVoucher" endpoint for "PUT" request with status of 200 + When I call the activate voucher API with expected status of 202 and stub "/reactivateVoucher" + And I can call the voucher status API with expected status of 200 until I get the status as "02" + Given I can create an VoucherRequestDTO for voucher cancellation + And I can register the stub with "/cancelVoucher" endpoint for "PUT" request with status of 200 + When I call the cancel voucher API with expected status of 202 and stub "/cancelVoucher" + And I can call the voucher status API with expected status of 200 until I get the status as "03" + diff --git a/ph-ee-operations-app/.circleci/config.yml b/ph-ee-operations-app/.circleci/config.yml new file mode 100644 index 000000000..a6799e6ea --- /dev/null +++ b/ph-ee-operations-app/.circleci/config.yml @@ -0,0 +1,288 @@ +version: 2.1 +orbs: + slack: circleci/slack@4.12.5 + aws-ecr: circleci/aws-ecr@8.2.1 + helm: circleci/helm@2.0.1 + aws-eks: circleci/aws-eks@2.2.0 + kubernetes: circleci/kubernetes@1.3 + fynarfin-orb: fynarfin/docker-image-availability-check-and-upgrade@1.0.0 +executors: + docker-executor: + docker: + - image: circleci/openjdk:11-buster-node-browsers-legacy + auth: + username: $DOCKERHUB_USERNAME + password: $DOCKERHUB_PASSWORD + + +jobs: + build_and_push_tag_image: + executor: docker-executor + environment: + JVM_OPTS: -Xmx512m + TERM: dumb + GITHUB_TOKEN: ${GITHUB_TOKEN} # Add the GitHub token as an environment variable + + steps: + - checkout + - setup_remote_docker: + version: 20.10.24 + - kubernetes/install-kubectl + - checkout + - run: + name: Build and Push Docker tag Image + command: | + # Set environment variables + IMAGE_TAG=$CIRCLE_TAG + + # Check if the Docker image with the same tag already exists in Docker Hub + if curl -s -f -u "$DOCKERHUB_USERNAME":"$DOCKERHUB_PASSWORD" "https://hub.docker.com/v2/repositories/fynarfin/ph-ee-operations-app/tags/$IMAGE_TAG" > /dev/null; then + echo "Skipping the build and push as the tag $IMAGE_TAG already exists in Docker Hub." + exit 0 + fi + + # Build and tag the Docker image + ./gradlew clean + ./gradlew bootJar + docker build -t "fynarfin/ph-ee-operations-app:$IMAGE_TAG" . + + # Push the Docker image to Docker Hub + docker login -u "$DOCKERHUB_USERNAME" -p "$DOCKERHUB_PASSWORD" + docker push "fynarfin/ph-ee-operations-app:$IMAGE_TAG" + + # when: always # The job will be executed even if there's no match for the tag filter + + build_and_push_latest_image: + executor: docker-executor + environment: + JVM_OPTS: -Xmx512m + TERM: dumb + + steps: + - checkout + # Install Docker to build and push the image + - setup_remote_docker: + version: 20.10.24 + - kubernetes/install-kubectl + - checkout + - aws-eks/update-kubeconfig-with-authenticator: + cluster-name: "sit" + aws-region: "$REGION" + # Build the Docker image + - run: + name: Build Docker image + command: | + ./gradlew clean + ./gradlew bootJar + docker build -t fynarfin/ph-ee-operations-app:latest . + if [ "$CIRCLE_BRANCH" != "develop" ]; then + PR_NUMBER=$(basename $CIRCLE_PULL_REQUEST) + PR_TITLE=$(curl -sSL "https://api.github.com/repos/fynarfin/$CIRCLE_PR_REPONAME/pulls/$PR_NUMBER" | jq -r '.title') + JIRA_STORY=$(echo $PR_TITLE | cut -d "[" -f2 | cut -d "]" -f1 | tr '[A-Z]' '[a-z]') + if [ -z "$JIRA_STORY" ]; then echo "Invalid PR title" && exit 1; else echo "Ticket NO: $JIRA_STORY"; fi + docker image tag fynarfin/$CIRCLE_PR_REPONAME:latest fynarfin/$CIRCLE_PR_REPONAME:$JIRA_STORY + fi + + # Log in to DockerHub using environment variables + - run: + name: Login to DockerHub + command: echo "${DOCKERHUB_PASSWORD}" | docker login -u "${DOCKERHUB_USERNAME}" --password-stdin + + # Push the Docker image to DockerHub + - run: + name: Push Docker image to DockerHub + command: | + if [ "$CIRCLE_BRANCH" = "develop" ]; then + docker push fynarfin/ph-ee-operations-app:latest + fi + if [ "$CIRCLE_BRANCH" != "develop" ]; then + PR_NUMBER=$(basename $CIRCLE_PULL_REQUEST) + PR_TITLE=$(curl -sSL "https://api.github.com/repos/fynarfin/$CIRCLE_PR_REPONAME/pulls/$PR_NUMBER" | jq -r '.title') + JIRA_STORY=$(echo $PR_TITLE | cut -d "[" -f2 | cut -d "]" -f1 | tr '[A-Z]' '[a-z]') + docker push fynarfin/$CIRCLE_PR_REPONAME:${JIRA_STORY} + fi + docker-image-availability-check-and-upgrade: + docker: + - image: cimg/python:3.10 + steps: + - fynarfin-orb/docker-image-availability-check-and-upgrade: + namespace: paymenthub + chart-base-url: https://fynarfin.io/images + chart-name: ph-ee-g2psandbox-fynarfin + chart-version: 0.2.0 + release-name: g2p-sandbox + cluster-name: "sit" + aws-region: "$REGION" + service-file-path: https://raw.githubusercontent.com/fynarfin/ph-ee-env-labs/develop/.circleci/services.txt + build-and-host-engine: + docker: + - image: cimg/python:3.10 + working_directory: ~/repo + environment: + TERM: dumb + steps: + - run: git clone https://github.com/fynarfin/ph-ee-env-template + - run: rm -f ph-ee-env-template/helm/ph-ee-engine/Chart.lock ph-ee-env-template/helm/ph-ee-engine/requirements.lock ph-ee-env-template/helm/ph-ee-engine/charts/* + - helm/install-helm-client: + version: "v3.8.2" + # - run: "sed -i '2s/.*/appVersion: 0.0.0/' helm/ph-ee-engine/Chart.yaml" + # - run: "sed -i '5s/.*/version: 0.0.0-SNAPSHOT/' helm/ph-ee-engine/Chart.yaml" + - run: helm dep up ph-ee-env-template/helm/ph-ee-engine + - run: helm package ph-ee-env-template/helm/ph-ee-engine + - run: helm repo index . + - run: echo "$CERT_FILE" | base64 --decode > b64encoded.pem + - run: chmod 400 b64encoded.pem + - run: scp -o StrictHostKeyChecking=No -i b64encoded.pem index.yaml ph-ee-engine-0.0.0-SNAPSHOT.tgz ec2-user@13.233.68.128:~/ + - run: ssh -i b64encoded.pem -o StrictHostKeyChecking=No ec2-user@13.233.68.128 sudo cp -t /apps/apache-tomcat-7.0.82/webapps/ROOT/images/ph-ee-engine-0.0.0-SNAPSHOT index.yaml ph-ee-engine-0.0.0-SNAPSHOT.tgz + + build-and-host-g2p-sandbox: + docker: + - image: cimg/python:3.10 + working_directory: ~/repo + environment: + TERM: dumb + steps: + - run: git clone https://github.com/fynarfin/ph-ee-env-template + - run: rm -f ph-ee-env-template/helm/g2p-sandbox/Chart.lock ph-ee-env-template/helm/g2p-sandbox/requirements.lock ph-ee-env-template/helm/g2p-sandbox/charts/* + - helm/install-helm-client: + version: "v3.8.2" + # - run: "sed -i '6s/.*/appVersion: 0.0.0/' helm/g2p-sandbox/Chart.yaml" + # - run: "sed -i '7s/.*/version: 0.0.0/' helm/g2p-sandbox/Chart.yaml" + # - run: "sed -i '4s/.*/version: 0.0.0-SNAPSHOT/' helm/g2p-sandbox/requirements.yaml" + # SED & replace dependency with 0.0.0 + - run: helm dep up ph-ee-env-template/helm/g2p-sandbox + - run: helm package ph-ee-env-template/helm/g2p-sandbox + - run: helm repo index . + - run: echo "$CERT_FILE" | base64 --decode > b64encoded.pem + - run: chmod 400 b64encoded.pem + - run: scp -o StrictHostKeyChecking=No -i b64encoded.pem index.yaml ph-ee-g2psandbox-0.0.0.tgz ec2-user@13.233.68.128:~/ + - run: ssh -i b64encoded.pem -o StrictHostKeyChecking=No ec2-user@13.233.68.128 sudo cp -t /apps/apache-tomcat-7.0.82/webapps/ROOT/images/ph-ee-g2psandbox-0.0.0 index.yaml ph-ee-g2psandbox-0.0.0.tgz + + build-host-g2p-fyn-chart: + docker: + - image: cimg/python:3.10 + working_directory: ~/repo + environment: + TERM: dumb + steps: + - run: git clone https://github.com/fynarfin/ph-ee-env-labs + - run: rm -f ph-ee-env-labs/helm/g2p-sandbox-fynarfin-SIT/Chart.lock ph-ee-env-labs/helm/g2p-sandbox-fynarfin-SIT/requirements.lock ph-ee-env-labs/helm/g2p-sandbox-fynarfin-SIT/charts/* + - helm/install-helm-client: + version: "v3.8.2" + # - run: "sed -i '12s/.*/version: 0.0.0/' helm/g2p-sandbox-fynarfin-SIT/Chart.yaml" + - run: cat ph-ee-env-labs/helm/g2p-sandbox-fynarfin-SIT/Chart.yaml + - run: helm dep up ph-ee-env-labs/helm/g2p-sandbox-fynarfin-SIT + - run: helm package ph-ee-env-labs/helm/g2p-sandbox-fynarfin-SIT + - run: helm repo index . + - run: echo "$CERT_FILE" | base64 --decode > b64encoded.pem + - run: chmod 400 b64encoded.pem + - run: scp -o StrictHostKeyChecking=No -i b64encoded.pem index.yaml ph-ee-g2psandbox-fynarfin-0.2.0.tgz ec2-user@13.233.68.128:~/ + - run: ssh -i b64encoded.pem -o StrictHostKeyChecking=No ec2-user@13.233.68.128 sudo mv -t /apps/apache-tomcat-7.0.82/webapps/ROOT/images/ph-ee-g2psandbox-fynarfin index.yaml ph-ee-g2psandbox-fynarfin-0.2.0.tgz + + + + test-chart-gov: + docker: + - image: cimg/openjdk:17.0.0 + steps: + - run: git clone https://github.com/fynarfin/ph-ee-integration-test + - run: + name: Ngrok setup + command: curl -s https://ngrok-agent.s3.amazonaws.com/ngrok.asc | sudo tee /etc/apt/trusted.gpg.d/ngrok.asc >/dev/null && echo "deb https://ngrok-agent.s3.amazonaws.com buster main" | sudo tee /etc/apt/sources.list.d/ngrok.list && sudo apt update && sudo apt install ngrok + - run: + name: Test execution + command: | + ngrok config add-authtoken "$AUTH_TOKEN" + ngrok http 53013 > /dev/null & + echo -n "Extracting ngrok public url ." + NGROK_PUBLIC_URL="" + while [ -z "$NGROK_PUBLIC_URL" ]; do + # Run 'curl' against ngrok API and extract public (using 'sed' command) + export NGROK_PUBLIC_URL=$(curl --silent --max-time 10 --connect-timeout 5 \ + --show-error http://127.0.0.1:4040/api/tunnels | \ + sed -nE 's/.*public_url":"https:..([^"]*).*/\1/p') + sleep 1 + echo -n "." + done + + export CALLBACK_URL="https://$NGROK_PUBLIC_URL" + echo -n "Public url ." + echo $CALLBACK_URL + cd ph-ee-integration-test && ./gradlew test -Dcucumber.filter.tags="@gov" + echo -n "Test execution is completed, kill ngrok" + pkill ngrok + - store_test_results: + path: ph-ee-integration-test/build/cucumber.xml + - store_artifacts: + path: ph-ee-integration-test/build/reports/tests/test + test-chart-ams: + docker: + - image: cimg/openjdk:17.0.0 + steps: + - run: git clone https://github.com/fynarfin/ph-ee-integration-test + - run: cd ph-ee-integration-test && ./gradlew test -Dcucumber.filter.tags="@amsIntegration" + - store_test_results: + path: ph-ee-integration-test/build/cucumber.xml + - store_artifacts: + path: ph-ee-integration-test/build/reports/tests/test + + +workflows: + version: 2 + build-and-push: + jobs: + - build_and_push_tag_image: + filters: + tags: + only: /^v\d+\.\d+\.\d+$/ # Match tags in the format v1.2.3 + context: + - DOCKER + - build_and_push_latest_image: + context: + - DOCKER + - AWS + - build-and-host-engine: + requires: + - build_and_push_tag_image + - build_and_push_latest_image + context: + - AWS + - Helm + - slack + - build-and-host-g2p-sandbox: + requires: + - build-and-host-engine + context: + - AWS + - Helm + - slack + - build-host-g2p-fyn-chart: + requires: + - build-and-host-g2p-sandbox + context: + - AWS + - Helm + - docker-image-availability-check-and-upgrade: + context: + - AWS + - Helm + - slack + requires: + - build-host-g2p-fyn-chart + - test-chart-gov: + requires: + - docker-image-availability-check-and-upgrade + context: + - AWS + - Helm + - slack + - Ngrok + - test-chart-ams: + requires: + - docker-image-availability-check-and-upgrade + context: + - AWS + - Helm + - slack + + diff --git a/ph-ee-operations-app/.factorypath b/ph-ee-operations-app/.factorypath new file mode 100644 index 000000000..09cf049f3 --- /dev/null +++ b/ph-ee-operations-app/.factorypath @@ -0,0 +1,75 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ph-ee-operations-app/.github/pull_request_template.md b/ph-ee-operations-app/.github/pull_request_template.md new file mode 100644 index 000000000..9110b69d4 --- /dev/null +++ b/ph-ee-operations-app/.github/pull_request_template.md @@ -0,0 +1,22 @@ +## Description + +* PR title should have jira ticket enclosed in `[]`.
+ Format: ``` [jira_ticket] description```
+ ex: [phee-123] PR title. +* Add a link to the Jira ticket. +* Describe the changes made and why they were made. + +## Checklist + +Please make sure these boxes are checked before submitting your pull request - thanks! +- [ ] Followed the PR title naming convention mentioned above. + +- [ ] Design related bullet points or design document link related to this PR added in the description above. + +- [ ] Updated corresponding Postman Collection or Api documentation for the changes in this PR. + +- [ ] Create/update unit or integration tests for verifying the changes made. + +- [ ] Add required Swagger annotation and update API documentation with details of any API changes if applicable + +- [ ] Followed the naming conventions as given in https://docs.google.com/document/d/1Q4vaMSzrTxxh9TS0RILuNkSkYCxotuYk1Xe0CMIkkCU/edit?usp=sharing diff --git a/ph-ee-operations-app/.gitignore b/ph-ee-operations-app/.gitignore new file mode 100644 index 000000000..3d6b74c8e --- /dev/null +++ b/ph-ee-operations-app/.gitignore @@ -0,0 +1,12 @@ +.classpath +.project +.settings +*.log +.idea +target/ +*.iml +.gradle +build +bin +src/generated +.DS_Store diff --git a/ph-ee-operations-app/.gitpod.yml b/ph-ee-operations-app/.gitpod.yml new file mode 100644 index 000000000..7a9ad9d6e --- /dev/null +++ b/ph-ee-operations-app/.gitpod.yml @@ -0,0 +1,8 @@ +# This configuration file was automatically generated by Gitpod. +# Please adjust to your needs (see https://www.gitpod.io/docs/config-gitpod-file) +# and commit this file to your remote git repository to share the goodness with others. + +tasks: + - init: ./gradlew clean build + + diff --git a/ph-ee-operations-app/Dockerfile b/ph-ee-operations-app/Dockerfile new file mode 100644 index 000000000..0531a7ea6 --- /dev/null +++ b/ph-ee-operations-app/Dockerfile @@ -0,0 +1,6 @@ +FROM openjdk:11 +EXPOSE 5000 + +COPY build/libs/*.jar . +CMD java -jar *.jar + diff --git a/ph-ee-operations-app/Jenkinsfile b/ph-ee-operations-app/Jenkinsfile new file mode 100644 index 000000000..5d41b2506 --- /dev/null +++ b/ph-ee-operations-app/Jenkinsfile @@ -0,0 +1,17 @@ +pipeline { + agent any + stages { + stage('build') { + steps { + sh 'mvn --version' + sh 'mvn -U clean package' + } + } + stage('docker') { + steps { + sh 'docker build . -t paymenthubee.azurecr.io/phee/operations-app' + sh 'docker push paymenthubee.azurecr.io/phee/operations-app' + } + } + } +} diff --git a/ph-ee-operations-app/LICENSE b/ph-ee-operations-app/LICENSE new file mode 100644 index 000000000..a612ad981 --- /dev/null +++ b/ph-ee-operations-app/LICENSE @@ -0,0 +1,373 @@ +Mozilla Public License Version 2.0 +================================== + +1. Definitions +-------------- + +1.1. "Contributor" + means each individual or legal entity that creates, contributes to + the creation of, or owns Covered Software. + +1.2. "Contributor Version" + means the combination of the Contributions of others (if any) used + by a Contributor and that particular Contributor's Contribution. + +1.3. "Contribution" + means Covered Software of a particular Contributor. + +1.4. "Covered Software" + means Source Code Form to which the initial Contributor has attached + the notice in Exhibit A, the Executable Form of such Source Code + Form, and Modifications of such Source Code Form, in each case + including portions thereof. + +1.5. "Incompatible With Secondary Licenses" + means + + (a) that the initial Contributor has attached the notice described + in Exhibit B to the Covered Software; or + + (b) that the Covered Software was made available under the terms of + version 1.1 or earlier of the License, but not also under the + terms of a Secondary License. + +1.6. "Executable Form" + means any form of the work other than Source Code Form. + +1.7. "Larger Work" + means a work that combines Covered Software with other material, in + a separate file or files, that is not Covered Software. + +1.8. "License" + means this document. + +1.9. "Licensable" + means having the right to grant, to the maximum extent possible, + whether at the time of the initial grant or subsequently, any and + all of the rights conveyed by this License. + +1.10. "Modifications" + means any of the following: + + (a) any file in Source Code Form that results from an addition to, + deletion from, or modification of the contents of Covered + Software; or + + (b) any new file in Source Code Form that contains any Covered + Software. + +1.11. "Patent Claims" of a Contributor + means any patent claim(s), including without limitation, method, + process, and apparatus claims, in any patent Licensable by such + Contributor that would be infringed, but for the grant of the + License, by the making, using, selling, offering for sale, having + made, import, or transfer of either its Contributions or its + Contributor Version. + +1.12. "Secondary License" + means either the GNU General Public License, Version 2.0, the GNU + Lesser General Public License, Version 2.1, the GNU Affero General + Public License, Version 3.0, or any later versions of those + licenses. + +1.13. "Source Code Form" + means the form of the work preferred for making modifications. + +1.14. "You" (or "Your") + means an individual or a legal entity exercising rights under this + License. For legal entities, "You" includes any entity that + controls, is controlled by, or is under common control with You. For + purposes of this definition, "control" means (a) the power, direct + or indirect, to cause the direction or management of such entity, + whether by contract or otherwise, or (b) ownership of more than + fifty percent (50%) of the outstanding shares or beneficial + ownership of such entity. + +2. License Grants and Conditions +-------------------------------- + +2.1. Grants + +Each Contributor hereby grants You a world-wide, royalty-free, +non-exclusive license: + +(a) under intellectual property rights (other than patent or trademark) + Licensable by such Contributor to use, reproduce, make available, + modify, display, perform, distribute, and otherwise exploit its + Contributions, either on an unmodified basis, with Modifications, or + as part of a Larger Work; and + +(b) under Patent Claims of such Contributor to make, use, sell, offer + for sale, have made, import, and otherwise transfer either its + Contributions or its Contributor Version. + +2.2. Effective Date + +The licenses granted in Section 2.1 with respect to any Contribution +become effective for each Contribution on the date the Contributor first +distributes such Contribution. + +2.3. Limitations on Grant Scope + +The licenses granted in this Section 2 are the only rights granted under +this License. No additional rights or licenses will be implied from the +distribution or licensing of Covered Software under this License. +Notwithstanding Section 2.1(b) above, no patent license is granted by a +Contributor: + +(a) for any code that a Contributor has removed from Covered Software; + or + +(b) for infringements caused by: (i) Your and any other third party's + modifications of Covered Software, or (ii) the combination of its + Contributions with other software (except as part of its Contributor + Version); or + +(c) under Patent Claims infringed by Covered Software in the absence of + its Contributions. + +This License does not grant any rights in the trademarks, service marks, +or logos of any Contributor (except as may be necessary to comply with +the notice requirements in Section 3.4). + +2.4. Subsequent Licenses + +No Contributor makes additional grants as a result of Your choice to +distribute the Covered Software under a subsequent version of this +License (see Section 10.2) or under the terms of a Secondary License (if +permitted under the terms of Section 3.3). + +2.5. Representation + +Each Contributor represents that the Contributor believes its +Contributions are its original creation(s) or it has sufficient rights +to grant the rights to its Contributions conveyed by this License. + +2.6. Fair Use + +This License is not intended to limit any rights You have under +applicable copyright doctrines of fair use, fair dealing, or other +equivalents. + +2.7. Conditions + +Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted +in Section 2.1. + +3. Responsibilities +------------------- + +3.1. Distribution of Source Form + +All distribution of Covered Software in Source Code Form, including any +Modifications that You create or to which You contribute, must be under +the terms of this License. You must inform recipients that the Source +Code Form of the Covered Software is governed by the terms of this +License, and how they can obtain a copy of this License. You may not +attempt to alter or restrict the recipients' rights in the Source Code +Form. + +3.2. Distribution of Executable Form + +If You distribute Covered Software in Executable Form then: + +(a) such Covered Software must also be made available in Source Code + Form, as described in Section 3.1, and You must inform recipients of + the Executable Form how they can obtain a copy of such Source Code + Form by reasonable means in a timely manner, at a charge no more + than the cost of distribution to the recipient; and + +(b) You may distribute such Executable Form under the terms of this + License, or sublicense it under different terms, provided that the + license for the Executable Form does not attempt to limit or alter + the recipients' rights in the Source Code Form under this License. + +3.3. Distribution of a Larger Work + +You may create and distribute a Larger Work under terms of Your choice, +provided that You also comply with the requirements of this License for +the Covered Software. If the Larger Work is a combination of Covered +Software with a work governed by one or more Secondary Licenses, and the +Covered Software is not Incompatible With Secondary Licenses, this +License permits You to additionally distribute such Covered Software +under the terms of such Secondary License(s), so that the recipient of +the Larger Work may, at their option, further distribute the Covered +Software under the terms of either this License or such Secondary +License(s). + +3.4. Notices + +You may not remove or alter the substance of any license notices +(including copyright notices, patent notices, disclaimers of warranty, +or limitations of liability) contained within the Source Code Form of +the Covered Software, except that You may alter any license notices to +the extent required to remedy known factual inaccuracies. + +3.5. Application of Additional Terms + +You may choose to offer, and to charge a fee for, warranty, support, +indemnity or liability obligations to one or more recipients of Covered +Software. However, You may do so only on Your own behalf, and not on +behalf of any Contributor. You must make it absolutely clear that any +such warranty, support, indemnity, or liability obligation is offered by +You alone, and You hereby agree to indemnify every Contributor for any +liability incurred by such Contributor as a result of warranty, support, +indemnity or liability terms You offer. You may include additional +disclaimers of warranty and limitations of liability specific to any +jurisdiction. + +4. Inability to Comply Due to Statute or Regulation +--------------------------------------------------- + +If it is impossible for You to comply with any of the terms of this +License with respect to some or all of the Covered Software due to +statute, judicial order, or regulation then You must: (a) comply with +the terms of this License to the maximum extent possible; and (b) +describe the limitations and the code they affect. Such description must +be placed in a text file included with all distributions of the Covered +Software under this License. Except to the extent prohibited by statute +or regulation, such description must be sufficiently detailed for a +recipient of ordinary skill to be able to understand it. + +5. Termination +-------------- + +5.1. The rights granted under this License will terminate automatically +if You fail to comply with any of its terms. However, if You become +compliant, then the rights granted under this License from a particular +Contributor are reinstated (a) provisionally, unless and until such +Contributor explicitly and finally terminates Your grants, and (b) on an +ongoing basis, if such Contributor fails to notify You of the +non-compliance by some reasonable means prior to 60 days after You have +come back into compliance. Moreover, Your grants from a particular +Contributor are reinstated on an ongoing basis if such Contributor +notifies You of the non-compliance by some reasonable means, this is the +first time You have received notice of non-compliance with this License +from such Contributor, and You become compliant prior to 30 days after +Your receipt of the notice. + +5.2. If You initiate litigation against any entity by asserting a patent +infringement claim (excluding declaratory judgment actions, +counter-claims, and cross-claims) alleging that a Contributor Version +directly or indirectly infringes any patent, then the rights granted to +You by any and all Contributors for the Covered Software under Section +2.1 of this License shall terminate. + +5.3. In the event of termination under Sections 5.1 or 5.2 above, all +end user license agreements (excluding distributors and resellers) which +have been validly granted by You or Your distributors under this License +prior to termination shall survive termination. + +************************************************************************ +* * +* 6. Disclaimer of Warranty * +* ------------------------- * +* * +* Covered Software is provided under this License on an "as is" * +* basis, without warranty of any kind, either expressed, implied, or * +* statutory, including, without limitation, warranties that the * +* Covered Software is free of defects, merchantable, fit for a * +* particular purpose or non-infringing. The entire risk as to the * +* quality and performance of the Covered Software is with You. * +* Should any Covered Software prove defective in any respect, You * +* (not any Contributor) assume the cost of any necessary servicing, * +* repair, or correction. This disclaimer of warranty constitutes an * +* essential part of this License. No use of any Covered Software is * +* authorized under this License except under this disclaimer. * +* * +************************************************************************ + +************************************************************************ +* * +* 7. Limitation of Liability * +* -------------------------- * +* * +* Under no circumstances and under no legal theory, whether tort * +* (including negligence), contract, or otherwise, shall any * +* Contributor, or anyone who distributes Covered Software as * +* permitted above, be liable to You for any direct, indirect, * +* special, incidental, or consequential damages of any character * +* including, without limitation, damages for lost profits, loss of * +* goodwill, work stoppage, computer failure or malfunction, or any * +* and all other commercial damages or losses, even if such party * +* shall have been informed of the possibility of such damages. This * +* limitation of liability shall not apply to liability for death or * +* personal injury resulting from such party's negligence to the * +* extent applicable law prohibits such limitation. Some * +* jurisdictions do not allow the exclusion or limitation of * +* incidental or consequential damages, so this exclusion and * +* limitation may not apply to You. * +* * +************************************************************************ + +8. Litigation +------------- + +Any litigation relating to this License may be brought only in the +courts of a jurisdiction where the defendant maintains its principal +place of business and such litigation shall be governed by laws of that +jurisdiction, without reference to its conflict-of-law provisions. +Nothing in this Section shall prevent a party's ability to bring +cross-claims or counter-claims. + +9. Miscellaneous +---------------- + +This License represents the complete agreement concerning the subject +matter hereof. If any provision of this License is held to be +unenforceable, such provision shall be reformed only to the extent +necessary to make it enforceable. Any law or regulation which provides +that the language of a contract shall be construed against the drafter +shall not be used to construe this License against a Contributor. + +10. Versions of the License +--------------------------- + +10.1. New Versions + +Mozilla Foundation is the license steward. Except as provided in Section +10.3, no one other than the license steward has the right to modify or +publish new versions of this License. Each version will be given a +distinguishing version number. + +10.2. Effect of New Versions + +You may distribute the Covered Software under the terms of the version +of the License under which You originally received the Covered Software, +or under the terms of any subsequent version published by the license +steward. + +10.3. Modified Versions + +If you create software not governed by this License, and you want to +create a new license for such software, you may create and use a +modified version of this License if you rename the license and remove +any references to the name of the license steward (except to note that +such modified license differs from this License). + +10.4. Distributing Source Code Form that is Incompatible With Secondary +Licenses + +If You choose to distribute Source Code Form that is Incompatible With +Secondary Licenses under the terms of this version of the License, the +notice described in Exhibit B of this License must be attached. + +Exhibit A - Source Code Form License Notice +------------------------------------------- + + This Source Code Form is subject to the terms of the Mozilla Public + License, v. 2.0. If a copy of the MPL was not distributed with this + file, You can obtain one at http://mozilla.org/MPL/2.0/. + +If it is not possible or desirable to put the notice in a particular +file, then You may include the notice in a location (such as a LICENSE +file in a relevant directory) where a recipient would be likely to look +for such a notice. + +You may add additional accurate notices of copyright ownership. + +Exhibit B - "Incompatible With Secondary Licenses" Notice +--------------------------------------------------------- + + This Source Code Form is "Incompatible With Secondary Licenses", as + defined by the Mozilla Public License, v. 2.0. diff --git a/ph-ee-operations-app/README.md b/ph-ee-operations-app/README.md new file mode 100644 index 000000000..5006ff7b5 --- /dev/null +++ b/ph-ee-operations-app/README.md @@ -0,0 +1,3 @@ +# payment-hub-ee +Payment Hub Enterprise Edition middleware for integration to real-time payment systems. +#Auto-trigger diff --git a/ph-ee-operations-app/build.gradle b/ph-ee-operations-app/build.gradle new file mode 100644 index 000000000..143ad2038 --- /dev/null +++ b/ph-ee-operations-app/build.gradle @@ -0,0 +1,85 @@ +/* + * This file was generated by the Gradle 'init' task. + */ + +plugins { + id 'java' + id 'maven-publish' + id 'eclipse' + id 'org.springframework.boot' version '2.5.5' +} +apply plugin: "io.spring.dependency-management" + +repositories { + maven { + url = uri('https://repo.maven.apache.org/maven2') + } + + maven { + url = uri('https://jfrog.sandbox.fynarfin.io/artifactory/fyn-libs-snapshot') + } +} + +ext { + springBootVersion = '2.1.9.RELEASE' +} + +dependencies { + implementation 'org.springframework.security:spring-security-jwt:1.1.0.RELEASE' + implementation 'org.springframework.boot:spring-boot-starter-web' + implementation 'org.springframework.boot:spring-boot-starter-cache' + implementation 'org.springframework.boot:spring-boot-starter-data-jpa' + implementation 'org.springframework.security:spring-security-crypto' + implementation 'org.springframework.security.oauth:spring-security-oauth2:2.4.1.RELEASE' + implementation 'org.json:json:20190722' + implementation 'org.eclipse.persistence:org.eclipse.persistence.jpa:2.7.6' + implementation 'org.hibernate:hibernate-jpamodelgen:5.4.17.Final' + annotationProcessor 'org.hibernate:hibernate-jpamodelgen:5.4.17.Final' + implementation 'joda-time:joda-time:2.10.6' + implementation 'org.apache.commons:commons-lang3:3.3.2' + implementation 'com.zaxxer:HikariCP:3.4.5' + implementation 'mysql:mysql-connector-java:8.0.20' + implementation 'com.googlecode.flyway:flyway-core:2.1.1' + implementation 'net.sf.ehcache:ehcache:2.10.6' + testImplementation 'junit:junit:4.11' + implementation 'net.sf.supercsv:super-csv:2.4.0' + implementation 'com.amazonaws:aws-java-sdk:1.11.486' + implementation 'com.azure:azure-storage-blob:12.12.0' + implementation 'commons-io:commons-io:2.4' + compileOnly 'org.projectlombok:lombok:1.18.24' + annotationProcessor 'org.projectlombok:lombok:1.18.24' + implementation "org.springdoc:springdoc-openapi-ui:1.6.11" + implementation 'org.mifos:ph-ee-connector-common:1.4.1-SNAPSHOT' + implementation "org.springframework.boot:spring-boot-starter:$springBootVersion" + implementation "org.springframework.boot:spring-boot-starter-web:$springBootVersion" + implementation "org.springframework.boot:spring-boot-starter-actuator:$springBootVersion" + +} + +group = 'org.apache.fineract' +version = '1.0.0-SNAPSHOT' +sourceCompatibility = '11' + + +sourceSets { + generated { + java { + srcDirs = ['src/generated/java'] + } + } +} + +publishing { + publications { + maven(MavenPublication) { + from(components.java) + } + } +} + +tasks.withType(JavaCompile) { + options.encoding = 'UTF-8' + options.annotationProcessorGeneratedSourcesDirectory = file("src/generated/java") +} +task bootRun() { +} diff --git a/ph-ee-operations-app/docker-compose.yml b/ph-ee-operations-app/docker-compose.yml new file mode 100644 index 000000000..0ee3ed763 --- /dev/null +++ b/ph-ee-operations-app/docker-compose.yml @@ -0,0 +1,21 @@ +version: '2' +services: + operations-mysql: + image: mysql:5.7 + restart: always + volumes: + - /home/docker/data/mysql:/var/lib/mysql + environment: + MYSQL_ROOT_PASSWORD: mysql + ports: + - "3306:3306" + + operations-app: + build: . + ports: + - 5000:5000 + environment: + FINERACT_DATASOURCE_CORE_HOST: operations-mysql + SPRING_PROFILES_ACTIVE: bb + depends_on: + - operations-mysql diff --git a/ph-ee-operations-app/gradle/wrapper/gradle-wrapper.jar b/ph-ee-operations-app/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 000000000..490fda857 Binary files /dev/null and b/ph-ee-operations-app/gradle/wrapper/gradle-wrapper.jar differ diff --git a/ph-ee-operations-app/gradle/wrapper/gradle-wrapper.properties b/ph-ee-operations-app/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 000000000..a4b442974 --- /dev/null +++ b/ph-ee-operations-app/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-6.3-bin.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/ph-ee-operations-app/gradlew b/ph-ee-operations-app/gradlew new file mode 100755 index 000000000..2fe81a7d9 --- /dev/null +++ b/ph-ee-operations-app/gradlew @@ -0,0 +1,183 @@ +#!/usr/bin/env sh + +# +# Copyright 2015 the original author or authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn () { + echo "$*" +} + +die () { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin or MSYS, switch paths to Windows format before running java +if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=`expr $i + 1` + done + case $i in + 0) set -- ;; + 1) set -- "$args0" ;; + 2) set -- "$args0" "$args1" ;; + 3) set -- "$args0" "$args1" "$args2" ;; + 4) set -- "$args0" "$args1" "$args2" "$args3" ;; + 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=`save "$@"` + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +exec "$JAVACMD" "$@" diff --git a/ph-ee-operations-app/gradlew.bat b/ph-ee-operations-app/gradlew.bat new file mode 100644 index 000000000..9109989e3 --- /dev/null +++ b/ph-ee-operations-app/gradlew.bat @@ -0,0 +1,103 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windows variants + +if not "%OS%" == "Windows_NT" goto win9xME_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/ph-ee-operations-app/settings.gradle b/ph-ee-operations-app/settings.gradle new file mode 100644 index 000000000..27e92f379 --- /dev/null +++ b/ph-ee-operations-app/settings.gradle @@ -0,0 +1,5 @@ +/* + * This file was generated by the Gradle 'init' task. + */ + +rootProject.name = 'operations-app' diff --git a/ph-ee-operations-app/src/main/java/org/apache/fineract/ServerApplication.java b/ph-ee-operations-app/src/main/java/org/apache/fineract/ServerApplication.java new file mode 100644 index 000000000..c7fca7b06 --- /dev/null +++ b/ph-ee-operations-app/src/main/java/org/apache/fineract/ServerApplication.java @@ -0,0 +1,168 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.apache.fineract.core.service.AudienceVerifier; +import org.apache.fineract.core.service.TenantAwareHeaderFilter; +import org.apache.fineract.organisation.tenant.TenantServerConnectionRepository; +import org.mifos.connector.common.interceptor.annotation.EnableJsonWebSignature; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration; +import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; +import org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration; +import org.springframework.boot.autoconfigure.web.servlet.error.ErrorMvcAutoConfiguration; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.boot.web.client.RestTemplateBuilder; +import org.springframework.boot.web.servlet.FilterRegistrationBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Primary; +import org.springframework.core.io.ClassPathResource; +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.authentication.AuthenticationProvider; +import org.springframework.security.authentication.ProviderManager; +import org.springframework.security.authentication.dao.DaoAuthenticationProvider; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.security.oauth2.provider.token.DefaultTokenServices; +import org.springframework.security.oauth2.provider.token.TokenStore; +import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter; +import org.springframework.security.oauth2.provider.token.store.JwtTokenStore; +import org.springframework.web.client.RestTemplate; +import org.springframework.web.cors.CorsConfiguration; +import org.springframework.web.cors.UrlBasedCorsConfigurationSource; +import org.springframework.web.filter.CorsFilter; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.net.URISyntaxException; +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +@SpringBootApplication +@EnableConfigurationProperties +@EnableAutoConfiguration(exclude = {DataSourceAutoConfiguration.class, + DataSourceTransactionManagerAutoConfiguration.class, + FlywayAutoConfiguration.class, + ErrorMvcAutoConfiguration.class}) +@EnableJsonWebSignature +public class ServerApplication { + + /** + * Spring security filter chain ordering, the tenant header filter + * must run before this to set current tenant so it's order has to be lower to gain priority + */ + @Value("${security.filter-order}") + private int securityFilterOrder; + + @Bean + public RestTemplate restTemplate(RestTemplateBuilder builder) { + return builder.build(); + } + + @Bean + public ObjectMapper mapper() { + return new ObjectMapper(); + } + + @Bean + public PasswordEncoder passwordEncoder() { + return new BCryptPasswordEncoder(); + } + + @Bean + public DaoAuthenticationProvider customAuthenticationProvider(PasswordEncoder passwordEncoder, + UserDetailsService userDetailsService) { + DaoAuthenticationProvider provider = new DaoAuthenticationProvider(); + provider.setUserDetailsService(userDetailsService); + provider.setPasswordEncoder(passwordEncoder); + return provider; + } + + @Bean + public FilterRegistrationBean tenantFilter(TenantServerConnectionRepository repository) { + FilterRegistrationBean registration = new FilterRegistrationBean(); + registration.setFilter(new TenantAwareHeaderFilter(repository)); + registration.addUrlPatterns("/*"); + registration.setName("tenantFilter"); + registration.setOrder(Integer.MIN_VALUE+1); + return registration; + } + + @Bean + public FilterRegistrationBean corsFilter() { + CorsConfiguration config = new CorsConfiguration(); + config.setAllowCredentials(true); + config.addAllowedOrigin("*"); + config.addAllowedHeader("*"); + config.addAllowedMethod("*"); + UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); + source.registerCorsConfiguration("/**", config); + FilterRegistrationBean bean = new FilterRegistrationBean(new CorsFilter(source)); + bean.setOrder(securityFilterOrder - 5); + return bean; + } + + @Bean + @Primary + public TokenStore tokenStore(JwtAccessTokenConverter accessTokenConverter) { + return new JwtTokenStore(accessTokenConverter); + } + + @Bean + @Primary + public DefaultTokenServices tokenServices(TokenStore tokenStore) { + DefaultTokenServices service = new DefaultTokenServices(); + service.setTokenStore(tokenStore); + return service; + } + + @Bean + @Primary + public JwtAccessTokenConverter accessTokenConverter(AudienceVerifier verifier) throws IOException, URISyntaxException { + JwtAccessTokenConverter converter = new JwtAccessTokenConverter(); + converter.setSigningKey(getPemContent("jwt.pem")); + converter.setVerifierKey(getPemContent("jwt_pub.pem")); + converter.setJwtClaimsSetVerifier(verifier); + return converter; + } + + private String getPemContent(String file) throws IOException, URISyntaxException { + try (BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(new ClassPathResource(file).getInputStream()))) { + return bufferedReader.lines().collect(Collectors.joining("")); + } + } + + @Bean + public AuthenticationManager authenticationManager(DaoAuthenticationProvider customAuthenticationProvider) { + List providers = new ArrayList<>(); + providers.add(customAuthenticationProvider); + return new ProviderManager(providers); + } + + public static void main(String[] args) throws Exception { + SpringApplication.run(ServerApplication.class, args); + } +} diff --git a/ph-ee-operations-app/src/main/java/org/apache/fineract/api/AssignmentAction.java b/ph-ee-operations-app/src/main/java/org/apache/fineract/api/AssignmentAction.java new file mode 100644 index 000000000..a50791792 --- /dev/null +++ b/ph-ee-operations-app/src/main/java/org/apache/fineract/api/AssignmentAction.java @@ -0,0 +1,5 @@ +package org.apache.fineract.api; + +public enum AssignmentAction { + ASSIGN, REVOKE +} diff --git a/ph-ee-operations-app/src/main/java/org/apache/fineract/api/BatchApi.java b/ph-ee-operations-app/src/main/java/org/apache/fineract/api/BatchApi.java new file mode 100644 index 000000000..300fd9afd --- /dev/null +++ b/ph-ee-operations-app/src/main/java/org/apache/fineract/api/BatchApi.java @@ -0,0 +1,531 @@ +package org.apache.fineract.api; + +import com.fasterxml.jackson.databind.ObjectMapper; +import io.swagger.v3.oas.annotations.security.SecurityRequirement; +import lombok.extern.slf4j.Slf4j; +import org.apache.fineract.config.PaymentModeConfiguration; +import org.apache.fineract.file.FileTransferService; +import org.apache.fineract.operations.*; +import org.apache.fineract.response.BatchAndSubBatchSummaryResponse; +import org.apache.fineract.response.SubBatchSummary; +import org.apache.fineract.service.BatchDbService; +import org.apache.fineract.service.BatchService; +import org.apache.fineract.utils.DateUtil; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Sort; +import org.springframework.util.ObjectUtils; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; +import javax.servlet.http.HttpServletResponse; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileWriter; +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.text.DecimalFormat; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Optional; + +import static org.apache.fineract.core.service.OperatorUtils.strip; + +@Slf4j +@RestController +@SecurityRequirement(name = "auth") +@RequestMapping("/api/v1") +public class BatchApi { + @Autowired + private TransferRepository transferRepository; + + @Autowired + private BatchRepository batchRepository; + + @Autowired + private VariableRepository variableRepository; + + @Autowired + @Qualifier("awsStorage") + private FileTransferService fileTransferService; + + @Autowired + private PaymentModeConfiguration paymentModeConfig; + + @Autowired + private DateUtil dateUtil; + + @Autowired + private ObjectMapper objectMapper; + + @Autowired + private BatchDbService batchDbService; + + @Value("${application.bucket-name}") + private String bucketName; + @Autowired + private BatchService batchService; + + private Sort getSortObject(String sort) { + Sort.Direction sortDirection; + String sortedBy; + if (sort.contains("+") && sort.split("\\+").length == 2) { + sortDirection = Sort.Direction.ASC; + sortedBy = sort.split("\\+")[1]; + } else if (sort.contains("-") && sort.split("-").length == 2) { + sortDirection = Sort.Direction.DESC; + sortedBy = sort.split("-")[1]; + } else { + sortDirection = Sort.Direction.ASC; + sortedBy = sort; + } + sortedBy = sortedBy.replace(" ", ""); + log.info("Sorting by: {} and Sorting direction: {}", sortedBy, sortDirection.name()); + return new Sort(sortDirection, sortedBy); + } + + @GetMapping("/batches") + public BatchPaginatedResponse getBatch(@RequestParam(value = "offset", required = false, defaultValue = "0") + Integer offset, + @RequestParam(value = "limit", required = false, defaultValue = "10") + Integer limit, + @RequestParam(value = "sort", required = false, + defaultValue = "-startedAt") String sort, + @RequestParam(value = "dateFrom", required = false) String startFrom, + @RequestParam(value = "dateTo", required = false) String startTo, + @RequestParam(value = "registeringInstitutionId", required = false, + defaultValue = "%") String registeringInstituteId, + @RequestParam(value = "payerFsp", required = false, defaultValue = "%") + String payerFsp, + @RequestParam(value = "batchId", required = false, defaultValue = "%") + String batchId, + HttpServletResponse httpServletResponse) { + log.info("Registering Id: {}, PayerFsp: {}, batchId: {}", registeringInstituteId, payerFsp, batchId); + Sort sortObject = getSortObject(sort); + int page = Math.floorDiv(offset, limit); + PageRequest pager = PageRequest.of(page, limit, sortObject); + + if (startFrom != null) { + startFrom = dateUtil.getUTCFormat(startFrom); + } + if (startTo != null) { + startTo = dateUtil.getUTCFormat(startTo); + } + try { + BatchPaginatedResponse batchPaginatedResponse; + + if (startFrom != null && startTo != null) { + batchPaginatedResponse = batchDbService.getBatch(startFrom, startTo, registeringInstituteId, payerFsp, batchId, pager); + } else if (startFrom != null) { + batchPaginatedResponse = batchDbService.getBatchDateFrom(startFrom, registeringInstituteId, payerFsp, batchId, pager); + } else if (startTo != null) { + batchPaginatedResponse = batchDbService.getBatchDateTo(startTo, registeringInstituteId, payerFsp, batchId, pager); + } else { + batchPaginatedResponse = batchDbService.getBatch(registeringInstituteId, payerFsp, batchId, pager); + } + httpServletResponse.setStatus(200); + return batchPaginatedResponse; + } catch (Exception e) { + e.printStackTrace(); + httpServletResponse.setStatus(400); + return null; + } + } + + @GetMapping("/batch") + public ResponseEntity batchDetails(@RequestParam(value = "batchId", required = false) String batchId, + @RequestParam(value = "requestId", required = false) String requestId) { + Batch batch = batchRepository.findByBatchId(batchId); + + if (batch == null) { + String errorMessage = "Batch corresponding to batchId: " + batchId + " does not exist."; + return ResponseEntity.status(HttpStatus.NOT_FOUND).body(errorMessage); + } + return ResponseEntity.ok(generateBatchSummaryResponse(batch)); + } + + @GetMapping("/batch/{batchId}") + public ResponseEntity batchAggregation(@PathVariable(value = "batchId") String batchId, + @RequestParam(value = "requestId", required = false) String requestId, + @RequestParam(value = "command", required = false, defaultValue = "aggregate") String command) { + Batch batch = batchRepository.findByBatchId(batchId); + + if (batch == null) { + String errorMessage = "Batch corresponding to batchId: " + batchId + " does not exist."; + return ResponseEntity.status(HttpStatus.NOT_FOUND).body(errorMessage); + } + return ResponseEntity.ok(generateDetails(batch)); + } + + @GetMapping("/batch/detail") + public Page batchDetails(HttpServletResponse httpServletResponse, + @RequestParam(value = "batchId") String batchId, + @RequestParam(value = "status", defaultValue = "ALL") String status, + @RequestParam(value = "pageNo", defaultValue = "0") Integer pageNo, + @RequestParam(value = "pageSize", defaultValue = "10") Integer pageSize, + @RequestParam(value = "command", required = false, defaultValue = "json") String command) { + + if (command.equalsIgnoreCase("download")) { + Batch batch = batchRepository.findByBatchId(batchId); + if (batch != null && batch.getResult_file() != null) { + httpServletResponse.setHeader("Location", batch.getResult_file()); + httpServletResponse.setStatus(302); + } else { + httpServletResponse.setStatus(404); + } + return null; + } + + Page transfers; + List batchAndSubBatches = batchRepository.findAllByBatchId(batchId); + + if (status.equalsIgnoreCase(TransferStatus.COMPLETED.toString()) || + status.equalsIgnoreCase(TransferStatus.IN_PROGRESS.toString()) || + status.equalsIgnoreCase(TransferStatus.FAILED.toString())) { + transfers = transferRepository.findAllByBatchIdAndStatus(batchId, status.toUpperCase(), new PageRequest(pageNo, pageSize)); + } else { + if(batchAndSubBatches.size()>1){ + transfers = transferRepository.findAllByBatchIdMatchSubBatchId(batchId, new PageRequest(pageNo, pageSize)); + } else { + transfers = transferRepository.findAllByBatchId(batchId, new PageRequest(pageNo, pageSize)); + } + } + + return transfers; + } + + @GetMapping("/batch/transactions") + public HashMap batchTransactionDetails(@RequestParam String batchId) { + Batch batch = batchRepository.findByBatchId(batchId); + if (batch != null) { + List transfers = transferRepository.findAllByBatchId(batch.getBatchId()); + HashMap status = new HashMap<>(); + for (Transfer transfer : transfers) { + status.put(transfer.getTransactionId(), transfer.getStatus().name()); + } + return status; + } else { + return null; + } + } + @GetMapping("/batches/{batchId}") + public ResponseEntity getBatchAndSubBatchSummary(@PathVariable String batchId, + @RequestHeader(name = "X-Correlation-ID") String clientCorrelationId, + @RequestParam(value = "offset", required = false, defaultValue = "0") + Integer offset, + @RequestParam(value = "limit", required = false, defaultValue = "10") + Integer limit, + @RequestParam(value = "associations", required = false) + String associations, + @RequestParam(value = "orderBy", required = false, defaultValue = "instructionId") + String orderBy, + @RequestParam(value = "sortBy", required = false, defaultValue = "asc") + String sortBy){ + + if (associations!=null && associations.equals("all")) { + PaymentBatchDetail response = batchService.getPaymentBathDetail(batchId, clientCorrelationId, offset, limit, orderBy, sortBy); + if (ObjectUtils.isEmpty(response)) { + return new ResponseEntity<>(HttpStatus.NOT_FOUND); + } + + return (ResponseEntity) new ResponseEntity<>(response, HttpStatus.OK); + + } else { + BatchAndSubBatchSummaryResponse response = batchService.getBatchAndSubBatchSummary(batchId, clientCorrelationId); + + if (ObjectUtils.isEmpty(response)) { + return new ResponseEntity<>(HttpStatus.NOT_FOUND); + } + + return (ResponseEntity) new ResponseEntity<>(response, HttpStatus.OK); + } + } + @GetMapping("/batches/{batchId}/subBatches/{subBatchId}") + public ResponseEntity getSubBatchPaymentDetail(@PathVariable String batchId, @PathVariable String subBatchId, + @RequestHeader(name = "X-Correlation-ID") String clientCorrelationId, + @RequestParam(value = "offset", required = false, defaultValue = "0") + Integer offset, + @RequestParam(value = "limit", required = false, defaultValue = "10") + Integer limit, + @RequestParam(value = "orderBy", required = false, defaultValue = "instructionId") + String orderBy, + @RequestParam(value = "sortBy", required = false, defaultValue = "asc") + String sortBy){ + + SubBatchSummary response = batchService.getPaymentSubBatchDetail(batchId, subBatchId, clientCorrelationId, offset, limit, orderBy, sortBy); + + if (ObjectUtils.isEmpty(response)) { + return new ResponseEntity<>(HttpStatus.NOT_FOUND); + } + + return (ResponseEntity) new ResponseEntity<>(response, HttpStatus.OK); + } + private void saveBatch(Batch batch,Long completed,Long ongoing,Long failed, + Long totalTransfers,Long totalAmount,Long totalCompletedAmount, + Long totalOngoingAmount,Long totalFailedAmount){ + batch.setCompleted(completed); + batch.setFailed(failed); + batch.setResultGeneratedAt(new Date()); + batch.setOngoing(ongoing); + batch.setTotalTransactions(totalTransfers); + batch.setTotalAmount(totalAmount); + batch.setCompletedAmount(totalCompletedAmount); + batch.setOngoingAmount(totalOngoingAmount); + batch.setFailedAmount(totalFailedAmount); + batch.setCompletedAt(new Date()); + if(completed.equals(totalTransfers)){ + batch.setStatus(BatchStatus.COMPLETED); + } else if(ongoing > 0){ + batch.setStatus(BatchStatus.IN_PROGRESS); + } else if(failed>0){ + batch.setStatus(BatchStatus.FAILED); + } + batchRepository.save(batch); + } + private BatchDTO getBatchSummary(Batch batch,String modes) { + Double batchCompletedPercent = 0.0; + Double batchFailedPercent = 0.0; + if (batch.getCompleted() != null){ + batchCompletedPercent = (double) batch.getCompleted() / batch.getTotalTransactions() * 100; + } + if(batch.getFailed() != null){ + batchFailedPercent = (double) batch.getFailed() / batch.getTotalTransactions() * 100; + } + + BatchDTO response = new BatchDTO(batch.getBatchId(), + batch.getRequestId(), batch.getTotalTransactions(), batch.getOngoing(), + batch.getFailed(), batch.getCompleted(),BigDecimal.valueOf(batch.getTotalAmount()),BigDecimal.valueOf(batch.getCompletedAmount()), + BigDecimal.valueOf(batch.getOngoingAmount()), BigDecimal.valueOf(batch.getFailedAmount()), batch.getResult_file(), batch.getNote(), + batchFailedPercent.toString(),batchCompletedPercent.toString(), batch.getRegisteringInstitutionId(), + batch.getPayerFsp(), batch.getCorrelationId()); + + response.setCreatedAt("" + batch.getStartedAt()); + response.setModes(modes); + response.setPurpose("Unknown purpose"); + System.out.println("Batch details generated for batchId: " + response.getSuccessPercentage()); + + if (batch.getCompleted().longValue() == batch.getTotalTransactions().longValue()) { + response.setStatus("COMPLETED"); + } else if (batch.getOngoing() != 0 && batch.getCompletedAt() == null) { + response.setStatus("Pending"); + } else if (batch.getFailed().longValue() == batch.getFailed().longValue()) { + response.setStatus("Failed"); + } else { + response.setStatus("UNKNOWN"); + } + + return response; + } + private void evaluateBatchSummary(Batch batch) { + Long completed = 0L; + Long failed = 0L; + Long total = 0L; + Long ongoing = 0L; + BigDecimal totalAmount = BigDecimal.ZERO; + BigDecimal completedAmount = BigDecimal.ZERO; + BigDecimal ongoingAmount = BigDecimal.ZERO; + BigDecimal failedAmount = BigDecimal.ZERO; + List transfers = null; + if(batch.getSubBatchId()!=null){ + transfers = transferRepository.findAllByBatchId(batch.getSubBatchId()); + }else{ + transfers = transferRepository.findAllByBatchId(batch.getBatchId()); + } + + for (Transfer transfer : transfers) { + Optional variable = variableRepository.findByWorkflowInstanceKeyAndVariableName("paymentMode", + transfer.getWorkflowInstanceKey()); + if (variable.isPresent()) { + // this will prevent 2x count of variables by eliminating data from transfers table + if (paymentModeConfig.getByMode(strip(variable.get().getValue())) + .getType().equalsIgnoreCase("BATCH")) { + continue; + } + } + total++; + BigDecimal amount = transfer.getAmount(); + totalAmount = totalAmount.add(amount); + if (transfer.getStatus().equals(TransferStatus.COMPLETED)) { + completed++; + completedAmount = completedAmount.add(amount); + } else if (transfer.getStatus().equals(TransferStatus.FAILED)) { + failed++; + failedAmount = failedAmount.add(amount); + } else if (transfer.getStatus().equals(TransferStatus.IN_PROGRESS)) { + if (transfer.getCompletedAt() == null || transfer.getCompletedAt().toString().isEmpty()) { + ongoing++; + ongoingAmount = ongoingAmount.add(amount); + } else { + completed++; + completedAmount = completedAmount.add(amount); + } + } + } + if (batch.getResult_file() == null || (batch.getResult_file() != null && batch.getResult_file().isEmpty())) { + batch.setResult_file(createDetailsFile(transfers)); + } + saveBatch(batch, completed, ongoing, failed, total, totalAmount.longValue(), completedAmount.longValue(), ongoingAmount.longValue(), failedAmount.longValue()); + } + private Batch getParentBatchSummary(List batches){ + StringBuilder modes = new StringBuilder(); + + Long subBatchFailed = 0L; + Long subBatchCompleted = 0L; + Long subBatchOngoing = 0L; + Long subBatchTotal = 0L; + + BigDecimal totalAmount = BigDecimal.ZERO; + BigDecimal completedAmount = BigDecimal.ZERO; + BigDecimal ongoingAmount = BigDecimal.ZERO; + BigDecimal failedAmount = BigDecimal.ZERO; + Batch parentBatch = null; + + for (Batch bt : batches) { + if (bt.getPaymentMode() != null && !modes.toString().contains(bt.getPaymentMode())) { + if (!modes.toString().equals("")) { + modes.append(","); + } + modes.append(bt.getPaymentMode()); + } + if (bt.getSubBatchId() == null || bt.getSubBatchId().isEmpty()) { + parentBatch = bt; + continue; + } + if (bt.getFailed() != null) { + subBatchFailed += bt.getFailed(); + failedAmount = failedAmount.add(BigDecimal.valueOf(bt.getFailedAmount())); + } + if (bt.getCompleted() != null) { + subBatchCompleted += bt.getCompleted(); + completedAmount = completedAmount.add(BigDecimal.valueOf(bt.getCompletedAmount())); + } + if (bt.getOngoing() != null) { + subBatchOngoing += bt.getOngoing(); + ongoingAmount = ongoingAmount.add(BigDecimal.valueOf(bt.getOngoingAmount())); + } + if (bt.getTotalTransactions() != null) { + subBatchTotal += bt.getTotalTransactions(); + totalAmount = totalAmount.add(BigDecimal.valueOf(bt.getTotalAmount())); + } + } + saveBatch(parentBatch,subBatchCompleted,subBatchOngoing,subBatchFailed,subBatchTotal, + totalAmount.longValue(),completedAmount.longValue(),ongoingAmount.longValue(),failedAmount.longValue()); + return parentBatch; + } + private BatchDTO generateDetails(Batch batch){ + + StringBuilder modes = new StringBuilder(); + List batches = batchRepository.findAllByBatchId(batch.getBatchId()); + for (Batch subBatch:batches){ + if (subBatch.getPaymentMode() != null && !modes.toString().contains(subBatch.getPaymentMode())) { + if (!modes.toString().equals("")) { + modes.append(","); + } + modes.append(subBatch.getPaymentMode()); + } + evaluateBatchSummary(subBatch); + } + Batch parentBatchSummary = null; + if(batches.size()==1){ + parentBatchSummary = batch; + }else{ + parentBatchSummary = getParentBatchSummary(batches); + } + + + return getBatchSummary(parentBatchSummary, modes.toString()); + } + + private String createDetailsFile(List transfers) { + String CSV_SEPARATOR = ","; + File tempFile = new File(System.currentTimeMillis() + "_response.csv"); + try ( + FileWriter writer = new FileWriter(tempFile.getName()); + BufferedWriter bw = new BufferedWriter(writer)) { + for (Transfer transfer : transfers) { + StringBuffer oneLine = new StringBuffer(); + oneLine.append(transfer.getTransactionId()); + oneLine.append(CSV_SEPARATOR); + oneLine.append(transfer.getStatus().toString()); + oneLine.append(CSV_SEPARATOR); + oneLine.append(transfer.getPayeeDfspId()); + oneLine.append(CSV_SEPARATOR); + oneLine.append(transfer.getPayeePartyId()); + oneLine.append(CSV_SEPARATOR); + oneLine.append(transfer.getPayerDfspId()); + oneLine.append(CSV_SEPARATOR); + oneLine.append(transfer.getPayerPartyId()); + oneLine.append(CSV_SEPARATOR); + oneLine.append(transfer.getAmount().toString()); + oneLine.append(CSV_SEPARATOR); + oneLine.append(transfer.getCurrency()); + oneLine.append(CSV_SEPARATOR); + oneLine.append(transfer.getErrorInformation()); + oneLine.append(CSV_SEPARATOR); + oneLine.append(transfer.getStartedAt().toString()); + oneLine.append(CSV_SEPARATOR); + oneLine.append(transfer.getCompletedAt().toString()); + oneLine.append(CSV_SEPARATOR); + bw.write(oneLine.toString()); + bw.newLine(); + } + bw.flush(); + return fileTransferService.uploadFile(tempFile, bucketName); + } catch (Exception e) { + System.err.format("Exception: %s%n", e); + } + return null; + } + + private BatchDTO generateBatchSummaryResponse(Batch batch) { + double batchFailedPercent = 0; + double batchCompletedPercent = 0; + + if(batch.getTotalTransactions() != null){ + batchFailedPercent = ((double) batch.getFailed()) / batch.getTotalTransactions() * 100; + batchCompletedPercent = ((double) batch.getCompleted()) / batch.getTotalTransactions() * 100; + } + + DecimalFormat decimalFormat = new DecimalFormat("#.##"); + decimalFormat.setRoundingMode(RoundingMode.FLOOR); + + Optional totalAmount = Optional.ofNullable(batch.getTotalAmount()); + Optional completedAmount = Optional.ofNullable(batch.getCompletedAmount()); + Optional ongoingAmount = Optional.ofNullable(batch.getOngoingAmount()); + Optional failedAmount = Optional.ofNullable(batch.getFailedAmount()); + + Long nullValue = 0L; + + BatchDTO batchDTO = new BatchDTO(batch.getBatchId(), + batch.getRequestId(), batch.getTotalTransactions(), batch.getOngoing(), + batch.getFailed(), batch.getCompleted(), + BigDecimal.valueOf(totalAmount.orElse(nullValue)), + BigDecimal.valueOf(completedAmount.orElse(nullValue)), + BigDecimal.valueOf(ongoingAmount.orElse(nullValue)), + BigDecimal.valueOf(failedAmount.orElse(nullValue)), + batch.getResult_file(), batch.getNote(), + decimalFormat.format(batchFailedPercent), decimalFormat.format(batchCompletedPercent), + batch.getRegisteringInstitutionId(), batch.getPayerFsp(), batch.getCorrelationId()); + + if (batch.getTotalTransactions() != null && + batch.getCompleted() != null && + batch.getTotalTransactions().longValue() == batch.getCompleted().longValue()) { + batchDTO.setStatus("COMPLETED"); + } else if (batch.getOngoing() != null && batch.getOngoing() != 0 && batch.getCompletedAt() == null) { + batchDTO.setStatus("Pending"); + } else { + batchDTO.setStatus("UNKNOWN"); + } + + return batchDTO; + } + +} diff --git a/ph-ee-operations-app/src/main/java/org/apache/fineract/api/BeneficiaryApi.java b/ph-ee-operations-app/src/main/java/org/apache/fineract/api/BeneficiaryApi.java new file mode 100644 index 000000000..b47308ea9 --- /dev/null +++ b/ph-ee-operations-app/src/main/java/org/apache/fineract/api/BeneficiaryApi.java @@ -0,0 +1,61 @@ +package org.apache.fineract.api; + +import io.swagger.v3.oas.annotations.security.SecurityRequirement; +import org.apache.fineract.operations.Beneficiary; +import org.apache.fineract.operations.BeneficiaryRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.MediaType; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import javax.servlet.http.HttpServletResponse; +import java.util.List; + +@RestController +@SecurityRequirement(name = "auth") +@RequestMapping("/api/v1") +public class BeneficiaryApi { + + @Autowired + BeneficiaryRepository beneficiaryRepository; + + @PostMapping(path = "/beneficiary", consumes = MediaType.APPLICATION_JSON_VALUE) + public void create(@RequestBody Beneficiary beneficiary, HttpServletResponse response) { + Beneficiary existing = beneficiaryRepository.findOneByCustIdentifierAndIdentifier(beneficiary.getCustIdentifier(), + beneficiary.getIdentifier()); + if(existing == null){ + beneficiary.setId(null); + beneficiaryRepository.save(beneficiary); + }else{ + response.setStatus(HttpServletResponse.SC_CONFLICT); + } + } + + @GetMapping(path = "/beneficiary/{custIdentifier}", produces = MediaType.APPLICATION_JSON_VALUE) + public List getAllForCustomer(@PathVariable("custIdentifier") String custIdentifier, HttpServletResponse response) { + List beneficiaries = beneficiaryRepository.findBycustIdentifier(custIdentifier); + if(beneficiaries != null) { + beneficiaries.forEach(b -> b.removeId()); + return beneficiaries; + } else { + response.setStatus(HttpServletResponse.SC_NOT_FOUND); + return null; + } + } + + @DeleteMapping(path = "/beneficiary/{custIdentifier}/{identifier}", produces = MediaType.TEXT_HTML_VALUE) + public void delete(@PathVariable("custIdentifier") String custIdentifier, + @PathVariable("identifier") String identifier, HttpServletResponse response) { + Beneficiary beneficiary = beneficiaryRepository.findOneByCustIdentifierAndIdentifier(custIdentifier, identifier); + if(beneficiary != null){ + beneficiaryRepository.delete(beneficiary); + }else{ + response.setStatus(HttpServletResponse.SC_NOT_FOUND); + } + } +} diff --git a/ph-ee-operations-app/src/main/java/org/apache/fineract/api/EntityAssignments.java b/ph-ee-operations-app/src/main/java/org/apache/fineract/api/EntityAssignments.java new file mode 100644 index 000000000..2633248ef --- /dev/null +++ b/ph-ee-operations-app/src/main/java/org/apache/fineract/api/EntityAssignments.java @@ -0,0 +1,19 @@ +package org.apache.fineract.api; + +import java.util.List; + +public class EntityAssignments { + + private List entityIds; + + public EntityAssignments() { + } + + public List getEntityIds() { + return entityIds; + } + + public void setEntityIds(List entityIds) { + this.entityIds = entityIds; + } +} diff --git a/ph-ee-operations-app/src/main/java/org/apache/fineract/api/ErrorCodesCRUDApi.java b/ph-ee-operations-app/src/main/java/org/apache/fineract/api/ErrorCodesCRUDApi.java new file mode 100644 index 000000000..4120e9ec7 --- /dev/null +++ b/ph-ee-operations-app/src/main/java/org/apache/fineract/api/ErrorCodesCRUDApi.java @@ -0,0 +1,76 @@ +package org.apache.fineract.api; + +import org.apache.fineract.operations.ErrorCode; +import org.apache.fineract.operations.ErrorCodeRepository; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import java.util.ArrayList; +import java.util.List; + +@RestController +@RequestMapping("/api/v1/errorcode") +public class ErrorCodesCRUDApi { + + private Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Autowired + private ErrorCodeRepository errorCodesRepository; + + @PostMapping("/") + public ErrorCode addErrorCode(@RequestBody ErrorCode errorCode) { + ErrorCode response = errorCodesRepository.save(errorCode); + return response; + } + + @GetMapping("/") + public List getAllErrorCode() { + List errorCodes = new ArrayList<>(); + errorCodesRepository.findAll().forEach(errorCodes::add); + return errorCodes; + } + + @GetMapping("/{id}") + public ErrorCode getSpecificErrorCode(@PathVariable Long id) { + return errorCodesRepository.findById(id).get(); + } + + @GetMapping("/filter") + public List getErrorCodeByFilter(@RequestParam("by") String filterType, @RequestParam("value") Object value) { + switch (filterType){ + case "errorCode": + return errorCodesRepository.getErrorCodesByErrorCode(value.toString()); + case "recoverable": + boolean option = value.toString().equals("true"); + return errorCodesRepository.getErrorCodesByRecoverable(option); + case "transactionType": + return errorCodesRepository.getErrorCodesByTransactionType(value.toString()); + default: + return null; + } + } + + @PutMapping("/{id}") + public ErrorCode updateErrorCode(@PathVariable Long id, @RequestBody ErrorCode errorCode) { + errorCode.setId(id); + ErrorCode response = errorCodesRepository.save(errorCode); + return response; + } + + @DeleteMapping("/{id}") + public ErrorCode deleteErrorCode(@PathVariable Long id) { + ErrorCode errorCode = getSpecificErrorCode(id); + errorCodesRepository.deleteById(id); + return errorCode; + } +} diff --git a/ph-ee-operations-app/src/main/java/org/apache/fineract/api/IMUConversionApi.java b/ph-ee-operations-app/src/main/java/org/apache/fineract/api/IMUConversionApi.java new file mode 100644 index 000000000..a85d9dd63 --- /dev/null +++ b/ph-ee-operations-app/src/main/java/org/apache/fineract/api/IMUConversionApi.java @@ -0,0 +1,130 @@ +package org.apache.fineract.api; + +import io.swagger.v3.oas.annotations.security.SecurityRequirement; +import org.apache.fineract.data.IMUConversionData; +import org.apache.fineract.operations.CurrencyRate; +import org.apache.fineract.operations.CurrencyRateLock; +import org.apache.fineract.operations.CurrencyRateLockRepository; +import org.apache.fineract.operations.CurrencyRateRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.MediaType; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import javax.servlet.http.HttpServletResponse; +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.Calendar; +import java.util.Date; +import java.util.GregorianCalendar; +import java.util.List; +import java.util.UUID; + +@RestController +@SecurityRequirement(name = "auth") +@RequestMapping("/api/v1") +public class IMUConversionApi { + @Autowired + private CurrencyRateRepository currencyRateRepository; + + @Autowired + private CurrencyRateLockRepository currencyRateLockRepository; + + @Value("${config.imu.rate-validity-seconds}") + private Integer imuRateValidSeconds; + + @PostMapping(path = "/imuexchange/preview", consumes = MediaType.APPLICATION_JSON_VALUE, + produces = MediaType.APPLICATION_JSON_VALUE) + public IMUConversionData create(@RequestBody IMUConversionData imuConversion, HttpServletResponse response) { + Date currentDate = new Date(); + Date expireBy = this.getExpireBy(currentDate); + BigDecimal rate = null; + String uniqueKey = null; + if(imuConversion.getLockKey() != null){ + CurrencyRateLock lockedRate = currencyRateLockRepository.findOneByUniqueKey(imuConversion.getLockKey()); + if(lockedRate == null){ + uniqueKey = imuConversion.getLockKey(); + }else if(!lockedRate.isExpiredAtDate(currentDate)){//?? + rate = lockedRate.getRate(); + if(!imuConversion.getFailWhenExpired()){ + lockedRate.setExpireBy(expireBy); + currencyRateLockRepository.save(lockedRate); + } + imuConversion.setExpireBy(lockedRate.getExpireBy()); + }else if(imuConversion.getFailWhenExpired()){ + response.setStatus(HttpServletResponse.SC_FORBIDDEN); + imuConversion.setErrorCode("002"); + imuConversion.setErrorMessage("Conversion Rate Expired!"); + return imuConversion; + } + } + if(rate == null){ + CurrencyRate exchange = currencyRateRepository.findOneByFromCurrencyAndToCurrency(imuConversion.getFrom(), imuConversion.getTo()); + if (exchange != null) { + rate = exchange.getRate(); + if(uniqueKey == null){ + uniqueKey = UUID.randomUUID().toString(); + } + CurrencyRateLock lockedRate = exchange.getLock(uniqueKey, expireBy); + currencyRateLockRepository.save(lockedRate); + imuConversion.setLockKey(uniqueKey); + imuConversion.setExpireBy(expireBy); + } + } + if(rate != null){ + BigDecimal convertedAmount = rate.multiply(imuConversion.getAmount()); + imuConversion.setRate(rate); + imuConversion.setConvertedAmount(convertedAmount); + } else { + response.setStatus(HttpServletResponse.SC_NOT_FOUND); + imuConversion.setErrorCode("001"); + imuConversion.setErrorMessage("Master data not found"); + } + return imuConversion; + } + + @PostMapping(path = "/imuexchange/master", consumes = MediaType.APPLICATION_JSON_VALUE) + public void create(@RequestBody List exchangeRates, HttpServletResponse response) { + + List currencyRates = new ArrayList<>(); + + Date currentDate = new Date(); + for(IMUConversionData exchangeRate : exchangeRates){ + CurrencyRate exchange = currencyRateRepository.findOneByFromCurrencyAndToCurrency(exchangeRate.getFrom(), exchangeRate.getTo()); + + if(exchange != null){ + exchange.setRate(exchangeRate.getRate()); + exchange.setLastUpdated(currentDate); + }else{ + exchange = new CurrencyRate(exchangeRate.getFrom(), exchangeRate.getTo(), exchangeRate.getRate(), currentDate); + } + currencyRates.add(exchange); + } + currencyRateRepository.saveAll(currencyRates); + } + + @DeleteMapping(path = "/imuexchange/master", consumes = MediaType.APPLICATION_JSON_VALUE) + public void delete(@RequestBody IMUConversionData imuConversion, HttpServletResponse response) { + CurrencyRate exchange = currencyRateRepository.findOneByFromCurrencyAndToCurrency(imuConversion.getFrom(), imuConversion.getTo()); + if (exchange != null) { + currencyRateRepository.delete(exchange); + } else { + response.setStatus(HttpServletResponse.SC_FORBIDDEN); + imuConversion.setErrorCode("001"); + imuConversion.setErrorMessage("Master data not found"); + } + } + + private Date getExpireBy(Date curDate){ + Calendar gcal = new GregorianCalendar(); + gcal.setTime(curDate); + gcal.add(Calendar.SECOND, imuRateValidSeconds); + return gcal.getTime(); + } + +} + diff --git a/ph-ee-operations-app/src/main/java/org/apache/fineract/api/OperationsApi.java b/ph-ee-operations-app/src/main/java/org/apache/fineract/api/OperationsApi.java new file mode 100644 index 000000000..9212df084 --- /dev/null +++ b/ph-ee-operations-app/src/main/java/org/apache/fineract/api/OperationsApi.java @@ -0,0 +1,198 @@ +package org.apache.fineract.api; + + +import com.amazonaws.services.fms.model.InvalidInputException; +import io.swagger.v3.oas.annotations.security.SecurityRequirement; +import org.apache.fineract.operations.BatchRepository; +import org.apache.fineract.operations.BusinessKey; +import org.apache.fineract.operations.BusinessKeyRepository; +import org.apache.fineract.operations.Task; +import org.apache.fineract.operations.TaskRepository; +import org.apache.fineract.operations.TransactionRequest; +import org.apache.fineract.operations.TransactionRequestDetail; +import org.apache.fineract.operations.TransactionRequestRepository; +import org.apache.fineract.operations.Transfer; +import org.apache.fineract.operations.TransferDetail; +import org.apache.fineract.operations.TransferRepository; +import org.apache.fineract.operations.TransferStatus; +import org.apache.fineract.operations.Variable; +import org.apache.fineract.operations.VariableRepository; +import org.json.JSONArray; +import org.json.JSONObject; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestHeader; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.client.RestTemplate; + +import javax.servlet.http.HttpServletResponse; +import java.util.HashMap;import java.util.List; +import java.util.Map;import java.util.stream.Collectors; + +@RestController +@SecurityRequirement(name = "auth") +@RequestMapping("/api/v1") +public class OperationsApi { + private Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Autowired + private BusinessKeyRepository businessKeyRepository; + + @Autowired + private TaskRepository taskRepository; + + @Autowired + private VariableRepository variableRepository; + + @Autowired + private TransferRepository transferRepository; + + @Autowired + private TransactionRequestRepository transactionRequestRepository; + + @Autowired + private BatchRepository batchRepository; + + @Autowired + private RestTemplate restTemplate; + + @Value("${channel-connector.url}") + private String channelConnectorUrl; + + @Value("${channel-connector.transfer-path}") + private String channelConnectorTransferPath; + + @PostMapping("/transfer/{transactionId}/refund") + public String refundTransfer(@RequestHeader("Platform-TenantId") String tenantId, + @PathVariable("transactionId") String transactionId, + @RequestBody String requestBody, + HttpServletResponse response) { + Transfer existingIncomingTransfer = transferRepository.findFirstByTransactionIdAndDirection(transactionId, "INCOMING"); + if (existingIncomingTransfer == null || !TransferStatus.COMPLETED.equals(existingIncomingTransfer.getStatus())) { + response.setStatus(HttpServletResponse.SC_NOT_FOUND); + JSONObject failResponse = new JSONObject(); + failResponse.put("response", "Requested incoming transfer does not exist or not yet completed!"); + return failResponse.toString(); + } + + HttpHeaders httpHeaders = new HttpHeaders(); + httpHeaders.add("Platform-TenantId", tenantId); + httpHeaders.add("Content-Type", "application/json"); + // httpHeaders.add("Authorization", "Bearer token"); TODO auth needed? + + JSONObject channelRequest = new JSONObject(); + JSONObject payer = new JSONObject(); + JSONObject payerPartyIdInfo = new JSONObject(); + payerPartyIdInfo.put("partyIdType", existingIncomingTransfer.getPayeePartyIdType()); + payerPartyIdInfo.put("partyIdentifier", existingIncomingTransfer.getPayeePartyId()); + payer.put("partyIdInfo", payerPartyIdInfo); + channelRequest.put("payer", payer); + JSONObject payee = new JSONObject(); + JSONObject payeePartyIdInfo = new JSONObject(); + payeePartyIdInfo.put("partyIdType", existingIncomingTransfer.getPayerPartyIdType()); + payeePartyIdInfo.put("partyIdentifier", existingIncomingTransfer.getPayerPartyId()); + payee.put("partyIdInfo", payeePartyIdInfo); + channelRequest.put("payee", payee); + JSONObject amount = new JSONObject(); + amount.put("amount", existingIncomingTransfer.getAmount()); + amount.put("currency", existingIncomingTransfer.getCurrency()); + channelRequest.put("amount", amount); + try { + JSONObject body = new JSONObject(requestBody); + String comment = body.optString("comment", null); + if (comment != null) { + JSONObject extensionList = new JSONObject(); + JSONArray extensions = new JSONArray(); + addExtension(extensions, "comment", comment); + extensionList.put("extension", extensions); + channelRequest.put("extensionList", extensionList); + } + } catch (Exception e) { + logger.error("Could not parse refund request body {}, can not set comment on refund!", requestBody); + } + + ResponseEntity channelResponse = restTemplate.exchange(channelConnectorUrl + channelConnectorTransferPath, + HttpMethod.POST, + new HttpEntity(channelRequest.toString(), httpHeaders), + String.class); + response.setStatus(channelResponse.getStatusCodeValue()); + return channelResponse.getBody(); + } + + private void addExtension(JSONArray extensionList, String key, String value) { + JSONObject extension = new JSONObject(); + extension.put("key", key); + extension.put("value", value); + extensionList.put(extension); + } + + @GetMapping("/transfer/{workflowInstanceKey}") + public TransferDetail transferDetails(@PathVariable Long workflowInstanceKey) { + Transfer transfer = transferRepository.findFirstByWorkflowInstanceKey(workflowInstanceKey); + List tasks = taskRepository.findByWorkflowInstanceKeyOrderByTimestamp(workflowInstanceKey); + List variables = variableRepository.findByWorkflowInstanceKeyOrderByTimestamp(workflowInstanceKey); + return new TransferDetail(transfer, tasks, variables); + } + + @GetMapping("/transactionRequest/{workflowInstanceKey}") + public TransactionRequestDetail transactionRequestDetails(@PathVariable Long workflowInstanceKey) { + TransactionRequest transactionRequest = transactionRequestRepository.findFirstByWorkflowInstanceKey(workflowInstanceKey); + List tasks = taskRepository.findByWorkflowInstanceKeyOrderByTimestamp(workflowInstanceKey); + List variables = variableRepository.findByWorkflowInstanceKeyOrderByTimestamp(workflowInstanceKey); + return new TransactionRequestDetail(transactionRequest, tasks, variables); + } + + @GetMapping("/variables") + public List> variables( + @RequestParam(value = "businessKey") String businessKey, + @RequestParam(value = "businessKeyType") String businessKeyType + ) { + return loadTransfers(businessKey, businessKeyType).stream() + .map(transfer -> variableRepository.findByWorkflowInstanceKeyOrderByTimestamp(transfer.getWorkflowInstanceKey())) + .collect(Collectors.toList()); + } + + @GetMapping("/variables/{transactionId}") + public Map variablesList( @PathVariable String transactionId) { + Long workflowInstanceKey = transferRepository.findFirstByTransactionId(transactionId) + .map(Transfer::getWorkflowInstanceKey) + .orElseGet(() -> Long.valueOf(transactionRequestRepository.findFirstByTransactionId(transactionId) + .map(TransactionRequest::getWorkflowInstanceKey) + .orElseThrow(() -> new InvalidInputException("Transaction Id does not exist")))); + HashMap variables = new HashMap<>(); + variableRepository.findByWorkflowInstanceKeyOrderByTimestamp(workflowInstanceKey).forEach(variable -> { + variables.put(variable.getName(), variable.getValue()); + }); + return variables; + } + + @GetMapping("/tasks") + public List> tasks( + @RequestParam(value = "businessKey") String businessKey, + @RequestParam(value = "businessKeyType") String businessKeyType + ) { + return loadTransfers(businessKey, businessKeyType).stream() + .map(transfer -> taskRepository.findByWorkflowInstanceKeyOrderByTimestamp(transfer.getWorkflowInstanceKey())) + .collect(Collectors.toList()); + } + + private List loadTransfers(@RequestParam("businessKey") String + businessKey, @RequestParam("businessKeyType") String businessKeyType) { + List businessKeys = businessKeyRepository.findByBusinessKeyAndBusinessKeyType(businessKey, businessKeyType); + logger.debug("loaded {} transfer(s) for business key {} of type {}", businessKeys.size(), businessKey, businessKeyType); + return businessKeys; + } + +} diff --git a/ph-ee-operations-app/src/main/java/org/apache/fineract/api/OperationsDetailedApi.java b/ph-ee-operations-app/src/main/java/org/apache/fineract/api/OperationsDetailedApi.java new file mode 100644 index 000000000..2896a95b2 --- /dev/null +++ b/ph-ee-operations-app/src/main/java/org/apache/fineract/api/OperationsDetailedApi.java @@ -0,0 +1,587 @@ +package org.apache.fineract.api; + +import com.fasterxml.jackson.databind.ObjectMapper; +import io.swagger.v3.oas.annotations.security.SecurityRequirement; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.apache.fineract.data.ErrorResponse; +import org.apache.fineract.exception.WriteToCsvException; +import org.apache.fineract.operations.*; +import org.apache.fineract.utils.CsvUtility; +import org.apache.fineract.utils.DateUtil; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageImpl; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Sort; +import org.springframework.data.jpa.domain.Specifications; +import org.springframework.web.bind.annotation.*; + +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.math.BigDecimal; +import java.net.URLDecoder; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import static org.apache.fineract.core.service.OperatorUtils.dateFormat; + +@RestController +@RequestMapping("/api/v1") +@SecurityRequirement(name = "auth") +@Tag(name = "Operations Detailed API") +@SecurityRequirement(name = "api") +public class OperationsDetailedApi { + + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Autowired + private TransferRepository transferRepository; + + @Autowired + private TransactionRequestRepository transactionRequestRepository; + + @Autowired + private ObjectMapper objectMapper; + + @Autowired + private DateUtil dateUtil; + + @GetMapping("/transfers") + public Page transfers( + @RequestParam(value = "page", required = false, defaultValue = "0") Integer page, + @RequestParam(value = "size", required = false, defaultValue = "1") Integer size, + @RequestParam(value = "payerPartyId", required = false) String payerPartyId, + @RequestParam(value = "payerDfspId", required = false) String payerDfspId, + @RequestParam(value = "payeePartyId", required = false) String payeePartyId, + @RequestParam(value = "payeeDfspId", required = false) String payeeDfspId, + @RequestParam(value = "transactionId", required = false) String transactionId, + @RequestParam(value = "status", required = false) String status, + @RequestParam(value = "amount", required = false) BigDecimal amount, + @RequestParam(value = "currency", required = false) String currency, + @RequestParam(value = "startFrom", required = false) String startFrom, + @RequestParam(value = "startTo", required = false) String startTo, + @RequestParam(value = "direction", required = false) String direction, + @RequestParam(value = "sortedBy", required = false) String sortedBy, + @RequestParam(value = "partyId", required = false) String partyId, + @RequestParam(value = "partyIdType", required = false) String partyIdType, + @RequestParam(value = "clientCorrelationId", required = false) String clientCorrelationId, + @RequestParam(value = "sortedOrder", required = false, defaultValue = "DESC") String sortedOrder) { + List> specs = new ArrayList<>(); + + if (payerPartyId != null) { + if (payerPartyId.contains("%2B")) { + try { + payerPartyId = URLDecoder.decode(payerPartyId, "UTF-8"); + logger.info("Decoded payerPartyId: " + payerPartyId); + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + } + } + specs.add(TransferSpecs.match(Transfer_.payerPartyId, payerPartyId)); + } + if (payeePartyId != null) { + if (payeePartyId.contains("%2B")) { + try { + payeePartyId = URLDecoder.decode(payeePartyId, "UTF-8"); + logger.info("Decoded payeePartyId: " + payeePartyId); + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + } + } + specs.add(TransferSpecs.match(Transfer_.payeePartyId, payeePartyId)); + } + if (payeeDfspId != null) { + specs.add(TransferSpecs.match(Transfer_.payeeDfspId, payeeDfspId)); + } + if (payerDfspId != null) { + specs.add(TransferSpecs.match(Transfer_.payerDfspId, payerDfspId)); + } + if (transactionId != null) { + specs.add(TransferSpecs.match(Transfer_.transactionId, transactionId)); + } + if (clientCorrelationId != null) { + specs.add(TransferSpecs.match(Transfer_.clientCorrelationId, clientCorrelationId)); + } + if (status != null && parseStatus(status) != null) { + specs.add(TransferSpecs.match(Transfer_.status, parseStatus(status))); + } + if (amount != null) { + specs.add(TransferSpecs.match(Transfer_.amount, amount)); + } + if (currency != null) { + specs.add(TransferSpecs.match(Transfer_.currency, currency)); + } + if (direction != null) { + specs.add(TransferSpecs.match(Transfer_.direction, direction)); + } + if (partyIdType != null) { + specs.add(TransferSpecs.multiMatch(Transfer_.payeePartyIdType, Transfer_.payerPartyIdType, partyIdType)); + } + if (partyId != null) { + if (partyId.contains("%2B")) { + try { + partyId = URLDecoder.decode(partyId, "UTF-8"); + logger.info("Decoded PartyId: " + partyId); + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + } + } + specs.add(TransferSpecs.multiMatch(Transfer_.payerPartyId, Transfer_.payeePartyId, partyId)); + } + if (startFrom != null) { + startFrom = dateUtil.getUTCFormat(startFrom); + } + if (startTo != null) { + startTo = dateUtil.getUTCFormat(startTo); + } + try { + if (startFrom != null && startTo != null) { + specs.add(TransferSpecs.between(Transfer_.startedAt, dateFormat().parse(startFrom), dateFormat().parse(startTo))); + } else if (startFrom != null) { + specs.add(TransferSpecs.later(Transfer_.startedAt, dateFormat().parse(startFrom))); + } else if (startTo != null) { + specs.add(TransferSpecs.earlier(Transfer_.startedAt, dateFormat().parse(startTo))); + } + } catch (Exception e) { + logger.warn("failed to parse dates {} / {}", startFrom, startTo); + } + + PageRequest pager; + if (sortedBy == null || "startedAt".equals(sortedBy)) { + pager = new PageRequest(page, size, new Sort(Sort.Direction.fromString(sortedOrder), "startedAt")); + } else { + pager = new PageRequest(page, size, new Sort(Sort.Direction.fromString(sortedOrder), sortedBy)); + } + + Page transferPage; + if (specs.size() > 0) { + Specifications compiledSpecs = specs.get(0); + for (int i = 1; i < specs.size(); i++) { + compiledSpecs = compiledSpecs.and(specs.get(i)); + } + transferPage = transferRepository.findAll(compiledSpecs, pager); + } else { + transferPage = transferRepository.findAll(pager); + } + + List transferResponseList = new ArrayList<>(); + int i = 0; + for (Transfer transfer : transferPage.getContent()) { + TransferResponse transferResponse = null; + try { + String json = transfer.getErrorInformation(); + transfer.setErrorInformation(null); + transferResponse = objectMapper.readValue(objectMapper.writeValueAsString(transfer), + TransferResponse.class); + transferResponse.parseErrorInformation(json, objectMapper); + transferResponseList.add(transferResponse); + } catch (Exception e) { + logger.error("Error parsing errorInformation into DTO: {}", e.getMessage()); + e.printStackTrace(); + if (transferResponse != null) { + transferResponseList.add(transferResponse); + } + } + } + + Page paginatedTransferResponse = new PageImpl<>(transferResponseList, transferPage.getPageable(), transferPage.getTotalPages()); + + return paginatedTransferResponse; + } + + //payment status check api + @PostMapping("/transfers") + public Page transfersStatusCheck( + @RequestHeader("Platform-TenantId") String tenantId, + @RequestParam(value = "page", required = false, defaultValue = "0") Integer page, + @RequestParam(value = "size", required = false, defaultValue = "10000") Integer size, + @RequestParam(value = "sortedOrder", required = false, defaultValue = "DESC") String sortedOrder, + @RequestParam(value = "startFrom", required = false) String startFrom, + @RequestParam(value = "startTo", required = false) String startTo, + @RequestParam(value = "sortedBy", required = false) String sortedBy, + @RequestBody Map> body) throws IOException { + List> specs = new ArrayList<>(); + PageRequest pager; + if (sortedBy == null || "startedAt".equals(sortedBy)) { + pager = new PageRequest(page, size, new Sort(Sort.Direction.fromString(sortedOrder), + "startedAt")); + } else { + pager = new PageRequest(page, size, new Sort(Sort.Direction.fromString(sortedOrder), sortedBy)); + } + Specifications spec = null; + List filterByList = new ArrayList<>(body.keySet()); + for (String filterBy : filterByList) { + List ids = body.get(filterBy); + if (ids.isEmpty()) { + continue; + } else { + if (filterBy.equals("requestIds")) { + spec = TransferSpecs.in(Transfer_.clientCorrelationId, ids); + } else if (filterBy.equals("payeePartyIds")) { + spec = TransferSpecs.in(Transfer_.payeeDfspId, ids); + } + } + } + Page transferPage; + transferPage = executeTransferRequest(spec, specs, page, size, sortedOrder); + List transferResponseList = new ArrayList<>(); + for (Transfer transfer : transferPage.getContent()) { + TransferResponse transferResponse = null; + try { + String json = transfer.getErrorInformation(); + transfer.setErrorInformation(null); + transferResponse = objectMapper.readValue(objectMapper.writeValueAsString(transfer), + TransferResponse.class); + transferResponse.parseErrorInformation(json, objectMapper); + transferResponseList.add(transferResponse); + } catch (Exception e) { + logger.error("Error parsing errorInformation into DTO: {}", e.getMessage()); + if (transferResponse != null) { + transferResponseList.add(transferResponse); + } + } + } + Page paginatedTransferResponse = new PageImpl<>(transferResponseList, transferPage.getPageable(), transferPage.getTotalPages()); + return paginatedTransferResponse; + } + + @GetMapping("/transactionRequests") + public Page transactionRequests( + @RequestParam(value = "page", required = false, defaultValue = "0") Integer page, + @RequestParam(value = "size", required = false, defaultValue = "20") Integer size, + @RequestParam(value = "payerPartyId", required = false) String payerPartyId, + @RequestParam(value = "payeePartyId", required = false) String payeePartyId, + @RequestParam(value = "payeeDfspId", required = false) String payeeDfspId, + @RequestParam(value = "payerDfspId", required = false) String payerDfspId, + @RequestParam(value = "transactionId", required = false) String transactionId, + @RequestParam(value = "state", required = false) String state, + @RequestParam(value = "amount", required = false) BigDecimal amount, + @RequestParam(value = "currency", required = false) String currency, + @RequestParam(value = "startFrom", required = false) String startFrom, + @RequestParam(value = "startTo", required = false) String startTo, + @RequestParam(value = "direction", required = false) String direction, + @RequestParam(value = "clientCorrelationId", required = false) String clientCorrelationId, + @RequestParam(value = "sortedBy", required = false) String sortedBy, + @RequestParam(value = "sortedOrder", required = false, defaultValue = "DESC") String sortedOrder) { + List> specs = new ArrayList<>(); + if (payerPartyId != null) { + specs.add(TransactionRequestSpecs.match(TransactionRequest_.payerPartyId, payerPartyId)); + } + if (payeePartyId != null) { + specs.add(TransactionRequestSpecs.match(TransactionRequest_.payeePartyId, payeePartyId)); + } + if (payeeDfspId != null) { + specs.add(TransactionRequestSpecs.match(TransactionRequest_.payeeDfspId, payeeDfspId)); + } + if (payerDfspId != null) { + specs.add(TransactionRequestSpecs.match(TransactionRequest_.payerDfspId, payerDfspId)); + } + if (transactionId != null) { + specs.add(TransactionRequestSpecs.match(TransactionRequest_.transactionId, transactionId)); + } + if (state != null && parseState(state) != null) { + specs.add(TransactionRequestSpecs.match(TransactionRequest_.state, parseState(state))); + } + if (amount != null) { + specs.add(TransactionRequestSpecs.match(TransactionRequest_.amount, amount)); + } + if (currency != null) { + specs.add(TransactionRequestSpecs.match(TransactionRequest_.currency, currency)); + } + if (clientCorrelationId != null) { + specs.add(TransactionRequestSpecs.match(TransactionRequest_.clientCorrelationId, clientCorrelationId)); + } + if (direction != null) { + specs.add(TransactionRequestSpecs.match(TransactionRequest_.direction, direction)); + } + try { + if (startFrom != null) { + startFrom = dateUtil.getUTCFormat(startFrom); + } + if (startTo != null) { + startTo = dateUtil.getUTCFormat(startTo); + } + if (startFrom != null && startTo != null) { + specs.add(TransactionRequestSpecs.between(TransactionRequest_.startedAt, dateFormat().parse(startFrom), dateFormat().parse(startTo))); + } else if (startFrom != null) { + specs.add(TransactionRequestSpecs.later(TransactionRequest_.startedAt, dateFormat().parse(startFrom))); + } else if (startTo != null) { + specs.add(TransactionRequestSpecs.earlier(TransactionRequest_.startedAt, dateFormat().parse(startTo))); + } + } catch (Exception e) { + logger.warn("failed to parse dates {} / {}", startFrom, startTo); + } + + PageRequest pager; + if (sortedBy == null || "startedAt".equals(sortedBy)) { + pager = new PageRequest(page, size, new Sort(Sort.Direction.valueOf(sortedOrder), "startedAt")); + } else { + pager = new PageRequest(page, size, new Sort(Sort.Direction.valueOf(sortedOrder), sortedBy)); + } + + if (specs.size() > 0) { + Specifications compiledSpecs = specs.get(0); + for (int i = 1; i < specs.size(); i++) { + compiledSpecs = compiledSpecs.and(specs.get(i)); + } + return transactionRequestRepository.findAll(compiledSpecs, pager); + } else { + return transactionRequestRepository.findAll(pager); + } + } + + /** + * Filter the [TransactionRequests] based on multiple type of ids + * + * @param response instance of HttpServletResponse + * @param page the count/number of page which we want to fetch + * @param size the size of the single page defaults to [10000] + * @param sortedOrder the order of sorting [ASC] or [DESC], defaults to [DESC] + * @param startFrom use for filtering records after this date, format: "yyyy-MM-dd HH:mm:ss" + * @param startTo use for filtering records before this date + * @param state filter based on state of the transaction + */ + @PostMapping("/transactionRequests") + public Map filterTransactionRequests( + HttpServletResponse response, + @RequestParam(value = "command", required = false, defaultValue = "export") String command, + @RequestParam(value = "page", required = false, defaultValue = "0") Integer page, + @RequestParam(value = "size", required = false, defaultValue = "10000") Integer size, + @RequestParam(value = "sortedOrder", required = false, defaultValue = "DESC") String sortedOrder, + @RequestParam(value = "startFrom", required = false) String startFrom, + @RequestParam(value = "startTo", required = false) String startTo, + @RequestParam(value = "state", required = false) String state, + @RequestBody Map> body) { + + if (!command.equalsIgnoreCase("export")) { + return new ErrorResponse.Builder() + .setErrorCode("" + HttpServletResponse.SC_NOT_FOUND) + .setErrorDescription(command + " not supported") + .setDeveloperMessage("Possible supported command is " + command).build(); + } + + List filterByList = new ArrayList<>(body.keySet()); + + List> specs = new ArrayList<>(); + if (state != null && parseState(state) != null) { + specs.add(TransactionRequestSpecs.match(TransactionRequest_.state, parseState(state))); + logger.info("State filter added"); + } + if (startFrom != null) { + startFrom = dateUtil.getUTCFormat(startFrom); + } + if (startTo != null) { + startTo = dateUtil.getUTCFormat(startTo); + } + try { + specs.add(getDateSpecification(startTo, startFrom)); + logger.info("Date filter parsed successful"); + } catch (Exception e) { + logger.warn("failed to parse dates {} / {}", startFrom, startTo); + } + + Specifications spec = null; + List data = new ArrayList<>(); + for (String filterBy : filterByList) { + List ids = body.get(filterBy); + if (ids.isEmpty()) { + continue; + } + Filter filter; + try { + filter = parseFilter(filterBy); + logger.info("Filter parsed successfully " + filter.name()); + } catch (Exception e) { + logger.info("Unable to parse filter " + filterBy + " skipping"); + continue; + } + spec = getFilterSpecs(filter, ids); + Page result = executeRequest(spec, specs, page, size, sortedOrder); + data.addAll(result.getContent()); + logger.info("Result for " + filter + " : " + data); + } + if (data.isEmpty()) { + response.setStatus(HttpServletResponse.SC_NOT_FOUND); + return new ErrorResponse.Builder() + .setErrorCode("" + HttpServletResponse.SC_NOT_FOUND) + .setErrorDescription("Empty response") + .setDeveloperMessage("Empty response").build(); + } + try { + CsvUtility.writeToCsv(response, data); + } catch (WriteToCsvException e) { + return new ErrorResponse.Builder() + .setErrorCode(e.getErrorCode()) + .setErrorDescription(e.getErrorDescription()) + .setDeveloperMessage(e.getDeveloperMessage()).build(); + } + return null; + } + + /* + * Returns respective [TransactionRequest] specifications based on filter + * @param filter the filter we want to apply + * @param listOfValues the values to which we want to apply filter + */ + private Specifications getFilterSpecs(Filter filter, List listOfValues) { + Specifications spec = null; + switch (filter) { + case TRANSACTIONID: + spec = TransactionRequestSpecs.in(TransactionRequest_.transactionId, listOfValues); + break; + case PAYERID: + spec = TransactionRequestSpecs.in(TransactionRequest_.payerPartyId, listOfValues); + break; + case PAYEEID: + spec = TransactionRequestSpecs.in(TransactionRequest_.payeePartyId, listOfValues); + break; + case WORKFLOWINSTANCEKEY: + spec = TransactionRequestSpecs.in(TransactionRequest_.workflowInstanceKey, listOfValues); + break; + case STATE: + spec = TransactionRequestSpecs.in(TransactionRequest_.state, parseStates(listOfValues)); + break; + case ERRORDESCRIPTION: + spec = TransactionRequestSpecs.filterByErrorDescription(parseErrorDescription(listOfValues)); + break; + case EXTERNALID: + spec = TransactionRequestSpecs.in(TransactionRequest_.externalId, listOfValues); + break; + + case CLIENTCORRELATIONID: + spec = TransactionRequestSpecs.in(TransactionRequest_.clientCorrelationId, listOfValues); + break; + } + return spec; + } + + /* + * Parse the date filter and return the specification accordingly + * @param startTo date before which we want all the records, in format "yyyy-MM-dd HH:mm:ss" + * @param startFrom date after which we want all the records, in format "yyyy-MM-dd HH:mm:ss" + */ + private Specifications getDateSpecification(String startTo, String startFrom) throws Exception { + if (startFrom != null && startTo != null) { + return TransactionRequestSpecs.between(TransactionRequest_.startedAt, dateFormat().parse(startFrom), dateFormat().parse(startTo)); + } else if (startFrom != null) { + return TransactionRequestSpecs.later(TransactionRequest_.startedAt, dateFormat().parse(startFrom)); + } else if (startTo != null) { + return TransactionRequestSpecs.earlier(TransactionRequest_.startedAt, dateFormat().parse(startTo)); + } else { + throw new Exception("Both dates(startTo, startFrom empty, skipping"); + } + } + + /* + * Executes the transactionRequest api request with specifications and returns the paged result + * @param baseSpec the base specification in which all the other spec needed to be merged + * @param extraSpecs the list of specification which is required to be merged in [baseSpec] + * @param page the page number we want to fetch + * @param size the size of single page or number of elements in single page + * @param sortedOrder the order of sorting to be applied ASC OR DESC + */ + private Page executeRequest( + Specifications baseSpec, List> extraSpecs, + int page, int size, String sortedOrder) { + PageRequest pager = new PageRequest(page, size, new Sort(Sort.Direction.valueOf(sortedOrder), "startedAt")); + Page result; + if (baseSpec == null) { + result = transactionRequestRepository.findAll(pager); + logger.info("Getting data without spec"); + } else { + Specifications combineSpecs = combineSpecs(baseSpec, extraSpecs); + result = transactionRequestRepository.findAll(combineSpecs, pager); + } + return result; + } + + private Page executeTransferRequest( + Specifications baseSpec, List> extraSpecs, + int page, int size, String sortedOrder) { + PageRequest pager = new PageRequest(page, size, new Sort(Sort.Direction.valueOf(sortedOrder), "startedAt")); + Page result; + if (baseSpec == null) { + result = transferRepository.findAll(pager); + logger.info("Getting data without spec"); + } else { + Specifications combineSpecs = combineSpecs(baseSpec, extraSpecs); + result = transferRepository.findAll(combineSpecs, pager); + } + return result; + } + + /* + * Combines the multiple specifications into one using and clause + * @param baseSpec the base specification in which all the other spec needed to be merged + * @param specs the list of specification which is required to be merged in [baseSpec] + */ + private Specifications combineSpecs(Specifications baseSpec, + List> specs) { + logger.info("Combining specs " + specs.size()); + for (Specifications specifications : specs) { + baseSpec = baseSpec.and(specifications); + } + return baseSpec; + } + + /* + * Generates the exhaustive errorDescription list by prefixing and suffixing it with double quotes (") + * + * Example: [ "AMS Local is disabled"] => [ "AMS Local is disabled", "\"AMS Local is disabled\""] + */ + private List parseErrorDescription(List description) { + List errorDesc = new ArrayList<>(description); + for (String s : description) { + errorDesc.add(String.format("\"%s\"", s)); + } + return errorDesc; + } + + /* + * Parses the [Filter] enum from filter string + */ + private Filter parseFilter(String filterBy) { + return filterBy == null ? null : Filter.valueOf(filterBy.toUpperCase()); + } + + /* + * Parses the [TransferStatus] enum from transactionStatus string + */ + private TransferStatus parseStatus(@RequestParam(value = "transactionStatus", required = false) String + transactionStatus) { + try { + return transactionStatus == null ? null : TransferStatus.valueOf(transactionStatus); + } catch (Exception e) { + logger.warn("failed to parse transaction status {}, ignoring it", transactionStatus); + return null; + } + } + + /* + * Parses the [TransactionRequestState] enum from transactionState string + */ + private TransactionRequestState parseState(String state) { + try { + return state == null ? null : TransactionRequestState.valueOf(state); + } catch (Exception e) { + logger.warn("failed to parse TransactionRequestState {}, ignoring it", state); + return null; + } + } + + /* + * Parses the list of [TransactionRequestState] enum from list of transactionState string + */ + private List parseStates(List states) { + List stateList = new ArrayList<>(); + for (String state : states) { + stateList.add(parseState(state)); + } + return stateList; + } + +} diff --git a/ph-ee-operations-app/src/main/java/org/apache/fineract/api/PermissionsApi.java b/ph-ee-operations-app/src/main/java/org/apache/fineract/api/PermissionsApi.java new file mode 100644 index 000000000..975c265bf --- /dev/null +++ b/ph-ee-operations-app/src/main/java/org/apache/fineract/api/PermissionsApi.java @@ -0,0 +1,94 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.api; + +import io.swagger.v3.oas.annotations.security.SecurityRequirement; +import org.apache.fineract.organisation.permission.Permission; +import org.apache.fineract.organisation.permission.PermissionRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.MediaType; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import javax.servlet.http.HttpServletResponse; +import java.util.List; + + +@RestController +@SecurityRequirement(name = "auth") +@RequestMapping("/api/v1") +public class PermissionsApi { + + @Autowired + private PermissionRepository permissionRepository; + + @GetMapping(path = "/permissions", produces = MediaType.APPLICATION_JSON_VALUE) + public List retrieveAll() { + return this.permissionRepository.findAll(); + } + + @GetMapping(path = "/permission/{permissionId}", produces = MediaType.APPLICATION_JSON_VALUE) + public Permission retrieveOne(@PathVariable("permissionId") Long permissionId, HttpServletResponse response) { + Permission permission = permissionRepository.findById(permissionId).get(); + if(permission != null) { + return permission; + } else { + response.setStatus(HttpServletResponse.SC_NOT_FOUND); + return null; + } + } + + @PostMapping(path = "/permission", consumes = MediaType.APPLICATION_JSON_VALUE) + public void create(@RequestBody Permission permission, HttpServletResponse response) { + Permission existing = permissionRepository.findOneByCode(permission.getCode()); + if (existing == null) { + permission.setId(null); + permissionRepository.saveAndFlush(permission); + } else { + response.setStatus(HttpServletResponse.SC_CONFLICT); + } + } + + @PutMapping(path = "/permission/{permissionId}", consumes = MediaType.APPLICATION_JSON_VALUE) + public void update(@PathVariable("permissionId") Long permissionId, @RequestBody Permission permission, HttpServletResponse response) { + Permission existing = permissionRepository.findById(permissionId).get(); + if (existing != null) { + permission.setId(permissionId); + permission.setRoles(existing.getRoles()); + permissionRepository.saveAndFlush(permission); + } else { + response.setStatus(HttpServletResponse.SC_NOT_FOUND); + } + } + + @DeleteMapping(path = "/permission/{permissionId}") + public void delete(@PathVariable("permissionId") Long permissionId, HttpServletResponse response) { + if(permissionRepository.existsById(permissionId)) { + permissionRepository.deleteById(permissionId); + } else { + response.setStatus(HttpServletResponse.SC_NOT_FOUND); + } + } +} diff --git a/ph-ee-operations-app/src/main/java/org/apache/fineract/api/RolesApi.java b/ph-ee-operations-app/src/main/java/org/apache/fineract/api/RolesApi.java new file mode 100644 index 000000000..4d2d1f061 --- /dev/null +++ b/ph-ee-operations-app/src/main/java/org/apache/fineract/api/RolesApi.java @@ -0,0 +1,156 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.api; + + +import io.swagger.v3.oas.annotations.security.SecurityRequirement; +import org.apache.fineract.organisation.permission.Permission; +import org.apache.fineract.organisation.permission.PermissionRepository; +import org.apache.fineract.organisation.role.Role; +import org.apache.fineract.organisation.role.RoleRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.MediaType; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import javax.servlet.http.HttpServletResponse; +import java.util.Collection; +import java.util.List; + +import static java.util.stream.Collectors.toList; +import static org.apache.fineract.api.AssignmentAction.ASSIGN; + +@RestController +@SecurityRequirement(name = "auth") +@RequestMapping("/api/v1") +public class RolesApi { + + @Autowired + private RoleRepository roleRepository; + + @Autowired + private PermissionRepository permissionRepository; + + @GetMapping(path = "/roles", produces = MediaType.APPLICATION_JSON_VALUE) + public List retrieveAll() { + return this.roleRepository.findAll(); + } + + @GetMapping(path = "/role/{roleId}", produces = MediaType.APPLICATION_JSON_VALUE) + public Role retrieveOne(@PathVariable("roleId") Long roleId, HttpServletResponse response) { + Role role = roleRepository.findById(roleId).get(); + if(role != null) { + return role; + } else { + response.setStatus(HttpServletResponse.SC_NOT_FOUND); + return null; + } + } + + @GetMapping(path = "/role/{roleId}/permissions", produces = MediaType.APPLICATION_JSON_VALUE) + public Collection retrievePermissions(@PathVariable("roleId") Long roleId, HttpServletResponse response) { + Role role = roleRepository.findById(roleId).get(); + if(role != null) { + return role.getPermissions(); + } else { + response.setStatus(HttpServletResponse.SC_NOT_FOUND); + return null; + } + } + + @PostMapping(path = "/role", consumes = MediaType.APPLICATION_JSON_VALUE) + public void create(@RequestBody Role role, HttpServletResponse response) { + Role existing = roleRepository.getRoleByName(role.getName()); + if (existing == null) { + role.setId(null); + roleRepository.saveAndFlush(role); + } else { + response.setStatus(HttpServletResponse.SC_CONFLICT); + } + } + + @PutMapping(path = "/role/{roleId}", consumes = MediaType.APPLICATION_JSON_VALUE) + public void update(@PathVariable("roleId") Long roleId, @RequestBody Role role, HttpServletResponse response) { + Role existing = roleRepository.findById(roleId).get(); + if (existing != null) { + role.setId(roleId); + role.setAppUsers(existing.getAppusers()); + role.setPermissions(existing.getPermissions()); + roleRepository.saveAndFlush(role); + } else { + response.setStatus(HttpServletResponse.SC_NOT_FOUND); + } + } + + @DeleteMapping(path = "/role/{roleId}") + public void delete(@PathVariable("roleId") Long roleId, HttpServletResponse response) { + if(roleRepository.existsById(roleId)) { + roleRepository.deleteById(roleId); + } else { + response.setStatus(HttpServletResponse.SC_NOT_FOUND); + } + } + + @PutMapping(path = "/role/{roleId}/permissions", consumes = MediaType.APPLICATION_JSON_VALUE) + public void permissionAssignment(@PathVariable("roleId") Long roleId, @RequestParam("action") AssignmentAction action, + @RequestBody EntityAssignments assignments, HttpServletResponse response) { + Role existingRole = roleRepository.findById(roleId).get(); + if (existingRole != null) { + Collection permissionToAssign = existingRole.getPermissions(); + List existingPermissionIds = permissionToAssign.stream() + .map(Permission::getId) + .collect(toList()); + List deltaPermissions = assignments.getEntityIds().stream() + .filter(id -> { + if (ASSIGN.equals(action)) { + return !existingPermissionIds.contains(id); + } else { // revoke + return existingPermissionIds.contains(id); + } + }) + .map(id -> { + Permission p = permissionRepository.findById(id).get(); + if (p == null) { + throw new RuntimeException("Invalid permission id: " + id + " can not continue assignment!"); + } else { + return p; + } + }).collect(toList()); + + if (!deltaPermissions.isEmpty()) { + if (ASSIGN.equals(action)) { + permissionToAssign.addAll(deltaPermissions); + } else { // revoke + permissionToAssign.removeAll(deltaPermissions); + } + existingRole.setPermissions(permissionToAssign); + roleRepository.saveAndFlush(existingRole); + } + } else { + response.setStatus(HttpServletResponse.SC_NOT_FOUND); + } + } +} diff --git a/ph-ee-operations-app/src/main/java/org/apache/fineract/api/UsersApi.java b/ph-ee-operations-app/src/main/java/org/apache/fineract/api/UsersApi.java new file mode 100644 index 000000000..ddd2a25fd --- /dev/null +++ b/ph-ee-operations-app/src/main/java/org/apache/fineract/api/UsersApi.java @@ -0,0 +1,163 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.api; + +import io.swagger.v3.oas.annotations.security.SecurityRequirement; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.apache.fineract.organisation.role.Role; +import org.apache.fineract.organisation.role.RoleRepository; +import org.apache.fineract.organisation.user.AppUser; +import org.apache.fineract.organisation.user.AppUserRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.MediaType; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import javax.servlet.http.HttpServletResponse; +import java.util.Collection; +import java.util.List; + +import static java.util.stream.Collectors.toList; +import static org.apache.fineract.api.AssignmentAction.ASSIGN; + +@RestController +@SecurityRequirement(name = "auth") +@RequestMapping("/api/v1") +@Tag(name = "Users API") +public class UsersApi { + + @Autowired + private PasswordEncoder passwordEncoder; + + @Autowired + private AppUserRepository appuserRepository; + + @Autowired + private RoleRepository roleRepository; + + @GetMapping(path = "/users", produces = MediaType.APPLICATION_JSON_VALUE) + public List retrieveAll() { + return this.appuserRepository.findAll(); + } + + @GetMapping(path = "/user/{userId}", produces = MediaType.APPLICATION_JSON_VALUE) + public AppUser retrieveOne(@PathVariable("userId") Long userId, HttpServletResponse response) { + AppUser user = appuserRepository.findById(userId).get(); + if(user != null) { + return user; + } else { + response.setStatus(HttpServletResponse.SC_NOT_FOUND); + return null; + } + } + + @GetMapping(path = "/user/{userId}/roles", produces = MediaType.APPLICATION_JSON_VALUE) + public Collection retrieveRoles(@PathVariable("userId") Long userId, HttpServletResponse response) { + AppUser user = appuserRepository.findById(userId).get(); + if(user != null) { + return user.getRoles(); + } else { + response.setStatus(HttpServletResponse.SC_NOT_FOUND); + return null; + } + } + + @PostMapping(path = "/user", consumes = MediaType.APPLICATION_JSON_VALUE) + public void create(@RequestBody AppUser appUser, HttpServletResponse response) { + AppUser existing = appuserRepository.findAppUserByName(appUser.getUsername()); + if (existing == null) { + // TODO enforce password policy + appUser.setId(null); + appUser.setPassword(passwordEncoder.encode(appUser.getPassword())); + appuserRepository.saveAndFlush(appUser); + } else { + response.setStatus(HttpServletResponse.SC_CONFLICT); + } + } + + @PutMapping(path = "/user/{userId}", consumes = MediaType.APPLICATION_JSON_VALUE) + public void update(@PathVariable("userId") Long userId, @RequestBody AppUser appUser, HttpServletResponse response) { + AppUser existing = appuserRepository.findById(userId).get(); + if (existing != null) { + appUser.setId(userId); + appUser.setPassword(passwordEncoder.encode(appUser.getPassword())); + appUser.setRoles(existing.getRoles()); + appuserRepository.saveAndFlush(appUser); + } else { + response.setStatus(HttpServletResponse.SC_NOT_FOUND); + } + } + + @DeleteMapping(path = "/user/{userId}", produces = MediaType.TEXT_HTML_VALUE) + public void delete(@PathVariable("userId") Long userId, HttpServletResponse response) { + if(appuserRepository.findById(userId).isPresent()) { + appuserRepository.deleteById(userId); + } else { + response.setStatus(HttpServletResponse.SC_NOT_FOUND); + } + } + + @PutMapping(path = "/user/{userId}/roles", consumes = MediaType.APPLICATION_JSON_VALUE) + public void userAssignment(@PathVariable("userId") Long userId, @RequestParam("action") AssignmentAction action, + @RequestBody EntityAssignments assignments, HttpServletResponse response) { + AppUser existingUser = appuserRepository.findById(userId).get(); + if (existingUser != null) { + Collection rolesToAssign = existingUser.getRoles(); + List existingRoleIds = rolesToAssign.stream() + .map(Role::getId) + .collect(toList()); + List deltaRoles = assignments.getEntityIds().stream() + .filter(id -> { + if (ASSIGN.equals(action)) { + return !existingRoleIds.contains(id); + } else { // revoke + return existingRoleIds.contains(id); + } + }) + .map(id -> { + Role r = roleRepository.findById(id).get(); + if (r == null) { + throw new RuntimeException("Invalid role id: " + id + " can not continue assignment!"); + } else { + return r; + } + }).collect(toList()); + + if (!deltaRoles.isEmpty()) { + if (ASSIGN.equals(action)) { + rolesToAssign.addAll(deltaRoles); + } else { // revoke + rolesToAssign.removeAll(deltaRoles); + } + existingUser.setRoles(rolesToAssign); + appuserRepository.saveAndFlush(existingUser); + } + } else { + response.setStatus(HttpServletResponse.SC_NOT_FOUND); + } + } +} \ No newline at end of file diff --git a/ph-ee-operations-app/src/main/java/org/apache/fineract/api/UtilityApi.java b/ph-ee-operations-app/src/main/java/org/apache/fineract/api/UtilityApi.java new file mode 100644 index 000000000..2b8b55b69 --- /dev/null +++ b/ph-ee-operations-app/src/main/java/org/apache/fineract/api/UtilityApi.java @@ -0,0 +1,74 @@ +package org.apache.fineract.api; + +import io.swagger.v3.oas.annotations.security.SecurityRequirement; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.apache.fineract.service.UtilityService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestHeader; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.multipart.MultipartFile; +import javax.crypto.BadPaddingException; +import javax.crypto.IllegalBlockSizeException; +import javax.crypto.NoSuchPaddingException; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.security.spec.InvalidKeySpecException; +import java.util.stream.Collectors; + + +@RestController +@SecurityRequirement(name = "auth") +@RequestMapping("/api/v1") +@Tag(name = "Users API") +public class UtilityApi { + + @Autowired + UtilityService utilityService; + + @PostMapping("/util/x-signature") + public ResponseEntity getXSignature( + @RequestHeader("X-CorrelationID") String correlationId, + @RequestHeader("Platform-TenantId") String tenantId, + @RequestHeader("privateKey") String privateKey, + @RequestParam(required = false) MultipartFile data, + @RequestBody(required = false) String rawData + )throws NoSuchPaddingException, IllegalBlockSizeException, NoSuchAlgorithmException, BadPaddingException, InvalidKeySpecException, InvalidKeyException, IOException { + + String tobeHashed = ""; + + if(data != null && !data.isEmpty()) { + String fileContent; + try { + fileContent = readInputStreamToString(data.getInputStream()); + } catch (IOException e) { + e.printStackTrace(); + return new ResponseEntity<>("Failed to read file content", HttpStatus.INTERNAL_SERVER_ERROR); + } + tobeHashed = correlationId+":"+tenantId+":"+fileContent; + } + else if(rawData != null && !rawData.isEmpty()){ + tobeHashed = correlationId+":"+tenantId+":"+rawData; + } + else { + return new ResponseEntity<>("No file or raw data provided", HttpStatus.BAD_REQUEST); + } + + return new ResponseEntity<>(utilityService.getSignature(tobeHashed, privateKey), HttpStatus.OK); + } + + private String readInputStreamToString(InputStream inputStream) throws IOException { + try (BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream))) { + return bufferedReader.lines().collect(Collectors.joining("\n")); + } + } +} diff --git a/ph-ee-operations-app/src/main/java/org/apache/fineract/config/AuthExceptionTranslator.java b/ph-ee-operations-app/src/main/java/org/apache/fineract/config/AuthExceptionTranslator.java new file mode 100644 index 000000000..2e819fa91 --- /dev/null +++ b/ph-ee-operations-app/src/main/java/org/apache/fineract/config/AuthExceptionTranslator.java @@ -0,0 +1,32 @@ +package org.apache.fineract.config; + +import org.json.JSONObject; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.security.oauth2.common.exceptions.InvalidGrantException; +import org.springframework.security.oauth2.provider.error.WebResponseExceptionTranslator; +import org.springframework.stereotype.Component; + +import java.util.Date; + + +@Component +public class AuthExceptionTranslator implements WebResponseExceptionTranslator { + + @Override + public ResponseEntity translate(Exception e) { + if (e instanceof InvalidGrantException) { + JSONObject body = new JSONObject(); + body.put("timestamp", new Date().toInstant().toEpochMilli()); + body.put("status", "401"); + body.put("error", "Unauthorized"); + body.put("message", "Invalid credentials"); + body.put("path", "/oauth/token"); + return new ResponseEntity(body.toString(), HttpStatus.UNAUTHORIZED); + } else { + JSONObject body = new JSONObject(); + body.put("error", e.getMessage()); + return new ResponseEntity(body.toString(), HttpStatus.BAD_REQUEST); + } + } +} diff --git a/ph-ee-operations-app/src/main/java/org/apache/fineract/config/AuthProperties.java b/ph-ee-operations-app/src/main/java/org/apache/fineract/config/AuthProperties.java new file mode 100644 index 000000000..97d0df8ce --- /dev/null +++ b/ph-ee-operations-app/src/main/java/org/apache/fineract/config/AuthProperties.java @@ -0,0 +1,21 @@ +package org.apache.fineract.config; + +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.List; + +@Component +@ConfigurationProperties(prefix = "rest.authorization") +public class AuthProperties { + + private List settings = new ArrayList<>(); + + public AuthProperties() { + } + + public List getSettings() { + return settings; + } +} diff --git a/ph-ee-operations-app/src/main/java/org/apache/fineract/config/AuthorizationServerConfig.java b/ph-ee-operations-app/src/main/java/org/apache/fineract/config/AuthorizationServerConfig.java new file mode 100644 index 000000000..1402e0567 --- /dev/null +++ b/ph-ee-operations-app/src/main/java/org/apache/fineract/config/AuthorizationServerConfig.java @@ -0,0 +1,59 @@ +package org.apache.fineract.config; + +import org.apache.fineract.core.service.RoutingDataSource; +import org.apache.fineract.core.service.TenantAwareUserDetailsService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer; +import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter; +import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer; +import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer; +import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer; +import org.springframework.security.oauth2.provider.client.JdbcClientDetailsService; +import org.springframework.security.oauth2.provider.token.TokenStore; +import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter; + +@Configuration +@EnableAuthorizationServer +public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter { + + @Autowired + private AuthenticationManager authenticationManager; + + @Autowired + private RoutingDataSource routingDataSource; + + @Autowired + private JwtAccessTokenConverter accessTokenConverter; + + @Autowired + private TokenStore tokenStore; + + @Autowired + private TenantAwareUserDetailsService userDetailsService; + + @Autowired + private InvalidAuthEntryPoint invalidAuthEntryPoint; + + @Autowired + private AuthExceptionTranslator translator; + + public void configure(ClientDetailsServiceConfigurer clients) throws Exception { + clients.withClientDetails(new JdbcClientDetailsService(routingDataSource)); + } + + public void configure(AuthorizationServerEndpointsConfigurer endpoints) { + endpoints.authenticationManager(authenticationManager) + .tokenStore(tokenStore) + .accessTokenConverter(accessTokenConverter) + .userDetailsService(userDetailsService) + .exceptionTranslator(translator); + } + + public void configure(AuthorizationServerSecurityConfigurer security) { + security.tokenKeyAccess("permitAll()") + .checkTokenAccess("isAuthenticated()") + .authenticationEntryPoint(invalidAuthEntryPoint); + } +} diff --git a/ph-ee-operations-app/src/main/java/org/apache/fineract/config/CacheConfig.java b/ph-ee-operations-app/src/main/java/org/apache/fineract/config/CacheConfig.java new file mode 100644 index 000000000..45eba6c59 --- /dev/null +++ b/ph-ee-operations-app/src/main/java/org/apache/fineract/config/CacheConfig.java @@ -0,0 +1,34 @@ +package org.apache.fineract.config; + +import net.sf.ehcache.Cache; +import net.sf.ehcache.config.CacheConfiguration; +import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; +import org.springframework.cache.CacheManager; +import org.springframework.cache.annotation.EnableCaching; +import org.springframework.cache.ehcache.EhCacheCacheManager; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Primary; + +@EnableCaching +@Configuration +@ConditionalOnExpression("${caching.enabled}") +public class CacheConfig { + + public static final String CACHE_USER_BY_NAME = "userByName"; + + @Bean + @Primary + public CacheManager cacheManager() { + CacheConfiguration cacheConfiguration = new CacheConfiguration(CACHE_USER_BY_NAME, 1000); + cacheConfiguration.timeToLiveSeconds(10); + CacheConfiguration.CacheEventListenerFactoryConfiguration factory = new CacheConfiguration.CacheEventListenerFactoryConfiguration(); + factory.setClass("org.apache.fineract.config.CustomCacheEventListenerFactory"); + cacheConfiguration.addCacheEventListenerFactory(factory); + + net.sf.ehcache.CacheManager ehCacheManager = new net.sf.ehcache.CacheManager(); + ehCacheManager.addCache(new Cache(cacheConfiguration)); + + return new EhCacheCacheManager(ehCacheManager); + } +} diff --git a/ph-ee-operations-app/src/main/java/org/apache/fineract/config/CacheEventLogger.java b/ph-ee-operations-app/src/main/java/org/apache/fineract/config/CacheEventLogger.java new file mode 100644 index 000000000..9a2bce570 --- /dev/null +++ b/ph-ee-operations-app/src/main/java/org/apache/fineract/config/CacheEventLogger.java @@ -0,0 +1,54 @@ +package org.apache.fineract.config; + +import net.sf.ehcache.CacheException; +import net.sf.ehcache.Ehcache; +import net.sf.ehcache.Element; +import net.sf.ehcache.event.CacheEventListener; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + + +public class CacheEventLogger implements CacheEventListener { + + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Override + public void notifyElementRemoved(Ehcache ehcache, Element element) throws CacheException { + logger.info("Cache remove {} {} {}", element.getKey(), element.getObjectValue(), element.getHitCount()); + } + + @Override + public void notifyElementPut(Ehcache ehcache, Element element) throws CacheException { + logger.info("Cache put {} {} {}", element.getKey(), element.getObjectValue(), element.getHitCount()); + } + + @Override + public void notifyElementUpdated(Ehcache ehcache, Element element) throws CacheException { + logger.info("Cache updated {} {} {}", element.getKey(), element.getObjectValue(), element.getHitCount()); + } + + @Override + public void notifyElementExpired(Ehcache ehcache, Element element) { + logger.info("Cache expired {} {} {}", element.getKey(), element.getObjectValue(), element.getHitCount()); + } + + @Override + public void notifyElementEvicted(Ehcache ehcache, Element element) { + logger.info("Cache evicted {} {} {}", element.getKey(), element.getObjectValue(), element.getHitCount()); + } + + @Override + public void notifyRemoveAll(Ehcache ehcache) { + logger.info("Cache removeall"); + } + + @Override + public Object clone() throws CloneNotSupportedException { + return null; + } + + @Override + public void dispose() { + + } +} diff --git a/ph-ee-operations-app/src/main/java/org/apache/fineract/config/CustomCacheEventListenerFactory.java b/ph-ee-operations-app/src/main/java/org/apache/fineract/config/CustomCacheEventListenerFactory.java new file mode 100644 index 000000000..255a0e231 --- /dev/null +++ b/ph-ee-operations-app/src/main/java/org/apache/fineract/config/CustomCacheEventListenerFactory.java @@ -0,0 +1,14 @@ +package org.apache.fineract.config; + +import net.sf.ehcache.event.CacheEventListener; +import net.sf.ehcache.event.CacheEventListenerFactory; + +import java.util.Properties; + +public class CustomCacheEventListenerFactory extends CacheEventListenerFactory { + + @Override + public CacheEventListener createCacheEventListener(Properties properties) { + return new CacheEventLogger(); + } +} diff --git a/ph-ee-operations-app/src/main/java/org/apache/fineract/config/EclipselinkJpaConfig.java b/ph-ee-operations-app/src/main/java/org/apache/fineract/config/EclipselinkJpaConfig.java new file mode 100644 index 000000000..4ff2b94cf --- /dev/null +++ b/ph-ee-operations-app/src/main/java/org/apache/fineract/config/EclipselinkJpaConfig.java @@ -0,0 +1,64 @@ +package org.apache.fineract.config; + +import org.eclipse.persistence.config.PersistenceUnitProperties; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.ObjectProvider; +import org.springframework.boot.autoconfigure.domain.EntityScan; +import org.springframework.boot.autoconfigure.orm.jpa.JpaBaseConfiguration; +import org.springframework.boot.autoconfigure.orm.jpa.JpaProperties; +import org.springframework.boot.autoconfigure.transaction.TransactionManagerCustomizers; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.jpa.repository.config.EnableJpaRepositories; +import org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver; +import org.springframework.orm.jpa.vendor.AbstractJpaVendorAdapter; +import org.springframework.orm.jpa.vendor.EclipseLinkJpaVendorAdapter; +import org.springframework.transaction.annotation.EnableTransactionManagement; +import org.springframework.transaction.jta.JtaTransactionManager; + +import javax.sql.DataSource; +import java.util.HashMap; +import java.util.Map; + +@Configuration +@EntityScan(basePackages = "org.apache.fineract") +@EnableJpaRepositories(basePackages = "org.apache.fineract") +@EnableTransactionManagement(proxyTargetClass = true) +public class EclipselinkJpaConfig extends JpaBaseConfiguration { + + private Logger logger = LoggerFactory.getLogger(this.getClass()); + + public EclipselinkJpaConfig(DataSource routingDataSource, JpaProperties properties, ObjectProvider jtaTransactionManager, ObjectProvider transactionManagerCustomizers) { + super(routingDataSource, properties, jtaTransactionManager, transactionManagerCustomizers); + } + + @Override + protected AbstractJpaVendorAdapter createJpaVendorAdapter() { + return new EclipseLinkJpaVendorAdapter(); + } + + @Override + protected Map getVendorProperties() { + HashMap map = new HashMap<>(); + map.put(PersistenceUnitProperties.WEAVING, detectWeavingMode()); + map.put(PersistenceUnitProperties.DDL_GENERATION, "none"); + map.put(PersistenceUnitProperties.LOGGING_LEVEL, "INFO"); + map.put(PersistenceUnitProperties.DDL_GENERATION_MODE, "sql-script"); + map.put("eclipselink.jdbc.batch-writing", "JDBC"); + map.put("eclipselink.jdbc.batch-writing.size", "1000"); + map.put("eclipselink.cache.shared.default", "false"); + + map.put("eclipselink.logging.level.sql", "INFO"); + map.put("eclipselink.logging.parameters", "true"); + map.put("eclipselink.logging.session", "true"); + map.put("eclipselink.logging.thread", "true"); + map.put("eclipselink.logging.timestamp", "false"); + return map; + } + + private String detectWeavingMode() { + String weavingMode = InstrumentationLoadTimeWeaver.isInstrumentationAvailable() ? "true" : "static"; + logger.debug("weaving mode is set to {}", weavingMode); + return weavingMode; + } +} diff --git a/ph-ee-operations-app/src/main/java/org/apache/fineract/config/EndpointSetting.java b/ph-ee-operations-app/src/main/java/org/apache/fineract/config/EndpointSetting.java new file mode 100644 index 000000000..a8659ffbb --- /dev/null +++ b/ph-ee-operations-app/src/main/java/org/apache/fineract/config/EndpointSetting.java @@ -0,0 +1,25 @@ +package org.apache.fineract.config; + +public class EndpointSetting { + + private String endpoint, authority; + + public EndpointSetting() { + } + + public String getEndpoint() { + return endpoint; + } + + public void setEndpoint(String endpoint) { + this.endpoint = endpoint; + } + + public String getAuthority() { + return authority; + } + + public void setAuthority(String authority) { + this.authority = authority; + } +} diff --git a/ph-ee-operations-app/src/main/java/org/apache/fineract/config/InvalidAuthEntryPoint.java b/ph-ee-operations-app/src/main/java/org/apache/fineract/config/InvalidAuthEntryPoint.java new file mode 100644 index 000000000..68f28b5d3 --- /dev/null +++ b/ph-ee-operations-app/src/main/java/org/apache/fineract/config/InvalidAuthEntryPoint.java @@ -0,0 +1,18 @@ +package org.apache.fineract.config; + +import org.springframework.security.core.AuthenticationException; +import org.springframework.security.web.AuthenticationEntryPoint; +import org.springframework.stereotype.Component; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +@Component +public class InvalidAuthEntryPoint implements AuthenticationEntryPoint { + + @Override + public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException { + response.sendError(HttpServletResponse.SC_UNAUTHORIZED, authException.getMessage()); + } +} diff --git a/ph-ee-operations-app/src/main/java/org/apache/fineract/config/PaymentMode.java b/ph-ee-operations-app/src/main/java/org/apache/fineract/config/PaymentMode.java new file mode 100644 index 000000000..7f7f21685 --- /dev/null +++ b/ph-ee-operations-app/src/main/java/org/apache/fineract/config/PaymentMode.java @@ -0,0 +1,18 @@ +package org.apache.fineract.config; + +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@NoArgsConstructor +public class PaymentMode { + + private String id, type; + + public PaymentMode(String id, String type) { + this.id = id; + this.type = type; + } +} diff --git a/ph-ee-operations-app/src/main/java/org/apache/fineract/config/PaymentModeConfiguration.java b/ph-ee-operations-app/src/main/java/org/apache/fineract/config/PaymentModeConfiguration.java new file mode 100644 index 000000000..b3f15b57b --- /dev/null +++ b/ph-ee-operations-app/src/main/java/org/apache/fineract/config/PaymentModeConfiguration.java @@ -0,0 +1,28 @@ +package org.apache.fineract.config; + +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.List; + +@Getter +@Setter +@NoArgsConstructor +@Component +@ConfigurationProperties(prefix = "payment") +public class PaymentModeConfiguration { + + private List modes = new ArrayList<>(); + + public PaymentMode getByMode(String id) { + return getModes().stream() + .filter(p -> p.getId().equals(id)) + .findFirst() + .orElse(new PaymentMode("UNKNOWN", "UNKNOWN")); + } + +} diff --git a/ph-ee-operations-app/src/main/java/org/apache/fineract/config/ResourceServerConfig.java b/ph-ee-operations-app/src/main/java/org/apache/fineract/config/ResourceServerConfig.java new file mode 100644 index 000000000..2fd143b42 --- /dev/null +++ b/ph-ee-operations-app/src/main/java/org/apache/fineract/config/ResourceServerConfig.java @@ -0,0 +1,79 @@ +package org.apache.fineract.config; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer; +import org.springframework.security.config.annotation.web.configurers.SessionManagementConfigurer; +import org.springframework.security.config.http.SessionCreationPolicy; +import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer; +import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter; +import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer; +import org.springframework.security.oauth2.provider.token.DefaultTokenServices; + +import java.util.List; + +@Configuration +@EnableResourceServer +public class ResourceServerConfig extends ResourceServerConfigurerAdapter { + + public static final String IDENTITY_PROVIDER_RESOURCE_ID = "identity-provider"; + + @Autowired + private DefaultTokenServices tokenServices; + + @Autowired + private AuthProperties authProperties; + + @Value("${rest.authorization.enabled}") + private boolean isRestAuthEnabled; + + @Override + public void configure(ResourceServerSecurityConfigurer resources) { + resources.resourceId(IDENTITY_PROVIDER_RESOURCE_ID) + .stateless(true) + .tokenServices(tokenServices); + } + + @Override + public void configure(HttpSecurity http) throws Exception { + if (!isRestAuthEnabled) { + http.authorizeRequests().antMatchers("/api/v1/**").permitAll() + .and() + .csrf().disable() + //.anonymous().disable() important to enable, if not, the request will always fail with 401 regardless of permission settings + .cors().disable() + .formLogin().disable() + .httpBasic().disable() + .rememberMe().disable() + .x509().disable() + .jee().disable(); + } else { + SessionManagementConfigurer httpConfig = http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS); + + ExpressionUrlAuthorizationConfigurer.ExpressionInterceptUrlRegistry authorization = httpConfig.and() + .authorizeRequests(); + List settings = authProperties.getSettings(); + if (settings.isEmpty()) { + throw new RuntimeException("Configuration property rest.authorization.settings can not be empty!"); + } else { + for (EndpointSetting setting : settings) { + authorization = authorization.antMatchers(setting.getEndpoint()).access(setting.getAuthority()); + } + } + + authorization.anyRequest() + .fullyAuthenticated() + .and() + .csrf().disable() + .anonymous().disable() + .cors().disable() + .formLogin().disable() + .httpBasic().disable() + .rememberMe().disable() + .x509().disable() + .jee().disable(); + } + } +} diff --git a/ph-ee-operations-app/src/main/java/org/apache/fineract/config/WebSecurityConfiguration.java b/ph-ee-operations-app/src/main/java/org/apache/fineract/config/WebSecurityConfiguration.java new file mode 100644 index 000000000..78b9ae5c5 --- /dev/null +++ b/ph-ee-operations-app/src/main/java/org/apache/fineract/config/WebSecurityConfiguration.java @@ -0,0 +1,69 @@ +package org.apache.fineract.config; + +import io.swagger.v3.oas.annotations.OpenAPIDefinition; +import io.swagger.v3.oas.annotations.enums.ParameterIn; +import io.swagger.v3.oas.annotations.enums.SecuritySchemeIn; +import io.swagger.v3.oas.annotations.enums.SecuritySchemeType; +import io.swagger.v3.oas.annotations.info.Info; +import io.swagger.v3.oas.annotations.info.License; +import io.swagger.v3.oas.annotations.security.SecurityScheme; +import io.swagger.v3.oas.models.Operation; +import io.swagger.v3.oas.models.media.StringSchema; +import io.swagger.v3.oas.models.parameters.HeaderParameter; +import io.swagger.v3.oas.models.parameters.Parameter; +import org.springdoc.core.customizers.OperationCustomizer; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.config.annotation.web.builders.WebSecurity; +import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; +import org.springframework.web.method.HandlerMethod; + +@OpenAPIDefinition ( + info = @Info ( + title = "Operations App", + description = "" + + "Operations app is a secure, multi-tenanted microservice platform", + license = @License ( + name = "MIT Licence", + url = "https://github.com/openMF/ph-ee-operations-app/blob/master/LICENSE" + ) + ) +) +@SecurityScheme ( + name = "auth", + scheme = "bearer", + type = SecuritySchemeType.HTTP, + in = SecuritySchemeIn.HEADER, + paramName = "Authorization: Bearer", + description = "Use this curl request to generate authToken\n\n\n" + + "curl --location --request POST 'ops-bk.sandbox.fynarfin.io/oauth/token?username=mifos&password=password&grant_type=password' --header 'Platform-TenantId: gorilla' --header 'Authorization: Basic Y2xpZW50Og==' --header 'Content-Type: text/plain' --data-raw '{}'\n\n" +) +@Configuration +public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter { + + @Override + public void configure(WebSecurity web) throws Exception { + web.ignoring().antMatchers( + "/v3/api-docs/**", + "/swagger-resources/**", + "/swagger-ui/**", + "/swagger-config/**", + "/api/v1/errorcode/**"); + } + + @Bean + public OperationCustomizer customGlobalHeaders() { + + return (Operation operation, HandlerMethod handlerMethod) -> { + + Parameter missingParam1 = new HeaderParameter() + .in(ParameterIn.HEADER.toString()) + .name("Platform-TenantId") + .schema(new StringSchema()) + .description("Tenant Id") + .required(true); + operation.addParametersItem(missingParam1); + return operation; + }; + } +} \ No newline at end of file diff --git a/ph-ee-operations-app/src/main/java/org/apache/fineract/core/service/AudienceVerifier.java b/ph-ee-operations-app/src/main/java/org/apache/fineract/core/service/AudienceVerifier.java new file mode 100644 index 000000000..18e7a3536 --- /dev/null +++ b/ph-ee-operations-app/src/main/java/org/apache/fineract/core/service/AudienceVerifier.java @@ -0,0 +1,31 @@ +package org.apache.fineract.core.service; + +import org.apache.fineract.organisation.tenant.TenantServerConnection; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.security.oauth2.common.exceptions.InvalidTokenException; +import org.springframework.security.oauth2.provider.token.store.JwtClaimsSetVerifier; +import org.springframework.stereotype.Component; + +import java.util.List; +import java.util.Map; + +@Component +public class AudienceVerifier implements JwtClaimsSetVerifier { + + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Override + public void verify(Map claims) throws InvalidTokenException { + TenantServerConnection tenant = ThreadLocalContextUtil.getTenant(); + List audiences = (List) claims.get("aud"); + audiences.stream() + .filter(a -> tenant.getSchemaName().equals(a)) + .findFirst() + .orElseThrow(() -> { + String message = "Token audiences " + audiences + " are not matching with request " + tenant.getSchemaName(); + logger.error(message); + return new RuntimeException(message); + }); + } +} diff --git a/ph-ee-operations-app/src/main/java/org/apache/fineract/core/service/DataSourcePerTenantService.java b/ph-ee-operations-app/src/main/java/org/apache/fineract/core/service/DataSourcePerTenantService.java new file mode 100644 index 000000000..cc9014b8e --- /dev/null +++ b/ph-ee-operations-app/src/main/java/org/apache/fineract/core/service/DataSourcePerTenantService.java @@ -0,0 +1,140 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.core.service; + +import com.zaxxer.hikari.HikariConfig; +import com.zaxxer.hikari.HikariDataSource; +import org.apache.fineract.organisation.tenant.TenantServerConnection; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.DisposableBean; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; + +import javax.sql.DataSource; +import java.util.HashMap; +import java.util.Map; + + +@Service +public class DataSourcePerTenantService implements DisposableBean { + + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + private final Map tenantToDataSourceMap = new HashMap<>(); + + @Value("${fineract.datasource.core.port}") + private int defaultPort; + + @Value("${fineract.datasource.core.host}") + private String defaultHostname; + + @Value("${fineract.datasource.core.schema}") + private String defaultSchema; + + @Value("${fineract.datasource.core.username}") + private String defaultUsername; + + @Value("${fineract.datasource.core.password}") + private String defaultPassword; + + @Value("${fineract.datasource.common.protocol}") + private String jdbcProtocol; + + @Value("${fineract.datasource.common.subprotocol}") + private String jdbcSubprotocol; + + @Value("${fineract.datasource.common.driverclass_name}") + private String driverClass; + + public DataSource retrieveDataSource() { + DataSource tenantDataSource; + + final TenantServerConnection tenant = ThreadLocalContextUtil.getTenant(); + if (tenant != null) { + synchronized (this.tenantToDataSourceMap) { + if (this.tenantToDataSourceMap.containsKey(tenant.getId())) { + tenantDataSource = this.tenantToDataSourceMap.get(tenant.getId()); + } else { + tenantDataSource = createNewDataSourceFor(tenant); + this.tenantToDataSourceMap.put(tenant.getId(), tenantDataSource); + } + } + } else { + synchronized (this.tenantToDataSourceMap) { + long defaultConnectionKey = 0; + if (this.tenantToDataSourceMap.containsKey(defaultConnectionKey)) { + tenantDataSource = this.tenantToDataSourceMap.get(defaultConnectionKey); + } else { + TenantServerConnection defaultConnection = new TenantServerConnection(); + defaultConnection.setSchemaServer(defaultHostname); + defaultConnection.setSchemaServerPort(String.valueOf(defaultPort)); + defaultConnection.setSchemaName(defaultSchema); + defaultConnection.setSchemaUsername(defaultUsername); + defaultConnection.setSchemaPassword(defaultPassword); + tenantDataSource = createNewDataSourceFor(defaultConnection); + this.tenantToDataSourceMap.put(defaultConnectionKey, tenantDataSource); + } + } + } + + return tenantDataSource; + } + + private DataSource createNewDataSourceFor(TenantServerConnection tenant) { + HikariConfig config = new HikariConfig(); + config.setUsername(tenant.getSchemaUsername()); + config.setPassword(tenant.getSchemaPassword()); + config.setJdbcUrl(createJdbcUrl(jdbcProtocol, jdbcSubprotocol, tenant.getSchemaServer(), + Integer.parseInt(tenant.getSchemaServerPort()), tenant.getSchemaName())); + config.setAutoCommit(false); + config.setConnectionInitSql("SELECT 1"); + config.setValidationTimeout(30000); + config.setConnectionTestQuery("SELECT 1"); + config.setConnectionTimeout(30000); + config.setDriverClassName(driverClass); + config.setIdleTimeout(600000); + config.setMaximumPoolSize(20); + config.setMinimumIdle(5); + config.setPoolName(tenant.getSchemaName() + "Pool"); + return new HikariDataSource(config); + } + + private String createJdbcUrl(String jdbcProtocol, String jdbcSubprotocol, String hostname, int port, String dbName) { + return new StringBuilder() + .append(jdbcProtocol) + .append(':') + .append(jdbcSubprotocol) + .append("://") + .append(hostname) + .append(':') + .append(port) + .append('/') + .append(dbName) + .toString(); + } + + @Override + public void destroy() { + for (Map.Entry entry : this.tenantToDataSourceMap.entrySet()) { + HikariDataSource ds = (HikariDataSource) entry.getValue(); + ds.close(); + logger.info("Datasource closed: {}", ds.getPoolName()); + } + } +} \ No newline at end of file diff --git a/ph-ee-operations-app/src/main/java/org/apache/fineract/core/service/OperatorUtils.java b/ph-ee-operations-app/src/main/java/org/apache/fineract/core/service/OperatorUtils.java new file mode 100644 index 000000000..2085143d0 --- /dev/null +++ b/ph-ee-operations-app/src/main/java/org/apache/fineract/core/service/OperatorUtils.java @@ -0,0 +1,14 @@ +package org.apache.fineract.core.service; + +import java.text.SimpleDateFormat; + +public class OperatorUtils { + + public static String strip(String str) { + return str.replaceAll("^\"|\"$", ""); + } + + public static SimpleDateFormat dateFormat() { + return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + } +} diff --git a/ph-ee-operations-app/src/main/java/org/apache/fineract/core/service/PlatformRequestLog.java b/ph-ee-operations-app/src/main/java/org/apache/fineract/core/service/PlatformRequestLog.java new file mode 100644 index 000000000..5a1a9aa22 --- /dev/null +++ b/ph-ee-operations-app/src/main/java/org/apache/fineract/core/service/PlatformRequestLog.java @@ -0,0 +1,75 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.core.service; + +import org.apache.commons.lang3.time.StopWatch; + +import javax.servlet.http.HttpServletRequest; +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; +import java.util.stream.Collectors; + +/** + * Immutable data object representing platform API request used for + * logging/debugging. + */ +public class PlatformRequestLog { + + @SuppressWarnings("unused") + private final long startTime; + @SuppressWarnings("unused") + private final long totalTime; + @SuppressWarnings("unused") + private final String method; + @SuppressWarnings("unused") + private final String url; + @SuppressWarnings("unused") + private final Map parameters; + + public static PlatformRequestLog from(final StopWatch task, final HttpServletRequest request) throws IOException { + final String requestUrl = request.getRequestURL().toString(); + + final Map parameters = new HashMap<>(request.getParameterMap()); + parameters.remove("password"); + parameters.remove("_"); + + return new PlatformRequestLog(task.getStartTime(), task.getTime(), request.getMethod(), requestUrl, parameters); + } + + private PlatformRequestLog(final long startTime, final long time, final String method, final String requestUrl, + final Map parameters) { + this.startTime = startTime; + this.totalTime = time; + this.method = method; + this.url = requestUrl; + this.parameters = parameters; + } + + public String toString() { + return String.format("Start: %s -- total: %s -- method: %s -- url: %s -- parameters: %s", + startTime, + totalTime, + method, + url, + parameters.entrySet().stream() + .map(e -> e.getKey() + " - " + String.join(",", e.getValue())) + .collect(Collectors.joining(" # "))); + } +} \ No newline at end of file diff --git a/ph-ee-operations-app/src/main/java/org/apache/fineract/core/service/RoutingDataSource.java b/ph-ee-operations-app/src/main/java/org/apache/fineract/core/service/RoutingDataSource.java new file mode 100644 index 000000000..dade32db5 --- /dev/null +++ b/ph-ee-operations-app/src/main/java/org/apache/fineract/core/service/RoutingDataSource.java @@ -0,0 +1,45 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.core.service; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.jdbc.datasource.AbstractDataSource; +import org.springframework.stereotype.Service; + +import java.sql.Connection; +import java.sql.SQLException; + + +@Service +public class RoutingDataSource extends AbstractDataSource { + + @Autowired + private DataSourcePerTenantService dataSourcePerTenantService; + + @Override + public Connection getConnection() throws SQLException { + return dataSourcePerTenantService.retrieveDataSource().getConnection(); + } + + @Override + public Connection getConnection(final String username, final String password) throws SQLException { + return dataSourcePerTenantService.retrieveDataSource().getConnection(username, password); + } + +} \ No newline at end of file diff --git a/ph-ee-operations-app/src/main/java/org/apache/fineract/core/service/TenantAwareHeaderFilter.java b/ph-ee-operations-app/src/main/java/org/apache/fineract/core/service/TenantAwareHeaderFilter.java new file mode 100644 index 000000000..5e2aa0f03 --- /dev/null +++ b/ph-ee-operations-app/src/main/java/org/apache/fineract/core/service/TenantAwareHeaderFilter.java @@ -0,0 +1,81 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.core.service; + +import org.apache.commons.lang3.time.StopWatch; +import org.apache.fineract.organisation.tenant.TenantServerConnectionRepository; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.web.filter.GenericFilterBean; + +import javax.servlet.FilterChain; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + + +public class TenantAwareHeaderFilter extends GenericFilterBean { + + private static final String TENANT_IDENTIFIER_REQUEST_HEADER = "Platform-TenantId"; + private static final String TENANT_IDENTIFIER_REQUEST_PARAM = "tenantIdentifier"; + private static final String EXCLUDED_URL = "/oauth/token_key"; + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + private final TenantServerConnectionRepository repository; + + public TenantAwareHeaderFilter(TenantServerConnectionRepository repository) { + this.repository = repository; + } + + @Override + public void doFilter(final ServletRequest req, final ServletResponse res, final FilterChain chain) throws IOException { + final HttpServletRequest request = (HttpServletRequest) req; + final HttpServletResponse response = (HttpServletResponse) res; + final StopWatch task = new StopWatch(); + task.start(); + + try { + if(!EXCLUDED_URL.equals(request.getServletPath()) && + !request.getServletPath().contains("swagger") && !request.getServletPath().contains("api-docs") && !request.getServletPath().contains("actuator") ) { + String tenantIdentifier = request.getHeader(TENANT_IDENTIFIER_REQUEST_HEADER); + if (tenantIdentifier == null || tenantIdentifier.length() < 1) { + tenantIdentifier = request.getParameter(TENANT_IDENTIFIER_REQUEST_PARAM); + } + + if (tenantIdentifier == null || tenantIdentifier.length() < 1) { + throw new RuntimeException( + String.format("No tenant identifier found! Add request header: %s or request param: %s", TENANT_IDENTIFIER_REQUEST_HEADER, TENANT_IDENTIFIER_REQUEST_PARAM)); + } + + ThreadLocalContextUtil.setTenant(this.repository.findOneBySchemaName(tenantIdentifier)); + } + chain.doFilter(request, res); + } catch (Exception e) { + logger.error("Error when executing request!", e); + SecurityContextHolder.getContext().setAuthentication(null); + response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); + } finally { + task.stop(); + ThreadLocalContextUtil.clear(); + logger.info(PlatformRequestLog.from(task, request).toString()); + } + } +} diff --git a/ph-ee-operations-app/src/main/java/org/apache/fineract/core/service/TenantAwareUserDetailsService.java b/ph-ee-operations-app/src/main/java/org/apache/fineract/core/service/TenantAwareUserDetailsService.java new file mode 100644 index 000000000..ed78f0b89 --- /dev/null +++ b/ph-ee-operations-app/src/main/java/org/apache/fineract/core/service/TenantAwareUserDetailsService.java @@ -0,0 +1,47 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.core.service; + +import org.apache.fineract.organisation.user.AppUser; +import org.apache.fineract.organisation.user.AppUserRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.stereotype.Component; + +import java.util.Collections; + +import static org.apache.fineract.config.CacheConfig.CACHE_USER_BY_NAME; + +@Component(value = "userDetailsService") +public class TenantAwareUserDetailsService implements UserDetailsService { + + @Autowired + private AppUserRepository appUserRepository; + + @Override + @Cacheable(cacheNames = CACHE_USER_BY_NAME) + public UserDetails loadUserByUsername(final String username) { + AppUser appUserByName = appUserRepository.findAppUserByName(username); + AppUser unknowUser = new AppUser(); + unknowUser.setRoles(Collections.emptyList()); + return appUserByName == null ? unknowUser : appUserByName; + } +} \ No newline at end of file diff --git a/ph-ee-operations-app/src/main/java/org/apache/fineract/core/service/TenantDatabaseUpgradeService.java b/ph-ee-operations-app/src/main/java/org/apache/fineract/core/service/TenantDatabaseUpgradeService.java new file mode 100644 index 000000000..185541493 --- /dev/null +++ b/ph-ee-operations-app/src/main/java/org/apache/fineract/core/service/TenantDatabaseUpgradeService.java @@ -0,0 +1,143 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.core.service; + +import com.googlecode.flyway.core.Flyway; +import org.apache.fineract.organisation.tenant.TenantServerConnection; +import org.apache.fineract.organisation.tenant.TenantServerConnectionRepository; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; + +import javax.annotation.PostConstruct; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static org.apache.fineract.config.ResourceServerConfig.IDENTITY_PROVIDER_RESOURCE_ID; + +@Service +public class TenantDatabaseUpgradeService { + + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Autowired + private TenantServerConnectionRepository repository; + + @Autowired + private DataSourcePerTenantService dataSourcePerTenantService; + + @Value("${fineract.datasource.core.host}") + private String hostname; + + @Value("${fineract.datasource.core.port}") + private int port; + + @Value("${fineract.datasource.core.username}") + private String username; + + @Value("${fineract.datasource.core.password}") + private String password; + + @Value("${fineract.datasource.common.protocol}") + private String jdbcProtocol; + + @Value("${fineract.datasource.common.subprotocol}") + private String jdbcSubprotocol; + + @Value("${fineract.datasource.common.driverclass_name}") + private String driverClass; + + @Value("${token.user.access-validity-seconds}") + private String userTokenAccessValiditySeconds; + + @Value("${token.user.refresh-validity-seconds}") + private String userTokenRefreshValiditySeconds; + + @Value("${token.client.access-validity-seconds}") + private String clientAccessTokenValidity; + + @Value("${token.client.channel.secret}") + private String channelClientSecret; + + @Value("#{'${tenants}'.split(',')}") + private List tenants; + + @PostConstruct + public void setupEnvironment() { + flywayDefaultSchema(); + insertTenants(); + flywayTenants(); + } + + private void flywayTenants() { + for (TenantServerConnection tenant : repository.findAll()) { + if (tenant.isAutoUpdateEnabled()) { + try { + ThreadLocalContextUtil.setTenant(tenant); + final Flyway fw = new Flyway(); + fw.setDataSource(dataSourcePerTenantService.retrieveDataSource()); + fw.setLocations("sql/migrations/tenant"); + fw.setInitOnMigrate(true); + fw.setOutOfOrder(true); + Map placeholders = new HashMap<>(); + placeholders.put("tenantDatabase", tenant.getSchemaName()); // add tenant as aud claim + placeholders.put("userAccessTokenValidity", userTokenAccessValiditySeconds); + placeholders.put("userRefreshTokenValidity", userTokenRefreshValiditySeconds); + placeholders.put("clientAccessTokenValidity", clientAccessTokenValidity); + placeholders.put("channelClientSecret", channelClientSecret); + placeholders.put("identityProviderResourceId", IDENTITY_PROVIDER_RESOURCE_ID); // add identity provider as aud claim + fw.setPlaceholders(placeholders); + fw.migrate(); + } catch (Exception e) { + logger.error("Error when running flyway on tenant: {}", tenant.getSchemaName(), e); + } finally { + ThreadLocalContextUtil.clear(); + } + } + } + } + + private void insertTenants() { + for(String tenant : tenants) { + TenantServerConnection existingTenant = repository.findOneBySchemaName(tenant); + if(existingTenant == null) { + TenantServerConnection tenantServerConnection = new TenantServerConnection(); + tenantServerConnection.setSchemaName(tenant); + tenantServerConnection.setSchemaServer(hostname); + tenantServerConnection.setSchemaServerPort(String.valueOf(port)); + tenantServerConnection.setSchemaUsername(username); + tenantServerConnection.setSchemaPassword(password); + tenantServerConnection.setAutoUpdateEnabled(true); + repository.saveAndFlush(tenantServerConnection); + } + } + } + + private void flywayDefaultSchema() { + final Flyway fw = new Flyway(); + fw.setDataSource(dataSourcePerTenantService.retrieveDataSource()); + fw.setLocations("sql/migrations/core"); + fw.setInitOnMigrate(true); + fw.setOutOfOrder(true); + fw.migrate(); + } +} diff --git a/ph-ee-operations-app/src/main/java/org/apache/fineract/core/service/ThreadLocalContextUtil.java b/ph-ee-operations-app/src/main/java/org/apache/fineract/core/service/ThreadLocalContextUtil.java new file mode 100644 index 000000000..45a1bbc5a --- /dev/null +++ b/ph-ee-operations-app/src/main/java/org/apache/fineract/core/service/ThreadLocalContextUtil.java @@ -0,0 +1,40 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.core.service; + +import org.apache.fineract.organisation.tenant.TenantServerConnection; +import org.springframework.util.Assert; + +public class ThreadLocalContextUtil { + + private static final ThreadLocal tenantcontext = new ThreadLocal<>(); + + public static void setTenant(final TenantServerConnection tenant) { + Assert.notNull(tenant, "tenant cannot be null"); + tenantcontext.set(tenant); + } + + public static TenantServerConnection getTenant() { + return tenantcontext.get(); + } + + public static void clear() { + tenantcontext.remove(); + } +} \ No newline at end of file diff --git a/ph-ee-operations-app/src/main/java/org/apache/fineract/data/ErrorCode.java b/ph-ee-operations-app/src/main/java/org/apache/fineract/data/ErrorCode.java new file mode 100644 index 000000000..d1a314645 --- /dev/null +++ b/ph-ee-operations-app/src/main/java/org/apache/fineract/data/ErrorCode.java @@ -0,0 +1,12 @@ +package org.apache.fineract.data; + +public enum ErrorCode { + CSV_GET_WRITER, + CSV_WRITE_HEADER, + CSV_WRITE_DATA, + CSV_STREAM, + CSV_BUILDER, + INVALID_FILTER, + FILTER_ID, + EMPTY_RESULT +} diff --git a/ph-ee-operations-app/src/main/java/org/apache/fineract/data/ErrorResponse.java b/ph-ee-operations-app/src/main/java/org/apache/fineract/data/ErrorResponse.java new file mode 100644 index 000000000..f56d73334 --- /dev/null +++ b/ph-ee-operations-app/src/main/java/org/apache/fineract/data/ErrorResponse.java @@ -0,0 +1,50 @@ +package org.apache.fineract.data; + +import java.util.HashMap; + +public class ErrorResponse extends HashMap { + + private enum Key { + ERRORCODE("errorCode"), + ERRORDESCRIPTION("errorDescription"), + DEVELOPERMESSAGE("developerMessage"); + + private final String text; + + private Key(final String text) { + this.text = text; + } + } + + public static class Builder { + ErrorResponse res = new ErrorResponse(); + + public Builder setErrorCode(String errorCode) { + res.put(Key.ERRORCODE.text, errorCode); + return this; + } + + public Builder setErrorDescription(String errorDescription) { + res.put(Key.ERRORDESCRIPTION.text, errorDescription); + return this; + } + + public Builder setDeveloperMessage(String developerMessage) { + res.put(Key.DEVELOPERMESSAGE.text, developerMessage); + return this; + } + + public ErrorResponse build() { + if(!res.containsKey(Key.ERRORCODE.text)) { + setErrorCode(""); + } + if(!res.containsKey(Key.ERRORDESCRIPTION.text)) { + setErrorDescription(""); + } + if (!res.containsKey(Key.DEVELOPERMESSAGE.text)) { + setDeveloperMessage(res.get(Key.ERRORDESCRIPTION.text)); + } + return res; + } + } +} diff --git a/ph-ee-operations-app/src/main/java/org/apache/fineract/data/IMUConversionData.java b/ph-ee-operations-app/src/main/java/org/apache/fineract/data/IMUConversionData.java new file mode 100644 index 000000000..6a35b58b6 --- /dev/null +++ b/ph-ee-operations-app/src/main/java/org/apache/fineract/data/IMUConversionData.java @@ -0,0 +1,110 @@ +package org.apache.fineract.data; + +import com.fasterxml.jackson.annotation.JsonInclude; + +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.util.Date; + +@JsonInclude(JsonInclude.Include.NON_NULL) +public class IMUConversionData { + private String lockKey; + private String from; + private String to; + private Boolean failWhenExpired; + private BigDecimal amount; + private BigDecimal rate; + private BigDecimal convertedAmount; + private String errorCode; + private String errorMessage; + private Date expireBy; + + public IMUConversionData() { + } + + public String getFrom() { + return from; + } + + public void setFrom(String from) { + this.from = from; + } + + public String getTo() { + return to; + } + + public void setTo(String to) { + this.to = to; + } + + public BigDecimal getAmount() { + return amount; + } + + public void setAmount(BigDecimal amount) { + if(amount != null) + amount = amount.setScale(2, RoundingMode.HALF_UP); + this.amount = amount; + } + + public BigDecimal getRate() { + return rate; + } + + public void setRate(BigDecimal rate) { + if(rate != null) + rate = rate.setScale(2, RoundingMode.HALF_UP); + this.rate = rate; + } + + public BigDecimal getConvertedAmount() { + return convertedAmount; + } + + public void setConvertedAmount(BigDecimal convertedAmount) { + if(convertedAmount != null) + convertedAmount = convertedAmount.setScale(2, RoundingMode.HALF_UP); + this.convertedAmount = convertedAmount; + } + + public String getErrorCode() { + return errorCode; + } + + public void setErrorCode(String errorCode) { + this.errorCode = errorCode; + } + + public String getErrorMessage() { + return errorMessage; + } + + public void setErrorMessage(String errorMessage) { + this.errorMessage = errorMessage; + } + + public String getLockKey() { + return lockKey; + } + + public void setLockKey(String lockKey) { + this.lockKey = lockKey; + } + + public Boolean getFailWhenExpired() { + return failWhenExpired; + } + + public void setFailWhenExpired(Boolean failWhenExpired) { + this.failWhenExpired = failWhenExpired; + } + + public Date getExpireBy() { + return expireBy; + } + + public void setExpireBy(Date expireBy) { + this.expireBy = expireBy; + } +} diff --git a/ph-ee-operations-app/src/main/java/org/apache/fineract/exception/CsvWriterException.java b/ph-ee-operations-app/src/main/java/org/apache/fineract/exception/CsvWriterException.java new file mode 100644 index 000000000..e71e0d636 --- /dev/null +++ b/ph-ee-operations-app/src/main/java/org/apache/fineract/exception/CsvWriterException.java @@ -0,0 +1,11 @@ +package org.apache.fineract.exception; + +import org.apache.fineract.data.ErrorCode; + +public class CsvWriterException extends WriteToCsvException{ + + public CsvWriterException(ErrorCode errorCode, String errorDescription) { + super(errorCode, errorDescription); + } + +} diff --git a/ph-ee-operations-app/src/main/java/org/apache/fineract/exception/WriteToCsvException.java b/ph-ee-operations-app/src/main/java/org/apache/fineract/exception/WriteToCsvException.java new file mode 100644 index 000000000..449e3f396 --- /dev/null +++ b/ph-ee-operations-app/src/main/java/org/apache/fineract/exception/WriteToCsvException.java @@ -0,0 +1,48 @@ +package org.apache.fineract.exception; + +import org.apache.fineract.data.ErrorCode; + +public class WriteToCsvException extends Exception { + + private String developerMessage; + private final String errorDescription; + private final ErrorCode errorCode; + + public WriteToCsvException(ErrorCode errorCode, String errorDescription, String developerMessage) { + super(developerMessage); + this.errorCode = errorCode; + this.errorDescription = errorDescription; + this.developerMessage = developerMessage; + } + + public WriteToCsvException(ErrorCode errorCode, String errorDescription) { + super(errorDescription); + this.errorCode = errorCode; + this.errorDescription = errorDescription; + this.developerMessage = errorDescription; + } + + public void setDeveloperMessage(String developerMessage) { + this.developerMessage = developerMessage; + } + + public String getErrorCode() { + return errorCode.name(); + } + + public String getErrorDescription() { + return errorDescription; + } + + public String getDeveloperMessage() { return developerMessage; } + + @Override + public String toString() { + return "{" + + "developerMessage='" + developerMessage + '\'' + + ", errorDescription='" + errorDescription + '\'' + + ", errorCode=" + errorCode + + '}'; + } + +} diff --git a/ph-ee-operations-app/src/main/java/org/apache/fineract/file/AwsFileTransferImpl.java b/ph-ee-operations-app/src/main/java/org/apache/fineract/file/AwsFileTransferImpl.java new file mode 100644 index 000000000..af9856f94 --- /dev/null +++ b/ph-ee-operations-app/src/main/java/org/apache/fineract/file/AwsFileTransferImpl.java @@ -0,0 +1,99 @@ +package org.apache.fineract.file; + +import com.amazonaws.auth.AWSCredentials; +import com.amazonaws.auth.AWSStaticCredentialsProvider; +import com.amazonaws.auth.BasicAWSCredentials; +import com.amazonaws.client.builder.AwsClientBuilder; +import com.amazonaws.services.s3.AmazonS3; +import com.amazonaws.services.s3.AmazonS3ClientBuilder; +import com.amazonaws.services.s3.model.PutObjectRequest; +import com.amazonaws.services.s3.model.S3Object; +import com.amazonaws.services.s3.model.S3ObjectInputStream; +import com.amazonaws.util.IOUtils; +import com.mysql.cj.log.Log; +import org.apache.commons.lang3.time.DateUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; +import org.springframework.web.multipart.MultipartFile; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.Date; + +@Service +@Qualifier("awsStorage") +public class AwsFileTransferImpl implements FileTransferService { + private Logger logger = LoggerFactory.getLogger(this.getClass()); + @Value("${cloud.aws.credentials.access-key}") + private String accessKey; + + @Value("${cloud.aws.credentials.secret-key}") + private String accessSecret; + + @Value("${cloud.aws.region.static}") + private String region; + @Autowired + private AmazonS3 s3Client; + @Value("${cloud.aws.s3BaseUrl}") + private String endpoint; + @Value("${cloud.aws.minio-public-host}") + private String minioPublicHost; + private static final String MINIO = "minio"; + @Override + public String uploadFile(File file, String bucketName) { + + AWSCredentials credentials = new BasicAWSCredentials(accessKey, accessSecret); + + s3Client = AmazonS3ClientBuilder.standard().withCredentials(new AWSStaticCredentialsProvider(credentials)) + .withPathStyleAccessEnabled(true).withEndpointConfiguration(new AwsClientBuilder.EndpointConfiguration(endpoint, region)) + .build(); + String fileName = System.currentTimeMillis() + "_" + file.getName(); + logger.info("uploading file"); + s3Client.putObject(new PutObjectRequest(bucketName, fileName, file)); + String url = s3Client.getUrl(bucketName, fileName).toString(); + if(url.contains(MINIO)){ + url = url.replaceFirst("^.*(?=/"+bucketName+")",minioPublicHost); + } + logger.debug("File access URL",url); + file.delete(); + return url; + } + + @Override + public byte[] downloadFile(String fileName, String bucketName) { + AWSCredentials credentials = new BasicAWSCredentials(accessKey, accessSecret); + s3Client = AmazonS3ClientBuilder.standard().withCredentials(new AWSStaticCredentialsProvider(credentials)) + .withPathStyleAccessEnabled(true).withEndpointConfiguration(new AwsClientBuilder.EndpointConfiguration(endpoint, region)) + .build(); + S3Object s3Object = s3Client.getObject(bucketName, fileName); + S3ObjectInputStream inputStream = s3Object.getObjectContent(); + try { + byte[] content = IOUtils.toByteArray(inputStream); + return content; + } catch (IOException e) { + e.printStackTrace(); + } + return null; + } + + @Override + public void deleteFile(String fileName, String bucketName) { + s3Client.deleteObject(bucketName, fileName); + } + + private File convertMultiPartFileToFile(MultipartFile file) { + File convertedFile = new File(file.getOriginalFilename()); + try (FileOutputStream fos = new FileOutputStream(convertedFile)) { + fos.write(file.getBytes()); + } catch (IOException e) { + logger.error("Error converting multipartFile to file", e); + } + return convertedFile; + } +} diff --git a/ph-ee-operations-app/src/main/java/org/apache/fineract/file/AzureFileTransferImpl.java b/ph-ee-operations-app/src/main/java/org/apache/fineract/file/AzureFileTransferImpl.java new file mode 100644 index 000000000..c6f7eea6f --- /dev/null +++ b/ph-ee-operations-app/src/main/java/org/apache/fineract/file/AzureFileTransferImpl.java @@ -0,0 +1,62 @@ +package org.apache.fineract.file; + +import com.azure.storage.blob.BlobClientBuilder; +import com.azure.storage.blob.models.BlobProperties; +import org.apache.commons.io.FileUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.stereotype.Service; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Paths; + +@Service +@Qualifier("azureStorage") +@ConditionalOnProperty( + value="cloud.azure.enabled", + havingValue = "true") +public class AzureFileTransferImpl implements FileTransferService { + private Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Autowired + BlobClientBuilder client; + + @Override + public String uploadFile(File file, String bucketName) { + + try { + String fileName = System.currentTimeMillis() + "_" + file.getName(); + client.containerName(bucketName).blobName(fileName).buildClient().upload(FileUtils.openInputStream(file), file.length()); + file.delete(); + return fileName; + } catch (IOException e) { + logger.error("Error uploading file to Azure", e); + } + + return null; + } + + @Override + public byte[] downloadFile(String fileName, String bucketName) { + try { + File temp = new File("/temp/"+fileName); + BlobProperties properties = client.containerName(bucketName).blobName(fileName).buildClient().downloadToFile(temp.getPath()); + byte[] content = Files.readAllBytes(Paths.get(temp.getPath())); + temp.delete(); + return content; + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + + @Override + public void deleteFile(String fileName, String bucketName) { + client.containerName(bucketName).blobName(fileName).buildClient().delete(); + } +} diff --git a/ph-ee-operations-app/src/main/java/org/apache/fineract/file/FileTransferService.java b/ph-ee-operations-app/src/main/java/org/apache/fineract/file/FileTransferService.java new file mode 100644 index 000000000..722d995fb --- /dev/null +++ b/ph-ee-operations-app/src/main/java/org/apache/fineract/file/FileTransferService.java @@ -0,0 +1,16 @@ +package org.apache.fineract.file; + +import org.springframework.stereotype.Service; + +import java.io.File; + +@Service +public interface FileTransferService { + + String uploadFile(File file, String bucketName); + + byte[] downloadFile(String fileName, String bucketName); + + void deleteFile(String fileName, String bucketName); + +} diff --git a/ph-ee-operations-app/src/main/java/org/apache/fineract/file/config/AwsStorageConfig.java b/ph-ee-operations-app/src/main/java/org/apache/fineract/file/config/AwsStorageConfig.java new file mode 100644 index 000000000..3f3a610c4 --- /dev/null +++ b/ph-ee-operations-app/src/main/java/org/apache/fineract/file/config/AwsStorageConfig.java @@ -0,0 +1,39 @@ +package org.apache.fineract.file.config; + +import com.amazonaws.auth.AWSCredentials; +import com.amazonaws.auth.AWSStaticCredentialsProvider; +import com.amazonaws.auth.BasicAWSCredentials; +import com.amazonaws.client.builder.AwsClientBuilder; +import com.amazonaws.services.s3.AmazonS3; +import com.amazonaws.services.s3.AmazonS3ClientBuilder; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class AwsStorageConfig { + + @Value("${cloud.aws.credentials.access-key}") + private String accessKey; + + @Value("${cloud.aws.credentials.secret-key}") + private String accessSecret; + + @Value("${cloud.aws.region.static}") + private String region; + @Value("${cloud.aws.s3BaseUrl}") + private String endpoint; + + @Bean + @ConditionalOnProperty( + value="cloud.aws.enabled", + havingValue = "true") + public AmazonS3 s3Client() { + AWSCredentials credentials = new BasicAWSCredentials(accessKey, accessSecret); + return AmazonS3ClientBuilder.standard().withCredentials(new AWSStaticCredentialsProvider(credentials)) + .withPathStyleAccessEnabled(true).withEndpointConfiguration(new AwsClientBuilder.EndpointConfiguration(endpoint, region)) + .build(); + } + +} diff --git a/ph-ee-operations-app/src/main/java/org/apache/fineract/file/config/AzureStorageConfig.java b/ph-ee-operations-app/src/main/java/org/apache/fineract/file/config/AzureStorageConfig.java new file mode 100644 index 000000000..cc9bc4651 --- /dev/null +++ b/ph-ee-operations-app/src/main/java/org/apache/fineract/file/config/AzureStorageConfig.java @@ -0,0 +1,25 @@ +package org.apache.fineract.file.config; + +import com.azure.storage.blob.BlobClientBuilder; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class AzureStorageConfig { + + @Value("${cloud.azure.blob.connection-string}") + String connectionString; + + @Bean + @ConditionalOnProperty( + value="cloud.azure.enabled", + havingValue = "true") + public BlobClientBuilder getClient() { + BlobClientBuilder client = new BlobClientBuilder(); + client.connectionString(connectionString); + return client; + } + +} diff --git a/ph-ee-operations-app/src/main/java/org/apache/fineract/operations/Batch.java b/ph-ee-operations-app/src/main/java/org/apache/fineract/operations/Batch.java new file mode 100644 index 000000000..a60839d61 --- /dev/null +++ b/ph-ee-operations-app/src/main/java/org/apache/fineract/operations/Batch.java @@ -0,0 +1,108 @@ +package org.apache.fineract.operations; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import org.apache.fineract.organisation.parent.AbstractPersistableCustom; +import org.eclipse.persistence.annotations.Index; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.EnumType; +import javax.persistence.Enumerated; +import javax.persistence.Table; +import java.util.Date; + +@Entity +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +@Table(name = "batches") +public class Batch extends AbstractPersistableCustom { + + @Column(name = "BATCH_ID") + private String batchId; + + @Column(name = "SUB_BATCH_ID") + private String subBatchId; + + @Column(name = "REQUEST_ID") + private String requestId; + + @Column(name = "REQUEST_FILE") + private String requestFile; + + @Column(name = "TOTAL_TRANSACTIONS") + private Long totalTransactions; + + @Column(name = "ONGOING") + private Long ongoing; + + @Column(name = "FAILED") + private Long failed; + + @Column(name = "COMPLETED") + private Long completed; + + @Column(name = "TOTAL_AMOUNT") + private Long totalAmount; + + @Column(name = "ONGOING_AMOUNT") + private Long ongoingAmount; + + @Column(name = "FAILED_AMOUNT") + private Long failedAmount; + + @Column(name = "COMPLETED_AMOUNT") + private Long completedAmount; + + @Column(name = "RESULT_FILE") + private String result_file; + + @Column(name = "RESULT_GENERATED_AT") + private Date resultGeneratedAt; + + @Column(name = "NOTE") + private String note; + + @Column(name = "WORKFLOW_KEY") + private Long workflowKey; + + @Column(name = "WORKFLOW_INSTANCE_KEY") + @Index(name = "idx_batches_key") + private Long workflowInstanceKey; + + @Column(name = "STARTED_AT") + private Date startedAt; + + @Column(name = "COMPLETED_AT") + private Date completedAt; + + @Column(name = "PAYMENT_MODE") + private String paymentMode; + + @Column(name = "REGISTERING_INSTITUTION_ID") + private String registeringInstitutionId; + + @Column(name = "PAYER_FSP") + private String payerFsp; + + @Column(name = "CLIENT_CORRELATION_ID") + private String correlationId; + + @Column(name = "APPROVED_AMOUNT") + private Long approvedAmount; + + @Column(name = "APPROVED_COUNT") + private Long approvedCount; + + @Enumerated(EnumType.STRING) + @Column(name = "STATUS") + private BatchStatus status; + + public Batch(Long workflowInstanceKey) { + this.workflowInstanceKey = workflowInstanceKey; + } +} diff --git a/ph-ee-operations-app/src/main/java/org/apache/fineract/operations/BatchDTO.java b/ph-ee-operations-app/src/main/java/org/apache/fineract/operations/BatchDTO.java new file mode 100644 index 000000000..d9c005517 --- /dev/null +++ b/ph-ee-operations-app/src/main/java/org/apache/fineract/operations/BatchDTO.java @@ -0,0 +1,81 @@ +package org.apache.fineract.operations; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import lombok.ToString; + +import java.math.BigDecimal; + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +public class BatchDTO { + + private String batchId; + + private String requestId; + + private Long total; + + private Long ongoing; + + private Long failed; + + private Long successful; + + private BigDecimal totalAmount; + + private BigDecimal successfulAmount; + + private BigDecimal pendingAmount; + + private BigDecimal failedAmount; + + private String file; + + private String notes; + + private String createdAt; + + private String status; + + private String modes; + + private String purpose; + + private String failPercentage; + + private String successPercentage; + + private String registeringInstitutionId; + + private String payerFsp; + + private String correlationId; + + public BatchDTO(String batchId, String requestId, Long totalTransactions, Long ongoing, Long failed, + Long completed, BigDecimal total_amount, BigDecimal completed_amount, BigDecimal ongoing_amount, + BigDecimal failed_amount, String result_file, String note, String failPercentage, + String successPercentage, String registeringInstitutionId, String payerFsp, String correlationId) { + this.batchId = batchId; + this.requestId = requestId; + this.total = totalTransactions; + this.ongoing = ongoing; + this.failed = failed; + this.successful = completed; + this.totalAmount = total_amount; + this.successfulAmount = completed_amount; + this.pendingAmount = ongoing_amount; + this.failedAmount = failed_amount; + this.file = result_file; + this.notes = note; + this.failPercentage = failPercentage; + this.successPercentage = successPercentage; + this.registeringInstitutionId = registeringInstitutionId; + this.payerFsp = payerFsp; + this.correlationId = correlationId; + } +} diff --git a/ph-ee-operations-app/src/main/java/org/apache/fineract/operations/BatchPaginatedResponse.java b/ph-ee-operations-app/src/main/java/org/apache/fineract/operations/BatchPaginatedResponse.java new file mode 100644 index 000000000..4b0a22d9e --- /dev/null +++ b/ph-ee-operations-app/src/main/java/org/apache/fineract/operations/BatchPaginatedResponse.java @@ -0,0 +1,62 @@ +package org.apache.fineract.operations; + +import lombok.Getter; +import lombok.Setter; + +import java.util.List; + +@Getter +@Setter +public class BatchPaginatedResponse { + + long totalBatches, totalTransactions, totalAmount, totalApprovedCount, totalApprovedAmount, totalSubBatchesCreated; + List data; + + public void setTotalBatches(Long totalBatches) { + if (totalBatches != null) { + this.totalBatches = totalBatches; + } else { + this.totalBatches = 0; + } + } + + public void setTotalTransactions(Long totalTransactions) { + if (totalTransactions != null) { + this.totalTransactions = totalTransactions; + } else { + this.totalTransactions = 0; + } + } + + public void setTotalAmount(Long totalAmount) { + if (totalAmount != null) { + this.totalAmount = totalAmount; + } else { + this.totalAmount = 0; + } + } + + public void setTotalApprovedCount(Long totalApprovedCount) { + if (totalApprovedCount != null) { + this.totalApprovedCount = totalApprovedCount; + } else { + this.totalApprovedCount = 0; + } + } + + public void setTotalApprovedAmount(Long totalApprovedAmount) { + if (totalApprovedAmount != null) { + this.totalApprovedAmount = totalApprovedAmount; + } else { + this.totalApprovedAmount = 0; + } + } + + public void setTotalSubBatchesCreated(Long totalSubBatchesCreated) { + if (totalSubBatchesCreated != null) { + this.totalSubBatchesCreated = totalSubBatchesCreated; + } else { + this.totalSubBatchesCreated = 0; + } + } +} diff --git a/ph-ee-operations-app/src/main/java/org/apache/fineract/operations/BatchRepository.java b/ph-ee-operations-app/src/main/java/org/apache/fineract/operations/BatchRepository.java new file mode 100644 index 000000000..1f8fe1a31 --- /dev/null +++ b/ph-ee-operations-app/src/main/java/org/apache/fineract/operations/BatchRepository.java @@ -0,0 +1,159 @@ +package org.apache.fineract.operations; + +import org.springframework.data.domain.Pageable; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; +import org.springframework.data.jpa.repository.Query; + +import java.util.Date; +import java.util.List; +import java.util.Optional; + +public interface BatchRepository extends JpaRepository, JpaSpecificationExecutor { + + Batch findByWorkflowInstanceKey(Long workflowInstanceKey); + + @Query("SELECT bt FROM Batch bt WHERE bt.batchId = :batchId and bt.subBatchId is null") + Batch findByBatchId(String batchId); + @Query("SELECT bt FROM Batch bt WHERE bt.batchId = :batchId and bt.subBatchId is not null") + List findAllSubBatchId(String batchId); + + List findAllByBatchId(String batchId); + Batch findBySubBatchId(String subBatchId); + + @Query("SELECT bt FROM Batch bt " + + "WHERE bt.registeringInstitutionId LIKE :registeringInstituteId AND bt.payerFsp LIKE :payerFsp AND " + + "bt.batchId LIKE :batchId AND bt.subBatchId IS NULL") + List findAllBatch(String registeringInstituteId, String payerFsp, String batchId, Pageable pageable); + + @Query(value = "SELECT bt FROM Batch bt WHERE bt.startedAt >= :dateFrom AND " + + "(bt.registeringInstitutionId LIKE :registeringInstitutionId) AND (bt.payerFsp LIKE :payerFsp) AND " + + "bt.batchId LIKE :batchId AND bt.subBatchId IS NULL") + List findAllFilterDateFrom(Date dateFrom, String registeringInstitutionId, String payerFsp, String batchId, Pageable pageable); + + @Query(value = "SELECT bt FROM Batch bt WHERE bt.startedAt <= :dateTo AND " + + "(bt.registeringInstitutionId LIKE :registeringInstitutionId) AND (bt.payerFsp LIKE :payerFsp) AND " + + "bt.batchId LIKE :batchId AND bt.subBatchId IS NULL") + List findAllFilterDateTo(Date dateTo, String registeringInstitutionId, String payerFsp, String batchId, Pageable pageable); + + @Query(value = "SELECT bt FROM Batch bt WHERE bt.startedAt BETWEEN :dateFrom AND :dateTo AND " + + "(bt.registeringInstitutionId LIKE :registeringInstitutionId) AND (bt.payerFsp LIKE :payerFsp) AND " + + "bt.batchId LIKE :batchId AND bt.subBatchId IS NULL") + List findAllFilterDateBetween(Date dateFrom, Date dateTo, String registeringInstitutionId, String payerFsp, String batchId, Pageable pageable); + + + @Query(value = "SELECT COUNT(bt) FROM Batch bt " + + "WHERE (bt.registeringInstitutionId LIKE :registeringInstitutionId) AND (bt.payerFsp LIKE :payerFsp) AND " + + "bt.batchId LIKE :batchId AND bt.subBatchId IS NULL") + Optional getTotalBatches(String registeringInstitutionId, String payerFsp, String batchId); + + @Query(value = "SELECT COUNT(bt) FROM Batch bt " + + "WHERE bt.startedAt >= :dateFrom AND " + + "(bt.registeringInstitutionId LIKE :registeringInstitutionId) AND (bt.payerFsp LIKE :payerFsp) AND " + + "bt.batchId LIKE :batchId AND bt.subBatchId IS NULL") + Optional getTotalBatchesDateFrom(Date dateFrom, String registeringInstitutionId, String payerFsp, String batchId); + + @Query(value = "SELECT COUNT(bt) FROM Batch bt " + + "WHERE bt.startedAt <= :dateTo AND " + + "(bt.registeringInstitutionId LIKE :registeringInstitutionId) AND (bt.payerFsp LIKE :payerFsp) AND " + + "bt.batchId LIKE :batchId AND bt.subBatchId IS NULL") + Optional getTotalBatchesDateTo(Date dateTo, String registeringInstitutionId, String payerFsp, String batchId); + + @Query(value = "SELECT COUNT(bt) FROM Batch bt " + + "WHERE bt.startedAt BETWEEN :dateFrom AND :dateTo AND " + + "(bt.registeringInstitutionId LIKE :registeringInstitutionId) AND (bt.payerFsp LIKE :payerFsp) AND " + + "bt.batchId LIKE :batchId AND bt.subBatchId IS NULL") + Optional getTotalBatchesDateBetween(Date dateFrom, Date dateTo, String registeringInstitutionId, String payerFsp, String batchId); + + @Query(value = "SELECT SUM(bt.totalTransactions) FROM Batch bt " + + "WHERE (bt.registeringInstitutionId LIKE :registeringInstitutionId) AND (bt.payerFsp LIKE :payerFsp) AND " + + "bt.batchId LIKE :batchId AND bt.subBatchId IS NULL") + Optional getTotalTransactions(String registeringInstitutionId, String payerFsp, String batchId); + + @Query(value = "SELECT SUM(bt.totalTransactions) FROM Batch bt " + + "WHERE bt.startedAt >= :dateFrom AND " + + "(bt.registeringInstitutionId LIKE :registeringInstitutionId) AND (bt.payerFsp LIKE :payerFsp) AND " + + "bt.batchId LIKE :batchId AND bt.subBatchId IS NULL") + Optional getTotalTransactionsDateFrom(Date dateFrom, String registeringInstitutionId, String payerFsp, String batchId); + + @Query(value = "SELECT SUM(bt.totalTransactions) FROM Batch bt " + + "WHERE bt.startedAt <= :dateTo AND " + + "(bt.registeringInstitutionId LIKE :registeringInstitutionId) AND (bt.payerFsp LIKE :payerFsp) AND " + + "bt.batchId LIKE :batchId AND bt.subBatchId IS NULL") + Optional getTotalTransactionsDateTo(Date dateTo, String registeringInstitutionId, String payerFsp, String batchId); + + @Query(value = "SELECT SUM(bt.totalTransactions) FROM Batch bt " + + "WHERE bt.startedAt BETWEEN :dateFrom AND :dateTo AND " + + "(bt.registeringInstitutionId LIKE :registeringInstitutionId) AND (bt.payerFsp LIKE :payerFsp) AND " + + "bt.batchId LIKE :batchId AND bt.subBatchId IS NULL") + Optional getTotalTransactionsDateBetween(Date dateFrom, Date dateTo, String registeringInstitutionId, String payerFsp, String batchId); + + @Query(value = "SELECT SUM(bt.totalAmount) FROM Batch bt " + + "WHERE (bt.registeringInstitutionId LIKE :registeringInstitutionId) AND (bt.payerFsp LIKE :payerFsp) AND " + + "bt.batchId LIKE :batchId AND bt.subBatchId IS NULL") + Optional getTotalAmount(String registeringInstitutionId, String payerFsp, String batchId); + + @Query(value = "SELECT SUM(bt.totalAmount) FROM Batch bt " + + "WHERE bt.startedAt >= :dateFrom AND " + + "(bt.registeringInstitutionId LIKE :registeringInstitutionId) AND (bt.payerFsp LIKE :payerFsp) AND " + + "bt.batchId LIKE :batchId AND bt.subBatchId IS NULL") + Optional getTotalAmountDateFrom(Date dateFrom, String registeringInstitutionId, String payerFsp, String batchId); + + @Query(value = "SELECT SUM(bt.totalAmount) FROM Batch bt " + + "WHERE bt.startedAt <= :dateTo AND " + + "(bt.registeringInstitutionId LIKE :registeringInstitutionId) AND (bt.payerFsp LIKE :payerFsp) AND " + + "bt.batchId LIKE :batchId AND bt.subBatchId IS NULL") + Optional getTotalAmountDateTo(Date dateTo, String registeringInstitutionId, String payerFsp, String batchId); + + @Query(value = "SELECT SUM(bt.totalAmount) FROM Batch bt " + + "WHERE bt.startedAt BETWEEN :dateFrom AND :dateTo AND " + + "(bt.registeringInstitutionId LIKE :registeringInstitutionId) AND (bt.payerFsp LIKE :payerFsp) AND " + + "bt.batchId LIKE :batchId AND bt.subBatchId IS NULL") + Optional getTotalAmountDateBetween(Date dateFrom, Date dateTo, String registeringInstitutionId, String payerFsp, String batchId); + + @Query(value = "SELECT SUM(bt.approvedAmount) FROM Batch bt " + + "WHERE (bt.registeringInstitutionId LIKE :registeringInstitutionId) AND (bt.payerFsp LIKE :payerFsp) AND " + + "bt.batchId LIKE :batchId AND bt.subBatchId IS NULL") + Optional getTotalApprovedAmount(String registeringInstitutionId, String payerFsp, String batchId); + + @Query(value = "SELECT SUM(bt.approvedAmount) FROM Batch bt " + + "WHERE bt.startedAt >= :dateFrom AND " + + "(bt.registeringInstitutionId LIKE :registeringInstitutionId) AND (bt.payerFsp LIKE :payerFsp) AND " + + "bt.batchId LIKE :batchId AND bt.subBatchId IS NULL") + Optional getTotalApprovedAmountDateFrom(Date dateFrom, String registeringInstitutionId, String payerFsp, String batchId); + + @Query(value = "SELECT SUM(bt.approvedAmount) FROM Batch bt " + + "WHERE bt.startedAt <= :dateTo AND " + + "(bt.registeringInstitutionId LIKE :registeringInstitutionId) AND (bt.payerFsp LIKE :payerFsp) AND " + + "bt.batchId LIKE :batchId AND bt.subBatchId IS NULL") + Optional getTotalApprovedAmountDateTo(Date dateTo, String registeringInstitutionId, String payerFsp, String batchId); + + @Query(value = "SELECT SUM(bt.approvedAmount) FROM Batch bt " + + "WHERE bt.startedAt BETWEEN :dateFrom AND :dateTo AND " + + "(bt.registeringInstitutionId LIKE :registeringInstitutionId) AND (bt.payerFsp LIKE :payerFsp) AND " + + "bt.batchId LIKE :batchId AND bt.subBatchId IS NULL") + Optional getTotalApprovedAmountDateBetween(Date dateFrom, Date dateTo, String registeringInstitutionId, String payerFsp, String batchId); + + @Query(value = "SELECT SUM(bt.approvedCount) FROM Batch bt " + + "WHERE (bt.registeringInstitutionId LIKE :registeringInstitutionId) AND (bt.payerFsp LIKE :payerFsp) AND " + + "bt.batchId LIKE :batchId AND bt.subBatchId IS NULL") + Optional getTotalApprovedCount(String registeringInstitutionId, String payerFsp, String batchId); + + @Query(value = "SELECT SUM(bt.approvedCount) FROM Batch bt " + + "WHERE bt.startedAt >= :dateFrom AND " + + "(bt.registeringInstitutionId LIKE :registeringInstitutionId) AND (bt.payerFsp LIKE :payerFsp) AND " + + "bt.batchId LIKE :batchId AND bt.subBatchId IS NULL") + Optional getTotalApprovedCountDateFrom(Date dateFrom, String registeringInstitutionId, String payerFsp, String batchId); + + @Query(value = "SELECT SUM(bt.approvedCount) FROM Batch bt " + + "WHERE bt.startedAt <= :dateTo AND " + + "(bt.registeringInstitutionId LIKE :registeringInstitutionId) AND (bt.payerFsp LIKE :payerFsp) AND " + + "bt.batchId LIKE :batchId AND bt.subBatchId IS NULL") + Optional getTotalApprovedCountDateTo(Date dateTo, String registeringInstitutionId, String payerFsp, String batchId); + + @Query(value = "SELECT SUM(bt.approvedCount) FROM Batch bt " + + "WHERE bt.startedAt BETWEEN :dateFrom AND :dateTo AND " + + "(bt.registeringInstitutionId LIKE :registeringInstitutionId) AND (bt.payerFsp LIKE :payerFsp) AND " + + "bt.batchId LIKE :batchId AND bt.subBatchId IS NULL") + Optional getTotalApprovedCountDateBetween(Date dateFrom, Date dateTo, String registeringInstitutionId, String payerFsp, String batchId); +} diff --git a/ph-ee-operations-app/src/main/java/org/apache/fineract/operations/BatchSpecs.java b/ph-ee-operations-app/src/main/java/org/apache/fineract/operations/BatchSpecs.java new file mode 100644 index 000000000..88eee90b2 --- /dev/null +++ b/ph-ee-operations-app/src/main/java/org/apache/fineract/operations/BatchSpecs.java @@ -0,0 +1,30 @@ +package org.apache.fineract.operations; + +import org.springframework.data.jpa.domain.Specifications; + +import javax.persistence.metamodel.SingularAttribute; +import java.util.Date; + +import static org.springframework.data.jpa.domain.Specifications.where; + +public class BatchSpecs { + + public static Specifications match(SingularAttribute attribute, T input) { + return where((root, query, builder) -> builder.equal(root.get(attribute), input)); + } + + public static Specifications between(SingularAttribute attribute, Date from, Date to) { + return where((root, query, builder) -> builder.and( + builder.greaterThanOrEqualTo(root.get(attribute), from), + builder.lessThanOrEqualTo(root.get(attribute), to) + )); + } + + public static Specifications later(SingularAttribute attribute, Date from) { + return where((root, query, builder) -> builder.greaterThanOrEqualTo(root.get(attribute), from)); + } + + public static Specifications earlier(SingularAttribute attribute, Date to) { + return where((root, query, builder) -> builder.lessThanOrEqualTo(root.get(attribute), to)); + } +} diff --git a/ph-ee-operations-app/src/main/java/org/apache/fineract/operations/BatchStatus.java b/ph-ee-operations-app/src/main/java/org/apache/fineract/operations/BatchStatus.java new file mode 100644 index 000000000..74537d053 --- /dev/null +++ b/ph-ee-operations-app/src/main/java/org/apache/fineract/operations/BatchStatus.java @@ -0,0 +1,9 @@ +package org.apache.fineract.operations; + +public enum BatchStatus { + COMPLETED, + FAILED, + IN_PROGRESS, + UNKNOWN, + EXCEPTION +} diff --git a/ph-ee-operations-app/src/main/java/org/apache/fineract/operations/Beneficiary.java b/ph-ee-operations-app/src/main/java/org/apache/fineract/operations/Beneficiary.java new file mode 100644 index 000000000..167c732bb --- /dev/null +++ b/ph-ee-operations-app/src/main/java/org/apache/fineract/operations/Beneficiary.java @@ -0,0 +1,88 @@ +package org.apache.fineract.operations; + +import com.fasterxml.jackson.annotation.JsonInclude; +import org.apache.fineract.organisation.parent.AbstractPersistableCustom; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.Table; + +@JsonInclude(JsonInclude.Include.NON_NULL) +@Entity +@Table(name = "m_beneficiary") +public class Beneficiary extends AbstractPersistableCustom { + @Column(name = "c_identifier") + private String custIdentifier; + + @Column(name = "b_identifier") + private String identifier; + + @Column(name = "b_name") + private String name; + + @Column(name = "b_nick_name") + private String nickName; + + @Column(name = "b_account_no") + private String accountNo; + + @Column(name = "b_leId") + private String leId; + + @Column(name = "b_currency_code") + private String currencyCode; + + @Column(name = "b_country_code") + private String countryCode; + + public Beneficiary() { + } + + public Beneficiary(String custIdentifier, String identifier, String name, String nickName, String accountNo, + String leId, String currencyCode, String countryCode) { + this.custIdentifier = custIdentifier; + this.identifier = identifier; + this.name = name; + this.nickName = nickName; + this.accountNo = accountNo; + this.leId = leId; + this.currencyCode = currencyCode; + this.countryCode = countryCode; + } + + public String getCustIdentifier() { + return custIdentifier; + } + + public String getIdentifier() { + return identifier; + } + + public String getName() { + return name; + } + + public String getNickName() { + return nickName; + } + + public String getAccountNo() { + return accountNo; + } + + public String getLeId() { + return leId; + } + + public String getCurrencyCode() { + return currencyCode; + } + + public String getCountryCode() { + return countryCode; + } + + public void removeId(){ + super.setId(null); + } +} diff --git a/ph-ee-operations-app/src/main/java/org/apache/fineract/operations/BeneficiaryRepository.java b/ph-ee-operations-app/src/main/java/org/apache/fineract/operations/BeneficiaryRepository.java new file mode 100644 index 000000000..1ec6357c5 --- /dev/null +++ b/ph-ee-operations-app/src/main/java/org/apache/fineract/operations/BeneficiaryRepository.java @@ -0,0 +1,12 @@ +package org.apache.fineract.operations; + +import org.springframework.data.repository.CrudRepository; + +import java.util.List; + +public interface BeneficiaryRepository extends CrudRepository { + + List findBycustIdentifier(String custIdentifier); + + Beneficiary findOneByCustIdentifierAndIdentifier(String custIdentifier, String identifier); +} diff --git a/ph-ee-operations-app/src/main/java/org/apache/fineract/operations/BusinessKey.java b/ph-ee-operations-app/src/main/java/org/apache/fineract/operations/BusinessKey.java new file mode 100644 index 000000000..45db7ebda --- /dev/null +++ b/ph-ee-operations-app/src/main/java/org/apache/fineract/operations/BusinessKey.java @@ -0,0 +1,61 @@ +package org.apache.fineract.operations; + + +import org.apache.fineract.organisation.parent.AbstractPersistableCustom; +import org.eclipse.persistence.annotations.Index; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.Table; + +@Entity +@Table(name = "businesskeys") +public class BusinessKey extends AbstractPersistableCustom { + + @Column(name = "BUSINESS_KEY") + @Index(name = "idx_businessKey") + private String businessKey; + + @Column(name = "BUSINESS_KEY_TYPE") + @Index(name = "idx_businessKeyType") + private String businessKeyType; + + @Column(name = "WORKFLOW_INSTANCE_KEY") + @Index(name = "idx_workflowInstanceKey") + private Long workflowInstanceKey; + + @Column(name = "TIMESTAMP") + private Long timestamp; + + public String getBusinessKeyType() { + return businessKeyType; + } + + public void setBusinessKeyType(String businessKeyType) { + this.businessKeyType = businessKeyType; + } + + public Long getWorkflowInstanceKey() { + return workflowInstanceKey; + } + + public void setWorkflowInstanceKey(Long workflowInstanceKey) { + this.workflowInstanceKey = workflowInstanceKey; + } + + public Long getTimestamp() { + return timestamp; + } + + public void setTimestamp(Long timestamp) { + this.timestamp = timestamp; + } + + public String getBusinessKey() { + return businessKey; + } + + public void setBusinessKey(String transactionId) { + this.businessKey = transactionId; + } +} diff --git a/ph-ee-operations-app/src/main/java/org/apache/fineract/operations/BusinessKeyRepository.java b/ph-ee-operations-app/src/main/java/org/apache/fineract/operations/BusinessKeyRepository.java new file mode 100644 index 000000000..40a80b930 --- /dev/null +++ b/ph-ee-operations-app/src/main/java/org/apache/fineract/operations/BusinessKeyRepository.java @@ -0,0 +1,11 @@ +package org.apache.fineract.operations; + +import org.springframework.data.repository.CrudRepository; + +import java.util.List; + +public interface BusinessKeyRepository extends CrudRepository { + + List findByBusinessKeyAndBusinessKeyType(String businessKey, String businessKeyType); + +} diff --git a/ph-ee-operations-app/src/main/java/org/apache/fineract/operations/CurrencyRate.java b/ph-ee-operations-app/src/main/java/org/apache/fineract/operations/CurrencyRate.java new file mode 100644 index 000000000..fa2a19380 --- /dev/null +++ b/ph-ee-operations-app/src/main/java/org/apache/fineract/operations/CurrencyRate.java @@ -0,0 +1,54 @@ +package org.apache.fineract.operations; + +import org.apache.fineract.organisation.parent.AbstractPersistableCustom; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.Table; +import javax.persistence.Temporal; +import javax.persistence.TemporalType; +import java.math.BigDecimal; +import java.util.Date; + +@Entity +@Table(name = "m_currency_rates") +public class CurrencyRate extends AbstractPersistableCustom { + @Column(name = "from_currency") + private String fromCurrency; + + @Column(name = "to_currency") + private String toCurrency; + + @Column(name = "rate") + private BigDecimal rate; + + @Column(name = "last_updated") + @Temporal(TemporalType.TIMESTAMP) + private Date lastUpdated; + + public CurrencyRate(String fromCurrency, String toCurrency, BigDecimal rate, Date lastUpdated) { + this.fromCurrency = fromCurrency; + this.toCurrency = toCurrency; + this.rate = rate; + this.lastUpdated = lastUpdated; + } + + public CurrencyRate() { + } + + public BigDecimal getRate() { + return rate; + } + + public void setRate(BigDecimal rate) { + this.rate = rate; + } + + public void setLastUpdated(Date lastUpdated) { + this.lastUpdated = lastUpdated; + } + + public CurrencyRateLock getLock(String uniqueKey, Date expireBy) { + return new CurrencyRateLock(uniqueKey, fromCurrency, toCurrency, rate, expireBy); + } +} diff --git a/ph-ee-operations-app/src/main/java/org/apache/fineract/operations/CurrencyRateLock.java b/ph-ee-operations-app/src/main/java/org/apache/fineract/operations/CurrencyRateLock.java new file mode 100644 index 000000000..0dfcaaa02 --- /dev/null +++ b/ph-ee-operations-app/src/main/java/org/apache/fineract/operations/CurrencyRateLock.java @@ -0,0 +1,59 @@ +package org.apache.fineract.operations; + +import org.apache.fineract.organisation.parent.AbstractPersistableCustom; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.Table; +import javax.persistence.Temporal; +import javax.persistence.TemporalType; +import java.math.BigDecimal; +import java.util.Date; + +@Entity +@Table(name = "m_currency_rates_lock") +public class CurrencyRateLock extends AbstractPersistableCustom { + + @Column(name = "unique_key") + private String uniqueKey; + + @Column(name = "from_currency") + private String fromCurrency; + + @Column(name = "to_currency") + private String toCurrency; + + @Column(name = "rate") + private BigDecimal rate; + + @Column(name = "expire_by") + @Temporal(TemporalType.TIMESTAMP) + private Date expireBy; + + public CurrencyRateLock() { + } + + public CurrencyRateLock(String uniqueKey, String fromCurrency, String toCurrency, BigDecimal rate, Date expireBy) { + this.uniqueKey = uniqueKey; + this.fromCurrency = fromCurrency; + this.toCurrency = toCurrency; + this.rate = rate; + this.expireBy = expireBy; + } + + public boolean isExpiredAtDate(Date date){ + return expireBy.before(date); + } + + public BigDecimal getRate() { + return rate; + } + + public Date getExpireBy() { + return expireBy; + } + + public void setExpireBy(Date expireBy) { + this.expireBy = expireBy; + } +} diff --git a/ph-ee-operations-app/src/main/java/org/apache/fineract/operations/CurrencyRateLockRepository.java b/ph-ee-operations-app/src/main/java/org/apache/fineract/operations/CurrencyRateLockRepository.java new file mode 100644 index 000000000..bcd31b53f --- /dev/null +++ b/ph-ee-operations-app/src/main/java/org/apache/fineract/operations/CurrencyRateLockRepository.java @@ -0,0 +1,16 @@ +package org.apache.fineract.operations; + +import org.springframework.data.jpa.repository.Modifying; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.CrudRepository; +import org.springframework.data.repository.query.Param; + +import java.util.Date; + +public interface CurrencyRateLockRepository extends CrudRepository { + CurrencyRateLock findOneByUniqueKey(String uniqueKey); + + @Modifying + @Query("delete from CurrencyRateLock c where c.expireBy=:timeStamp") + void deleteBooks(@Param("timeStamp") Date timeStamp); +} diff --git a/ph-ee-operations-app/src/main/java/org/apache/fineract/operations/CurrencyRateRepository.java b/ph-ee-operations-app/src/main/java/org/apache/fineract/operations/CurrencyRateRepository.java new file mode 100644 index 000000000..5cb67eb48 --- /dev/null +++ b/ph-ee-operations-app/src/main/java/org/apache/fineract/operations/CurrencyRateRepository.java @@ -0,0 +1,8 @@ +package org.apache.fineract.operations; + +import org.springframework.data.repository.CrudRepository; + +public interface CurrencyRateRepository extends CrudRepository { + + CurrencyRate findOneByFromCurrencyAndToCurrency(String fromCurrency, String toCurrency); +} diff --git a/ph-ee-operations-app/src/main/java/org/apache/fineract/operations/ErrorCode.java b/ph-ee-operations-app/src/main/java/org/apache/fineract/operations/ErrorCode.java new file mode 100644 index 000000000..a615eae42 --- /dev/null +++ b/ph-ee-operations-app/src/main/java/org/apache/fineract/operations/ErrorCode.java @@ -0,0 +1,56 @@ +package org.apache.fineract.operations; + +import org.apache.fineract.organisation.parent.AbstractPersistableCustom; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.Table; + +@Entity +@Table(name = "errorcode") +public class ErrorCode extends AbstractPersistableCustom { + + @Column(name = "TRANSACTION_TYPE") + String transactionType; + + @Column(name = "ERROR_MESSAGE") + String errorMessage; + + @Column(name = "ERROR_CODE") + String errorCode; + + @Column(name = "RECOVERABLE") + boolean recoverable; + + public String getTransactionType() { + return transactionType; + } + + public void setTransactionType(String transactionType) { + this.transactionType = transactionType; + } + + public String getErrorMessage() { + return errorMessage; + } + + public void setErrorMessage(String errorMessage) { + this.errorMessage = errorMessage; + } + + public String getErrorCode() { + return errorCode; + } + + public void setErrorCode(String errorCode) { + this.errorCode = errorCode; + } + + public boolean isRecoverable() { + return recoverable; + } + + public void setRecoverable(boolean recoverable) { + this.recoverable = recoverable; + } +} diff --git a/ph-ee-operations-app/src/main/java/org/apache/fineract/operations/ErrorCodeRepository.java b/ph-ee-operations-app/src/main/java/org/apache/fineract/operations/ErrorCodeRepository.java new file mode 100644 index 000000000..34212dbf2 --- /dev/null +++ b/ph-ee-operations-app/src/main/java/org/apache/fineract/operations/ErrorCodeRepository.java @@ -0,0 +1,20 @@ +package org.apache.fineract.operations; + +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.CrudRepository; +import org.springframework.data.repository.query.Param; + +import java.util.List; + +public interface ErrorCodeRepository extends CrudRepository { + + @Query(value = "select e from ErrorCode e where e.errorCode = :code") + List getErrorCodesByErrorCode(@Param("code") String code); + + @Query(value = "select e from ErrorCode e where e.recoverable = :recoverable") + List getErrorCodesByRecoverable(@Param("recoverable") boolean code); + + @Query(value = "select e from ErrorCode e where e.transactionType = :transactionType") + List getErrorCodesByTransactionType(@Param("transactionType") String transactionType); + +} diff --git a/ph-ee-operations-app/src/main/java/org/apache/fineract/operations/Filter.java b/ph-ee-operations-app/src/main/java/org/apache/fineract/operations/Filter.java new file mode 100644 index 000000000..e8c8184a3 --- /dev/null +++ b/ph-ee-operations-app/src/main/java/org/apache/fineract/operations/Filter.java @@ -0,0 +1,12 @@ +package org.apache.fineract.operations; + +public enum Filter { + TRANSACTIONID, + PAYERID, + PAYEEID, + EXTERNALID, + WORKFLOWINSTANCEKEY, + STATE, + CLIENTCORRELATIONID, + ERRORDESCRIPTION +} diff --git a/ph-ee-operations-app/src/main/java/org/apache/fineract/operations/Instruction.java b/ph-ee-operations-app/src/main/java/org/apache/fineract/operations/Instruction.java new file mode 100644 index 000000000..5f2fb7ba3 --- /dev/null +++ b/ph-ee-operations-app/src/main/java/org/apache/fineract/operations/Instruction.java @@ -0,0 +1,21 @@ +package org.apache.fineract.operations; + +import lombok.Getter; +import lombok.Setter; + +import java.math.BigDecimal; +import java.util.Date; + +@Getter +@Setter +public class Instruction { + private String instructionId; + private String payerFsp; + private String payeeFunctionalId; + private BigDecimal amount; + private TransferStatus status; + private String reason; + private Date startedAt; + private Date completedAt; + private String subBatchId; +} \ No newline at end of file diff --git a/ph-ee-operations-app/src/main/java/org/apache/fineract/operations/PaymentBatchDetail.java b/ph-ee-operations-app/src/main/java/org/apache/fineract/operations/PaymentBatchDetail.java new file mode 100644 index 000000000..3267ef16a --- /dev/null +++ b/ph-ee-operations-app/src/main/java/org/apache/fineract/operations/PaymentBatchDetail.java @@ -0,0 +1,35 @@ +package org.apache.fineract.operations; + +import lombok.Getter; +import lombok.Setter; +import org.apache.fineract.response.SubBatchSummary; + +import java.math.BigDecimal; +import java.util.Date; +import java.util.List; + +@Getter +@Setter +public class PaymentBatchDetail { + private String batchId; + private String payerFsp; + private String reportGeneratedBy; + private String reportGeneratedAt; + private Date startedAt; + private Date completedAt; + private String registeringInstitutionId; + private String status; + private List subBatchList; + private List instructionList; + private Long total; + private Long ongoing; + private Long successful; + private Long failed; + private BigDecimal totalAmount; + private BigDecimal pendingAmount; + private BigDecimal successfulAmount; + private BigDecimal failedAmount; + private Long totalInstruction; + private Long totalBatchAmount; + private String clientCorrelationId; +} \ No newline at end of file diff --git a/ph-ee-operations-app/src/main/java/org/apache/fineract/operations/SubBatch.java b/ph-ee-operations-app/src/main/java/org/apache/fineract/operations/SubBatch.java new file mode 100644 index 000000000..6ee6a6965 --- /dev/null +++ b/ph-ee-operations-app/src/main/java/org/apache/fineract/operations/SubBatch.java @@ -0,0 +1,12 @@ +package org.apache.fineract.operations; + +public class SubBatch { + private String subBatchId; + private String payerFSP; + private String payeeFSPSet; + private int totalRecordsInBatch; + private double totalAmountOfBatch; + private int totalPaymentsApprovedByPayerFSP; + private double totalAmountApprovedByPayerFSP; + +} diff --git a/ph-ee-operations-app/src/main/java/org/apache/fineract/operations/SubBatchSummaryDTO.java b/ph-ee-operations-app/src/main/java/org/apache/fineract/operations/SubBatchSummaryDTO.java new file mode 100644 index 000000000..9c7003ec8 --- /dev/null +++ b/ph-ee-operations-app/src/main/java/org/apache/fineract/operations/SubBatchSummaryDTO.java @@ -0,0 +1,19 @@ +package org.apache.fineract.operations; + +import java.util.Date; +import java.util.List; + +public class SubBatchSummaryDTO { + private String batchId; + private String xCorrelationId; + private String payerFSP; + private Date reportGeneratedAt; + private String reportGeneratedBy; + private List subBatchList; + private int totalNumberOfSubBatches; + private int totalNumberOfInstructionsInSubBatch; + private double totalAmountInSubBatch; + private int totalApprovedPaymentsInSubBatch; + private double totalApprovedAmountInSubBatch; + +} diff --git a/ph-ee-operations-app/src/main/java/org/apache/fineract/operations/Task.java b/ph-ee-operations-app/src/main/java/org/apache/fineract/operations/Task.java new file mode 100644 index 000000000..8622ddcc8 --- /dev/null +++ b/ph-ee-operations-app/src/main/java/org/apache/fineract/operations/Task.java @@ -0,0 +1,84 @@ +package org.apache.fineract.operations; + + +import org.apache.fineract.organisation.parent.AbstractPersistableCustom; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.Table; + +@Entity +@Table(name = "tasks") +public class Task extends AbstractPersistableCustom { + + @Column(name = "WORKFLOW_KEY") + private Long workflowKey; + @Column(name = "WORKFLOW_INSTANCE_KEY") + private Long workflowInstanceKey; + @Column(name = "TIMESTAMP") + private Long timestamp; + @Column(name = "INTENT") + private String intent; + @Column(name = "RECORD_TYPE") + private String recordType; + @Column(name = "TYPE") + private String type; + @Column(name = "ELEMENT_ID") + private String elementId; + + public Long getTimestamp() { + return timestamp; + } + + public void setTimestamp(Long timestamp) { + this.timestamp = timestamp; + } + + public Long getWorkflowKey() { + return workflowKey; + } + + public void setWorkflowKey(Long workflowKey) { + this.workflowKey = workflowKey; + } + + public Long getWorkflowInstanceKey() { + return workflowInstanceKey; + } + + public void setWorkflowInstanceKey(Long workflowInstanceKey) { + this.workflowInstanceKey = workflowInstanceKey; + } + + public String getIntent() { + return intent; + } + + public void setIntent(String intent) { + this.intent = intent; + } + + public String getRecordType() { + return recordType; + } + + public void setRecordType(String recordType) { + this.recordType = recordType; + } + + public String getType() { + return type; + } + + public String getElementId() { + return elementId; + } + + public void setElementId(String elementId) { + this.elementId = elementId; + } + + public void setType(String type) { + this.type = type; + } +} diff --git a/ph-ee-operations-app/src/main/java/org/apache/fineract/operations/TaskRepository.java b/ph-ee-operations-app/src/main/java/org/apache/fineract/operations/TaskRepository.java new file mode 100644 index 000000000..4a6afc23a --- /dev/null +++ b/ph-ee-operations-app/src/main/java/org/apache/fineract/operations/TaskRepository.java @@ -0,0 +1,11 @@ +package org.apache.fineract.operations; + +import org.springframework.data.repository.CrudRepository; + +import java.util.List; + +public interface TaskRepository extends CrudRepository { + + List findByWorkflowInstanceKeyOrderByTimestamp(Long workflowInstanceKey); + +} diff --git a/ph-ee-operations-app/src/main/java/org/apache/fineract/operations/TransactionRequest.java b/ph-ee-operations-app/src/main/java/org/apache/fineract/operations/TransactionRequest.java new file mode 100644 index 000000000..36c96c0d8 --- /dev/null +++ b/ph-ee-operations-app/src/main/java/org/apache/fineract/operations/TransactionRequest.java @@ -0,0 +1,335 @@ +package org.apache.fineract.operations; + + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonManagedReference; +import org.apache.fineract.organisation.parent.AbstractPersistableCustom; + +import javax.persistence.CascadeType; +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.EnumType; +import javax.persistence.Enumerated; +import javax.persistence.FetchType; +import javax.persistence.OneToMany; +import javax.persistence.Table; +import java.math.BigDecimal; +import java.util.Date; +import java.util.List; + +import static org.apache.fineract.operations.TransactionRequestState.IN_PROGRESS; + + +@Entity +@Table(name = "transaction_requests") +public class TransactionRequest extends AbstractPersistableCustom { + + @Column(name = "WORKFLOW_INSTANCE_KEY") + private String workflowInstanceKey; + + @Column(name = "TRANSACTION_ID") + private String transactionId; + + @Column(name = "STARTED_AT") + private Date startedAt; + + @Column(name = "COMPLETED_AT") + private Date completedAt; + + @Enumerated(EnumType.STRING) + @Column(name = "STATE") + private TransactionRequestState state; + + @Column(name = "PAYEE_DFSP_ID") + private String payeeDfspId; + @Column(name = "PAYEE_PARTY_ID") + private String payeePartyId; + @Column(name = "PAYEE_PARTY_ID_TYPE") + private String payeePartyIdType; + @Column(name = "PAYEE_FEE") + private BigDecimal payeeFee; + @Column(name = "PAYEE_QUOTE_CODE") + private String payeeQuoteCode; + + @Column(name = "PAYER_DFSP_ID") + private String payerDfspId; + @Column(name = "PAYER_PARTY_ID") + private String payerPartyId; + @Column(name = "PAYER_PARTY_ID_TYPE") + private String payerPartyIdType; + @Column(name = "PAYER_FEE") + private BigDecimal payerFee; + @Column(name = "PAYER_QUOTE_CODE") + private String payerQuoteCode; + + @Column(name = "AMOUNT") + private BigDecimal amount; + + @Column(name = "CURRENCY") + private String currency; + + @Column(name = "DIRECTION") + private String direction; + + @Column(name = "AUTH_TYPE") + private String authType; + + @Column(name = "INITIATOR_TYPE") + private String initiatorType; + + @Column(name = "SCENARIO") + private String scenario; + + @Column(name = "EXTERNAL_ID") + private String externalId; + + @Column(name = "CLIENTCORRELATIONID") + private String clientCorrelationId; + + @Column(name = "ERROR_INFORMATION") + private String errorInformation; + + @OneToMany(cascade = CascadeType.ALL, mappedBy = "transactionRequest", fetch = FetchType.LAZY) + private List variables; + + @JsonIgnore + @JsonManagedReference + public List getVariables() { + return variables; + } + + public void setVariables(List variables) { + this.variables = variables; + } + + public TransactionRequest() { + } + + public String getExternalId() { + return externalId; + } + + public void setExternalId(String externalId) { + this.externalId = externalId; + } + + public TransactionRequest(String workflowInstanceKey) { + this.workflowInstanceKey = workflowInstanceKey; + this.state = IN_PROGRESS; + } + + public String getWorkflowInstanceKey() { + return workflowInstanceKey; + } + + public void setWorkflowInstanceKey(String workflowInstanceKey) { + this.workflowInstanceKey = workflowInstanceKey; + } + + public String getTransactionId() { + return transactionId; + } + + public void setTransactionId(String transactionId) { + this.transactionId = transactionId; + } + + public Date getStartedAt() { + return startedAt; + } + + public void setStartedAt(Date startedAt) { + this.startedAt = startedAt; + } + + public Date getCompletedAt() { + return completedAt; + } + + public void setCompletedAt(Date completedAt) { + this.completedAt = completedAt; + } + + public TransactionRequestState getState() { + return state; + } + + public void setState(TransactionRequestState state) { + this.state = state; + } + + public String getPayeeDfspId() { + return payeeDfspId; + } + + public void setPayeeDfspId(String payeeDfspId) { + this.payeeDfspId = payeeDfspId; + } + + public String getPayeePartyId() { + return payeePartyId; + } + + public void setPayeePartyId(String payeePartyId) { + this.payeePartyId = payeePartyId; + } + + public String getPayeePartyIdType() { + return payeePartyIdType; + } + + public void setPayeePartyIdType(String payeePartyIdType) { + this.payeePartyIdType = payeePartyIdType; + } + + public BigDecimal getPayeeFee() { + return payeeFee; + } + + public void setPayeeFee(BigDecimal payeeFee) { + this.payeeFee = payeeFee; + } + + public String getPayeeQuoteCode() { + return payeeQuoteCode; + } + + public void setPayeeQuoteCode(String payeeQuoteCode) { + this.payeeQuoteCode = payeeQuoteCode; + } + + public String getPayerDfspId() { + return payerDfspId; + } + + public void setPayerDfspId(String payerDfspId) { + this.payerDfspId = payerDfspId; + } + + public String getPayerPartyId() { + return payerPartyId; + } + + public void setPayerPartyId(String payerPartyId) { + this.payerPartyId = payerPartyId; + } + + public String getPayerPartyIdType() { + return payerPartyIdType; + } + + public void setPayerPartyIdType(String payerPartyIdType) { + this.payerPartyIdType = payerPartyIdType; + } + + public BigDecimal getPayerFee() { + return payerFee; + } + + public void setPayerFee(BigDecimal payerFee) { + this.payerFee = payerFee; + } + + public String getPayerQuoteCode() { + return payerQuoteCode; + } + + public void setPayerQuoteCode(String payerQuoteCode) { + this.payerQuoteCode = payerQuoteCode; + } + + public BigDecimal getAmount() { + return amount; + } + + public void setAmount(BigDecimal amount) { + this.amount = amount; + } + + public String getCurrency() { + return currency; + } + + public void setCurrency(String currency) { + this.currency = currency; + } + + public String getDirection() { + return direction; + } + + public void setDirection(String direction) { + this.direction = direction; + } + + public String getAuthType() { + return authType; + } + + public void setAuthType(String authType) { + this.authType = authType; + } + + public String getInitiatorType() { + return initiatorType; + } + + public void setInitiatorType(String initiatorType) { + this.initiatorType = initiatorType; + } + + public String getScenario() { + return scenario; + } + + public void setScenario(String scenario) { + this.scenario = scenario; + } + + public String getClientCorrelationId() { + return clientCorrelationId; + } + + public void setClientCorrelationId(String clientCorrelationId) { + this.clientCorrelationId = clientCorrelationId; + } + + public String getErrorInformation() { + return errorInformation; + } + + public void setErrorInformation(String errorInformation) { + this.errorInformation = errorInformation; + } + + @Override + public String toString() { + return "TransactionRequest{" + + "workflowInstanceKey='" + workflowInstanceKey + '\'' + + ", transactionId='" + transactionId + '\'' + + ", startedAt=" + startedAt + + ", completedAt=" + completedAt + + ", state=" + state + + ", payeeDfspId='" + payeeDfspId + '\'' + + ", payeePartyId='" + payeePartyId + '\'' + + ", payeePartyIdType='" + payeePartyIdType + '\'' + + ", payeeFee=" + payeeFee + + ", payeeQuoteCode='" + payeeQuoteCode + '\'' + + ", payerDfspId='" + payerDfspId + '\'' + + ", payerPartyId='" + payerPartyId + '\'' + + ", payerPartyIdType='" + payerPartyIdType + '\'' + + ", payerFee=" + payerFee + + ", payerQuoteCode='" + payerQuoteCode + '\'' + + ", amount=" + amount + + ", currency='" + currency + '\'' + + ", direction='" + direction + '\'' + + ", authType='" + authType + '\'' + + ", initiatorType='" + initiatorType + '\'' + + ", scenario='" + scenario + '\'' + + ", externalId='" + externalId + '\'' + + ", clientCorrelationId='" + clientCorrelationId + '\'' + + ", errorInformation='" + errorInformation + '\'' + + ", variables=" + variables + + '}'; + } +} diff --git a/ph-ee-operations-app/src/main/java/org/apache/fineract/operations/TransactionRequestDetail.java b/ph-ee-operations-app/src/main/java/org/apache/fineract/operations/TransactionRequestDetail.java new file mode 100644 index 000000000..cfe38de97 --- /dev/null +++ b/ph-ee-operations-app/src/main/java/org/apache/fineract/operations/TransactionRequestDetail.java @@ -0,0 +1,40 @@ +package org.apache.fineract.operations; + +import java.util.List; + + +public class TransactionRequestDetail { + private TransactionRequest transactionRequest; + private List tasks; + private List variables; + + public TransactionRequestDetail(TransactionRequest transactionRequest, List tasks, List variables) { + this.transactionRequest = transactionRequest; + this.tasks = tasks; + this.variables = variables; + } + + public TransactionRequest getTransactionRequest() { + return transactionRequest; + } + + public void setTransactionRequest(TransactionRequest transactionRequest) { + this.transactionRequest = transactionRequest; + } + + public List getTasks() { + return tasks; + } + + public void setTasks(List tasks) { + this.tasks = tasks; + } + + public List getVariables() { + return variables; + } + + public void setVariables(List variables) { + this.variables = variables; + } +} diff --git a/ph-ee-operations-app/src/main/java/org/apache/fineract/operations/TransactionRequestRepository.java b/ph-ee-operations-app/src/main/java/org/apache/fineract/operations/TransactionRequestRepository.java new file mode 100644 index 000000000..8bf8d4d99 --- /dev/null +++ b/ph-ee-operations-app/src/main/java/org/apache/fineract/operations/TransactionRequestRepository.java @@ -0,0 +1,21 @@ +package org.apache.fineract.operations; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; + +import java.util.List; +import java.util.Optional; + +public interface TransactionRequestRepository extends JpaRepository, JpaSpecificationExecutor { + + TransactionRequest findFirstByWorkflowInstanceKey(Long workflowInstanceKey); + +// @Deprecated(forRemoval = true) + @Query("SELECT tr FROM TransactionRequest tr INNER JOIN Variable v ON tr.workflowInstanceKey = v.workflowInstanceKey" + + " WHERE v.name=\"errorDescription\" and v.value IN :errorDescription") + List filterByErrorDescription(@Param("errorDescription") List errorDescription); + + Optional findFirstByTransactionId(String transactionId); +} diff --git a/ph-ee-operations-app/src/main/java/org/apache/fineract/operations/TransactionRequestSpecs.java b/ph-ee-operations-app/src/main/java/org/apache/fineract/operations/TransactionRequestSpecs.java new file mode 100644 index 000000000..0ba36b5ce --- /dev/null +++ b/ph-ee-operations-app/src/main/java/org/apache/fineract/operations/TransactionRequestSpecs.java @@ -0,0 +1,64 @@ +package org.apache.fineract.operations; + +import org.springframework.data.jpa.domain.Specifications; + +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.Join; +import javax.persistence.criteria.Path; +import javax.persistence.criteria.Predicate; +import javax.persistence.metamodel.SingularAttribute; +import java.util.Date; +import java.util.List; + +import static org.springframework.data.jpa.domain.Specifications.where; + +public class TransactionRequestSpecs { + + public static Specifications between(SingularAttribute attribute, Date from, Date to) { + return where((root, query, builder) -> builder.and( + builder.greaterThanOrEqualTo(root.get(attribute), from), + builder.lessThanOrEqualTo(root.get(attribute), to) + )); + } + + public static Specifications later(SingularAttribute attribute, Date from) { + return where((root, query, builder) -> builder.greaterThanOrEqualTo(root.get(attribute), from)); + } + + public static Specifications earlier(SingularAttribute attribute, Date to) { + return where((root, query, builder) -> builder.lessThanOrEqualTo(root.get(attribute), to)); + } + + + public static Specifications match(SingularAttribute attribute, T input) { + return where((root, query, builder) -> builder.equal(root.get(attribute), input)); + } + + public static Specifications in(SingularAttribute attribute, List inputs) { + return where(((root, query, cb) -> { + final Path group = root.get(attribute); + CriteriaBuilder.In cr = cb.in(group); + for(T input: inputs ) { + cr.value(input); + } + return cr; + })); + } + + public static Specifications filterByErrorDescription(List errorDescriptions) { + return where(((root, query, cb) -> { + Join txnVariables = root.join("variables"); + + Predicate a = cb.equal(txnVariables.get("name"), "errorDescription"); + + Path group = txnVariables.get("value"); + CriteriaBuilder.In cr = cb.in(group); + for(String errorDesc: errorDescriptions) { + cr.value(errorDesc); + } + + return cb.and(cr, a); + })); + } + +} diff --git a/ph-ee-operations-app/src/main/java/org/apache/fineract/operations/TransactionRequestState.java b/ph-ee-operations-app/src/main/java/org/apache/fineract/operations/TransactionRequestState.java new file mode 100644 index 000000000..d39f19050 --- /dev/null +++ b/ph-ee-operations-app/src/main/java/org/apache/fineract/operations/TransactionRequestState.java @@ -0,0 +1,6 @@ +package org.apache.fineract.operations; + +public enum TransactionRequestState { + + INITIATED, IN_PROGRESS, RECEIVED, REQUEST_ACCEPTED, ACCEPTED, REJECTED, FAILED, SUCCESS; +} \ No newline at end of file diff --git a/ph-ee-operations-app/src/main/java/org/apache/fineract/operations/Transfer.java b/ph-ee-operations-app/src/main/java/org/apache/fineract/operations/Transfer.java new file mode 100644 index 000000000..45a30e4f4 --- /dev/null +++ b/ph-ee-operations-app/src/main/java/org/apache/fineract/operations/Transfer.java @@ -0,0 +1,284 @@ +package org.apache.fineract.operations; + + +import com.fasterxml.jackson.annotation.JsonFormat; +import org.apache.fineract.organisation.parent.AbstractPersistableCustom; +import org.eclipse.persistence.annotations.Index; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.EnumType; +import javax.persistence.Enumerated; +import javax.persistence.Table; +import java.math.BigDecimal; +import java.util.Date; + +@Entity +@Table(name = "transfers") +public class Transfer extends AbstractPersistableCustom { + + @Column(name = "WORKFLOW_INSTANCE_KEY") + @Index(name = "idx_paymentProcessId") + @JsonFormat(shape = JsonFormat.Shape.STRING) + private Long workflowInstanceKey; + + @Column(name = "TRANSACTION_ID") + private String transactionId; + + @Column(name = "STARTED_AT") + private Date startedAt; + @Column(name = "COMPLETED_AT") + private Date completedAt; + + @Enumerated(EnumType.STRING) + private TransferStatus status; + + @Column(name = "STATUS_DETAIL") + private String statusDetail; + + @Column(name = "PAYEE_DFSP_ID") + private String payeeDfspId; + @Column(name = "PAYEE_PARTY_ID") + private String payeePartyId; + @Column(name = "PAYEE_PARTY_ID_TYPE") + private String payeePartyIdType; + @Column(name = "PAYEE_FEE") + private BigDecimal payeeFee; + @Column(name = "PAYEE_FEE_CURRENCY") + private String payeeFeeCurrency; + @Column(name = "PAYEE_QUOTE_CODE") + private String payeeQuoteCode; + + @Column(name = "PAYER_DFSP_ID") + private String payerDfspId; + @Column(name = "PAYER_PARTY_ID") + private String payerPartyId; + @Column(name = "PAYER_PARTY_ID_TYPE") + private String payerPartyIdType; + @Column(name = "PAYER_FEE") + private BigDecimal payerFee; + @Column(name = "PAYER_FEE_CURRENCY") + private String payerFeeCurrency; + @Column(name = "PAYER_QUOTE_CODE") + private String payerQuoteCode; + + @Column(name = "amount") + @JsonFormat(shape = JsonFormat.Shape.STRING) + private BigDecimal amount; + + @Column(name = "currency") + private String currency; + + @Column(name = "direction") + private String direction; + + @Column(name = "error_information") + private String errorInformation; + + @Column(name = "BATCH_ID") + private String batchId; + + @Column(name = "CLIENTCORRELATIONID") + private String clientCorrelationId; + + public Transfer() { + } + + public Transfer(Long workflowInstanceKey) { + this.workflowInstanceKey = workflowInstanceKey; + this.status = TransferStatus.IN_PROGRESS; + } + + public Date getCompletedAt() { + return completedAt; + } + + public void setCompletedAt(Date completedAt) { + this.completedAt = completedAt; + } + + public Date getStartedAt() { + return startedAt; + } + + public void setStartedAt(Date startedAt) { + this.startedAt = startedAt; + } + + public BigDecimal getPayeeFee() { + return payeeFee; + } + + public void setPayeeFee(BigDecimal payeeFee) { + this.payeeFee = payeeFee; + } + + public String getPayeeQuoteCode() { + return payeeQuoteCode; + } + + public void setPayeeQuoteCode(String payeeQuoteCode) { + this.payeeQuoteCode = payeeQuoteCode; + } + + public BigDecimal getPayerFee() { + return payerFee; + } + + public void setPayerFee(BigDecimal payerFee) { + this.payerFee = payerFee; + } + + public String getPayerQuoteCode() { + return payerQuoteCode; + } + + public void setPayerQuoteCode(String payerQuoteCode) { + this.payerQuoteCode = payerQuoteCode; + } + + public String getTransactionId() { + return transactionId; + } + + public void setTransactionId(String transactionId) { + this.transactionId = transactionId; + } + + public Long getWorkflowInstanceKey() { + return workflowInstanceKey; + } + + public void setWorkflowInstanceKey(Long paymentProcessId) { + this.workflowInstanceKey = paymentProcessId; + } + + public TransferStatus getStatus() { + return status; + } + + public void setStatus(TransferStatus status) { + this.status = status; + } + + public String getPayeePartyId() { + return payeePartyId; + } + + public void setPayeePartyId(String payeePartyId) { + this.payeePartyId = payeePartyId; + } + + public String getPayeePartyIdType() { + return payeePartyIdType; + } + + public void setPayeePartyIdType(String payeePartyType) { + this.payeePartyIdType = payeePartyType; + } + + public String getPayerPartyId() { + return payerPartyId; + } + + public void setPayerPartyId(String payerPartyId) { + this.payerPartyId = payerPartyId; + } + + public String getPayerPartyIdType() { + return payerPartyIdType; + } + + public void setPayerPartyIdType(String payerPartyType) { + this.payerPartyIdType = payerPartyType; + } + + public String getPayeeFeeCurrency() { + return payeeFeeCurrency; + } + + public void setPayeeFeeCurrency(String payeeFeeCurrency) { + this.payeeFeeCurrency = payeeFeeCurrency; + } + + public String getPayerFeeCurrency() { + return payerFeeCurrency; + } + + public void setPayerFeeCurrency(String payerFeeCurrency) { + this.payerFeeCurrency = payerFeeCurrency; + } + + public BigDecimal getAmount() { + return amount; + } + + public void setAmount(BigDecimal amount) { + this.amount = amount; + } + + public String getPayeeDfspId() { + return payeeDfspId; + } + + public void setPayeeDfspId(String payeeDfspId) { + this.payeeDfspId = payeeDfspId; + } + + public String getPayerDfspId() { + return payerDfspId; + } + + public void setPayerDfspId(String payerDfspId) { + this.payerDfspId = payerDfspId; + } + + public String getCurrency() { + return currency; + } + + public void setCurrency(String currency) { + this.currency = currency; + } + + public String getStatusDetail() { + return statusDetail; + } + + public void setStatusDetail(String statusDetail) { + this.statusDetail = statusDetail; + } + + public String getDirection() { + return direction; + } + + public void setDirection(String direction) { + this.direction = direction; + } + + public String getErrorInformation() { + return errorInformation; + } + + public void setErrorInformation(String errorInformation) { + this.errorInformation = errorInformation; + } + + public String getBatchId() { + return batchId; + } + + public void setBatchId(String batchId) { + this.batchId = batchId; + } + + public String getClientCorrelationId() { + return clientCorrelationId; + } + + public void setClientCorrelationId(String clientCorrelationId) { + this.clientCorrelationId = clientCorrelationId; + } + +} diff --git a/ph-ee-operations-app/src/main/java/org/apache/fineract/operations/TransferDetail.java b/ph-ee-operations-app/src/main/java/org/apache/fineract/operations/TransferDetail.java new file mode 100644 index 000000000..bf2303d8f --- /dev/null +++ b/ph-ee-operations-app/src/main/java/org/apache/fineract/operations/TransferDetail.java @@ -0,0 +1,40 @@ +package org.apache.fineract.operations; + +import java.util.List; + + +public class TransferDetail { + private Transfer transfer; + private List tasks; + private List variables; + + public TransferDetail(Transfer transfer, List tasks, List variables) { + this.transfer = transfer; + this.tasks = tasks; + this.variables = variables; + } + + public Transfer getTransfer() { + return transfer; + } + + public void setTransfer(Transfer transfer) { + this.transfer = transfer; + } + + public List getTasks() { + return tasks; + } + + public void setTasks(List tasks) { + this.tasks = tasks; + } + + public List getVariables() { + return variables; + } + + public void setVariables(List variables) { + this.variables = variables; + } +} diff --git a/ph-ee-operations-app/src/main/java/org/apache/fineract/operations/TransferRepository.java b/ph-ee-operations-app/src/main/java/org/apache/fineract/operations/TransferRepository.java new file mode 100644 index 000000000..253ebe8e7 --- /dev/null +++ b/ph-ee-operations-app/src/main/java/org/apache/fineract/operations/TransferRepository.java @@ -0,0 +1,32 @@ +package org.apache.fineract.operations; + +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; + +import java.util.List; +import java.util.Optional; + +public interface TransferRepository extends JpaRepository, JpaSpecificationExecutor { + + Transfer findFirstByWorkflowInstanceKey(Long workflowInstanceKey); + + Transfer findFirstByTransactionIdAndDirection(String transactionId, String direction); + + Optional findFirstByTransactionId(String transactionId); + + List findAllByBatchId(String batchId); + + Page findAllByBatchIdAndStatus(String batchId, String status, Pageable pageable); + + Page findAllByBatchId(String batchId, Pageable pageable); + Long countAllByBatchId(String batchId); + Page findAll(Pageable pageable); + @Query("SELECT t FROM Transfer t WHERE t.batchId IN (SELECT b.subBatchId FROM Batch b WHERE b.batchId = :batchId AND b.subBatchId IS NOT NULL)") + PagefindAllByBatchIdMatchSubBatchId(String batchId, Pageable pageable); + +} diff --git a/ph-ee-operations-app/src/main/java/org/apache/fineract/operations/TransferResponse.java b/ph-ee-operations-app/src/main/java/org/apache/fineract/operations/TransferResponse.java new file mode 100644 index 000000000..e689ad15c --- /dev/null +++ b/ph-ee-operations-app/src/main/java/org/apache/fineract/operations/TransferResponse.java @@ -0,0 +1,59 @@ +package org.apache.fineract.operations; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.Getter; +import lombok.Setter; +import org.apache.commons.lang3.StringEscapeUtils; +import org.mifos.connector.common.channel.dto.PhErrorDTO; + +import java.io.IOException; +import java.math.BigDecimal; +import java.util.Date; + +@Getter +@Setter +public class TransferResponse { + + private int id; + private Long workflowInstanceKey; + + private String transactionId; + + private Date startedAt; + private Date completedAt; + private TransferStatus status; + private String statusDetail; + private String payeeDfspId; + private String payeePartyId; + private String payeePartyIdType; + private BigDecimal payeeFee; + private String payeeFeeCurrency; + private String payeeQuoteCode; + private String payerDfspId; + private String payerPartyId; + private String payerPartyIdType; + private BigDecimal payerFee; + private String payerFeeCurrency; + private String payerQuoteCode; + @JsonFormat(shape = JsonFormat.Shape.STRING) + private BigDecimal amount; + private String currency; + private String direction; + private PhErrorDTO errorInformation; + private String batchId; + private String clientCorrelationId; + + public void parseErrorInformation(String json, ObjectMapper mapper) throws IOException { + try { + this.errorInformation = mapper.readValue(json, PhErrorDTO.class); + } catch (Exception e) { + try { + String formattedJson = StringEscapeUtils.unescapeJava(json); + this.errorInformation = mapper.readValue(formattedJson, PhErrorDTO.class); + } catch (Exception innerException) { + this.errorInformation = null; + } + } + } +} diff --git a/ph-ee-operations-app/src/main/java/org/apache/fineract/operations/TransferSpecs.java b/ph-ee-operations-app/src/main/java/org/apache/fineract/operations/TransferSpecs.java new file mode 100644 index 000000000..f9f655a28 --- /dev/null +++ b/ph-ee-operations-app/src/main/java/org/apache/fineract/operations/TransferSpecs.java @@ -0,0 +1,54 @@ +package org.apache.fineract.operations; + +import org.springframework.data.jpa.domain.Specifications; + +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.Path; +import javax.persistence.metamodel.SingularAttribute; +import java.util.Date; +import java.util.List; + +import static org.springframework.data.jpa.domain.Specifications.where; + +public class TransferSpecs { + + public static Specifications between(SingularAttribute attribute, Date from, Date to) { + return where((root, query, builder) -> builder.and( + builder.greaterThanOrEqualTo(root.get(attribute), from), + builder.lessThanOrEqualTo(root.get(attribute), to) + )); + } + + public static Specifications later(SingularAttribute attribute, Date from) { + return where((root, query, builder) -> builder.greaterThanOrEqualTo(root.get(attribute), from)); + } + + public static Specifications earlier(SingularAttribute attribute, Date to) { + return where((root, query, builder) -> builder.lessThanOrEqualTo(root.get(attribute), to)); + } + + + public static Specifications match(SingularAttribute attribute, T input) { + return where((root, query, builder) -> builder.equal(root.get(attribute), input)); + } + + public static Specifications multiMatch(SingularAttribute attribute1, SingularAttribute attribute2, T input) { + return where((root, query, builder) -> builder.or( + builder.equal(root.get(attribute1), input), + builder.equal(root.get(attribute2), input) + )); + } + + public static Specifications in(SingularAttribute attribute, + List inputs) { + return where(((root, query, cb) -> { + final Path group = root.get(attribute); + CriteriaBuilder.In cr = cb.in(group); + for (T input : inputs) { + cr.value(input); + } + return cr; + })); + } +} + diff --git a/ph-ee-operations-app/src/main/java/org/apache/fineract/operations/TransferStatus.java b/ph-ee-operations-app/src/main/java/org/apache/fineract/operations/TransferStatus.java new file mode 100644 index 000000000..a3d6169ae --- /dev/null +++ b/ph-ee-operations-app/src/main/java/org/apache/fineract/operations/TransferStatus.java @@ -0,0 +1,9 @@ +package org.apache.fineract.operations; + +public enum TransferStatus { + COMPLETED, + FAILED, + IN_PROGRESS, + UNKNOWN, + EXCEPTION +} diff --git a/ph-ee-operations-app/src/main/java/org/apache/fineract/operations/TransferStatusCheck.java b/ph-ee-operations-app/src/main/java/org/apache/fineract/operations/TransferStatusCheck.java new file mode 100644 index 000000000..7d2f7852a --- /dev/null +++ b/ph-ee-operations-app/src/main/java/org/apache/fineract/operations/TransferStatusCheck.java @@ -0,0 +1,37 @@ +package org.apache.fineract.operations; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; + +import java.math.BigDecimal; +import java.util.List; + +public class TransferStatusCheck { + + + @JsonProperty + List requestIds; + @JsonProperty + List payeePartyIds; + + public TransferStatusCheck() { + super(); + } + + public List getRequestIds() { + return requestIds; + } + + public void setRequestIds(List requestIds) { + this.requestIds = requestIds; + } + + public List getPayeePartyIds() { + return payeePartyIds; + } + + public void setPayeePartyIds(List payeePartyIds) { + this.payeePartyIds = payeePartyIds; + } +} + diff --git a/ph-ee-operations-app/src/main/java/org/apache/fineract/operations/Variable.java b/ph-ee-operations-app/src/main/java/org/apache/fineract/operations/Variable.java new file mode 100644 index 000000000..48938649d --- /dev/null +++ b/ph-ee-operations-app/src/main/java/org/apache/fineract/operations/Variable.java @@ -0,0 +1,89 @@ +package org.apache.fineract.operations; + + +import com.fasterxml.jackson.annotation.JsonBackReference; +import org.apache.fineract.organisation.parent.AbstractPersistableCustom; +import org.eclipse.persistence.annotations.Index; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.JoinColumn; +import javax.persistence.Lob; +import javax.persistence.ManyToOne; +import javax.persistence.Table; + +@Entity +@Table(name = "variables") +public class Variable extends AbstractPersistableCustom { + + @Column(name = "WORKFLOW_KEY") + private Long workflowKey; + + @Column(name = "WORKFLOW_INSTANCE_KEY") + @Index(name = "idx_workflowInstanceKey") + private Long workflowInstanceKey; + + @Column(name = "TIMESTAMP") + private Long timestamp; + + @Column(name = "NAME") + private String name; + + @Lob + @Column(name = "VALUE") + private String value; + + @JoinColumn(name = "WORKFLOW_INSTANCE_KEY", insertable=false, updatable=false, + referencedColumnName = "WORKFLOW_INSTANCE_KEY") + @ManyToOne() + private TransactionRequest transactionRequest; + + @JsonBackReference + public TransactionRequest getTransactionRequest() { + return transactionRequest; + } + + public void setTransactionRequest(TransactionRequest transactionRequest) { + this.transactionRequest = transactionRequest; + } + + public Long getWorkflowKey() { + return workflowKey; + } + + public void setWorkflowKey(Long workflowKey) { + this.workflowKey = workflowKey; + } + + public Long getWorkflowInstanceKey() { + return workflowInstanceKey; + } + + public void setWorkflowInstanceKey(Long workflowInstanceKey) { + this.workflowInstanceKey = workflowInstanceKey; + } + + public Long getTimestamp() { + return timestamp; + } + + public void setTimestamp(Long timestamp) { + this.timestamp = timestamp; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } +} diff --git a/ph-ee-operations-app/src/main/java/org/apache/fineract/operations/VariableRepository.java b/ph-ee-operations-app/src/main/java/org/apache/fineract/operations/VariableRepository.java new file mode 100644 index 000000000..539ae3f6e --- /dev/null +++ b/ph-ee-operations-app/src/main/java/org/apache/fineract/operations/VariableRepository.java @@ -0,0 +1,18 @@ +package org.apache.fineract.operations; + +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.CrudRepository; +import org.springframework.data.repository.query.Param; + +import java.util.List; +import java.util.Optional; + +public interface VariableRepository extends CrudRepository { + + List findByWorkflowInstanceKeyOrderByTimestamp(Long workflowInstanceKey); + + @Query("SELECT v from Variable v WHERE v.workflowInstanceKey=:workflowInstanceKey and v.name=:name") + Optional findByWorkflowInstanceKeyAndVariableName(@Param("name") String name, + @Param("workflowInstanceKey") Long workflowInstanceKey); + +} diff --git a/ph-ee-operations-app/src/main/java/org/apache/fineract/organisation/code/Code.java b/ph-ee-operations-app/src/main/java/org/apache/fineract/organisation/code/Code.java new file mode 100644 index 000000000..5a95d5ce0 --- /dev/null +++ b/ph-ee-operations-app/src/main/java/org/apache/fineract/organisation/code/Code.java @@ -0,0 +1,70 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.organisation.code; + +import org.apache.fineract.organisation.parent.AbstractPersistableCustom; + +import javax.persistence.CascadeType; +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.OneToMany; +import javax.persistence.Table; +import javax.persistence.UniqueConstraint; +import java.util.Set; + +@Entity +@Table(name = "m_code", uniqueConstraints = { @UniqueConstraint(columnNames = { "code_name" }, name = "code_name") }) +public class Code extends AbstractPersistableCustom { + + @Column(name = "code_name", length = 100) + private String name; + + @Column(name = "is_system_defined") + private boolean systemDefined; + + @OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL, mappedBy = "code", orphanRemoval = true) + private Set values; + + public Code() {} + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public boolean isSystemDefined() { + return systemDefined; + } + + public void setSystemDefined(boolean systemDefined) { + this.systemDefined = systemDefined; + } + + public Set getValues() { + return values; + } + + public void setValues(Set values) { + this.values = values; + } +} \ No newline at end of file diff --git a/ph-ee-operations-app/src/main/java/org/apache/fineract/organisation/code/CodeValue.java b/ph-ee-operations-app/src/main/java/org/apache/fineract/organisation/code/CodeValue.java new file mode 100644 index 000000000..1afa1bc5e --- /dev/null +++ b/ph-ee-operations-app/src/main/java/org/apache/fineract/organisation/code/CodeValue.java @@ -0,0 +1,102 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.organisation.code; + +import org.apache.fineract.organisation.parent.AbstractPersistableCustom; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.JoinColumn; +import javax.persistence.ManyToOne; +import javax.persistence.Table; +import javax.persistence.UniqueConstraint; + +@Entity +@Table(name = "m_code_value", uniqueConstraints = { @UniqueConstraint(columnNames = { "code_id", "code_value" }, name = "code_value_duplicate") }) +public class CodeValue extends AbstractPersistableCustom { + + @Column(name = "code_value", length = 100) + private String label; + + @Column(name = "order_position") + private int position; + + @Column(name = "code_description") + private String description; + + @ManyToOne + @JoinColumn(name = "code_id", nullable = false) + private Code code; + + @Column(name = "is_active") + private boolean isActive; + + @Column(name = "is_mandatory") + private boolean mandatory; + + public CodeValue() {} + + public String getLabel() { + return label; + } + + public void setLabel(String label) { + this.label = label; + } + + public int getPosition() { + return position; + } + + public void setPosition(int position) { + this.position = position; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public Code getCode() { + return code; + } + + public void setCode(Code code) { + this.code = code; + } + + public boolean isActive() { + return isActive; + } + + public void setActive(boolean active) { + isActive = active; + } + + public boolean isMandatory() { + return mandatory; + } + + public void setMandatory(boolean mandatory) { + this.mandatory = mandatory; + } +} \ No newline at end of file diff --git a/ph-ee-operations-app/src/main/java/org/apache/fineract/organisation/document/Document.java b/ph-ee-operations-app/src/main/java/org/apache/fineract/organisation/document/Document.java new file mode 100644 index 000000000..b8fac5735 --- /dev/null +++ b/ph-ee-operations-app/src/main/java/org/apache/fineract/organisation/document/Document.java @@ -0,0 +1,146 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.organisation.document; + +import org.apache.commons.lang3.StringUtils; +import org.apache.fineract.organisation.parent.AbstractPersistableCustom; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.Table; + +@Entity +@Table(name = "m_document") +public class Document extends AbstractPersistableCustom { + + @Column(name = "parent_entity_type", length = 50) + private String parentEntityType; + + @Column(name = "parent_entity_id", length = 1000) + private Long parentEntityId; + + @Column(name = "name", length = 250) + private String name; + + @Column(name = "file_name", length = 250) + private String fileName; + + @Column(name = "size") + private Long size; + + @Column(name = "type", length = 50) + private String type; + + @Column(name = "description", length = 1000) + private String description; + + @Column(name = "location", length = 500) + private String location; + + @Column(name = "storage_type_enum") + private Integer storageType; + + public Document() {} + + public static Document createNew(final String parentEntityType, final Long parentEntityId, final String name, final String fileName, + final Long size, final String type, final String description, final String location, final StorageType storageType) { + return new Document(parentEntityType, parentEntityId, name, fileName, size, type, description, location, storageType); + } + + private Document(final String parentEntityType, final Long parentEntityId, final String name, final String fileName, final Long size, + final String type, final String description, final String location, final StorageType storageType) { + this.parentEntityType = StringUtils.defaultIfEmpty(parentEntityType, null); + this.parentEntityId = parentEntityId; + this.name = StringUtils.defaultIfEmpty(name, null); + this.fileName = StringUtils.defaultIfEmpty(fileName, null); + this.size = size; + this.type = StringUtils.defaultIfEmpty(type, null); + this.description = StringUtils.defaultIfEmpty(description, null); + this.location = StringUtils.defaultIfEmpty(location, null); + this.storageType = storageType.getValue(); + } + + public String getParentEntityType() { + return this.parentEntityType; + } + + public void setParentEntityType(final String parentEntityType) { + this.parentEntityType = parentEntityType; + } + + public Long getParentEntityId() { + return this.parentEntityId; + } + + public void setParentEntityId(final Long parentEntityId) { + this.parentEntityId = parentEntityId; + } + + public String getName() { + return this.name; + } + + public void setName(final String name) { + this.name = name; + } + + public String getFileName() { + return this.fileName; + } + + public void setFileName(final String fileName) { + this.fileName = fileName; + } + + public Long getSize() { + return this.size; + } + + public void setSize(final Long size) { + this.size = size; + } + + public String getType() { + return this.type; + } + + public void setType(final String type) { + this.type = type; + } + + public String getDescription() { + return this.description; + } + + public void setDescription(final String description) { + this.description = description; + } + + public String getLocation() { + return this.location; + } + + public void setLocation(final String location) { + this.location = location; + } + + public StorageType storageType() { + return StorageType.fromInt(this.storageType); + } +} \ No newline at end of file diff --git a/ph-ee-operations-app/src/main/java/org/apache/fineract/organisation/document/DocumentRepository.java b/ph-ee-operations-app/src/main/java/org/apache/fineract/organisation/document/DocumentRepository.java new file mode 100644 index 000000000..df9ea6f8a --- /dev/null +++ b/ph-ee-operations-app/src/main/java/org/apache/fineract/organisation/document/DocumentRepository.java @@ -0,0 +1,27 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.organisation.document; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; + + +public interface DocumentRepository extends JpaRepository, JpaSpecificationExecutor { + +} \ No newline at end of file diff --git a/ph-ee-operations-app/src/main/java/org/apache/fineract/organisation/document/Image.java b/ph-ee-operations-app/src/main/java/org/apache/fineract/organisation/document/Image.java new file mode 100644 index 000000000..693a0aaab --- /dev/null +++ b/ph-ee-operations-app/src/main/java/org/apache/fineract/organisation/document/Image.java @@ -0,0 +1,62 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.organisation.document; + +import org.apache.fineract.organisation.parent.AbstractPersistableCustom; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.Table; + +@Entity +@Table(name = "m_image") +public final class Image extends AbstractPersistableCustom { + + @Column(name = "location", length = 500) + private String location; + + @Column(name = "storage_type_enum") + private Integer storageType; + + public Image(final String location, final StorageType storageType) { + this.location = location; + this.storageType = storageType.getValue(); + } + + protected Image() { + + } + + public String getLocation() { + return this.location; + } + + public Integer getStorageType() { + return this.storageType; + } + + public void setLocation(final String location) { + this.location = location; + } + + public void setStorageType(final Integer storageType) { + this.storageType = storageType; + } + +} diff --git a/ph-ee-operations-app/src/main/java/org/apache/fineract/organisation/document/ImageRepository.java b/ph-ee-operations-app/src/main/java/org/apache/fineract/organisation/document/ImageRepository.java new file mode 100644 index 000000000..c889c33cd --- /dev/null +++ b/ph-ee-operations-app/src/main/java/org/apache/fineract/organisation/document/ImageRepository.java @@ -0,0 +1,25 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.organisation.document; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; + + +public interface ImageRepository extends JpaRepository, JpaSpecificationExecutor {} \ No newline at end of file diff --git a/ph-ee-operations-app/src/main/java/org/apache/fineract/organisation/document/StorageType.java b/ph-ee-operations-app/src/main/java/org/apache/fineract/organisation/document/StorageType.java new file mode 100644 index 000000000..5ef6a792f --- /dev/null +++ b/ph-ee-operations-app/src/main/java/org/apache/fineract/organisation/document/StorageType.java @@ -0,0 +1,48 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.organisation.document; + +import java.util.HashMap; +import java.util.Map; + +public enum StorageType { + FILE_SYSTEM(1), S3(2); + + private Integer value; + + StorageType(final Integer value) { + this.value = value; + } + + public Integer getValue() { + return this.value; + } + + private static final Map intToEnumMap = new HashMap<>(); + static { + for (final StorageType type : StorageType.values()) { + intToEnumMap.put(type.value, type); + } + } + + public static StorageType fromInt(final int i) { + final StorageType type = intToEnumMap.get(Integer.valueOf(i)); + return type; + } +} \ No newline at end of file diff --git a/ph-ee-operations-app/src/main/java/org/apache/fineract/organisation/group/Group.java b/ph-ee-operations-app/src/main/java/org/apache/fineract/organisation/group/Group.java new file mode 100644 index 000000000..3c9d9b3f2 --- /dev/null +++ b/ph-ee-operations-app/src/main/java/org/apache/fineract/organisation/group/Group.java @@ -0,0 +1,270 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.organisation.group; + +import org.apache.fineract.organisation.code.CodeValue; +import org.apache.fineract.organisation.office.Office; +import org.apache.fineract.organisation.parent.AbstractPersistableCustom; +import org.apache.fineract.organisation.staff.Staff; +import org.apache.fineract.organisation.user.AppUser; + +import javax.persistence.CascadeType; +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.JoinColumn; +import javax.persistence.ManyToOne; +import javax.persistence.OneToMany; +import javax.persistence.Table; +import javax.persistence.Temporal; +import javax.persistence.TemporalType; +import javax.persistence.Transient; +import java.util.Date; +import java.util.LinkedList; +import java.util.List; +import java.util.Set; + +@Entity +@Table(name = "m_group") +public final class Group extends AbstractPersistableCustom { + + @Column(name = "external_id", length = 100, unique = true) + private String externalId; + + @Column(name = "status_enum", nullable = false) + private Integer status; + + @Column(name = "activation_date", nullable = true) + @Temporal(TemporalType.DATE) + private Date activationDate; + + @ManyToOne(optional = true) + @JoinColumn(name = "activatedon_userid", nullable = true) + private AppUser activatedBy; + + @ManyToOne + @JoinColumn(name = "office_id", nullable = false) + private Office office; + + @ManyToOne + @JoinColumn(name = "staff_id", nullable = true) + private Staff staff; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "parent_id") + private Group parent; + + @ManyToOne + @JoinColumn(name = "level_id", nullable = false) + private GroupLevel groupLevel; + + @Column(name = "display_name", length = 100, unique = true) + private String name; + + @Column(name = "hierarchy", length = 100) + private String hierarchy; + + @OneToMany(fetch = FetchType.EAGER) + @JoinColumn(name = "parent_id") + private List groupMembers = new LinkedList<>(); + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "closure_reason_cv_id", nullable = true) + private CodeValue closureReason; + + @Column(name = "closedon_date", nullable = true) + @Temporal(TemporalType.DATE) + private Date closureDate; + + @ManyToOne(optional = true, fetch=FetchType.LAZY) + @JoinColumn(name = "closedon_userid", nullable = true) + private AppUser closedBy; + + @Column(name = "submittedon_date", nullable = true) + @Temporal(TemporalType.DATE) + private Date submittedOnDate; + + @ManyToOne(optional = true, fetch=FetchType.LAZY) + @JoinColumn(name = "submittedon_userid", nullable = true) + private AppUser submittedBy; + + @Column(name = "account_no", length = 20, unique = true, nullable = false) + private String accountNumber; + + @Transient + private boolean accountNumberRequiresAutoGeneration = false; + + @OneToMany(mappedBy="group",cascade = CascadeType.REMOVE) + private Set groupRole; + + public Group() { + } + + public String getExternalId() { + return externalId; + } + + public void setExternalId(String externalId) { + this.externalId = externalId; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } + + public Date getActivationDate() { + return activationDate; + } + + public void setActivationDate(Date activationDate) { + this.activationDate = activationDate; + } + + public AppUser getActivatedBy() { + return activatedBy; + } + + public void setActivatedBy(AppUser activatedBy) { + this.activatedBy = activatedBy; + } + + public Office getOffice() { + return office; + } + + public void setOffice(Office office) { + this.office = office; + } + + public Staff getStaff() { + return staff; + } + + public void setStaff(Staff staff) { + this.staff = staff; + } + + public Group getParent() { + return parent; + } + + public void setParent(Group parent) { + this.parent = parent; + } + + public GroupLevel getGroupLevel() { + return groupLevel; + } + + public void setGroupLevel(GroupLevel groupLevel) { + this.groupLevel = groupLevel; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getHierarchy() { + return hierarchy; + } + + public void setHierarchy(String hierarchy) { + this.hierarchy = hierarchy; + } + + public List getGroupMembers() { + return groupMembers; + } + + public void setGroupMembers(List groupMembers) { + this.groupMembers = groupMembers; + } + + public CodeValue getClosureReason() { + return closureReason; + } + + public void setClosureReason(CodeValue closureReason) { + this.closureReason = closureReason; + } + + public Date getClosureDate() { + return closureDate; + } + + public void setClosureDate(Date closureDate) { + this.closureDate = closureDate; + } + + public AppUser getClosedBy() { + return closedBy; + } + + public void setClosedBy(AppUser closedBy) { + this.closedBy = closedBy; + } + + public Date getSubmittedOnDate() { + return submittedOnDate; + } + + public void setSubmittedOnDate(Date submittedOnDate) { + this.submittedOnDate = submittedOnDate; + } + + public AppUser getSubmittedBy() { + return submittedBy; + } + + public void setSubmittedBy(AppUser submittedBy) { + this.submittedBy = submittedBy; + } + + public String getAccountNumber() { + return accountNumber; + } + + public void setAccountNumber(String accountNumber) { + this.accountNumber = accountNumber; + } + + public boolean isAccountNumberRequiresAutoGeneration() { + return accountNumberRequiresAutoGeneration; + } + + public void setAccountNumberRequiresAutoGeneration(boolean accountNumberRequiresAutoGeneration) { + this.accountNumberRequiresAutoGeneration = accountNumberRequiresAutoGeneration; + } + + public Set getGroupRole() { + return groupRole; + } + + public void setGroupRole(Set groupRole) { + this.groupRole = groupRole; + } +} diff --git a/ph-ee-operations-app/src/main/java/org/apache/fineract/organisation/group/GroupLevel.java b/ph-ee-operations-app/src/main/java/org/apache/fineract/organisation/group/GroupLevel.java new file mode 100644 index 000000000..703b049ed --- /dev/null +++ b/ph-ee-operations-app/src/main/java/org/apache/fineract/organisation/group/GroupLevel.java @@ -0,0 +1,77 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.organisation.group; + +import org.apache.fineract.organisation.parent.AbstractPersistableCustom; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.Table; + +@Entity +@Table(name = "m_group_level") +public class GroupLevel extends AbstractPersistableCustom { + + @Column(name = "parent_id") + private Long parentId; + + @Column(name = "super_parent", nullable = false) + private boolean superParent; + + @Column(name = "level_name", nullable = false, length = 100, unique = true) + private String levelName; + + @Column(name = "recursable", nullable = false) + private boolean recursable; + + public GroupLevel() { + } + + public Long getParentId() { + return parentId; + } + + public void setParentId(Long parentId) { + this.parentId = parentId; + } + + public boolean isSuperParent() { + return superParent; + } + + public void setSuperParent(boolean superParent) { + this.superParent = superParent; + } + + public String getLevelName() { + return levelName; + } + + public void setLevelName(String levelName) { + this.levelName = levelName; + } + + public boolean isRecursable() { + return recursable; + } + + public void setRecursable(boolean recursable) { + this.recursable = recursable; + } +} \ No newline at end of file diff --git a/ph-ee-operations-app/src/main/java/org/apache/fineract/organisation/group/GroupLevelRepository.java b/ph-ee-operations-app/src/main/java/org/apache/fineract/organisation/group/GroupLevelRepository.java new file mode 100644 index 000000000..c5af50d78 --- /dev/null +++ b/ph-ee-operations-app/src/main/java/org/apache/fineract/organisation/group/GroupLevelRepository.java @@ -0,0 +1,28 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.organisation.group; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; + + +public interface GroupLevelRepository extends JpaRepository, JpaSpecificationExecutor { + + +} diff --git a/ph-ee-operations-app/src/main/java/org/apache/fineract/organisation/group/GroupRepository.java b/ph-ee-operations-app/src/main/java/org/apache/fineract/organisation/group/GroupRepository.java new file mode 100644 index 000000000..e640eb667 --- /dev/null +++ b/ph-ee-operations-app/src/main/java/org/apache/fineract/organisation/group/GroupRepository.java @@ -0,0 +1,40 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.organisation.group; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; +import org.springframework.stereotype.Repository; + +import javax.transaction.Transactional; +import java.util.Collection; +import java.util.Date; + +@Repository +@Transactional +public interface GroupRepository extends JpaRepository, JpaSpecificationExecutor { + + Collection findByParentId(Long parentId); + + @Query("select g.submittedOnDate from Group g where g.id = :groupId") + Date retrieveGroupTypeSubmitteOndDate(@Param("groupId") Long groupId); + +} diff --git a/ph-ee-operations-app/src/main/java/org/apache/fineract/organisation/group/GroupRole.java b/ph-ee-operations-app/src/main/java/org/apache/fineract/organisation/group/GroupRole.java new file mode 100644 index 000000000..a2fce1932 --- /dev/null +++ b/ph-ee-operations-app/src/main/java/org/apache/fineract/organisation/group/GroupRole.java @@ -0,0 +1,66 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.organisation.group; + +import org.apache.fineract.organisation.code.CodeValue; +import org.apache.fineract.organisation.parent.AbstractPersistableCustom; + +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.JoinColumn; +import javax.persistence.ManyToOne; +import javax.persistence.Table; + +@Entity +@Table(name = "m_group_roles") +public class GroupRole extends AbstractPersistableCustom { + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "group_id") + private Group group; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "role_cv_id") + private CodeValue role; + + public GroupRole() { + // TODO Auto-generated constructor stub + } + + public GroupRole(final Group group, final CodeValue role) { + this.group = group; + this.role = role; + } + + public Group getGroup() { + return group; + } + + public void setGroup(Group group) { + this.group = group; + } + + public CodeValue getRole() { + return role; + } + + public void setRole(CodeValue role) { + this.role = role; + } +} diff --git a/ph-ee-operations-app/src/main/java/org/apache/fineract/organisation/group/GroupRoleRepository.java b/ph-ee-operations-app/src/main/java/org/apache/fineract/organisation/group/GroupRoleRepository.java new file mode 100644 index 000000000..52a69801b --- /dev/null +++ b/ph-ee-operations-app/src/main/java/org/apache/fineract/organisation/group/GroupRoleRepository.java @@ -0,0 +1,27 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.organisation.group; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; + + +public interface GroupRoleRepository extends JpaRepository, JpaSpecificationExecutor { + +} diff --git a/ph-ee-operations-app/src/main/java/org/apache/fineract/organisation/group/GroupTypes.java b/ph-ee-operations-app/src/main/java/org/apache/fineract/organisation/group/GroupTypes.java new file mode 100644 index 000000000..e14834737 --- /dev/null +++ b/ph-ee-operations-app/src/main/java/org/apache/fineract/organisation/group/GroupTypes.java @@ -0,0 +1,89 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.organisation.group; + +import java.util.HashMap; +import java.util.Map; + +public enum GroupTypes { + + INVALID(0l, "lendingStrategy.invalid", "invalid"), // + CENTER(1l, "groupTypes.center", "center"), // + GROUP(2l, "groupTypes.group", "group"); // + + private Long id; + private String code; + private String value; + + private GroupTypes(final Long id, final String code, final String value) { + this.id = id; + this.code = code; + this.value = value; + } + + private static final Map intToEnumMap = new HashMap<>(); + private static long minValue; + private static long maxValue; + static { + int i = 0; + for (final GroupTypes type : GroupTypes.values()) { + if (i == 0) { + minValue = type.id; + } + intToEnumMap.put(type.id, type); + if (minValue >= type.id) { + minValue = type.id; + } + if (maxValue < type.id) { + maxValue = type.id; + } + i = i + 1; + } + } + + public static GroupTypes fromInt(final int i) { + final GroupTypes type = intToEnumMap.get(Integer.valueOf(i)); + return type; + } + + public static long getMinValue() { + return minValue; + } + + public static long getMaxValue() { + return maxValue; + } + + @Override + public String toString() { + return name().toString(); + } + + public Long getId() { + return this.id; + } + + public String getCode() { + return this.code; + } + + public String getValue() { + return this.value; + } +} \ No newline at end of file diff --git a/ph-ee-operations-app/src/main/java/org/apache/fineract/organisation/office/CurrencyData.java b/ph-ee-operations-app/src/main/java/org/apache/fineract/organisation/office/CurrencyData.java new file mode 100644 index 000000000..9f683bafe --- /dev/null +++ b/ph-ee-operations-app/src/main/java/org/apache/fineract/organisation/office/CurrencyData.java @@ -0,0 +1,100 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.organisation.office; + +/** + * Immutable data object representing currency. + */ +public class CurrencyData { + + private final String code; + private final String name; + private final int decimalPlaces; + private final Integer inMultiplesOf; + private final String displaySymbol; + @SuppressWarnings("unused") + private final String nameCode; + @SuppressWarnings("unused") + private final String displayLabel; + + public static CurrencyData blank() { + return new CurrencyData("", "", 0, 0, "", ""); + } + + public CurrencyData(String code) { + this.code = code; + this.name = null; + this.decimalPlaces =0; + this.inMultiplesOf = null; + this.displaySymbol = null; + this.nameCode = null; + this.displayLabel = null; + } + + public CurrencyData(final String code, final String name, final int decimalPlaces, final Integer inMultiplesOf, + final String displaySymbol, final String nameCode) { + this.code = code; + this.name = name; + this.decimalPlaces = decimalPlaces; + this.inMultiplesOf = inMultiplesOf; + this.displaySymbol = displaySymbol; + this.nameCode = nameCode; + this.displayLabel = generateDisplayLabel(); + } + + public String code() { + return this.code; + } + + public int decimalPlaces() { + return this.decimalPlaces; + } + + public Integer currencyInMultiplesOf() { + return this.inMultiplesOf; + } + + @Override + public boolean equals(final Object obj) { + final CurrencyData currencyData = (CurrencyData) obj; + return currencyData.code.equals(this.code); + } + + @Override + public int hashCode() { + return this.code.hashCode(); + } + + private String generateDisplayLabel() { + + final StringBuilder builder = new StringBuilder(this.name).append(' '); + + if (this.displaySymbol != null && !"".equalsIgnoreCase(this.displaySymbol.trim())) { + builder.append('(').append(this.displaySymbol).append(')'); + } else { + builder.append('[').append(this.code).append(']'); + } + + return builder.toString(); + } + + public String getName() { + return name; + } +} \ No newline at end of file diff --git a/ph-ee-operations-app/src/main/java/org/apache/fineract/organisation/office/Office.java b/ph-ee-operations-app/src/main/java/org/apache/fineract/organisation/office/Office.java new file mode 100644 index 000000000..3c7325209 --- /dev/null +++ b/ph-ee-operations-app/src/main/java/org/apache/fineract/organisation/office/Office.java @@ -0,0 +1,110 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.organisation.office; + +import org.apache.fineract.organisation.parent.AbstractPersistableCustom; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.JoinColumn; +import javax.persistence.ManyToOne; +import javax.persistence.OneToMany; +import javax.persistence.Table; +import javax.persistence.Temporal; +import javax.persistence.TemporalType; +import java.util.Date; +import java.util.LinkedList; +import java.util.List; + +@Entity +@Table(name = "m_office") +public class Office extends AbstractPersistableCustom { + + @OneToMany(fetch = FetchType.LAZY) + @JoinColumn(name = "parent_id") + private List children = new LinkedList<>(); + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "parent_id") + private Office parent; + + @Column(name = "name", nullable = false, length = 100) + private String name; + + @Column(name = "hierarchy", nullable = true, length = 50) + private String hierarchy; + + @Column(name = "opening_date", nullable = false) + @Temporal(TemporalType.DATE) + private Date openingDate; + + @Column(name = "external_id", length = 100) + private String externalId; + + public Office() {} + + public List getChildren() { + return children; + } + + public void setChildren(List children) { + this.children = children; + } + + public Office getParent() { + return parent; + } + + public void setParent(Office parent) { + this.parent = parent; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getHierarchy() { + return hierarchy; + } + + public void setHierarchy(String hierarchy) { + this.hierarchy = hierarchy; + } + + public Date getOpeningDate() { + return openingDate; + } + + public void setOpeningDate(Date openingDate) { + this.openingDate = openingDate; + } + + public String getExternalId() { + return externalId; + } + + public void setExternalId(String externalId) { + this.externalId = externalId; + } +} \ No newline at end of file diff --git a/ph-ee-operations-app/src/main/java/org/apache/fineract/organisation/office/OfficeData.java b/ph-ee-operations-app/src/main/java/org/apache/fineract/organisation/office/OfficeData.java new file mode 100644 index 000000000..b2bcf089e --- /dev/null +++ b/ph-ee-operations-app/src/main/java/org/apache/fineract/organisation/office/OfficeData.java @@ -0,0 +1,110 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.organisation.office; + +import org.joda.time.LocalDate; + +import java.io.Serializable; +import java.util.Collection; +import java.util.List; + +/** + * Immutable data object for office data. + */ +public class OfficeData implements Serializable { + + private final Long id; + private final String name; + private final String nameDecorated; + private final String externalId; + private final LocalDate openingDate; + private final String hierarchy; + private final Long parentId; + private final String parentName; + @SuppressWarnings("unused") + private final Collection allowedParents; + + //import fields + private transient Integer rowIndex; + private String locale; + private String dateFormat; + + public static OfficeData importInstance(final String name, final Long parentId, final LocalDate openingDate,final String externalId) { + return new OfficeData(null, name, null, externalId, openingDate, null, parentId, null, null); + } + public void setImportFields(final Integer rowIndex, final String locale, final String dateFormat) { + this.rowIndex = rowIndex; + this.locale = locale; + this.dateFormat = dateFormat; + } + public static OfficeData testInstance(final Long id,final String name){ + return new OfficeData(id,name,null,null, + null,null,null,null, + null); + } + public LocalDate getOpeningDate() { + return openingDate; + } + + public Integer getRowIndex() { + return rowIndex; + } + + public Long getId() { + return id; + } + + public static OfficeData dropdown(final Long id, final String name, final String nameDecorated) { + return new OfficeData(id, name, nameDecorated, null, null, null, null, null, null); + } + + public static OfficeData template(final List parentLookups, final LocalDate defaultOpeningDate) { + return new OfficeData(null, null, null, null, defaultOpeningDate, null, null, null, parentLookups); + } + + public static OfficeData appendedTemplate(final OfficeData office, final Collection allowedParents) { + return new OfficeData(office.id, office.name, office.nameDecorated, office.externalId, office.openingDate, office.hierarchy, + office.parentId, office.parentName, allowedParents); + } + + public OfficeData(final Long id, final String name, final String nameDecorated, final String externalId, final LocalDate openingDate, + final String hierarchy, final Long parentId, final String parentName, final Collection allowedParents) { + this.id = id; + this.name = name; + this.nameDecorated = nameDecorated; + this.externalId = externalId; + this.openingDate = openingDate; + this.hierarchy = hierarchy; + this.parentName = parentName; + this.parentId = parentId; + this.allowedParents = allowedParents; + } + + public boolean hasIdentifyOf(final Long officeId) { + return this.id.equals(officeId); + } + + public String name() { + return this.name; + } + + public String getHierarchy() { + return this.hierarchy; + } +} diff --git a/ph-ee-operations-app/src/main/java/org/apache/fineract/organisation/office/OfficeRepository.java b/ph-ee-operations-app/src/main/java/org/apache/fineract/organisation/office/OfficeRepository.java new file mode 100644 index 000000000..2f0b8aa8f --- /dev/null +++ b/ph-ee-operations-app/src/main/java/org/apache/fineract/organisation/office/OfficeRepository.java @@ -0,0 +1,27 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.organisation.office; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; + + +public interface OfficeRepository extends JpaRepository, JpaSpecificationExecutor { + +} diff --git a/ph-ee-operations-app/src/main/java/org/apache/fineract/organisation/office/OfficeTransactionData.java b/ph-ee-operations-app/src/main/java/org/apache/fineract/organisation/office/OfficeTransactionData.java new file mode 100644 index 000000000..17567b3e6 --- /dev/null +++ b/ph-ee-operations-app/src/main/java/org/apache/fineract/organisation/office/OfficeTransactionData.java @@ -0,0 +1,81 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.organisation.office; + +import org.joda.time.LocalDate; + +import java.math.BigDecimal; +import java.util.Collection; + +/** + * Immutable data object for office transactions. + */ +public class OfficeTransactionData { + + @SuppressWarnings("unused") + private final Long id; + @SuppressWarnings("unused") + private final LocalDate transactionDate; + @SuppressWarnings("unused") + private final Long fromOfficeId; + @SuppressWarnings("unused") + private final String fromOfficeName; + @SuppressWarnings("unused") + private final Long toOfficeId; + @SuppressWarnings("unused") + private final String toOfficeName; + @SuppressWarnings("unused") + private final CurrencyData currency; + @SuppressWarnings("unused") + private final BigDecimal transactionAmount; + @SuppressWarnings("unused") + private final String description; + @SuppressWarnings("unused") + private final Collection currencyOptions; + @SuppressWarnings("unused") + private final Collection allowedOffices; + + public static OfficeTransactionData instance(final Long id, final LocalDate transactionDate, final Long fromOfficeId, + final String fromOfficeName, final Long toOfficeId, final String toOfficeName, final CurrencyData currency, + final BigDecimal transactionAmount, final String description) { + return new OfficeTransactionData(id, transactionDate, fromOfficeId, fromOfficeName, toOfficeId, toOfficeName, currency, + transactionAmount, description, null, null); + } + + public static OfficeTransactionData template(final LocalDate transactionDate, final Collection parentLookups, + final Collection currencyOptions) { + return new OfficeTransactionData(null, transactionDate, null, null, null, null, null, null, null, parentLookups, currencyOptions); + } + + private OfficeTransactionData(final Long id, final LocalDate transactionDate, final Long fromOfficeId, final String fromOfficeName, + final Long toOfficeId, final String toOfficeName, final CurrencyData currency, final BigDecimal transactionAmount, + final String description, final Collection allowedOffices, final Collection currencyOptions) { + this.id = id; + this.fromOfficeId = fromOfficeId; + this.fromOfficeName = fromOfficeName; + this.toOfficeId = toOfficeId; + this.toOfficeName = toOfficeName; + this.currency = currency; + this.transactionAmount = transactionAmount; + this.description = description; + this.transactionDate = transactionDate; + this.allowedOffices = allowedOffices; + this.currencyOptions = currencyOptions; + } +} diff --git a/ph-ee-operations-app/src/main/java/org/apache/fineract/organisation/parent/AbstractPersistableCustom.java b/ph-ee-operations-app/src/main/java/org/apache/fineract/organisation/parent/AbstractPersistableCustom.java new file mode 100644 index 000000000..b7de32dc2 --- /dev/null +++ b/ph-ee-operations-app/src/main/java/org/apache/fineract/organisation/parent/AbstractPersistableCustom.java @@ -0,0 +1,53 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.organisation.parent; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import org.springframework.data.domain.Persistable; + +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.MappedSuperclass; +import java.io.Serializable; + + +@MappedSuperclass +public abstract class AbstractPersistableCustom implements Persistable { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @Override + public Long getId() { + return id; + } + + public void setId(final Long id) { + + this.id = id; + } + + @Override + @JsonIgnore + public boolean isNew() { + return null == this.id; + } +} diff --git a/ph-ee-operations-app/src/main/java/org/apache/fineract/organisation/password/AppUserPreviousPassword.java b/ph-ee-operations-app/src/main/java/org/apache/fineract/organisation/password/AppUserPreviousPassword.java new file mode 100644 index 000000000..6f46a2893 --- /dev/null +++ b/ph-ee-operations-app/src/main/java/org/apache/fineract/organisation/password/AppUserPreviousPassword.java @@ -0,0 +1,71 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.organisation.password; + +import org.apache.fineract.organisation.parent.AbstractPersistableCustom; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.Table; +import javax.persistence.Temporal; +import javax.persistence.TemporalType; +import java.util.Date; + +@Entity +@Table(name = "m_appuser_previous_password") +public class AppUserPreviousPassword extends AbstractPersistableCustom { + + @Column(name = "user_id", nullable = false) + private Long userId; + + @Column(name = "removal_date") + @Temporal(TemporalType.DATE) + private Date removalDate; + + @Column(name = "password", nullable = false) + private String password; + + public AppUserPreviousPassword() { + + } + + public Long getUserId() { + return userId; + } + + public void setUserId(Long userId) { + this.userId = userId; + } + + public Date getRemovalDate() { + return removalDate; + } + + public void setRemovalDate(Date removalDate) { + this.removalDate = removalDate; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } +} \ No newline at end of file diff --git a/ph-ee-operations-app/src/main/java/org/apache/fineract/organisation/password/AppUserPreviousPasswordRepository.java b/ph-ee-operations-app/src/main/java/org/apache/fineract/organisation/password/AppUserPreviousPasswordRepository.java new file mode 100644 index 000000000..56d7c66e2 --- /dev/null +++ b/ph-ee-operations-app/src/main/java/org/apache/fineract/organisation/password/AppUserPreviousPasswordRepository.java @@ -0,0 +1,32 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.organisation.password; + +import org.springframework.data.domain.Pageable; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; + +import java.util.List; + + +public interface AppUserPreviousPasswordRepository extends JpaRepository, + JpaSpecificationExecutor { + + public List findByUserId(Long userId, Pageable pageable); +} diff --git a/ph-ee-operations-app/src/main/java/org/apache/fineract/organisation/password/PasswordValidationPolicy.java b/ph-ee-operations-app/src/main/java/org/apache/fineract/organisation/password/PasswordValidationPolicy.java new file mode 100644 index 000000000..7f8a4149b --- /dev/null +++ b/ph-ee-operations-app/src/main/java/org/apache/fineract/organisation/password/PasswordValidationPolicy.java @@ -0,0 +1,86 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.organisation.password; + +import org.apache.fineract.organisation.parent.AbstractPersistableCustom; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.Table; +import java.util.LinkedHashMap; +import java.util.Map; + +@Entity +@Table(name = "m_password_validation_policy") +public class PasswordValidationPolicy extends AbstractPersistableCustom { + + @Column(name = "regex", nullable = false) + private String regex; + + @Column(name = "description", nullable = false) + private String description; + + @Column(name = "active", nullable = false) + private boolean active; + + public PasswordValidationPolicy(final String regex, final String description, final boolean active) { + this.description = description; + this.regex = regex; + this.active = active; + } + + public PasswordValidationPolicy() { + this.active = false; + } + + public String getDescription() { + return description; + } + + public String getRegex() { + return regex; + } + + public boolean getActive() { + return this.active; + } + + public Map activate() { + final Map actualChanges = new LinkedHashMap<>(1); + + final String active = "active"; + + if (!this.active) { + + actualChanges.put(active, true); + this.active = true; + } + + return actualChanges; + } + + public boolean isActive() { + return this.active; + } + + public void deActivate() { + this.active = false; + } + +} diff --git a/ph-ee-operations-app/src/main/java/org/apache/fineract/organisation/password/PasswordValidationPolicyData.java b/ph-ee-operations-app/src/main/java/org/apache/fineract/organisation/password/PasswordValidationPolicyData.java new file mode 100644 index 000000000..09f04b748 --- /dev/null +++ b/ph-ee-operations-app/src/main/java/org/apache/fineract/organisation/password/PasswordValidationPolicyData.java @@ -0,0 +1,44 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.organisation.password; + +import java.io.Serializable; + +/** + * Immutable data object for role data. + */ +public class PasswordValidationPolicyData implements Serializable { + + @SuppressWarnings("unused") + private final Long id; + @SuppressWarnings("unused") + private final String description; + @SuppressWarnings("unused") + private final boolean active; + @SuppressWarnings("unused") + private final String key; + + public PasswordValidationPolicyData(final Long id, final Boolean active, final String description, final String key) { + this.id = id; + this.active = active; + this.description = description; + this.key = key; + } + +} \ No newline at end of file diff --git a/ph-ee-operations-app/src/main/java/org/apache/fineract/organisation/password/PasswordValidationPolicyRepository.java b/ph-ee-operations-app/src/main/java/org/apache/fineract/organisation/password/PasswordValidationPolicyRepository.java new file mode 100644 index 000000000..9233a7861 --- /dev/null +++ b/ph-ee-operations-app/src/main/java/org/apache/fineract/organisation/password/PasswordValidationPolicyRepository.java @@ -0,0 +1,34 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.organisation.password; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; +import org.springframework.data.jpa.repository.Query; + + +public interface PasswordValidationPolicyRepository extends JpaRepository, + JpaSpecificationExecutor { + + @Query("select PVP from PasswordValidationPolicy PVP WHERE PVP.active = true") + public PasswordValidationPolicy findActivePasswordValidationPolicy(); + + + +} diff --git a/ph-ee-operations-app/src/main/java/org/apache/fineract/organisation/permission/Permission.java b/ph-ee-operations-app/src/main/java/org/apache/fineract/organisation/permission/Permission.java new file mode 100644 index 000000000..0114f8bf5 --- /dev/null +++ b/ph-ee-operations-app/src/main/java/org/apache/fineract/organisation/permission/Permission.java @@ -0,0 +1,120 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.organisation.permission; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import org.apache.fineract.organisation.parent.AbstractPersistableCustom; +import org.apache.fineract.organisation.role.Role; + +import javax.persistence.CascadeType; +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.ManyToMany; +import javax.persistence.Table; +import java.util.Collection; +import java.util.Objects; + +@Entity +@Table(name = "m_permission") +public class Permission extends AbstractPersistableCustom { + + @Column(name = "grouping", nullable = false, length = 45) + private String grouping; + + @Column(name = "code", nullable = false, length = 100) + private String code; + + @Column(name = "entity_name", nullable = true, length = 100) + private String entityName; + + @Column(name = "action_name", nullable = true, length = 100) + private String actionName; + + @Column(name = "can_maker_checker", nullable = false) + private boolean canMakerChecker; + + @ManyToMany(fetch = FetchType.LAZY, mappedBy = "permissions", cascade = {CascadeType.REFRESH, CascadeType.DETACH, CascadeType.PERSIST, CascadeType.MERGE}) + private Collection roles; + + public Permission() { + } + + @JsonIgnore + public Collection getRoles() { + return this.roles; + } + + public void setRoles(Collection roles) { + this.roles = roles; + } + + public String getGrouping() { + return grouping; + } + + public void setGrouping(String grouping) { + this.grouping = grouping; + } + + public String getCode() { + return code; + } + + public void setCode(String code) { + this.code = code; + } + + public String getEntityName() { + return entityName; + } + + public void setEntityName(String entityName) { + this.entityName = entityName; + } + + public String getActionName() { + return actionName; + } + + public void setActionName(String actionName) { + this.actionName = actionName; + } + + public boolean isCanMakerChecker() { + return canMakerChecker; + } + + public void setCanMakerChecker(boolean canMakerChecker) { + this.canMakerChecker = canMakerChecker; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Permission that = (Permission) o; + return Objects.equals(code, that.code); + } + + @Override + public int hashCode() { + return Objects.hash(code); + } +} \ No newline at end of file diff --git a/ph-ee-operations-app/src/main/java/org/apache/fineract/organisation/permission/PermissionData.java b/ph-ee-operations-app/src/main/java/org/apache/fineract/organisation/permission/PermissionData.java new file mode 100644 index 000000000..b1dcccdbc --- /dev/null +++ b/ph-ee-operations-app/src/main/java/org/apache/fineract/organisation/permission/PermissionData.java @@ -0,0 +1,96 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.organisation.permission; + +/** + * Immutable representation of permissions + */ +public class PermissionData { + + @SuppressWarnings("unused") + private String grouping; + @SuppressWarnings("unused") + private String code; + @SuppressWarnings("unused") + private String entityName; + @SuppressWarnings("unused") + private String actionName; + @SuppressWarnings("unused") + private Boolean selected; + + public String getGrouping() { + return grouping; + } + + public void setGrouping(String grouping) { + this.grouping = grouping; + } + + public String getCode() { + return code; + } + + public void setCode(String code) { + this.code = code; + } + + public String getEntityName() { + return entityName; + } + + public void setEntityName(String entityName) { + this.entityName = entityName; + } + + public String getActionName() { + return actionName; + } + + public void setActionName(String actionName) { + this.actionName = actionName; + } + + public Boolean getSelected() { + return selected; + } + + public void setSelected(Boolean selected) { + this.selected = selected; + } + + public PermissionData() {} + + public static PermissionData from(final String permissionCode, final boolean isSelected) { + return new PermissionData(null, permissionCode, null, null, isSelected); + } + + public static PermissionData instance(final String grouping, final String code, final String entityName, final String actionName, + final Boolean selected) { + return new PermissionData(grouping, code, entityName, actionName, selected); + } + + private PermissionData(final String grouping, final String code, final String entityName, final String actionName, + final Boolean selected) { + this.grouping = grouping; + this.code = code; + this.entityName = entityName; + this.actionName = actionName; + this.selected = selected; + } +} \ No newline at end of file diff --git a/ph-ee-operations-app/src/main/java/org/apache/fineract/organisation/permission/PermissionRepository.java b/ph-ee-operations-app/src/main/java/org/apache/fineract/organisation/permission/PermissionRepository.java new file mode 100644 index 000000000..4f6c792e2 --- /dev/null +++ b/ph-ee-operations-app/src/main/java/org/apache/fineract/organisation/permission/PermissionRepository.java @@ -0,0 +1,27 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.organisation.permission; + +import org.springframework.data.jpa.repository.JpaRepository; + + +public interface PermissionRepository extends JpaRepository { + + Permission findOneByCode(String code); +} diff --git a/ph-ee-operations-app/src/main/java/org/apache/fineract/organisation/role/Role.java b/ph-ee-operations-app/src/main/java/org/apache/fineract/organisation/role/Role.java new file mode 100644 index 000000000..9e01af6e2 --- /dev/null +++ b/ph-ee-operations-app/src/main/java/org/apache/fineract/organisation/role/Role.java @@ -0,0 +1,113 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.organisation.role; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import org.apache.fineract.organisation.parent.AbstractPersistableCustom; +import org.apache.fineract.organisation.permission.Permission; +import org.apache.fineract.organisation.user.AppUser; + +import javax.persistence.CascadeType; +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.JoinColumn; +import javax.persistence.JoinTable; +import javax.persistence.ManyToMany; +import javax.persistence.Table; +import java.util.Collection; +import java.util.Objects; + +@Entity +@Table(name = "m_role") +public class Role extends AbstractPersistableCustom { + + @Column(name = "name", unique = true, nullable = false, length = 100) + private String name; + + @Column(name = "description", nullable = false, length = 500) + private String description; + + @Column(name = "is_disabled", nullable = false) + private Boolean disabled; + + @ManyToMany(fetch = FetchType.LAZY, cascade = {CascadeType.REFRESH, CascadeType.DETACH, CascadeType.PERSIST, CascadeType.MERGE}) + private Collection appUsers; + + @ManyToMany(fetch = FetchType.LAZY, cascade = {CascadeType.REFRESH, CascadeType.DETACH, CascadeType.PERSIST, CascadeType.MERGE}) + @JoinTable(name = "m_role_permission", joinColumns = @JoinColumn(name = "role_id"), inverseJoinColumns = @JoinColumn(name = "permission_id")) + private Collection permissions; + + public Role() {} + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public Boolean getDisabled() { + return disabled; + } + + public void setDisabled(Boolean disabled) { + this.disabled = disabled; + } + + @JsonIgnore + public Collection getPermissions() { + return permissions; + } + + public void setPermissions(Collection permissions) { + this.permissions = permissions; + } + + @JsonIgnore + public Collection getAppusers() { + return this.appUsers; + } + + public void setAppUsers(Collection appUsers) { + this.appUsers = appUsers; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Role role = (Role) o; + return Objects.equals(name, role.name); + } + + @Override + public int hashCode() { + return Objects.hash(name); + } +} \ No newline at end of file diff --git a/ph-ee-operations-app/src/main/java/org/apache/fineract/organisation/role/RoleData.java b/ph-ee-operations-app/src/main/java/org/apache/fineract/organisation/role/RoleData.java new file mode 100644 index 000000000..ab061507f --- /dev/null +++ b/ph-ee-operations-app/src/main/java/org/apache/fineract/organisation/role/RoleData.java @@ -0,0 +1,65 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.organisation.role; + +import org.apache.fineract.organisation.permission.PermissionData; + +import java.io.Serializable; +import java.util.Collection; + +/** + * Immutable data object for role data. + */ +public class RoleData implements Serializable { + + private final Long id; + private final String name; + private final String description; + private final Boolean disabled; + + public RolePermissionsData toRolePermissionData(final Collection permissionUsageData) { + return new RolePermissionsData(this.id, this.name, this.description, this.disabled, permissionUsageData); + } + + public RoleData(final Long id, final String name, final String description, final Boolean disabled) { + this.id = id; + this.name = name; + this.description = description; + this.disabled = disabled; + } + + @Override + public boolean equals(final Object obj) { + final RoleData role = (RoleData) obj; + return this.id.equals(role.id); + } + + @Override + public int hashCode() { + return this.id.hashCode(); + } + + public Long getId() { + return id; + } + + public String getName() { + return name; + } +} \ No newline at end of file diff --git a/ph-ee-operations-app/src/main/java/org/apache/fineract/organisation/role/RolePermissionsData.java b/ph-ee-operations-app/src/main/java/org/apache/fineract/organisation/role/RolePermissionsData.java new file mode 100644 index 000000000..2d5ca4ee5 --- /dev/null +++ b/ph-ee-operations-app/src/main/java/org/apache/fineract/organisation/role/RolePermissionsData.java @@ -0,0 +1,50 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.organisation.role; + +import org.apache.fineract.organisation.permission.PermissionData; + +import java.util.Collection; + +/** + * Immutable data object representing a role with associated permissions. + */ +public class RolePermissionsData { + + @SuppressWarnings("unused") + private final Long id; + @SuppressWarnings("unused") + private final String name; + @SuppressWarnings("unused") + private final String description; + @SuppressWarnings("unused") + private final Boolean disabled; + + @SuppressWarnings("unused") + private final Collection permissionUsageData; + + public RolePermissionsData(final Long id, final String name, final String description, final Boolean disabled, + final Collection permissionUsageData) { + this.id = id; + this.name = name; + this.description = description; + this.disabled = disabled; + this.permissionUsageData = permissionUsageData; + } +} \ No newline at end of file diff --git a/ph-ee-operations-app/src/main/java/org/apache/fineract/organisation/role/RoleRepository.java b/ph-ee-operations-app/src/main/java/org/apache/fineract/organisation/role/RoleRepository.java new file mode 100644 index 000000000..a74d12e4d --- /dev/null +++ b/ph-ee-operations-app/src/main/java/org/apache/fineract/organisation/role/RoleRepository.java @@ -0,0 +1,31 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.organisation.role; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; + +public interface RoleRepository extends JpaRepository, JpaSpecificationExecutor { + + @Query("SELECT role FROM Role role WHERE role.name = :name") + Role getRoleByName(@Param("name") String name); + +} \ No newline at end of file diff --git a/ph-ee-operations-app/src/main/java/org/apache/fineract/organisation/staff/EnumOptionData.java b/ph-ee-operations-app/src/main/java/org/apache/fineract/organisation/staff/EnumOptionData.java new file mode 100644 index 000000000..a5fb8764c --- /dev/null +++ b/ph-ee-operations-app/src/main/java/org/apache/fineract/organisation/staff/EnumOptionData.java @@ -0,0 +1,51 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.organisation.staff; + +/** + *

+ * Immutable data object representing generic enumeration value. + *

+ */ +public class EnumOptionData { + + private final Long id; + private final String code; + private final String value; + + public EnumOptionData(final Long id, final String code, final String value) { + this.id = id; + this.code = code; + this.value = value; + } + + public Long getId() { + return this.id; + } + + public String getCode() { + return this.code; + } + + public String getValue() { + return this.value; + } + + +} \ No newline at end of file diff --git a/ph-ee-operations-app/src/main/java/org/apache/fineract/organisation/staff/Staff.java b/ph-ee-operations-app/src/main/java/org/apache/fineract/organisation/staff/Staff.java new file mode 100644 index 000000000..14f72334c --- /dev/null +++ b/ph-ee-operations-app/src/main/java/org/apache/fineract/organisation/staff/Staff.java @@ -0,0 +1,171 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.organisation.staff; + +import org.apache.commons.lang3.StringUtils; +import org.apache.fineract.organisation.document.Image; +import org.apache.fineract.organisation.office.Office; +import org.apache.fineract.organisation.parent.AbstractPersistableCustom; +import org.joda.time.LocalDate; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.JoinColumn; +import javax.persistence.ManyToOne; +import javax.persistence.OneToOne; +import javax.persistence.Table; +import javax.persistence.Temporal; +import javax.persistence.TemporalType; +import java.util.Date; + +@Entity +@Table(name = "m_staff") +public class Staff extends AbstractPersistableCustom { + + @Column(name = "firstname", length = 50) + private String firstname; + + @Column(name = "lastname", length = 50) + private String lastname; + + @Column(name = "display_name", length = 100) + private String displayName; + + @Column(name = "mobile_no", length = 50, nullable = false, unique = true) + private String mobileNo; + + @Column(name = "external_id", length = 100, nullable = true, unique = true) + private String externalId; + + @Column(name = "email_address", length = 50, unique = true) + private String emailAddress; + + @ManyToOne + @JoinColumn(name = "office_id", nullable = false) + private Office office; + + @Column(name = "is_loan_officer", nullable = false) + private boolean loanOfficer; + + @Column(name = "organisational_role_enum", nullable = true) + private Integer organisationalRoleType; + + @Column(name = "is_active", nullable = false) + private boolean active; + + @Column(name = "joining_date", nullable = true) + @Temporal(TemporalType.DATE) + private Date joiningDate; + + @ManyToOne + @JoinColumn(name = "organisational_role_parent_staff_id", nullable = true) + private Staff organisationalRoleParentStaff; + + @OneToOne(optional = true) + @JoinColumn(name = "image_id", nullable = true) + private Image image; + + protected Staff() { + // + } + + private Staff(final Office staffOffice, final String firstname, final String lastname, final String externalId, final String mobileNo, + final boolean isLoanOfficer, final Boolean isActive, final LocalDate joiningDate) { + this.office = staffOffice; + this.firstname = StringUtils.defaultIfEmpty(firstname, null); + this.lastname = StringUtils.defaultIfEmpty(lastname, null); + this.externalId = StringUtils.defaultIfEmpty(externalId, null); + this.mobileNo = StringUtils.defaultIfEmpty(mobileNo, null); + this.loanOfficer = isLoanOfficer; + this.active = (isActive == null) ? true : isActive; + deriveDisplayName(firstname); + if (joiningDate != null) { + this.joiningDate = joiningDate.toDateTimeAtStartOfDay().toDate(); + } + } + + public EnumOptionData organisationalRoleData() { + EnumOptionData organisationalRole = null; + if (this.organisationalRoleType != null) { + organisationalRole = StaffEnumerations.organisationalRole(this.organisationalRoleType); + } + return organisationalRole; + } + + public void changeOffice(final Office newOffice) { + this.office = newOffice; + } + + + public boolean isNotLoanOfficer() { + return !isLoanOfficer(); + } + + public boolean isLoanOfficer() { + return this.loanOfficer; + } + + public boolean isNotActive() { + return !isActive(); + } + + public boolean isActive() { + return this.active; + } + + private void deriveDisplayName(final String firstname) { + if (!StringUtils.isBlank(firstname)) { + this.displayName = this.lastname + ", " + this.firstname; + } else { + this.displayName = this.lastname; + } + } + + public boolean identifiedBy(final Staff staff) { + return getId().equals(staff.getId()); + } + + public String emailAddress() { + return emailAddress; + } + + public Long officeId() { + return this.office.getId(); + } + + public String displayName() { + return this.displayName; + } + + public String mobileNo() { + return this.mobileNo; + } + + public Office office() { + return this.office; + } + + public void setImage(Image image) { + this.image = image; + } + + public Image getImage() { + return this.image; + } +} diff --git a/ph-ee-operations-app/src/main/java/org/apache/fineract/organisation/staff/StaffData.java b/ph-ee-operations-app/src/main/java/org/apache/fineract/organisation/staff/StaffData.java new file mode 100644 index 000000000..3d6d97ea9 --- /dev/null +++ b/ph-ee-operations-app/src/main/java/org/apache/fineract/organisation/staff/StaffData.java @@ -0,0 +1,141 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.organisation.staff; + +import org.apache.fineract.organisation.office.OfficeData; +import org.joda.time.LocalDate; + +import java.util.Collection; + +/** + * Immutable data object representing staff data. + */ +public class StaffData { + + private final Long id; + private final String externalId; + private final String firstname; + private final String lastname; + private final String displayName; + private final String mobileNo; + private final Long officeId; + private final String officeName; + private final Boolean isLoanOfficer; + private final Boolean isActive; + private final LocalDate joiningDate; + + //import fields + private transient Integer rowIndex; + private String dateFormat; + private String locale; + + public static StaffData importInstance(String externalId, String firstName, String lastName, String mobileNo, Long officeId, Boolean isLoanOfficer, + Boolean isActive, LocalDate joinedOnDate, Integer rowIndex,String locale, String dateFormat){ + return new StaffData(externalId,firstName,lastName,mobileNo,officeId,isLoanOfficer,isActive, + joinedOnDate,rowIndex,locale,dateFormat); + + } + private StaffData(String externalId, String firstname, String lastname, String mobileNo, Long officeId, Boolean isLoanOfficer, + Boolean isActive, LocalDate joiningDate, Integer rowIndex,String locale, String dateFormat) { + + this.externalId = externalId; + this.firstname = firstname; + this.lastname = lastname; + this.mobileNo = mobileNo; + this.officeId = officeId; + this.isLoanOfficer = isLoanOfficer; + this.isActive = isActive; + this.joiningDate = joiningDate; + this.rowIndex = rowIndex; + this.dateFormat= dateFormat; + this.locale= locale; + this.allowedOffices = null; + this.id = null; + this.officeName = null; + this.displayName = null; + } + + public Integer getRowIndex() { + return rowIndex; + } + + @SuppressWarnings("unused") + private final Collection allowedOffices; + + public static StaffData templateData(final StaffData staff, final Collection allowedOffices) { + return new StaffData(staff.id, staff.firstname, staff.lastname, staff.displayName, staff.officeId, staff.officeName, + staff.isLoanOfficer, staff.externalId, staff.mobileNo, allowedOffices, staff.isActive, staff.joiningDate); + } + + public static StaffData lookup(final Long id, final String displayName) { + return new StaffData(id, null, null, displayName, null, null, null, null, null, null, null, null); + } + + public static StaffData instance(final Long id, final String firstname, final String lastname, final String displayName, + final Long officeId, final String officeName, final Boolean isLoanOfficer, final String externalId, final String mobileNo, + final boolean isActive, final LocalDate joiningDate) { + return new StaffData(id, firstname, lastname, displayName, officeId, officeName, isLoanOfficer, externalId, mobileNo, null, + isActive, joiningDate); + } + + private StaffData(final Long id, final String firstname, final String lastname, final String displayName, final Long officeId, + final String officeName, final Boolean isLoanOfficer, final String externalId, final String mobileNo, + final Collection allowedOffices, final Boolean isActive, final LocalDate joiningDate) { + this.id = id; + this.firstname = firstname; + this.lastname = lastname; + this.displayName = displayName; + this.officeName = officeName; + this.isLoanOfficer = isLoanOfficer; + this.externalId = externalId; + this.officeId = officeId; + this.mobileNo = mobileNo; + this.allowedOffices = allowedOffices; + this.isActive = isActive; + this.joiningDate = joiningDate; + } + + public Long getId() { + return this.id; + } + + public String getDisplayName() { + return this.displayName; + } + + public String getFirstname() { + return this.firstname; + } + + public String getLastname() { + return this.lastname; + } + + public String getOfficeName() { + return this.officeName; + } + + public LocalDate getJoiningDate() { + return this.joiningDate; + } + + public Long getOfficeId() { + return this.officeId; + } +} diff --git a/ph-ee-operations-app/src/main/java/org/apache/fineract/organisation/staff/StaffEnumerations.java b/ph-ee-operations-app/src/main/java/org/apache/fineract/organisation/staff/StaffEnumerations.java new file mode 100644 index 000000000..82fe58a58 --- /dev/null +++ b/ph-ee-operations-app/src/main/java/org/apache/fineract/organisation/staff/StaffEnumerations.java @@ -0,0 +1,48 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.organisation.staff; + +public class StaffEnumerations { + + public static EnumOptionData organisationalRole(final Integer id) { + return organisationalRole(StaffOrganisationalRoleType.fromInt(id)); + } + + public static EnumOptionData organisationalRole(final StaffOrganisationalRoleType type) { + EnumOptionData optionData = new EnumOptionData(StaffOrganisationalRoleType.INVALID.getValue().longValue(), + StaffOrganisationalRoleType.INVALID.getCode(), "Invalid"); + switch (type) { + case PROGRAM_DIRECTOR: + optionData = new EnumOptionData(type.getValue().longValue(), type.getCode(), "Program Director"); + break; + case BRANCH_MANAGER: + optionData = new EnumOptionData(type.getValue().longValue(), type.getCode(), "Branch Manager"); + break; + case FIELD_OFFICER_COORDINATOR: + optionData = new EnumOptionData(type.getValue().longValue(), type.getCode(), "Field Officer Coordinator"); + break; + case FIELD_OFFICER: + optionData = new EnumOptionData(type.getValue().longValue(), type.getCode(), "Field Officer"); + break; + case INVALID: + break; + } + return optionData; + } +} \ No newline at end of file diff --git a/ph-ee-operations-app/src/main/java/org/apache/fineract/organisation/staff/StaffOrganisationalRoleType.java b/ph-ee-operations-app/src/main/java/org/apache/fineract/organisation/staff/StaffOrganisationalRoleType.java new file mode 100644 index 000000000..1f6904118 --- /dev/null +++ b/ph-ee-operations-app/src/main/java/org/apache/fineract/organisation/staff/StaffOrganisationalRoleType.java @@ -0,0 +1,63 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.organisation.staff; + +public enum StaffOrganisationalRoleType { + + INVALID(0, "staffOrganisationalRoleType.invalid"), // + PROGRAM_DIRECTOR(100, "staffOrganisationalRoleType.programDirector"), // + BRANCH_MANAGER(200, "staffOrganisationalRoleType.branchManager"), // + FIELD_OFFICER_COORDINATOR(300, "staffOrganisationalRoleType.coordinator"), // + FIELD_OFFICER(400, "staffOrganisationalRoleType.fieldAgent"); + + private final Integer value; + private final String code; + + private StaffOrganisationalRoleType(final Integer value, final String code) { + this.value = value; + this.code = code; + } + + public Integer getValue() { + return this.value; + } + + public String getCode() { + return this.code; + } + + public static StaffOrganisationalRoleType fromInt(final Integer chargeCalculation) { + StaffOrganisationalRoleType chargeCalculationType = StaffOrganisationalRoleType.INVALID; + switch (chargeCalculation) { + case 100: + chargeCalculationType = PROGRAM_DIRECTOR; + break; + case 200: + chargeCalculationType = BRANCH_MANAGER; + break; + case 300: + chargeCalculationType = FIELD_OFFICER_COORDINATOR; + break; + case 400: + chargeCalculationType = FIELD_OFFICER; + break; + } + return chargeCalculationType; + } +} \ No newline at end of file diff --git a/ph-ee-operations-app/src/main/java/org/apache/fineract/organisation/staff/StaffRepository.java b/ph-ee-operations-app/src/main/java/org/apache/fineract/organisation/staff/StaffRepository.java new file mode 100644 index 000000000..ce0af36de --- /dev/null +++ b/ph-ee-operations-app/src/main/java/org/apache/fineract/organisation/staff/StaffRepository.java @@ -0,0 +1,32 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.organisation.staff; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; + + +public interface StaffRepository extends JpaRepository, JpaSpecificationExecutor { + + @Query("select s from Staff s where s.id = :id AND s.office.id = :officeId") + public Staff findByOffice(@Param("id") Long id, @Param("officeId") Long officeId); + +} \ No newline at end of file diff --git a/ph-ee-operations-app/src/main/java/org/apache/fineract/organisation/tenant/TenantServerConnection.java b/ph-ee-operations-app/src/main/java/org/apache/fineract/organisation/tenant/TenantServerConnection.java new file mode 100644 index 000000000..d87314b1a --- /dev/null +++ b/ph-ee-operations-app/src/main/java/org/apache/fineract/organisation/tenant/TenantServerConnection.java @@ -0,0 +1,99 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.organisation.tenant; + + +import org.apache.fineract.organisation.parent.AbstractPersistableCustom; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.Table; + +@Entity +@Table(name = "tenant_server_connections") +public class TenantServerConnection extends AbstractPersistableCustom { + + @Column(name = "schema_server") + private String schemaServer; + + @Column(name = "schema_name") + private String schemaName; + + @Column(name = "schema_server_port") + private String schemaServerPort; + + @Column(name = "schema_username") + private String schemaUsername; + + @Column(name = "schema_password") + private String schemaPassword; + + @Column(name = "auto_update") + private boolean autoUpdateEnabled; + + public TenantServerConnection() {} + + public String getSchemaServer() { + return schemaServer; + } + + public void setSchemaServer(String schemaServer) { + this.schemaServer = schemaServer; + } + + public String getSchemaName() { + return schemaName; + } + + public void setSchemaName(String schemaName) { + this.schemaName = schemaName; + } + + public String getSchemaServerPort() { + return schemaServerPort; + } + + public void setSchemaServerPort(String schemaServerPort) { + this.schemaServerPort = schemaServerPort; + } + + public String getSchemaUsername() { + return schemaUsername; + } + + public void setSchemaUsername(String schemaUsername) { + this.schemaUsername = schemaUsername; + } + + public String getSchemaPassword() { + return schemaPassword; + } + + public void setSchemaPassword(String schemaPassword) { + this.schemaPassword = schemaPassword; + } + + public boolean isAutoUpdateEnabled() { + return autoUpdateEnabled; + } + + public void setAutoUpdateEnabled(boolean autoUpdateEnabled) { + this.autoUpdateEnabled = autoUpdateEnabled; + } +} diff --git a/ph-ee-operations-app/src/main/java/org/apache/fineract/organisation/tenant/TenantServerConnectionRepository.java b/ph-ee-operations-app/src/main/java/org/apache/fineract/organisation/tenant/TenantServerConnectionRepository.java new file mode 100644 index 000000000..1b68e0f3c --- /dev/null +++ b/ph-ee-operations-app/src/main/java/org/apache/fineract/organisation/tenant/TenantServerConnectionRepository.java @@ -0,0 +1,28 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.organisation.tenant; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; + + +public interface TenantServerConnectionRepository extends JpaRepository, JpaSpecificationExecutor { + + TenantServerConnection findOneBySchemaName(String schemaName); +} \ No newline at end of file diff --git a/ph-ee-operations-app/src/main/java/org/apache/fineract/organisation/user/AppUser.java b/ph-ee-operations-app/src/main/java/org/apache/fineract/organisation/user/AppUser.java new file mode 100644 index 000000000..e8aab155c --- /dev/null +++ b/ph-ee-operations-app/src/main/java/org/apache/fineract/organisation/user/AppUser.java @@ -0,0 +1,274 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.organisation.user; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import org.apache.fineract.organisation.office.Office; +import org.apache.fineract.organisation.parent.AbstractPersistableCustom; +import org.apache.fineract.organisation.permission.Permission; +import org.apache.fineract.organisation.role.Role; +import org.apache.fineract.organisation.staff.Staff; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.security.core.userdetails.UserDetails; + +import javax.persistence.CascadeType; +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.JoinColumn; +import javax.persistence.JoinTable; +import javax.persistence.ManyToMany; +import javax.persistence.ManyToOne; +import javax.persistence.Table; +import javax.persistence.Temporal; +import javax.persistence.TemporalType; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Date; +import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; + +@Entity +@Table(name = "m_appuser") +public class AppUser extends AbstractPersistableCustom implements UserDetails { + + @Column(name = "email", nullable = false, length = 100) + private String email; + + @Column(name = "username", nullable = false, length = 100) + private String username; + + @Column(name = "firstname", nullable = false, length = 100) + private String firstname; + + @Column(name = "lastname", nullable = false, length = 100) + private String lastname; + + @Column(name = "password", nullable = false) + private String password; + + @Column(name = "nonexpired", nullable = false) + private boolean accountNonExpired; + + @Column(name = "nonlocked", nullable = false) + private boolean accountNonLocked; + + @Column(name = "nonexpired_credentials", nullable = false) + private boolean credentialsNonExpired; + + @Column(name = "enabled", nullable = false) + private boolean enabled; + + @Column(name = "firsttime_login_remaining", nullable = false) + private boolean firstTimeLoginRemaining; + + @Column(name = "is_deleted", nullable = false) + private boolean deleted; + + @ManyToOne + @JoinColumn(name = "office_id", nullable = false) + private Office office; + + @ManyToOne + @JoinColumn(name = "staff_id", nullable = true) + private Staff staff; + + @ManyToMany(fetch = FetchType.LAZY, cascade = {CascadeType.REFRESH, CascadeType.DETACH, CascadeType.PERSIST, CascadeType.MERGE}) + @JoinTable(name = "m_appuser_role", joinColumns = @JoinColumn(name = "appuser_id"), inverseJoinColumns = @JoinColumn(name = "role_id")) + private Collection roles; + + @Column(name = "last_time_password_updated") + @Temporal(TemporalType.DATE) + private Date lastTimePasswordUpdated; + + @Column(name = "password_never_expires", nullable = false) + private boolean passwordNeverExpires; + + @Override + @JsonIgnore + public Collection getAuthorities() { + List finalPermissions = new ArrayList<>(); + for (final Role role : this.getRoles()) { + if (!role.getDisabled()) { + final Collection permissions = role.getPermissions(); + for (final Permission permission : permissions) { + if(!finalPermissions.contains(permission)) { + finalPermissions.add(permission); + } + } + } + } + + return finalPermissions.stream() + .map(p -> new SimpleGrantedAuthority(p.getCode())) + .collect(Collectors.toList()); + } + + @Override + public String getPassword() { + return this.password; + } + + @Override + public String getUsername() { + return this.username; + } + + @Override + public boolean isAccountNonExpired() { + return this.accountNonExpired; + } + + @Override + public boolean isAccountNonLocked() { + return this.accountNonLocked; + } + + @Override + public boolean isCredentialsNonExpired() { + return this.credentialsNonExpired; + } + + @Override + public boolean isEnabled() { + return this.enabled; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } + + public void setUsername(String username) { + this.username = username; + } + + public String getFirstname() { + return firstname; + } + + public void setFirstname(String firstname) { + this.firstname = firstname; + } + + public String getLastname() { + return lastname; + } + + public void setLastname(String lastname) { + this.lastname = lastname; + } + + public void setPassword(String password) { + this.password = password; + } + + public void setAccountNonExpired(boolean accountNonExpired) { + this.accountNonExpired = accountNonExpired; + } + + public void setAccountNonLocked(boolean accountNonLocked) { + this.accountNonLocked = accountNonLocked; + } + + public void setCredentialsNonExpired(boolean credentialsNonExpired) { + this.credentialsNonExpired = credentialsNonExpired; + } + + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } + + public boolean isFirstTimeLoginRemaining() { + return firstTimeLoginRemaining; + } + + public void setFirstTimeLoginRemaining(boolean firstTimeLoginRemaining) { + this.firstTimeLoginRemaining = firstTimeLoginRemaining; + } + + public boolean isDeleted() { + return deleted; + } + + public void setDeleted(boolean deleted) { + this.deleted = deleted; + } + + @JsonIgnore + public Office getOffice() { + return office; + } + + public void setOffice(Office office) { + this.office = office; + } + + @JsonIgnore + public Staff getStaff() { + return staff; + } + + public void setStaff(Staff staff) { + this.staff = staff; + } + + @JsonIgnore + public Collection getRoles() { + return roles; + } + + public void setRoles(Collection roles) { + this.roles = roles; + } + + public Date getLastTimePasswordUpdated() { + return lastTimePasswordUpdated; + } + + public void setLastTimePasswordUpdated(Date lastTimePasswordUpdated) { + this.lastTimePasswordUpdated = lastTimePasswordUpdated; + } + + public boolean isPasswordNeverExpires() { + return passwordNeverExpires; + } + + public void setPasswordNeverExpires(boolean passwordNeverExpires) { + this.passwordNeverExpires = passwordNeverExpires; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + AppUser appUser = (AppUser) o; + return Objects.equals(username, appUser.username); + } + + @Override + public int hashCode() { + return Objects.hash(username); + } +} \ No newline at end of file diff --git a/ph-ee-operations-app/src/main/java/org/apache/fineract/organisation/user/AppUserData.java b/ph-ee-operations-app/src/main/java/org/apache/fineract/organisation/user/AppUserData.java new file mode 100644 index 000000000..4c7459332 --- /dev/null +++ b/ph-ee-operations-app/src/main/java/org/apache/fineract/organisation/user/AppUserData.java @@ -0,0 +1,180 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.organisation.user; + +import org.apache.fineract.organisation.office.OfficeData; +import org.apache.fineract.organisation.role.RoleData; +import org.apache.fineract.organisation.staff.StaffData; + +import java.util.Collection; +import java.util.Objects; + + +public class AppUserData { + + private Long id; + private String username; + private Long officeId; + private String officeName; + private String firstname; + private String lastname; + private String email; + private Boolean passwordNeverExpires; + private Collection allowedOffices; + private Collection availableRoles; + private Collection selectedRoles; + private StaffData staff; + + public AppUserData() {} + + public AppUserData(Long id, String username, Long officeId, String officeName, String firstname, String lastname, String email, Boolean passwordNeverExpires, Collection allowedOffices, Collection availableRoles, Collection selectedRoles, StaffData staff) { + this.id = id; + this.username = username; + this.officeId = officeId; + this.officeName = officeName; + this.firstname = firstname; + this.lastname = lastname; + this.email = email; + this.passwordNeverExpires = passwordNeverExpires; + this.allowedOffices = allowedOffices; + this.availableRoles = availableRoles; + this.selectedRoles = selectedRoles; + this.staff = staff; + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public Long getOfficeId() { + return officeId; + } + + public void setOfficeId(Long officeId) { + this.officeId = officeId; + } + + public String getOfficeName() { + return officeName; + } + + public void setOfficeName(String officeName) { + this.officeName = officeName; + } + + public String getFirstname() { + return firstname; + } + + public void setFirstname(String firstname) { + this.firstname = firstname; + } + + public String getLastname() { + return lastname; + } + + public void setLastname(String lastname) { + this.lastname = lastname; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } + + public Boolean getPasswordNeverExpires() { + return passwordNeverExpires; + } + + public void setPasswordNeverExpires(Boolean passwordNeverExpires) { + this.passwordNeverExpires = passwordNeverExpires; + } + + public Collection getAllowedOffices() { + return allowedOffices; + } + + public void setAllowedOffices(Collection allowedOffices) { + this.allowedOffices = allowedOffices; + } + + public Collection getAvailableRoles() { + return availableRoles; + } + + public void setAvailableRoles(Collection availableRoles) { + this.availableRoles = availableRoles; + } + + public Collection getSelectedRoles() { + return selectedRoles; + } + + public void setSelectedRoles(Collection selectedRoles) { + this.selectedRoles = selectedRoles; + } + + public StaffData getStaff() { + return staff; + } + + public void setStaff(StaffData staff) { + this.staff = staff; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + AppUserData that = (AppUserData) o; + return Objects.equals(id, that.id) && + Objects.equals(username, that.username) && + Objects.equals(officeId, that.officeId) && + Objects.equals(officeName, that.officeName) && + Objects.equals(firstname, that.firstname) && + Objects.equals(lastname, that.lastname) && + Objects.equals(email, that.email) && + Objects.equals(passwordNeverExpires, that.passwordNeverExpires) && + Objects.equals(allowedOffices, that.allowedOffices) && + Objects.equals(availableRoles, that.availableRoles) && + Objects.equals(selectedRoles, that.selectedRoles) && + Objects.equals(staff, that.staff); + } + + @Override + public int hashCode() { + return Objects.hash(id, username, officeId, officeName, firstname, lastname, email, passwordNeverExpires, allowedOffices, availableRoles, selectedRoles, staff); + } +} \ No newline at end of file diff --git a/ph-ee-operations-app/src/main/java/org/apache/fineract/organisation/user/AppUserRepository.java b/ph-ee-operations-app/src/main/java/org/apache/fineract/organisation/user/AppUserRepository.java new file mode 100644 index 000000000..1d0c02a11 --- /dev/null +++ b/ph-ee-operations-app/src/main/java/org/apache/fineract/organisation/user/AppUserRepository.java @@ -0,0 +1,30 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.organisation.user; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; + +public interface AppUserRepository extends JpaRepository, JpaSpecificationExecutor { + + @Query("Select appUser from AppUser appUser where appUser.username = :username") + AppUser findAppUserByName(@Param("username") String username); +} diff --git a/ph-ee-operations-app/src/main/java/org/apache/fineract/response/BatchAndSubBatchSummaryResponse.java b/ph-ee-operations-app/src/main/java/org/apache/fineract/response/BatchAndSubBatchSummaryResponse.java new file mode 100644 index 000000000..cb95ac979 --- /dev/null +++ b/ph-ee-operations-app/src/main/java/org/apache/fineract/response/BatchAndSubBatchSummaryResponse.java @@ -0,0 +1,73 @@ +package org.apache.fineract.response; + +import com.fasterxml.jackson.annotation.JsonInclude; +import lombok.Getter; +import lombok.Setter; + +import java.math.BigDecimal; +import java.util.Date; +import java.util.List; +import java.util.Set; + +@Getter +@Setter +public class BatchAndSubBatchSummaryResponse { + + private String batchId; + + private String requestId; + + private Date startedAt; + + private Date completedAt; + + private String registeringInstitutionId; + + private Long total; + + private Long ongoing; + + private Long successful; + + private Long failed; + + private BigDecimal totalAmount; + + private BigDecimal pendingAmount; + + private BigDecimal successfulAmount; + + private BigDecimal failedAmount; + + private String file; + + private String notes; + + private String createdAt; + + private String status; + + private String modes; + + private String purpose; + + private String failedPercentage; + + private String successPercentage; + + private String payerFsp; + private Set payeeFsp; + + private String generatedBy; + + private String generatedAt; + + private Long totalSubBatches; + + private Long approvedTransactionCount; + + private Long approvedAmount; + @JsonInclude(JsonInclude.Include.NON_NULL) + private List subBatchSummaryList; + private Long totalInstructionCount; +} diff --git a/ph-ee-operations-app/src/main/java/org/apache/fineract/response/SubBatchSummary.java b/ph-ee-operations-app/src/main/java/org/apache/fineract/response/SubBatchSummary.java new file mode 100644 index 000000000..27b26f3cd --- /dev/null +++ b/ph-ee-operations-app/src/main/java/org/apache/fineract/response/SubBatchSummary.java @@ -0,0 +1,77 @@ +package org.apache.fineract.response; + +import lombok.Getter; +import lombok.Setter; +import org.apache.fineract.operations.Instruction; + +import java.math.BigDecimal; +import java.util.Date; +import java.util.List; +import java.util.Set; + +@Getter +@Setter +public class SubBatchSummary { + private String subBatchId; + + private String batchId; + + private Date startedAt; + + private Date completedAt; + + private String registeringInstitutionId; + + private String requestId; + + private Long total; + + private Long ongoing; + + private Long successful; + + private Long failed; + + private BigDecimal totalAmount; + + private BigDecimal pendingAmount; + + private BigDecimal successfulAmount; + + private BigDecimal failedAmount; + + private String file; + + private String notes; + + private String createdAt; + + private String status; + + private String modes; + + private String purpose; + + private String failedPercentage; + + private String successPercentage; + + private String payerFsp; + + private Long approvedAmount; + + private Long approvedTransactionCount; + + private Set payeeFspSet; + + private List instructionList; + + private String budgetAccount; + + private String generatedBy; + + private String generatedAt; + + private Long totalInstructionCount; + +} diff --git a/ph-ee-operations-app/src/main/java/org/apache/fineract/service/BatchDbService.java b/ph-ee-operations-app/src/main/java/org/apache/fineract/service/BatchDbService.java new file mode 100644 index 000000000..1a2f418ee --- /dev/null +++ b/ph-ee-operations-app/src/main/java/org/apache/fineract/service/BatchDbService.java @@ -0,0 +1,20 @@ +package org.apache.fineract.service; + +import org.apache.fineract.operations.BatchPaginatedResponse; +import org.springframework.data.domain.PageRequest; +import org.springframework.stereotype.Service; + +@Service +public interface BatchDbService { + + public BatchPaginatedResponse getBatch(String startFrom, String startTo, String registeringInstitutionId, + String payerFsp, String batchId, PageRequest pager); + + public BatchPaginatedResponse getBatch(String registeringInstitutionId, String payerFsp, String batchId, PageRequest pager); + + public BatchPaginatedResponse getBatchDateTo(String startTo, String registeringInstitutionId, + String payerFsp, String batchId, PageRequest pager); + + public BatchPaginatedResponse getBatchDateFrom(String startFrom, String registeringInstitutionId, + String payerFsp, String batchId, PageRequest pager); +} diff --git a/ph-ee-operations-app/src/main/java/org/apache/fineract/service/BatchDbServiceImpl.java b/ph-ee-operations-app/src/main/java/org/apache/fineract/service/BatchDbServiceImpl.java new file mode 100644 index 000000000..84530270c --- /dev/null +++ b/ph-ee-operations-app/src/main/java/org/apache/fineract/service/BatchDbServiceImpl.java @@ -0,0 +1,289 @@ +package org.apache.fineract.service; + +import lombok.extern.slf4j.Slf4j; +import org.apache.fineract.core.service.ThreadLocalContextUtil; +import org.apache.fineract.operations.Batch; +import org.apache.fineract.operations.BatchPaginatedResponse; +import org.apache.fineract.operations.BatchRepository; +import org.apache.fineract.organisation.tenant.TenantServerConnection; +import org.springframework.data.domain.PageRequest; +import org.springframework.stereotype.Service; +import java.util.Date; +import java.util.List; +import java.util.Optional; +import java.util.concurrent.CompletableFuture; +import static org.apache.fineract.core.service.OperatorUtils.dateFormat; + +/** + * For all the date part use the below format and make sure to pass the local date + * DD:MM:YYYY hh:mm:ss + */ +@Slf4j +@Service +public class BatchDbServiceImpl implements BatchDbService { + + private final BatchRepository batchRepository; + + public BatchDbServiceImpl(BatchRepository batchRepository) { + this.batchRepository = batchRepository; + } + + @Override + public BatchPaginatedResponse getBatch(String startFrom, String startTo, String registeringInstitutionId, String payerFsp, String batchId, PageRequest pager) { + try { + Date startDateObject = dateFormat().parse(startFrom); + Date endDateObject = dateFormat().parse(startTo); + TenantServerConnection connection = ThreadLocalContextUtil.getTenant(); + + CompletableFuture> totalTransactionsAsync = + CompletableFuture.supplyAsync(() -> { + ThreadLocalContextUtil.setTenant(connection); + return batchRepository.getTotalTransactionsDateBetween( + startDateObject, endDateObject, + registeringInstitutionId, payerFsp, batchId); + }); + CompletableFuture> totalAmountAsync = + CompletableFuture.supplyAsync(() -> { + ThreadLocalContextUtil.setTenant(connection); + return batchRepository.getTotalAmountDateBetween( + startDateObject, endDateObject, + registeringInstitutionId, payerFsp, batchId); + }); + CompletableFuture> totalBatchesAsync = + CompletableFuture.supplyAsync(() -> { + ThreadLocalContextUtil.setTenant(connection); + return batchRepository.getTotalBatchesDateBetween( + startDateObject, endDateObject, + registeringInstitutionId, payerFsp, batchId); + }); + CompletableFuture> totalApprovedCountAsync = + CompletableFuture.supplyAsync(() -> { + ThreadLocalContextUtil.setTenant(connection); + return batchRepository.getTotalApprovedCountDateBetween( + startDateObject, endDateObject, + registeringInstitutionId, payerFsp, batchId); + }); + CompletableFuture> totalApprovedAmountAsync = + CompletableFuture.supplyAsync(() -> { + ThreadLocalContextUtil.setTenant(connection); + return batchRepository.getTotalApprovedAmountDateBetween( + startDateObject, endDateObject, + registeringInstitutionId, payerFsp, batchId); + }); + CompletableFuture> batchesAsync = + CompletableFuture.supplyAsync(() -> { + ThreadLocalContextUtil.setTenant(connection); + return batchRepository.findAllFilterDateBetween( + startDateObject, endDateObject, + registeringInstitutionId, payerFsp, batchId, + pager); + }); + + CompletableFuture allTasks = CompletableFuture.allOf(totalTransactionsAsync, totalAmountAsync, + totalBatchesAsync, totalApprovedCountAsync, totalApprovedAmountAsync, batchesAsync); + allTasks.join(); + + Optional totalTransactions = totalTransactionsAsync.join(); + Optional totalAmount = totalAmountAsync.join(); + Optional totalBatches = totalBatchesAsync.join(); + Optional totalApprovedCount = totalApprovedCountAsync.join(); + Optional totalApprovedAmount = totalApprovedAmountAsync.join(); + List batches = batchesAsync.join(); + + return getBatchPaginatedResponseInstance(totalBatches.orElse(0L), totalTransactions.orElse(0L), + totalAmount.orElse(0L), totalApprovedCount.orElse(0L), + totalApprovedAmount.orElse(0L), 10, batches); + } catch (Exception e) { + log.warn("failed to parse dates {} / {}", startFrom, startTo); + return null; + } + } + + @Override + public BatchPaginatedResponse getBatch(String registeringInstitutionId, String payerFsp, String batchId, PageRequest pager) { + log.info("Get batch function"); + TenantServerConnection connection = ThreadLocalContextUtil.getTenant(); + + CompletableFuture> totalTransactionsAsync = CompletableFuture.supplyAsync(() -> { + ThreadLocalContextUtil.setTenant(connection); + return batchRepository.getTotalTransactions(registeringInstitutionId, payerFsp, batchId); + }); + CompletableFuture> totalAmountAsync = CompletableFuture.supplyAsync(() -> { + ThreadLocalContextUtil.setTenant(connection); + return batchRepository.getTotalAmount(registeringInstitutionId, payerFsp, batchId); + }); + CompletableFuture> totalBatchesAsync = CompletableFuture.supplyAsync(() -> { + ThreadLocalContextUtil.setTenant(connection); + return batchRepository.getTotalBatches(registeringInstitutionId, payerFsp, batchId); + }); + CompletableFuture> totalApprovedCountAsync = CompletableFuture.supplyAsync(() -> { + ThreadLocalContextUtil.setTenant(connection); + return batchRepository.getTotalApprovedCount(registeringInstitutionId, payerFsp, batchId); + }); + CompletableFuture> totalApprovedAmountAsync = CompletableFuture.supplyAsync(() -> { + ThreadLocalContextUtil.setTenant(connection); + return batchRepository.getTotalApprovedAmount(registeringInstitutionId, payerFsp, batchId); + }); + CompletableFuture> batchesAsync = CompletableFuture.supplyAsync(() -> { + ThreadLocalContextUtil.setTenant(connection); + return batchRepository.findAllBatch(registeringInstitutionId, payerFsp, batchId, pager); + }); + + CompletableFuture allTasks = CompletableFuture.allOf(totalTransactionsAsync, totalAmountAsync, + totalBatchesAsync, totalApprovedCountAsync, totalApprovedAmountAsync, batchesAsync); + allTasks.join(); + + Optional totalTransactions = totalTransactionsAsync.join(); + Optional totalAmount = totalAmountAsync.join(); + Optional totalBatches = totalBatchesAsync.join(); + Optional totalApprovedCount = totalApprovedCountAsync.join(); + Optional totalApprovedAmount = totalApprovedAmountAsync.join(); + List batches = batchesAsync.join(); + return getBatchPaginatedResponseInstance(totalBatches.orElse(0L), totalTransactions.orElse(0L), + totalAmount.orElse(0L), totalApprovedCount.orElse(0L), + totalApprovedAmount.orElse(0L), 10, batches); + } + + @Override + public BatchPaginatedResponse getBatchDateTo(String startTo, String registeringInstitutionId, String payerFsp, String batchId, PageRequest pager) { + try { + Date endDateObject = dateFormat().parse(startTo); + TenantServerConnection connection = ThreadLocalContextUtil.getTenant(); + + CompletableFuture> totalTransactionsAsync = CompletableFuture.supplyAsync(() -> { + ThreadLocalContextUtil.setTenant(connection); + return batchRepository.getTotalTransactionsDateTo( + endDateObject, + registeringInstitutionId, payerFsp, batchId); + }); + CompletableFuture> totalAmountAsync = CompletableFuture.supplyAsync(() -> { + ThreadLocalContextUtil.setTenant(connection); + return batchRepository.getTotalAmountDateTo( + endDateObject, + registeringInstitutionId, payerFsp, batchId); + }); + CompletableFuture> totalBatchesAsync = CompletableFuture.supplyAsync(() -> { + ThreadLocalContextUtil.setTenant(connection); + return batchRepository.getTotalBatchesDateTo( + endDateObject, + registeringInstitutionId, payerFsp, batchId); + }); + CompletableFuture> totalApprovedCountAsync = CompletableFuture.supplyAsync(() -> { + ThreadLocalContextUtil.setTenant(connection); + return batchRepository.getTotalApprovedCountDateTo( + endDateObject, + registeringInstitutionId, payerFsp, batchId); + }); + CompletableFuture> totalApprovedAmountAsync = CompletableFuture.supplyAsync(() -> { + ThreadLocalContextUtil.setTenant(connection); + return batchRepository.getTotalApprovedAmountDateTo( + endDateObject, + registeringInstitutionId, payerFsp, batchId); + }); + CompletableFuture> batchesAsync = CompletableFuture.supplyAsync(() -> { + ThreadLocalContextUtil.setTenant(connection); + return batchRepository.findAllFilterDateTo( + endDateObject, + registeringInstitutionId, payerFsp, batchId, pager); + }); + + CompletableFuture allTasks = CompletableFuture.allOf(totalTransactionsAsync, totalAmountAsync, + totalBatchesAsync, totalApprovedCountAsync, totalApprovedAmountAsync, batchesAsync); + allTasks.join(); + + Optional totalTransactions = totalTransactionsAsync.join(); + Optional totalAmount = totalAmountAsync.join(); + Optional totalBatches = totalBatchesAsync.join(); + Optional totalApprovedCount = totalApprovedCountAsync.join(); + Optional totalApprovedAmount = totalApprovedAmountAsync.join(); + List batches = batchesAsync.join(); + return getBatchPaginatedResponseInstance(totalBatches.orElse(0L), totalTransactions.orElse(0L), + totalAmount.orElse(0L), totalApprovedCount.orElse(0L), + totalApprovedAmount.orElse(0L), 10, batches); + } catch (Exception e) { + log.warn("failed to parse startTo date {}", startTo); + return null; + } + } + + @Override + public BatchPaginatedResponse getBatchDateFrom(String startFrom, String registeringInstitutionId, String payerFsp, String batchId, PageRequest pager) { + try { + Date startDateObject = dateFormat().parse(startFrom); + TenantServerConnection connection = ThreadLocalContextUtil.getTenant(); + + CompletableFuture> totalTransactionsAsync = CompletableFuture.supplyAsync(() -> { + ThreadLocalContextUtil.setTenant(connection); + return batchRepository.getTotalTransactionsDateFrom( + startDateObject, + registeringInstitutionId, payerFsp, batchId); + }); + CompletableFuture> totalAmountAsync = CompletableFuture.supplyAsync(() -> { + ThreadLocalContextUtil.setTenant(connection); + return batchRepository.getTotalAmountDateFrom( + startDateObject, + registeringInstitutionId, payerFsp, batchId); + }); + CompletableFuture> totalBatchesAsync = CompletableFuture.supplyAsync(() -> { + ThreadLocalContextUtil.setTenant(connection); + return batchRepository.getTotalBatchesDateFrom( + startDateObject, + registeringInstitutionId, payerFsp, batchId); + }); + CompletableFuture> totalApprovedCountAsync = CompletableFuture.supplyAsync(() -> { + ThreadLocalContextUtil.setTenant(connection); + return batchRepository.getTotalApprovedCountDateFrom( + startDateObject, + registeringInstitutionId, payerFsp, batchId); + }); + CompletableFuture> totalApprovedAmountAsync = CompletableFuture.supplyAsync(() -> { + ThreadLocalContextUtil.setTenant(connection); + return batchRepository.getTotalApprovedAmountDateFrom( + startDateObject, + registeringInstitutionId, payerFsp, batchId); + }); + CompletableFuture> batchesAsync = CompletableFuture.supplyAsync(() -> { + ThreadLocalContextUtil.setTenant(connection); + return batchRepository.findAllFilterDateFrom( + startDateObject, + registeringInstitutionId, payerFsp, batchId, pager); + }); + + CompletableFuture allTasks = CompletableFuture.allOf(totalTransactionsAsync, totalAmountAsync, + totalBatchesAsync, totalApprovedCountAsync, totalApprovedAmountAsync, batchesAsync); + allTasks.join(); + + Optional totalTransactions = totalTransactionsAsync.join(); + Optional totalAmount = totalAmountAsync.join(); + Optional totalBatches = totalBatchesAsync.join(); + Optional totalApprovedCount = totalApprovedCountAsync.join(); + Optional totalApprovedAmount = totalApprovedAmountAsync.join(); + List batches = batchesAsync.join(); + return getBatchPaginatedResponseInstance(totalBatches.orElse(0L), totalTransactions.orElse(0L), + totalAmount.orElse(0L), totalApprovedCount.orElse(0L), + totalApprovedAmount.orElse(0L), 10, batches); + } catch (Exception e) { + log.warn("failed to parse startFrom date {}", startFrom); + return null; + } + } + + + private BatchPaginatedResponse getBatchPaginatedResponseInstance(long totalBatches, long totalTransactions, + long totalAmount, long totalApprovedCount, + long totalApprovedAmount, + long totalSubBatchesCreated, List batches) { + log.info("Inside getBatchPaginatedResponseInstance"); + log.info("TotalBatch: {}, TotalTransactions: {}, Total Amount: {}, Batches: {}", + totalBatches, totalTransactions, totalAmount, batches.size()); + BatchPaginatedResponse batchPaginatedResponse = new BatchPaginatedResponse(); + batchPaginatedResponse.setData(batches); + batchPaginatedResponse.setTotalBatches(totalBatches); + batchPaginatedResponse.setTotalTransactions(totalTransactions); + batchPaginatedResponse.setTotalAmount(totalAmount); + batchPaginatedResponse.setTotalApprovedCount(totalApprovedCount); + batchPaginatedResponse.setTotalApprovedAmount(totalApprovedAmount); + batchPaginatedResponse.setTotalSubBatchesCreated(totalSubBatchesCreated); + return batchPaginatedResponse; + } +} diff --git a/ph-ee-operations-app/src/main/java/org/apache/fineract/service/BatchService.java b/ph-ee-operations-app/src/main/java/org/apache/fineract/service/BatchService.java new file mode 100644 index 000000000..761a96fc9 --- /dev/null +++ b/ph-ee-operations-app/src/main/java/org/apache/fineract/service/BatchService.java @@ -0,0 +1,12 @@ +package org.apache.fineract.service; + +import org.apache.fineract.operations.PaymentBatchDetail; +import org.apache.fineract.operations.SubBatch; +import org.apache.fineract.response.BatchAndSubBatchSummaryResponse; +import org.apache.fineract.response.SubBatchSummary; + +public interface BatchService { + BatchAndSubBatchSummaryResponse getBatchAndSubBatchSummary(String batchId, String clientCorrelationId); + PaymentBatchDetail getPaymentBathDetail(String batchId, String clientCorrelationId, int offset, int limit, String orderBy, String sortBy); + SubBatchSummary getPaymentSubBatchDetail(String batchId, String subBatchId, String clientCorrelationId, int offset, int limit, String orderBy, String sortBy); +} diff --git a/ph-ee-operations-app/src/main/java/org/apache/fineract/service/BatchServiceImpl.java b/ph-ee-operations-app/src/main/java/org/apache/fineract/service/BatchServiceImpl.java new file mode 100644 index 000000000..fcee61b98 --- /dev/null +++ b/ph-ee-operations-app/src/main/java/org/apache/fineract/service/BatchServiceImpl.java @@ -0,0 +1,360 @@ +package org.apache.fineract.service; + +import lombok.extern.slf4j.Slf4j; +import org.apache.fineract.operations.*; +import org.apache.fineract.response.BatchAndSubBatchSummaryResponse; +import org.apache.fineract.response.SubBatchSummary; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort; +import org.springframework.stereotype.Service; +import org.springframework.util.CollectionUtils; +import org.springframework.util.StringUtils; + +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.text.DecimalFormat; +import java.time.LocalDateTime; +import java.util.*; + +@Slf4j +@Service +public class BatchServiceImpl implements BatchService{ + + @Autowired + private BatchRepository batchRepository; + @Autowired + private TransferRepository transferRepository; + private static long subBatchAmount; + private static long subBatchCount; + private static Set payeeFspSet; + + + @Override + public BatchAndSubBatchSummaryResponse getBatchAndSubBatchSummary(String batchId, String clientCorrelationId) { + + List batchAndSubBatches = batchRepository.findAllByBatchId(batchId); + + if(CollectionUtils.isEmpty(batchAndSubBatches)){ + return null; + } + + BatchAndSubBatchSummaryResponse response = new BatchAndSubBatchSummaryResponse(); + subBatchCount=0; + subBatchAmount=0; + Long totalSubBatch = 0L; + + for(Batch batch : batchAndSubBatches){ + if(StringUtils.isEmpty(batch.getSubBatchId())){ + updateResponseWithBatchInfo(batch, response); + } + else{ + SubBatchSummary subBatchSummary = updateResponseWithSubBatchInfo(batch, response); + totalSubBatch++; + response.getSubBatchSummaryList().add(subBatchSummary); + } + } + response.setApprovedTransactionCount(subBatchCount); + response.setApprovedAmount(subBatchAmount); + response.setTotalSubBatches(totalSubBatch); + + return response; + } + + @Override + public PaymentBatchDetail getPaymentBathDetail(String batchId, String clientCorrelationId, int offset, int limit, String orderBy, String sortBy) { + List batchAndSubBatches = batchRepository.findAllByBatchId(batchId); + //List subBatchList = batchRepository.findAllSubBatchId(batchId); + //Batch batch = batchRepository.findByBatchId(batchId); + if (CollectionUtils.isEmpty(batchAndSubBatches)) { + return null; + } + List allInstructions = new ArrayList<>(); + PaymentBatchDetail response = new PaymentBatchDetail(); + subBatchCount = 0; + subBatchAmount = 0; + List subBatchSummaryList = new ArrayList<>(); + if (batchAndSubBatches.size() == 1) { + //Batch batch = batchAndSubBatches.get(0); + updatePaymentDetailBatchInfo(batchAndSubBatches.get(0), response); + int pageNumber = (offset / limit) ; + Page transferList = transferRepository.findAllByBatchId(batchId, new PageRequest(pageNumber, limit)); + List instructionList = generateInstructionList(transferList.getContent(),orderBy,sortBy); + response.setInstructionList(instructionList); + response.setTotalInstruction(batchAndSubBatches.get(0).getTotalTransactions()); + return response; + } + Long totalInstruction = 0L; + for(Batch batch : batchAndSubBatches) { + if (StringUtils.isEmpty(batch.getSubBatchId())) { + updatePaymentDetailBatchInfo(batch, response); + } else { + payeeFspSet = new HashSet<>(); + int pageNumber = (offset / limit); + Page transferList = transferRepository.findAllByBatchId(batch.getSubBatchId(), new PageRequest(pageNumber, limit)); + + log.info(transferList.toString()); + List instructionList = generateInstructionList(transferList.getContent(),orderBy,sortBy); + allInstructions.addAll(instructionList); + + SubBatchSummary subBatch = updateSubBatchPaymentDetail(batch, response); + Long subBatchCount = transferRepository.countAllByBatchId(batch.getSubBatchId()); + totalInstruction += subBatchCount; + subBatchSummaryList.add(subBatch); + + } + } +/* updatePaymentDetailBatchInfo(batch, response); + for(Batch subBatches : subBatchList) { + payeeFspSet = new HashSet<>(); + int pageNumber = (offset / limit); + Page transferList = transferRepository.findAllByBatchId(batch.getSubBatchId(), new PageRequest(pageNumber, limit)); + log.info(subBatches.getBatchId()); + log.info(transferList.toString()); + List instructionList = generateInstructionList(transferList.getContent(),orderBy,sortBy); + allInstructions.addAll(instructionList); + + SubBatchSummary subBatch = updateSubBatchPaymentDetail(batch, response); + Long subBatchCount = transferRepository.countAllByBatchId(batch.getSubBatchId()); + totalInstruction += subBatchCount; + subBatchSummaryList.add(subBatch); + }*/ + response.setInstructionList(allInstructions); + response.setTotalInstruction(subBatchCount); + response.setSubBatchList(subBatchSummaryList); + return response; + } + public List generateInstructionList(List transferList, String orderBy, String sortBy){ + List instructionList = new ArrayList<>(); + + for (Transfer transfer : transferList) { + log.info(String.valueOf(transfer)); + Instruction instruction = new Instruction(); + instruction.setInstructionId(transfer.getTransactionId()); + instruction.setPayerFsp(transfer.getPayerDfspId() != null ? transfer.getPayerDfspId() : null); + instruction.setPayeeFunctionalId(transfer.getPayeePartyId() != null ? transfer.getPayeePartyId() : null); + instruction.setAmount(transfer.getAmount() != null ? transfer.getAmount() : BigDecimal.valueOf(0)); + instruction.setStatus(transfer.getStatus() != null ? transfer.getStatus() : null); + instruction.setStartedAt(transfer.getStartedAt() != null ? transfer.getStartedAt() : null); + instruction.setCompletedAt(transfer.getCompletedAt() != null ? transfer.getCompletedAt() : null); + instruction.setSubBatchId(transfer.getBatchId() != null ? transfer.getBatchId() : null); + if (transfer.getPayeeDfspId() != null) { + payeeFspSet.add(transfer.getPayeeDfspId()); + } + + instructionList.add(instruction); + } + Comparator comparator = null; + Boolean validOrderBy = true; + + if ("instructionId".equals(orderBy)) { + comparator = Comparator.comparing(Instruction::getPayerFsp); + } else if ("payeeFunctionalId".equals(orderBy)) { + comparator = Comparator.comparing(Instruction::getPayeeFunctionalId); + } else if ("subBatchId".equals(orderBy)) { + comparator = Comparator.comparing(Instruction::getAmount); + } else { + validOrderBy=false; + } + + if ("desc".equalsIgnoreCase(sortBy) && validOrderBy && comparator != null) { + comparator = comparator.reversed(); + } + return instructionList; + } + + @Override + public SubBatchSummary getPaymentSubBatchDetail(String batchId, String subBatchId, String clientCorrelationId, int offset, int limit, String orderBy, String sortBy) { + Batch batch = batchRepository.findBySubBatchId(subBatchId); + SubBatchSummary subBatch = new SubBatchSummary(); + subBatch.setSubBatchId(subBatchId); + subBatch.setPayerFsp(batch.getPayerFsp() != null ? batch.getPayerFsp() : null); + subBatch.setGeneratedAt(LocalDateTime.now().toString()); + subBatch.setBatchId(batchId); + + Long totalInstructionCount = transferRepository.countAllByBatchId(subBatchId); + //List transferList = transferRepository.findAllByBatchId(subBatchId); + int pageNumber = (offset / limit) ; + List transferList = transferRepository.findAllByBatchId(subBatchId); + + + List instructionList = new ArrayList<>(); + + for (Transfer transfer : transferList) { + Instruction instruction = new Instruction(); + instruction.setInstructionId(transfer.getTransactionId()); + instruction.setPayeeFunctionalId(transfer.getPayeePartyId() != null ? transfer.getPayerPartyId() : null); + instruction.setPayerFsp(transfer.getPayerDfspId() != null ? transfer.getPayerDfspId() : null); + instruction.setAmount(transfer.getAmount() != null ? transfer.getAmount() : null); + instruction.setStatus(transfer.getStatus() != null ? transfer.getStatus() : null); + instruction.setReason(transfer.getStatusDetail() != null ? transfer.getStatusDetail() : null); + instruction.setStartedAt(transfer.getStartedAt() != null ? transfer.getStartedAt() : null); + instruction.setCompletedAt(transfer.getCompletedAt() != null ? transfer.getCompletedAt() : null); + instructionList.add(instruction); + } + Comparator comparator = null; + Boolean validOrderBy = true; + + if ("instructionId".equals(orderBy)) { + comparator = Comparator.comparing(Instruction::getPayerFsp); + } else if ("payeeFunctionalId".equals(orderBy)) { + comparator = Comparator.comparing(Instruction::getPayeeFunctionalId); + } else if ("subBatchId".equals(orderBy)) { + comparator = Comparator.comparing(Instruction::getAmount); + } else { + validOrderBy=false; + } + + if ("desc".equalsIgnoreCase(sortBy) && validOrderBy && comparator != null) { + comparator = comparator.reversed(); + } + + subBatch.setInstructionList(instructionList); + subBatch.setTotalInstructionCount(totalInstructionCount); + subBatch.setTotalAmount(subBatch.getTotalAmount()); + + return subBatch; + } + + private void updatePaymentDetailBatchInfo( Batch batch, PaymentBatchDetail response){ + log.info("Inside batch"); + response.setBatchId(batch.getBatchId()); + response.setPayerFsp(batch.getPayerFsp()); + response.setTotalBatchAmount(batch.getTotalAmount()); + response.setReportGeneratedAt(LocalDateTime.now().toString()); + response.setStartedAt(batch.getStartedAt()); + response.setCompletedAt(batch.getCompletedAt()); + response.setRegisteringInstitutionId(batch.getRegisteringInstitutionId()); + response.setStatus(String.valueOf(batch.getStatus())); + response.setClientCorrelationId(batch.getCorrelationId()); + response.setFailed(batch.getFailed()); + response.setOngoing(batch.getOngoing()); + response.setSuccessful(batch.getCompleted()); + response.setTotal(batch.getTotalTransactions()); + response.setTotalAmount(BigDecimal.valueOf(batch.getTotalAmount())); + response.setSuccessfulAmount(BigDecimal.valueOf(batch.getCompletedAmount())); + response.setFailedAmount(BigDecimal.valueOf(batch.getFailedAmount())); + response.setPendingAmount(BigDecimal.valueOf(batch.getOngoingAmount())); + } + private SubBatchSummary updateSubBatchPaymentDetail(Batch batch, PaymentBatchDetail response){ + SubBatchSummary subBatch = new SubBatchSummary(); + subBatch.setSubBatchId(batch.getSubBatchId()); + subBatch.setPayerFsp(batch.getPayerFsp()); + List transferList = transferRepository.findAllByBatchId(batch.getSubBatchId()); + if(!transferList.isEmpty()) { + subBatch.setBudgetAccount(transferList.get(0).getPayerPartyId() != null ? transferList.get(0).getPayerPartyId() : null); + } + subBatch.setTotalAmount(batch.getTotalAmount()!=null? BigDecimal.valueOf(batch.getTotalAmount()): BigDecimal.valueOf(0)); + subBatch.setTotal(batch.getTotalTransactions()!=null ? batch.getTotalTransactions(): 0 ); + subBatch.setPayeeFspSet(payeeFspSet); + return subBatch; + } + + private SubBatchSummary updateResponseWithSubBatchInfo(Batch batch, BatchAndSubBatchSummaryResponse response) { + double batchFailedPercent = 0; + double batchSuccessPercent = 0; + + if (batch != null) { + if (CollectionUtils.isEmpty(response.getSubBatchSummaryList())) { + response.setSubBatchSummaryList(new ArrayList<>()); + } + + if (batch.getTotalTransactions() != null) { + batchFailedPercent = ((double) batch.getFailed()) / batch.getTotalTransactions() * 100; + batchSuccessPercent = ((double) batch.getCompleted()) / batch.getTotalTransactions() * 100; + } + + DecimalFormat decimalFormat = new DecimalFormat("#.##"); + decimalFormat.setRoundingMode(RoundingMode.FLOOR); + + SubBatchSummary subBatchSummary = new SubBatchSummary(); + subBatchSummary.setBatchId(batch.getBatchId()); + subBatchSummary.setSubBatchId(batch.getSubBatchId()); + subBatchSummary.setRequestId(batch.getRequestId()); + + subBatchSummary.setTotal(batch.getTotalTransactions() != null ? batch.getTotalTransactions() : 0); + subBatchSummary.setTotalAmount(BigDecimal.valueOf(batch.getTotalAmount() != null ? batch.getTotalAmount() : 0)); + subBatchSummary.setOngoing(batch.getOngoing() != null ? batch.getOngoing() : 0); + subBatchSummary.setPendingAmount(BigDecimal.valueOf(batch.getOngoingAmount() != null ? batch.getOngoingAmount() : 0)); + subBatchSummary.setSuccessful(batch.getCompleted() != null ? batch.getCompleted() : 0); + subBatchSummary.setSuccessfulAmount(BigDecimal.valueOf(batch.getCompletedAmount() != null ? batch.getCompletedAmount() : 0)); + subBatchSummary.setFailed(batch.getFailed() != null ? batch.getFailed() : 0); + subBatchSummary.setFailedAmount(BigDecimal.valueOf(batch.getFailedAmount() != null ? batch.getFailedAmount() : 0)); + subBatchSummary.setFile(batch.getRequestFile()); + subBatchSummary.setNotes(batch.getNote()); + subBatchSummary.setCreatedAt(batch.getStartedAt() != null ? batch.getStartedAt().toString() : null); + + subBatchSummary.setModes(batch.getPaymentMode()); + subBatchSummary.setPurpose(null); + subBatchSummary.setSuccessPercentage(decimalFormat.format(batchSuccessPercent)); + subBatchSummary.setFailedPercentage(decimalFormat.format(batchFailedPercent)); + subBatchSummary.setApprovedAmount(batch.getApprovedAmount()); + subBatchSummary.setApprovedTransactionCount(batch.getApprovedCount()); + subBatchSummary.setPayerFsp(batch.getPayerFsp()); + subBatchAmount += batch.getApprovedAmount() != null ? batch.getApprovedAmount() : 0; + subBatchCount += batch.getApprovedCount() != null ? batch.getApprovedCount() : 0; + List transferList = transferRepository.findAllByBatchId(batch.getSubBatchId()); + Set payeeFspSet = new HashSet<>(); + for (Transfer transfer : transferList) { + payeeFspSet.add(transfer.getPayeeDfspId()); + } + subBatchSummary.setPayeeFspSet(payeeFspSet); + subBatchSummary.setStartedAt(batch.getStartedAt()); + subBatchSummary.setCompletedAt(batch.getCompletedAt()); + subBatchSummary.setStatus(String.valueOf(batch.getStatus())); + + + return subBatchSummary; + } else { + return null; // Return null if batch is null + } + } + private void updateResponseWithBatchInfo(Batch batch, BatchAndSubBatchSummaryResponse response) { + double batchFailedPercent = 0; + double batchSuccessPercent = 0; + + if (batch != null) { + if (batch.getTotalTransactions() != null) { + batchFailedPercent = ((double) batch.getFailed()) / batch.getTotalTransactions() * 100; + batchSuccessPercent = ((double) batch.getCompleted()) / batch.getTotalTransactions() * 100; + } + + DecimalFormat decimalFormat = new DecimalFormat("#.##"); + decimalFormat.setRoundingMode(RoundingMode.FLOOR); + + response.setBatchId(batch.getBatchId()); + response.setRequestId(batch.getRequestId()); + + response.setTotal(batch.getTotalTransactions() != null ? batch.getTotalTransactions() : 0); + response.setTotalAmount(BigDecimal.valueOf(batch.getTotalAmount() != null ? batch.getTotalAmount() : 0)); + response.setOngoing(batch.getOngoing() != null ? batch.getOngoing() : 0); + response.setPendingAmount(BigDecimal.valueOf(batch.getOngoingAmount() != null ? batch.getOngoingAmount() :0)); + response.setSuccessful(batch.getCompleted() != null ? batch.getCompleted() : 0); + response.setSuccessfulAmount(BigDecimal.valueOf(batch.getCompletedAmount() !=null ? batch.getCompletedAmount(): 0)); + response.setFailed(batch.getFailed() != null ? batch.getFailed() : 0); + response.setFailedAmount(BigDecimal.valueOf(batch.getFailedAmount()!= null ? batch.getFailedAmount() : 0)); + response.setFile(batch.getResult_file()); + response.setNotes(batch.getNote()); + + response.setCreatedAt(batch.getStartedAt() != null ? batch.getStartedAt().toString() : null); + + response.setModes(batch.getPaymentMode()); + response.setPurpose(null); + response.setSuccessPercentage(decimalFormat.format(batchSuccessPercent)); + response.setFailedPercentage(decimalFormat.format(batchFailedPercent)); + response.setApprovedTransactionCount(batch.getApprovedCount() != null ? batch.getApprovedCount() : 0); + response.setApprovedAmount(batch.getApprovedAmount()!= null ? batch.getApprovedAmount() : 0); + response.setPayerFsp(batch.getPayerFsp()!= null ? batch.getPayerFsp(): null); + response.setGeneratedAt(LocalDateTime.now().toString()); + response.setTotalInstructionCount(transferRepository.countAllByBatchId(batch.getBatchId())); + response.setStartedAt(batch.getStartedAt()); + response.setCompletedAt(batch.getCompletedAt()); + response.setRegisteringInstitutionId(batch.getRegisteringInstitutionId()); + response.setStatus(String.valueOf(batch.getStatus())); + + + } + } +} diff --git a/ph-ee-operations-app/src/main/java/org/apache/fineract/service/UtilityService.java b/ph-ee-operations-app/src/main/java/org/apache/fineract/service/UtilityService.java new file mode 100644 index 000000000..8b94353c5 --- /dev/null +++ b/ph-ee-operations-app/src/main/java/org/apache/fineract/service/UtilityService.java @@ -0,0 +1,15 @@ +package org.apache.fineract.service; + +import org.springframework.stereotype.Service; +import javax.crypto.BadPaddingException; +import javax.crypto.IllegalBlockSizeException; +import javax.crypto.NoSuchPaddingException; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.security.spec.InvalidKeySpecException; + +@Service +public interface UtilityService { + + String getSignature(String toBeHashed, String privateKeyString)throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeySpecException, IllegalBlockSizeException, BadPaddingException, InvalidKeyException; +} diff --git a/ph-ee-operations-app/src/main/java/org/apache/fineract/service/UtilityServiceImpl.java b/ph-ee-operations-app/src/main/java/org/apache/fineract/service/UtilityServiceImpl.java new file mode 100644 index 000000000..973f9c5d0 --- /dev/null +++ b/ph-ee-operations-app/src/main/java/org/apache/fineract/service/UtilityServiceImpl.java @@ -0,0 +1,39 @@ +package org.apache.fineract.service; + +import org.apache.commons.codec.binary.Base64; +import org.apache.commons.codec.digest.DigestUtils; +import org.springframework.stereotype.Service; +import javax.crypto.BadPaddingException; +import javax.crypto.Cipher; +import javax.crypto.IllegalBlockSizeException; +import javax.crypto.NoSuchPaddingException; +import java.nio.charset.StandardCharsets; +import java.security.InvalidKeyException; +import java.security.KeyFactory; +import java.security.NoSuchAlgorithmException; +import java.security.PrivateKey; +import java.security.spec.EncodedKeySpec; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.PKCS8EncodedKeySpec; + +@Service +public class UtilityServiceImpl implements UtilityService{ + @Override + public String getSignature(String tobeHashed, String privateKeyString)throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeySpecException, IllegalBlockSizeException, BadPaddingException, InvalidKeyException { + String hashData = (new DigestUtils("SHA3-256")).digestAsHex(tobeHashed); + + Cipher cipher = Cipher.getInstance("RSA"); + PrivateKey publicKey = getPrivateKeyFromString(privateKeyString); + cipher.init(1, publicKey); + byte[] cipherText = cipher.doFinal(hashData.getBytes(StandardCharsets.UTF_8)); + + return Base64.encodeBase64String(cipherText); + } + + public static PrivateKey getPrivateKeyFromString(String key) throws NoSuchAlgorithmException, InvalidKeySpecException { + byte[] keyBytes = Base64.decodeBase64(key); + EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes); + KeyFactory keyFactory = KeyFactory.getInstance("RSA"); + return keyFactory.generatePrivate(keySpec); + } +} diff --git a/ph-ee-operations-app/src/main/java/org/apache/fineract/utils/CsvUtility.java b/ph-ee-operations-app/src/main/java/org/apache/fineract/utils/CsvUtility.java new file mode 100644 index 000000000..ef9117521 --- /dev/null +++ b/ph-ee-operations-app/src/main/java/org/apache/fineract/utils/CsvUtility.java @@ -0,0 +1,43 @@ +package org.apache.fineract.utils; + +import org.apache.fineract.data.ErrorCode; +import org.apache.fineract.exception.WriteToCsvException; + +import javax.servlet.http.HttpServletResponse; +import java.io.PrintWriter; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.List; + +import static org.apache.fineract.utils.CsvWriter.performErrorProneTask; + +public class CsvUtility { + + public static void writeToCsv(HttpServletResponse response, List listOfData) throws WriteToCsvException { + response.setContentType("text/csv"); + DateFormat dateFormatter = new SimpleDateFormat("yyyy-MM-dd_HH-mm-ss"); + String currentDateTime = dateFormatter.format(new Date()); + String filename = "transactionRequest_" + currentDateTime + ".csv"; + String headerKey = "Content-Disposition"; + String headerValue = "attachment; filename=" + filename; + response.setHeader(headerKey, headerValue); + + PrintWriter printWriter = performErrorProneTask( + new WriteToCsvException( + ErrorCode.CSV_GET_WRITER, + "Unable get writer from HttpServletResponse"), + response::getWriter) ; + + //System.out.println("Print writer fetch success"); + + CsvWriter writer = new CsvWriter.Builder() + .setPrintWriter(printWriter) + .setData(listOfData) + .build(); + + //System.out.println("Writer object created success"); + writer.write(); + } + +} diff --git a/ph-ee-operations-app/src/main/java/org/apache/fineract/utils/CsvWriter.java b/ph-ee-operations-app/src/main/java/org/apache/fineract/utils/CsvWriter.java new file mode 100644 index 000000000..c649e2a33 --- /dev/null +++ b/ph-ee-operations-app/src/main/java/org/apache/fineract/utils/CsvWriter.java @@ -0,0 +1,187 @@ +package org.apache.fineract.utils; + +import org.apache.fineract.data.ErrorCode; +import org.apache.fineract.exception.CsvWriterException; +import org.apache.fineract.exception.WriteToCsvException; +import org.supercsv.io.CsvBeanWriter; +import org.supercsv.io.ICsvBeanWriter; +import org.supercsv.prefs.CsvPreference; + +import java.io.PrintWriter; +import java.lang.reflect.Field; +import java.util.List; + +/** + * custom csv writer for writing list of POJOs into printer of HttpServletResponse + * @param generic type representing the data type of POJO + */ +public class CsvWriter { + + interface Callback { + T call() throws Exception; + } + + private final ICsvBeanWriter iCsvBeanWriter; + private final String[] csvHeader; + private final List data; + private final String[] nameMapping; + + private CsvWriter(PrintWriter printWriter, String[] csvHeader, List data, String[] nameMapping) { + this.iCsvBeanWriter = new CsvBeanWriter(printWriter, CsvPreference.STANDARD_PREFERENCE); + this.csvHeader = csvHeader; + this.data = data; + this.nameMapping = nameMapping; + } + + /** + * writes csv data into printer + * @throws WriteToCsvException @see [writeCsvHeaders], [writeData] and [closeStream] + */ + public void write() throws WriteToCsvException { + writeCsvHeaders(csvHeader); + writeData(nameMapping, data); + closeStream(); + } + + /** + * writes the headers into csv + * @param csvHeader the headers to be written in csv of type string array + * @throws WriteToCsvException @see [performErrorProneTask] + */ + private void writeCsvHeaders(String[] csvHeader) throws WriteToCsvException { + performErrorProneTask( + new WriteToCsvException(ErrorCode.CSV_WRITE_HEADER, "Unable to write csv headers"), + () -> { + iCsvBeanWriter.writeHeader(csvHeader); + return null; + }); + } + + /** + * writes the data/ rows in csv + * @param nameMapping string array of the fields to be populated from POJO + * @param objects list of the objects to be translated into rows in csv + * @throws WriteToCsvException @see [performErrorProneTask] + */ + private void writeData(String[] nameMapping, List objects) throws WriteToCsvException { + for(T data: objects) { + performErrorProneTask( + new WriteToCsvException(ErrorCode.CSV_WRITE_DATA, "Unable to write csv headers"), + () -> { + iCsvBeanWriter.write(data, nameMapping); + return null; + }); + } + } + + /** + * Closes the existing [ICsvBeanWriter] stream + * @throws WriteToCsvException @see [performErrorProneTask] + */ + private void closeStream() throws WriteToCsvException { + performErrorProneTask( + new WriteToCsvException(ErrorCode.CSV_STREAM, "Unable to close/flush stream"), + () -> { + iCsvBeanWriter.close(); + return null; + }); + } + + /** + * Use this function to perform the task which are prone to errors along with custom [WriteToCsvException] + * instance. + * @param exception an instance of [WriteToCsvException], which is to be thrown on error occurred + * @param callback the task which needs to be performed under try block + * @param generic return type of the successful callback call + * @return the result of the successful callback of type [T] or throws an error passed + * @throws WriteToCsvException if callbacks throws and exception + */ + public static T performErrorProneTask(WriteToCsvException exception, Callback callback) throws WriteToCsvException { + try { + return callback.call(); + } catch (Exception e) { + exception.setStackTrace(e.getStackTrace()); + exception.setDeveloperMessage(e.getLocalizedMessage()); + throw exception; + } + } + + /** + * Automatically generates the name mapping string using the java reflect api + * @param pojoClass the Class instance of the generic type [T] + * @param the generic type for [pojoClass] + * @return string array of name mapping + */ + public static String[] generateNameMapping(Class pojoClass) { + Field[] fields = pojoClass.getDeclaredFields(); + String[] nm = new String[fields.length]; + int i = 0; + for (Field field :fields) { + nm[i++] = field.getName(); + } + return nm; + } + + /** + * creates the csv header based on the fields provided + * @return csv header of type String array + */ + private static String[] getCsvHeader(String[] fields) { + String[] csvHeader = new String[fields.length]; + for (int i = 0; i < fields.length; i++) { + csvHeader[i] = fields[i].toUpperCase(); + } + return csvHeader; + } + + public static class Builder { + private PrintWriter printWriter; + private String[] csvHeader; + private List data; + private String[] nameMapping; + + public Builder setPrintWriter(PrintWriter printWriter) throws WriteToCsvException { + this.printWriter = printWriter; + return this; + } + + public Builder setHeader(String[] header) { + this.csvHeader = header; + return this; + } + + public Builder setData(List data) { + this.data = data; + return this; + } + + public void setNameMapping(Class pojoClass) { + this.nameMapping = CsvWriter.generateNameMapping(pojoClass); + } + + public Builder setNameMapping(String[] nameMapping) { + this.nameMapping = nameMapping; + return this; + } + + public CsvWriter build() throws CsvWriterException { + if(printWriter == null) { + throw new CsvWriterException(ErrorCode.CSV_BUILDER,"Print writer can't be null"); + } + if(data == null) { + throw new CsvWriterException(ErrorCode.CSV_BUILDER,"Data can't be null"); + } + if(data.isEmpty()) { + throw new CsvWriterException(ErrorCode.EMPTY_RESULT, "No matching records"); + } + if(nameMapping == null) { + setNameMapping((Class) this.data.get(0).getClass()); + } + if(csvHeader == null) { + this.csvHeader = getCsvHeader(nameMapping); + } + return new CsvWriter<>(printWriter, csvHeader, data, nameMapping); + } + + } +} diff --git a/ph-ee-operations-app/src/main/java/org/apache/fineract/utils/DateUtil.java b/ph-ee-operations-app/src/main/java/org/apache/fineract/utils/DateUtil.java new file mode 100644 index 000000000..ca90ff5b0 --- /dev/null +++ b/ph-ee-operations-app/src/main/java/org/apache/fineract/utils/DateUtil.java @@ -0,0 +1,29 @@ +package org.apache.fineract.utils; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; + +@Component +public class DateUtil { + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + @Value("${interface.timezone}") + public String interfaceTimezone; + + public String getUTCFormat(String dateTime) { + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); + LocalDateTime localDateTime = LocalDateTime.parse(dateTime, formatter); + ZoneId interfaceZone = ZoneId.of(interfaceTimezone); + ZonedDateTime interfaceDateTime = ZonedDateTime.of(localDateTime, interfaceZone); + ZonedDateTime gmtDateTime = interfaceDateTime.withZoneSameInstant(ZoneId.of("GMT")); + DateTimeFormatter gmtFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); + String gmtDateTimeString = gmtDateTime.format(gmtFormatter); + return gmtDateTimeString; + } +} diff --git a/ph-ee-operations-app/src/main/resources/application-bb.yml b/ph-ee-operations-app/src/main/resources/application-bb.yml new file mode 100644 index 000000000..25a09209e --- /dev/null +++ b/ph-ee-operations-app/src/main/resources/application-bb.yml @@ -0,0 +1,10 @@ +tenants: "tn01,tn02" + +token: + client: + channel: + secret: "p1234" + +channel-connector: + url: http://bb-connector-channel.mifos.io + transfer-path: /channel/transfer \ No newline at end of file diff --git a/ph-ee-operations-app/src/main/resources/application-large.yml b/ph-ee-operations-app/src/main/resources/application-large.yml new file mode 100644 index 000000000..7e30fdcb7 --- /dev/null +++ b/ph-ee-operations-app/src/main/resources/application-large.yml @@ -0,0 +1,10 @@ +tenants: "tn01,tn02" + +token: + client: + channel: + secret: "p3456" + +channel-connector: + url: http://large-connector-channel.mifos.io + transfer-path: /channel/transfer \ No newline at end of file diff --git a/ph-ee-operations-app/src/main/resources/application-med.yml b/ph-ee-operations-app/src/main/resources/application-med.yml new file mode 100644 index 000000000..fdda98bf5 --- /dev/null +++ b/ph-ee-operations-app/src/main/resources/application-med.yml @@ -0,0 +1,10 @@ +tenants: "tn05,tn06" + +token: + client: + channel: + secret: "p2345" + +channel-connector: + url: http://med-connector-channel.mifos.io + transfer-path: /channel/transfer \ No newline at end of file diff --git a/ph-ee-operations-app/src/main/resources/application.yml b/ph-ee-operations-app/src/main/resources/application.yml new file mode 100644 index 000000000..7faf601b4 --- /dev/null +++ b/ph-ee-operations-app/src/main/resources/application.yml @@ -0,0 +1,109 @@ +fineract: + datasource: + core: + host: operations-mysql +# host: "127.0.0.1" + port: 3306 + schema: tenants + username: root + password: mysql +# password: "ethieTieCh8ahv" + common: + protocol: jdbc + subprotocol: mysql + driverclass_name: com.mysql.cj.jdbc.Driver + +# Interface time zone reference : https://en.wikipedia.org/wiki/List_of_tz_database_time_zones +interface: + timezone: "Asia/Kolkata" + +token: + user: + access-validity-seconds: 600 + refresh-validity-seconds: 43200 + client: + access-validity-seconds: 3600 + channel: + secret: "p2345" + +config: + imu: + rate-validity-seconds: 300 + +caching: + enabled: false + +security: + filter-order: 4 + jws: + enable: false + +spring: + resources: + add-mappings: false + mvc: + favicon: + enabled: false + jmx: + enabled: false + +server: + port: 5000 + +rest: + authorization: + enabled: false + settings: + - endpoint: "/api/v1/transfer/*/refund" + authority: "hasAuthority('REFUND')" + - endpoint: "/api/v1/**" + authority: "hasAuthority('ALL_FUNCTIONS')" +logging: + level: + ROOT: ERROR + pattern: + console: "%clr(%d{dd-MM-yyyy HH:mm:ss.SSS}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr([%35.35t]){faint} %clr(%-28.28logger{28}){cyan} %clr(:){faint}%X{BUSINESS-LOG} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}" + +cloud: + aws: + enabled: true + minio-public-host: "http://minio.sandbox.mifos.io" + s3BaseUrl: "https://s3.ap-south-1.amazonaws.com" + credentials: + access-key: ${AWS_ACCESS_KEY:AKIAX32JM37TZOJ5AKFB} + secret-key: ${AWS_SECRET_KEY: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} + region: + static: us-east-2 + stack: + auto: false + azure: + enabled: false + blob: + connection-string: + +payment: + modes: + - id: "slcb" + type: "BATCH" + +application: + bucket-name: paymenthub-ee-dev + +channel-connector: + url: http://bb-connector-channel.mifos.io + transfer-path: /channel/transfer + +management: +# server: +# port: 5000 + endpoint: + health: + probes: + enabled: true + liveness: + enabled: true + readiness: + enabled: true +# show-details: always + + diff --git a/ph-ee-operations-app/src/main/resources/jwt.pem b/ph-ee-operations-app/src/main/resources/jwt.pem new file mode 100644 index 000000000..8bc106910 --- /dev/null +++ b/ph-ee-operations-app/src/main/resources/jwt.pem @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEpQIBAAKCAQEAz7GeFSs8Pj322thsMox/+Vm6urnCUbYyDsnkdAZy78avVjVh +fA5J/sVR++osLtfP0l19hMjyWCrtN/Otll1Xaw6BGAyDT08Bfd9TJQtB0aH9c69r +4p8Qo0+JyeVY8Dj7g3KV3J7mfGv79++TXxEIxXUUAmkXoKtqih1qW/rkNEq6zQgX +LgZTMZudXZPROT8ngg5fcZPAfV/k+MyTr+7eX/0zZgNNKoUKs0AZphsHyJLHjWNR +AQCMNvTvPGy3TGsDKUE1GcOAETrh4GwV1hSmURFT6IMu8qYQR1nyhQRZUeqig7Rw +ySX/3ql0IwXvxSm6LePRl9e8Vdd49Qg8EV0o2QIDAQABAoIBAAplCVRl5Y336/Lo +AgJFpeIE66OMyHzucXLsB9MGv5ngh8X4xfg/ftSRa5kAD1YI1w3gP/f1Vquy+kxi +lb2Azm89OpjJh4jgm2KBWtfvyEuFn/m6PdwJuftyb6L7J4heUbgyc+2mxkJT5Thz +dRy87YN0aJv2Roh0C9D9x+TymZlETR/IcxbccpiUQmbVH937acLEGTP1S1QpDoRN +16+GOgPLuRf8/rESlXDTea18CQ6/q/8jFLq1S/z97/9LaP7t3EvfKvK8MTA3ETmP +JItETVAMUPmi/6h4adNgsXP6iayDYWgwF5nvWOKzxy//MYwXtAWkw0VdbTGnwhEE +Qw+BAkECgYEA6cI8bJjGuFvPlY3Gdeao9bo/fGVZFQ1OUko0XUhTxq2KTuDNX3T4 +gy5JBf+ddU9xvKwn/rpkKbdvL3nF1VvJ/laLHmuWFVy76HoUiJF9YTES4NheWX7O +g551XF/EpBd1Pw68bsr2gbMv/iMW9gsnO0Vkdm8o5l0V7DUFcR+Y6AcCgYEA43SB +w5zG+9kCHqw/uL0Z9fss3CzQlDjHr5wlo0EOfBDohVLIw2bGtrT4wSfq9Ej+fJye +7Axiaw+bNpxMUsWio+hLaPONREX1fvhrriwsdD02kJG094XxmDot4zSMERZ5TBNy +Z5w9AmFusuU2CRRy4IUofpVFvRFYXJyNFtN6cB8CgYEA0gOwReD8qKXT2omFxGd3 +ZU3vu9NSNZe+xi/k2+ofWmCP4k4WNazhmPn8oWcGEF9P0DLbu/+5/cDQI9dD5myR +DfCzDKGcNZUbPcJwsEIGY0uzqk66da133MiAqH1iLgrlS8HxiZjP37cdZzYfau6a +UKYHnGBCXrVC/PSl7vx0ZAECgYEAg1e/pwldDgkd5EBq+26XEyfbm7h1KWIwTQPJ +6B+lEZdh7bsEG3G5xb9y9Xbrgey0p5h5XK06F8CHTF2s5Q8i/6sgAJbDOG19ebhR +1d3EPcsrOwgoi9ZY0CKoZM7vIt7rZDbGlXXu9PT2S294aH3aaDP8Ujw4bRkbAT+V +aVztEtkCgYEA2h72LAc2UK37xt+dv1ZEDS/jHpA9hZTJm/3b4CBQwYZgapYdKWHg +/Kp9ORvuWBjYADKQEQXUsXj1O7KHP/AwCI8xzpYsCLJqH96vOt6+xX4hfr8rQyhl +Win2poxMH+yDdcHzrg7x9XqKG7vHT3/iP0Arh1auA+b501TPPMqj+7Y= +-----END RSA PRIVATE KEY----- diff --git a/ph-ee-operations-app/src/main/resources/jwt_pub.pem b/ph-ee-operations-app/src/main/resources/jwt_pub.pem new file mode 100644 index 000000000..21cd142bc --- /dev/null +++ b/ph-ee-operations-app/src/main/resources/jwt_pub.pem @@ -0,0 +1,9 @@ +-----BEGIN PUBLIC KEY----- +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAz7GeFSs8Pj322thsMox/ ++Vm6urnCUbYyDsnkdAZy78avVjVhfA5J/sVR++osLtfP0l19hMjyWCrtN/Otll1X +aw6BGAyDT08Bfd9TJQtB0aH9c69r4p8Qo0+JyeVY8Dj7g3KV3J7mfGv79++TXxEI +xXUUAmkXoKtqih1qW/rkNEq6zQgXLgZTMZudXZPROT8ngg5fcZPAfV/k+MyTr+7e +X/0zZgNNKoUKs0AZphsHyJLHjWNRAQCMNvTvPGy3TGsDKUE1GcOAETrh4GwV1hSm +URFT6IMu8qYQR1nyhQRZUeqig7RwySX/3ql0IwXvxSm6LePRl9e8Vdd49Qg8EV0o +2QIDAQAB +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/ph-ee-operations-app/src/main/resources/logback.xml b/ph-ee-operations-app/src/main/resources/logback.xml new file mode 100644 index 000000000..b53433eca --- /dev/null +++ b/ph-ee-operations-app/src/main/resources/logback.xml @@ -0,0 +1,18 @@ + + + + + + + + + + ${CONSOLE_LOG_PATTERN} + utf8 + + + + + + + \ No newline at end of file diff --git a/ph-ee-operations-app/src/main/resources/sql/migrations/core/V2__tenant-server-connections.sql b/ph-ee-operations-app/src/main/resources/sql/migrations/core/V2__tenant-server-connections.sql new file mode 100644 index 000000000..2e45b2dbb --- /dev/null +++ b/ph-ee-operations-app/src/main/resources/sql/migrations/core/V2__tenant-server-connections.sql @@ -0,0 +1,32 @@ +-- +-- Licensed to the Apache Software Foundation (ASF) under one +-- or more contributor license agreements. See the NOTICE file +-- distributed with this work for additional information +-- regarding copyright ownership. The ASF licenses this file +-- to you under the Apache License, Version 2.0 (the +-- "License"); you may not use this file except in compliance +-- with the License. You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, +-- software distributed under the License is distributed on an +-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +-- KIND, either express or implied. See the License for the +-- specific language governing permissions and limitations +-- under the License. +-- + +create table tenant_server_connections( + `id` BIGINT(20) NOT NULL AUTO_INCREMENT, + `schema_server` VARCHAR(100) NOT NULL, + `schema_name` VARCHAR(100) NOT NULL, + `schema_server_port` VARCHAR(10) NOT NULL, + `schema_username` VARCHAR(100) NOT NULL, + `schema_password` VARCHAR(100) NOT NULL, + `auto_update` TINYINT(1) NOT NULL, + PRIMARY KEY (`id`) + ) +COLLATE='utf8_general_ci' +ENGINE=InnoDB +AUTO_INCREMENT=1; diff --git a/ph-ee-operations-app/src/main/resources/sql/migrations/tenant/V10__adding-S3-Support.sql b/ph-ee-operations-app/src/main/resources/sql/migrations/tenant/V10__adding-S3-Support.sql new file mode 100644 index 000000000..71f3b60b4 --- /dev/null +++ b/ph-ee-operations-app/src/main/resources/sql/migrations/tenant/V10__adding-S3-Support.sql @@ -0,0 +1,32 @@ +-- +-- Licensed to the Apache Software Foundation (ASF) under one +-- or more contributor license agreements. See the NOTICE file +-- distributed with this work for additional information +-- regarding copyright ownership. The ASF licenses this file +-- to you under the Apache License, Version 2.0 (the +-- "License"); you may not use this file except in compliance +-- with the License. You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, +-- software distributed under the License is distributed on an +-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +-- KIND, either express or implied. See the License for the +-- specific language governing permissions and limitations +-- under the License. +-- + +/*Image tables stores details of all images*/ +CREATE TABLE IF NOT EXISTS `m_image`( + `id` BIGINT(20) NOT NULL AUTO_INCREMENT, + `location` varchar(500), + `storage_type_enum` SMALLINT(5), + PRIMARY KEY (`id`) +) +COLLATE='utf8_general_ci' +ENGINE=InnoDB; + +/*Add storage type for m_document table and update existing documents to file storage*/ +ALTER TABLE m_document ADD COLUMN storage_type_enum SMALLINT(5); +UPDATE m_document set storage_type_enum=1; diff --git a/ph-ee-operations-app/src/main/resources/sql/migrations/tenant/V11__add_group_roles_schema_and_permissions.sql b/ph-ee-operations-app/src/main/resources/sql/migrations/tenant/V11__add_group_roles_schema_and_permissions.sql new file mode 100644 index 000000000..b687feb5e --- /dev/null +++ b/ph-ee-operations-app/src/main/resources/sql/migrations/tenant/V11__add_group_roles_schema_and_permissions.sql @@ -0,0 +1,35 @@ +-- +-- Licensed to the Apache Software Foundation (ASF) under one +-- or more contributor license agreements. See the NOTICE file +-- distributed with this work for additional information +-- regarding copyright ownership. The ASF licenses this file +-- to you under the Apache License, Version 2.0 (the +-- "License"); you may not use this file except in compliance +-- with the License. You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, +-- software distributed under the License is distributed on an +-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +-- KIND, either express or implied. See the License for the +-- specific language governing permissions and limitations +-- under the License. +-- + +INSERT INTO `m_code` (`code_name`, `is_system_defined`) VALUES ('GROUPROLE', 1); + +CREATE TABLE `m_group_roles` ( + `id` BIGINT(20) NOT NULL AUTO_INCREMENT, + `client_id` BIGINT(20) NULL DEFAULT NULL, + `group_id` BIGINT(20) NULL DEFAULT NULL, + `role_cv_id` INT(11) NULL DEFAULT NULL, + PRIMARY KEY (`id`), + INDEX `FKGroupRoleGroupId` (`group_id`), + INDEX `FK_grouprole_m_codevalue` (`role_cv_id`), + UNIQUE INDEX `UNIQUE_GROUP_ROLES` (`client_id`, `group_id`, `role_cv_id`), + CONSTRAINT `FKGroupRoleGroupId` FOREIGN KEY (`group_id`) REFERENCES `m_group` (`id`), + CONSTRAINT `FK_grouprole_m_codevalue` FOREIGN KEY (`role_cv_id`) REFERENCES `m_code_value` (`id`) +) +COLLATE='utf8_general_ci' +ENGINE=InnoDB; \ No newline at end of file diff --git a/ph-ee-operations-app/src/main/resources/sql/migrations/tenant/V12__group_center_close.sql b/ph-ee-operations-app/src/main/resources/sql/migrations/tenant/V12__group_center_close.sql new file mode 100644 index 000000000..87126d3a0 --- /dev/null +++ b/ph-ee-operations-app/src/main/resources/sql/migrations/tenant/V12__group_center_close.sql @@ -0,0 +1,24 @@ +-- +-- Licensed to the Apache Software Foundation (ASF) under one +-- or more contributor license agreements. See the NOTICE file +-- distributed with this work for additional information +-- regarding copyright ownership. The ASF licenses this file +-- to you under the Apache License, Version 2.0 (the +-- "License"); you may not use this file except in compliance +-- with the License. You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, +-- software distributed under the License is distributed on an +-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +-- KIND, either express or implied. See the License for the +-- specific language governing permissions and limitations +-- under the License. +-- + +INSERT INTO `m_code` (`code_name`, `is_system_defined`) VALUES ('GroupClosureReason', 1); + +ALTER TABLE `m_group` ADD COLUMN `closure_reason_cv_id` INT(11) NULL DEFAULT NULL, +ADD COLUMN `closedon_date` DATE NULL DEFAULT NULL, +ADD CONSTRAINT `FK_m_group_m_code` FOREIGN KEY (`closure_reason_cv_id`) REFERENCES `m_code_value` (`id`); \ No newline at end of file diff --git a/ph-ee-operations-app/src/main/resources/sql/migrations/tenant/V13__mobile_no_fields.sql b/ph-ee-operations-app/src/main/resources/sql/migrations/tenant/V13__mobile_no_fields.sql new file mode 100644 index 000000000..db2fd9503 --- /dev/null +++ b/ph-ee-operations-app/src/main/resources/sql/migrations/tenant/V13__mobile_no_fields.sql @@ -0,0 +1,24 @@ +-- +-- Licensed to the Apache Software Foundation (ASF) under one +-- or more contributor license agreements. See the NOTICE file +-- distributed with this work for additional information +-- regarding copyright ownership. The ASF licenses this file +-- to you under the Apache License, Version 2.0 (the +-- "License"); you may not use this file except in compliance +-- with the License. You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, +-- software distributed under the License is distributed on an +-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +-- KIND, either express or implied. See the License for the +-- specific language governing permissions and limitations +-- under the License. +-- + + + +ALTER TABLE `m_staff` +ADD COLUMN `mobile_no` VARCHAR(50) NULL DEFAULT NULL AFTER `display_name`, +ADD UNIQUE INDEX `mobile_no_UNIQUE` (`mobile_no` ASC); \ No newline at end of file diff --git a/ph-ee-operations-app/src/main/resources/sql/migrations/tenant/V14__client_and_group_timeline.sql b/ph-ee-operations-app/src/main/resources/sql/migrations/tenant/V14__client_and_group_timeline.sql new file mode 100644 index 000000000..4f1325493 --- /dev/null +++ b/ph-ee-operations-app/src/main/resources/sql/migrations/tenant/V14__client_and_group_timeline.sql @@ -0,0 +1,24 @@ +-- +-- Licensed to the Apache Software Foundation (ASF) under one +-- or more contributor license agreements. See the NOTICE file +-- distributed with this work for additional information +-- regarding copyright ownership. The ASF licenses this file +-- to you under the Apache License, Version 2.0 (the +-- "License"); you may not use this file except in compliance +-- with the License. You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, +-- software distributed under the License is distributed on an +-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +-- KIND, either express or implied. See the License for the +-- specific language governing permissions and limitations +-- under the License. +-- + + +ALTER TABLE `m_group` ADD `activatedon_userid` BIGINT( 20 ) NULL , +ADD `submittedon_date` DATE NULL , +ADD `submittedon_userid` BIGINT( 20 ) NULL , +ADD `closedon_userid` BIGINT( 20 ) NULL ; \ No newline at end of file diff --git a/ph-ee-operations-app/src/main/resources/sql/migrations/tenant/V15__added_is_active_column_in_m_staff.sql b/ph-ee-operations-app/src/main/resources/sql/migrations/tenant/V15__added_is_active_column_in_m_staff.sql new file mode 100644 index 000000000..46093c63c --- /dev/null +++ b/ph-ee-operations-app/src/main/resources/sql/migrations/tenant/V15__added_is_active_column_in_m_staff.sql @@ -0,0 +1,20 @@ +-- +-- Licensed to the Apache Software Foundation (ASF) under one +-- or more contributor license agreements. See the NOTICE file +-- distributed with this work for additional information +-- regarding copyright ownership. The ASF licenses this file +-- to you under the Apache License, Version 2.0 (the +-- "License"); you may not use this file except in compliance +-- with the License. You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, +-- software distributed under the License is distributed on an +-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +-- KIND, either express or implied. See the License for the +-- specific language governing permissions and limitations +-- under the License. +-- + +ALTER TABLE `m_staff` ADD COLUMN `is_active` TINYINT(1) DEFAULT '0' AFTER `organisational_role_parent_staff_id`; \ No newline at end of file diff --git a/ph-ee-operations-app/src/main/resources/sql/migrations/tenant/V16__default_value_for_is_active_updated_to_true_in_m_staff.sql b/ph-ee-operations-app/src/main/resources/sql/migrations/tenant/V16__default_value_for_is_active_updated_to_true_in_m_staff.sql new file mode 100644 index 000000000..22fea7954 --- /dev/null +++ b/ph-ee-operations-app/src/main/resources/sql/migrations/tenant/V16__default_value_for_is_active_updated_to_true_in_m_staff.sql @@ -0,0 +1,22 @@ +-- +-- Licensed to the Apache Software Foundation (ASF) under one +-- or more contributor license agreements. See the NOTICE file +-- distributed with this work for additional information +-- regarding copyright ownership. The ASF licenses this file +-- to you under the Apache License, Version 2.0 (the +-- "License"); you may not use this file except in compliance +-- with the License. You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, +-- software distributed under the License is distributed on an +-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +-- KIND, either express or implied. See the License for the +-- specific language governing permissions and limitations +-- under the License. +-- + +ALTER TABLE `m_staff` + CHANGE COLUMN `is_active` `is_active` TINYINT(1) NOT NULL DEFAULT '1' AFTER `organisational_role_parent_staff_id`; +UPDATE `m_staff` SET `is_active`=1; \ No newline at end of file diff --git a/ph-ee-operations-app/src/main/resources/sql/migrations/tenant/V17__add_force_password_reset_in_c_configuration.sql b/ph-ee-operations-app/src/main/resources/sql/migrations/tenant/V17__add_force_password_reset_in_c_configuration.sql new file mode 100644 index 000000000..8c5c77f5f --- /dev/null +++ b/ph-ee-operations-app/src/main/resources/sql/migrations/tenant/V17__add_force_password_reset_in_c_configuration.sql @@ -0,0 +1,34 @@ +-- +-- Licensed to the Apache Software Foundation (ASF) under one +-- or more contributor license agreements. See the NOTICE file +-- distributed with this work for additional information +-- regarding copyright ownership. The ASF licenses this file +-- to you under the Apache License, Version 2.0 (the +-- "License"); you may not use this file except in compliance +-- with the License. You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, +-- software distributed under the License is distributed on an +-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +-- KIND, either express or implied. See the License for the +-- specific language governing permissions and limitations +-- under the License. +-- + +ALTER TABLE `m_appuser` ADD `last_time_password_updated` DATE NOT NULL DEFAULT '1970-01-01', +ADD INDEX ( `last_time_password_updated` ) ; + +UPDATE `m_appuser` SET `last_time_password_updated` = NOW() WHERE `m_appuser`.`last_time_password_updated` ='1970-01-01'; + +CREATE TABLE IF NOT EXISTS `m_appuser_previous_password` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT, + `user_id` bigint(20) NOT NULL, + `password` varchar(255) NOT NULL, + `removal_date` date NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ; + +ALTER TABLE m_appuser_previous_password +ADD FOREIGN KEY (user_id) REFERENCES m_appuser(id); \ No newline at end of file diff --git a/ph-ee-operations-app/src/main/resources/sql/migrations/tenant/V18__client_substatus_and_codevalue_description.sql b/ph-ee-operations-app/src/main/resources/sql/migrations/tenant/V18__client_substatus_and_codevalue_description.sql new file mode 100644 index 000000000..8e1fb51a3 --- /dev/null +++ b/ph-ee-operations-app/src/main/resources/sql/migrations/tenant/V18__client_substatus_and_codevalue_description.sql @@ -0,0 +1,29 @@ +-- +-- Licensed to the Apache Software Foundation (ASF) under one +-- or more contributor license agreements. See the NOTICE file +-- distributed with this work for additional information +-- regarding copyright ownership. The ASF licenses this file +-- to you under the Apache License, Version 2.0 (the +-- "License"); you may not use this file except in compliance +-- with the License. You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, +-- software distributed under the License is distributed on an +-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +-- KIND, either express or implied. See the License for the +-- specific language governing permissions and limitations +-- under the License. +-- + +ALTER TABLE `m_code_value` +ADD COLUMN `code_score` INT(11) NULL AFTER `order_position`; + +alter table m_staff +add column joining_date date; + +INSERT INTO `m_code` (`code_name`, `is_system_defined`) VALUES ('ClientSubStatus', 1); + +ALTER TABLE `m_code_value` +ADD COLUMN `code_description` VARCHAR(500) NULL DEFAULT NULL AFTER `code_value`; \ No newline at end of file diff --git a/ph-ee-operations-app/src/main/resources/sql/migrations/tenant/V19__role_status_and_correspoding_permissions.sql b/ph-ee-operations-app/src/main/resources/sql/migrations/tenant/V19__role_status_and_correspoding_permissions.sql new file mode 100644 index 000000000..85487ee64 --- /dev/null +++ b/ph-ee-operations-app/src/main/resources/sql/migrations/tenant/V19__role_status_and_correspoding_permissions.sql @@ -0,0 +1,24 @@ +-- +-- Licensed to the Apache Software Foundation (ASF) under one +-- or more contributor license agreements. See the NOTICE file +-- distributed with this work for additional information +-- regarding copyright ownership. The ASF licenses this file +-- to you under the Apache License, Version 2.0 (the +-- "License"); you may not use this file except in compliance +-- with the License. You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, +-- software distributed under the License is distributed on an +-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +-- KIND, either express or implied. See the License for the +-- specific language governing permissions and limitations +-- under the License. +-- + +ALTER TABLE `m_role` ADD COLUMN `is_disabled` TINYINT(1) NOT NULL DEFAULT 0 AFTER `description`; +INSERT INTO `m_permission` (`grouping`, `code`, `entity_name`, `action_name`, `can_maker_checker`) VALUES ('authorisation', 'DISABLE_ROLE', 'ROLE', 'DISABLE', 0); +INSERT INTO `m_permission` (`grouping`, `code`, `entity_name`, `action_name`, `can_maker_checker`) VALUES ('authorisation', 'DISABLE_ROLE_CHECKER', 'ROLE', 'DISABLE_CHECKER', 0); +INSERT INTO `m_permission` (`grouping`, `code`, `entity_name`, `action_name`, `can_maker_checker`) VALUES ('authorisation', 'ENABLE_ROLE', 'ROLE', 'ENABLE', 0); +INSERT INTO `m_permission` (`grouping`, `code`, `entity_name`, `action_name`, `can_maker_checker`) VALUES ('authorisation', 'ENABLE_ROLE_CHECKER', 'ROLE', 'ENABLE_CHECKER', 0); \ No newline at end of file diff --git a/ph-ee-operations-app/src/main/resources/sql/migrations/tenant/V20__update_staff_display_name_length.sql b/ph-ee-operations-app/src/main/resources/sql/migrations/tenant/V20__update_staff_display_name_length.sql new file mode 100644 index 000000000..1007308b0 --- /dev/null +++ b/ph-ee-operations-app/src/main/resources/sql/migrations/tenant/V20__update_staff_display_name_length.sql @@ -0,0 +1,23 @@ +-- +-- Licensed to the Apache Software Foundation (ASF) under one +-- or more contributor license agreements. See the NOTICE file +-- distributed with this work for additional information +-- regarding copyright ownership. The ASF licenses this file +-- to you under the Apache License, Version 2.0 (the +-- "License"); you may not use this file except in compliance +-- with the License. You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, +-- software distributed under the License is distributed on an +-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +-- KIND, either express or implied. See the License for the +-- specific language governing permissions and limitations +-- under the License. +-- + +ALTER TABLE `m_staff` + ALTER `display_name` DROP DEFAULT; +ALTER TABLE `m_staff` + CHANGE COLUMN `display_name` `display_name` VARCHAR(102) NOT NULL AFTER `lastname`; diff --git a/ph-ee-operations-app/src/main/resources/sql/migrations/tenant/V21__added_password_never_expired_to_User.sql b/ph-ee-operations-app/src/main/resources/sql/migrations/tenant/V21__added_password_never_expired_to_User.sql new file mode 100644 index 000000000..0b626d1da --- /dev/null +++ b/ph-ee-operations-app/src/main/resources/sql/migrations/tenant/V21__added_password_never_expired_to_User.sql @@ -0,0 +1,20 @@ +-- +-- Licensed to the Apache Software Foundation (ASF) under one +-- or more contributor license agreements. See the NOTICE file +-- distributed with this work for additional information +-- regarding copyright ownership. The ASF licenses this file +-- to you under the Apache License, Version 2.0 (the +-- "License"); you may not use this file except in compliance +-- with the License. You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, +-- software distributed under the License is distributed on an +-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +-- KIND, either express or implied. See the License for the +-- specific language governing permissions and limitations +-- under the License. +-- + +ALTER TABLE `m_appuser` ADD `password_never_expires` TINYINT NOT NULL DEFAULT '0' COMMENT 'define if the password, should be check for validity period or not'; \ No newline at end of file diff --git a/ph-ee-operations-app/src/main/resources/sql/migrations/tenant/V22__password_validation_policy.sql b/ph-ee-operations-app/src/main/resources/sql/migrations/tenant/V22__password_validation_policy.sql new file mode 100644 index 000000000..5bb1d2790 --- /dev/null +++ b/ph-ee-operations-app/src/main/resources/sql/migrations/tenant/V22__password_validation_policy.sql @@ -0,0 +1,62 @@ +-- +-- Licensed to the Apache Software Foundation (ASF) under one +-- or more contributor license agreements. See the NOTICE file +-- distributed with this work for additional information +-- regarding copyright ownership. The ASF licenses this file +-- to you under the Apache License, Version 2.0 (the +-- "License"); you may not use this file except in compliance +-- with the License. You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, +-- software distributed under the License is distributed on an +-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +-- KIND, either express or implied. See the License for the +-- specific language governing permissions and limitations +-- under the License. +-- + + +CREATE TABLE IF NOT EXISTS `m_password_validation_policy` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `regex` text NOT NULL, + `description` text NOT NULL, + `active` tinyint(4) NOT NULL DEFAULT '0', + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ; + + +INSERT INTO `m_password_validation_policy` ( +`id` , +`regex` , +`description` , +`active` +) +VALUES ( +NULL , '^.{1,50}$', 'Password most be at least 1 character and not more that 50 characters long', '1' +); + +INSERT INTO `m_password_validation_policy` ( +`id` , +`regex` , +`description` , +`active` +) +VALUES ( +NULL , '^(?=.*\\d)(?=.*[a-z])(?=.*[A-Z])(?!.*\\s).{6,50}$', 'Password must be at least 6 characters, no more than 50 characters long, must include at least one upper case letter, one lower case letter, one numeric digit and no space', '0' +); + +INSERT INTO m_permission (grouping, code, entity_name, action_name, can_maker_checker) +VALUE ("authorisation","READ_PASSWORD_PREFERENCES","PASSWORD_PREFERENCES","READ",0); + +INSERT INTO m_permission (grouping, code, entity_name, action_name, can_maker_checker) +VALUE ("authorisation","UPDATE_PASSWORD_PREFERENCES","PASSWORD_PREFERENCES","UPDATE",0); + +INSERT INTO m_permission (grouping, code, entity_name, action_name, can_maker_checker) +VALUE ("authorisation","UPDATE_PASSWORD_PREFERENCES_CHECKER","PASSWORD_PREFERENCES","UPDATE_CHECKER",0); + + + + + diff --git a/ph-ee-operations-app/src/main/resources/sql/migrations/tenant/V23__alter_password_validation_policy.sql b/ph-ee-operations-app/src/main/resources/sql/migrations/tenant/V23__alter_password_validation_policy.sql new file mode 100644 index 000000000..a39ab9869 --- /dev/null +++ b/ph-ee-operations-app/src/main/resources/sql/migrations/tenant/V23__alter_password_validation_policy.sql @@ -0,0 +1,15 @@ +ALTER TABLE `m_staff` +ADD COLUMN `image_id` BIGINT(20) NULL, +ADD CONSTRAINT `FK_m_staff_m_image` FOREIGN KEY (`image_id`) REFERENCES `m_image` (`id`); + +ALTER TABLE `m_password_validation_policy` ADD COLUMN `key` VARCHAR(255) NOT NULL; + +UPDATE `m_password_validation_policy` pvp SET pvp.`key`='simple' where pvp.id='1' ; +UPDATE `m_password_validation_policy` pvp SET pvp.`key`='secure' where pvp.id='2' ; + +ALTER TABLE m_group ADD COLUMN `account_no` VARCHAR(20) NOT NULL; +UPDATE m_group set account_no = lpad(id,9,0); + +ALTER TABLE `m_code_value` ADD COLUMN `is_active` TINYINT(1) NOT NULL DEFAULT '1' AFTER `code_score`; + +alter table `m_code_value` add `is_mandatory` tinyint(1) not null default '0'; diff --git a/ph-ee-operations-app/src/main/resources/sql/migrations/tenant/V24__oauth_changes.sql b/ph-ee-operations-app/src/main/resources/sql/migrations/tenant/V24__oauth_changes.sql new file mode 100644 index 000000000..5c9c8e051 --- /dev/null +++ b/ph-ee-operations-app/src/main/resources/sql/migrations/tenant/V24__oauth_changes.sql @@ -0,0 +1,20 @@ +CREATE TABLE `oauth_client_details` ( + `client_id` varchar(128) NOT NULL, + `resource_ids` varchar(256) DEFAULT NULL, + `client_secret` varchar(256) DEFAULT NULL, + `scope` varchar(256) DEFAULT NULL, + `authorized_grant_types` varchar(256) DEFAULT NULL, + `web_server_redirect_uri` varchar(256) DEFAULT NULL, + `authorities` varchar(256) DEFAULT NULL, + `access_token_validity` int(11) DEFAULT NULL, + `refresh_token_validity` int(11) DEFAULT NULL, + `additional_information` varchar(4096) DEFAULT NULL, + `autoapprove` BIT(1) NULL DEFAULT NULL, + PRIMARY KEY (`client_id`) +) +COLLATE='utf8_general_ci' +ENGINE=InnoDB +AUTO_INCREMENT=1; + +INSERT INTO `oauth_client_details` (`client_id`, `resource_ids`, `scope`, `authorized_grant_types`, `access_token_validity`, `refresh_token_validity`) +VALUES ('client', '${identityProviderResourceId},${tenantDatabase}', 'identity', 'password,refresh_token', ${userAccessTokenValidity}, ${userRefreshTokenValidity}); \ No newline at end of file diff --git a/ph-ee-operations-app/src/main/resources/sql/migrations/tenant/V25__operations_ddl.sql b/ph-ee-operations-app/src/main/resources/sql/migrations/tenant/V25__operations_ddl.sql new file mode 100644 index 000000000..502b7e9bf --- /dev/null +++ b/ph-ee-operations-app/src/main/resources/sql/migrations/tenant/V25__operations_ddl.sql @@ -0,0 +1,91 @@ +CREATE TABLE `businesskeys` ( + `ID` bigint(20) NOT NULL AUTO_INCREMENT, + `BUSINESS_KEY` varchar(255) DEFAULT NULL, + `BUSINESS_KEY_TYPE` varchar(255) DEFAULT NULL, + `TIMESTAMP` bigint(20) DEFAULT NULL, + `WORKFLOW_INSTANCE_KEY` bigint(20) DEFAULT NULL, + PRIMARY KEY (`ID`), + KEY `idx_businessKey` (`BUSINESS_KEY`), + KEY `idx_workflowInstanceKey` (`WORKFLOW_INSTANCE_KEY`), + KEY `idx_businessKeyType` (`BUSINESS_KEY_TYPE`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; + +CREATE TABLE `tasks` ( + `ID` bigint(20) NOT NULL AUTO_INCREMENT, + `ELEMENT_ID` varchar(255) DEFAULT NULL, + `INTENT` varchar(255) DEFAULT NULL, + `RECORD_TYPE` varchar(255) DEFAULT NULL, + `TIMESTAMP` bigint(20) DEFAULT NULL, + `TYPE` varchar(255) DEFAULT NULL, + `WORKFLOW_INSTANCE_KEY` bigint(20) DEFAULT NULL, + `WORKFLOW_KEY` bigint(20) DEFAULT NULL, + PRIMARY KEY (`ID`), + KEY `idx_tasks_key` (`WORKFLOW_INSTANCE_KEY`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; + +CREATE TABLE `transfers` ( + `ID` bigint(20) NOT NULL AUTO_INCREMENT, + `AMOUNT` decimal(38,0) DEFAULT NULL, + `CURRENCY` varchar(255) DEFAULT NULL, + `COMPLETED_AT` datetime DEFAULT NULL, + `DIRECTION` varchar(10) DEFAULT NULL, + `PAYEE_DFSP_ID` varchar(255) DEFAULT NULL, + `PAYEE_FEE` decimal(38,0) DEFAULT NULL, + `PAYEE_FEE_CURRENCY` varchar(255) DEFAULT NULL, + `PAYEE_PARTY_ID` varchar(255) DEFAULT NULL, + `PAYEE_PARTY_ID_TYPE` varchar(255) DEFAULT NULL, + `PAYEE_QUOTE_CODE` varchar(255) DEFAULT NULL, + `PAYER_DFSP_ID` varchar(255) DEFAULT NULL, + `PAYER_FEE` decimal(38,0) DEFAULT NULL, + `PAYER_FEE_CURRENCY` varchar(255) DEFAULT NULL, + `PAYER_PARTY_ID` varchar(255) DEFAULT NULL, + `PAYER_PARTY_ID_TYPE` varchar(255) DEFAULT NULL, + `PAYER_QUOTE_CODE` varchar(255) DEFAULT NULL, + `STARTED_AT` datetime DEFAULT NULL, + `STATUS` varchar(255) DEFAULT NULL, + `STATUS_DETAIL` varchar(255) DEFAULT NULL, + `TRANSACTION_ID` varchar(255) DEFAULT NULL, + `WORKFLOW_INSTANCE_KEY` bigint(20) DEFAULT NULL, + PRIMARY KEY (`ID`), + KEY `idx_transfers_key` (`WORKFLOW_INSTANCE_KEY`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; + +CREATE TABLE `transaction_requests` ( + `ID` bigint(20) NOT NULL AUTO_INCREMENT, + `AMOUNT` decimal(38,0) DEFAULT NULL, + `CURRENCY` varchar(255) DEFAULT NULL, + `COMPLETED_AT` datetime DEFAULT NULL, + `DIRECTION` varchar(10) DEFAULT NULL, + `PAYEE_DFSP_ID` varchar(255) DEFAULT NULL, + `PAYEE_FEE` decimal(38,0) DEFAULT NULL, + `PAYEE_PARTY_ID` varchar(255) DEFAULT NULL, + `PAYEE_PARTY_ID_TYPE` varchar(255) DEFAULT NULL, + `PAYEE_QUOTE_CODE` varchar(255) DEFAULT NULL, + `PAYER_DFSP_ID` varchar(255) DEFAULT NULL, + `PAYER_FEE` decimal(38,0) DEFAULT NULL, + `PAYER_PARTY_ID` varchar(255) DEFAULT NULL, + `PAYER_PARTY_ID_TYPE` varchar(255) DEFAULT NULL, + `PAYER_QUOTE_CODE` varchar(255) DEFAULT NULL, + `STARTED_AT` datetime DEFAULT NULL, + `STATE` varchar(255) DEFAULT NULL, + `TRANSACTION_ID` varchar(255) DEFAULT NULL, + `WORKFLOW_INSTANCE_KEY` bigint(20) DEFAULT NULL, + `AUTH_TYPE` varchar(255) DEFAULT NULL, + `INITIATOR_TYPE` varchar(255) DEFAULT NULL, + `SCENARIO` varchar(255) DEFAULT NULL, + PRIMARY KEY (`ID`), + KEY `idx_transaction_requests_key` (`WORKFLOW_INSTANCE_KEY`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; + +CREATE TABLE `variables` ( + `ID` bigint(20) NOT NULL AUTO_INCREMENT, + `NAME` varchar(255) DEFAULT NULL, + `TIMESTAMP` bigint(20) DEFAULT NULL, + `VALUE` longtext, + `WORKFLOW_INSTANCE_KEY` bigint(20) DEFAULT NULL, + `WORKFLOW_KEY` bigint(20) DEFAULT NULL, + PRIMARY KEY (`ID`), + KEY `idx_variables_key` (`WORKFLOW_INSTANCE_KEY`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; + + diff --git a/ph-ee-operations-app/src/main/resources/sql/migrations/tenant/V26__add_oauth_clients.sql b/ph-ee-operations-app/src/main/resources/sql/migrations/tenant/V26__add_oauth_clients.sql new file mode 100644 index 000000000..9d6927a97 --- /dev/null +++ b/ph-ee-operations-app/src/main/resources/sql/migrations/tenant/V26__add_oauth_clients.sql @@ -0,0 +1,2 @@ +INSERT INTO `oauth_client_details` (`client_id`, `client_secret`, `resource_ids`, `scope`, `authorized_grant_types`, `access_token_validity`, `authorities`) +VALUES ('channel-${tenantDatabase}', '${channelClientSecret}', '${identityProviderResourceId},${tenantDatabase}', 'identity', 'client_credentials', ${clientAccessTokenValidity}, 'ALL_FUNCTIONS'); \ No newline at end of file diff --git a/ph-ee-operations-app/src/main/resources/sql/migrations/tenant/V27__add_refund_permission.sql b/ph-ee-operations-app/src/main/resources/sql/migrations/tenant/V27__add_refund_permission.sql new file mode 100644 index 000000000..63cb09706 --- /dev/null +++ b/ph-ee-operations-app/src/main/resources/sql/migrations/tenant/V27__add_refund_permission.sql @@ -0,0 +1,7 @@ +INSERT INTO `m_permission` (`grouping`, `code`, `entity_name`, `action_name`, `can_maker_checker`) +VALUES ('operations', 'REFUND', 'TRANSFER', 'ACTIVATE', '0'); + +INSERT INTO m_role_permission(role_id, permission_id) +select 1, id +from m_permission +where code = 'REFUND'; \ No newline at end of file diff --git a/ph-ee-operations-app/src/main/resources/sql/migrations/tenant/V28__currency_rate_master.sql b/ph-ee-operations-app/src/main/resources/sql/migrations/tenant/V28__currency_rate_master.sql new file mode 100644 index 000000000..564884b64 --- /dev/null +++ b/ph-ee-operations-app/src/main/resources/sql/migrations/tenant/V28__currency_rate_master.sql @@ -0,0 +1,9 @@ +CREATE TABLE `m_currency_rates` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT, + `from_currency` varchar(5) NOT NULL, + `to_currency` varchar(5) NOT NULL, + `rate` decimal(19,6) NOT NULL DEFAULT '0.000000', + `last_updated` datetime DEFAULT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `exchange_UNIQUE` (`from_currency` ,`to_currency`) +); \ No newline at end of file diff --git a/ph-ee-operations-app/src/main/resources/sql/migrations/tenant/V29__beneficiary_list.sql b/ph-ee-operations-app/src/main/resources/sql/migrations/tenant/V29__beneficiary_list.sql new file mode 100644 index 000000000..01202cdb4 --- /dev/null +++ b/ph-ee-operations-app/src/main/resources/sql/migrations/tenant/V29__beneficiary_list.sql @@ -0,0 +1,13 @@ +CREATE TABLE `m_beneficiary` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT, + `c_identifier` varchar(100) NOT NULL, + `b_name` varchar(100) DEFAULT NULL, + `b_nick_name` varchar(100) DEFAULT NULL, + `b_identifier` varchar(100) DEFAULT NULL, + `b_account_no` varchar(100) DEFAULT NULL, + `b_leId` varchar(100) DEFAULT NULL, + `b_currency_code` varchar(100) DEFAULT NULL, + `b_country_code` varchar(100) DEFAULT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `beneficiary_UNIQUE` (`c_identifier`,`b_identifier`) +); \ No newline at end of file diff --git a/ph-ee-operations-app/src/main/resources/sql/migrations/tenant/V2__core-ddl-latest.sql b/ph-ee-operations-app/src/main/resources/sql/migrations/tenant/V2__core-ddl-latest.sql new file mode 100644 index 000000000..03a9da9e8 --- /dev/null +++ b/ph-ee-operations-app/src/main/resources/sql/migrations/tenant/V2__core-ddl-latest.sql @@ -0,0 +1,168 @@ +-- +-- Licensed to the Apache Software Foundation (ASF) under one +-- or more contributor license agreements. See the NOTICE file +-- distributed with this work for additional information +-- regarding copyright ownership. The ASF licenses this file +-- to you under the Apache License, Version 2.0 (the +-- "License"); you may not use this file except in compliance +-- with the License. You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, +-- software distributed under the License is distributed on an +-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +-- KIND, either express or implied. See the License for the +-- specific language governing permissions and limitations +-- under the License. +-- + +CREATE TABLE `m_code` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `code_name` varchar(100) DEFAULT NULL, + `is_system_defined` TINYINT(1) NOT NULL DEFAULT '0', + PRIMARY KEY (`id`), + UNIQUE KEY `code_name` (`code_name`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +CREATE TABLE `m_code_value` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `code_id` int(11) NOT NULL, + `code_value` varchar(100) DEFAULT NULL, + `order_position` int(11) NOT NULL DEFAULT '0', + PRIMARY KEY (`id`), + UNIQUE KEY `code_value` (`code_id`,`code_value`), + KEY `FKCFCEA42640BE071Z` (`code_id`), + CONSTRAINT `FKCFCEA42640BE071Z` FOREIGN KEY (`code_id`) REFERENCES `m_code` (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +CREATE TABLE `m_document` ( + `id` int(20) NOT NULL AUTO_INCREMENT, + `parent_entity_type` varchar(50) NOT NULL, + `parent_entity_id` int(20) NOT NULL DEFAULT '0', + `name` varchar(250) NOT NULL, + `file_name` varchar(250) NOT NULL, + `size` int(20) DEFAULT '0', + `type` varchar(50) DEFAULT NULL, + `description` varchar(1000) DEFAULT NULL, + `location` varchar(500) NOT NULL DEFAULT '0', + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +CREATE TABLE `m_office` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT, + `parent_id` bigint(20) DEFAULT NULL, + `hierarchy` varchar(100) DEFAULT NULL, + `external_id` varchar(100) DEFAULT NULL, + `name` varchar(50) NOT NULL, + `opening_date` date NOT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `name_org` (`name`), + UNIQUE KEY `externalid_org` (`external_id`), + KEY `FK2291C477E2551DCC` (`parent_id`), + CONSTRAINT `FK2291C477E2551DCC` FOREIGN KEY (`parent_id`) REFERENCES `m_office` (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +CREATE TABLE `m_permission` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT, + `grouping` varchar(45) DEFAULT NULL, + `code` varchar(100) NOT NULL, + `entity_name` varchar(100) DEFAULT NULL, + `action_name` varchar(100) DEFAULT NULL, + `can_maker_checker` tinyint(1) NOT NULL DEFAULT '1', + PRIMARY KEY (`id`), + UNIQUE KEY `code` (`code`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +CREATE TABLE `m_role` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT, + `name` varchar(100) NOT NULL, + `description` varchar(500) NOT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `unq_name` (`name`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +CREATE TABLE `m_role_permission` ( + `role_id` bigint(20) NOT NULL, + `permission_id` bigint(20) NOT NULL, + PRIMARY KEY (`role_id`,`permission_id`), + KEY `FK8DEDB04815CEC7AB` (`role_id`), + KEY `FK8DEDB048103B544B` (`permission_id`), + CONSTRAINT `FK8DEDB048103B544B` FOREIGN KEY (`permission_id`) REFERENCES `m_permission` (`id`), + CONSTRAINT `FK8DEDB04815CEC7AB` FOREIGN KEY (`role_id`) REFERENCES `m_role` (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +CREATE TABLE `m_appuser` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT, + `is_deleted` tinyint(1) NOT NULL DEFAULT '0', + `office_id` bigint(20) DEFAULT NULL, + `username` varchar(100) NOT NULL, + `firstname` varchar(100) NOT NULL, + `lastname` varchar(100) NOT NULL, + `password` varchar(255) NOT NULL, + `email` varchar(100) NOT NULL, + `firsttime_login_remaining` bit(1) NOT NULL, + `nonexpired` bit(1) NOT NULL, + `nonlocked` bit(1) NOT NULL, + `nonexpired_credentials` bit(1) NOT NULL, + `enabled` bit(1) NOT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `username_org` (`username`), + KEY `FKB3D587CE0DD567A` (`office_id`), + CONSTRAINT `FKB3D587CE0DD567A` FOREIGN KEY (`office_id`) REFERENCES `m_office` (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +CREATE TABLE `m_appuser_role` ( + `appuser_id` bigint(20) NOT NULL, + `role_id` bigint(20) NOT NULL, + PRIMARY KEY (`appuser_id`,`role_id`), + KEY `FK7662CE59B4100309` (`appuser_id`), + KEY `FK7662CE5915CEC7AB` (`role_id`), + CONSTRAINT `FK7662CE5915CEC7AB` FOREIGN KEY (`role_id`) REFERENCES `m_role` (`id`), + CONSTRAINT `FK7662CE59B4100309` FOREIGN KEY (`appuser_id`) REFERENCES `m_appuser` (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +CREATE TABLE `m_staff` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT, + `is_loan_officer` tinyint(1) NOT NULL DEFAULT '0', + `office_id` bigint(20) DEFAULT NULL, + `firstname` varchar(50) DEFAULT NULL, + `lastname` varchar(50) DEFAULT NULL, + `display_name` varchar(100) NOT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `display_name` (`display_name`), + KEY `FK_m_staff_m_office` (`office_id`), + CONSTRAINT `FK_m_staff_m_office` FOREIGN KEY (`office_id`) REFERENCES `m_office` (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +CREATE TABLE `m_group_level` ( +`id` INT(11) NOT NULL AUTO_INCREMENT, +`parent_id` INT(11) NULL DEFAULT NULL, +`super_parent` TINYINT(1) NOT NULL, +`level_name` VARCHAR(100) NOT NULL, +`recursable` TINYINT(1) NOT NULL, +PRIMARY KEY (`id`), +INDEX `Parent_levelId_reference` (`parent_id`), +CONSTRAINT `Parent_levelId_reference` FOREIGN KEY (`parent_id`) REFERENCES `m_group_level` (`id`) +)ENGINE=InnoDB DEFAULT CHARSET=utf8; + +CREATE TABLE `m_group` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT, + `office_id` bigint(20) NOT NULL, + `staff_id` BIGINT(20) DEFAULT NULL, + `parent_id` BIGINT(20) NULL DEFAULT NULL, + `level_Id` INT(11) NOT NULL, + `hierarchy` VARCHAR(100) NULL DEFAULT NULL, + `name` varchar(100) NOT NULL, + `external_id` varchar(100) DEFAULT NULL, + `is_deleted` tinyint(1) NOT NULL DEFAULT '0', + PRIMARY KEY (`id`), + UNIQUE KEY `name` (`name`, `level_id`), + UNIQUE KEY `external_id` (`external_id`, `level_Id`), + KEY `office_id` (`office_id`), + KEY `staff_id` (`staff_id`), + CONSTRAINT `m_group_ibfk_1` FOREIGN KEY (`office_id`) REFERENCES `m_office` (`id`), + CONSTRAINT `Parent_Id_reference` FOREIGN KEY (`parent_id`) REFERENCES `m_group` (`id`), + CONSTRAINT `FK_m_group_level` FOREIGN KEY (`level_Id`) REFERENCES `m_group_level` (`id`), + CONSTRAINT `FK_m_group_m_staff` FOREIGN KEY (`staff_id`) REFERENCES `m_staff` (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; diff --git a/ph-ee-operations-app/src/main/resources/sql/migrations/tenant/V30__currency_rate_temp_lock.sql b/ph-ee-operations-app/src/main/resources/sql/migrations/tenant/V30__currency_rate_temp_lock.sql new file mode 100644 index 000000000..8bc4b9447 --- /dev/null +++ b/ph-ee-operations-app/src/main/resources/sql/migrations/tenant/V30__currency_rate_temp_lock.sql @@ -0,0 +1,9 @@ +CREATE TABLE `m_currency_rates_lock` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT, + `unique_key` varchar(100) NOT NULL UNIQUE, + `from_currency` varchar(5) NOT NULL, + `to_currency` varchar(5) NOT NULL, + `rate` decimal(19,6) NOT NULL DEFAULT '0.000000', + `expire_by` datetime NOT NULL, + PRIMARY KEY (`id`) +) ; \ No newline at end of file diff --git a/ph-ee-operations-app/src/main/resources/sql/migrations/tenant/V31__batch_transfer.sql b/ph-ee-operations-app/src/main/resources/sql/migrations/tenant/V31__batch_transfer.sql new file mode 100644 index 000000000..439996dbc --- /dev/null +++ b/ph-ee-operations-app/src/main/resources/sql/migrations/tenant/V31__batch_transfer.sql @@ -0,0 +1,24 @@ +CREATE TABLE `batches` ( + `ID` bigint(20) NOT NULL AUTO_INCREMENT, + `BATCH_ID` varchar(255) DEFAULT NULL, + `REQUEST_ID` varchar(255) DEFAULT NULL, + `REQUEST_FILE` varchar(255) DEFAULT NULL, + `TOTAL_TRANSACTIONS` bigint(20) DEFAULT NULL, + `ONGOING` bigint(20) DEFAULT NULL, + `FAILED` bigint(20) DEFAULT NULL, + `COMPLETED` bigint(20) DEFAULT NULL, + `RESULT_FILE` varchar(255) DEFAULT NULL, + `RESULT_GENERATED_AT` datetime DEFAULT NULL, + `NOTE` varchar(255) DEFAULT NULL, + `WORKFLOW_INSTANCE_KEY` bigint(20) DEFAULT NULL, + `WORKFLOW_KEY` bigint(20) DEFAULT NULL, + `STARTED_AT` datetime DEFAULT NULL, + `COMPLETED_AT` datetime DEFAULT NULL, + PRIMARY KEY (`ID`), + KEY `idx_batches_key` (`WORKFLOW_INSTANCE_KEY`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; + + +ALTER TABLE `transfers` + ADD `ERROR_INFORMATION` longtext DEFAULT NULL, + ADD `BATCH_ID` varchar(255) DEFAULT NULL; \ No newline at end of file diff --git a/ph-ee-operations-app/src/main/resources/sql/migrations/tenant/V32__errorcode.sql b/ph-ee-operations-app/src/main/resources/sql/migrations/tenant/V32__errorcode.sql new file mode 100644 index 000000000..dc4540577 --- /dev/null +++ b/ph-ee-operations-app/src/main/resources/sql/migrations/tenant/V32__errorcode.sql @@ -0,0 +1,8 @@ +CREATE TABLE `errorcode` ( + `ID` bigint(20) NOT NULL AUTO_INCREMENT, + `TRANSACTION_TYPE` text DEFAULT NULL, + `ERROR_MESSAGE` text DEFAULT NULL, + `ERROR_CODE` text DEFAULT NULL, + `RECOVERABLE` tinyint DEFAULT 0, + PRIMARY KEY (`ID`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; \ No newline at end of file diff --git a/ph-ee-operations-app/src/main/resources/sql/migrations/tenant/V33__insert_errorcode.sql b/ph-ee-operations-app/src/main/resources/sql/migrations/tenant/V33__insert_errorcode.sql new file mode 100644 index 000000000..fb18d535e --- /dev/null +++ b/ph-ee-operations-app/src/main/resources/sql/migrations/tenant/V33__insert_errorcode.sql @@ -0,0 +1,32 @@ +INSERT INTO `errorcode` (`TRANSACTION_TYPE`, `ERROR_MESSAGE`, `ERROR_CODE`, `RECOVERABLE`) +VALUES ( + 'COLLECTION-MPESA', + 'The transaction is being processed', + '500.001.1001', + true +); + +INSERT INTO `errorcode` (`TRANSACTION_TYPE`, `ERROR_MESSAGE`, `ERROR_CODE`, `RECOVERABLE`) +VALUES ( + 'COLLECTION-MPESA', + 'DS timeout.', + '1037', + true +); + +INSERT INTO `errorcode` (`TRANSACTION_TYPE`, `ERROR_MESSAGE`, `ERROR_CODE`, `RECOVERABLE`) +VALUES ( + 'COLLECTION-MPESA', + 'Request cancelled by user', + '1031', + false +); + +INSERT INTO `errorcode` (`TRANSACTION_TYPE`, `ERROR_MESSAGE`, `ERROR_CODE`, `RECOVERABLE`) +VALUES ( + 'COLLECTION-MPESA', + 'Request cancelled by user', + '1032', + false +); + diff --git a/ph-ee-operations-app/src/main/resources/sql/migrations/tenant/V34__errorcode_fix.sql b/ph-ee-operations-app/src/main/resources/sql/migrations/tenant/V34__errorcode_fix.sql new file mode 100644 index 000000000..491a67ab7 --- /dev/null +++ b/ph-ee-operations-app/src/main/resources/sql/migrations/tenant/V34__errorcode_fix.sql @@ -0,0 +1,3 @@ +DELETE FROM `errorcode` WHERE `RECOVERABLE`=false; + +DELETE FROM `errorcode` WHERE `ERROR_MESSAGE`='DS timeout.' diff --git a/ph-ee-operations-app/src/main/resources/sql/migrations/tenant/V35__insert_errorcode.sql b/ph-ee-operations-app/src/main/resources/sql/migrations/tenant/V35__insert_errorcode.sql new file mode 100644 index 000000000..a35dc722f --- /dev/null +++ b/ph-ee-operations-app/src/main/resources/sql/migrations/tenant/V35__insert_errorcode.sql @@ -0,0 +1,24 @@ +INSERT INTO `errorcode` (`TRANSACTION_TYPE`, `ERROR_MESSAGE`, `ERROR_CODE`, `RECOVERABLE`) +VALUES ( + 'COLLECTION-MPESA', + '', + 'BWENGINE-100029', + true +); + +INSERT INTO `errorcode` (`TRANSACTION_TYPE`, `ERROR_MESSAGE`, `ERROR_CODE`, `RECOVERABLE`) +VALUES ( + 'COLLECTION-MPESA', + '', + 'BW-HTTP-100300', + true +); + + +INSERT INTO `errorcode` (`TRANSACTION_TYPE`, `ERROR_MESSAGE`, `ERROR_CODE`, `RECOVERABLE`) +VALUES ( + 'COLLECTION-MPESA', + 'System busy. The service request is rejected.', + '26', + true +); diff --git a/ph-ee-operations-app/src/main/resources/sql/migrations/tenant/V36__add_external_id_in_transaction_request_table.sql b/ph-ee-operations-app/src/main/resources/sql/migrations/tenant/V36__add_external_id_in_transaction_request_table.sql new file mode 100644 index 000000000..b4991b18a --- /dev/null +++ b/ph-ee-operations-app/src/main/resources/sql/migrations/tenant/V36__add_external_id_in_transaction_request_table.sql @@ -0,0 +1,2 @@ +ALTER TABLE `transaction_requests` + ADD `EXTERNAL_ID` VARCHAR(255); \ No newline at end of file diff --git a/ph-ee-operations-app/src/main/resources/sql/migrations/tenant/V37__add_sub_batch_id_field_in_batches.sql b/ph-ee-operations-app/src/main/resources/sql/migrations/tenant/V37__add_sub_batch_id_field_in_batches.sql new file mode 100644 index 000000000..eaafb48ba --- /dev/null +++ b/ph-ee-operations-app/src/main/resources/sql/migrations/tenant/V37__add_sub_batch_id_field_in_batches.sql @@ -0,0 +1,23 @@ +-- +-- Licensed to the Apache Software Foundation (ASF) under one +-- or more contributor license agreements. See the NOTICE file +-- distributed with this work for additional information +-- regarding copyright ownership. The ASF licenses this file +-- to you under the Apache License, Version 2.0 (the +-- "License"); you may not use this file except in compliance +-- with the License. You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, +-- software distributed under the License is distributed on an +-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +-- KIND, either express or implied. See the License for the +-- specific language governing permissions and limitations +-- under the License. +-- + + + +ALTER TABLE `batches` +ADD COLUMN `SUB_BATCH_ID` VARCHAR(255) DEFAULT NULL; diff --git a/ph-ee-operations-app/src/main/resources/sql/migrations/tenant/V38__add_amount_fields_in_batches.sql b/ph-ee-operations-app/src/main/resources/sql/migrations/tenant/V38__add_amount_fields_in_batches.sql new file mode 100644 index 000000000..c49a3b432 --- /dev/null +++ b/ph-ee-operations-app/src/main/resources/sql/migrations/tenant/V38__add_amount_fields_in_batches.sql @@ -0,0 +1,26 @@ +-- +-- Licensed to the Apache Software Foundation (ASF) under one +-- or more contributor license agreements. See the NOTICE file +-- distributed with this work for additional information +-- regarding copyright ownership. The ASF licenses this file +-- to you under the Apache License, Version 2.0 (the +-- "License"); you may not use this file except in compliance +-- with the License. You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, +-- software distributed under the License is distributed on an +-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +-- KIND, either express or implied. See the License for the +-- specific language governing permissions and limitations +-- under the License. +-- + + + +ALTER TABLE `batches` +ADD COLUMN `TOTAL_AMOUNT` bigint(20) DEFAULT NULL, +ADD COLUMN `ONGOING_AMOUNT` bigint(20) DEFAULT NULL, +ADD COLUMN `FAILED_AMOUNT` bigint(20) DEFAULT NULL, +ADD COLUMN `COMPLETED_AMOUNT` bigint(20) DEFAULT NULL; diff --git a/ph-ee-operations-app/src/main/resources/sql/migrations/tenant/V39__add_mode_field_in_batches.sql b/ph-ee-operations-app/src/main/resources/sql/migrations/tenant/V39__add_mode_field_in_batches.sql new file mode 100644 index 000000000..d6a180725 --- /dev/null +++ b/ph-ee-operations-app/src/main/resources/sql/migrations/tenant/V39__add_mode_field_in_batches.sql @@ -0,0 +1,23 @@ +-- +-- Licensed to the Apache Software Foundation (ASF) under one +-- or more contributor license agreements. See the NOTICE file +-- distributed with this work for additional information +-- regarding copyright ownership. The ASF licenses this file +-- to you under the Apache License, Version 2.0 (the +-- "License"); you may not use this file except in compliance +-- with the License. You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, +-- software distributed under the License is distributed on an +-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +-- KIND, either express or implied. See the License for the +-- specific language governing permissions and limitations +-- under the License. +-- + + + +ALTER TABLE `batches` +ADD COLUMN `PAYMENT_MODE` VARCHAR(255) DEFAULT NULL; diff --git a/ph-ee-operations-app/src/main/resources/sql/migrations/tenant/V3__base-reference-data-utf8.sql b/ph-ee-operations-app/src/main/resources/sql/migrations/tenant/V3__base-reference-data-utf8.sql new file mode 100644 index 000000000..c3b70ffe2 --- /dev/null +++ b/ph-ee-operations-app/src/main/resources/sql/migrations/tenant/V3__base-reference-data-utf8.sql @@ -0,0 +1,53 @@ +-- +-- Licensed to the Apache Software Foundation (ASF) under one +-- or more contributor license agreements. See the NOTICE file +-- distributed with this work for additional information +-- regarding copyright ownership. The ASF licenses this file +-- to you under the Apache License, Version 2.0 (the +-- "License"); you may not use this file except in compliance +-- with the License. You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, +-- software distributed under the License is distributed on an +-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +-- KIND, either express or implied. See the License for the +-- specific language governing permissions and limitations +-- under the License. +-- + +INSERT INTO `m_office` (`id`, `parent_id`, `hierarchy`, `external_id`, `name`, `opening_date`) +VALUES +(1,NULL,'.','1','Head Office','2009-01-01'); + +INSERT INTO `m_group_level` (`id`, `parent_id`, `super_parent`, `level_name`, `recursable`) +VALUES (1, NULL, 1, 'Center', 1); +INSERT INTO `m_group_level` (`id`, `parent_id`, `super_parent`, `level_name`, `recursable`) +VALUES (2, 1, 0, 'Group', 0); + +-- create single code and code value for client identifiers +INSERT INTO `m_code` +(`code_name`, `is_system_defined`) +VALUES +('Customer Identifier',1), +('LoanCollateral',1), +('LoanPurpose',1), +('Gender',1), +('YesNo',1), +('GuarantorRelationship',1); + +INSERT INTO `m_code_value`(`code_id`,`code_value`,`order_position`) +select mc.id, 'Passport', 1 +from m_code mc +where mc.`code_name` = "Customer Identifier"; + +INSERT INTO `m_code_value`(`code_id`,`code_value`,`order_position`) +select mc.id, 'Id', 2 +from m_code mc +where mc.`code_name` = "Customer Identifier"; + +INSERT INTO `m_code_value`(`code_id`,`code_value`,`order_position`) +select mc.id, 'Drivers License', 3 +from m_code mc +where mc.`code_name` = "Customer Identifier"; diff --git a/ph-ee-operations-app/src/main/resources/sql/migrations/tenant/V40__add_empty_encoded_string_in_oauth_client_details.sql b/ph-ee-operations-app/src/main/resources/sql/migrations/tenant/V40__add_empty_encoded_string_in_oauth_client_details.sql new file mode 100644 index 000000000..b243b36bd --- /dev/null +++ b/ph-ee-operations-app/src/main/resources/sql/migrations/tenant/V40__add_empty_encoded_string_in_oauth_client_details.sql @@ -0,0 +1,22 @@ +-- +-- Licensed to the Apache Software Foundation (ASF) under one +-- or more contributor license agreements. See the NOTICE file +-- distributed with this work for additional information +-- regarding copyright ownership. The ASF licenses this file +-- to you under the Apache License, Version 2.0 (the +-- "License"); you may not use this file except in compliance +-- with the License. You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, +-- software distributed under the License is distributed on an +-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +-- KIND, either express or implied. See the License for the +-- specific language governing permissions and limitations +-- under the License. +-- + +UPDATE `oauth_client_details` t +SET t.client_secret = "$2a$10$95Awfz7pxeg.IMywl.NlTu8L6c1ecuP.IRTDpBgO7A.MfTBlVw46W" +WHERE t.client_id = "client"; diff --git a/ph-ee-operations-app/src/main/resources/sql/migrations/tenant/V41__add_clientcorrealationid_in_transfers_transactionreq.sql b/ph-ee-operations-app/src/main/resources/sql/migrations/tenant/V41__add_clientcorrealationid_in_transfers_transactionreq.sql new file mode 100644 index 000000000..0b886c04c --- /dev/null +++ b/ph-ee-operations-app/src/main/resources/sql/migrations/tenant/V41__add_clientcorrealationid_in_transfers_transactionreq.sql @@ -0,0 +1,26 @@ +-- +-- Licensed to the Apache Software Foundation (ASF) under one +-- or more contributor license agreements. See the NOTICE file +-- distributed with this work for additional information +-- regarding copyright ownership. The ASF licenses this file +-- to you under the Apache License, Version 2.0 (the +-- "License"); you may not use this file except in compliance +-- with the License. You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, +-- software distributed under the License is distributed on an +-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +-- KIND, either express or implied. See the License for the +-- specific language governing permissions and limitations +-- under the License. +-- + + + +ALTER TABLE `transaction_requests` + ADD `CLIENTCORRELATIONID` VARCHAR(255); + +ALTER TABLE `transfers` + ADD `CLIENTCORRELATIONID` VARCHAR(255); diff --git a/ph-ee-operations-app/src/main/resources/sql/migrations/tenant/V42__add_error_information_in_transaction_request_table.sql b/ph-ee-operations-app/src/main/resources/sql/migrations/tenant/V42__add_error_information_in_transaction_request_table.sql new file mode 100644 index 000000000..7568af7cd --- /dev/null +++ b/ph-ee-operations-app/src/main/resources/sql/migrations/tenant/V42__add_error_information_in_transaction_request_table.sql @@ -0,0 +1,2 @@ +ALTER TABLE `transaction_requests` + ADD `ERROR_INFORMATION` LONGTEXT; diff --git a/ph-ee-operations-app/src/main/resources/sql/migrations/tenant/V43__add_budget_account_approve_field_in_batch.sql b/ph-ee-operations-app/src/main/resources/sql/migrations/tenant/V43__add_budget_account_approve_field_in_batch.sql new file mode 100644 index 000000000..8501facb6 --- /dev/null +++ b/ph-ee-operations-app/src/main/resources/sql/migrations/tenant/V43__add_budget_account_approve_field_in_batch.sql @@ -0,0 +1,14 @@ +ALTER TABLE `batches` + ADD COLUMN `PAYER_FSP` VARCHAR(255) DEFAULT NULL; + +ALTER TABLE `batches` + ADD COLUMN `REGISTERING_INSTITUTION_ID` VARCHAR(255) DEFAULT NULL; + +ALTER TABLE `batches` + ADD COLUMN `CLIENT_CORRELATION_ID` VARCHAR(255) DEFAULT NULL; + +ALTER TABLE `batches` + ADD COLUMN `APPROVED_AMOUNT` BIGINT(20) DEFAULT 0; + +ALTER TABLE `batches` + ADD COLUMN `APPROVED_COUNT` BIGINT(20) DEFAULT 0; diff --git a/ph-ee-operations-app/src/main/resources/sql/migrations/tenant/V44__add_sub_batch_id_in_transfers_tabe.sql b/ph-ee-operations-app/src/main/resources/sql/migrations/tenant/V44__add_sub_batch_id_in_transfers_tabe.sql new file mode 100644 index 000000000..ba82c89ce --- /dev/null +++ b/ph-ee-operations-app/src/main/resources/sql/migrations/tenant/V44__add_sub_batch_id_in_transfers_tabe.sql @@ -0,0 +1,2 @@ +ALTER TABLE `transfers` + ADD COLUMN `SUB_BATCH_ID` VARCHAR(255) DEFAULT NULL; diff --git a/ph-ee-operations-app/src/main/resources/sql/migrations/tenant/V45__add_status_in_batches_tabe.sql b/ph-ee-operations-app/src/main/resources/sql/migrations/tenant/V45__add_status_in_batches_tabe.sql new file mode 100644 index 000000000..bfc9e0a91 --- /dev/null +++ b/ph-ee-operations-app/src/main/resources/sql/migrations/tenant/V45__add_status_in_batches_tabe.sql @@ -0,0 +1,2 @@ +ALTER TABLE `batches` + ADD COLUMN `STATUS` VARCHAR(255) DEFAULT NULL; \ No newline at end of file diff --git a/ph-ee-operations-app/src/main/resources/sql/migrations/tenant/V4__permissions-and-authorisation-utf8.sql b/ph-ee-operations-app/src/main/resources/sql/migrations/tenant/V4__permissions-and-authorisation-utf8.sql new file mode 100644 index 000000000..538f37a7c --- /dev/null +++ b/ph-ee-operations-app/src/main/resources/sql/migrations/tenant/V4__permissions-and-authorisation-utf8.sql @@ -0,0 +1,41 @@ +-- +-- Licensed to the Apache Software Foundation (ASF) under one +-- or more contributor license agreements. See the NOTICE file +-- distributed with this work for additional information +-- regarding copyright ownership. The ASF licenses this file +-- to you under the Apache License, Version 2.0 (the +-- "License"); you may not use this file except in compliance +-- with the License. You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, +-- software distributed under the License is distributed on an +-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +-- KIND, either express or implied. See the License for the +-- specific language governing permissions and limitations +-- under the License. +-- + +INSERT INTO `m_permission` +(`grouping`,`code`,`entity_name`,`action_name`,`can_maker_checker`) VALUES +('special','ALL_FUNCTIONS',NULL,NULL,0), +('special','ALL_FUNCTIONS_READ',NULL,NULL,0), +('special', 'CHECKER_SUPER_USER', NULL, NULL, '0'), +('special','REPORTING_SUPER_USER',NULL,NULL,0); + +INSERT INTO `m_role` (`id`, `name`, `description`) +VALUES +(1,'Super user','This role provides all application permissions.'); + +INSERT INTO m_role_permission(role_id, permission_id) +select 1, id +from m_permission +where code = 'ALL_FUNCTIONS'; + +INSERT INTO `m_appuser` (`id`, `office_id`, `username`, `firstname`, `lastname`, `password`, `email`, `firsttime_login_remaining`, `nonexpired`, `nonlocked`, `nonexpired_credentials`, `enabled`) +VALUES (1, 1, 'mifos', 'App', 'Administrator', '$2a$10$/rF0VNbTctI1034UwHPHr.XiQxBU3gCbKY/haNtWQTLpqfx8FH0gi', 'demomfi@mifos.org', '\0','','','',''); + +INSERT INTO `m_appuser_role` (`appuser_id`, `role_id`) VALUES (1,1); + +update m_permission set can_maker_checker = false; \ No newline at end of file diff --git a/ph-ee-operations-app/src/main/resources/sql/migrations/tenant/V5__add_external_id_to_couple_of_tables.sql b/ph-ee-operations-app/src/main/resources/sql/migrations/tenant/V5__add_external_id_to_couple_of_tables.sql new file mode 100644 index 000000000..4404c1b8b --- /dev/null +++ b/ph-ee-operations-app/src/main/resources/sql/migrations/tenant/V5__add_external_id_to_couple_of_tables.sql @@ -0,0 +1,28 @@ +-- +-- Licensed to the Apache Software Foundation (ASF) under one +-- or more contributor license agreements. See the NOTICE file +-- distributed with this work for additional information +-- regarding copyright ownership. The ASF licenses this file +-- to you under the Apache License, Version 2.0 (the +-- "License"); you may not use this file except in compliance +-- with the License. You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, +-- software distributed under the License is distributed on an +-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +-- KIND, either express or implied. See the License for the +-- specific language governing permissions and limitations +-- under the License. +-- + +ALTER TABLE m_group + ADD UNIQUE INDEX `external_id_UNIQUE` (`external_id` ASC) ; + +ALTER TABLE m_staff + ADD COLUMN `external_id` VARCHAR(100) NULL AFTER `display_name` , + ADD UNIQUE INDEX `external_id_UNIQUE` (`external_id` ASC) ; + +ALTER TABLE m_group + ADD COLUMN `status_id` INT(5) NOT NULL DEFAULT 300 AFTER `is_deleted` ; diff --git a/ph-ee-operations-app/src/main/resources/sql/migrations/tenant/V6__rename_status_id_to_enum.sql b/ph-ee-operations-app/src/main/resources/sql/migrations/tenant/V6__rename_status_id_to_enum.sql new file mode 100644 index 000000000..a87b991e3 --- /dev/null +++ b/ph-ee-operations-app/src/main/resources/sql/migrations/tenant/V6__rename_status_id_to_enum.sql @@ -0,0 +1,22 @@ +-- +-- Licensed to the Apache Software Foundation (ASF) under one +-- or more contributor license agreements. See the NOTICE file +-- distributed with this work for additional information +-- regarding copyright ownership. The ASF licenses this file +-- to you under the Apache License, Version 2.0 (the +-- "License"); you may not use this file except in compliance +-- with the License. You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, +-- software distributed under the License is distributed on an +-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +-- KIND, either express or implied. See the License for the +-- specific language governing permissions and limitations +-- under the License. +-- + + +ALTER TABLE m_group CHANGE COLUMN `status_id` `status_enum` INT(5) NOT NULL DEFAULT '300' ; + diff --git a/ph-ee-operations-app/src/main/resources/sql/migrations/tenant/V7__alter-group-for-consistency-add-permissions.sql b/ph-ee-operations-app/src/main/resources/sql/migrations/tenant/V7__alter-group-for-consistency-add-permissions.sql new file mode 100644 index 000000000..6fe53277c --- /dev/null +++ b/ph-ee-operations-app/src/main/resources/sql/migrations/tenant/V7__alter-group-for-consistency-add-permissions.sql @@ -0,0 +1,31 @@ +-- +-- Licensed to the Apache Software Foundation (ASF) under one +-- or more contributor license agreements. See the NOTICE file +-- distributed with this work for additional information +-- regarding copyright ownership. The ASF licenses this file +-- to you under the Apache License, Version 2.0 (the +-- "License"); you may not use this file except in compliance +-- with the License. You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, +-- software distributed under the License is distributed on an +-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +-- KIND, either express or implied. See the License for the +-- specific language governing permissions and limitations +-- under the License. +-- + +ALTER TABLE `m_group` DROP FOREIGN KEY `FK_m_group_level`; +ALTER TABLE `m_group` +CHANGE COLUMN `external_id` `external_id` VARCHAR(100) NULL DEFAULT NULL AFTER `id`, +CHANGE COLUMN `status_enum` `status_enum` INT(5) NOT NULL DEFAULT '300' AFTER `external_id`, +CHANGE COLUMN `name` `display_name` VARCHAR(100) NOT NULL AFTER `level_id`, +CHANGE COLUMN `level_Id` `level_id` INT(11) NOT NULL, +ADD CONSTRAINT `FK_m_group_level` FOREIGN KEY (`level_id`) REFERENCES `m_group_level` (`id`); + + +ALTER TABLE `m_group` +DROP COLUMN `is_deleted`, +ADD COLUMN `activation_date` DATE NULL DEFAULT NULL AFTER `status_enum` ; \ No newline at end of file diff --git a/ph-ee-operations-app/src/main/resources/sql/migrations/tenant/V8__document-increase-size-of-column-type.sql b/ph-ee-operations-app/src/main/resources/sql/migrations/tenant/V8__document-increase-size-of-column-type.sql new file mode 100644 index 000000000..6424ed2fa --- /dev/null +++ b/ph-ee-operations-app/src/main/resources/sql/migrations/tenant/V8__document-increase-size-of-column-type.sql @@ -0,0 +1,21 @@ +-- +-- Licensed to the Apache Software Foundation (ASF) under one +-- or more contributor license agreements. See the NOTICE file +-- distributed with this work for additional information +-- regarding copyright ownership. The ASF licenses this file +-- to you under the Apache License, Version 2.0 (the +-- "License"); you may not use this file except in compliance +-- with the License. You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, +-- software distributed under the License is distributed on an +-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +-- KIND, either express or implied. See the License for the +-- specific language governing permissions and limitations +-- under the License. +-- + +ALTER TABLE `m_document` + CHANGE COLUMN `type` `type` VARCHAR(500) NULL DEFAULT NULL AFTER `size`; \ No newline at end of file diff --git a/ph-ee-operations-app/src/main/resources/sql/migrations/tenant/V9__staff-hierarchy-link-to-users.sql b/ph-ee-operations-app/src/main/resources/sql/migrations/tenant/V9__staff-hierarchy-link-to-users.sql new file mode 100644 index 000000000..d83a733bd --- /dev/null +++ b/ph-ee-operations-app/src/main/resources/sql/migrations/tenant/V9__staff-hierarchy-link-to-users.sql @@ -0,0 +1,33 @@ +-- +-- Licensed to the Apache Software Foundation (ASF) under one +-- or more contributor license agreements. See the NOTICE file +-- distributed with this work for additional information +-- regarding copyright ownership. The ASF licenses this file +-- to you under the Apache License, Version 2.0 (the +-- "License"); you may not use this file except in compliance +-- with the License. You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, +-- software distributed under the License is distributed on an +-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +-- KIND, either express or implied. See the License for the +-- specific language governing permissions and limitations +-- under the License. +-- + +ALTER TABLE `m_appuser` +ADD COLUMN `staff_id` BIGINT(20) NULL DEFAULT NULL AFTER `office_id` ; + +ALTER TABLE m_appuser +ADD CONSTRAINT `fk_m_appuser_002` +FOREIGN KEY (`staff_id`) +REFERENCES m_staff (`id`) +ON DELETE NO ACTION +ON UPDATE NO ACTION +,ADD INDEX `fk_m_appuser_002x` (`staff_id` ASC); + +ALTER TABLE `m_staff` +ADD COLUMN `organisational_role_enum` SMALLINT NULL DEFAULT NULL AFTER `external_id`, +ADD COLUMN `organisational_role_parent_staff_id` BIGINT(20) NULL DEFAULT NULL AFTER `organisational_role_enum`; diff --git a/ph-ee-operations-app/src/test/java/org/apache/fineract/test/TestSomething.java b/ph-ee-operations-app/src/test/java/org/apache/fineract/test/TestSomething.java new file mode 100644 index 000000000..bcaccb606 --- /dev/null +++ b/ph-ee-operations-app/src/test/java/org/apache/fineract/test/TestSomething.java @@ -0,0 +1,29 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.test; + +import org.junit.Test; + +public class TestSomething { + + @Test + public void testIt() { + + } +} diff --git a/ph-ee-operations-app/src/test/resources/application.properties b/ph-ee-operations-app/src/test/resources/application.properties new file mode 100644 index 000000000..3172b44b2 --- /dev/null +++ b/ph-ee-operations-app/src/test/resources/application.properties @@ -0,0 +1 @@ +test=1 \ No newline at end of file diff --git a/ph-ee-vouchers/.circleci/config.yml b/ph-ee-vouchers/.circleci/config.yml new file mode 100644 index 000000000..4243304be --- /dev/null +++ b/ph-ee-vouchers/.circleci/config.yml @@ -0,0 +1,141 @@ +version: 2.1 +orbs: + slack: circleci/slack@4.12.5 + aws-ecr: circleci/aws-ecr@8.2.1 +executors: + docker-executor: + docker: + - image: circleci/openjdk:17-buster-node-browsers-legacy +jobs: + build: + docker: + - image: cimg/openjdk:17.0.0 + - image: docker:17.05.0-ce-git + working_directory: ~/repo + environment: + # Customize the JVM maximum heap limit + JVM_OPTS: -Xmx512m + TERM: dumb + steps: + - checkout + - setup_remote_docker +# - slack/notify: +# event: fail +# mentions: '@here' +# template: basic_fail_1 +# - slack/notify: +# event: pass +# template: basic_success_1 + - run: ./gradlew clean bootJar + - aws-ecr/build-and-push-image: + aws-access-key-id: AWS_ACCESS_KEY_ID + aws-secret-access-key: AWS_SECRET_ACCESS_KEY + extra-build-args: '--compress' + push-image: true + region: ap-south-1 + registry-id: AWS_REGISTRY_ID + repo: ph-ee-vouchers + repo-scan-on-push: true + role-arn: arn:aws:iam::419830066942:role/CustomAdmin + tag: latest + # - run: ./gradlew cucumberCli + # run tests! Slack Success/Fail Notification Step + #- run: ./gradlew test + + build_and_push_tag_image: + executor: docker-executor + environment: + JVM_OPTS: -Xmx512m + TERM: dumb + GITHUB_TOKEN: ${GITHUB_TOKEN} # Add the GitHub token as an environment variable + + steps: + - checkout + - setup_remote_docker: + version: 20.10.24 + - run: + name: Build and Push Docker tag Image + command: | + # Set environment variables + IMAGE_TAG=$CIRCLE_TAG + + # Check if the Docker image with the same tag already exists in Docker Hub + if curl -s -f -u "$DOCKERHUB_USERNAME":"$DOCKERHUB_PASSWORD" "https://hub.docker.com/v2/repositories/fynarfin/ph-ee-vouchers/tags/$IMAGE_TAG" > /dev/null; then + echo "Skipping the build and push as the tag $IMAGE_TAG already exists in Docker Hub." + exit 0 + fi + + # Build and tag the Docker image + ./gradlew bootJar + docker build -t "fynarfin/ph-ee-vouchers:$IMAGE_TAG" . + + # Push the Docker image to Docker Hub + docker login -u "$DOCKERHUB_USERNAME" -p "$DOCKERHUB_PASSWORD" + docker push "fynarfin/ph-ee-vouchers:$IMAGE_TAG" + + # when: always # The job will be executed even if there's no match for the tag filter + + build_and_push_latest_image: + executor: docker-executor + environment: + JVM_OPTS: -Xmx512m + TERM: dumb + + steps: + - checkout + # Install Docker to build and push the image + - setup_remote_docker: + version: 20.10.24 + + # Build the Docker image + - run: + name: Build Docker image + command: | + ./gradlew checkstyleMain + ./gradlew clean bootJar + docker build -t fynarfin/ph-ee-vouchers:latest . + if [ "$CIRCLE_BRANCH" != "develop" ]; then + PR_NUMBER=$(basename $CIRCLE_PULL_REQUEST) + PR_TITLE=$(curl -sSL "https://api.github.com/repos/fynarfin/$CIRCLE_PR_REPONAME/pulls/$PR_NUMBER" | jq -r '.title') + JIRA_STORY=$(echo $PR_TITLE | cut -d "[" -f2 | cut -d "]" -f1 | tr '[A-Z]' '[a-z]') + if [ -z "$JIRA_STORY" ]; then echo "Invalid PR title" && exit 1; else echo "Ticket NO: $JIRA_STORY"; fi + docker image tag fynarfin/$CIRCLE_PR_REPONAME:latest fynarfin/$CIRCLE_PR_REPONAME:$JIRA_STORY + fi + + # Log in to DockerHub using environment variables + - run: + name: Login to DockerHub + command: echo "${DOCKERHUB_PASSWORD}" | docker login -u "${DOCKERHUB_USERNAME}" --password-stdin + + # Push the Docker image to DockerHub + - run: + name: Push Docker image to DockerHub + command: | + if [ "$CIRCLE_BRANCH" = "develop" ]; then + docker push fynarfin/ph-ee-vouchers:latest + fi + if [ "$CIRCLE_BRANCH" != "develop" ]; then + PR_NUMBER=$(basename $CIRCLE_PULL_REQUEST) + PR_TITLE=$(curl -sSL "https://api.github.com/repos/fynarfin/$CIRCLE_PR_REPONAME/pulls/$PR_NUMBER" | jq -r '.title') + JIRA_STORY=$(echo $PR_TITLE | cut -d "[" -f2 | cut -d "]" -f1 | tr '[A-Z]' '[a-z]') + docker push fynarfin/$CIRCLE_PR_REPONAME:${JIRA_STORY} + fi + +workflows: + build_and_push_image: + jobs: + - build: + context: + - AWS + - slack + - build_and_push_tag_image: + filters: + tags: + only: /^v\d+\.\d+\.\d+$/ # Match tags in the format v1.2.3 + context: + - DOCKER + - build_and_push_latest_image: + requires: + - build + context: + - DOCKER diff --git a/ph-ee-vouchers/.github/pull_request_template.md b/ph-ee-vouchers/.github/pull_request_template.md new file mode 100644 index 000000000..bcf84d8d0 --- /dev/null +++ b/ph-ee-vouchers/.github/pull_request_template.md @@ -0,0 +1,22 @@ +## Description + +* PR title should have jira ticket enclosed in `[]`.
+Format: ``` [jira_ticket] description```
+ex: [phee-123] PR title. +* Add a link to the Jira ticket. +* Describe the changes made and why they were made. + +## Checklist + +Please make sure these boxes are checked before submitting your pull request - thanks! +- [ ] Followed the PR title naming convention mentioned above. + +- [ ] Design related bullet points or design document link related to this PR added in the description above. + +- [ ] Updated corresponding Postman Collection or Api documentation for the changes in this PR. + +- [ ] Created/updated unit or integration tests for verifying the changes made. + +- [ ] Added required Swagger annotation and update API documentation with details of any API changes if applicable + +- [ ] Followed the naming conventions as given in https://docs.google.com/document/d/1Q4vaMSzrTxxh9TS0RILuNkSkYCxotuYk1Xe0CMIkkCU/edit?usp=sharing diff --git a/ph-ee-vouchers/.gitignore b/ph-ee-vouchers/.gitignore new file mode 100644 index 000000000..c2065bc26 --- /dev/null +++ b/ph-ee-vouchers/.gitignore @@ -0,0 +1,37 @@ +HELP.md +.gradle +build/ +!gradle/wrapper/gradle-wrapper.jar +!**/src/main/**/build/ +!**/src/test/**/build/ + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache +bin/ +!**/src/main/**/bin/ +!**/src/test/**/bin/ + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr +out/ +!**/src/main/**/out/ +!**/src/test/**/out/ + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ + +### VS Code ### +.vscode/ diff --git a/ph-ee-vouchers/Dockerfile b/ph-ee-vouchers/Dockerfile new file mode 100644 index 000000000..4782d6bd1 --- /dev/null +++ b/ph-ee-vouchers/Dockerfile @@ -0,0 +1,5 @@ +FROM openjdk:17 +EXPOSE 8080 + +COPY build/libs/*.jar . +CMD java -jar *.jar diff --git a/ph-ee-vouchers/LICENSE b/ph-ee-vouchers/LICENSE new file mode 100644 index 000000000..a612ad981 --- /dev/null +++ b/ph-ee-vouchers/LICENSE @@ -0,0 +1,373 @@ +Mozilla Public License Version 2.0 +================================== + +1. Definitions +-------------- + +1.1. "Contributor" + means each individual or legal entity that creates, contributes to + the creation of, or owns Covered Software. + +1.2. "Contributor Version" + means the combination of the Contributions of others (if any) used + by a Contributor and that particular Contributor's Contribution. + +1.3. "Contribution" + means Covered Software of a particular Contributor. + +1.4. "Covered Software" + means Source Code Form to which the initial Contributor has attached + the notice in Exhibit A, the Executable Form of such Source Code + Form, and Modifications of such Source Code Form, in each case + including portions thereof. + +1.5. "Incompatible With Secondary Licenses" + means + + (a) that the initial Contributor has attached the notice described + in Exhibit B to the Covered Software; or + + (b) that the Covered Software was made available under the terms of + version 1.1 or earlier of the License, but not also under the + terms of a Secondary License. + +1.6. "Executable Form" + means any form of the work other than Source Code Form. + +1.7. "Larger Work" + means a work that combines Covered Software with other material, in + a separate file or files, that is not Covered Software. + +1.8. "License" + means this document. + +1.9. "Licensable" + means having the right to grant, to the maximum extent possible, + whether at the time of the initial grant or subsequently, any and + all of the rights conveyed by this License. + +1.10. "Modifications" + means any of the following: + + (a) any file in Source Code Form that results from an addition to, + deletion from, or modification of the contents of Covered + Software; or + + (b) any new file in Source Code Form that contains any Covered + Software. + +1.11. "Patent Claims" of a Contributor + means any patent claim(s), including without limitation, method, + process, and apparatus claims, in any patent Licensable by such + Contributor that would be infringed, but for the grant of the + License, by the making, using, selling, offering for sale, having + made, import, or transfer of either its Contributions or its + Contributor Version. + +1.12. "Secondary License" + means either the GNU General Public License, Version 2.0, the GNU + Lesser General Public License, Version 2.1, the GNU Affero General + Public License, Version 3.0, or any later versions of those + licenses. + +1.13. "Source Code Form" + means the form of the work preferred for making modifications. + +1.14. "You" (or "Your") + means an individual or a legal entity exercising rights under this + License. For legal entities, "You" includes any entity that + controls, is controlled by, or is under common control with You. For + purposes of this definition, "control" means (a) the power, direct + or indirect, to cause the direction or management of such entity, + whether by contract or otherwise, or (b) ownership of more than + fifty percent (50%) of the outstanding shares or beneficial + ownership of such entity. + +2. License Grants and Conditions +-------------------------------- + +2.1. Grants + +Each Contributor hereby grants You a world-wide, royalty-free, +non-exclusive license: + +(a) under intellectual property rights (other than patent or trademark) + Licensable by such Contributor to use, reproduce, make available, + modify, display, perform, distribute, and otherwise exploit its + Contributions, either on an unmodified basis, with Modifications, or + as part of a Larger Work; and + +(b) under Patent Claims of such Contributor to make, use, sell, offer + for sale, have made, import, and otherwise transfer either its + Contributions or its Contributor Version. + +2.2. Effective Date + +The licenses granted in Section 2.1 with respect to any Contribution +become effective for each Contribution on the date the Contributor first +distributes such Contribution. + +2.3. Limitations on Grant Scope + +The licenses granted in this Section 2 are the only rights granted under +this License. No additional rights or licenses will be implied from the +distribution or licensing of Covered Software under this License. +Notwithstanding Section 2.1(b) above, no patent license is granted by a +Contributor: + +(a) for any code that a Contributor has removed from Covered Software; + or + +(b) for infringements caused by: (i) Your and any other third party's + modifications of Covered Software, or (ii) the combination of its + Contributions with other software (except as part of its Contributor + Version); or + +(c) under Patent Claims infringed by Covered Software in the absence of + its Contributions. + +This License does not grant any rights in the trademarks, service marks, +or logos of any Contributor (except as may be necessary to comply with +the notice requirements in Section 3.4). + +2.4. Subsequent Licenses + +No Contributor makes additional grants as a result of Your choice to +distribute the Covered Software under a subsequent version of this +License (see Section 10.2) or under the terms of a Secondary License (if +permitted under the terms of Section 3.3). + +2.5. Representation + +Each Contributor represents that the Contributor believes its +Contributions are its original creation(s) or it has sufficient rights +to grant the rights to its Contributions conveyed by this License. + +2.6. Fair Use + +This License is not intended to limit any rights You have under +applicable copyright doctrines of fair use, fair dealing, or other +equivalents. + +2.7. Conditions + +Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted +in Section 2.1. + +3. Responsibilities +------------------- + +3.1. Distribution of Source Form + +All distribution of Covered Software in Source Code Form, including any +Modifications that You create or to which You contribute, must be under +the terms of this License. You must inform recipients that the Source +Code Form of the Covered Software is governed by the terms of this +License, and how they can obtain a copy of this License. You may not +attempt to alter or restrict the recipients' rights in the Source Code +Form. + +3.2. Distribution of Executable Form + +If You distribute Covered Software in Executable Form then: + +(a) such Covered Software must also be made available in Source Code + Form, as described in Section 3.1, and You must inform recipients of + the Executable Form how they can obtain a copy of such Source Code + Form by reasonable means in a timely manner, at a charge no more + than the cost of distribution to the recipient; and + +(b) You may distribute such Executable Form under the terms of this + License, or sublicense it under different terms, provided that the + license for the Executable Form does not attempt to limit or alter + the recipients' rights in the Source Code Form under this License. + +3.3. Distribution of a Larger Work + +You may create and distribute a Larger Work under terms of Your choice, +provided that You also comply with the requirements of this License for +the Covered Software. If the Larger Work is a combination of Covered +Software with a work governed by one or more Secondary Licenses, and the +Covered Software is not Incompatible With Secondary Licenses, this +License permits You to additionally distribute such Covered Software +under the terms of such Secondary License(s), so that the recipient of +the Larger Work may, at their option, further distribute the Covered +Software under the terms of either this License or such Secondary +License(s). + +3.4. Notices + +You may not remove or alter the substance of any license notices +(including copyright notices, patent notices, disclaimers of warranty, +or limitations of liability) contained within the Source Code Form of +the Covered Software, except that You may alter any license notices to +the extent required to remedy known factual inaccuracies. + +3.5. Application of Additional Terms + +You may choose to offer, and to charge a fee for, warranty, support, +indemnity or liability obligations to one or more recipients of Covered +Software. However, You may do so only on Your own behalf, and not on +behalf of any Contributor. You must make it absolutely clear that any +such warranty, support, indemnity, or liability obligation is offered by +You alone, and You hereby agree to indemnify every Contributor for any +liability incurred by such Contributor as a result of warranty, support, +indemnity or liability terms You offer. You may include additional +disclaimers of warranty and limitations of liability specific to any +jurisdiction. + +4. Inability to Comply Due to Statute or Regulation +--------------------------------------------------- + +If it is impossible for You to comply with any of the terms of this +License with respect to some or all of the Covered Software due to +statute, judicial order, or regulation then You must: (a) comply with +the terms of this License to the maximum extent possible; and (b) +describe the limitations and the code they affect. Such description must +be placed in a text file included with all distributions of the Covered +Software under this License. Except to the extent prohibited by statute +or regulation, such description must be sufficiently detailed for a +recipient of ordinary skill to be able to understand it. + +5. Termination +-------------- + +5.1. The rights granted under this License will terminate automatically +if You fail to comply with any of its terms. However, if You become +compliant, then the rights granted under this License from a particular +Contributor are reinstated (a) provisionally, unless and until such +Contributor explicitly and finally terminates Your grants, and (b) on an +ongoing basis, if such Contributor fails to notify You of the +non-compliance by some reasonable means prior to 60 days after You have +come back into compliance. Moreover, Your grants from a particular +Contributor are reinstated on an ongoing basis if such Contributor +notifies You of the non-compliance by some reasonable means, this is the +first time You have received notice of non-compliance with this License +from such Contributor, and You become compliant prior to 30 days after +Your receipt of the notice. + +5.2. If You initiate litigation against any entity by asserting a patent +infringement claim (excluding declaratory judgment actions, +counter-claims, and cross-claims) alleging that a Contributor Version +directly or indirectly infringes any patent, then the rights granted to +You by any and all Contributors for the Covered Software under Section +2.1 of this License shall terminate. + +5.3. In the event of termination under Sections 5.1 or 5.2 above, all +end user license agreements (excluding distributors and resellers) which +have been validly granted by You or Your distributors under this License +prior to termination shall survive termination. + +************************************************************************ +* * +* 6. Disclaimer of Warranty * +* ------------------------- * +* * +* Covered Software is provided under this License on an "as is" * +* basis, without warranty of any kind, either expressed, implied, or * +* statutory, including, without limitation, warranties that the * +* Covered Software is free of defects, merchantable, fit for a * +* particular purpose or non-infringing. The entire risk as to the * +* quality and performance of the Covered Software is with You. * +* Should any Covered Software prove defective in any respect, You * +* (not any Contributor) assume the cost of any necessary servicing, * +* repair, or correction. This disclaimer of warranty constitutes an * +* essential part of this License. No use of any Covered Software is * +* authorized under this License except under this disclaimer. * +* * +************************************************************************ + +************************************************************************ +* * +* 7. Limitation of Liability * +* -------------------------- * +* * +* Under no circumstances and under no legal theory, whether tort * +* (including negligence), contract, or otherwise, shall any * +* Contributor, or anyone who distributes Covered Software as * +* permitted above, be liable to You for any direct, indirect, * +* special, incidental, or consequential damages of any character * +* including, without limitation, damages for lost profits, loss of * +* goodwill, work stoppage, computer failure or malfunction, or any * +* and all other commercial damages or losses, even if such party * +* shall have been informed of the possibility of such damages. This * +* limitation of liability shall not apply to liability for death or * +* personal injury resulting from such party's negligence to the * +* extent applicable law prohibits such limitation. Some * +* jurisdictions do not allow the exclusion or limitation of * +* incidental or consequential damages, so this exclusion and * +* limitation may not apply to You. * +* * +************************************************************************ + +8. Litigation +------------- + +Any litigation relating to this License may be brought only in the +courts of a jurisdiction where the defendant maintains its principal +place of business and such litigation shall be governed by laws of that +jurisdiction, without reference to its conflict-of-law provisions. +Nothing in this Section shall prevent a party's ability to bring +cross-claims or counter-claims. + +9. Miscellaneous +---------------- + +This License represents the complete agreement concerning the subject +matter hereof. If any provision of this License is held to be +unenforceable, such provision shall be reformed only to the extent +necessary to make it enforceable. Any law or regulation which provides +that the language of a contract shall be construed against the drafter +shall not be used to construe this License against a Contributor. + +10. Versions of the License +--------------------------- + +10.1. New Versions + +Mozilla Foundation is the license steward. Except as provided in Section +10.3, no one other than the license steward has the right to modify or +publish new versions of this License. Each version will be given a +distinguishing version number. + +10.2. Effect of New Versions + +You may distribute the Covered Software under the terms of the version +of the License under which You originally received the Covered Software, +or under the terms of any subsequent version published by the license +steward. + +10.3. Modified Versions + +If you create software not governed by this License, and you want to +create a new license for such software, you may create and use a +modified version of this License if you rename the license and remove +any references to the name of the license steward (except to note that +such modified license differs from this License). + +10.4. Distributing Source Code Form that is Incompatible With Secondary +Licenses + +If You choose to distribute Source Code Form that is Incompatible With +Secondary Licenses under the terms of this version of the License, the +notice described in Exhibit B of this License must be attached. + +Exhibit A - Source Code Form License Notice +------------------------------------------- + + This Source Code Form is subject to the terms of the Mozilla Public + License, v. 2.0. If a copy of the MPL was not distributed with this + file, You can obtain one at http://mozilla.org/MPL/2.0/. + +If it is not possible or desirable to put the notice in a particular +file, then You may include the notice in a location (such as a LICENSE +file in a relevant directory) where a recipient would be likely to look +for such a notice. + +You may add additional accurate notices of copyright ownership. + +Exhibit B - "Incompatible With Secondary Licenses" Notice +--------------------------------------------------------- + + This Source Code Form is "Incompatible With Secondary Licenses", as + defined by the Mozilla Public License, v. 2.0. diff --git a/ph-ee-vouchers/README.md b/ph-ee-vouchers/README.md new file mode 100644 index 000000000..5d727051d --- /dev/null +++ b/ph-ee-vouchers/README.md @@ -0,0 +1,16 @@ +# payment-hub-ee +Payment Hub Enterprise Edition middleware for integration to real-time payment systems. + +For detailed documentation check the documentation: https://app.gitbook.com/@mifos/s/docs/payment-hub-ee/overview + +## Spotless +Use below command to execute the spotless apply. +```shell +./gradlew spotlessApply +``` + +## Checkstyle +Use below command to execute the checkstyle test. +```shell +./gradlew checkstyleMain +``` diff --git a/ph-ee-vouchers/build.gradle b/ph-ee-vouchers/build.gradle new file mode 100644 index 000000000..0e593893f --- /dev/null +++ b/ph-ee-vouchers/build.gradle @@ -0,0 +1,284 @@ +plugins { + id 'java' + id 'org.springframework.boot' version '2.7.12' + id 'io.spring.dependency-management' version '1.0.15.RELEASE' + id 'eclipse' + id 'checkstyle' + id 'com.diffplug.spotless' version '6.19.0' + id 'net.ltgt.errorprone' version '3.1.0' +} + +group = 'org.mifos' +version = '0.0.1-SNAPSHOT' +sourceCompatibility = '17' + +configurations { + compileOnly { + extendsFrom annotationProcessor + } +} +ext { + camelVersion = '3.18.1' + zeebClientVersion = '8.1.23' + springBootVersion = '2.7.12' +} + +repositories { + mavenCentral() + maven { + url = uri('https://jfrog.sandbox.fynarfin.io/artifactory/fyn-libs-snapshot') + } +} + +dependencies { + implementation 'org.springframework.boot:spring-boot-starter-data-jpa' + implementation 'org.liquibase:liquibase-core' + compileOnly 'org.projectlombok:lombok' + runtimeOnly 'com.h2database:h2' + annotationProcessor 'org.projectlombok:lombok' + testImplementation 'org.springframework.boot:spring-boot-starter-test' + implementation 'mysql:mysql-connector-java:8.0.26' + implementation 'org.springframework.boot:spring-boot-starter-web' + implementation "org.springdoc:springdoc-openapi-ui:1.6.11" + implementation('io.rest-assured:rest-assured:4.4.0') + implementation "org.springdoc:springdoc-openapi-ui:1.6.11" + implementation("io.camunda:zeebe-client-java:$zeebClientVersion") + implementation "org.apache.camel.springboot:camel-spring-boot-starter:$camelVersion" + implementation "org.apache.camel:camel-undertow:$camelVersion" + implementation 'org.apache.camel.springboot:camel-jackson-starter:3.16.0' + implementation 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.7.9' + implementation "org.apache.camel:camel-http:$camelVersion" + implementation "org.apache.camel:camel-endpointdsl:$camelVersion" + implementation "org.apache.camel:camel-jetty:$camelVersion" + implementation("io.camunda:zeebe-client-java:$zeebClientVersion") + implementation 'org.mifos:ph-ee-connector-common:1.9.1-SNAPSHOT' + implementation 'org.json:json:20210307' + checkstyle 'com.puppycrawl.tools:checkstyle:10.9.3' + checkstyle 'com.github.sevntu-checkstyle:sevntu-checks:1.44.1' + implementation "org.springframework.boot:spring-boot-starter:$springBootVersion" + implementation "org.springframework.boot:spring-boot-starter-web:$springBootVersion" + implementation "org.springframework.boot:spring-boot-starter-actuator:$springBootVersion" +} + +tasks.named('test') { + useJUnitPlatform() +} + +apply plugin:'com.diffplug.spotless' +spotless { + format 'misc', { + target '**/*.md', '**/*.properties', '**/.gitignore', '**/.openapi-generator-ignore', '**/*.yml', '**/*.xml', '**/**.json', '**/*.sql' + targetExclude '**/build/**', '**/bin/**', '**/.settings/**', '**/.idea/**', '**/.gradle/**', '**/gradlew.bat', '**/licenses/**', '**/banner.txt', '.vscode/**' + indentWithSpaces(4) + endWithNewline() + trimTrailingWhitespace() + } + + groovyGradle { + target '*.gradle', '**/*.gradle' + targetExclude '**/build/**' + greclipse() + indentWithSpaces(4) + endWithNewline() + trimTrailingWhitespace() + } + + lineEndings 'UNIX' +} + +configure(this) { + // NOTE: order matters! + apply plugin: 'java' + apply plugin: 'idea' + apply plugin: 'eclipse' + apply plugin: 'checkstyle' + apply plugin: 'net.ltgt.errorprone' + configurations { + implementation.setCanBeResolved(true) + api.setCanBeResolved(true) + } + tasks.withType(JavaCompile) { + options.compilerArgs += [ + "-Xlint:unchecked", + "-Xlint:cast", + "-Xlint:auxiliaryclass", + "-Xlint:deprecation", + "-Xlint:dep-ann", + "-Xlint:divzero", + "-Xlint:empty", + "-Xlint:exports", + "-Xlint:fallthrough", + "-Xlint:finally", + "-Xlint:module", + "-Xlint:opens", + "-Xlint:options", + "-Xlint:overloads", + "-Xlint:overrides", + "-Xlint:path", + "-Xlint:processing", + "-Xlint:removal", + "-Xlint:requires-automatic", + "-Xlint:requires-transitive-automatic", + "-Xlint:try", + "-Xlint:varargs", + "-Xlint:preview", + "-Xlint:static", + // -Werror needs to be disabled because EclipseLink's static weaving doesn't generate warning-free code + // and during an IntelliJ recompilation, it fails + //"-Werror", + "-Xmaxwarns", + 1500, + "-Xmaxerrs", + 1500 + ] + options.deprecation = true + } + // Configuration for the spotless plugin + // https://github.com/diffplug/spotless/tree/main/plugin-gradle + spotless { + java { + targetExclude '**/build/**', '**/bin/**', '**/out/**' + importOrder() //sort imports alphabetically + removeUnusedImports() + eclipse().configFile "$rootDir/ph-ee-vouchers/config/voucher-formatter.xml" + endWithNewline() + trimTrailingWhitespace() + // Enforce style modifier order + custom 'Modifier ordering', { + def modifierRanking = [ + public : 1, + protected : 2, + private : 3, + abstract : 4, + default : 5, + static : 6, + final : 7, + transient : 8, + volatile : 9, + synchronized: 10, + native : 11, + strictfp : 12] + // Find any instance of multiple modifiers. Lead with a non-word character to avoid + // accidental matching against for instance, "an alternative default value" + it.replaceAll(/\W(?:public |protected |private |abstract |default |static |final |transient |volatile |synchronized |native |strictfp ){2,}/, { + // Do not replace the leading non-word character. Identify the modifiers + it.replaceAll(/(?:public |protected |private |abstract |default |static |final |transient |volatile |synchronized |native |strictfp ){2,}/, { + // Sort the modifiers according to the ranking above + it.split().sort({ modifierRanking[it] }).join(' ') + ' ' + } + ) + } + ) + } + } + lineEndings 'UNIX' + } + // If we are running Gradle within Eclipse to enhance classes, + // set the classes directory to point to Eclipse's default build directory + if (project.hasProperty('env') && project.getProperty('env') == 'eclipse') { + sourceSets.main.java.outputDir = file("$projectDir/bin/main") + } + // Configuration for the Checkstyle plugin + // https://docs.gradle.org/current/userguide/checkstyle_plugin.html + dependencies { + checkstyle 'com.puppycrawl.tools:checkstyle:10.3.1' + checkstyle 'com.github.sevntu-checkstyle:sevntu-checks:1.42.0' + } + // Configuration for the errorprone plugin + // https://github.com/tbroyer/gradle-errorprone-plugin + dependencies { + errorprone "com.google.errorprone:error_prone_core:2.20.0" + } + + tasks.withType(JavaCompile) { + options.errorprone { + enabled = project.gradle.startParameter.taskNames.contains('build') || project.gradle.startParameter.taskNames.contains('check') + disableWarningsInGeneratedCode = true + excludedPaths = ".*/build/.*" + disable( + // TODO Remove disabled checks from this list, by fixing remaining usages + "UnusedVariable", + "TypeParameterUnusedInFormals", + "EmptyBlockTag", + "MissingSummary", + "InvalidParam", + "ReturnFromVoid", + "AlmostJavadoc", + "InvalidBlockTag", + "JavaUtilDate", // TODO FINERACT-1298 + "ReturnValueIgnored", + "DirectInvocationOnMock", + "CanIgnoreReturnValueSuggester", + "SameNameButDifferent", // Until errorprone recognizes Lombok + "MultiVariableDeclaration", // Until errorprone recognizes Lombok + "UnnecessaryDefaultInEnumSwitch" // FINERACT-1911 + ) + error( + "DefaultCharset", + "RemoveUnusedImports", + "WaitNotInLoop", + "ThreeLetterTimeZoneID", + "VariableNameSameAsType", + "UnnecessaryParentheses", + "MultipleTopLevelClasses", + "MixedMutabilityReturnType", + "AssertEqualsArgumentOrderChecker", + "EmptySetMultibindingContributions", + "BigDecimalEquals", + "MixedArrayDimensions", + "PackageLocation", + "UseBinds", + "BadImport", + "IntLongMath", + "FloatCast", + "ReachabilityFenceUsage", + "StreamResourceLeak", + "TruthIncompatibleType", + "ByteBufferBackingArray", + "OrphanedFormatString", + "CatchAndPrintStackTrace", + "ObjectToString", + "StringSplitter", + "AssertThrowsMultipleStatements", + "BoxedPrimitiveConstructor", + "EmptyCatch", + "BoxedPrimitiveEquality", + "SynchronizeOnNonFinalField", + "WildcardImport", + "PrivateConstructorForNoninstantiableModule", + "ClassCanBeStatic", + "ClassNewInstance", + "UnnecessaryStaticImport", + "UnsafeFinalization", + "JavaTimeDefaultTimeZone", + "JodaPlusMinusLong", + "SwitchDefault", + "VarTypeName", + "ArgumentSelectionDefectChecker", + "CompareToZero", + "InjectOnConstructorOfAbstractClass", + "ImmutableEnumChecker", + "NarrowingCompoundAssignment", + "MissingCasesInEnumSwitch", + "ReferenceEquality", + "UndefinedEquals", + "UnescapedEntity", + "ModifyCollectionInEnhancedForLoop", + "NonCanonicalType", + "InvalidInlineTag", + "MutablePublicArray", + "StaticAssignmentInConstructor", + "ProtectedMembersInFinalClass", + "OperatorPrecedence", + "EqualsGetClass", + "EqualsUnsafeCast", + "DoubleBraceInitialization", + "UnusedNestedClass", + "UnusedMethod", + "ModifiedButNotUsed", + "InconsistentCapitalization", + "MissingOverride", + ) + } + } +} diff --git a/ph-ee-vouchers/config/checkstyle/checkstyle.xml b/ph-ee-vouchers/config/checkstyle/checkstyle.xml new file mode 100644 index 000000000..20ea24e55 --- /dev/null +++ b/ph-ee-vouchers/config/checkstyle/checkstyle.xml @@ -0,0 +1,196 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ph-ee-vouchers/config/checkstyle/suppressions.xml b/ph-ee-vouchers/config/checkstyle/suppressions.xml new file mode 100644 index 000000000..f4e5b54c3 --- /dev/null +++ b/ph-ee-vouchers/config/checkstyle/suppressions.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + diff --git a/ph-ee-vouchers/config/voucher-cleanup.xml b/ph-ee-vouchers/config/voucher-cleanup.xml new file mode 100644 index 000000000..9a115794f --- /dev/null +++ b/ph-ee-vouchers/config/voucher-cleanup.xml @@ -0,0 +1,71 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ph-ee-vouchers/config/voucher-formatter.xml b/ph-ee-vouchers/config/voucher-formatter.xml new file mode 100644 index 000000000..b25f847ef --- /dev/null +++ b/ph-ee-vouchers/config/voucher-formatter.xml @@ -0,0 +1,366 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ph-ee-vouchers/gradle/wrapper/gradle-wrapper.jar b/ph-ee-vouchers/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 000000000..249e5832f Binary files /dev/null and b/ph-ee-vouchers/gradle/wrapper/gradle-wrapper.jar differ diff --git a/ph-ee-vouchers/gradle/wrapper/gradle-wrapper.properties b/ph-ee-vouchers/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 000000000..774fae876 --- /dev/null +++ b/ph-ee-vouchers/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.1-bin.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/ph-ee-vouchers/gradlew b/ph-ee-vouchers/gradlew new file mode 100755 index 000000000..a69d9cb6c --- /dev/null +++ b/ph-ee-vouchers/gradlew @@ -0,0 +1,240 @@ +#!/bin/sh + +# +# Copyright © 2015-2021 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit + +APP_NAME="Gradle" +APP_BASE_NAME=${0##*/} + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/ph-ee-vouchers/gradlew.bat b/ph-ee-vouchers/gradlew.bat new file mode 100644 index 000000000..53a6b238d --- /dev/null +++ b/ph-ee-vouchers/gradlew.bat @@ -0,0 +1,91 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 0 goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/ph-ee-vouchers/settings.gradle b/ph-ee-vouchers/settings.gradle new file mode 100644 index 000000000..e73031fb6 --- /dev/null +++ b/ph-ee-vouchers/settings.gradle @@ -0,0 +1 @@ +rootProject.name = 'ph-ee-vouchers' diff --git a/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/PhEeVoucherManagementSystemApplication.java b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/PhEeVoucherManagementSystemApplication.java new file mode 100644 index 000000000..e4af6be23 --- /dev/null +++ b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/PhEeVoucherManagementSystemApplication.java @@ -0,0 +1,16 @@ +package org.mifos.pheevouchermanagementsystem; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cache.annotation.EnableCaching; + +@EnableCaching +@SpringBootApplication +@SuppressWarnings({ "HideUtilityClassConstructor" }) +public class PhEeVoucherManagementSystemApplication { + + public static void main(String[] args) { + SpringApplication.run(PhEeVoucherManagementSystemApplication.class, args); + } + +} diff --git a/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/api/definition/BatchAuthorizationCallbackApi.java b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/api/definition/BatchAuthorizationCallbackApi.java new file mode 100644 index 000000000..05e011145 --- /dev/null +++ b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/api/definition/BatchAuthorizationCallbackApi.java @@ -0,0 +1,14 @@ +package org.mifos.pheevouchermanagementsystem.api.definition; + +import com.fasterxml.jackson.core.JsonProcessingException; +import java.util.concurrent.ExecutionException; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; + +public interface BatchAuthorizationCallbackApi { + + @PostMapping("/authorization/callbacks") + ResponseEntity accountLookupCallback(@RequestBody String requestBody) + throws ExecutionException, InterruptedException, JsonProcessingException; +} diff --git a/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/api/definition/CancelAndRedeemVoucherApi.java b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/api/definition/CancelAndRedeemVoucherApi.java new file mode 100644 index 000000000..1e6c40109 --- /dev/null +++ b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/api/definition/CancelAndRedeemVoucherApi.java @@ -0,0 +1,21 @@ +package org.mifos.pheevouchermanagementsystem.api.definition; + +import com.fasterxml.jackson.core.JsonProcessingException; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestHeader; +import org.springframework.web.bind.annotation.RequestParam; + +@Tag(name = "GOV") +public interface CancelAndRedeemVoucherApi { + + @Operation(summary = "Cancel or Redeem Voucher API") + @PostMapping("/vouchers") + ResponseEntity cancelOrRedeemVoucher(@RequestHeader(value = "X-CallbackURL") String callbackURL, + @RequestHeader(value = "X-Registering-Institution-ID") String registeringInstitutionId, + @RequestHeader(value = "X-Program-ID", required = false) String programId, @RequestBody Object requestBody, + @RequestParam(value = "command") String command) throws JsonProcessingException; +} diff --git a/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/api/definition/CreateVoucherApi.java b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/api/definition/CreateVoucherApi.java new file mode 100644 index 000000000..1c91b0fa6 --- /dev/null +++ b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/api/definition/CreateVoucherApi.java @@ -0,0 +1,22 @@ +package org.mifos.pheevouchermanagementsystem.api.definition; + +import com.fasterxml.jackson.core.JsonProcessingException; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import java.util.concurrent.ExecutionException; +import org.mifos.pheevouchermanagementsystem.data.RequestDTO; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestHeader; + +@Tag(name = "GOV") +public interface CreateVoucherApi { + + @Operation(summary = "Create Vouchers API") + @PostMapping(value = "/vouchers", params = "!command") + ResponseEntity createVouchers(@RequestHeader(value = "X-CallbackURL") String callbackURL, + @RequestHeader(value = "X-Program-ID", required = false) String programId, + @RequestHeader(value = "X-Registering-Institution-ID") String registeringInstitutionId, @RequestBody RequestDTO requestBody) + throws ExecutionException, InterruptedException, JsonProcessingException; +} diff --git a/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/api/definition/FetchVoucherApi.java b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/api/definition/FetchVoucherApi.java new file mode 100644 index 000000000..0ad5d01b3 --- /dev/null +++ b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/api/definition/FetchVoucherApi.java @@ -0,0 +1,25 @@ +package org.mifos.pheevouchermanagementsystem.api.definition; + +import java.util.concurrent.ExecutionException; +import org.mifos.pheevouchermanagementsystem.data.FetchVoucherResponseDTO; +import org.springframework.data.domain.Page; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestHeader; +import org.springframework.web.bind.annotation.RequestParam; + +public interface FetchVoucherApi { + + @GetMapping("/vouchers/{serialNumber}") + ResponseEntity fetchVoucher(@PathVariable String serialNumber, + @RequestHeader(value = "X-Registering-Institution-ID") String registeringInstitutionId) + throws ExecutionException, InterruptedException; + + @GetMapping("/vouchers") + ResponseEntity> fetchAllVouchers( + @RequestHeader(value = "X-Registering-Institution-ID") String registeringInstitutionId, + @RequestParam(value = "page", required = false, defaultValue = "0") Integer page, + @RequestParam(value = "size", required = false, defaultValue = "20") Integer size) + throws ExecutionException, InterruptedException; +} diff --git a/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/api/definition/VoucherLifecycleManagementApi.java b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/api/definition/VoucherLifecycleManagementApi.java new file mode 100644 index 000000000..8f7bc9a4c --- /dev/null +++ b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/api/definition/VoucherLifecycleManagementApi.java @@ -0,0 +1,24 @@ +package org.mifos.pheevouchermanagementsystem.api.definition; + + +import com.fasterxml.jackson.core.JsonProcessingException; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import java.util.concurrent.ExecutionException; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestHeader; +import org.springframework.web.bind.annotation.RequestParam; + +@Tag(name = "GOV") +public interface VoucherLifecycleManagementApi { + + @Operation(summary = "Create Vouchers API") + @PutMapping("/vouchers") + ResponseEntity voucherStatusChange(@RequestHeader(value = "X-CallbackURL") String callbackURL, + @RequestHeader(value = "X-Registering-Institution-ID") String registeringInstitutionId, + @RequestHeader(value = "X-Program-ID", required = false) String programId, @RequestBody Object requestBody, + @RequestParam(value = "command") String command) + throws ExecutionException, InterruptedException, JsonProcessingException, JsonProcessingException; +} diff --git a/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/api/definition/VoucherStatusApi.java b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/api/definition/VoucherStatusApi.java new file mode 100644 index 000000000..0b0a5b37f --- /dev/null +++ b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/api/definition/VoucherStatusApi.java @@ -0,0 +1,21 @@ +package org.mifos.pheevouchermanagementsystem.api.definition; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import java.util.concurrent.ExecutionException; +import org.mifos.pheevouchermanagementsystem.data.VoucherStatusResponseDTO; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestHeader; +import org.springframework.web.bind.annotation.RequestParam; + +@Tag(name = "GOV") +public interface VoucherStatusApi { + + @Operation(summary = "Voucher Status API ") + @GetMapping("/voucher/{serialnumber}") + ResponseEntity voucherStatus(@PathVariable(value = "serialnumber") String serialNumber, + @RequestHeader(value = "X-Registering-Institution-ID") String registeringInstitutionId, + @RequestParam(value = "fields", defaultValue = "status") String status) throws ExecutionException, InterruptedException; +} diff --git a/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/api/definition/VoucherValidityApi.java b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/api/definition/VoucherValidityApi.java new file mode 100644 index 000000000..c9013427e --- /dev/null +++ b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/api/definition/VoucherValidityApi.java @@ -0,0 +1,19 @@ +package org.mifos.pheevouchermanagementsystem.api.definition; + +import java.util.concurrent.ExecutionException; +import org.mifos.pheevouchermanagementsystem.data.ResponseDTO; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestHeader; +import org.springframework.web.bind.annotation.RequestParam; + +public interface VoucherValidityApi { + + @GetMapping("/voucher/validity") + ResponseEntity voucherValidity(@RequestHeader(value = "X-CallbackURL") String callbackURL, + @RequestHeader(value = "X-Registering-Institution-ID") String registeringInstitutionId, + @RequestParam(value = "serialNumber", required = false) String serialNumber, + @RequestParam(value = "voucherNumber", required = false) String voucherNumber, + @RequestParam(value = "groupCode", required = false) String groupCode, @RequestParam(value = "isValid") Boolean isValid) + throws ExecutionException, InterruptedException; +} diff --git a/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/api/implementation/BatchAuthorizationCallbackApiController.java b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/api/implementation/BatchAuthorizationCallbackApiController.java new file mode 100644 index 000000000..f2e3f4bc0 --- /dev/null +++ b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/api/implementation/BatchAuthorizationCallbackApiController.java @@ -0,0 +1,53 @@ +package org.mifos.pheevouchermanagementsystem.api.implementation; + +import static org.mifos.pheevouchermanagementsystem.zeebe.ZeebeMessages.BATCH_AUTHORIZATION; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import io.camunda.zeebe.client.ZeebeClient; +import java.io.IOException; +import java.time.Duration; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.ExecutionException; +import org.mifos.pheevouchermanagementsystem.api.definition.BatchAuthorizationCallbackApi; +import org.mifos.pheevouchermanagementsystem.data.AuthorizationResponse; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.RestController; + +@RestController +public class BatchAuthorizationCallbackApiController implements BatchAuthorizationCallbackApi { + + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Autowired(required = false) + private ZeebeClient zeebeClient; + @Autowired + private ObjectMapper objectMapper; + + @Override + public ResponseEntity accountLookupCallback(String response) + throws ExecutionException, InterruptedException, JsonProcessingException { + Map variables = new HashMap<>(); + AuthorizationResponse authorizationResponse = new AuthorizationResponse(); + String transactionId = null; + try { + authorizationResponse = objectMapper.readValue(response, AuthorizationResponse.class); + transactionId = authorizationResponse.getClientCorrelationId(); + variables.put("status", authorizationResponse.getStatus()); + + } catch (IOException e) { + logger.error(e.getMessage()); + } + if (zeebeClient != null) { + + zeebeClient.newPublishMessageCommand().messageName(BATCH_AUTHORIZATION).correlationKey(transactionId) + .timeToLive(Duration.ofMillis(50000)).variables(variables).send(); + } + return ResponseEntity.status(HttpStatus.OK).body("Accepted"); + } +} diff --git a/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/api/implementation/CancelAndRedeemVoucherApiController.java b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/api/implementation/CancelAndRedeemVoucherApiController.java new file mode 100644 index 000000000..525e2ae96 --- /dev/null +++ b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/api/implementation/CancelAndRedeemVoucherApiController.java @@ -0,0 +1,86 @@ +package org.mifos.pheevouchermanagementsystem.api.implementation; + +import static org.mifos.pheevouchermanagementsystem.util.VoucherManagementEnum.FAILED_RESPONSE; +import static org.mifos.pheevouchermanagementsystem.util.VoucherManagementEnum.SUCCESS_RESPONSE; + +import com.fasterxml.jackson.databind.ObjectMapper; +import java.util.HashMap; +import java.util.Map; +import lombok.extern.slf4j.Slf4j; +import org.mifos.connector.common.channel.dto.PhErrorDTO; +import org.mifos.pheevouchermanagementsystem.api.definition.CancelAndRedeemVoucherApi; +import org.mifos.pheevouchermanagementsystem.data.RedeemVoucherRequestDTO; +import org.mifos.pheevouchermanagementsystem.data.RequestDTO; +import org.mifos.pheevouchermanagementsystem.data.ResponseDTO; +import org.mifos.pheevouchermanagementsystem.data.VoucherValidator; +import org.mifos.pheevouchermanagementsystem.service.ActivateVoucherService; +import org.mifos.pheevouchermanagementsystem.service.RedeemVoucherService; +import org.mifos.pheevouchermanagementsystem.service.ValidateHeaders; +import org.mifos.pheevouchermanagementsystem.service.VoucherLifecycleService; +import org.mifos.pheevouchermanagementsystem.util.HeaderConstants; +import org.mifos.pheevouchermanagementsystem.validator.HeaderValidator; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@Slf4j +public class CancelAndRedeemVoucherApiController implements CancelAndRedeemVoucherApi { + + @Autowired + ActivateVoucherService activateVoucherService; + @Autowired + RedeemVoucherService redeemVoucherService; + @Autowired + ObjectMapper objectMapper; + @Autowired + VoucherLifecycleService voucherLifecycleService; + + @Autowired + VoucherValidator voucherValidator; + + @Override + @ValidateHeaders(requiredHeaders = { HeaderConstants.X_PROGRAM_ID, HeaderConstants.X_REGISTERING_INSTITUTION_ID, + HeaderConstants.X_CALLBACKURL }, validatorClass = HeaderValidator.class, validationFunction = "validateCancelOrRedeemVoucher") + public ResponseEntity cancelOrRedeemVoucher(String callbackURL, String registeringInstitutionId, String programId, + Object requestBody, String command) { + RequestDTO requestDTO = null; + RedeemVoucherRequestDTO redeemVoucherRequestDTO = null; + try { + if (command.equals("redeem")) { + redeemVoucherRequestDTO = objectMapper.convertValue(requestBody, RedeemVoucherRequestDTO.class); + PhErrorDTO phErrorDTO = voucherValidator.validateRedeemVoucher(redeemVoucherRequestDTO); + if (phErrorDTO != null) { + return ResponseEntity.status(HttpStatus.BAD_REQUEST).body((T) phErrorDTO); + } + return ResponseEntity.status(HttpStatus.OK) + .body((T) redeemVoucherService.redeemVoucher(redeemVoucherRequestDTO, registeringInstitutionId)); + } else if (command.equals("cancel")) { + requestDTO = objectMapper.convertValue(requestBody, RequestDTO.class); + PhErrorDTO phErrorDTO = voucherValidator.validateVoucherLifecycle(requestDTO); + if (phErrorDTO != null) { + return ResponseEntity.status(HttpStatus.BAD_REQUEST).body((T) phErrorDTO); + } + voucherLifecycleService.cancelVoucher(requestDTO, callbackURL, registeringInstitutionId); + } + } catch (NullPointerException e) { + Map responseBody = new HashMap<>(); + log.error("An error occurred : {}", e.getMessage()); + responseBody.put("failureReason", "An error occurred, contact the system admin !!"); + return (ResponseEntity) ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(responseBody); + } catch (Exception e) { + ResponseDTO responseDTO = new ResponseDTO(FAILED_RESPONSE.getValue(), FAILED_RESPONSE.getMessage(), requestDTO.getRequestID()); + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body((T) responseDTO); + } + + String requestId; + if (requestDTO == null) { + requestId = redeemVoucherRequestDTO.getRequestId(); + } else { + requestId = requestDTO.getRequestID(); + } + ResponseDTO responseDTO = new ResponseDTO(SUCCESS_RESPONSE.getValue(), SUCCESS_RESPONSE.getMessage(), requestId); + return ResponseEntity.status(HttpStatus.ACCEPTED).body((T) responseDTO); + } +} diff --git a/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/api/implementation/CreateVoucherApiController.java b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/api/implementation/CreateVoucherApiController.java new file mode 100644 index 000000000..f24c6455c --- /dev/null +++ b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/api/implementation/CreateVoucherApiController.java @@ -0,0 +1,50 @@ +package org.mifos.pheevouchermanagementsystem.api.implementation; + +import static org.mifos.pheevouchermanagementsystem.util.VoucherManagementEnum.FAILED_RESPONSE; +import static org.mifos.pheevouchermanagementsystem.util.VoucherManagementEnum.SUCCESS_RESPONSE; + +import com.fasterxml.jackson.core.JsonProcessingException; +import java.util.concurrent.ExecutionException; +import lombok.extern.slf4j.Slf4j; +import org.mifos.connector.common.channel.dto.PhErrorDTO; +import org.mifos.pheevouchermanagementsystem.api.definition.CreateVoucherApi; +import org.mifos.pheevouchermanagementsystem.data.RequestDTO; +import org.mifos.pheevouchermanagementsystem.data.ResponseDTO; +import org.mifos.pheevouchermanagementsystem.exception.ConflictingDataException; +import org.mifos.pheevouchermanagementsystem.exception.InstructionIdException; +import org.mifos.pheevouchermanagementsystem.service.CreateVoucherService; +import org.mifos.pheevouchermanagementsystem.service.ValidateHeaders; +import org.mifos.pheevouchermanagementsystem.util.HeaderConstants; +import org.mifos.pheevouchermanagementsystem.validator.HeaderValidator; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@Slf4j +public class CreateVoucherApiController implements CreateVoucherApi { + + @Autowired + CreateVoucherService createVoucherService; + + @Override + @ValidateHeaders(requiredHeaders = { HeaderConstants.X_PROGRAM_ID, HeaderConstants.X_REGISTERING_INSTITUTION_ID, + HeaderConstants.X_CALLBACKURL }, validatorClass = HeaderValidator.class, validationFunction = "validateCreateVoucher") + public ResponseEntity createVouchers(String callbackURL, String programId, String registeringInstitutionId, + RequestDTO requestBody) throws ExecutionException, InterruptedException, JsonProcessingException { + try { + PhErrorDTO phErrorDTO = createVoucherService.validateAndCreateVoucher(requestBody, callbackURL, registeringInstitutionId); + if (phErrorDTO != null) { + return ResponseEntity.status(HttpStatus.BAD_REQUEST).body((T) phErrorDTO); + } + } catch (InstructionIdException | ConflictingDataException | NullPointerException e) { + throw e; + } catch (Exception e) { + ResponseDTO responseDTO = new ResponseDTO(FAILED_RESPONSE.getValue(), e.getMessage(), requestBody.getRequestID()); + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body((T) responseDTO); + } + ResponseDTO responseDTO = new ResponseDTO(SUCCESS_RESPONSE.getValue(), SUCCESS_RESPONSE.getMessage(), requestBody.getRequestID()); + return ResponseEntity.status(HttpStatus.ACCEPTED).body((T) responseDTO); + } +} diff --git a/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/api/implementation/FetchVoucherApiController.java b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/api/implementation/FetchVoucherApiController.java new file mode 100644 index 000000000..d97e15914 --- /dev/null +++ b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/api/implementation/FetchVoucherApiController.java @@ -0,0 +1,52 @@ +package org.mifos.pheevouchermanagementsystem.api.implementation; + +import java.util.concurrent.ExecutionException; +import org.mifos.pheevouchermanagementsystem.api.definition.FetchVoucherApi; +import org.mifos.pheevouchermanagementsystem.data.FetchVoucherResponseDTO; +import org.mifos.pheevouchermanagementsystem.repository.VoucherRepository; +import org.mifos.pheevouchermanagementsystem.service.FetchVoucherService; +import org.mifos.pheevouchermanagementsystem.service.ValidateHeaders; +import org.mifos.pheevouchermanagementsystem.util.HeaderConstants; +import org.mifos.pheevouchermanagementsystem.validator.HeaderValidator; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Page; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.RestController; + +@RestController +public class FetchVoucherApiController implements FetchVoucherApi { + + @Autowired + private FetchVoucherService fetchVoucherService; + @Autowired + private final VoucherRepository voucherRepository; + + public FetchVoucherApiController(VoucherRepository voucherRepository) { + this.voucherRepository = voucherRepository; + } + + @Override + @ValidateHeaders(requiredHeaders = { + HeaderConstants.X_REGISTERING_INSTITUTION_ID }, validatorClass = HeaderValidator.class, validationFunction = "validateForRegisteringInstitutionID") + public ResponseEntity fetchVoucher(String serialNumber, String registeringInstitutionId) + throws ExecutionException, InterruptedException { + if (registeringInstitutionId == null || registeringInstitutionId.isEmpty() || !voucherRepository.existsBySerialNo(serialNumber)) { + return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(null); + } + FetchVoucherResponseDTO fetchVoucherResponseDTO = fetchVoucherService.fetchVoucher(serialNumber, registeringInstitutionId); + return ResponseEntity.status(HttpStatus.OK).body(fetchVoucherResponseDTO); + } + + @Override + @ValidateHeaders(requiredHeaders = { + HeaderConstants.X_REGISTERING_INSTITUTION_ID }, validatorClass = HeaderValidator.class, validationFunction = "validateForRegisteringInstitutionID") + public ResponseEntity> fetchAllVouchers(String registeringInstitutionId, Integer page, Integer size) + throws ExecutionException, InterruptedException { + if (registeringInstitutionId == null || registeringInstitutionId.isEmpty()) { + return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(null); + } + Page fetchVoucherResponseDTOS = fetchVoucherService.fetchAllVouchers(registeringInstitutionId, page, size); + return ResponseEntity.status(HttpStatus.OK).body(fetchVoucherResponseDTOS); + } +} diff --git a/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/api/implementation/VoucherLifecycleManagementApiController.java b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/api/implementation/VoucherLifecycleManagementApiController.java new file mode 100644 index 000000000..cff6b46ba --- /dev/null +++ b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/api/implementation/VoucherLifecycleManagementApiController.java @@ -0,0 +1,100 @@ +package org.mifos.pheevouchermanagementsystem.api.implementation; + +import static org.mifos.pheevouchermanagementsystem.util.VoucherManagementEnum.FAILED_RESPONSE; +import static org.mifos.pheevouchermanagementsystem.util.VoucherManagementEnum.SUCCESS_RESPONSE; + +import com.fasterxml.jackson.databind.ObjectMapper; +import java.util.HashMap; +import java.util.Map; +import lombok.extern.slf4j.Slf4j; +import org.mifos.connector.common.channel.dto.PhErrorDTO; +import org.mifos.pheevouchermanagementsystem.api.definition.VoucherLifecycleManagementApi; +import org.mifos.pheevouchermanagementsystem.data.RedeemVoucherRequestDTO; +import org.mifos.pheevouchermanagementsystem.data.RequestDTO; +import org.mifos.pheevouchermanagementsystem.data.ResponseDTO; +import org.mifos.pheevouchermanagementsystem.data.VoucherValidator; +import org.mifos.pheevouchermanagementsystem.service.ActivateVoucherService; +import org.mifos.pheevouchermanagementsystem.service.RedeemVoucherService; +import org.mifos.pheevouchermanagementsystem.service.ValidateHeaders; +import org.mifos.pheevouchermanagementsystem.service.VoucherLifecycleService; +import org.mifos.pheevouchermanagementsystem.util.HeaderConstants; +import org.mifos.pheevouchermanagementsystem.validator.HeaderValidator; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@Slf4j +public class VoucherLifecycleManagementApiController implements VoucherLifecycleManagementApi { + + @Autowired + ActivateVoucherService activateVoucherService; + @Autowired + RedeemVoucherService redeemVoucherService; + @Autowired + ObjectMapper objectMapper; + @Autowired + VoucherLifecycleService voucherLifecycleService; + + @Autowired + VoucherValidator voucherValidator; + + @Override + @ValidateHeaders(requiredHeaders = { HeaderConstants.X_PROGRAM_ID, HeaderConstants.X_REGISTERING_INSTITUTION_ID, + HeaderConstants.X_CALLBACKURL }, validatorClass = HeaderValidator.class, validationFunction = "validateVoucherLifecycle") + public ResponseEntity voucherStatusChange(String callbackURL, String registeringInstitutionId, String programId, + Object requestBody, String command) { + RequestDTO requestDTO = null; + RedeemVoucherRequestDTO redeemVoucherRequestDTO = null; + try { + if (command.equals("activate")) { + requestDTO = objectMapper.convertValue(requestBody, RequestDTO.class); + PhErrorDTO phErrorDTO = voucherValidator.validateVoucherLifecycle(requestDTO); + if (phErrorDTO != null) { + return ResponseEntity.status(HttpStatus.BAD_REQUEST).body((T) phErrorDTO); + } + activateVoucherService.activateVouchers(requestDTO, callbackURL, registeringInstitutionId); + } else if (command.equals("suspend")) { + requestDTO = objectMapper.convertValue(requestBody, RequestDTO.class); + PhErrorDTO phErrorDTO = voucherValidator.validateVoucherLifecycle(requestDTO); + if (phErrorDTO != null) { + return ResponseEntity.status(HttpStatus.BAD_REQUEST).body((T) phErrorDTO); + } + voucherLifecycleService.suspendVoucher(requestDTO, callbackURL, registeringInstitutionId); + } else if (command.equals("reactivate")) { + requestDTO = objectMapper.convertValue(requestBody, RequestDTO.class); + PhErrorDTO phErrorDTO = voucherValidator.validateVoucherLifecycle(requestDTO); + if (phErrorDTO != null) { + return ResponseEntity.status(HttpStatus.BAD_REQUEST).body((T) phErrorDTO); + } + voucherLifecycleService.reactivateVoucher(requestDTO, callbackURL, registeringInstitutionId); + } else if (command.equals("redeemPay")) { + redeemVoucherRequestDTO = objectMapper.convertValue(requestBody, RedeemVoucherRequestDTO.class); + + PhErrorDTO phErrorDTO = voucherValidator.validateRedeemVoucher(redeemVoucherRequestDTO); + if (phErrorDTO != null) { + return ResponseEntity.status(HttpStatus.BAD_REQUEST).body((T) phErrorDTO); + } + redeemVoucherService.redeemAndPay(redeemVoucherRequestDTO, callbackURL, registeringInstitutionId); + } + } catch (NullPointerException e) { + Map responseBody = new HashMap<>(); + log.error("An error occurred : {}", e.getMessage()); + responseBody.put("failureReason", "An error occurred, contact the system admin !!"); + return (ResponseEntity) ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(responseBody); + } catch (Exception e) { + ResponseDTO responseDTO = new ResponseDTO(FAILED_RESPONSE.getValue(), FAILED_RESPONSE.getMessage(), requestDTO.getRequestID()); + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body((T) responseDTO); + } + String requestId; + if (requestDTO == null) { + requestId = redeemVoucherRequestDTO.getRequestId(); + } else { + requestId = requestDTO.getRequestID(); + } + ResponseDTO responseDTO = new ResponseDTO(SUCCESS_RESPONSE.getValue(), SUCCESS_RESPONSE.getMessage(), requestId); + return ResponseEntity.status(HttpStatus.ACCEPTED).body((T) responseDTO); + + } +} diff --git a/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/api/implementation/VoucherStatusApiController.java b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/api/implementation/VoucherStatusApiController.java new file mode 100644 index 000000000..a25488347 --- /dev/null +++ b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/api/implementation/VoucherStatusApiController.java @@ -0,0 +1,44 @@ +package org.mifos.pheevouchermanagementsystem.api.implementation; + +import java.util.concurrent.ExecutionException; +import org.mifos.pheevouchermanagementsystem.api.definition.VoucherStatusApi; +import org.mifos.pheevouchermanagementsystem.data.FetchVoucherResponseDTO; +import org.mifos.pheevouchermanagementsystem.data.VoucherStatusResponseDTO; +import org.mifos.pheevouchermanagementsystem.repository.VoucherRepository; +import org.mifos.pheevouchermanagementsystem.service.FetchVoucherService; +import org.mifos.pheevouchermanagementsystem.service.ValidateHeaders; +import org.mifos.pheevouchermanagementsystem.util.HeaderConstants; +import org.mifos.pheevouchermanagementsystem.validator.HeaderValidator; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.RestController; + +@RestController +public class VoucherStatusApiController implements VoucherStatusApi { + + @Autowired + private FetchVoucherService fetchVoucherService; + @Autowired + private final VoucherRepository voucherRepository; + + public VoucherStatusApiController(VoucherRepository voucherRepository) { + this.voucherRepository = voucherRepository; + } + + @Override + @ValidateHeaders(requiredHeaders = { + HeaderConstants.X_REGISTERING_INSTITUTION_ID }, validatorClass = HeaderValidator.class, validationFunction = "validateForRegisteringInstitutionID") + public ResponseEntity voucherStatus(String serialNumber, String registeringInstitutionId, String status) + throws ExecutionException, InterruptedException { + if (registeringInstitutionId == null || registeringInstitutionId.isEmpty() || !voucherRepository.existsBySerialNo(serialNumber)) { + return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(null); + } + FetchVoucherResponseDTO fetchVoucherResponseDTO = fetchVoucherService.fetchVoucher(serialNumber, registeringInstitutionId); + VoucherStatusResponseDTO voucherStatusResponseDTO = new VoucherStatusResponseDTO(); + voucherStatusResponseDTO.setSerialNumber(fetchVoucherResponseDTO.getSerialNumber()); + voucherStatusResponseDTO.setStatus(fetchVoucherResponseDTO.getStatus()); + return ResponseEntity.status(HttpStatus.OK).body(voucherStatusResponseDTO); + } + +} diff --git a/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/api/implementation/VoucherValidityApiController.java b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/api/implementation/VoucherValidityApiController.java new file mode 100644 index 000000000..848538758 --- /dev/null +++ b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/api/implementation/VoucherValidityApiController.java @@ -0,0 +1,38 @@ +package org.mifos.pheevouchermanagementsystem.api.implementation; + +import static org.mifos.pheevouchermanagementsystem.util.VoucherManagementEnum.FAILED_RESPONSE; +import static org.mifos.pheevouchermanagementsystem.util.VoucherManagementEnum.SUCCESS_RESPONSE; + +import java.util.concurrent.ExecutionException; +import org.mifos.pheevouchermanagementsystem.api.definition.VoucherValidityApi; +import org.mifos.pheevouchermanagementsystem.data.ResponseDTO; +import org.mifos.pheevouchermanagementsystem.service.ValidateHeaders; +import org.mifos.pheevouchermanagementsystem.service.VoucherValidityService; +import org.mifos.pheevouchermanagementsystem.util.HeaderConstants; +import org.mifos.pheevouchermanagementsystem.validator.HeaderValidator; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.RestController; + +@RestController +public class VoucherValidityApiController implements VoucherValidityApi { + + @Autowired + VoucherValidityService voucherValidityService; + + @Override + @ValidateHeaders(requiredHeaders = { HeaderConstants.X_PROGRAM_ID, HeaderConstants.X_REGISTERING_INSTITUTION_ID, + HeaderConstants.X_CALLBACKURL }, validatorClass = HeaderValidator.class, validationFunction = "validateVoucherLifecycle") + public ResponseEntity voucherValidity(String callbackURL, String registeringInstitutionId, String serialNumber, + String voucherNumber, String groupCode, Boolean isValid) throws ExecutionException, InterruptedException { + try { + voucherValidityService.getVoucherValidity(serialNumber, voucherNumber, groupCode, callbackURL); + } catch (Exception e) { + ResponseDTO responseDTO = new ResponseDTO(FAILED_RESPONSE.getValue(), FAILED_RESPONSE.getMessage(), ""); + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(responseDTO); + } + ResponseDTO responseDTO = new ResponseDTO(SUCCESS_RESPONSE.getValue(), SUCCESS_RESPONSE.getMessage(), ""); + return ResponseEntity.status(HttpStatus.ACCEPTED).body(responseDTO); + } +} diff --git a/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/camel/config/CamelContextConfig.java b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/camel/config/CamelContextConfig.java new file mode 100644 index 000000000..ad7c164d8 --- /dev/null +++ b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/camel/config/CamelContextConfig.java @@ -0,0 +1,45 @@ +package org.mifos.pheevouchermanagementsystem.camel.config; + +import java.util.HashMap; +import org.apache.camel.CamelContext; +import org.apache.camel.spi.RestConfiguration; +import org.apache.camel.spring.boot.CamelContextConfiguration; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class CamelContextConfig { + + @Value("${camel.serverPort}") + private int serverPort; + + @Bean + CamelContextConfiguration contextConfiguration() { + return new CamelContextConfiguration() { + + @Override + public void beforeApplicationStart(CamelContext camelContext) { + camelContext.setTracing(false); + camelContext.setMessageHistory(false); + camelContext.setStreamCaching(true); + camelContext.disableJMX(); + + RestConfiguration rest = new RestConfiguration(); + camelContext.setRestConfiguration(rest); + rest.setComponent("undertow"); + rest.setProducerComponent("undertow"); + rest.setPort(serverPort); + rest.setBindingMode(RestConfiguration.RestBindingMode.json); + rest.setDataFormatProperties(new HashMap<>()); + rest.getDataFormatProperties().put("prettyPrint", "true"); + rest.setScheme("http"); + } + + @Override + public void afterApplicationStart(CamelContext camelContext) { + // empty + } + }; + } +} diff --git a/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/camel/config/CamelProperties.java b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/camel/config/CamelProperties.java new file mode 100644 index 000000000..f9002a7aa --- /dev/null +++ b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/camel/config/CamelProperties.java @@ -0,0 +1,15 @@ +package org.mifos.pheevouchermanagementsystem.camel.config; + +public final class CamelProperties { + + private CamelProperties() {} + + public static final String HOST = "externalApiCallHost"; + public static final String ENDPOINT = "externalApiCallEndpoint"; + public static final String CACHED_TRANSACTION_ID = "cachedTransactionId"; + public static final String PAYEE_IDENTITY = "payeeIdentity"; + public static final String PAYMENT_MODALITY = "paymentModality"; + public static final String PAYEE_PARTY_ID = "payeePartyId"; + public static final String PAYEE_PARTY_ID_TYPE = "payeePartyIdType"; + +} diff --git a/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/camel/processor/AccountLookupCallbackProcessor.java b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/camel/processor/AccountLookupCallbackProcessor.java new file mode 100644 index 000000000..2190ad175 --- /dev/null +++ b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/camel/processor/AccountLookupCallbackProcessor.java @@ -0,0 +1,62 @@ +package org.mifos.pheevouchermanagementsystem.camel.processor; + +import static org.mifos.pheevouchermanagementsystem.camel.config.CamelProperties.CACHED_TRANSACTION_ID; +import static org.mifos.pheevouchermanagementsystem.camel.config.CamelProperties.PAYEE_PARTY_ID; +import static org.mifos.pheevouchermanagementsystem.camel.config.CamelProperties.PAYEE_PARTY_ID_TYPE; +import static org.mifos.pheevouchermanagementsystem.util.PaymentModalityEnum.getKeyByValue; +import static org.mifos.pheevouchermanagementsystem.zeebe.ZeebeMessages.ACCOUNT_LOOKUP; +import static org.mifos.pheevouchermanagementsystem.zeebe.ZeebeVariables.ACCOUNT_LOOKUP_FAILED; +import static org.mifos.pheevouchermanagementsystem.zeebe.ZeebeVariables.TENANT_ID; + +import com.fasterxml.jackson.databind.ObjectMapper; +import io.camunda.zeebe.client.ZeebeClient; +import java.io.IOException; +import java.time.Duration; +import java.util.HashMap; +import java.util.Map; +import org.apache.camel.Exchange; +import org.apache.camel.Processor; +import org.mifos.pheevouchermanagementsystem.data.AccountLookupResponseDTO; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component +public class AccountLookupCallbackProcessor implements Processor { + + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Autowired(required = false) + private ZeebeClient zeebeClient; + @Autowired + private ObjectMapper objectMapper; + + @Override + public void process(Exchange exchange) throws Exception { + Map variables = new HashMap<>(); + + String error = null; + String response = exchange.getIn().getBody(String.class); + AccountLookupResponseDTO accountLookupResponseDTO = null; + try { + accountLookupResponseDTO = objectMapper.readValue(response, AccountLookupResponseDTO.class); + variables.put(ACCOUNT_LOOKUP_FAILED, false); + variables.put(PAYEE_PARTY_ID, accountLookupResponseDTO.getPaymentModalityList().get(0).getFinancialAddress()); + variables.put(PAYEE_PARTY_ID_TYPE, + getKeyByValue(accountLookupResponseDTO.getPaymentModalityList().get(0).getPaymentModality())); + variables.put(TENANT_ID, accountLookupResponseDTO.getPaymentModalityList().get(0).getBankingInstitutionCode()); + exchange.setProperty(CACHED_TRANSACTION_ID, accountLookupResponseDTO.getRequestId()); + } catch (IOException e) { + variables.put(ACCOUNT_LOOKUP_FAILED, true); + error = objectMapper.readValue(response, String.class); + } + + if (zeebeClient != null) { + + zeebeClient.newPublishMessageCommand().messageName(ACCOUNT_LOOKUP) + .correlationKey(exchange.getProperty(CACHED_TRANSACTION_ID, String.class)).timeToLive(Duration.ofMillis(50000)) + .variables(variables).send(); + } + } +} diff --git a/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/camel/routes/AccountLookupRoute.java b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/camel/routes/AccountLookupRoute.java new file mode 100644 index 000000000..a8a3676ae --- /dev/null +++ b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/camel/routes/AccountLookupRoute.java @@ -0,0 +1,40 @@ +package org.mifos.pheevouchermanagementsystem.camel.routes; + +import static org.mifos.pheevouchermanagementsystem.camel.config.CamelProperties.ENDPOINT; +import static org.mifos.pheevouchermanagementsystem.camel.config.CamelProperties.HOST; +import static org.mifos.pheevouchermanagementsystem.camel.config.CamelProperties.PAYEE_IDENTITY; +import static org.mifos.pheevouchermanagementsystem.zeebe.ZeebeVariables.CALLBACK; +import static org.mifos.pheevouchermanagementsystem.zeebe.ZeebeVariables.REGISTERING_INSTITUTION_ID; + +import org.apache.camel.Exchange; +import org.apache.camel.LoggingLevel; +import org.mifos.pheevouchermanagementsystem.camel.processor.AccountLookupCallbackProcessor; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component +public class AccountLookupRoute extends BaseRouteBuilder { + + @Autowired + AccountLookupCallbackProcessor accountLookupCallbackProcessor; + + @Override + public void configure() throws Exception { + + from("rest:PUT:/accountLookup/Callback").log(LoggingLevel.DEBUG, "######## -> ACCOUNT LOOKUP CALLBACK") + .process(accountLookupCallbackProcessor).setBody(constant("Received")).setHeader(Exchange.HTTP_RESPONSE_CODE, constant(200)) + .end(); + + from("direct:send-account-lookup").id("account-lookup").process(exchange -> { + String callbackUrl = exchange.getProperty(CALLBACK, String.class); + exchange.getIn().setHeader(CALLBACK, callbackUrl); + exchange.getIn().setHeader("X-Registering-Institution-ID", exchange.getProperty(REGISTERING_INSTITUTION_ID)); + }).setHeader(Exchange.HTTP_METHOD, constant("GET")) + .setHeader(Exchange.HTTP_QUERY, + simple(new StringBuilder().append(PAYEE_IDENTITY).append("=${exchangeProperty.").append(PAYEE_IDENTITY).append("}&") + .append("requestId=${exchangeProperty.requestId}") + .append("&paymentModality=${exchangeProperty.paymentModality}").toString())) + .setProperty(HOST, simple("{{identity-account-mapper.hostname}}")).setProperty(ENDPOINT, simple("beneficiary/")) + .to("direct:external-api-calling"); + } +} diff --git a/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/camel/routes/BaseRouteBuilder.java b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/camel/routes/BaseRouteBuilder.java new file mode 100644 index 000000000..21b45bad3 --- /dev/null +++ b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/camel/routes/BaseRouteBuilder.java @@ -0,0 +1,35 @@ +package org.mifos.pheevouchermanagementsystem.camel.routes; + +import com.fasterxml.jackson.databind.ObjectMapper; +import io.camunda.zeebe.client.ZeebeClient; +import org.apache.camel.builder.RouteBuilder; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; + +public abstract class BaseRouteBuilder extends RouteBuilder { + + @Autowired + public ObjectMapper objectMapper; + + @Autowired + ZeebeClient zeebeClient; + + public Logger logger = LoggerFactory.getLogger(this.getClass()); + + protected enum HttpRequestMethod { + + GET("GET"), POST("POST"), PUT("PUT"), DELETE("DELETE"); + + private final String text; + + HttpRequestMethod(String text) { + this.text = text; + } + + @Override + public String toString() { + return text; + } + } +} diff --git a/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/camel/routes/ExternalApiCallRoute.java b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/camel/routes/ExternalApiCallRoute.java new file mode 100644 index 000000000..4bde0a2a9 --- /dev/null +++ b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/camel/routes/ExternalApiCallRoute.java @@ -0,0 +1,28 @@ +package org.mifos.pheevouchermanagementsystem.camel.routes; + +import static org.mifos.pheevouchermanagementsystem.camel.config.CamelProperties.ENDPOINT; +import static org.mifos.pheevouchermanagementsystem.camel.config.CamelProperties.HOST; + +import org.apache.camel.LoggingLevel; +import org.apache.camel.builder.RouteBuilder; +import org.springframework.stereotype.Component; + +@Component +public class ExternalApiCallRoute extends RouteBuilder { + + @Override + public void configure() { + from("direct:external-api-calling").id("external-api-call").log(LoggingLevel.DEBUG, "######## API CALL -> Calling an external api") + .process(exchange -> { + // remove the trailing "/" from endpoint + String endpoint = exchange.getProperty(ENDPOINT, String.class); + if (endpoint.startsWith("/")) { + exchange.setProperty(ENDPOINT, endpoint.substring(1)); + } + }).log(LoggingLevel.DEBUG, "Host: ${exchangeProperty." + HOST + "}") + .log(LoggingLevel.DEBUG, "Endpoint: ${exchangeProperty." + ENDPOINT + "}").log(LoggingLevel.DEBUG, "Headers: ${headers}") + .log(LoggingLevel.DEBUG, "Request Body: ${body}").toD("${exchangeProperty." + HOST + "}/${exchangeProperty." + ENDPOINT + + "}" + "?bridgeEndpoint=true" + "&throwExceptionOnFailure=false") + .log(LoggingLevel.DEBUG, "Response body: ${body}"); + } +} diff --git a/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/camel/routes/TransferStatusRoute.java b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/camel/routes/TransferStatusRoute.java new file mode 100644 index 000000000..5a261fd31 --- /dev/null +++ b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/camel/routes/TransferStatusRoute.java @@ -0,0 +1,23 @@ +package org.mifos.pheevouchermanagementsystem.camel.routes; + +import static org.mifos.pheevouchermanagementsystem.camel.config.CamelProperties.ENDPOINT; +import static org.mifos.pheevouchermanagementsystem.camel.config.CamelProperties.HOST; + +import org.apache.camel.Exchange; +import org.springframework.stereotype.Component; + +@Component +public class TransferStatusRoute extends BaseRouteBuilder { + + @Override + public void configure() throws Exception { + from("direct:direct:send-transfer-query").id("transfer-status").process(exchange -> { + exchange.getIn().setHeader("Platform-TenantId", exchange.getProperty("tenantId")); + }).setHeader(Exchange.HTTP_METHOD, constant("GET")) + .setHeader(Exchange.HTTP_QUERY, + simple(new StringBuilder().append("size=1").append("page=0") + .append("clientCorrelationId=${exchangeProperty.clientCorrelationId}").toString())) + .setProperty(HOST, simple("{{operations.hostname}}")).setProperty(ENDPOINT, simple("/api/v1/transfers/")) + .to("direct:external-api-calling"); + } +} diff --git a/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/data/AccountLookupResponseDTO.java b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/data/AccountLookupResponseDTO.java new file mode 100644 index 000000000..a6dfb8461 --- /dev/null +++ b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/data/AccountLookupResponseDTO.java @@ -0,0 +1,22 @@ +package org.mifos.pheevouchermanagementsystem.data; + +import java.io.Serializable; +import java.util.List; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +@Data +public class AccountLookupResponseDTO implements Serializable { + + private String requestId; + private String payeeIdentity; + private List paymentModalityList; + +} diff --git a/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/data/AuthorizationRequest.java b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/data/AuthorizationRequest.java new file mode 100644 index 000000000..b52fa8f36 --- /dev/null +++ b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/data/AuthorizationRequest.java @@ -0,0 +1,22 @@ +package org.mifos.pheevouchermanagementsystem.data; + +import java.math.BigDecimal; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +public class AuthorizationRequest { + + private String batchId; + + private String payerIdentifier; + + private String currency; + + private BigDecimal amount; +} diff --git a/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/data/AuthorizationResponse.java b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/data/AuthorizationResponse.java new file mode 100644 index 000000000..d4a462a30 --- /dev/null +++ b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/data/AuthorizationResponse.java @@ -0,0 +1,19 @@ +package org.mifos.pheevouchermanagementsystem.data; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +public class AuthorizationResponse { + + private String clientCorrelationId; + + private String status; + + private String reason; +} diff --git a/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/data/CallbackRequestDTO.java b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/data/CallbackRequestDTO.java new file mode 100644 index 000000000..2258f92c4 --- /dev/null +++ b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/data/CallbackRequestDTO.java @@ -0,0 +1,19 @@ +package org.mifos.pheevouchermanagementsystem.data; + +import java.util.List; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +public class CallbackRequestDTO { + + private String requestID; + private String batchID; + private List voucherInstructions; + +} diff --git a/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/data/ConflictResponseDTO.java b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/data/ConflictResponseDTO.java new file mode 100644 index 000000000..616a4debd --- /dev/null +++ b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/data/ConflictResponseDTO.java @@ -0,0 +1,18 @@ +package org.mifos.pheevouchermanagementsystem.data; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +public class ConflictResponseDTO { + + private String responseCode; + private String responseDescription; + private String conflictingFieldName; + private String conflictingFieldValue; +} diff --git a/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/data/FailedCaseDTO.java b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/data/FailedCaseDTO.java new file mode 100644 index 000000000..44842568d --- /dev/null +++ b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/data/FailedCaseDTO.java @@ -0,0 +1,16 @@ +package org.mifos.pheevouchermanagementsystem.data; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +public class FailedCaseDTO { + + private String serialNumber; + private String failureReason; +} diff --git a/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/data/FetchVoucherResponseDTO.java b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/data/FetchVoucherResponseDTO.java new file mode 100644 index 000000000..002a4222b --- /dev/null +++ b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/data/FetchVoucherResponseDTO.java @@ -0,0 +1,20 @@ +package org.mifos.pheevouchermanagementsystem.data; + +import java.time.LocalDateTime; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +public class FetchVoucherResponseDTO { + + private String serialNumber; + private LocalDateTime createdDate; + private String registeringInstitutionId; + private String status; + private String payeeFunctionalID; +} diff --git a/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/data/PaymentModalityDTO.java b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/data/PaymentModalityDTO.java new file mode 100644 index 000000000..0809c2a31 --- /dev/null +++ b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/data/PaymentModalityDTO.java @@ -0,0 +1,17 @@ +package org.mifos.pheevouchermanagementsystem.data; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +public class PaymentModalityDTO { + + private String paymentModality; + private String financialAddress; + private String bankingInstitutionCode; +} diff --git a/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/data/RedeemVoucherRequestDTO.java b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/data/RedeemVoucherRequestDTO.java new file mode 100644 index 000000000..b4203c09a --- /dev/null +++ b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/data/RedeemVoucherRequestDTO.java @@ -0,0 +1,27 @@ +package org.mifos.pheevouchermanagementsystem.data; + +import com.fasterxml.jackson.annotation.JsonAnySetter; +import java.util.HashMap; +import java.util.Map; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +public class RedeemVoucherRequestDTO { + + private String requestId; + private String agentId; + private String voucherSerialNumber; + private String voucherSecretNumber; + private Map additionalProperties = new HashMap<>(); + + @JsonAnySetter + public void setAdditionalProperty(String name, Object value) { + additionalProperties.put(name, value); + } +} diff --git a/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/data/RedeemVoucherResponseDTO.java b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/data/RedeemVoucherResponseDTO.java new file mode 100644 index 000000000..2f06e61d4 --- /dev/null +++ b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/data/RedeemVoucherResponseDTO.java @@ -0,0 +1,20 @@ +package org.mifos.pheevouchermanagementsystem.data; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +public class RedeemVoucherResponseDTO { + + private String status; + private String message; + private String serialNumber; + private String value; + private String timestamp; + private String transactionId; +} diff --git a/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/data/RequestDTO.java b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/data/RequestDTO.java new file mode 100644 index 000000000..3337101b6 --- /dev/null +++ b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/data/RequestDTO.java @@ -0,0 +1,27 @@ +package org.mifos.pheevouchermanagementsystem.data; + +import com.fasterxml.jackson.annotation.JsonAnySetter; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +public class RequestDTO { + + public String requestID; + public String batchID; + public ArrayList voucherInstructions; + private Map additionalProperties = new HashMap<>(); + + @JsonAnySetter + public void setAdditionalProperty(String name, Object value) { + additionalProperties.put(name, value); + } +} diff --git a/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/data/ResponseDTO.java b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/data/ResponseDTO.java new file mode 100644 index 000000000..2c1d98a9f --- /dev/null +++ b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/data/ResponseDTO.java @@ -0,0 +1,17 @@ +package org.mifos.pheevouchermanagementsystem.data; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +public class ResponseDTO { + + private String responseCode; + private String responseDescription; + private String requestID; +} diff --git a/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/data/SuccessfulVouchers.java b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/data/SuccessfulVouchers.java new file mode 100644 index 000000000..b6261ce1b --- /dev/null +++ b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/data/SuccessfulVouchers.java @@ -0,0 +1,21 @@ +package org.mifos.pheevouchermanagementsystem.data; + +import java.math.BigDecimal; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +public class SuccessfulVouchers { + + private String instructionID; + private String currency; + private BigDecimal amount; + private String narration; + private String voucherNumber; + private String serialNumber; +} diff --git a/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/data/UnsupportedParameterValidation.java b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/data/UnsupportedParameterValidation.java new file mode 100644 index 000000000..11052e804 --- /dev/null +++ b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/data/UnsupportedParameterValidation.java @@ -0,0 +1,67 @@ +package org.mifos.pheevouchermanagementsystem.data; + +import java.util.List; +import java.util.Map; +import java.util.Set; +import org.mifos.connector.common.validation.ValidationCodeType; +import org.mifos.connector.common.validation.ValidatorBuilder; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +@Component +public class UnsupportedParameterValidation { + + @Value("#{'${default_headers}'.split(',')}") + private Set defaultHeader; + final StringBuilder validationErrorCode = new StringBuilder("error.msg.parameter.unsupported"); + + public void handleUnsupportedParameterValidation(Map additionalProperties, ValidatorBuilder validatorBuilder) { + + for (final String parameterName : additionalProperties.keySet()) { + final StringBuilder defaultEnglishMessage = new StringBuilder("The parameter ").append(parameterName) + .append(" is not supported."); + + ValidationCodeType validationCode = convertToStructuredErrorMessage(validationErrorCode.toString(), + defaultEnglishMessage.toString()); + validatorBuilder.failWithCode(validationCode); + } + + } + + public void handleRequiredParameterValidation(List fields, Set requiredFields, ValidatorBuilder validatorBuilder) { + + for (final String fieldName : fields) { + if (fieldName != "additionalProperties" && !requiredFields.contains(fieldName) && !defaultHeader.contains(fieldName)) { + + final StringBuilder defaultEnglishMessage = new StringBuilder("The parameter ").append(fieldName) + .append(" is not supported."); + + ValidationCodeType validationCode = convertToStructuredErrorMessage(validationErrorCode.toString(), + defaultEnglishMessage.toString()); + validatorBuilder.failWithCode(validationCode); + } + } + + } + + private ValidationCodeType convertToStructuredErrorMessage(String errorCode, String errorMessage) { + return new ValidationCodeType() { + + @Override + public String getCode() { + return errorCode; + } + + @Override + public String getCategory() { + return "Validation"; + } + + @Override + public String getMessage() { + return errorMessage; + } + }; + } + +} \ No newline at end of file diff --git a/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/data/ValidityDTO.java b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/data/ValidityDTO.java new file mode 100644 index 000000000..92688f029 --- /dev/null +++ b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/data/ValidityDTO.java @@ -0,0 +1,16 @@ +package org.mifos.pheevouchermanagementsystem.data; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +public class ValidityDTO { + + private String serialNumber; + private Boolean isValid; +} diff --git a/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/data/VoucherInstruction.java b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/data/VoucherInstruction.java new file mode 100644 index 000000000..2b7673147 --- /dev/null +++ b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/data/VoucherInstruction.java @@ -0,0 +1,54 @@ +package org.mifos.pheevouchermanagementsystem.data; + +import com.fasterxml.jackson.annotation.JsonAnySetter; +import java.lang.reflect.Field; +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +public class VoucherInstruction { + + private String instructionID; + private String groupCode; + private String currency; + private BigDecimal amount; + private String payeeFunctionalID; + private String narration; + private String voucherNumber; + private String serialNumber; + private String status; + + private Map additionalProperties = new HashMap<>(); + + @JsonAnySetter + public void setAdditionalProperty(String name, Object value) { + additionalProperties.put(name, value); + } + + public List getNonNullFieldNames() throws IllegalAccessException { + List nonNullFields = new ArrayList<>(); + Field[] fields = this.getClass().getDeclaredFields(); + for (Field field : fields) { + try { + field.setAccessible(true); + Object value = field.get(this); + if (value != null && !field.getName().equals("additionalProperties")) { + nonNullFields.add(field.getName()); + } + } catch (IllegalAccessException e) { + throw e; + } + } + return nonNullFields; + } +} diff --git a/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/data/VoucherLifecycleCallbackResponseDTO.java b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/data/VoucherLifecycleCallbackResponseDTO.java new file mode 100644 index 000000000..fab49d002 --- /dev/null +++ b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/data/VoucherLifecycleCallbackResponseDTO.java @@ -0,0 +1,19 @@ +package org.mifos.pheevouchermanagementsystem.data; + +import java.util.List; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +public class VoucherLifecycleCallbackResponseDTO { + + private String requestID; + private String registerRequestID; + private Integer numberFailedCases; + private List failedCases; +} diff --git a/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/data/VoucherStatusResponseDTO.java b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/data/VoucherStatusResponseDTO.java new file mode 100644 index 000000000..34081d79f --- /dev/null +++ b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/data/VoucherStatusResponseDTO.java @@ -0,0 +1,19 @@ +package org.mifos.pheevouchermanagementsystem.data; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +public class VoucherStatusResponseDTO { + + private String serialNumber; + private String status; + + private String value; + +} diff --git a/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/data/VoucherValidator.java b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/data/VoucherValidator.java new file mode 100644 index 000000000..e4a7802c5 --- /dev/null +++ b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/data/VoucherValidator.java @@ -0,0 +1,221 @@ +package org.mifos.pheevouchermanagementsystem.data; + +import static org.mifos.connector.common.exception.PaymentHubError.ExtValidationError; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; +import org.mifos.connector.common.channel.dto.PhErrorDTO; +import org.mifos.connector.common.exception.PaymentHubErrorCategory; +import org.mifos.connector.common.validation.ValidatorBuilder; +import org.mifos.pheevouchermanagementsystem.util.VoucherValidatorsEnum; +import org.mifos.pheevouchermanagementsystem.util.VouchersDTOConstant; +import org.springframework.stereotype.Component; + +@Component +public class VoucherValidator { + + private static final String resource = "voucherValidator"; + private static final String requestId = "requestId"; + private static final int expectedRequestIdLength = 12; + private static final String batchId = "batchId"; + private static final int expectedBatchIdLength = 12; + private static final String voucherInstructions = "voucherInstructions"; + private static final String instructionID = "instructionId"; + private static final int expectedInstructionIdLength = 16; + private static final String groupCode = "groupCode"; + private static final int expectedGroupCodeLength = 3; + private static final String currency = "currency"; + private static final int expectedCurrencyLength = 3; + private static final String amount = "amount"; + private static final String payeeFunctionalID = "payeeFunctionalId"; + private static final int expectedPayeeFunctionalIDLength = 20; + private static final String narration = "narration"; + private static final int maximumNarrationLength = 50; + private static final String serialNumber = "serialNumber"; + private static final int expectedSerialNumberLength = 20; + private static final String agentID = "agentId"; + private static final int expectedAgentIDLength = 10; + private static final String voucherSerialNumber = "voucherSerialNumber"; + private static final String voucherSecretNumber = "voucherSecretNumber"; + private static final int expectedVoucherSecretNumberLength = 6; + + public UnsupportedParameterValidation unsupportedParameterValidation = new UnsupportedParameterValidation(); + + public PhErrorDTO validateCreateVoucher(RequestDTO request) { + final ValidatorBuilder validatorBuilder = new ValidatorBuilder(); + unsupportedParameterValidation.handleUnsupportedParameterValidation(request.getAdditionalProperties(), validatorBuilder); + + // Checks for requestID + validatorBuilder.reset().resource(resource).parameter(requestId).value(request.getRequestID()) + .isNullWithFailureCode(VoucherValidatorsEnum.INVALID_REQUEST_ID).validateFieldMaxLengthWithFailureCodeAndErrorParams( + expectedRequestIdLength, VoucherValidatorsEnum.INVALID_REQUEST_ID_LENGTH); + + // Checks for batchID + validatorBuilder.reset().resource(resource).parameter(batchId).value(request.getBatchID()) + .isNullWithFailureCode(VoucherValidatorsEnum.INVALID_BATCH_ID) + .validateFieldMaxLengthWithFailureCodeAndErrorParams(expectedBatchIdLength, VoucherValidatorsEnum.INVALID_BATCH_ID_LENGTH); + + // Check for voucherInstructions + validatorBuilder.reset().resource(resource).parameter(voucherInstructions).value(request.getVoucherInstructions()) + .isNullWithFailureCode(VoucherValidatorsEnum.INVALID_VOUCHER_INSTRUCTIONS); + if (request.getVoucherInstructions() == null) { + request.setVoucherInstructions(new ArrayList<>(Arrays.asList(new VoucherInstruction()))); + } + + request.getVoucherInstructions().forEach(voucherInstruction -> { + // check for unsupported parameters in voucherInstruction + unsupportedParameterValidation.handleUnsupportedParameterValidation(voucherInstruction.getAdditionalProperties(), + validatorBuilder); + + // Check for instructionID + validatorBuilder.reset().resource(resource).parameter(instructionID).value(voucherInstruction.getInstructionID()) + .isNullWithFailureCode(VoucherValidatorsEnum.INVALID_INSTRUCTION_ID) + .validateFieldMaxLengthWithFailureCodeAndErrorParams(expectedInstructionIdLength, + VoucherValidatorsEnum.INVALID_INSTRUCTION_ID_LENGTH); + + // Check for groupCode + validatorBuilder.reset().resource(resource).parameter(groupCode).value(voucherInstruction.getGroupCode()) + .isNullWithFailureCode(VoucherValidatorsEnum.INVALID_GROUP_CODE) + .validateFieldNotBlankAndLengthWithFailureCodeAndErrorParams(expectedGroupCodeLength, + VoucherValidatorsEnum.INVALID_GROUP_CODE_LENGTH); + + // Check for currency + validatorBuilder.reset().resource(resource).parameter(currency).value(voucherInstruction.getCurrency()) + .isNullWithFailureCode(VoucherValidatorsEnum.INVALID_CURRENCY) + .validateFieldNotBlankAndLengthWithFailureCodeAndErrorParams(expectedCurrencyLength, + VoucherValidatorsEnum.INVALID_CURRENCY_LENGTH); + + // Check for amount + validatorBuilder.reset().resource(resource).parameter(amount).value(voucherInstruction.getAmount()) + .isNullWithFailureCode(VoucherValidatorsEnum.INVALID_AMOUNT) + .validateBigDecimalFieldNotNegativeWithFailureCode(VoucherValidatorsEnum.INVALID_NEGATIVE_AMOUNT); + + // Check for payeeFunctionalID + validatorBuilder.reset().resource(resource).parameter(payeeFunctionalID).value(voucherInstruction.getPayeeFunctionalID()) + .ignoreIfNull().validateFieldMaxLengthWithFailureCodeAndErrorParams(expectedPayeeFunctionalIDLength, + VoucherValidatorsEnum.INVALID_PAYEE_FUNCTIONAL_ID_LENGTH); + + // Check for narration + validatorBuilder.reset().resource(resource).parameter(narration).value(voucherInstruction.getNarration()).ignoreIfNull() + .validateFieldMaxLengthWithFailureCodeAndErrorParams(maximumNarrationLength, + VoucherValidatorsEnum.INVALID_NARRATION_LENGTH); + }); + + // If errors exist, build and return PhErrorDTO + if (validatorBuilder.hasError()) { + validatorBuilder.errorCategory(PaymentHubErrorCategory.Validation.toString()) + .errorCode(VoucherValidatorsEnum.VOUCHER_SCHEMA_VALIDATION_ERROR.getCode()) + .errorDescription(VoucherValidatorsEnum.VOUCHER_SCHEMA_VALIDATION_ERROR.getMessage()) + .developerMessage(VoucherValidatorsEnum.VOUCHER_SCHEMA_VALIDATION_ERROR.getMessage()) + .defaultUserMessage(VoucherValidatorsEnum.VOUCHER_SCHEMA_VALIDATION_ERROR.getMessage()); + + PhErrorDTO.PhErrorDTOBuilder phErrorDTOBuilder = new PhErrorDTO.PhErrorDTOBuilder(ExtValidationError.getErrorCode()); + phErrorDTOBuilder.fromValidatorBuilder(validatorBuilder); + return phErrorDTOBuilder.build(); + } + + return null; + } + + public PhErrorDTO validateVoucherLifecycle(RequestDTO request) { + final ValidatorBuilder validatorBuilder = new ValidatorBuilder(); + + // check for unsupported parameter + unsupportedParameterValidation.handleUnsupportedParameterValidation(request.getAdditionalProperties(), validatorBuilder); + + // Checks for requestID + validatorBuilder.reset().resource(resource).parameter(requestId).value(request.getRequestID()) + .validateFieldMaxLengthWithFailureCodeAndErrorParams(expectedRequestIdLength, + VoucherValidatorsEnum.INVALID_REQUEST_ID_LENGTH); + + // Checks for batchID + validatorBuilder.reset().resource(resource).parameter(batchId).value(request.getBatchID()) + .isNullWithFailureCode(VoucherValidatorsEnum.INVALID_BATCH_ID) + .validateFieldMaxLengthWithFailureCodeAndErrorParams(expectedBatchIdLength, VoucherValidatorsEnum.INVALID_BATCH_ID_LENGTH); + + // Check for voucherInstructions + validatorBuilder.reset().resource(resource).parameter(voucherInstructions).value(request.getVoucherInstructions()) + .isNullWithFailureCode(VoucherValidatorsEnum.INVALID_VOUCHER_INSTRUCTIONS); + if (request.getVoucherInstructions() == null) { + request.setVoucherInstructions(new ArrayList<>(Arrays.asList(new VoucherInstruction()))); + } + + Set requiredFields = new HashSet<>(); + requiredFields.add(VouchersDTOConstant.serialNumber); + requiredFields.add(VouchersDTOConstant.status); + + request.getVoucherInstructions().forEach(voucherInstruction -> { + // check for unsupported parameters in voucherInstruction + unsupportedParameterValidation.handleUnsupportedParameterValidation(voucherInstruction.getAdditionalProperties(), + validatorBuilder); + + // check for only required fields needed from the voucherInstructionDTO + try { + unsupportedParameterValidation.handleRequiredParameterValidation(voucherInstruction.getNonNullFieldNames(), requiredFields, + validatorBuilder); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } + + // // Check for serialNumber + // validatorBuilder.reset().resource(resource).parameter(serialNumber).value(voucherInstruction.getSerialNumber()) + // .isNullWithFailureCode(VoucherValidatorsEnum.INVALID_SERIAL_NUMBER).validateFieldMaxLengthWithFailureCodeAndErrorParams( + // expectedSerialNumberLength, VoucherValidatorsEnum.INVALID_SERIAL_NUMBER_LENGTH); + }); + + // If errors exist, build and return PhErrorDTO + if (validatorBuilder.hasError()) { + validatorBuilder.errorCategory(PaymentHubErrorCategory.Validation.toString()) + .errorCode(VoucherValidatorsEnum.VOUCHER_LIFECYCLE_VALIDATION_ERROR.getCode()) + .errorDescription(VoucherValidatorsEnum.VOUCHER_LIFECYCLE_VALIDATION_ERROR.getMessage()) + .developerMessage(VoucherValidatorsEnum.VOUCHER_LIFECYCLE_VALIDATION_ERROR.getMessage()) + .defaultUserMessage(VoucherValidatorsEnum.VOUCHER_LIFECYCLE_VALIDATION_ERROR.getMessage()); + + PhErrorDTO.PhErrorDTOBuilder phErrorDTOBuilder = new PhErrorDTO.PhErrorDTOBuilder(ExtValidationError.getErrorCode()); + phErrorDTOBuilder.fromValidatorBuilder(validatorBuilder); + return phErrorDTOBuilder.build(); + } + + return null; + } + + public PhErrorDTO validateRedeemVoucher(RedeemVoucherRequestDTO request) { + final ValidatorBuilder validatorBuilder = new ValidatorBuilder(); + + // check for unsupported parameter + unsupportedParameterValidation.handleUnsupportedParameterValidation(request.getAdditionalProperties(), validatorBuilder); + + // Check for requestID + validatorBuilder.reset().resource(resource).parameter(requestId).value(request.getRequestId()) + .isNullWithFailureCode(VoucherValidatorsEnum.INVALID_REQUEST_ID).validateFieldMaxLengthWithFailureCodeAndErrorParams( + expectedRequestIdLength, VoucherValidatorsEnum.INVALID_REQUEST_ID_LENGTH); + + // Check for agentID + validatorBuilder.reset().resource(resource).parameter(agentID).value(request.getAgentId()) + .isNullWithFailureCode(VoucherValidatorsEnum.INVALID_AGENT_ID) + .validateFieldMaxLengthWithFailureCodeAndErrorParams(expectedAgentIDLength, VoucherValidatorsEnum.INVALID_AGENT_ID_LENGTH); + + // // Check for voucherSecretNumber + // validatorBuilder.reset().resource(resource).parameter(voucherSecretNumber).value(request.getVoucherSecretNumber()) + // .isNullWithFailureCode(VoucherValidatorsEnum.INVALID_VOUCHER_SECRET_NUMBER) + // .validateFieldNotBlankAndLengthWithFailureCodeAndErrorParams(expectedVoucherSecretNumberLength, + // VoucherValidatorsEnum.INVALID_VOUCHER_SECRET_NUMBER_LENGTH); + + // If errors exist, build and return PhErrorDTO + if (validatorBuilder.hasError()) { + validatorBuilder.errorCategory(PaymentHubErrorCategory.Validation.toString()) + .errorCode(VoucherValidatorsEnum.REDEEM_VOUCHER_VALIDATION_ERROR.getCode()) + .errorDescription(VoucherValidatorsEnum.REDEEM_VOUCHER_VALIDATION_ERROR.getMessage()) + .developerMessage(VoucherValidatorsEnum.REDEEM_VOUCHER_VALIDATION_ERROR.getMessage()) + .defaultUserMessage(VoucherValidatorsEnum.REDEEM_VOUCHER_VALIDATION_ERROR.getMessage()); + + PhErrorDTO.PhErrorDTOBuilder phErrorDTOBuilder = new PhErrorDTO.PhErrorDTOBuilder(ExtValidationError.getErrorCode()); + phErrorDTOBuilder.fromValidatorBuilder(validatorBuilder); + return phErrorDTOBuilder.build(); + } + + return null; + } +} diff --git a/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/domain/ErrorTracking.java b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/domain/ErrorTracking.java new file mode 100644 index 000000000..39b534b2b --- /dev/null +++ b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/domain/ErrorTracking.java @@ -0,0 +1,29 @@ +package org.mifos.pheevouchermanagementsystem.domain; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.Table; + +@Entity +@Table(name = "error") +public class ErrorTracking { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + @Column(name = "request_id", nullable = false) + private String requestId; + @Column(name = "instruction_id", nullable = false) + private String instructionId; + @Column(name = "error_description", nullable = false) + private String errorDescription; + + public ErrorTracking(String requestId, String instructionId, String errorDescription) { + this.requestId = requestId; + this.instructionId = instructionId; + this.errorDescription = errorDescription; + } +} diff --git a/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/domain/Voucher.java b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/domain/Voucher.java new file mode 100644 index 000000000..e23d0c105 --- /dev/null +++ b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/domain/Voucher.java @@ -0,0 +1,204 @@ +package org.mifos.pheevouchermanagementsystem.domain; + +import java.math.BigDecimal; +import java.sql.Date; +import java.time.LocalDateTime; +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.Table; + +@Entity +@Table(name = "vouchers") +public class Voucher { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @Column(name = "serial_no", unique = true) + private String serialNo; + + @Column(name = "voucher_no", unique = true) + private String voucherNo; + + @Column(name = "amount") + private BigDecimal amount; + + @Column(name = "currency") + private String currency; + + @Column(name = "group_code") + private String groupCode; + + @Column(name = "status") + private String status; + + @Column(name = "expiry_date") + private Date expiryDate; + + @Column(name = "created_date") + private LocalDateTime createdDate; + + @Column(name = "activated_date") + private LocalDateTime activatedDate; + + @Column(name = "payee_functional_id") + private String payeeFunctionalId; + + @Column(name = "batch_id", unique = true, nullable = false) + private String batchId; + + @Column(name = "instruction_id", unique = true) + private String instructionId; + + @Column(name = "request_id", unique = true, nullable = false) + private String requestId; + @Column(name = "registering_institution_id", nullable = false) + private String registeringInstitutionId; + + public Voucher(String serialNo, String voucherNo, BigDecimal amount, String currency, String groupCode, String status, Date expiryDate, + LocalDateTime createdDate, LocalDateTime activatedDate, String payeeFunctionalId, String batchId, String instructionId, + String requestId, String registeringInstitutionId) { + this.serialNo = serialNo; + this.voucherNo = voucherNo; + this.amount = amount; + this.currency = currency; + this.groupCode = groupCode; + this.status = status; + this.expiryDate = expiryDate; + this.createdDate = createdDate; + this.activatedDate = activatedDate; + this.payeeFunctionalId = payeeFunctionalId; + this.batchId = batchId; + this.instructionId = instructionId; + this.requestId = requestId; + this.registeringInstitutionId = registeringInstitutionId; + } + + public Voucher() { + + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getSerialNo() { + return serialNo; + } + + public void setSerialNo(String serialNo) { + this.serialNo = serialNo; + } + + public String getVoucherNo() { + return voucherNo; + } + + public void setVoucherNo(String voucherNo) { + this.voucherNo = voucherNo; + } + + public BigDecimal getAmount() { + return amount; + } + + public void setAmount(BigDecimal amount) { + this.amount = amount; + } + + public String getCurrency() { + return currency; + } + + public void setCurrency(String currency) { + this.currency = currency; + } + + public String getGroupCode() { + return groupCode; + } + + public void setGroupCode(String groupCode) { + this.groupCode = groupCode; + } + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } + + public Date getExpiryDate() { + return expiryDate; + } + + public void setExpiryDate(Date expiryDate) { + this.expiryDate = expiryDate; + } + + public LocalDateTime getCreatedDate() { + return createdDate; + } + + public void setCreatedDate(LocalDateTime createdDate) { + this.createdDate = createdDate; + } + + public LocalDateTime getActivatedDate() { + return activatedDate; + } + + public void setActivatedDate(LocalDateTime activatedDate) { + this.activatedDate = activatedDate; + } + + public String getPayeeFunctionalId() { + return payeeFunctionalId; + } + + public void setPayeeFunctionalId(String payeeFunctionalId) { + this.payeeFunctionalId = payeeFunctionalId; + } + + public String getBatchId() { + return batchId; + } + + public void setBatchId(String batchId) { + this.batchId = batchId; + } + + public String getInstructionId() { + return instructionId; + } + + public void setInstructionId(String instructionId) { + this.instructionId = instructionId; + } + + public String getRequestId() { + return requestId; + } + + public void setRequestId(String requestId) { + this.requestId = requestId; + } + + public String getRegisteringInstitutionId() { + return registeringInstitutionId; + } + + public void setRegisteringInstitutionId(String registeringInstitutionId) { + this.registeringInstitutionId = registeringInstitutionId; + } +} diff --git a/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/exception/ConflictingDataException.java b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/exception/ConflictingDataException.java new file mode 100644 index 000000000..2bfc9cecf --- /dev/null +++ b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/exception/ConflictingDataException.java @@ -0,0 +1,21 @@ +package org.mifos.pheevouchermanagementsystem.exception; + +public class ConflictingDataException extends RuntimeException { + + private final String conflictingFieldName; + private final String conflictingFieldValue; + + public ConflictingDataException(String fieldName, String fieldValue) { + super(String.format("Conflicting data detected for field: %s, value: %s", fieldName, fieldValue)); + this.conflictingFieldName = fieldName; + this.conflictingFieldValue = fieldValue; + } + + public String getConflictingFieldName() { + return conflictingFieldName; + } + + public String getConflictingFieldValue() { + return conflictingFieldValue; + } +} diff --git a/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/exception/InstructionIdException.java b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/exception/InstructionIdException.java new file mode 100644 index 000000000..6e4bf4172 --- /dev/null +++ b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/exception/InstructionIdException.java @@ -0,0 +1,15 @@ +package org.mifos.pheevouchermanagementsystem.exception; + +import java.text.MessageFormat; + +public class InstructionIdException extends RuntimeException { + + public InstructionIdException(String message) { + super(message); + } + + public static InstructionIdException instructionIdNotFound(final String instructionId) { + String stringWithPlaceHolder = "Instruction ID with {0} already exist!"; + return new InstructionIdException(MessageFormat.format(stringWithPlaceHolder, instructionId)); + } +} diff --git a/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/exception/VoucherNotFoundException.java b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/exception/VoucherNotFoundException.java new file mode 100644 index 000000000..74289bf3b --- /dev/null +++ b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/exception/VoucherNotFoundException.java @@ -0,0 +1,15 @@ +package org.mifos.pheevouchermanagementsystem.exception; + +import java.text.MessageFormat; + +public class VoucherNotFoundException extends RuntimeException { + + public VoucherNotFoundException(String message) { + super(message); + } + + public static InstructionIdException voucherNotFound(final String voucherSerialNo) { + String stringWithPlaceHolder = "Voucher with serial/voucher number {0} not found!"; + return new InstructionIdException(MessageFormat.format(stringWithPlaceHolder, voucherSerialNo)); + } +} diff --git a/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/exception/ZeebeClientStatusException.java b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/exception/ZeebeClientStatusException.java new file mode 100644 index 000000000..ec891c743 --- /dev/null +++ b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/exception/ZeebeClientStatusException.java @@ -0,0 +1,15 @@ +package org.mifos.pheevouchermanagementsystem.exception; + +public class ZeebeClientStatusException extends RuntimeException { + + private final String id; + + public String getId() { + return id; + } + + public ZeebeClientStatusException(String message, String id, Throwable cause) { + super(message); + this.id = id; + } +} diff --git a/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/exceptionmapper/GlobalExceptionMapper.java b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/exceptionmapper/GlobalExceptionMapper.java new file mode 100644 index 000000000..0ef8fc978 --- /dev/null +++ b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/exceptionmapper/GlobalExceptionMapper.java @@ -0,0 +1,58 @@ +package org.mifos.pheevouchermanagementsystem.exceptionmapper; + +import static org.mifos.pheevouchermanagementsystem.util.VoucherManagementEnum.CONFLICT_OCCURRED; +import static org.mifos.pheevouchermanagementsystem.util.VoucherManagementEnum.FAILED_RESPONSE; +import static org.mifos.pheevouchermanagementsystem.util.VoucherManagementEnum.PROCESS_DEFINITION_NOT_FOUND; + +import java.util.HashMap; +import java.util.Map; +import lombok.extern.slf4j.Slf4j; +import org.mifos.pheevouchermanagementsystem.data.ConflictResponseDTO; +import org.mifos.pheevouchermanagementsystem.data.ResponseDTO; +import org.mifos.pheevouchermanagementsystem.exception.ConflictingDataException; +import org.mifos.pheevouchermanagementsystem.exception.InstructionIdException; +import org.mifos.pheevouchermanagementsystem.exception.ZeebeClientStatusException; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.RestControllerAdvice; + +@RestControllerAdvice +@Slf4j +public class GlobalExceptionMapper { + + @ExceptionHandler(ZeebeClientStatusException.class) + public ResponseEntity handleClientStatusException(ZeebeClientStatusException ex) { + ResponseDTO responseDTO = new ResponseDTO(PROCESS_DEFINITION_NOT_FOUND.getValue(), PROCESS_DEFINITION_NOT_FOUND.getMessage(), + ex.getId()); + return ResponseEntity.status(HttpStatus.PRECONDITION_FAILED).body(responseDTO); + } + + @ExceptionHandler(InstructionIdException.class) + public ResponseEntity handleInstructionIdException(InstructionIdException ex) { + ConflictResponseDTO responseDTO = new ConflictResponseDTO(CONFLICT_OCCURRED.getValue(), CONFLICT_OCCURRED.getMessage(), + "instructionID", ex.getMessage()); + return ResponseEntity.status(HttpStatus.CONFLICT).body(responseDTO); + } + + @ExceptionHandler(ConflictingDataException.class) + public ResponseEntity handleInstructionIdException(ConflictingDataException ex) { + ConflictResponseDTO dto = new ConflictResponseDTO(CONFLICT_OCCURRED.getValue(), CONFLICT_OCCURRED.getMessage(), + ex.getConflictingFieldName(), ex.getConflictingFieldValue()); + return (ResponseEntity) ResponseEntity.status(HttpStatus.CONFLICT).body(dto); + } + + @ExceptionHandler(NullPointerException.class) + public ResponseEntity handleNullPointerException(NullPointerException ex) { + Map responseBody = new HashMap<>(); + log.error("An error occurred : {}", ex.getMessage()); + responseBody.put("failureReason", "An error occurred, contact the system admin !!"); + return (ResponseEntity) ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(responseBody); + } + + @ExceptionHandler(Exception.class) + public ResponseEntity handleException(Exception ex) { + ResponseDTO responseDTO = new ResponseDTO(FAILED_RESPONSE.getValue(), FAILED_RESPONSE.getMessage(), null); + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(responseDTO); + } +} diff --git a/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/interceptor/ValidatorInterceptor.java b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/interceptor/ValidatorInterceptor.java new file mode 100644 index 000000000..90847a8dd --- /dev/null +++ b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/interceptor/ValidatorInterceptor.java @@ -0,0 +1,72 @@ +package org.mifos.pheevouchermanagementsystem.interceptor; + +import com.fasterxml.jackson.databind.ObjectMapper; +import java.lang.reflect.Method; +import java.util.Arrays; +import java.util.Set; +import java.util.stream.Collectors; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import lombok.extern.slf4j.Slf4j; +import org.mifos.pheevouchermanagementsystem.service.ValidateHeaders; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.http.HttpStatus; +import org.springframework.stereotype.Component; +import org.springframework.web.method.HandlerMethod; +import org.springframework.web.servlet.HandlerInterceptor; + +@Slf4j +@Component +public class ValidatorInterceptor implements HandlerInterceptor { + + @Autowired + private ApplicationContext applicationContext; + + @Override + public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { + log.debug("At interceptor"); + if (handler instanceof HandlerMethod) { + HandlerMethod handlerMethod = (HandlerMethod) handler; + Method method = handlerMethod.getMethod(); + if (method.isAnnotationPresent(ValidateHeaders.class)) { + ValidateHeaders validateHeaders = method.getAnnotation(ValidateHeaders.class); + Set headersSet = extractRequiredHeaders(validateHeaders); + + Object validatorInstance = getValidatorInstance(validateHeaders); + + Object methodResponse = invokeValidationMethod(validateHeaders, validatorInstance, headersSet, request); + + if (methodResponse != null) { + handleValidationFailure(response, methodResponse); + return false; + } + } + } + return true; + } + + private Set extractRequiredHeaders(ValidateHeaders validateHeaders) { + return Arrays.stream(validateHeaders.requiredHeaders()).map(String::toLowerCase).collect(Collectors.toSet()); + } + + private Object getValidatorInstance(ValidateHeaders validateHeaders) { + return applicationContext.getBean(validateHeaders.validatorClass()); + } + + private Object invokeValidationMethod(ValidateHeaders validateHeaders, Object validatorInstance, Set headersSet, + HttpServletRequest request) throws Exception { + Method validationMethod = validatorInstance.getClass().getDeclaredMethod(validateHeaders.validationFunction(), Set.class, + HttpServletRequest.class); + Object[] parameters = { headersSet, request }; + return validationMethod.invoke(validatorInstance, parameters); + } + + private void handleValidationFailure(HttpServletResponse response, Object methodResponse) throws Exception { + ObjectMapper objectMapper = new ObjectMapper(); + String jsonResponse = objectMapper.writeValueAsString(methodResponse); + response.setHeader("Content-Type", "application/json"); + response.setStatus(HttpStatus.BAD_REQUEST.value()); + response.getWriter().write(jsonResponse); + } +} \ No newline at end of file diff --git a/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/interceptor/config/WebMvcConfig.java b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/interceptor/config/WebMvcConfig.java new file mode 100644 index 000000000..73b5c433a --- /dev/null +++ b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/interceptor/config/WebMvcConfig.java @@ -0,0 +1,21 @@ +package org.mifos.pheevouchermanagementsystem.interceptor.config; + +import org.mifos.pheevouchermanagementsystem.interceptor.ValidatorInterceptor; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Primary; +import org.springframework.stereotype.Component; +import org.springframework.web.servlet.config.annotation.InterceptorRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +@Component +@Primary +public class WebMvcConfig implements WebMvcConfigurer { + + @Autowired + ValidatorInterceptor validatorInterceptor; + + @Override + public void addInterceptors(InterceptorRegistry registry) { + registry.addInterceptor(validatorInterceptor).addPathPatterns("/vouchers"); + } +} diff --git a/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/repository/ErrorTrackingRepository.java b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/repository/ErrorTrackingRepository.java new file mode 100644 index 000000000..2ef535132 --- /dev/null +++ b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/repository/ErrorTrackingRepository.java @@ -0,0 +1,7 @@ +package org.mifos.pheevouchermanagementsystem.repository; + +import org.mifos.pheevouchermanagementsystem.domain.ErrorTracking; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; + +public interface ErrorTrackingRepository extends JpaRepository, JpaSpecificationExecutor {} diff --git a/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/repository/VoucherRepository.java b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/repository/VoucherRepository.java new file mode 100644 index 000000000..105c94493 --- /dev/null +++ b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/repository/VoucherRepository.java @@ -0,0 +1,27 @@ +package org.mifos.pheevouchermanagementsystem.repository; + +import java.util.Optional; +import org.mifos.pheevouchermanagementsystem.domain.Voucher; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; + +public interface VoucherRepository extends JpaRepository, JpaSpecificationExecutor { + + Boolean existsByRequestId(String requestId); + + Boolean existsByBatchId(String batchId); + + Boolean existsByInstructionId(String instructionId); + + Boolean existsBySerialNo(String serialNo); + + Boolean existsByVoucherNo(String voucherNo); + + Optional findBySerialNo(String serialNo); + + Optional findByVoucherNo(String voucherNo); + + Page findByRegisteringInstitutionId(String registeringInstitutionId, Pageable pageable); +} diff --git a/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/service/ActivateVoucherService.java b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/service/ActivateVoucherService.java new file mode 100644 index 000000000..8d810f80f --- /dev/null +++ b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/service/ActivateVoucherService.java @@ -0,0 +1,130 @@ +package org.mifos.pheevouchermanagementsystem.service; + +import static org.mifos.pheevouchermanagementsystem.util.VoucherStatusEnum.ACTIVE; +import static org.mifos.pheevouchermanagementsystem.util.VoucherStatusEnum.CANCELLED; +import static org.mifos.pheevouchermanagementsystem.util.VoucherStatusEnum.EXPIRED; +import static org.mifos.pheevouchermanagementsystem.util.VoucherStatusEnum.UTILIZED; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.util.ArrayList; +import java.util.List; +import org.mifos.pheevouchermanagementsystem.data.FailedCaseDTO; +import org.mifos.pheevouchermanagementsystem.data.RequestDTO; +import org.mifos.pheevouchermanagementsystem.data.VoucherInstruction; +import org.mifos.pheevouchermanagementsystem.data.VoucherLifecycleCallbackResponseDTO; +import org.mifos.pheevouchermanagementsystem.domain.Voucher; +import org.mifos.pheevouchermanagementsystem.exception.VoucherNotFoundException; +import org.mifos.pheevouchermanagementsystem.repository.ErrorTrackingRepository; +import org.mifos.pheevouchermanagementsystem.repository.VoucherRepository; +import org.mifos.pheevouchermanagementsystem.util.UniqueIDGenerator; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +public class ActivateVoucherService { + + private final VoucherRepository voucherRepository; + private final ErrorTrackingRepository errorTrackingRepository; + private final SendCallbackService sendCallbackService; + private final ObjectMapper objectMapper; + @Value("${expiry_time}") + private Integer expiryTime; + + private static final Logger logger = LoggerFactory.getLogger(ActivateVoucherService.class); + + @Autowired + public ActivateVoucherService(VoucherRepository voucherRepository, ErrorTrackingRepository errorTrackingRepository, + SendCallbackService sendCallbackService, ObjectMapper objectMapper) { + this.voucherRepository = voucherRepository; + this.errorTrackingRepository = errorTrackingRepository; + this.sendCallbackService = sendCallbackService; + this.objectMapper = objectMapper; + } + + @Async("asyncExecutor") + public void activateVouchers(RequestDTO request, String callbackURL, String registeringInstitutionId) { + List voucherInstructionList = request.getVoucherInstructions(); + List failedCaseList = new ArrayList<>(); + validateVouchers(voucherInstructionList, request, failedCaseList, registeringInstitutionId); + try { + sendCallbackService.sendCallback( + objectMapper.writeValueAsString(new VoucherLifecycleCallbackResponseDTO(UniqueIDGenerator.generateUniqueNumber(12), + request.getRequestID(), failedCaseList.size(), failedCaseList)), + callbackURL); + } catch (JsonProcessingException e) { + throw new RuntimeException(e); + } + + } + + public void validateVouchers(List voucherInstructionList, RequestDTO request, List failedCaseList, + String registeringInstitutionId) { + voucherInstructionList.stream().forEach(voucherInstruction -> { + String requestID = request.getRequestID(); + Boolean voucherValidation = validateVoucher(voucherInstruction, request); + if (voucherValidation) { + Voucher voucher = voucherRepository.findBySerialNo(voucherInstruction.getSerialNumber()) + .orElseThrow(() -> VoucherNotFoundException.voucherNotFound(voucherInstruction.getSerialNumber())); + if (validateRegisteringInstitutionId(voucher, registeringInstitutionId)) { + activateVouchers(voucherInstruction, failedCaseList, request); + } else { + FailedCaseDTO failedCase = new FailedCaseDTO(voucherInstruction.getSerialNumber(), + "The voucher provided in the request does not correspond to the same registering ID."); + failedCaseList.add(failedCase); + } + } else { + FailedCaseDTO failedCase = new FailedCaseDTO(voucherInstruction.getSerialNumber(), + "Voucher with serial number does not exist."); + failedCaseList.add(failedCase); + } + }); + } + + public Boolean validateVoucher(VoucherInstruction voucherInstruction, RequestDTO request) { + if (voucherRepository.existsBySerialNo(voucherInstruction.getSerialNumber())) { + Voucher voucher = voucherRepository.findBySerialNo(voucherInstruction.getSerialNumber()) + .orElseThrow(() -> VoucherNotFoundException.voucherNotFound(voucherInstruction.getSerialNumber())); + return !voucher.getStatus().equals(EXPIRED.getValue()) && !voucher.getStatus().equals(UTILIZED.getValue()) + && !voucher.getStatus().equals(CANCELLED.getValue()); + } + return false; + } + + @Transactional + public void activateVouchers(VoucherInstruction voucherInstruction, List failedCaseList, RequestDTO request) { + try { + Voucher voucher = voucherRepository.findBySerialNo(voucherInstruction.getSerialNumber()) + .orElseThrow(() -> VoucherNotFoundException.voucherNotFound(voucherInstruction.getSerialNumber())); + if (validateVoucherStatus(voucher, failedCaseList)) { + voucher.setStatus(ACTIVE.getValue()); + LocalDate updatedDate = LocalDate.now(ZoneId.systemDefault()).plusDays(expiryTime); + voucher.setActivatedDate(LocalDateTime.now(ZoneId.systemDefault())); + voucher.setExpiryDate(java.sql.Date.valueOf(updatedDate)); + voucherRepository.save(voucher); + } + } catch (RuntimeException e) { + logger.error(e.getMessage()); + } + } + + public Boolean validateVoucherStatus(Voucher voucher, List failedCaseList) { + if (voucher.getStatus().equals(ACTIVE.getValue())) { + failedCaseList.add(new FailedCaseDTO(voucher.getSerialNo(), "Voucher Already Active.")); + return false; + } + return true; + } + + public static Boolean validateRegisteringInstitutionId(Voucher voucher, String registeringInstitutionId) { + return voucher.getRegisteringInstitutionId().equals(registeringInstitutionId); + } +} diff --git a/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/service/CreateVoucherService.java b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/service/CreateVoucherService.java new file mode 100644 index 000000000..aa3ffeac9 --- /dev/null +++ b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/service/CreateVoucherService.java @@ -0,0 +1,175 @@ +package org.mifos.pheevouchermanagementsystem.service; + +import static org.mifos.pheevouchermanagementsystem.util.UniqueIDGenerator.generateUniqueNumber; +import static org.mifos.pheevouchermanagementsystem.util.VoucherStatusEnum.INACTIVE; + +import com.fasterxml.jackson.databind.ObjectMapper; +import java.math.BigDecimal; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.security.spec.InvalidKeySpecException; +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import javax.crypto.BadPaddingException; +import javax.crypto.IllegalBlockSizeException; +import javax.crypto.NoSuchPaddingException; +import javax.transaction.Transactional; +import org.mifos.connector.common.channel.dto.PhErrorDTO; +import org.mifos.connector.common.util.SecurityUtil; +import org.mifos.pheevouchermanagementsystem.data.RequestDTO; +import org.mifos.pheevouchermanagementsystem.data.SuccessfulVouchers; +import org.mifos.pheevouchermanagementsystem.data.VoucherInstruction; +import org.mifos.pheevouchermanagementsystem.data.VoucherValidator; +import org.mifos.pheevouchermanagementsystem.domain.ErrorTracking; +import org.mifos.pheevouchermanagementsystem.domain.Voucher; +import org.mifos.pheevouchermanagementsystem.exception.ConflictingDataException; +import org.mifos.pheevouchermanagementsystem.exception.InstructionIdException; +import org.mifos.pheevouchermanagementsystem.repository.ErrorTrackingRepository; +import org.mifos.pheevouchermanagementsystem.repository.VoucherRepository; +import org.mifos.pheevouchermanagementsystem.util.VouchersDTOConstant; +import org.mifos.pheevouchermanagementsystem.zeebe.ZeebeProcessStarter; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +@Service +public class CreateVoucherService { + + private final VoucherRepository voucherRepository; + private final ErrorTrackingRepository errorTrackingRepository; + private final SendCallbackService sendCallbackService; + private final ObjectMapper objectMapper; + private final ZeebeProcessStarter zeebeProcessStarter; + private final VoucherValidator voucherValidator; + + private static final Logger logger = LoggerFactory.getLogger(CreateVoucherService.class); + + @Autowired + private EncryptionService encryptionService; + + @Autowired + public CreateVoucherService(VoucherRepository voucherRepository, ErrorTrackingRepository errorTrackingRepository, + SendCallbackService sendCallbackService, ObjectMapper objectMapper, ZeebeProcessStarter zeebeProcessStarter, + VoucherValidator voucherValidator) { + this.voucherRepository = voucherRepository; + this.errorTrackingRepository = errorTrackingRepository; + this.sendCallbackService = sendCallbackService; + this.objectMapper = objectMapper; + this.zeebeProcessStarter = zeebeProcessStarter; + this.voucherValidator = voucherValidator; + } + + public PhErrorDTO validateAndCreateVoucher(RequestDTO request, String callbackURL, String registeringInstitutionId) { + PhErrorDTO phErrorDTO = voucherValidator.validateCreateVoucher(request); + if (phErrorDTO == null) { + createVouchers(request, callbackURL, registeringInstitutionId); + } + + return phErrorDTO; + } + + public void createVouchers(RequestDTO request, String callbackURL, String registeringInstitutionId) { + try { + validateRequestID(request.getRequestID()); + validateBatchID(request.getBatchID()); + } catch (ConflictingDataException e) { + logger.error(e.getMessage()); + throw e; + } + List voucherInstructionList = request.getVoucherInstructions(); + List errorTrackingsList = new ArrayList<>(); + List successfulVouchers = new ArrayList<>(); + validateAndSaveVoucher(voucherInstructionList, successfulVouchers, errorTrackingsList, request, registeringInstitutionId, + callbackURL); + /* + * try { sendCallbackService.sendCallback(objectMapper.writeValueAsString(new + * CallbackRequestDTO(request.getRequestID(), request.getBatchID(), successfulVouchers)), callbackURL); } catch + * (JsonProcessingException e) { logger.error(e.getMessage()); } + */ + } + + public void validateRequestID(String requestID) { + if (voucherRepository.existsByRequestId(requestID)) { + throw new ConflictingDataException(VouchersDTOConstant.requestID, requestID); + } + } + + public void validateBatchID(String batchID) { + if (voucherRepository.existsByBatchId(batchID)) { + throw new ConflictingDataException(VouchersDTOConstant.batchID, batchID); + } + } + + public void validateAndSaveVoucher(List voucherInstructionList, List successfulVouchers, + List errorTrackingList, RequestDTO request, String registeringInstitutionId, String callbackURL) { + final BigDecimal[] totalAmount = { BigDecimal.valueOf(0) }; + String currency = voucherInstructionList.get(0).getCurrency(); + String requestID = request.getRequestID(); + try { + voucherInstructionList.stream().forEach(voucherInstruction -> { + + Boolean instructionValidation = validateInstruction(voucherInstruction, request, successfulVouchers); + if (!instructionValidation) { + totalAmount[0] = totalAmount[0].add(voucherInstruction.getAmount()); + // addVouchers(voucherInstruction, successfulVouchers, errorTrackingList, request, + // registeringInstitutionId); + } else { + throw new InstructionIdException(voucherInstruction.getInstructionID()); + } + }); + batchAuthorization(totalAmount[0], currency, request.getBatchID(), voucherInstructionList, requestID, registeringInstitutionId, + callbackURL); + } catch (InstructionIdException e) { + logger.error("Instruction Id already exist : {}", e.getMessage()); + throw e; + } + } + + public void batchAuthorization(BigDecimal amount, String currency, String batchId, List voucherInstructionList, + String requestId, String registeringInstitutionId, String callbackURL) { + Map variables = new HashMap<>(); + variables.put("totalAmount", amount); + variables.put("currency", currency); + variables.put("batchId", batchId); + variables.put("requestId", requestId); + variables.put("instructionList", voucherInstructionList); + variables.put("registeringInstitutionId", registeringInstitutionId); + variables.put("callbackURL", callbackURL); + zeebeProcessStarter.startZeebeWorkflow("voucher_budget_check", generateUniqueNumber(20), variables); + } + + public Boolean validateInstruction(VoucherInstruction voucherInstruction, RequestDTO request, + List successfulVouchers) { + return voucherRepository.existsByInstructionId(voucherInstruction.getInstructionID()); + } + + @Transactional + public void addVouchers(VoucherInstruction voucherInstruction, List successfulVouchers, + List errorTrackingList, String registeringInstitutionId, String batchId, String requestId) { + String serialNumber = generateUniqueNumber(14); + String voucherNumber = generateUniqueNumber(18); + Voucher voucher = new Voucher(serialNumber, SecurityUtil.hash(voucherNumber), voucherInstruction.getAmount(), + voucherInstruction.getCurrency(), voucherInstruction.getGroupCode(), INACTIVE.getValue(), null, LocalDateTime.now(), null, + voucherInstruction.getPayeeFunctionalID(), batchId, voucherInstruction.getInstructionID(), requestId, + registeringInstitutionId); + try { + voucherRepository.save(voucher); + successfulVouchers.add(new SuccessfulVouchers(voucherInstruction.getInstructionID(), voucherInstruction.getCurrency(), + voucherInstruction.getAmount(), voucherInstruction.getNarration(), encryptionService.encrypt(voucherNumber), + serialNumber)); + } catch (RuntimeException | NoSuchPaddingException | IllegalBlockSizeException | NoSuchAlgorithmException | BadPaddingException + | InvalidKeySpecException | InvalidKeyException exception) { + ErrorTracking error = new ErrorTracking(requestId, voucherInstruction.getInstructionID(), exception.getMessage()); + errorTrackingList.add(error); + try { + errorTrackingRepository.save(error); + } catch (RuntimeException e) { + logger.error(e.getMessage()); + } + } + } +} diff --git a/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/service/EncryptionService.java b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/service/EncryptionService.java new file mode 100644 index 000000000..9bc82138c --- /dev/null +++ b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/service/EncryptionService.java @@ -0,0 +1,32 @@ +package org.mifos.pheevouchermanagementsystem.service; + +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.security.spec.InvalidKeySpecException; +import javax.crypto.BadPaddingException; +import javax.crypto.IllegalBlockSizeException; +import javax.crypto.NoSuchPaddingException; +import org.mifos.connector.common.util.SecurityUtil; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; + +@Service +public class EncryptionService { + + @Value("${rsa-key.private}") + private String privateKey; + + @Value("${rsa-key.public}") + private String publicKey; + + public String encrypt(String data) throws NoSuchPaddingException, IllegalBlockSizeException, NoSuchAlgorithmException, + BadPaddingException, InvalidKeySpecException, InvalidKeyException { + return SecurityUtil.encryptUsingPrivateKey(data, privateKey); + } + + public String decrypt(String encryptedData) throws NoSuchPaddingException, IllegalBlockSizeException, NoSuchAlgorithmException, + BadPaddingException, InvalidKeySpecException, InvalidKeyException { + return SecurityUtil.decryptUsingPublicKey(encryptedData, publicKey); + } + +} diff --git a/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/service/FetchVoucherService.java b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/service/FetchVoucherService.java new file mode 100644 index 000000000..07212c7af --- /dev/null +++ b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/service/FetchVoucherService.java @@ -0,0 +1,37 @@ +package org.mifos.pheevouchermanagementsystem.service; + +import org.mifos.pheevouchermanagementsystem.data.FetchVoucherResponseDTO; +import org.mifos.pheevouchermanagementsystem.domain.Voucher; +import org.mifos.pheevouchermanagementsystem.exception.VoucherNotFoundException; +import org.mifos.pheevouchermanagementsystem.repository.VoucherRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; +import org.springframework.stereotype.Service; + +@Service +public class FetchVoucherService { + + private final VoucherRepository voucherRepository; + + @Autowired + public FetchVoucherService(VoucherRepository voucherRepository) { + this.voucherRepository = voucherRepository; + } + + public FetchVoucherResponseDTO fetchVoucher(String serialNumber, String registeringInstitutionId) { + Voucher voucher = voucherRepository.findBySerialNo(serialNumber) + .orElseThrow(() -> VoucherNotFoundException.voucherNotFound(serialNumber)); + return new FetchVoucherResponseDTO(serialNumber, voucher.getCreatedDate(), registeringInstitutionId, voucher.getStatus(), + voucher.getPayeeFunctionalId()); + } + + public Page fetchAllVouchers(String registeringInstitutionId, Integer page, Integer size) { + Pageable pageRequest = PageRequest.of(page, size); + Page voucherPage = voucherRepository.findAll(pageRequest); + + return voucherPage.map(voucher -> new FetchVoucherResponseDTO(voucher.getSerialNo(), voucher.getCreatedDate(), + registeringInstitutionId, voucher.getStatus(), voucher.getPayeeFunctionalId())); + } +} diff --git a/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/service/RedeemVoucherService.java b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/service/RedeemVoucherService.java new file mode 100644 index 000000000..86782e4d8 --- /dev/null +++ b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/service/RedeemVoucherService.java @@ -0,0 +1,138 @@ +package org.mifos.pheevouchermanagementsystem.service; + +import static org.mifos.pheevouchermanagementsystem.util.RedemptionStatusEnum.FAILURE; +import static org.mifos.pheevouchermanagementsystem.util.RedemptionStatusEnum.SUCCESS; +import static org.mifos.pheevouchermanagementsystem.util.UniqueIDGenerator.generateUniqueNumber; +import static org.mifos.pheevouchermanagementsystem.util.VoucherStatusEnum.ACTIVE; +import static org.mifos.pheevouchermanagementsystem.util.VoucherStatusEnum.UTILIZED; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.security.spec.InvalidKeySpecException; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.util.HashMap; +import java.util.Map; +import javax.crypto.BadPaddingException; +import javax.crypto.IllegalBlockSizeException; +import javax.crypto.NoSuchPaddingException; +import org.mifos.connector.common.util.SecurityUtil; +import org.mifos.pheevouchermanagementsystem.data.RedeemVoucherRequestDTO; +import org.mifos.pheevouchermanagementsystem.data.RedeemVoucherResponseDTO; +import org.mifos.pheevouchermanagementsystem.domain.Voucher; +import org.mifos.pheevouchermanagementsystem.exception.VoucherNotFoundException; +import org.mifos.pheevouchermanagementsystem.repository.VoucherRepository; +import org.mifos.pheevouchermanagementsystem.zeebe.ZeebeProcessStarter; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Service; + +@Service +public class RedeemVoucherService { + + private final VoucherRepository voucherRepository; + private final ObjectMapper objectMapper; + private static final Logger logger = LoggerFactory.getLogger(RedeemVoucherService.class); + @Autowired + ZeebeProcessStarter zeebeProcessStarter; + + @Value("${paymentAdvice}") + Boolean paymentAdvice; + + @Autowired + EncryptionService encryptionService; + @Autowired + SendCallbackService sendCallbackService; + + @Autowired + public RedeemVoucherService(VoucherRepository voucherRepository, ObjectMapper objectMapper) { + this.voucherRepository = voucherRepository; + this.objectMapper = objectMapper; + } + + public RedeemVoucherResponseDTO redeemVoucher(RedeemVoucherRequestDTO redeemVoucherRequestDTO, String registeringInstitutionId) { + String transactionId = generateUniqueNumber(10); + Voucher voucher = null; + try { + // find voucher by voucher no / secret code + /* + * String encryptedVoucher = "this is hidden voucher"; String voucherNum = decrypt(encryptedVoucher, + * publicKey) find in db: findBy(hash(voucherNum)) + */ + String voucherNumber = encryptionService.decrypt(redeemVoucherRequestDTO.getVoucherSecretNumber()); + voucher = voucherRepository.findByVoucherNo(SecurityUtil.hash(voucherNumber)) + .orElseThrow(() -> VoucherNotFoundException.voucherNotFound(redeemVoucherRequestDTO.getVoucherSecretNumber())); + // Boolean validate = validateVoucher(voucher); + if (voucher.getStatus().equals(ACTIVE.getValue()) + && voucher.getExpiryDate().toLocalDate().isAfter(LocalDate.now(ZoneId.systemDefault())) + && voucher.getVoucherNo().equals(SecurityUtil.hash(voucherNumber)) + && voucher.getRegisteringInstitutionId().equals(registeringInstitutionId)) { + voucher.setStatus(UTILIZED.getValue()); + voucherRepository.save(voucher); + + } else { + return new RedeemVoucherResponseDTO(FAILURE.getValue(), "Voucher Details Invalid!", + redeemVoucherRequestDTO.getVoucherSecretNumber(), voucher.getAmount().toString(), + LocalDateTime.now(ZoneId.systemDefault()).toString(), transactionId); + } + } catch (RuntimeException e) { + logger.error(e.getMessage()); + return new RedeemVoucherResponseDTO(FAILURE.getValue(), "Voucher Not Found!", redeemVoucherRequestDTO.getVoucherSecretNumber(), + "", LocalDateTime.now(ZoneId.systemDefault()).toString(), transactionId); // sendCallbackService.sendCallback("Requested + // resource not found!"); + } catch (NoSuchPaddingException | IllegalBlockSizeException | NoSuchAlgorithmException | BadPaddingException + | InvalidKeySpecException | InvalidKeyException e) { + logger.error(e.getMessage()); + return new RedeemVoucherResponseDTO(FAILURE.getValue(), "Voucher number invalid!", + redeemVoucherRequestDTO.getVoucherSecretNumber(), "", LocalDateTime.now(ZoneId.systemDefault()).toString(), + transactionId); + } + return new RedeemVoucherResponseDTO(SUCCESS.getValue(), "Voucher redemption successful!", + redeemVoucherRequestDTO.getVoucherSecretNumber(), voucher.getAmount().toString(), + LocalDateTime.now(ZoneId.systemDefault()).toString(), transactionId); + } + + @Async("asyncExecutor") + public void redeemAndPay(RedeemVoucherRequestDTO redeemVoucherRequestDTO, String callbackURL, String registeringInstitutionId) { + try { + String voucherNumber = encryptionService.decrypt(redeemVoucherRequestDTO.getVoucherSecretNumber()); + Voucher voucher = voucherRepository.findByVoucherNo(SecurityUtil.hash(voucherNumber)) + .orElseThrow(() -> VoucherNotFoundException.voucherNotFound(redeemVoucherRequestDTO.getVoucherSecretNumber())); + // Boolean validate = validateVoucher(voucher); + if (voucher.getStatus().equals(ACTIVE.getValue()) + && voucher.getExpiryDate().toLocalDate().isAfter(LocalDate.now(ZoneId.systemDefault())) + && voucher.getVoucherNo().equals(SecurityUtil.hash(voucherNumber)) + && voucher.getRegisteringInstitutionId().equals(registeringInstitutionId)) { + voucher.setStatus(UTILIZED.getValue()); + voucherRepository.save(voucher); + Map extraVariables = new HashMap<>(); + extraVariables.put("payeeIdentity", voucher.getPayeeFunctionalId()); + // extraVariables.put("paymentModality", redeemVoucherRequestDTO.getPaymentModality()); + extraVariables.put("registeringInstitutionId", registeringInstitutionId); + extraVariables.put("callbackURL", callbackURL); + extraVariables.put("amount", voucher.getAmount()); + extraVariables.put("currency", voucher.getCurrency()); + extraVariables.put("voucherSerialNumber", redeemVoucherRequestDTO.getVoucherSecretNumber()); + extraVariables.put("paymentAdvice", paymentAdvice); + zeebeProcessStarter.startZeebeWorkflow("redeem_and_pay_voucher", null, extraVariables); + } else { + RedeemVoucherResponseDTO redeemVoucherResponseDTO = new RedeemVoucherResponseDTO(FAILURE.getValue(), + "Voucher number Utilized!", redeemVoucherRequestDTO.getVoucherSecretNumber(), "", + LocalDateTime.now(ZoneId.systemDefault()).toString(), null); + + ObjectMapper objectMapper = new ObjectMapper(); + String body = objectMapper.writeValueAsString(redeemVoucherResponseDTO); + sendCallbackService.sendCallback(body, callbackURL); + } + } catch (RuntimeException | NoSuchPaddingException | IllegalBlockSizeException | NoSuchAlgorithmException | BadPaddingException + | InvalidKeySpecException | InvalidKeyException | JsonProcessingException e) { + logger.error(e.getMessage()); + } + } +} diff --git a/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/service/SendCallbackService.java b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/service/SendCallbackService.java new file mode 100644 index 000000000..bfdde0e60 --- /dev/null +++ b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/service/SendCallbackService.java @@ -0,0 +1,29 @@ +package org.mifos.pheevouchermanagementsystem.service; + +import io.restassured.RestAssured; +import io.restassured.builder.RequestSpecBuilder; +import io.restassured.http.ContentType; +import io.restassured.response.Response; +import io.restassured.specification.RequestSpecification; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Service; + +@Service +public class SendCallbackService { + + private static final Logger logger = LoggerFactory.getLogger(SendCallbackService.class); + + public void sendCallback(String body, String callbackURL) { + logger.info(body); + logger.info(callbackURL); + RequestSpecification requestSpec = new RequestSpecBuilder().build(); + requestSpec.relaxedHTTPSValidation(); + Response response = RestAssured.given().baseUri(callbackURL).header("Content-Type", ContentType.JSON).body(body).when().put(); + String responseBody = response.getBody().asString(); + logger.info(responseBody); + int responseCode = response.getStatusCode(); + logger.info(String.valueOf(responseCode)); + } + +} diff --git a/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/service/ValidateHeaders.java b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/service/ValidateHeaders.java new file mode 100644 index 000000000..8815795e9 --- /dev/null +++ b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/service/ValidateHeaders.java @@ -0,0 +1,17 @@ +package org.mifos.pheevouchermanagementsystem.service; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +public @interface ValidateHeaders { + + String[] requiredHeaders(); + + Class validatorClass(); + + String validationFunction(); +} \ No newline at end of file diff --git a/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/service/VoucherLifecycleService.java b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/service/VoucherLifecycleService.java new file mode 100644 index 000000000..f175894da --- /dev/null +++ b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/service/VoucherLifecycleService.java @@ -0,0 +1,198 @@ +package org.mifos.pheevouchermanagementsystem.service; + +import static org.mifos.pheevouchermanagementsystem.service.ActivateVoucherService.validateRegisteringInstitutionId; +import static org.mifos.pheevouchermanagementsystem.util.VoucherStatusEnum.ACTIVE; +import static org.mifos.pheevouchermanagementsystem.util.VoucherStatusEnum.CANCELLED; +import static org.mifos.pheevouchermanagementsystem.util.VoucherStatusEnum.EXPIRED; +import static org.mifos.pheevouchermanagementsystem.util.VoucherStatusEnum.SUSPENDED; +import static org.mifos.pheevouchermanagementsystem.util.VoucherStatusEnum.UTILIZED; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import java.util.ArrayList; +import java.util.List; +import org.mifos.pheevouchermanagementsystem.data.FailedCaseDTO; +import org.mifos.pheevouchermanagementsystem.data.RequestDTO; +import org.mifos.pheevouchermanagementsystem.data.VoucherInstruction; +import org.mifos.pheevouchermanagementsystem.data.VoucherLifecycleCallbackResponseDTO; +import org.mifos.pheevouchermanagementsystem.domain.Voucher; +import org.mifos.pheevouchermanagementsystem.exception.VoucherNotFoundException; +import org.mifos.pheevouchermanagementsystem.repository.ErrorTrackingRepository; +import org.mifos.pheevouchermanagementsystem.repository.VoucherRepository; +import org.mifos.pheevouchermanagementsystem.util.UniqueIDGenerator; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +public class VoucherLifecycleService { + + private final VoucherRepository voucherRepository; + private final ErrorTrackingRepository errorTrackingRepository; + private final SendCallbackService sendCallbackService; + private final ObjectMapper objectMapper; + + private static final Logger logger = LoggerFactory.getLogger(VoucherLifecycleService.class); + + @Autowired + public VoucherLifecycleService(VoucherRepository voucherRepository, ErrorTrackingRepository errorTrackingRepository, + SendCallbackService sendCallbackService, ObjectMapper objectMapper) { + this.voucherRepository = voucherRepository; + this.errorTrackingRepository = errorTrackingRepository; + this.sendCallbackService = sendCallbackService; + this.objectMapper = objectMapper; + } + + @Async("asyncExecutor") + public void suspendVoucher(RequestDTO request, String callbackURL, String registeringInstitutionId) { + List voucherInstructionList = request.getVoucherInstructions(); + List failedCaseList = new ArrayList<>(); + validateAndSuspendVouchers(voucherInstructionList, request, failedCaseList, registeringInstitutionId); + try { + sendCallbackService.sendCallback( + objectMapper.writeValueAsString(new VoucherLifecycleCallbackResponseDTO(UniqueIDGenerator.generateUniqueNumber(12), + request.getRequestID(), failedCaseList.size(), failedCaseList)), + callbackURL); + } catch (JsonProcessingException e) { + throw new RuntimeException(e); + } + } + + @Async("asyncExecutor") + public void reactivateVoucher(RequestDTO request, String callbackURL, String registeringInstitutionId) { + List voucherInstructionList = request.getVoucherInstructions(); + List failedCaseList = new ArrayList<>(); + validateAndReactivateVouchers(voucherInstructionList, request, failedCaseList, registeringInstitutionId); + try { + sendCallbackService.sendCallback( + objectMapper.writeValueAsString(new VoucherLifecycleCallbackResponseDTO(UniqueIDGenerator.generateUniqueNumber(12), + request.getRequestID(), failedCaseList.size(), failedCaseList)), + callbackURL); + } catch (JsonProcessingException e) { + throw new RuntimeException(e); + } + } + + @Async("asyncExecutor") + public void cancelVoucher(RequestDTO request, String callbackURL, String registeringInstitutionId) { + List voucherInstructionList = request.getVoucherInstructions(); + List failedCaseList = new ArrayList<>(); + validateAndCancelVouchers(voucherInstructionList, request, failedCaseList, registeringInstitutionId); + try { + sendCallbackService.sendCallback( + objectMapper.writeValueAsString(new VoucherLifecycleCallbackResponseDTO(UniqueIDGenerator.generateUniqueNumber(12), + request.getRequestID(), failedCaseList.size(), failedCaseList)), + callbackURL); + } catch (JsonProcessingException e) { + throw new RuntimeException(e); + } + } + + public void validateAndReactivateVouchers(List voucherInstructionList, RequestDTO request, + List failedCaseList, String registeringInstitutionId) { + voucherInstructionList.stream().forEach(voucherInstruction -> { + String requestID = request.getRequestID(); + Boolean isValidated = validateVoucherForReactivate(voucherInstruction, request); + if (isValidated) { + Voucher voucher = fetchVoucher(voucherInstruction); + if (validateRegisteringInstitutionId(voucher, registeringInstitutionId)) { + changeStatus(voucher, ACTIVE.getValue()); + } else { + FailedCaseDTO failedCase = new FailedCaseDTO(voucherInstruction.getSerialNumber(), + "The voucher provided in the request does not correspond to the same registering ID."); + failedCaseList.add(failedCase); + } + } else { + FailedCaseDTO failedCase = new FailedCaseDTO(voucherInstruction.getSerialNumber(), "Voucher validation failed."); + failedCaseList.add(failedCase); + } + }); + } + + public void validateAndSuspendVouchers(List voucherInstructionList, RequestDTO request, + List failedCaseList, String registeringInstitutionId) { + voucherInstructionList.stream().forEach(voucherInstruction -> { + String requestID = request.getRequestID(); + Boolean isValidated = validateVoucherForSuspend(voucherInstruction, request); + if (isValidated) { + Voucher voucher = fetchVoucher(voucherInstruction); + if (validateRegisteringInstitutionId(voucher, registeringInstitutionId)) { + changeStatus(voucher, SUSPENDED.getValue()); + } else { + FailedCaseDTO failedCase = new FailedCaseDTO(voucherInstruction.getSerialNumber(), + "The voucher provided in the request does not correspond to the same registering ID."); + failedCaseList.add(failedCase); + } + } else { + FailedCaseDTO failedCase = new FailedCaseDTO(voucherInstruction.getSerialNumber(), "Voucher validation failed."); + failedCaseList.add(failedCase); + } + }); + } + + public void validateAndCancelVouchers(List voucherInstructionList, RequestDTO request, + List failedCaseList, String registeringInstitutionId) { + voucherInstructionList.stream().forEach(voucherInstruction -> { + String requestID = request.getRequestID(); + Boolean isValidated = validateVoucherForCancel(voucherInstruction, request); + if (isValidated) { + Voucher voucher = fetchVoucher(voucherInstruction); + if (validateRegisteringInstitutionId(voucher, registeringInstitutionId)) { + changeStatus(voucher, CANCELLED.getValue()); + } else { + FailedCaseDTO failedCase = new FailedCaseDTO(voucherInstruction.getSerialNumber(), + "The voucher provided in the request does not correspond to the same registering ID."); + failedCaseList.add(failedCase); + } + } else { + FailedCaseDTO failedCase = new FailedCaseDTO(voucherInstruction.getSerialNumber(), "Voucher validation failed."); + failedCaseList.add(failedCase); + } + }); + } + + public Boolean validateVoucherForReactivate(VoucherInstruction voucherInstruction, RequestDTO request) { + if (voucherRepository.existsBySerialNo(voucherInstruction.getSerialNumber())) { + Voucher voucher = fetchVoucher(voucherInstruction); + return !voucher.getStatus().equals(EXPIRED.getValue()) && !voucher.getStatus().equals(UTILIZED.getValue()) + && !voucher.getStatus().equals(CANCELLED.getValue()); + } + return false; + } + + public Boolean validateVoucherForCancel(VoucherInstruction voucherInstruction, RequestDTO request) { + if (voucherRepository.existsBySerialNo(voucherInstruction.getSerialNumber())) { + Voucher voucher = fetchVoucher(voucherInstruction); + return !voucher.getStatus().equals(EXPIRED.getValue()) && !voucher.getStatus().equals(UTILIZED.getValue()) + && !voucher.getStatus().equals(CANCELLED.getValue()); + } + return false; + } + + public Boolean validateVoucherForSuspend(VoucherInstruction voucherInstruction, RequestDTO request) { + if (voucherRepository.existsBySerialNo(voucherInstruction.getSerialNumber())) { + Voucher voucher = fetchVoucher(voucherInstruction); + return !voucher.getStatus().equals(EXPIRED.getValue()) && !voucher.getStatus().equals(CANCELLED.getValue()) + && !voucher.getStatus().equals(UTILIZED.getValue()); + } + return false; + } + + @Transactional + public void changeStatus(Voucher voucher, String status) { + voucher.setStatus(status); + try { + voucherRepository.save(voucher); + } catch (RuntimeException e) { + logger.error(e.getMessage()); + } + } + + public Voucher fetchVoucher(VoucherInstruction voucherInstruction) { + return voucherRepository.findBySerialNo(voucherInstruction.getSerialNumber()) + .orElseThrow(() -> VoucherNotFoundException.voucherNotFound(voucherInstruction.getSerialNumber())); + } +} diff --git a/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/service/VoucherValidityService.java b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/service/VoucherValidityService.java new file mode 100644 index 000000000..081cdac3f --- /dev/null +++ b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/service/VoucherValidityService.java @@ -0,0 +1,104 @@ +package org.mifos.pheevouchermanagementsystem.service; + +import static org.mifos.pheevouchermanagementsystem.util.VoucherStatusEnum.ACTIVE; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import java.time.LocalDate; +import java.time.ZoneId; +import org.mifos.connector.common.util.SecurityUtil; +import org.mifos.pheevouchermanagementsystem.data.ValidityDTO; +import org.mifos.pheevouchermanagementsystem.domain.Voucher; +import org.mifos.pheevouchermanagementsystem.exception.VoucherNotFoundException; +import org.mifos.pheevouchermanagementsystem.repository.ErrorTrackingRepository; +import org.mifos.pheevouchermanagementsystem.repository.VoucherRepository; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Service; + +@Service +public class VoucherValidityService { + + private final VoucherRepository voucherRepository; + private final ErrorTrackingRepository errorTrackingRepository; + private final SendCallbackService sendCallbackService; + private final ObjectMapper objectMapper; + + private static final Logger logger = LoggerFactory.getLogger(VoucherValidityService.class); + + @Autowired + public VoucherValidityService(VoucherRepository voucherRepository, ErrorTrackingRepository errorTrackingRepository, + SendCallbackService sendCallbackService, ObjectMapper objectMapper) { + this.voucherRepository = voucherRepository; + this.errorTrackingRepository = errorTrackingRepository; + this.sendCallbackService = sendCallbackService; + this.objectMapper = objectMapper; + } + + @Async("asyncExecutor") + public void getVoucherValidity(String serialNumber, String voucherNumber, String groupCode, String callbackURL) { + if (serialNumber != null) { + checkValidityBySerialNumber(serialNumber, callbackURL); + } else if (voucherNumber != null && groupCode != null) { + checkValidityByVoucherNumberAndGroupCode(voucherNumber, groupCode, callbackURL); + } else { + sendCallbackService.sendCallback("Requested resource not found!", callbackURL); + } + } + + public void checkValidityBySerialNumber(String serialNumber, String callbackURL) { + Voucher voucher = null; + try { + voucher = voucherRepository.findBySerialNo(serialNumber) + .orElseThrow(() -> VoucherNotFoundException.voucherNotFound(serialNumber)); + } catch (RuntimeException e) { + logger.error(e.getMessage()); + sendCallbackService.sendCallback("Requested resource not found!", callbackURL); + return; + } + if (voucher.getStatus().equals(ACTIVE.getValue())) { + + if (voucherRepository.existsBySerialNo(serialNumber) + && voucher.getExpiryDate().toLocalDate().isAfter(LocalDate.now(ZoneId.systemDefault()))) { + sendValidityCallback(true, callbackURL, voucher.getSerialNo()); + } else { + sendValidityCallback(false, callbackURL, voucher.getSerialNo()); + } + } else { + sendValidityCallback(false, callbackURL, voucher.getSerialNo()); + } + } + + public void checkValidityByVoucherNumberAndGroupCode(String voucherNumber, String groupCode, String callbackURL) { + try { + Voucher voucher = voucherRepository.findByVoucherNo(SecurityUtil.hash(voucherNumber)) + .orElseThrow(() -> VoucherNotFoundException.voucherNotFound(voucherNumber)); + String groupCodeVoucher = voucher.getGroupCode(); + if (voucher.getStatus().equals(ACTIVE.getValue())) { + if (groupCodeVoucher.equals(groupCode) + && voucher.getExpiryDate().toLocalDate().isAfter(LocalDate.now(ZoneId.systemDefault()))) { + sendValidityCallback(true, callbackURL, voucher.getSerialNo()); + } else { + sendValidityCallback(false, callbackURL, voucher.getSerialNo()); + } + } else { + sendValidityCallback(false, callbackURL, voucher.getSerialNo()); + } + } catch (RuntimeException e) { + logger.error(e.getMessage()); + if (!voucherRepository.existsByVoucherNo(SecurityUtil.hash(voucherNumber))) { + sendCallbackService.sendCallback("Requested resource not found!", callbackURL); + } + } + } + + public void sendValidityCallback(Boolean isValid, String callbackURL, String serialNumber) { + try { + sendCallbackService.sendCallback(objectMapper.writeValueAsString(new ValidityDTO(serialNumber, isValid)), callbackURL); + } catch (JsonProcessingException e) { + logger.error(e.getMessage()); + } + } +} diff --git a/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/util/AbstractApplicationConfiguration.java b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/util/AbstractApplicationConfiguration.java new file mode 100644 index 000000000..e7a22de43 --- /dev/null +++ b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/util/AbstractApplicationConfiguration.java @@ -0,0 +1,31 @@ +package org.mifos.pheevouchermanagementsystem.util; + +import java.util.concurrent.Executor; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.scheduling.annotation.EnableAsync; +import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; + +@Configuration +@EnableAsync +public class AbstractApplicationConfiguration { + + @Value("${async.core_pool_size}") + public Integer corePoolSize; + @Value("${async.max_pool_size}") + public Integer maxPoolSize; + @Value("${async.queue_capacity}") + public Integer queueCapacity; + + @Bean(name = "asyncExecutor") + public Executor asyncExecutor() { + ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); + executor.setCorePoolSize(corePoolSize); + executor.setMaxPoolSize(maxPoolSize); + executor.setQueueCapacity(queueCapacity); + executor.setThreadNamePrefix("AsyncThread-"); + executor.initialize(); + return executor; + } +} diff --git a/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/util/EncryptVoucher.java b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/util/EncryptVoucher.java new file mode 100644 index 000000000..e87f92d7f --- /dev/null +++ b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/util/EncryptVoucher.java @@ -0,0 +1,10 @@ +package org.mifos.pheevouchermanagementsystem.util; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public final class EncryptVoucher { + + private EncryptVoucher() {} + +} diff --git a/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/util/HeaderConstants.java b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/util/HeaderConstants.java new file mode 100644 index 000000000..3f1de6c84 --- /dev/null +++ b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/util/HeaderConstants.java @@ -0,0 +1,11 @@ +package org.mifos.pheevouchermanagementsystem.util; + +@SuppressWarnings("HideUtilityClassConstructor") +public class HeaderConstants { + + public static final String X_CALLBACKURL = "X-CallbackURL"; + public static final String X_PLATFORM_TENANT_ID = "X-Platform-TenantId"; + public static final String X_PROGRAM_ID = "X-Program-Id"; + public static final String X_REGISTERING_INSTITUTION_ID = "X-Registering-Institution-ID"; + +} \ No newline at end of file diff --git a/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/util/PaymentModalityEnum.java b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/util/PaymentModalityEnum.java new file mode 100644 index 000000000..19db0c519 --- /dev/null +++ b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/util/PaymentModalityEnum.java @@ -0,0 +1,34 @@ +package org.mifos.pheevouchermanagementsystem.util; + +public enum PaymentModalityEnum { + + ACCOUNT_ID("0"), MSISDN("1"), VOUCHER("2"); + + private final String value; + + PaymentModalityEnum(String value) { + this.value = value; + } + + public static String getValueByKey(String key) { + for (PaymentModalityEnum pair : values()) { + if (pair.name().equalsIgnoreCase(key)) { + return pair.getValue(); + } + } + return null; + } + + public static String getKeyByValue(String value) { + for (PaymentModalityEnum pair : values()) { + if (pair.getValue().equalsIgnoreCase(value)) { + return pair.name(); + } + } + return null; + } + + public String getValue() { + return this.value; + } +} diff --git a/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/util/RedemptionStatusEnum.java b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/util/RedemptionStatusEnum.java new file mode 100644 index 000000000..02b595fc9 --- /dev/null +++ b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/util/RedemptionStatusEnum.java @@ -0,0 +1,16 @@ +package org.mifos.pheevouchermanagementsystem.util; + +public enum RedemptionStatusEnum { + + FAILURE("00"), SUCCESS("01"); + + private final String value; + + RedemptionStatusEnum(String value) { + this.value = value; + } + + public String getValue() { + return this.value; + } +} diff --git a/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/util/UniqueIDGenerator.java b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/util/UniqueIDGenerator.java new file mode 100644 index 000000000..da4177696 --- /dev/null +++ b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/util/UniqueIDGenerator.java @@ -0,0 +1,16 @@ +package org.mifos.pheevouchermanagementsystem.util; + +import java.util.Random; + +public final class UniqueIDGenerator { + + private UniqueIDGenerator() {} + + public static String generateUniqueNumber(int length) { + Random rand = new Random(); + long timestamp = System.currentTimeMillis(); + long randomLong = rand.nextLong(100000000); + String uniqueNumber = timestamp + "" + randomLong; + return uniqueNumber.substring(0, length); + } +} diff --git a/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/util/VoucherManagementEnum.java b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/util/VoucherManagementEnum.java new file mode 100644 index 000000000..b1378b4fa --- /dev/null +++ b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/util/VoucherManagementEnum.java @@ -0,0 +1,24 @@ +package org.mifos.pheevouchermanagementsystem.util; + +public enum VoucherManagementEnum { + + SUCCESS_RESPONSE("00", "Request successfully received by Pay-BB"), FAILED_RESPONSE("01", + "Request not acknowledged by Pay-BB"), PROCESS_DEFINITION_NOT_FOUND("01", + "Process definition not found"), CONFLICT_OCCURRED("01", "Conflict occurred due to existing data"); + + private final String value; + private final String message; + + VoucherManagementEnum(String value, String message) { + this.value = value; + this.message = message; + } + + public String getValue() { + return this.value; + } + + public String getMessage() { + return message; + } +} diff --git a/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/util/VoucherStatusEnum.java b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/util/VoucherStatusEnum.java new file mode 100644 index 000000000..6ea3abcbe --- /dev/null +++ b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/util/VoucherStatusEnum.java @@ -0,0 +1,22 @@ +package org.mifos.pheevouchermanagementsystem.util; + +public enum VoucherStatusEnum { + + INACTIVE("01"), ACTIVE("02"), CANCELLED("03"), EXPIRED("04"), UTILIZED("05"), SUSPENDED("06"), ERROR("07"); + + private final String value; + + VoucherStatusEnum(String value) { + this.value = value; + } + + @Override + public String toString() { + String name = name(); + return name.charAt(0) + name.substring(1).toLowerCase(); + } + + public String getValue() { + return this.value; + } +} diff --git a/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/util/VoucherValidatorsEnum.java b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/util/VoucherValidatorsEnum.java new file mode 100644 index 000000000..28db7df23 --- /dev/null +++ b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/util/VoucherValidatorsEnum.java @@ -0,0 +1,99 @@ +package org.mifos.pheevouchermanagementsystem.util; + +import org.mifos.connector.common.exception.PaymentHubErrorCategory; +import org.mifos.connector.common.validation.ValidationCodeType; + +public enum VoucherValidatorsEnum implements ValidationCodeType { + + VOUCHER_HEADER_VALIDATION_ERROR("error.msg.header.validation.errors", "The headers are invalid"), VOUCHER_SCHEMA_VALIDATION_ERROR( + "error.msg.schema.validation.errors", + "The request is invalid"), INVALID_CALLBACK_URL("error.msg.schema.callback.url.cannot.be.null.or.empty", + "Callback URL cannot be null or empty"), INVALID_CALLBACK_URL_LENGTH("error.msg.schema.callback.url.length.is.invalid", + "Callback URL length is invalid"), INVALID_REGISTERING_INSTITUTION_ID( + "error.msg.schema.registering.institution.id.cannot.be.null.or.empty", + "Registering Institution Id cannot be null or empty"), INVALID_REGISTERING_INSTITUTION_ID_LENGTH( + "error.msg.schema.registering.institution.id.length.is.invalid", + "Registering Institution Id cannot length is invalid"), INVALID_REQUEST_ID( + "error.msg.schema.request.id.cannot.be.null.or.empty", + "Request Id cannot be null or empty"), INVALID_REQUEST_ID_LENGTH( + "error.msg.schema.request.id.length.is.invalid", + "Request Id length is invalid"), INVALID_BATCH_ID( + "error.msg.schema.batch.id.cannot.be.null.or.empty", + "Batch Id cannot be null or empty"), INVALID_BATCH_ID_LENGTH( + "error.msg.schema.batch.id.length.is.invalid", + "Batch Id length is invalid"), + + INVALID_VOUCHER_INSTRUCTIONS("error.msg.schema.voucher.instructions.cannot.be.null.or.empty", + "Voucher instructions cannot be null or empty"), INVALID_INSTRUCTION_ID( + "error.msg.schema.instruction.id.cannot.be.null.or.empty", + "Instruction Id cannot be null or empty"), INVALID_INSTRUCTION_ID_LENGTH( + "error.msg.schema.instruction.id.length.is.invalid", "Instruction Id length is invalid"), + + INVALID_GROUP_CODE("error.msg.schema.group.code.cannot.be.null.or.empty", + "Group Code cannot be null or empty"), INVALID_GROUP_CODE_LENGTH("error.msg.schema.group.code.length.is.invalid", + "Group Code length is invalid"), + + INVALID_CURRENCY("error.msg.schema.currency.cannot.be.null.or.empty", "Currency cannot be null or empty"), INVALID_CURRENCY_LENGTH( + "error.msg.schema.currency.length.is.invalid", "Currency length is invalid"), + + INVALID_AMOUNT("error.msg.schema.amount.cannot.be.null.or.empty", "Amount cannot be null or empty"), INVALID_NEGATIVE_AMOUNT( + "error.msg.schema.amount.cannot.be.negative", + "Amount cannot be negative"), INVALID_PAYEE_FUNCTIONAL_ID("error.msg.schema.payee.functional.id.cannot.be.null.or.empty", + "PayeeFunctional Id cannot be null or empty"), INVALID_PAYEE_FUNCTIONAL_ID_LENGTH( + "error.msg.schema.payee.functional.id.length.is.invalid", + "PayeeFunctional Id length is invalid"), INVALID_NARRATION_LENGTH( + "error.msg.schema.narration.length.is.invalid", "Narration is invalid"), INVALID_LENGTH( + "error.msg.schema.length.is.invalid", "Length is invalid"), INVALID_LIST( + "error.msg.schema.list.is.invalid", "List is invalid"), INVALID_MAX_LENGTH( + "error.msg.schema.max.length.cannot.exceed.50.words", + "Cannot exceed 50 words"), VOUCHER_LIFECYCLE_VALIDATION_ERROR( + "error.msg.voucher.lifecycle.validation.errors", + "Voucher lifecycle validation failed"), INVALID_SERIAL_NUMBER( + "error.msg.schema.serial.number.cannot.be.null.or.empty", + "Serial number cannot be null or empty"), INVALID_SERIAL_NUMBER_LENGTH( + "error.msg.schema.serial.number.length.is.invalid", + "Serial number length is invalid"), INVALID_STATUS( + "error.msg.schema.status.cannot.be.null.or.empty", + "Status cannot be null or empty"), INVALID_STATUS_LENGTH( + "error.msg.schema.status.length.is.invalid", + "Status length is invalid"), REDEEM_VOUCHER_VALIDATION_ERROR( + "error.msg.redeem.voucher.validation.errors", + "Redeem voucher validation failed"), INVALID_AGENT_ID( + "error.msg.schema.agent.id.cannot.be.null.or.empty", + "Agent Id cannot be null or empty"), INVALID_AGENT_ID_LENGTH( + "error.msg.schema.agent.id.length.is.invalid", + "Agent Id length is invalid"), INVALID_VOUCHER_SERIAL_NUMBER( + "error.msg.schema.voucher.serial.number.cannot.be.null.or.empty", + "Voucher serial number cannot be null or empty"), INVALID_VOUCHER_SERIAL_NUMBER_LENGTH( + "error.msg.schema.voucher.serial.number.length.is.invalid", + "Voucher serial number length is invalid"), INVALID_VOUCHER_SECRET_NUMBER( + "error.msg.schema.voucher.secret.number.cannot.be.null.or.empty", + "Voucher secret number cannot be null or empty"), INVALID_VOUCHER_SECRET_NUMBER_LENGTH( + "error.msg.schema.voucher.secret.number.length.is.invalid", + "Voucher secret number length is invalid"), HEADER_VALIDATION_ERROR( + "error.msg.header.validation.errors", "The headers are invalid"), INVALID_PROGRAM_ID_LENGTH( + "error.msg.schema.program.id.length.is.invalid", + "Program Id length is invalid"); + + private final String code; + private final String category; + private final String message; + + VoucherValidatorsEnum(String code, String message) { + this.code = code; + this.category = PaymentHubErrorCategory.Validation.toString(); + this.message = message; + } + + public String getCode() { + return this.code; + } + + public String getCategory() { + return this.category; + } + + public String getMessage() { + return message; + } +} \ No newline at end of file diff --git a/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/util/VouchersDTOConstant.java b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/util/VouchersDTOConstant.java new file mode 100644 index 000000000..a59949e43 --- /dev/null +++ b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/util/VouchersDTOConstant.java @@ -0,0 +1,25 @@ +package org.mifos.pheevouchermanagementsystem.util; + +@SuppressWarnings("HideUtilityClassConstructor") +public class VouchersDTOConstant { + + public static final String requestId = "requestId"; + public static final String requestID = "requestID"; + public static final String batchId = "batchId"; + public static final String batchID = "batchID"; + public static final String voucherInstructions = "voucherInstructions"; + public static final String instructionId = "instructionId"; + public static final String instructionID = "instructionID"; + public static final String groupCode = "groupCode"; + public static final String currency = "currency"; + public static final String amount = "amount"; + public static final String payeeFunctionalId = "payeeFunctionalId"; + public static final String payeeFunctionalID = "payeeFunctionalID"; + public static final String narration = "narration"; + public static final String serialNumber = "serialNumber"; + public static final String agentId = "agentId"; + public static final String agentID = "agentID"; + public static final String voucherSerialNumber = "voucherSerialNumber"; + public static final String voucherSecretNumber = "voucherSecretNumber"; + public static final String status = "status"; +} diff --git a/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/validator/HeaderValidator.java b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/validator/HeaderValidator.java new file mode 100644 index 000000000..c114ec81e --- /dev/null +++ b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/validator/HeaderValidator.java @@ -0,0 +1,140 @@ +package org.mifos.pheevouchermanagementsystem.validator; + +import static org.mifos.connector.common.exception.PaymentHubError.ExtValidationError; + +import java.util.Collections; +import java.util.Enumeration; +import java.util.List; +import java.util.Set; +import javax.servlet.http.HttpServletRequest; +import org.mifos.connector.common.channel.dto.PhErrorDTO; +import org.mifos.connector.common.exception.PaymentHubErrorCategory; +import org.mifos.connector.common.validation.ValidatorBuilder; +import org.mifos.pheevouchermanagementsystem.data.UnsupportedParameterValidation; +import org.mifos.pheevouchermanagementsystem.util.HeaderConstants; +import org.mifos.pheevouchermanagementsystem.util.VoucherValidatorsEnum; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +@Component +public class HeaderValidator { + + @Autowired + private UnsupportedParameterValidation unsupportedParameterValidator; + + @Value("#{'${default_headers}'.split(',')}") + private List defaultHeader; + + private static final String resource = "voucherValidator"; + + public PhErrorDTO validateCreateVoucher(Set requiredHeaders, HttpServletRequest request) { + final ValidatorBuilder validatorBuilder = new ValidatorBuilder(); + + List headers = getHeaderList(request); + + unsupportedParameterValidator.handleRequiredParameterValidation(headers, requiredHeaders, validatorBuilder); + + // Checks for X-Program-Id + validatorBuilder.validateFieldIgnoreNullAndMaxLengthWithFailureCode(resource, HeaderConstants.X_PROGRAM_ID, + request.getHeader(HeaderConstants.X_PROGRAM_ID), 20, VoucherValidatorsEnum.INVALID_PROGRAM_ID_LENGTH); + + // Checks for X-Registering-Institution-ID + validatorBuilder.validateFieldIgnoreNullAndMaxLengthWithFailureCode(resource, HeaderConstants.X_REGISTERING_INSTITUTION_ID, + request.getHeader(HeaderConstants.X_REGISTERING_INSTITUTION_ID), 20, + VoucherValidatorsEnum.INVALID_REGISTERING_INSTITUTION_ID_LENGTH); + + // Checks for X-Callback-URL + validatorBuilder.validateFieldIsNullAndMaxLengthWithFailureCode(resource, HeaderConstants.X_CALLBACKURL, + request.getHeader(HeaderConstants.X_CALLBACKURL), VoucherValidatorsEnum.INVALID_CALLBACK_URL, 100, + VoucherValidatorsEnum.INVALID_CALLBACK_URL_LENGTH); + + return handleValidationErrors(validatorBuilder); + } + + public PhErrorDTO validateVoucherLifecycle(Set requiredHeaders, HttpServletRequest request) { + + final ValidatorBuilder validatorBuilder = new ValidatorBuilder(); + + List headers = getHeaderList(request); + + unsupportedParameterValidator.handleRequiredParameterValidation(headers, requiredHeaders, validatorBuilder); + + // Checks for X-Program-Id + validatorBuilder.validateFieldIgnoreNullAndMaxLengthWithFailureCode(resource, HeaderConstants.X_PROGRAM_ID, + request.getHeader(HeaderConstants.X_PROGRAM_ID), 20, VoucherValidatorsEnum.INVALID_PROGRAM_ID_LENGTH); + + // Checks for X-Registering-Institution-ID + validatorBuilder.validateFieldIsNullAndMaxLengthWithFailureCode(resource, HeaderConstants.X_REGISTERING_INSTITUTION_ID, + request.getHeader(HeaderConstants.X_REGISTERING_INSTITUTION_ID), VoucherValidatorsEnum.INVALID_REGISTERING_INSTITUTION_ID, + 20, VoucherValidatorsEnum.INVALID_REGISTERING_INSTITUTION_ID_LENGTH); + + // Checks for X-Callback-URL + validatorBuilder.validateFieldIsNullAndMaxLengthWithFailureCode(resource, HeaderConstants.X_CALLBACKURL, + request.getHeader(HeaderConstants.X_CALLBACKURL), VoucherValidatorsEnum.INVALID_CALLBACK_URL, 100, + VoucherValidatorsEnum.INVALID_CALLBACK_URL_LENGTH); + + return handleValidationErrors(validatorBuilder); + } + + public PhErrorDTO validateCancelOrRedeemVoucher(Set requiredHeaders, HttpServletRequest request) { + + final ValidatorBuilder validatorBuilder = new ValidatorBuilder(); + + List headers = getHeaderList(request); + + String command = request.getParameter("command"); + if (command.equals("redeem")) { + headers.remove(HeaderConstants.X_CALLBACKURL); + headers.remove(HeaderConstants.X_PROGRAM_ID); + + unsupportedParameterValidator.handleRequiredParameterValidation(headers, requiredHeaders, validatorBuilder); + + // Checks for X-Registering-Institution-ID + validatorBuilder.validateFieldIsNullAndMaxLengthWithFailureCode(resource, HeaderConstants.X_REGISTERING_INSTITUTION_ID, + request.getHeader(HeaderConstants.X_REGISTERING_INSTITUTION_ID), + VoucherValidatorsEnum.INVALID_REGISTERING_INSTITUTION_ID, 20, + VoucherValidatorsEnum.INVALID_REGISTERING_INSTITUTION_ID_LENGTH); + } else { + return validateVoucherLifecycle(requiredHeaders, request); + } + + return handleValidationErrors(validatorBuilder); + } + + public PhErrorDTO validateForRegisteringInstitutionID(Set requiredHeaders, HttpServletRequest request) { + final ValidatorBuilder validatorBuilder = new ValidatorBuilder(); + + List headers = getHeaderList(request); + + unsupportedParameterValidator.handleRequiredParameterValidation(headers, requiredHeaders, validatorBuilder); + + // Checks for X-Registering-Institution-ID + validatorBuilder.validateFieldIsNullAndMaxLengthWithFailureCode(resource, HeaderConstants.X_REGISTERING_INSTITUTION_ID, + request.getHeader(HeaderConstants.X_REGISTERING_INSTITUTION_ID), VoucherValidatorsEnum.INVALID_REGISTERING_INSTITUTION_ID, + 20, VoucherValidatorsEnum.INVALID_REGISTERING_INSTITUTION_ID_LENGTH); + + return handleValidationErrors(validatorBuilder); + + } + + private PhErrorDTO handleValidationErrors(ValidatorBuilder validatorBuilder) { + if (validatorBuilder.hasError()) { + validatorBuilder.errorCategory(PaymentHubErrorCategory.Validation.toString()) + .errorCode(VoucherValidatorsEnum.HEADER_VALIDATION_ERROR.getCode()) + .errorDescription(VoucherValidatorsEnum.HEADER_VALIDATION_ERROR.getMessage()) + .developerMessage(VoucherValidatorsEnum.HEADER_VALIDATION_ERROR.getMessage()) + .defaultUserMessage(VoucherValidatorsEnum.HEADER_VALIDATION_ERROR.getMessage()); + + PhErrorDTO.PhErrorDTOBuilder phErrorDTOBuilder = new PhErrorDTO.PhErrorDTOBuilder(ExtValidationError.getErrorCode()); + phErrorDTOBuilder.fromValidatorBuilder(validatorBuilder); + return phErrorDTOBuilder.build(); + } + return null; + } + + public List getHeaderList(HttpServletRequest request) { + Enumeration headers = request.getHeaderNames(); + return Collections.list(request.getHeaderNames()); + } +} \ No newline at end of file diff --git a/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/zeebe/ZeebeClientConfiguration.java b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/zeebe/ZeebeClientConfiguration.java new file mode 100644 index 000000000..aceb3839b --- /dev/null +++ b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/zeebe/ZeebeClientConfiguration.java @@ -0,0 +1,27 @@ +package org.mifos.pheevouchermanagementsystem.zeebe; + +import io.camunda.zeebe.client.ZeebeClient; +import java.time.Duration; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class ZeebeClientConfiguration { + + @Value("${zeebe.broker.contactpoint}") + private String zeebeBrokerContactpoint; + + @Value("${zeebe.client.max-execution-threads}") + private int zeebeClientMaxThreads; + + @Value("${zeebe.client.poll-interval}") + private int zeebeClientPollInterval; + + @Bean + public ZeebeClient setup() { + return ZeebeClient.newClientBuilder().gatewayAddress(zeebeBrokerContactpoint).usePlaintext() + .defaultJobPollInterval(Duration.ofMillis(zeebeClientPollInterval)).defaultJobWorkerMaxJobsActive(2000) + .numJobWorkerExecutionThreads(zeebeClientMaxThreads).build(); + } +} diff --git a/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/zeebe/ZeebeMessages.java b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/zeebe/ZeebeMessages.java new file mode 100644 index 000000000..016173a67 --- /dev/null +++ b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/zeebe/ZeebeMessages.java @@ -0,0 +1,9 @@ +package org.mifos.pheevouchermanagementsystem.zeebe; + +public final class ZeebeMessages { + + private ZeebeMessages() {} + + public static final String ACCOUNT_LOOKUP = "account-lookup"; + public static final String BATCH_AUTHORIZATION = "batch-authorization"; +} diff --git a/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/zeebe/ZeebeProcessStarter.java b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/zeebe/ZeebeProcessStarter.java new file mode 100644 index 000000000..23ffd2425 --- /dev/null +++ b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/zeebe/ZeebeProcessStarter.java @@ -0,0 +1,52 @@ +package org.mifos.pheevouchermanagementsystem.zeebe; + +import io.camunda.zeebe.client.ZeebeClient; +import io.camunda.zeebe.client.api.command.ClientStatusException; +import io.camunda.zeebe.client.api.response.ProcessInstanceEvent; +import java.time.Instant; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; +import org.mifos.connector.common.zeebe.ZeebeVariables; +import org.mifos.pheevouchermanagementsystem.exception.ZeebeClientStatusException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component +public class ZeebeProcessStarter { + + private static final Logger logger = LoggerFactory.getLogger(ZeebeProcessStarter.class); + + @Autowired + private ZeebeClient zeebeClient; + + public String startZeebeWorkflow(String workflowId, String request, Map extraVariables) { + String transactionId = generateTransactionId(); + + Map variables = new HashMap<>(); + variables.put(org.mifos.connector.common.zeebe.ZeebeVariables.TRANSACTION_ID, transactionId); + variables.put(org.mifos.connector.common.zeebe.ZeebeVariables.CHANNEL_REQUEST, request); + variables.put(ZeebeVariables.ORIGIN_DATE, Instant.now().toEpochMilli()); + if (extraVariables != null) { + variables.putAll(extraVariables); + } + + logger.info("starting workflow HERE:"); + // TODO if successful transfer response arrives in X timeout return it otherwise do callback + try { + ProcessInstanceEvent instance = zeebeClient.newCreateInstanceCommand().bpmnProcessId(workflowId).latestVersion() + .variables(variables).send().join(); + logger.info("zeebee workflow instance from process {} started with transactionId {}, instance key: {}", workflowId, + transactionId, instance.getProcessInstanceKey()); + } catch (ClientStatusException ex) { + throw new ZeebeClientStatusException(ex.getMessage(), extraVariables.get("requestId").toString(), ex); + } + return transactionId; + } + + private String generateTransactionId() { + return UUID.randomUUID().toString(); + } +} diff --git a/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/zeebe/ZeebeVariables.java b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/zeebe/ZeebeVariables.java new file mode 100644 index 000000000..dcf7ca280 --- /dev/null +++ b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/zeebe/ZeebeVariables.java @@ -0,0 +1,27 @@ +package org.mifos.pheevouchermanagementsystem.zeebe; + +public final class ZeebeVariables { + + private ZeebeVariables() {} + + public static final String ACCOUNT_LOOKUP_FAILED = "accountLookupFailed"; + public static final String ORIGIN_CHANNEL_REQUEST = "originChannelRequest"; + public static final String CALLBACK = "X-CallbackURL"; + public static final String HOST = "externalApiCallHost"; + public static final String CACHED_TRANSACTION_ID = "cachedTransactionId"; + public static final String TENANT_ID = "tenantId"; + public static final String INITIATOR_FSP_ID = "initiatorFspId"; + public static final String REGISTERING_INSTITUTION_ID = "X-Registering-Institution-ID"; + public static final String PAYER_IDENTIFIER = "payerIdentifier"; + public static final String PAYER_IDENTIFIER_TYPE = "payerIdentifierType"; + public static final String REQUEST_ID = "requestId"; + public static final String PAYEE_IDENTITY = "payeeIdentity"; + public static final String PAYMENT_MODALITY = "paymentModality"; + public static final String MAX_RETRY = "maxRetry"; + public static final String RETRY = "retry"; + public static final String THRESHOLD_DELAY = "thresholdDelay"; + public static final String TRANSACTION_COMPLETED = "transactionCompleted"; + public static final String PARTY_LOOKUP_FSP_ID = "partyLookupFspId"; + public static final String PAYMENT_ADVICE = "paymentAdvice"; + +} diff --git a/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/zeebe/worker/AccountLookupWorker.java b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/zeebe/worker/AccountLookupWorker.java new file mode 100644 index 000000000..6845da35e --- /dev/null +++ b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/zeebe/worker/AccountLookupWorker.java @@ -0,0 +1,111 @@ +package org.mifos.pheevouchermanagementsystem.zeebe.worker; + +import static org.mifos.connector.common.zeebe.ZeebeVariables.TRANSACTION_ID; +import static org.mifos.pheevouchermanagementsystem.camel.config.CamelProperties.PAYEE_PARTY_ID; +import static org.mifos.pheevouchermanagementsystem.camel.config.CamelProperties.PAYEE_PARTY_ID_TYPE; +import static org.mifos.pheevouchermanagementsystem.util.PaymentModalityEnum.getKeyByValue; +import static org.mifos.pheevouchermanagementsystem.zeebe.ZeebeVariables.ACCOUNT_LOOKUP_FAILED; +import static org.mifos.pheevouchermanagementsystem.zeebe.ZeebeVariables.CACHED_TRANSACTION_ID; +import static org.mifos.pheevouchermanagementsystem.zeebe.ZeebeVariables.CALLBACK; +import static org.mifos.pheevouchermanagementsystem.zeebe.ZeebeVariables.HOST; +import static org.mifos.pheevouchermanagementsystem.zeebe.ZeebeVariables.INITIATOR_FSP_ID; +import static org.mifos.pheevouchermanagementsystem.zeebe.ZeebeVariables.PARTY_LOOKUP_FSP_ID; +import static org.mifos.pheevouchermanagementsystem.zeebe.ZeebeVariables.PAYEE_IDENTITY; +import static org.mifos.pheevouchermanagementsystem.zeebe.ZeebeVariables.PAYER_IDENTIFIER; +import static org.mifos.pheevouchermanagementsystem.zeebe.ZeebeVariables.PAYER_IDENTIFIER_TYPE; +import static org.mifos.pheevouchermanagementsystem.zeebe.ZeebeVariables.PAYMENT_MODALITY; +import static org.mifos.pheevouchermanagementsystem.zeebe.ZeebeVariables.REGISTERING_INSTITUTION_ID; +import static org.mifos.pheevouchermanagementsystem.zeebe.ZeebeVariables.REQUEST_ID; +import static org.mifos.pheevouchermanagementsystem.zeebe.ZeebeVariables.TENANT_ID; +import static org.mifos.pheevouchermanagementsystem.zeebe.worker.Worker.ACCOUNT_LOOKUP; + +import com.fasterxml.jackson.databind.ObjectMapper; +import io.camunda.zeebe.client.ZeebeClient; +import java.util.Map; +import org.apache.camel.CamelContext; +import org.apache.camel.Exchange; +import org.apache.camel.ProducerTemplate; +import org.apache.camel.support.DefaultExchange; +import org.mifos.pheevouchermanagementsystem.data.AccountLookupResponseDTO; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +@Component +public class AccountLookupWorker extends BaseWorker { + + @Autowired + private ZeebeClient zeebeClient; + + @Autowired + private ProducerTemplate producerTemplate; + @Autowired + private CamelContext camelContext; + @Autowired + private ObjectMapper objectMapper; + @Value("${identity-account-mapper.hostname}") + private String identityMapperURL; + @Value("${voucher.hostname}") + private String voucherHostname; + @Value("${payer.tenant}") + private String payerTenant; + @Value("${payer.identifier}") + private String payerIdentifier; + @Value("${payer.identifierType}") + private String payerIdentifierType; + @Value("${zeebe.client.evenly-allocated-max-jobs}") + private int workerMaxJobs; + @Value("${defaultPaymentModality}") + private String paymentModality; + private static final Logger logger = LoggerFactory.getLogger(AccountLookupWorker.class); + + @Override + public void setup() { + logger.info("## generating " + ACCOUNT_LOOKUP + "zeebe worker"); + zeebeClient.newWorker().jobType("payee-account-Lookup-voucher").handler((client, job) -> { + logger.info("Job '{}' started from process '{}' with key {}", job.getType(), job.getBpmnProcessId(), job.getKey()); + Map existingVariables = job.getVariablesAsMap(); + existingVariables.put(CACHED_TRANSACTION_ID, job.getKey()); + existingVariables.put(PAYER_IDENTIFIER, payerIdentifier); + existingVariables.put(PAYER_IDENTIFIER_TYPE, payerIdentifierType); + + existingVariables.put(INITIATOR_FSP_ID, payerTenant); + existingVariables.put(REQUEST_ID, job.getKey()); + + Exchange exchange = new DefaultExchange(camelContext); + exchange.setProperty(HOST, identityMapperURL); + exchange.setProperty(CALLBACK, identityMapperURL + "/accountLookupCallback"); + exchange.setProperty(TRANSACTION_ID, existingVariables.get(TRANSACTION_ID)); + exchange.setProperty(REQUEST_ID, job.getKey()); + exchange.setProperty(REGISTERING_INSTITUTION_ID, existingVariables.get("registeringInstitutionId").toString()); + exchange.setProperty(PAYEE_IDENTITY, existingVariables.get("payeeIdentity").toString()); + exchange.setProperty(PAYMENT_MODALITY, paymentModality); + // exchange.setProperty("paymentModality", existingVariables.get("paymentModality").toString()); + producerTemplate.send("direct:send-account-lookup", exchange); + + existingVariables.put("statusCode", exchange.getIn().getHeader("CamelHttpResponseCode")); + + logger.info((existingVariables.get("statusCode").toString())); + + if (exchange.getIn().getHeader("CamelHttpResponseCode").toString().equals("200")) { + AccountLookupResponseDTO accountLookupResponseDTO = null; + + String response = exchange.getIn().getBody(String.class); + + accountLookupResponseDTO = objectMapper.readValue(response, AccountLookupResponseDTO.class); + existingVariables.put(ACCOUNT_LOOKUP_FAILED, false); + existingVariables.put(PAYEE_PARTY_ID, accountLookupResponseDTO.getPaymentModalityList().get(0).getFinancialAddress()); + existingVariables.put(PAYEE_PARTY_ID_TYPE, + getKeyByValue(accountLookupResponseDTO.getPaymentModalityList().get(0).getPaymentModality())); + existingVariables.put(TENANT_ID, accountLookupResponseDTO.getPaymentModalityList().get(0).getBankingInstitutionCode()); + existingVariables.put(PARTY_LOOKUP_FSP_ID, + accountLookupResponseDTO.getPaymentModalityList().get(0).getBankingInstitutionCode()); + } + + client.newCompleteCommand(job.getKey()).variables(existingVariables).send(); + }).name("payee-account-Lookup-voucher").maxJobsActive(workerMaxJobs).open(); + + } +} diff --git a/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/zeebe/worker/BaseWorker.java b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/zeebe/worker/BaseWorker.java new file mode 100644 index 000000000..c002f216a --- /dev/null +++ b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/zeebe/worker/BaseWorker.java @@ -0,0 +1,42 @@ +package org.mifos.pheevouchermanagementsystem.zeebe.worker; + +import com.fasterxml.jackson.databind.ObjectMapper; +import io.camunda.zeebe.client.ZeebeClient; +import io.camunda.zeebe.client.api.worker.JobHandler; +import javax.annotation.PostConstruct; +import org.apache.camel.CamelContext; +import org.apache.camel.ProducerTemplate; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +@Component +public abstract class BaseWorker { + + @Autowired + private ZeebeClient zeebeClient; + + @Autowired + private ObjectMapper objectMapper; + + @Value("${zeebe.client.evenly-allocated-max-jobs}") + private int workerMaxJobs; + + @Autowired + protected CamelContext camelContext; + + @Autowired + private ProducerTemplate producerTemplate; + + protected Logger logger = LoggerFactory.getLogger(this.getClass()); + + @PostConstruct + public abstract void setup(); + + public void newWorker(Worker worker, JobHandler handler) { + zeebeClient.newWorker().jobType(worker.getValue()).handler(handler).name(worker.getValue()).maxJobsActive(workerMaxJobs).open(); + } + +} diff --git a/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/zeebe/worker/BatchAuthorizationWorker.java b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/zeebe/worker/BatchAuthorizationWorker.java new file mode 100644 index 000000000..c8f062827 --- /dev/null +++ b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/zeebe/worker/BatchAuthorizationWorker.java @@ -0,0 +1,67 @@ +package org.mifos.pheevouchermanagementsystem.zeebe.worker; + +import static org.mifos.pheevouchermanagementsystem.zeebe.ZeebeVariables.CACHED_TRANSACTION_ID; +import static org.mifos.pheevouchermanagementsystem.zeebe.worker.Worker.BATCH_AUTH; + +import io.camunda.zeebe.client.ZeebeClient; +import io.restassured.RestAssured; +import io.restassured.builder.RequestSpecBuilder; +import io.restassured.builder.ResponseSpecBuilder; +import io.restassured.specification.RequestSpecification; +import java.math.BigDecimal; +import java.util.Map; +import org.apache.camel.CamelContext; +import org.apache.camel.ProducerTemplate; +import org.mifos.pheevouchermanagementsystem.data.AuthorizationRequest; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +@Component +public class BatchAuthorizationWorker extends BaseWorker { + + @Autowired + private ZeebeClient zeebeClient; + @Autowired + private ProducerTemplate producerTemplate; + @Autowired + private CamelContext camelContext; + @Value("${zeebe.client.evenly-allocated-max-jobs}") + private int workerMaxJobs; + @Value("${mock_schema.hostname}") + private String mockSchemaHostname; + @Value("${mock_schema.endpoints.batch_auth}") + private String batchAuthEndpoint; + @Value("${voucher.hostname}") + private String voucherHostname; + @Value("${payer.identifier}") + private String payerIdentifier; + + @Override + public void setup() { + logger.info("## generating " + BATCH_AUTH.getValue() + "zeebe worker"); + zeebeClient.newWorker().jobType(BATCH_AUTH.getValue()).handler((client, job) -> { + logger.info("Job '{}' started from process '{}' with key {}", job.getType(), job.getBpmnProcessId(), job.getKey()); + Map existingVariables = job.getVariablesAsMap(); + existingVariables.put(CACHED_TRANSACTION_ID, job.getKey()); + RequestSpecification requestSpec = new RequestSpecBuilder().build(); + requestSpec.relaxedHTTPSValidation(); + requestSpec.header("X-Client-Correlation-ID", job.getKey()); + requestSpec.header("Content-Type", "application/json"); + requestSpec.header("X-CallbackURL", voucherHostname + "/authorization/callbacks"); + requestSpec.queryParam("command", "authorize"); + batchAuthEndpoint = batchAuthEndpoint + existingVariables.get("batchId").toString(); + AuthorizationRequest authorizationRequest = new AuthorizationRequest(); + authorizationRequest.setBatchId(existingVariables.get("batchId").toString()); + authorizationRequest.setPayerIdentifier(payerIdentifier); + String totalAmount = existingVariables.get("totalAmount").toString(); + authorizationRequest.setAmount(new BigDecimal(totalAmount)); + authorizationRequest.setCurrency(existingVariables.get("currency").toString()); + + String response = RestAssured.given(requestSpec).baseUri(mockSchemaHostname).body(authorizationRequest).expect() + .spec(new ResponseSpecBuilder().build()).when().post(batchAuthEndpoint).andReturn().asString(); + + client.newCompleteCommand(job.getKey()).variables(existingVariables).send(); + }).name(BATCH_AUTH.getValue()).maxJobsActive(workerMaxJobs).open(); + } +} diff --git a/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/zeebe/worker/CheckTransferStatusWorker.java b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/zeebe/worker/CheckTransferStatusWorker.java new file mode 100644 index 000000000..2f83339ea --- /dev/null +++ b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/zeebe/worker/CheckTransferStatusWorker.java @@ -0,0 +1,115 @@ +package org.mifos.pheevouchermanagementsystem.zeebe.worker; + +import static org.mifos.pheevouchermanagementsystem.util.VoucherStatusEnum.ACTIVE; +import static org.mifos.pheevouchermanagementsystem.zeebe.ZeebeVariables.MAX_RETRY; +import static org.mifos.pheevouchermanagementsystem.zeebe.ZeebeVariables.RETRY; +import static org.mifos.pheevouchermanagementsystem.zeebe.ZeebeVariables.THRESHOLD_DELAY; +import static org.mifos.pheevouchermanagementsystem.zeebe.ZeebeVariables.TRANSACTION_COMPLETED; + +import io.camunda.zeebe.client.ZeebeClient; +import io.restassured.RestAssured; +import io.restassured.builder.RequestSpecBuilder; +import io.restassured.builder.ResponseSpecBuilder; +import io.restassured.specification.RequestSpecification; +import java.util.Map; +import javax.annotation.PostConstruct; +import org.json.JSONArray; +import org.json.JSONObject; +import org.mifos.pheevouchermanagementsystem.domain.Voucher; +import org.mifos.pheevouchermanagementsystem.exception.VoucherNotFoundException; +import org.mifos.pheevouchermanagementsystem.repository.VoucherRepository; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +@Component +public class CheckTransferStatusWorker { + + @Autowired + private ZeebeClient zeebeClient; + + @Value("${operations.hostname}") + private String operationHostname; + @Value("${operations.endpoints.transfers}") + public String transfersEndpoint; + @Value("${maxRetry}") + private int maxRetry; + @Value("${thresholdDelay}") + private String thresholdDelay; + + @Autowired + private VoucherRepository voucherRepository; + + private static final Logger logger = LoggerFactory.getLogger(CheckTransferStatusWorker.class); + + @PostConstruct + public void setup() { + zeebeClient.newWorker().jobType("check-transfer-status").handler((client, job) -> { + logger.info("Job '{}' started from process '{}' with key {}", job.getType(), job.getBpmnProcessId(), job.getKey()); + + Map existingVariables = job.getVariablesAsMap(); + + existingVariables.put(THRESHOLD_DELAY, thresholdDelay); + existingVariables.put(MAX_RETRY, maxRetry); + existingVariables.put(TRANSACTION_COMPLETED, false); + + int retry = existingVariables.getOrDefault(RETRY, 0).equals(existingVariables.get(MAX_RETRY)) ? 0 + : (int) existingVariables.getOrDefault(RETRY, 0); + if (retry <= maxRetry) { + logger.info("No of retry {} of max retry count {}", retry, maxRetry); + RequestSpecification requestSpec = new RequestSpecBuilder().build(); + requestSpec.relaxedHTTPSValidation(); + requestSpec.header("Platform-TenantId", existingVariables.get("partyLookupFspId").toString()); + requestSpec.header("Content-Type", "application/json"); + String clientCorrelationId = existingVariables.get("clientCorrelationId").toString(); + + String response = RestAssured.given(requestSpec).baseUri(operationHostname).expect() + .spec(new ResponseSpecBuilder().expectStatusCode(200).build()).when() + .get(transfersEndpoint + "&clientCorrelationId=" + clientCorrelationId).andReturn().asString(); + + JSONObject responseJson = new JSONObject(response); + String status = null; + if (responseJson.has("content")) { + JSONArray contentArray = responseJson.getJSONArray("content"); + logger.info("content length {}", contentArray.length()); + if (contentArray.length() > 0) { + JSONObject contentObject = contentArray.getJSONObject(0); + logger.info("content object {}", contentObject.has("status")); + if (contentObject.has("status")) { + status = contentObject.getString("status"); + } + } else { + retry++; + existingVariables.put(RETRY, retry); + } + } + + if (status != null) { + if (!status.equals("COMPLETED")) { + try { + Voucher voucher = voucherRepository.findBySerialNo(existingVariables.get("voucherSerialNumber").toString()) + .orElseThrow(() -> VoucherNotFoundException + .voucherNotFound(existingVariables.get("voucherSerialNumber").toString())); + voucher.setStatus(ACTIVE.getValue()); + existingVariables.put(TRANSACTION_COMPLETED, false); + logger.info("Updating voucher status as ACTIVE redemption FAILED"); + voucherRepository.save(voucher); + } catch (RuntimeException e) { + logger.error(e.getMessage()); + } + } + if (status.equals("COMPLETED")) { + existingVariables.put(TRANSACTION_COMPLETED, true); + existingVariables.put("status", status); + } + } + logger.info("Updating status zeebe variable"); + + } + + client.newCompleteCommand(job.getKey()).variables(existingVariables).send(); + }).name("check-transfer-status").open(); + } +} diff --git a/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/zeebe/worker/CreateVoucherWorker.java b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/zeebe/worker/CreateVoucherWorker.java new file mode 100644 index 000000000..f573c857a --- /dev/null +++ b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/zeebe/worker/CreateVoucherWorker.java @@ -0,0 +1,81 @@ +package org.mifos.pheevouchermanagementsystem.zeebe.worker; + +import static org.mifos.pheevouchermanagementsystem.zeebe.worker.Worker.CREATE_VOUCHERS; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import io.camunda.zeebe.client.ZeebeClient; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import org.apache.camel.CamelContext; +import org.apache.camel.ProducerTemplate; +import org.json.JSONArray; +import org.mifos.pheevouchermanagementsystem.data.CallbackRequestDTO; +import org.mifos.pheevouchermanagementsystem.data.SuccessfulVouchers; +import org.mifos.pheevouchermanagementsystem.data.VoucherInstruction; +import org.mifos.pheevouchermanagementsystem.domain.ErrorTracking; +import org.mifos.pheevouchermanagementsystem.service.CreateVoucherService; +import org.mifos.pheevouchermanagementsystem.service.SendCallbackService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +@Component +public class CreateVoucherWorker extends BaseWorker { + + @Autowired + private ZeebeClient zeebeClient; + @Autowired + private ProducerTemplate producerTemplate; + @Autowired + private CamelContext camelContext; + @Value("${zeebe.client.evenly-allocated-max-jobs}") + private int workerMaxJobs; + @Autowired + private CreateVoucherService createVoucherService; + @Autowired + private SendCallbackService sendCallbackService; + @Autowired + private ObjectMapper objectMapper; + + @Override + public void setup() { + logger.info("## generating " + CREATE_VOUCHERS.getValue() + "zeebe worker"); + zeebeClient.newWorker().jobType(CREATE_VOUCHERS.getValue()).handler((client, job) -> { + logger.info("Job '{}' started from process '{}' with key {}", job.getType(), job.getBpmnProcessId(), job.getKey()); + Map existingVariables = job.getVariablesAsMap(); + String status = existingVariables.get("status").toString(); + String callbackURL = existingVariables.get("callbackURL").toString(); + + if (status.equals("Y")) { + List errorTrackingsList = new ArrayList<>(); + List successfulVouchers = new ArrayList<>(); + List voucherInstructionList = (List) existingVariables.get("instructionList"); + String requestId = existingVariables.get("requestId").toString(); + String batchId = existingVariables.get("batchId").toString(); + ObjectMapper mapper = new ObjectMapper(); + String jsonString = new JSONArray(voucherInstructionList).toString(); + List voucherInstructions = mapper.readValue(jsonString, + new TypeReference>() {}); + + for (VoucherInstruction voucherInstruction : voucherInstructions) { + createVoucherService.addVouchers(voucherInstruction, successfulVouchers, errorTrackingsList, + existingVariables.get("registeringInstitutionId").toString(), batchId, requestId); + } + try { + sendCallbackService.sendCallback( + objectMapper.writeValueAsString(new CallbackRequestDTO(requestId, batchId, successfulVouchers)), callbackURL); + } catch (JsonProcessingException e) { + logger.error(e.getMessage()); + } + + } else { + sendCallbackService.sendCallback("Voucher Creation Failed!", callbackURL); + } + + client.newCompleteCommand(job.getKey()).variables(existingVariables).send(); + }).name(CREATE_VOUCHERS.getValue()).maxJobsActive(workerMaxJobs).open(); + } +} diff --git a/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/zeebe/worker/SendCallbackWorker.java b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/zeebe/worker/SendCallbackWorker.java new file mode 100644 index 000000000..18569992b --- /dev/null +++ b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/zeebe/worker/SendCallbackWorker.java @@ -0,0 +1,56 @@ +package org.mifos.pheevouchermanagementsystem.zeebe.worker; + +import static org.mifos.pheevouchermanagementsystem.util.RedemptionStatusEnum.SUCCESS; +import static org.mifos.pheevouchermanagementsystem.zeebe.ZeebeVariables.PAYMENT_ADVICE; +import static org.mifos.pheevouchermanagementsystem.zeebe.worker.Worker.VOUCHER_STATUS_SEND_CALLBACK; + +import com.fasterxml.jackson.databind.ObjectMapper; +import io.camunda.zeebe.client.ZeebeClient; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.util.Map; +import org.mifos.pheevouchermanagementsystem.data.RedeemVoucherResponseDTO; +import org.mifos.pheevouchermanagementsystem.service.SendCallbackService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component +public class SendCallbackWorker extends BaseWorker { + + @Autowired + private ZeebeClient zeebeClient; + @Autowired + private SendCallbackService sendCallbackService; + private static final Logger logger = LoggerFactory.getLogger(SendCallbackWorker.class); + + @Override + public void setup() { + logger.info("## generating " + VOUCHER_STATUS_SEND_CALLBACK + "zeebe worker"); + zeebeClient.newWorker().jobType(VOUCHER_STATUS_SEND_CALLBACK.getValue()).handler((client, job) -> { + logger.info("Job '{}' started from process '{}' with key {}", job.getType(), job.getBpmnProcessId(), job.getKey()); + + Map existingVariables = job.getVariablesAsMap(); + if (existingVariables.get(PAYMENT_ADVICE).equals(true)) { + RedeemVoucherResponseDTO redeemVoucherResponseDTO = new RedeemVoucherResponseDTO(SUCCESS.getValue(), + "Voucher redemption successful", existingVariables.get("voucherSerialNumber").toString(), null, + LocalDateTime.now(ZoneId.systemDefault()).toString(), existingVariables.get("transactionId").toString()); + ObjectMapper objectMapper = new ObjectMapper(); + String body = objectMapper.writeValueAsString(redeemVoucherResponseDTO); + logger.info("Sending callback on URL: {}", existingVariables.get("callbackURL")); + sendCallbackService.sendCallback(body, existingVariables.get("callbackURL").toString()); + } else { + RedeemVoucherResponseDTO redeemVoucherResponseDTO = new RedeemVoucherResponseDTO(SUCCESS.getValue(), + "Voucher redemption successful", existingVariables.get("voucherSerialNumber").toString(), null, + LocalDateTime.now(ZoneId.systemDefault()).toString(), existingVariables.get("transactionId").toString()); + ObjectMapper objectMapper = new ObjectMapper(); + String body = objectMapper.writeValueAsString(redeemVoucherResponseDTO); + logger.info("Sending callback on URL: {}", existingVariables.get("callbackURL")); + sendCallbackService.sendCallback(body, existingVariables.get("callbackURL").toString()); + } + + client.newCompleteCommand(job.getKey()).variables(existingVariables).send(); + }).name(VOUCHER_STATUS_SEND_CALLBACK.getValue()).open(); + } +} diff --git a/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/zeebe/worker/SendErrorWorker.java b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/zeebe/worker/SendErrorWorker.java new file mode 100644 index 000000000..24697f71d --- /dev/null +++ b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/zeebe/worker/SendErrorWorker.java @@ -0,0 +1,52 @@ +package org.mifos.pheevouchermanagementsystem.zeebe.worker; + +import static org.mifos.pheevouchermanagementsystem.util.VoucherStatusEnum.ACTIVE; + +import com.fasterxml.jackson.databind.ObjectMapper; +import io.camunda.zeebe.client.ZeebeClient; +import java.util.Map; +import javax.annotation.PostConstruct; +import org.apache.camel.CamelContext; +import org.apache.camel.ProducerTemplate; +import org.mifos.pheevouchermanagementsystem.domain.Voucher; +import org.mifos.pheevouchermanagementsystem.exception.VoucherNotFoundException; +import org.mifos.pheevouchermanagementsystem.repository.VoucherRepository; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component +public class SendErrorWorker { + + @Autowired + private ZeebeClient zeebeClient; + + @Autowired + private ProducerTemplate producerTemplate; + @Autowired + private CamelContext camelContext; + @Autowired + private ObjectMapper objectMapper; + @Autowired + private VoucherRepository voucherRepository; + + private static final Logger logger = LoggerFactory.getLogger(SendErrorWorker.class); + + @PostConstruct + public void setup() { + zeebeClient.newWorker().jobType("send-failure-voucher").handler((client, job) -> { + logger.info("Job '{}' started from process '{}' with key {}", job.getType(), job.getBpmnProcessId(), job.getKey()); + Map existingVariables = job.getVariablesAsMap(); + try { + Voucher voucher = voucherRepository.findBySerialNo(existingVariables.get("voucherSerialNumber").toString()).orElseThrow( + () -> VoucherNotFoundException.voucherNotFound(existingVariables.get("voucherSerialNumber").toString())); + voucher.setStatus(ACTIVE.getValue()); + voucherRepository.save(voucher); + } catch (RuntimeException e) { + logger.error(e.getMessage()); + } + client.newCompleteCommand(job.getKey()).variables(existingVariables).send(); + }).name("send-failure-voucher").open(); + } +} diff --git a/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/zeebe/worker/Worker.java b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/zeebe/worker/Worker.java new file mode 100644 index 000000000..42ac1c420 --- /dev/null +++ b/ph-ee-vouchers/src/main/java/org/mifos/pheevouchermanagementsystem/zeebe/worker/Worker.java @@ -0,0 +1,17 @@ +package org.mifos.pheevouchermanagementsystem.zeebe.worker; + +public enum Worker { + + ACCOUNT_LOOKUP("payee-account-Lookup"), ACCOUNT_LOOKUP_CALLBACK("account-lookup-callback"), BATCH_AUTH( + "call-batch-authorization"), CREATE_VOUCHERS("create-vouchers"), VOUCHER_STATUS_SEND_CALLBACK("voucher-status-send-callback"); + + private final String value; + + Worker(String s) { + value = s; + } + + public String getValue() { + return value; + } +} diff --git a/ph-ee-vouchers/src/main/resources/application.properties b/ph-ee-vouchers/src/main/resources/application.properties new file mode 100644 index 000000000..8b1378917 --- /dev/null +++ b/ph-ee-vouchers/src/main/resources/application.properties @@ -0,0 +1 @@ + diff --git a/ph-ee-vouchers/src/main/resources/application.yml b/ph-ee-vouchers/src/main/resources/application.yml new file mode 100644 index 000000000..6aa329296 --- /dev/null +++ b/ph-ee-vouchers/src/main/resources/application.yml @@ -0,0 +1,89 @@ +server: + port: 8080 + +spring: + datasource: + url: jdbc:mysql://operationsmysql:3306/voucher_management + username: root + password: mysql + driver-class-name: com.mysql.cj.jdbc.Driver + liquibase: + enabled: true + default-schema: voucher_management + change-log: classpath:/db/changelog/changelog.xml + clear-checksums: true + +logging: + level: + ROOT: INFO + +async: + core_pool_size: 10 + max_pool_size: 10 + queue_capacity: 100 + +expiry_time: 60 + +salting: + enabled: true + +identity-account-mapper: + hostname : "https://identity-mapper.sandbox.mifos.io/" + +zeebe: + client: + max-execution-threads: 50 + evenly-allocated-max-jobs: 1000 + poll-interval: 10 + # number-of-workers: 15 + # evenly-allocated-max-jobs: "#{${zeebe.client.max-execution-threads} / ${zeebe.client.number-of-workers}}" + broker: + contactpoint: "localhost:26500" + +camel: + serverPort: 5050 + disable-ssl: false + springboot: + main-run-controller: true + dataformat: + json-jackson: + auto-discover-object-mapper: true + +payer: + tenant: rhino + identifier: 12345678 + identifierType: MSISDN + +voucher: + hostname: "https://vouchers.sandbox.mifos.io" +operations: + hostname: "https://ops-bk.sandbox.mifos.io" + endpoints: + transfers: "/api/v1/transfers?size=1&page=0" + +mock_schema: + hostname: "http://mockpaymentschema.sandbox.fynarfin.io" + endpoints: + batch_auth: "/batches/" + +rsa-key: + private: "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC07fxdEQlsvWvggBgrork401cdyZ9MqV6FF/RgX6+Om23gP/rME5sE5//OoG61KU3dEj9phcHH845TuyNEyc4Vhqxe1gzl4VIZkOj+/2qxYvCsP1Sv3twTs+fDfFv5NA1ZXqiswTlgjR2Lpf1tevFQEOzB9WYvH/Bu9kgr2AlHMPV6+b7gcJij/7W1hndiCk2ahbi7oXjjODF4yEU9yNAhopibe4zzMX+FO4eFYpUmrjS5wvv6aAanfoeIMTwhF81Gj9V3rHf4UsD3VEx773q7GPuXlZSLyiNrUCdvxITh+dW8Y9ICuCTy3bFbp1/HzoPdzkkUlzPNKLlLiV2w4EcxAgMBAAECggEAMjqHfwbFyQxlMHQfQa3xIdd6LejVcqDqfqSB0Wd/A2YfAMyCQbmHpbsKh0B+u4h191OjixX5EBuLfa9MQUKNFejHXaSq+/6rnjFenbwm0IwZKJiEWDbUfhvJ0blqhypuMktXJG6YETfb5fL1AjnJWGL6d3Y7IgYJ56QzsQhOuxZidSqw468xc4sIF0CoTeJdrSC2yDCVuVlLNifm/2SXBJD8mgc1WCz0rkJhvvpW4k5G9rRSkS5f0013ZNfsfiDXoqiKkafoYNEbk7TZQNInqSuONm/UECn5GLm6IXdXSGfm1O2Lt0Kk7uxW/3W00mIPeZD+hiOObheRm/2HoOEKiQKBgQDreVFQihXAEDviIB2s6fphvPcMw/IonE8tX565i3303ubQMDIyZmsi3apN5pqSjm1TKq1KIgY2D4vYTu6vO5x9MhEO2CCZWNwC+awrIYa32FwiT8D8eZ9g+DJ4/IwXyz1fG38RCz/eIsJ0NsS9z8RKBIbfMmM+WnXRez3Fq+cbRwKBgQDEs35qXThbbFUYo1QkO0vIo85iczu9NllRxo1nAqQkfu1oTYQQobxcGk/aZk0B02r9kt2eob8zfG+X3LadIhQ0/LalnGNKI9jWLkdW4dxi7xMU99MYc3NRXmR49xGxgOVkLzKyGMisUvkTnE5v/S1nhu5uFr3JPkWcCScLOTjVxwKBgHNWsDq3+GFkUkC3pHF/BhJ7wbLyA5pavfmmnZOavO6FhB8zjFLdkdq5IuMXcl0ZAHm9LLZkJhCy2rfwKb+RflxgerR/rrAOM24Np4RU3q0MgEyaLhg85pFT4T0bzu8UsRH14O6TSQxgkEjmTsX+j9IFl56aCryPCKi8Kgy53/CfAoGAdV2kUFLPDb3WCJ1r1zKKRW1398ZKHtwO73xJYu1wg1Y40cNuyX23pj0M6IOh7zT24dZ/5ecc7tuQukw3qgprhDJFyQtHMzWwbBuw9WZO2blM6XX1vuEkLajkykihhggi12RSG3IuSqQ3ejwJkUi/jsYz/fwTwcAmSLQtV8UM5IECgYEAh4h1EkMx3NXzVFmLsb4QLMXw8+Rnn9oG+NGObldQ+nmknUPu7iz5kl9lTJy+jWtqHlHL8ZtV1cZZSZnFxX5WQH5/lcz/UD+GqWoSlWuTU34PPTJqLKSYgkoOJQDEZVMVphLySS9tuo+K/h10lRS1r9KDm3RZASa1JnnWopBZIz4=" + public: "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtO38XREJbL1r4IAYK6K5ONNXHcmfTKlehRf0YF+vjptt4D/6zBObBOf/zqButSlN3RI/aYXBx/OOU7sjRMnOFYasXtYM5eFSGZDo/v9qsWLwrD9Ur97cE7Pnw3xb+TQNWV6orME5YI0di6X9bXrxUBDswfVmLx/wbvZIK9gJRzD1evm+4HCYo/+1tYZ3YgpNmoW4u6F44zgxeMhFPcjQIaKYm3uM8zF/hTuHhWKVJq40ucL7+mgGp36HiDE8IRfNRo/Vd6x3+FLA91RMe+96uxj7l5WUi8oja1Anb8SE4fnVvGPSArgk8t2xW6dfx86D3c5JFJczzSi5S4ldsOBHMQIDAQAB" + +management: + endpoint: + health: + probes: + enabled: true + liveness: + enabled: true + readiness: + enabled: true + +defaultPaymentModality: "01" +maxRetry: 3 +thresholdDelay: "PT2S" + +paymentAdvice: false + +default_headers: "user-agent,accept,postman-token,host,accept-encoding,connection,content-type,content-length,x-request-id,x-real-ip,x-forwarded-host,x-forwarded-port,x-forwarded-proto,x-forwarded-scheme,x-scheme" \ No newline at end of file diff --git a/ph-ee-vouchers/src/main/resources/db/changelog/01-create-voucher-table.xml b/ph-ee-vouchers/src/main/resources/db/changelog/01-create-voucher-table.xml new file mode 100644 index 000000000..ab2f9eebc --- /dev/null +++ b/ph-ee-vouchers/src/main/resources/db/changelog/01-create-voucher-table.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ph-ee-vouchers/src/main/resources/db/changelog/02-create-error-table.xml b/ph-ee-vouchers/src/main/resources/db/changelog/02-create-error-table.xml new file mode 100644 index 000000000..d4b0d8dc3 --- /dev/null +++ b/ph-ee-vouchers/src/main/resources/db/changelog/02-create-error-table.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + diff --git a/ph-ee-vouchers/src/main/resources/db/changelog/03-alter-voucher-table.xml b/ph-ee-vouchers/src/main/resources/db/changelog/03-alter-voucher-table.xml new file mode 100644 index 000000000..69c414c2c --- /dev/null +++ b/ph-ee-vouchers/src/main/resources/db/changelog/03-alter-voucher-table.xml @@ -0,0 +1,12 @@ + + + + + + + + + \ No newline at end of file diff --git a/ph-ee-vouchers/src/main/resources/db/changelog/changelog.xml b/ph-ee-vouchers/src/main/resources/db/changelog/changelog.xml new file mode 100644 index 000000000..91f924e0c --- /dev/null +++ b/ph-ee-vouchers/src/main/resources/db/changelog/changelog.xml @@ -0,0 +1,8 @@ + + + + + diff --git a/ph-ee-vouchers/src/test/java/org/mifos/pheevouchermanagementsystem/PhEeVoucherManagementSystemApplicationTests.java b/ph-ee-vouchers/src/test/java/org/mifos/pheevouchermanagementsystem/PhEeVoucherManagementSystemApplicationTests.java new file mode 100644 index 000000000..587bac2a0 --- /dev/null +++ b/ph-ee-vouchers/src/test/java/org/mifos/pheevouchermanagementsystem/PhEeVoucherManagementSystemApplicationTests.java @@ -0,0 +1,12 @@ +package org.mifos.pheevouchermanagementsystem; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +class PhEeVoucherManagementSystemApplicationTests { + + @Test + void contextLoads() {} + +} diff --git a/ph-ee-zeebe-ops/.circleci/config.yml b/ph-ee-zeebe-ops/.circleci/config.yml new file mode 100644 index 000000000..c085cda54 --- /dev/null +++ b/ph-ee-zeebe-ops/.circleci/config.yml @@ -0,0 +1,98 @@ +version: 2.1 +executors: + docker-executor: + docker: + - image: circleci/openjdk:17-buster-node-browsers-legacy + +jobs: + build_and_push_tag_image: + executor: docker-executor + environment: + JVM_OPTS: -Xmx512m + TERM: dumb + GITHUB_TOKEN: ${GITHUB_TOKEN} # Add the GitHub token as an environment variable + + steps: + - checkout + - setup_remote_docker: + version: 20.10.24 + - run: + name: Build and Push Docker tag Image + command: | + # Set environment variables + IMAGE_TAG=$CIRCLE_TAG + + # Check if the Docker image with the same tag already exists in Docker Hub + if curl -s -f -u "$DOCKERHUB_USERNAME":"$DOCKERHUB_PASSWORD" "https://hub.docker.com/v2/repositories/fynarfin/ph-ee-zeebe-ops/tags/$IMAGE_TAG" > /dev/null; then + echo "Skipping the build and push as the tag $IMAGE_TAG already exists in Docker Hub." + exit 0 + fi + + # Build and tag the Docker image + ./gradlew bootJar + docker build -t "fynarfin/ph-ee-zeebe-ops:$IMAGE_TAG" . + + # Push the Docker image to Docker Hub + docker login -u "$DOCKERHUB_USERNAME" -p "$DOCKERHUB_PASSWORD" + docker push "fynarfin/ph-ee-zeebe-ops:$IMAGE_TAG" + + # when: always # The job will be executed even if there's no match for the tag filter + + build_and_push_latest_image: + executor: docker-executor + environment: + JVM_OPTS: -Xmx512m + TERM: dumb + + steps: + - checkout + # Install Docker to build and push the image + - setup_remote_docker: + version: 20.10.24 + + # Build the Docker image + - run: + name: Build Docker image + command: | + ./gradlew bootJar + docker build -t fynarfin/ph-ee-zeebe-ops:latest . + if [ "$CIRCLE_BRANCH" != "develop" ]; then + PR_NUMBER=$(basename $CIRCLE_PULL_REQUEST) + PR_TITLE=$(curl -sSL "https://api.github.com/repos/fynarfin/$CIRCLE_PR_REPONAME/pulls/$PR_NUMBER" | jq -r '.title') + JIRA_STORY=$(echo $PR_TITLE | cut -d "[" -f2 | cut -d "]" -f1 | tr '[A-Z]' '[a-z]') + if [ -z "$JIRA_STORY" ]; then echo "Invalid PR title" && exit 1; else echo "Ticket NO: $JIRA_STORY"; fi + docker image tag fynarfin/$CIRCLE_PR_REPONAME:latest fynarfin/$CIRCLE_PR_REPONAME:$JIRA_STORY + fi + + # Log in to DockerHub using environment variables + - run: + name: Login to DockerHub + command: echo "${DOCKERHUB_PASSWORD}" | docker login -u "${DOCKERHUB_USERNAME}" --password-stdin + + # Push the Docker image to DockerHub + - run: + name: Push Docker image to DockerHub + command: | + if [ "$CIRCLE_BRANCH" = "develop" ]; then + docker push fynarfin/ph-ee-zeebe-ops:latest + fi + if [ "$CIRCLE_BRANCH" != "develop" ]; then + PR_NUMBER=$(basename $CIRCLE_PULL_REQUEST) + PR_TITLE=$(curl -sSL "https://api.github.com/repos/fynarfin/$CIRCLE_PR_REPONAME/pulls/$PR_NUMBER" | jq -r '.title') + JIRA_STORY=$(echo $PR_TITLE | cut -d "[" -f2 | cut -d "]" -f1 | tr '[A-Z]' '[a-z]') + docker push fynarfin/$CIRCLE_PR_REPONAME:${JIRA_STORY} + fi +workflows: + version: 2 + build-and-push: + jobs: + - build_and_push_tag_image: + filters: + tags: + only: /^v\d+\.\d+\.\d+$/ # Match tags in the format v1.2.3 + context: + - DOCKER + - build_and_push_latest_image: + context: + - DOCKER + diff --git a/ph-ee-zeebe-ops/.github/pull_request_template.md b/ph-ee-zeebe-ops/.github/pull_request_template.md new file mode 100644 index 000000000..9110b69d4 --- /dev/null +++ b/ph-ee-zeebe-ops/.github/pull_request_template.md @@ -0,0 +1,22 @@ +## Description + +* PR title should have jira ticket enclosed in `[]`.
+ Format: ``` [jira_ticket] description```
+ ex: [phee-123] PR title. +* Add a link to the Jira ticket. +* Describe the changes made and why they were made. + +## Checklist + +Please make sure these boxes are checked before submitting your pull request - thanks! +- [ ] Followed the PR title naming convention mentioned above. + +- [ ] Design related bullet points or design document link related to this PR added in the description above. + +- [ ] Updated corresponding Postman Collection or Api documentation for the changes in this PR. + +- [ ] Create/update unit or integration tests for verifying the changes made. + +- [ ] Add required Swagger annotation and update API documentation with details of any API changes if applicable + +- [ ] Followed the naming conventions as given in https://docs.google.com/document/d/1Q4vaMSzrTxxh9TS0RILuNkSkYCxotuYk1Xe0CMIkkCU/edit?usp=sharing diff --git a/ph-ee-zeebe-ops/.gitignore b/ph-ee-zeebe-ops/.gitignore new file mode 100644 index 000000000..eb9d61054 --- /dev/null +++ b/ph-ee-zeebe-ops/.gitignore @@ -0,0 +1,43 @@ +HELP.md +.gradle +build/ +!gradle/wrapper/gradle-wrapper.jar +!**/src/main/**/build/ +!**/src/test/**/build/ + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache +bin/ +!**/src/main/**/bin/ +!**/src/test/**/bin/ + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr +out/ +!**/src/main/**/out/ +!**/src/test/**/out/ + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ + +### VS Code ### +.vscode/ + +### mac ### +.DS_Store + +### BPMN upload location ### +upload diff --git a/ph-ee-zeebe-ops/Dockerfile b/ph-ee-zeebe-ops/Dockerfile new file mode 100755 index 000000000..addb65871 --- /dev/null +++ b/ph-ee-zeebe-ops/Dockerfile @@ -0,0 +1,5 @@ +FROM openjdk:13 + +COPY build/libs/*.jar ./ +CMD java -jar *.jar + diff --git a/ph-ee-zeebe-ops/Readme.md b/ph-ee-zeebe-ops/Readme.md new file mode 100755 index 000000000..d7a593988 --- /dev/null +++ b/ph-ee-zeebe-ops/Readme.md @@ -0,0 +1,3 @@ +# Zeebe operations Microservice + +This microservice is responsible for fetching, modifying and starting the Zeebe's operations \ No newline at end of file diff --git a/ph-ee-zeebe-ops/build.gradle b/ph-ee-zeebe-ops/build.gradle new file mode 100755 index 000000000..1674293c0 --- /dev/null +++ b/ph-ee-zeebe-ops/build.gradle @@ -0,0 +1,44 @@ +plugins { + id 'org.springframework.boot' version '2.5.5' + id 'io.spring.dependency-management' version '1.0.11.RELEASE' + id 'java' +} + +group = 'org.mifos' +version = '0.0.1-SNAPSHOT' +sourceCompatibility = '11' + +repositories { + mavenCentral() + mavenLocal() + maven { + url = uri('https://jfrog.sandbox.fynarfin.io/artifactory/fyn-libs-snapshot') + } +} + +ext { + springBootVersion = '2.5.5' +} + +dependencies { + implementation 'org.mifos:ph-ee-connector-common:1.0.0-SNAPSHOT' + implementation 'org.apache.camel.springboot:camel-spring-boot-starter:3.4.0' + implementation 'org.apache.camel:camel-bean-validator:3.4.0' + implementation 'org.apache.camel:camel-undertow:3.4.0' + implementation 'org.apache.camel.springboot:camel-jackson-starter:3.4.0' + implementation 'io.camunda:zeebe-client-java:8.1.1' + implementation 'io.netty:netty-bom:4.1.65.Final' + implementation 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.13.1' + implementation 'org.json:json:20211205' + implementation 'org.springframework.boot:spring-boot-starter-data-elasticsearch' + implementation 'org.springframework.boot:spring-boot-starter-web' + implementation 'javax.mail:mail:1.4.7' + testImplementation 'org.springframework.boot:spring-boot-starter-test' + implementation "org.springframework.boot:spring-boot-starter:$springBootVersion" + implementation "org.springframework.boot:spring-boot-starter-web:$springBootVersion" + implementation "org.springframework.boot:spring-boot-starter-actuator:$springBootVersion" +} + +test { + useJUnitPlatform() +} diff --git a/ph-ee-zeebe-ops/gradle/wrapper/gradle-wrapper.jar b/ph-ee-zeebe-ops/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 000000000..7454180f2 Binary files /dev/null and b/ph-ee-zeebe-ops/gradle/wrapper/gradle-wrapper.jar differ diff --git a/ph-ee-zeebe-ops/gradle/wrapper/gradle-wrapper.properties b/ph-ee-zeebe-ops/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 000000000..ffed3a254 --- /dev/null +++ b/ph-ee-zeebe-ops/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-bin.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/ph-ee-zeebe-ops/gradlew b/ph-ee-zeebe-ops/gradlew new file mode 100755 index 000000000..1b6c78733 --- /dev/null +++ b/ph-ee-zeebe-ops/gradlew @@ -0,0 +1,234 @@ +#!/bin/sh + +# +# Copyright © 2015-2021 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit + +APP_NAME="Gradle" +APP_BASE_NAME=${0##*/} + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/ph-ee-zeebe-ops/gradlew.bat b/ph-ee-zeebe-ops/gradlew.bat new file mode 100755 index 000000000..ac1b06f93 --- /dev/null +++ b/ph-ee-zeebe-ops/gradlew.bat @@ -0,0 +1,89 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/ph-ee-zeebe-ops/settings.gradle b/ph-ee-zeebe-ops/settings.gradle new file mode 100755 index 000000000..40e4915d3 --- /dev/null +++ b/ph-ee-zeebe-ops/settings.gradle @@ -0,0 +1 @@ +rootProject.name = 'ph-ee-zeebe-ops' diff --git a/ph-ee-zeebe-ops/src/main/java/org/mifos/ops/zeebe/ZeebeOpsApplication.java b/ph-ee-zeebe-ops/src/main/java/org/mifos/ops/zeebe/ZeebeOpsApplication.java new file mode 100644 index 000000000..a47f3309f --- /dev/null +++ b/ph-ee-zeebe-ops/src/main/java/org/mifos/ops/zeebe/ZeebeOpsApplication.java @@ -0,0 +1,146 @@ +package org.mifos.ops.zeebe; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; +import org.apache.http.HttpHost; +import org.apache.http.auth.AuthScope; +import org.apache.http.auth.UsernamePasswordCredentials; +import org.apache.http.client.CredentialsProvider; +import org.apache.http.conn.ssl.NoopHostnameVerifier; +import org.apache.http.impl.client.BasicCredentialsProvider; +import org.apache.http.impl.nio.client.HttpAsyncClientBuilder; +import org.apache.http.impl.nio.reactor.IOReactorConfig; +import org.apache.http.ssl.SSLContextBuilder; +import org.apache.http.ssl.SSLContexts; +import org.elasticsearch.client.RestClient; +import org.elasticsearch.client.RestClientBuilder; +import org.elasticsearch.client.RestHighLevelClient; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.web.client.RestTemplateBuilder; +import org.springframework.context.annotation.Bean; +import org.springframework.data.elasticsearch.client.ClientConfiguration; +import org.springframework.data.elasticsearch.client.RestClients; +import org.springframework.data.elasticsearch.core.ElasticsearchOperations; +import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate; +import org.springframework.stereotype.Component; +import org.springframework.web.client.RestTemplate; + +import javax.net.ssl.SSLContext; +import java.net.URI; +import java.net.URISyntaxException; +import java.security.KeyManagementException; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; + +@SpringBootApplication +@Component +public class ZeebeOpsApplication { + + @Value("${spring.data.elasticsearch.client.reactive.endpoints}") + private String contactPoint; + + + @Value("${elasticsearch.security.enabled}") + private Boolean securityEnabled; + + @Value("${elasticsearch.sslVerification}") + private Boolean sslVerify; + + @Value("${elasticsearch.username}") + private String username; + + @Value("${elasticsearch.password}") + private String password; + + @Value("${elasticsearch.url}") + private String elasticUrl; + + @Bean + public ObjectMapper objectMapper() { + ObjectMapper objectMapper = new ObjectMapper(); + objectMapper.registerModule(new JavaTimeModule()); + objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false); + return objectMapper + .setSerializationInclusion(JsonInclude.Include.NON_NULL) + .configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true) + .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + } + + @Bean + public RestHighLevelClient client() { + + RestClientBuilder builder; + SSLContext sslContext = null; + if(securityEnabled) { + final CredentialsProvider credentialsProvider = new BasicCredentialsProvider(); + credentialsProvider.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials(username, password)); + if (sslVerify) { + SSLContextBuilder sslBuilder; + try { + sslBuilder = SSLContexts.custom().loadTrustMaterial(null, (x509Certificates, s) -> true); + sslContext = sslBuilder.build(); + } catch (NoSuchAlgorithmException | KeyStoreException | KeyManagementException e) { + e.printStackTrace(); + } + HttpHost httpHost = urlToHttpHost(elasticUrl); + SSLContext finalSslContext = sslContext; + builder = RestClient.builder(httpHost) + .setHttpClientConfigCallback(httpClientBuilder -> httpClientBuilder + .setSSLContext(finalSslContext) + .setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE) + .setDefaultCredentialsProvider(credentialsProvider)); + } else { + HttpHost httpHost = urlToHttpHost(elasticUrl); + builder = RestClient.builder(httpHost) + .setHttpClientConfigCallback(httpClientBuilder -> httpClientBuilder + .setDefaultCredentialsProvider(credentialsProvider)); + } + } else { + HttpHost httpHost = urlToHttpHost(elasticUrl); + builder = + RestClient.builder(httpHost).setHttpClientConfigCallback(this::setHttpClientConfigCallback); + } + return new RestHighLevelClient(builder);} + private HttpAsyncClientBuilder setHttpClientConfigCallback(HttpAsyncClientBuilder builder) { + builder.setDefaultIOReactorConfig(IOReactorConfig.custom().setIoThreadCount(1).build()); + return builder; + } + + private static HttpHost urlToHttpHost(String url) { + URI uri = null; + try { + uri = new URI(url); + } catch (URISyntaxException e) { + e.printStackTrace(); + } + + return new HttpHost(uri.getHost(), uri.getPort(), uri.getScheme()); + } + + @Bean + public ElasticsearchOperations elasticsearchTemplate() { + return new ElasticsearchRestTemplate(client()); + } + + @Bean + public RestTemplate restTemplate(RestTemplateBuilder builder) { + return builder.build(); + } + + @Bean + public Logger logger() { + return LoggerFactory.getLogger(ZeebeOpsApplication.class); + } + + public static void main(String[] args) { + SpringApplication.run(ZeebeOpsApplication.class, args); + } + +} diff --git a/ph-ee-zeebe-ops/src/main/java/org/mifos/ops/zeebe/camel/config/CamelContextConfig.java b/ph-ee-zeebe-ops/src/main/java/org/mifos/ops/zeebe/camel/config/CamelContextConfig.java new file mode 100644 index 000000000..8edc14a92 --- /dev/null +++ b/ph-ee-zeebe-ops/src/main/java/org/mifos/ops/zeebe/camel/config/CamelContextConfig.java @@ -0,0 +1,45 @@ +package org.mifos.ops.zeebe.camel.config; + +import org.apache.camel.CamelContext; +import org.apache.camel.spi.RestConfiguration; +import org.apache.camel.spring.boot.CamelContextConfiguration; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import java.util.HashMap; + +@Configuration +public class CamelContextConfig { + + @Value("${camel.server-port}") + private int serverPort; + + @Bean + CamelContextConfiguration contextConfiguration() { + return new CamelContextConfiguration() { + @Override + public void beforeApplicationStart(CamelContext camelContext) { + camelContext.setTracing(false); + camelContext.setMessageHistory(false); + camelContext.setStreamCaching(true); + camelContext.disableJMX(); + + RestConfiguration rest = new RestConfiguration(); + camelContext.setRestConfiguration(rest); + rest.setComponent("undertow"); + rest.setProducerComponent("undertow"); + rest.setPort(serverPort); + rest.setBindingMode(RestConfiguration.RestBindingMode.json); + rest.setDataFormatProperties(new HashMap<>()); + rest.getDataFormatProperties().put("prettyPrint", "true"); + rest.setScheme("http"); + } + + @Override + public void afterApplicationStart(CamelContext camelContext) { + // empty + } + }; + } +} diff --git a/ph-ee-zeebe-ops/src/main/java/org/mifos/ops/zeebe/camel/routes/OperationsRouteBuilder.java b/ph-ee-zeebe-ops/src/main/java/org/mifos/ops/zeebe/camel/routes/OperationsRouteBuilder.java new file mode 100644 index 000000000..6f9081e82 --- /dev/null +++ b/ph-ee-zeebe-ops/src/main/java/org/mifos/ops/zeebe/camel/routes/OperationsRouteBuilder.java @@ -0,0 +1,801 @@ +package org.mifos.ops.zeebe.camel.routes; + +import io.camunda.zeebe.client.ZeebeClient; +import io.camunda.zeebe.client.api.response.DeploymentEvent; +import io.camunda.zeebe.client.api.response.ProcessInstanceEvent; +import io.camunda.zeebe.model.bpmn.Bpmn; +import io.camunda.zeebe.model.bpmn.BpmnModelInstance; +import io.camunda.zeebe.model.bpmn.instance.Definitions; +import org.apache.camel.Exchange; +import org.apache.camel.LoggingLevel; +import org.camunda.bpm.model.xml.instance.DomDocument; +import org.camunda.bpm.model.xml.instance.DomElement; +import org.elasticsearch.action.search.SearchRequest; +import org.elasticsearch.action.search.SearchResponse; +import org.elasticsearch.client.RequestOptions; +import org.elasticsearch.client.RestHighLevelClient; +import org.elasticsearch.index.query.BoolQueryBuilder; +import org.elasticsearch.index.query.QueryBuilder; +import org.elasticsearch.index.query.QueryBuilders; +import org.elasticsearch.search.aggregations.AggregationBuilders; +import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder; +import org.elasticsearch.search.builder.SearchSourceBuilder; +import org.json.JSONArray; +import org.elasticsearch.client.indices.GetIndexRequest; +import org.json.JSONObject; +import org.mifos.ops.zeebe.ZeebeOpsApplication; +import org.slf4j.Logger; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; +import org.mifos.connector.common.camel.ErrorHandlerRouteBuilder; +import org.springframework.web.multipart.MultipartFile; + +import javax.activation.DataHandler; +import javax.mail.internet.MimeBodyPart; +import java.io.*; +import java.time.Duration; +import java.util.*; +import java.util.concurrent.atomic.AtomicInteger; +import static org.mifos.ops.zeebe.zeebe.ZeebeMessages.OPERATOR_MANUAL_RECOVERY; +import static org.mifos.ops.zeebe.zeebe.ZeebeVariables.*; + +@Component +public class OperationsRouteBuilder extends ErrorHandlerRouteBuilder { + + @Autowired + private ZeebeClient zeebeClient; + + @Autowired + private Logger logger; + + RestHighLevelClient esClient; + + @Autowired + ZeebeOpsApplication zeebeOpsApplication; + + + @Value("${elasticsearch.security.enabled}") + private Boolean securityEnabled; + + + + @Value("#{'${tenants}'.split(',')}") + private List tenants; + + private void removeLastLine(String bpmnFileName) throws IOException { + String filePath = "upload/"+bpmnFileName; + RandomAccessFile f = new RandomAccessFile(filePath, "rw"); + long length = f.length() - 1; + byte b; + do { + length -= 1; + f.seek(length); + b = f.readByte(); + } while(b != 10); + f.setLength(length+1); + f.close(); + + } + + private List formatBpmn(String bpmnFileName) throws IOException { + removeLastLine(bpmnFileName); + String filePath = "upload/"+bpmnFileName; + List uploadingFilePath = new ArrayList<>(); + + if (!bpmnFileName.contains("DFSPID")) { + uploadingFilePath.add(filePath); + return uploadingFilePath; + } + + BpmnModelInstance instance = Bpmn.readModelFromFile(new File(filePath)); + String baseId = bpmnFileName.substring(0, bpmnFileName.indexOf("DFSPID")-1).replace("-", "_"); + + for (String tenant: tenants) { + logger.info("Creating tenant specific: " + tenant); + String tenantSpecificId = String.format("%s-%s", baseId, tenant); + logger.info("tenantSpecificId: " + tenantSpecificId); + BpmnModelInstance tenantSpecificInstance = instance.clone(); + DomDocument document = tenantSpecificInstance.getDocument(); + DomElement processElement = document.getRootElement().getChildElements().get(0); + processElement.setAttribute("id", tenantSpecificId); + processElement.setAttribute("name", tenantSpecificId); + String fp = String.format("upload/%s.bpmn", tenantSpecificId); + Bpmn.writeModelToFile(new File(fp), tenantSpecificInstance); + formatBpmnWorker(fp,tenant); + Bpmn.validateModel(tenantSpecificInstance); + uploadingFilePath.add(fp); + logger.info("Done"); + } + return uploadingFilePath; + } + private void formatBpmnWorker(String filePath, String tenant) throws IOException { + File fileToBeModified = new File(filePath); + String oldContent = ""; + BufferedReader reader = new BufferedReader(new FileReader(fileToBeModified)); + String line = reader.readLine(); + + while (line != null) + { + oldContent = oldContent + line + System.lineSeparator(); + line = reader.readLine(); + } + String newContent = oldContent.replaceAll("DFSPID", tenant); + FileWriter writer = new FileWriter(fileToBeModified); + writer.write(newContent); + reader.close(); + writer.close(); + } + + @Override + public void configure() { + + esClient = zeebeOpsApplication.client(); + + /* + * Use this endpoint for uploading the bpmns + */ + from("rest:POST:/zeebe/upload") + .id("upload-bpmn") + .log(LoggingLevel.INFO, "## Uploading the bpmn to zeebe") + .process(exchange -> { + InputStream is = exchange.getIn().getBody(InputStream.class); + MimeBodyPart mimeMessage = new MimeBodyPart(is); + DataHandler dh = mimeMessage.getDataHandler(); + exchange.getIn().setBody(dh.getInputStream()); + exchange.getIn().setHeader(Exchange.FILE_NAME, dh.getName()); + exchange.setProperty("BPMN_FILE_NAME", dh.getName()); + logger.info("\n\n\n " + dh.getName() + "\n\n\n"); + + }) + .to("file:upload") + .process(exchange -> { + String bpmnFileName = exchange.getProperty("BPMN_FILE_NAME", String.class); + StringBuilder response = new StringBuilder(); + response.append("Deployment created with keys: "); + + // file formatting + List bpmnFilePaths = formatBpmn(bpmnFileName); + + for(String path: bpmnFilePaths) { + // deploying + DeploymentEvent deploymentEvent = + zeebeClient.newDeployCommand().addResourceFile(path) + .send().join(); + new File(path).delete(); + response.append(String.format("\n{%s : %s}", path, deploymentEvent.getKey())); + } + + // deleting bpmn file + File file = new File("upload/"+bpmnFileName); + file.delete(); + logger.info("Deleted file " + "upload/"+bpmnFileName + "after successful deployment"); + + exchange.getIn().setBody(response.toString()); + logger.info(response.toString()); + }); + + /** + * Cancellation of the process by variable name and value + * + * sample request: { + * "key": "initiatorFspId", + * "value": "\"ibank-usa\"" + * } + * + * sample response: { + * "cancellationSuccessful": 0, + * "cancellationFailed": 1, + * "success": [], + * "failed": [ + * 2251799813686414 + * ] + * } + * + */ + from("rest:POST:/channel/workflow/cancelbyvalue") + .id("cancel-workflow") + .log(LoggingLevel.INFO, "## Cancelling the process by matching variable name and value") + .process(exchange -> { + + JSONObject object = new JSONObject(exchange.getIn().getBody(String.class)); + String key = object.getString("key"); + Object value = object.get("value"); + + TermsAggregationBuilder definitionNameAggregation = AggregationBuilders.terms("1") + .field("value.processDefinitionKey") + .size(5); + + BoolQueryBuilder query = QueryBuilders.boolQuery() + .filter(QueryBuilders.matchPhraseQuery("value.name", key)) + .filter(QueryBuilders.matchPhraseQuery("value.value", value)); + + SearchSourceBuilder builder = new SearchSourceBuilder().aggregation(definitionNameAggregation) + .query(query); + + SearchRequest searchRequest = + new SearchRequest().indices("zeebe-*").source(builder); + + SearchResponse response = esClient.search(searchRequest, RequestOptions.DEFAULT); + + String r = response.toString(); + JSONObject res = new JSONObject(r); + JSONArray processDefinitionKeysObject = res.getJSONObject("aggregations").getJSONObject("lterms#1") + .getJSONArray("buckets"); + + JSONArray processIds = new JSONArray(); + + processDefinitionKeysObject.forEach(elm -> { + long processId = ((JSONObject) elm).getLong("key"); + processIds.put(processId); + }); + + JSONObject responseToBeReturned = cancelProcess(processIds); + + exchange.getMessage().setBody(responseToBeReturned.toString()); + + }); + + /** + * Get the list of tasks that are already executed, by process definition key + * + * sample url: + * localhost:5000/channel/process/2251799813686414/task/ + * + * sample response: { + * "tasks": [ + * "" + * ] + * } + */ + from(String.format("rest:get:/channel/process/{%s}/task/", PROCESS_DEFINITION_KEY)) + .id("get-executed-task") + .log(LoggingLevel.INFO, "## Fetching the executed task") + .process(exchange -> { + + Long processInstanceKey = exchange.getIn().getHeader(PROCESS_DEFINITION_KEY, Long.class); + + TermsAggregationBuilder definitionNameAggregation = AggregationBuilders.terms("worker") + .field("value.worker") + .size(5); + + BoolQueryBuilder query = QueryBuilders.boolQuery() + .filter(QueryBuilders.matchPhraseQuery("intent", "ELEMENT_COMPLETED")) + .filter(QueryBuilders.matchPhraseQuery("value.processDefinitionKey", processInstanceKey)); + + SearchSourceBuilder builder = new SearchSourceBuilder().aggregation(definitionNameAggregation) + .query(query); + + SearchRequest searchRequest = + new SearchRequest().indices("zeebe-*").source(builder); + + SearchResponse response = esClient.search(searchRequest, RequestOptions.DEFAULT); + + String r = response.toString(); + JSONObject res = new JSONObject(r); + JSONArray keyBucket = res.getJSONObject("aggregations").getJSONObject("sterms#worker") + .getJSONArray("buckets"); + + JSONObject responseToBeReturned = new JSONObject(); + JSONArray taskList = new JSONArray(); + + keyBucket.forEach(elm -> { + JSONObject task = (JSONObject) elm; + taskList.put(task.getString("key")); + }); + responseToBeReturned.put("tasks", taskList); + + exchange.getMessage().setBody(responseToBeReturned.toString()); + }); + + /** + * Get the process variables by process instance key + * + * demo url: /channel/process/variable/2251799813783649 + * here [2251799813783649] is the value for path parameter [PROCESS_INSTANCE_KEY] + * + * example response: { + * "isRtpRequest":"false", + * "initiatorFspId":"\"ibank-usa\"", + * "originDate":"1633441154238" + * } + */ + from(String.format("rest:get:/channel/process/variable/{%s}", PROCESS_INSTANCE_KEY)) + .id("get-process-variable") + .log(LoggingLevel.INFO, "## Fetch process variable") + .process(exchange -> { + + Long processId = exchange.getIn().getHeader(PROCESS_INSTANCE_KEY, Long.class); + + TermsAggregationBuilder valueAgg = AggregationBuilders.terms("value") + .field("value.value") + .size(100); + TermsAggregationBuilder nameAgg = AggregationBuilders.terms("key") + .field("value.name") + .size(100) + .subAggregation(valueAgg); + + SearchSourceBuilder builder = new SearchSourceBuilder().aggregation(nameAgg) + .query(QueryBuilders.matchQuery("value.processInstanceKey", processId)); + + SearchRequest searchRequest = + new SearchRequest().indices("zeebe-*").source(builder); + + SearchResponse response = esClient.search(searchRequest, RequestOptions.DEFAULT); + + JSONObject responseToBeReturned = new JSONObject(); + + String r = response.toString(); + JSONObject res = new JSONObject(r); + JSONArray keyBucket = res.getJSONObject("aggregations").getJSONObject("sterms#key") + .getJSONArray("buckets"); + + keyBucket.forEach(elm -> { + JSONObject bucket = (JSONObject) elm; + String key = bucket.getString("key"); + Object value = ((JSONObject)bucket.getJSONObject("sterms#value").getJSONArray("buckets") + .get(0)).get("key"); + + responseToBeReturned.put(key, value); + }); + + exchange.getMessage().setBody(responseToBeReturned.toString()); + + }); + + /** + * Get the process current state and variables by process instance id + * + * demo url: /channel/process/2251799813686414 + * here [2251799813686414] is the value for path parameter [PROCESS_INSTANCE_ID] + * + * example response: { + * "currentState": "", + * "processVariables": {} + * } + */ + from(String.format("rest:get:/channel/process/{%s}", PROCESS_DEFINITION_KEY)) + .id("get-process-variable-and-state") + .log(LoggingLevel.INFO, "## Fetch process variable and current state") + .process(exchange -> { + + Long processInstanceKey = exchange.getIn().getHeader(PROCESS_DEFINITION_KEY, Long.class); + + try { + JSONObject processVariables = getProcessVariable(processInstanceKey); + String state = getCurrentState(processInstanceKey); + JSONObject responseToBeReturned = new JSONObject(); + responseToBeReturned.put("currentState", state); + responseToBeReturned.put("processVariables", processVariables); + exchange.getMessage().setBody(responseToBeReturned.toString()); + } catch (Exception e) { + exchange.getMessage().setHeader(Exchange.HTTP_RESPONSE_CODE, 404); + exchange.getMessage().setBody(e.toString()); + } + }); + + /** + * Cancel the workflow in specific state and having retry count greater than the passed value + * + * request body: { + * "state": "Activity_1m5hpl9", + * "retries": 12 + * } + * + * sample resonse: { + * "cancellationSuccessful": 0, + * "cancellationFailed": 4, + * "success": [], + * "failed": [ + * 2251799813776442, + * 2251799813779803, + * 2251799813783649, + * 2251799813686416 + * ] + * } + */ + from("rest:POST:channel/workflow/cancel") + .id("cancel-workflow-by-state") + .log(LoggingLevel.INFO, "## Canceling the workflow") + .process(exchange -> { + + JSONObject requestBody = new JSONObject(exchange.getIn().getBody(String.class)); + String state = requestBody.getString("state"); + Long retryCount = requestBody.getLong("retries"); + + TermsAggregationBuilder nameAgg = AggregationBuilders.terms("1") + .field("value.processInstanceKey") + .size(10); + + SearchSourceBuilder builder = new SearchSourceBuilder().aggregation(nameAgg) + .query(QueryBuilders.matchQuery("value.elementId", state)) + .query(QueryBuilders.rangeQuery("value.retries").gte(retryCount)); + + SearchRequest searchRequest = + new SearchRequest().indices("zeebe-*").source(builder); + + SearchResponse response = esClient.search(searchRequest, RequestOptions.DEFAULT); + + JSONArray processInstanceKey = new JSONArray(); + + String r = response.toString(); + JSONObject res = new JSONObject(r); + JSONArray buckets = res.getJSONObject("aggregations").getJSONObject("lterms#1") + .getJSONArray("buckets"); + + buckets.forEach(elm -> { + JSONObject bucket = (JSONObject) elm; + Long key = bucket.getLong("key"); + + processInstanceKey.put(key); + }); + + String responseToBeReturned = cancelWorkflow(processInstanceKey); + + + exchange.getMessage().setBody(responseToBeReturned); + }); + + + /** + * Starts a workflow with the set of variables passed as body parameters + * + * method: [POST] + * request body: { + * "var1": "val1", + * "var2": "val2" + * } + * + * response body: Null + * + * demo url: /channel/workflow/international_remittance_payer_process-ibank-usa + * Here [international_remittance_payer_process-ibank-usa] is the value of [BPMN_PROCESS_ID] path variable + * + */ + from(String.format("rest:POST:/channel/workflow/{%s}", BPMN_PROCESS_ID)) + .id("workflow-start") + .log(LoggingLevel.INFO, "## Starting new workflow") + .process(e -> { + + JSONObject variables = new JSONObject(e.getIn().getBody(String.class)); + Map map = variables.toMap(); + + e.getMessage().setBody(e.getIn().getHeader(BPMN_PROCESS_ID, String.class)); + + + ProcessInstanceEvent job = zeebeClient.newCreateInstanceCommand() + .bpmnProcessId(e.getIn().getHeader(BPMN_PROCESS_ID, String.class)) + .latestVersion() + .variables(map) + .send() + .join(); + JSONObject res = new JSONObject(); + res.put("bpmnProcessId", job.getBpmnProcessId()); + res.put("processInstanceKey", job.getProcessInstanceKey()); + res.put("processDefinitionKey", job.getProcessDefinitionKey()); + e.getMessage().setBody(res.toString()); + }); + + /** + * Bulk cancellation of active process by processId + * + * method: [PUT] + * request body: { + * processId: [123, 456, 789] + * } + * + * response body: { + * success: [], # list of processId which was successfully cancelled + * failed: [] # list of processId whose cancellation wasn't successful + * cancellationSuccessful: int # total number of process which was successfully cancelled + * cancellationFailed: int # total number of process whose cancellation wasn't successful + * + * } + */ + from("rest:PUT:/channel/workflow") + .id("bulk-cancellation") + .log(LoggingLevel.INFO, "## bulk cancellation by process id") + .process(exchange -> { + + JSONObject object = new JSONObject(exchange.getIn().getBody(String.class)); + JSONArray processIds = object.getJSONArray("processId"); + + JSONObject response =cancelProcess(processIds); + + exchange.getMessage().setBody(response.toString()); + }); + + /** + * Get the health of the elastic search cluster + */ + from("rest:get:/es/health") + .id("es-test") + .log(LoggingLevel.INFO, "## Testing es connection") + .process(exchange -> { + JSONObject jsonResponse = new JSONObject(); + try { + GetIndexRequest request = new GetIndexRequest("*"); + esClient.indices().get(request, RequestOptions.DEFAULT); + jsonResponse.put("status", "UP"); + } catch (Exception e) { + jsonResponse.put("status", "down"); + jsonResponse.put("reason", e.getMessage()); + } + + exchange.getMessage().setBody(jsonResponse.toString()); + }); + + /** + * Get the process definition key and name + * + * sample response body: { + * "bulk_processor-ibank-usa":[ + * 2251799813685998, + * 2251799814125425 + * ], + * "international_remittance_payee_process-ibank-india":[ + * 2251799813686276, + * 2251799814069864 + * ], + * "international_remittance_payer_process-ibank-usa":[ + * 2251799813686414, + * 2251799814069794 + * ], + * "international_remittance_payer_process-ibank-india":[ + * 2251799813686138, + * 2251799814070206 + * ], + * "international_remittance_payee_process-ibank-usa":[ + * 2251799813686068, + * 2251799814070344 + * ] + * } + */ + from("rest:get:/channel/process") + .id("get-process-definition-key-name") + .log(LoggingLevel.INFO, "## get process definition key and name") + .process(exchange -> { + TermsAggregationBuilder definitionKeyAggregation = AggregationBuilders.terms("defKey") + .field("value.processDefinitionKey") + .size(1005); + TermsAggregationBuilder definitionNameAggregation = AggregationBuilders.terms("processId") + .field("value.bpmnProcessId") + .size(5) + .subAggregation(definitionKeyAggregation); + + SearchSourceBuilder builder = new SearchSourceBuilder().aggregation(definitionNameAggregation); + + SearchRequest searchRequest = + new SearchRequest().indices("zeebe-*").source(builder); + SearchResponse response = esClient.search(searchRequest, RequestOptions.DEFAULT); + + JSONObject responseToBeReturned = new JSONObject(); + + String r = response.toString(); + JSONObject res = new JSONObject(r); + JSONArray buckets = res.getJSONObject("aggregations") + .getJSONObject("sterms#processId").getJSONArray("buckets"); + + buckets.forEach(element -> { + String processId = ((JSONObject) element).getString("key"); + JSONArray processDefinitionsKeys = new JSONArray(); + + // loop over each internal aggregation to get the processDefinitionKey + ((JSONObject) element).getJSONObject("lterms#defKey").getJSONArray("buckets") + .forEach(elm -> processDefinitionsKeys.put(((JSONObject) elm).getLong("key"))); + + responseToBeReturned.put(processId, processDefinitionsKeys); + }); + + exchange.getMessage().setBody(responseToBeReturned.toString()); + }); + + from("rest:POST:/channel/transaction/{" + TRANSACTION_ID + "}/resolve") + .id("transaction-resolve") + .log(LoggingLevel.INFO, "## operator transaction resolve") + .process(e -> { + Map variables = new HashMap<>(); + JSONObject request = new JSONObject(e.getIn().getBody(String.class)); + request.keys().forEachRemaining(k -> variables.put(k, request.get(k))); + + zeebeClient.newPublishMessageCommand() + .messageName(OPERATOR_MANUAL_RECOVERY) + .correlationKey(e.getIn().getHeader(TRANSACTION_ID, String.class)) + .timeToLive(Duration.ofMillis(30000)) + .variables(variables) + .send() + .join(); + }) + .setBody(constant(null)); + + from("rest:POST:/channel/job/resolve") + .id("job-resolve") + .log(LoggingLevel.INFO, "## operator job resolve") + .process(e -> { + JSONObject request = new JSONObject(e.getIn().getBody(String.class)); + JSONObject incident = request.getJSONObject("incident"); + Map newVariables = new HashMap<>(); + JSONObject requestedVariables = request.getJSONObject("variables"); + requestedVariables.keys().forEachRemaining(k -> newVariables.put(k, requestedVariables.get(k))); + + zeebeClient.newSetVariablesCommand(incident.getLong("elementInstanceKey")) + .variables(newVariables) + .send() + .join(); + + zeebeClient.newUpdateRetriesCommand(incident.getLong("jobKey")) + .retries(incident.getInt("newRetries")) + .send() + .join(); + + zeebeClient.newResolveIncidentCommand(incident.getLong("key")) + .send() + .join(); + }) + .setBody(constant(null)); + + from("rest:POST:/channel/workflow/resolve") + .id("workflow-resolve") + .log(LoggingLevel.INFO, "## operator workflow resolve") + .process(e -> { + JSONObject request = new JSONObject(e.getIn().getBody(String.class)); + JSONObject incident = request.getJSONObject("incident"); + Map newVariables = new HashMap<>(); + JSONObject requestedVariables = request.getJSONObject("variables"); + requestedVariables.keys().forEachRemaining(k -> newVariables.put(k, requestedVariables.get(k))); + + zeebeClient.newSetVariablesCommand(incident.getLong("elementInstanceKey")) + .variables(newVariables) + .send() + .join(); + + zeebeClient.newResolveIncidentCommand(incident.getLong("key")) + .send() + .join(); + }) + .setBody(constant(null)); + + /** + * Cancel a workflow by workflow instance key + */ + from("rest:POST:/channel/workflow/{workflowInstanceKey}/cancel") + .id("workflow-cancel") + .log(LoggingLevel.INFO, "## operator workflow cancel ${header.workflowInstanceKey}") + .process(e -> zeebeClient.newCancelInstanceCommand(Long.parseLong(e.getIn().getHeader("workflowInstanceKey", String.class))) + .send() + .join()) + .setBody(constant(null)); + + } + + private JSONObject getProcessVariable(Long processInstanceKey) throws IOException { + esClient = zeebeOpsApplication.client(); + TermsAggregationBuilder valueAgg = AggregationBuilders.terms("value") + .field("value.value") + .size(100); + TermsAggregationBuilder nameAgg = AggregationBuilders.terms("key") + .field("value.name") + .size(100) + .subAggregation(valueAgg); + + SearchSourceBuilder builder = new SearchSourceBuilder().aggregation(nameAgg) + .query(QueryBuilders.matchQuery("value.processInstanceKey", processInstanceKey)); + + SearchRequest searchRequest = + new SearchRequest().indices("zeebe-*").source(builder); + + SearchResponse response = esClient.search(searchRequest, RequestOptions.DEFAULT); + + JSONObject responseToBeReturned = new JSONObject(); + + String r = response.toString(); + JSONObject res = new JSONObject(r); + JSONArray keyBucket = res.getJSONObject("aggregations").getJSONObject("sterms#key") + .getJSONArray("buckets"); + + keyBucket.forEach(elm -> { + JSONObject bucket = (JSONObject) elm; + String key = bucket.getString("key"); + Object value = ((JSONObject)bucket.getJSONObject("sterms#value").getJSONArray("buckets") + .get(0)).get("key"); + + responseToBeReturned.put(key, value); + }); + + return responseToBeReturned; + } + + private String getCurrentState(Long processInstanceKey) throws Exception { + esClient = zeebeOpsApplication.client(); + TermsAggregationBuilder definitionNameAggregation = AggregationBuilders.terms("worker") + .field("value.worker") + .size(5); + + BoolQueryBuilder query = QueryBuilders.boolQuery() + .filter(QueryBuilders.boolQuery() + .should(QueryBuilders.matchPhraseQuery("intent", "ELEMENT_ACTIVATED")) + .should(QueryBuilders.matchPhraseQuery("intent", "ELEMENT_ACTIVATING")) + .minimumShouldMatch(1)) + .mustNot(QueryBuilders.matchPhraseQuery("intent", "ELEMENT_COMPLETED")) + .filter(QueryBuilders.matchPhraseQuery("value.processDefinitionKey", processInstanceKey)); + + SearchSourceBuilder builder = new SearchSourceBuilder().aggregation(definitionNameAggregation) + .query(query); + + SearchRequest searchRequest = + new SearchRequest().indices("zeebe-*").source(builder); + + SearchResponse response = esClient.search(searchRequest, RequestOptions.DEFAULT); + + String r = response.toString(); + JSONObject res = new JSONObject(r); + JSONArray keyBucket = res.getJSONObject("aggregations").getJSONObject("sterms#worker") + .getJSONArray("buckets"); + + if(keyBucket.isEmpty()) { + throw new Exception("Unable to fetch current state"); + } + + return ((JSONObject) keyBucket.get(0)).getString("key"); + } + + private String cancelWorkflow(JSONArray processIds) { + JSONArray success = new JSONArray(); + JSONArray failed = new JSONArray(); + AtomicInteger successfullyCancelled = new AtomicInteger(); + AtomicInteger cancellationFailed = new AtomicInteger(); + + processIds.forEach(elm -> { + long processId = Long.parseLong(elm.toString()); + + try { + zeebeClient.newCancelInstanceCommand(processId).send().join(); + success.put(processId); + successfullyCancelled.getAndIncrement(); + }catch (Exception e) { + failed.put(processId); + cancellationFailed.getAndIncrement(); + logger.error("Cancellation of process id " + processId + " failed\n" + e.getMessage()); + } + }); + JSONObject response = new JSONObject(); + response.put("success", success); + response.put("failed", failed); + response.put("cancellationSuccessful", successfullyCancelled.get()); + response.put("cancellationFailed", cancellationFailed.get()); + + return response.toString(); + } + + private JSONObject cancelProcess(JSONArray processIds) { + JSONArray success = new JSONArray(); + JSONArray failed = new JSONArray(); + + AtomicInteger successfullyCancelled = new AtomicInteger(); + AtomicInteger cancellationFailed = new AtomicInteger(); + + + processIds.forEach(elm -> { + long processId = Long.parseLong(elm.toString()); + + try { + zeebeClient.newCancelInstanceCommand(processId).send().join(); + success.put(processId); + successfullyCancelled.getAndIncrement(); + }catch (Exception e) { + failed.put(processId); + cancellationFailed.getAndIncrement(); + logger.error("Cancellation of process id " + processId + " failed\n" + e.getMessage()); + } + + }); + + JSONObject response = new JSONObject(); + response.put("success", success); + response.put("failed", failed); + response.put("cancellationSuccessful", successfullyCancelled.get()); + response.put("cancellationFailed", cancellationFailed.get()); + + return response; + } +} diff --git a/ph-ee-zeebe-ops/src/main/java/org/mifos/ops/zeebe/zeebe/ZeebeClientConfiguration.java b/ph-ee-zeebe-ops/src/main/java/org/mifos/ops/zeebe/zeebe/ZeebeClientConfiguration.java new file mode 100644 index 000000000..5d2041a7c --- /dev/null +++ b/ph-ee-zeebe-ops/src/main/java/org/mifos/ops/zeebe/zeebe/ZeebeClientConfiguration.java @@ -0,0 +1,25 @@ +package org.mifos.ops.zeebe.zeebe; + +import io.camunda.zeebe.client.ZeebeClient; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class ZeebeClientConfiguration { + + @Value("${zeebe.broker.contactpoint}") + private String zeebeBrokerContactpoint; + + @Value("${zeebe.client.max-execution-threads}") + private int zeebeClientMaxThreads; + + @Bean + public ZeebeClient setup() { + return ZeebeClient.newClientBuilder() + .gatewayAddress(zeebeBrokerContactpoint) + .usePlaintext() + .numJobWorkerExecutionThreads(zeebeClientMaxThreads) + .build(); + } +} diff --git a/ph-ee-zeebe-ops/src/main/java/org/mifos/ops/zeebe/zeebe/ZeebeMessages.java b/ph-ee-zeebe-ops/src/main/java/org/mifos/ops/zeebe/zeebe/ZeebeMessages.java new file mode 100644 index 000000000..f85ef8738 --- /dev/null +++ b/ph-ee-zeebe-ops/src/main/java/org/mifos/ops/zeebe/zeebe/ZeebeMessages.java @@ -0,0 +1,9 @@ +package org.mifos.ops.zeebe.zeebe; + +public class ZeebeMessages { + + private ZeebeMessages() {} + + public static final String OPERATOR_MANUAL_RECOVERY = "operator-manual-recovery"; + +} diff --git a/ph-ee-zeebe-ops/src/main/java/org/mifos/ops/zeebe/zeebe/ZeebeVariables.java b/ph-ee-zeebe-ops/src/main/java/org/mifos/ops/zeebe/zeebe/ZeebeVariables.java new file mode 100644 index 000000000..e66aab92e --- /dev/null +++ b/ph-ee-zeebe-ops/src/main/java/org/mifos/ops/zeebe/zeebe/ZeebeVariables.java @@ -0,0 +1,12 @@ +package org.mifos.ops.zeebe.zeebe; + +public class ZeebeVariables { + + private ZeebeVariables() { + } + + public static final String TRANSACTION_ID = "transactionId"; + public static final String BPMN_PROCESS_ID = "BPMN_PROCESS_ID"; + public static final String PROCESS_INSTANCE_KEY = "PROCESS_INSTANCE_KEY"; + public static final String PROCESS_DEFINITION_KEY = "PROCESS_DEFINITION_KEY"; +} \ No newline at end of file diff --git a/ph-ee-zeebe-ops/src/main/resources/application.yml b/ph-ee-zeebe-ops/src/main/resources/application.yml new file mode 100644 index 000000000..e5fbf9f54 --- /dev/null +++ b/ph-ee-zeebe-ops/src/main/resources/application.yml @@ -0,0 +1,50 @@ +camel: + server-port: 5000 + springboot: + main-run-controller: true + dataformat: + json-jackson: + auto-discover-object-mapper: true + +tenants: "ibank-india,ibank-usa" + +zeebe: + client: + max-execution-threads: 100 + number-of-workers: 5 + evenly-allocated-max-jobs: "#{${zeebe.client.max-execution-threads} / ${zeebe.client.number-of-workers}}" + broker: + contactpoint: "localhost:26500" + +spring: + data: + elasticsearch: + client: + reactive: + endpoints: "localhost:9200" + +logging: + level: + root: INFO + +elasticsearch: + url: "https://ph-ee-elasticsearch:9200/" + security: + enabled: false + sslVerification: false + username: "elastic" + password: "spmepassword" + + + +management: + endpoint: + health: + enabled: true + probes: + enabled: true + liveness: + enabled: true + readiness: + enabled: true +# show-details: always diff --git a/ph-ee-zeebe-ops/src/test/java/org/mifos/ops/zeebe/PhEeZeebeOpsApplicationTests.java b/ph-ee-zeebe-ops/src/test/java/org/mifos/ops/zeebe/PhEeZeebeOpsApplicationTests.java new file mode 100644 index 000000000..2cad22c24 --- /dev/null +++ b/ph-ee-zeebe-ops/src/test/java/org/mifos/ops/zeebe/PhEeZeebeOpsApplicationTests.java @@ -0,0 +1,13 @@ +package org.mifos.ops.zeebe; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +class PhEeZeebeOpsApplicationTests { + + @Test + void contextLoads() { + } + +} diff --git a/settings.gradle b/settings.gradle new file mode 100644 index 000000000..79867ebaa --- /dev/null +++ b/settings.gradle @@ -0,0 +1,9 @@ +include 'ph-ee-bill-pay' , 'ph-ee-bulk-processor', 'ph-ee-connector-channel', 'ph-ee-connector-mojaloop-java', +'ph-ee-connector-crm', 'ph-ee-importer-es', 'ph-ee-importer-rdbms', 'ph-ee-integration-test', +'ph-ee-vouchers', 'ph-ee-zeebe-ops', 'ph-ee-identity-account-mapper', 'ph-ee-connector-bulk', 'ph-ee-connector-mock-payment-schema', + 'ph-ee-exporter', 'ph-ee-connector-common', 'ph-ee-operations-app', 'ph-ee-connector-ams-mifos','ph-ee-connector-gsma-mm' + +gradle.ext{ + app_username = '' + app_password = '' +}